Having an arbitrary curve defined as InterpolatingFunction
, what is the best way to place a text on this curve? The text generally has two rows, for example: "This is\na text on a curve"
, the curve must go between the rows. I am interested both in character-based (preserving characters as selectable textual elements) and outlined solution (the text is first converted to outlines, then a transformation is applied to the resulting curves). It would be perfect to have a possibility to move the text along the curve interactively.
External links (updated!):
For the search engine: this is also known as "text on a path."
Answer
Here's another way...Text[] has a direction argument, so ArcTan is not necessary.
txt1 = "Now we can follow" // Characters;
txt2 = "an arbitrary path" // Characters;
f[t_] := {Cos[2 π t], Sin[6 π t]};
totalarclength = NIntegrate[Sqrt[f'[τ].f'[τ]], {τ, 0, 1}];
invarclength = First@NDSolve[{D[$t[s], s] == 1/Sqrt[f'[$t[s]].f'[$t[s]]], $t[0] == 0},
$t, {s, 0, totalarclength}];
ds = 0.12;
fs = Scaled[0.08];
Manipulate[
Show[
ParametricPlot[f[t], {t, 0, 1}],
Graphics[{
Table[Text[Style[txt1[[n]], "Text", FontSize -> fs],
f[$t[Mod[s0 + n ds, totalarclength]] /. invarclength],
{0, -1.1},
f'[$t[Mod[s0 + n ds, totalarclength]] /. invarclength]],
{n, Length[txt1]}],
Table[Text[Style[txt2[[n]], "Text", FontSize -> fs],
f[$t[Mod[s0 + n ds, totalarclength]] /. invarclength],
{0, 1.1},
f'[$t[Mod[s0 + n ds, totalarclength]] /. invarclength]],
{n, Length[txt2]}]}],
PlotRangePadding -> Scaled[0.09]
],
{s0, 0, totalarclength}
]
Computing the arclength can help space the characters out. As far as I know, Mathematica does not provide access to character widths, so that equal spacing is probably as good as one can do easily. As someone has remarked, tight curvatures pose a problem.
Addendum
One of Alexey Popkov's comments suggested the following modification, with help from the FilledCurve doc page. The glyphs are distorted by the curvature, and tight curvatures cause inversion.
txtbase = ImportString[ExportString["some movable text", "PDF"], "PDF"];
txt = First@First@txtbase;
xRange = -Subtract @@ First[PlotRange /. First@AbsoluteOptions[txtbase, PlotRange]];
c[t_] := {Cos[2 π t], Sin[6 π t]};
totalarclength = NIntegrate[Sqrt[c'[τ].c'[τ]], {τ, 0, 1}];
invarclength = First@NDSolve[{D[$t[s], s] == 1/Sqrt[c'[$t[s]].c'[$t[s]]], $t[0] == 0},
$t, {s, 0, totalarclength}];
NN[t_] := {{0, -1}, {1, 0}}.c'[t]/Sqrt[c'[t].c'[t]];
maptext[s_, Δn_] := With[{t = $t[Mod[s, totalarclength]] /. invarclength},
c[t] + Δn NN[t]];
Manipulate[
Show[
ParametricPlot[c[t], {t, 0, 1}],
Graphics[
Dynamic@{txt /. {x_Real, y_Real} :> maptext[-fs x/xRange + s0, -fs y/xRange + ΔN]}],
PlotRange -> 1.5
],
{{ΔN, 0.1}, -1, 1},
{{s0, 6.45}, 0, totalarclength},
{{fs, 2, "font scale"}, 0.1, 5}
]
Comments
Post a Comment