-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathparshape.tex
More file actions
176 lines (137 loc) · 6.27 KB
/
Copy pathparshape.tex
File metadata and controls
176 lines (137 loc) · 6.27 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
\input{config}
\input{macros}
\input{lorem}
%%% obsah
\title Visual \char`\\parshape Editor for \TeX
To try out the project, go to \ulink[https://parshape.com]{parshape.com} or checkout the
code at \ulink[https://github.com/tmscer/parshape]{github.com/tmscer/parshape}.
See this file's source at \ulink[https://github.com/tmscer/parshape/blob/master/doc/parshape.tex]{github.com/tmscer/parshape/blob/master/doc/parshape.tex}.
\subtitle The problem
\macro{parshape} allows a {\TeX} user to shape their paragraph.
The following block of text was shaped using
\macro{parshape 3 2cm 12cm 4cm 320pt 2cm 11cm}:
\parshape 3
2cm 12cm
4cm 320pt
2cm 11cm
\noindent
Notice the first line is moved by {\bf2cm} to the right and is {\bf12cm} long.
The second line is moved by {\bf4cm} to the right and is {\bf320pt} long.
The third line is moved by {\bf2cm} to the right and is {\bf11cm} long.
Creating just these 3 lines took the author quite a while.
Trying to fit a paragraph around a more complex shape like an image, table or
some weird shape is cumbersome and time consuming. Other software like MS Word
help the user by being a visual tool where users get immediate feedback.
{\TeX}, of course, isn't that.
\subtitle The solution
Below you can see two versions of the {\tt<Canvas>} component of the web-based solution.
\smallskip
\hfil
\hbox{\picw=8cm \inspic{before-bezier.png} \picw=8cm \inspic{after-bezier.png}}
\hfil
On the left is the {\it before} state. After the user {\it right clicks} at the bottom end
of the blue Bézier curve. The new state shown on the right will emerge. A similar edit can be
made to the right edge of every line of the paragraph and with other geometric shapes.
\subtitle Configuration
The \ulink[https://parshape.com]{web app} accepts several {\TeX} parameters to mimick a page.
To get their values, insert the left column of the following snippet into your source file.
The right column has values of this document.
\begmulti 2
{\tt
\def\thevalue#1{#1: \macro{the}\macro{#1} \macro{nl}}
\macro{tt\char`\{} \nl
\thevalue{pagewidth} \nl
\thevalue{pageheight} \nl
\thevalue{baselineskip} \nl
\thevalue{lineskip} \nl
\thevalue{hsize} \nl
\thevalue{hoffset} \nl
\thevalue{voffset} \nl
\thevalue{pdfhorigin} \nl
\thevalue{pdfvorigin} \nl
\char`\}
}
{\tt
\nl
pagewidth: \the\pagewidth \nl
pageheight: \the\pageheight \nl
baselineskip: \the\baselineskip \nl
lineskip: \the\lineskip \nl
hsize: \the\hsize \nl
hoffset: \the\hoffset \nl
voffset: \the\voffset \nl
pdfhorigin: \the\pdfhorigin \nl
pdfvorigin: \the\pdfvorigin \nl
}
\endmulti
\subtitle An Example
Here's how a paragraph edited using the editor previously shown above can look like
with some extra edits to the right edge of the paragraph:
\exampleparshape
\loremonepar
\subtitle Supported Geometric Shapes and Their Math
The editor currently supports three geometric shapes: lines, half-circles and Bézier curves.
Line has a variant called {\it snap-angle line} which forces the line's angle to be
a multiple of $15^{\circ}$.
Intersection with paragraph lines is always calculated for the middle of the paragraph
according to primitive register \macro{baselineskip}.
The coordinate system has its origin in the left top corner of where the text can start.
X-axis is positive to the right and y-axis is positive in the downward direction.
\curvetitle Line
This is the most simple geometric shape. Given two points, it is possible to get an equation
of the form $y = ax + b,\;a,\!b \in {\bbchar R}$. Then, for every paragraph line, which are all
horizontal of the form $y = baselineskip \cdot (i + 0.5)$, we can solve for $x$
provided the drawn line isn't vertical. In all cases bounding box of the drawn line is checked
in order to avoid the change of paragraph lines outside it.
\curvetitle Snap-angle Line
The equation remains the same as for the normal line. However, we have to recalculate the second placed
point such that the line's angle is a multiple of $\ang{15}$ degrees or $\pi \over 12$ radians.
We calculate the line's angle using using $\theta = \tan^{-1}{a}$ and round it.
After that we {\it rotate} the second placed point using trigonometric function
$\cos$ for x-coordinates $\sin$ for y-coordiantes.
\curvetitle Bézier Curve
For $n+1$ points, coordinates of {\it some} point on the Bézier curve would be:
$$
\vec{B_t} =
t^0 (1-t)^n \cdot {\bf P_0} +
t^1 (1-t)^{n-1} {n \choose 1} \cdot {\bf P_1} +
\cdots +
t^k (1-t)^{n-k} {n \choose k} \cdot {\bf P_k} +
\cdots +
t^n (1-t)^0 {\bf P_n}
$$
where $\bf P_i$ are placed points and $k \in {\bbchar N}_0$ is an iterator from $0$ to $n$.
Parameter $t$ is unique for each point and it is from the interval $[0,1]$.
The more accurate the approximation needs to be, the smaller $t_{step}$ should be.
Intersection algorithm for Bézier curves does the following: for every paragraph
line, intersect with all lines between adjacent points of the Bézier curve approximation
and choose the leftmost or rightmost based on whether we're shaping the left edge or the
right edge of the paragraph. Essentially we're reusing the previous algorithm for lines
several times.
\curvetitle Half-circles
There are four cases to handle:
1) we're shaping the {\it left} edge with the {\it left} half a full circle,
2) we're shaping the {\it left} edge with the {\it right} half a full circle,
3) we're shaping the {\it right} edge with the {\it left} half a full circle,
4) we're shaping the {\it right} edge with the {\it right} half a full circle.
That can be achieved by knowing how to intersect a full circle with a horizontal
paragraph line and then choosing which edge of the paragraph to change and choosing
whether to use the left or the right half-circle.
Equation for a circle with an origin $(x_0, y_0)$ has the form
$$
(x - x_0)^2 + (y - y_0)^2 = r^2
$$
where $r$ stands for radius. Given a paragraph line $y = c,\;c\in{\bbchar R}$, we can solve
for $x$:
$$
\eqalignno{
(x - x_0)^2 + (c - y_0)^2 &= r^2 \cr
x^2 -2x_0 + x_0^2+ (c - y_0)^2 &= r^2 \cr
x^2 -2x_0x + (x_0^2+ (c - y_0)^2 - r^2) &= 0
}
$$
That's nothing more than an ordinary quadratic equation. When determinant $D < 0$,
the circle has no intersection with the current paragraph line. When determinant $D = 0$,
there is only one intersection. When determinant $D > 0$, there are two intersections
and we have to choose based on which half-circle we're using.
\bye