1 /* This file is part of the GNU plotutils package.  Copyright (C) 1995,
2    1996, 1997, 1998, 1999, 2000, 2005, 2008, Free Software Foundation, Inc.
3 
4    The GNU plotutils package is free software.  You may redistribute it
5    and/or modify it under the terms of the GNU General Public License as
6    published by the Free Software foundation; either version 2, or (at your
7    option) any later version.
8 
9    The GNU plotutils package is distributed in the hope that it will be
10    useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
11    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12    General Public License for more details.
13 
14    You should have received a copy of the GNU General Public License along
15    with the GNU plotutils package; see the file COPYING.  If not, write to
16    the Free Software Foundation, Inc., 51 Franklin St., Fifth Floor,
17    Boston, MA 02110-1301, USA. */
18 
19 /* This file contains all of libplot's low-level code for constructing and
20    manipulating paths, both simple and compound.  It includes functions
21    that construct polygonal and Bezier approximations to a given path.
22    They are used by Plotters whose output format does not support all of
23    libplot's graphics primitives. */
24 
25 /* E.g., _fakearc() draws polygonal approximations to circular and elliptic
26    quarter-arcs.  Each polygonal approximation will contain
27    2**NUM_ARC_SUBDIVISIONS line segments.
28 
29    Similarly, polygonal approximations to quadratic and cubic Beziers will
30    contain no more than 2**MAX_NUM_BEZIER2_SUBDIVISIONS and
31    2**MAX_NUM_BEZIER3_SUBDIVISIONS line segments.  However, each bisection
32    algorithm used for drawing a Bezier normally usually its recursion based
33    on a relative flatness criterion (see below). */
34 
35 #include "sys-defines.h"
36 #include "extern.h"
37 #include "g_arc.h"		/* for chord table */
38 
39 /* Number of times a circular arc or quarter-ellipse will be recursively
40    subdivided.  Two raised to this power is the number of line segments
41    that the polygonalization will contain. */
42 
43 /* NOTE: the maximum allowed value for NUM_ARC_SUBDIVISIONS is
44    TABULATED_ARC_SUBDIVISIONS (i.e., the size of the chordal deviation
45    table for a quarter-circle or quarter-ellipse, defined in g_arc.h). */
46 #define NUM_ARC_SUBDIVISIONS 5
47 
48 /* Maximum number of times quadratic and cubic Beziers will be recursively
49    subdivided.  For Beziers we use an adaptive algorithm, in which
50    bisection stops when a specified relative flatness has been reached.
51    But these parameters provide a hard cutoff, which overrides the relative
52    flatness end condition. */
53 #define MAX_NUM_BEZIER2_SUBDIVISIONS 6
54 #define MAX_NUM_BEZIER3_SUBDIVISIONS 7
55 
56 /* The relative flatness parameters. */
57 #define REL_QUAD_FLATNESS 5e-4
58 #define REL_CUBIC_FLATNESS 5e-4
59 
60 #define DATAPOINTS_BUFSIZ PL_MAX_UNFILLED_PATH_LENGTH
61 #define DIST(p0,p1) (sqrt( ((p0).x - (p1).x)*((p0).x - (p1).x) \
62 			  + ((p0).y - (p1).y)*((p0).y - (p1).y)))
63 
64 #define MIDWAY(x0, x1) (0.5 * ((x0) + (x1)))
65 
66 /* forward references */
67 static void _prepare_chord_table (double sagitta, double custom_chord_table[TABULATED_ARC_SUBDIVISIONS]);
68 static void _fakearc (plPath *path, plPoint p0, plPoint p1, int arc_type, const double *custom_chord_table, const double m[4]);
69 
70 /* ctor for plPath class; constructs an empty plPath, with type set to
71    PATH_SEGMENT_LIST (default type) */
72 plPath *
_new_plPath(void)73 _new_plPath (void)
74 {
75   plPath *path;
76 
77   path = (plPath *)_pl_xmalloc (sizeof (plPath));
78 
79   path->type = PATH_SEGMENT_LIST;
80   path->segments = (plPathSegment *)NULL;
81   path->segments_len = 0;	/* number of slots allocated */
82   path->num_segments = 0;	/* number of slots occupied */
83 
84   path->primitive = false;
85   path->llx = DBL_MAX;
86   path->lly = DBL_MAX;
87   path->urx = -(DBL_MAX);
88   path->ury = -(DBL_MAX);
89 
90   return path;
91 }
92 
93 /* dtor for plPath class */
94 void
_delete_plPath(plPath * path)95 _delete_plPath (plPath *path)
96 {
97   if (path == (plPath *)NULL)
98     return;
99 
100   if (path->type == PATH_SEGMENT_LIST
101       && path->segments_len > 0) /* number of slots allocated */
102     free (path->segments);
103   free (path);
104 }
105 
106 /* reset function for plPath class */
107 void
_reset_plPath(plPath * path)108 _reset_plPath (plPath *path)
109 {
110   if (path == (plPath *)NULL)
111     return;
112 
113   if (path->type == PATH_SEGMENT_LIST
114       && path->segments_len > 0) /* number of slots allocated */
115     free (path->segments);
116   path->segments = (plPathSegment *)NULL;
117   path->segments_len = 0;
118   path->type = PATH_SEGMENT_LIST; /* restore to default */
119   path->num_segments = 0;
120 
121   path->primitive = false;
122   path->llx = DBL_MAX;
123   path->lly = DBL_MAX;
124   path->urx = -(DBL_MAX);
125   path->ury = -(DBL_MAX);
126 }
127 
128 void
_add_moveto(plPath * path,plPoint p)129 _add_moveto (plPath *path, plPoint p)
130 {
131   if (path == (plPath *)NULL)
132     return;
133 
134   if (path->type != PATH_SEGMENT_LIST || path->num_segments > 0)
135     return;
136 
137   /* empty, so allocate a segment buffer */
138   path->segments = (plPathSegment *)
139     _pl_xmalloc (DATAPOINTS_BUFSIZ * sizeof(plPathSegment));
140   path->segments_len = DATAPOINTS_BUFSIZ;
141 
142   path->segments[0].type = S_MOVETO;
143   path->segments[0].p = p;
144   path->num_segments = 1;
145 
146   path->llx = p.x;
147   path->lly = p.y;
148   path->urx = p.x;
149   path->ury = p.y;
150 }
151 
152 void
_add_line(plPath * path,plPoint p)153 _add_line (plPath *path, plPoint p)
154 {
155   if (path == (plPath *)NULL)
156     return;
157 
158   if (path->type != PATH_SEGMENT_LIST || path->num_segments == 0)
159     return;
160 
161   if (path->num_segments == 0)
162     /* empty, so allocate a segment buffer */
163     {
164       path->segments = (plPathSegment *)
165 	_pl_xmalloc (DATAPOINTS_BUFSIZ * sizeof(plPathSegment));
166       path->segments_len = DATAPOINTS_BUFSIZ;
167     }
168 
169   if (path->num_segments == path->segments_len)
170     /* full, so reallocate */
171     {
172       path->segments = (plPathSegment *)
173 	_pl_xrealloc (path->segments,
174 			2 * path->segments_len * sizeof(plPathSegment));
175       path->segments_len *= 2;
176     }
177 
178   path->segments[path->num_segments].type = S_LINE;
179   path->segments[path->num_segments].p = p;
180   path->num_segments++;
181 
182   path->llx = DMIN(path->llx, p.x);
183   path->lly = DMIN(path->lly, p.y);
184   path->urx = DMAX(path->urx, p.x);
185   path->ury = DMAX(path->ury, p.y);
186 }
187 
188 void
_add_closepath(plPath * path)189 _add_closepath (plPath *path)
190 {
191   if (path == (plPath *)NULL)
192     return;
193 
194   if (path->type != PATH_SEGMENT_LIST || path->num_segments == 0)
195     return;
196 
197   if (path->num_segments == 0)	/* meaningless */
198     return;
199 
200   if (path->num_segments == path->segments_len)
201     /* full, so reallocate */
202     {
203       path->segments = (plPathSegment *)
204 	_pl_xrealloc (path->segments,
205 			2 * path->segments_len * sizeof(plPathSegment));
206       path->segments_len *= 2;
207     }
208 
209   path->segments[path->num_segments].type = S_CLOSEPATH;
210   path->segments[path->num_segments].p = path->segments[0].p;
211   path->num_segments++;
212 }
213 
214 void
_add_bezier2(plPath * path,plPoint pc,plPoint p)215 _add_bezier2 (plPath *path, plPoint pc, plPoint p)
216 {
217   if (path == (plPath *)NULL)
218     return;
219 
220   if (path->type != PATH_SEGMENT_LIST || path->num_segments == 0)
221     return;
222 
223   if (path->num_segments == 0)
224     /* empty, so allocate a segment buffer */
225     {
226       path->segments = (plPathSegment *)
227 	_pl_xmalloc (DATAPOINTS_BUFSIZ * sizeof(plPathSegment));
228       path->segments_len = DATAPOINTS_BUFSIZ;
229     }
230 
231   if (path->num_segments == path->segments_len)
232     /* full, so reallocate */
233     {
234       path->segments = (plPathSegment *)
235 	_pl_xrealloc (path->segments,
236 			2 * path->segments_len * sizeof(plPathSegment));
237       path->segments_len *= 2;
238     }
239 
240   path->segments[path->num_segments].type = S_QUAD;
241   path->segments[path->num_segments].p = p;
242   path->segments[path->num_segments].pc = pc;
243   path->num_segments++;
244 }
245 
246 void
_add_bezier3(plPath * path,plPoint pc,plPoint pd,plPoint p)247 _add_bezier3 (plPath *path, plPoint pc, plPoint pd, plPoint p)
248 {
249   if (path == (plPath *)NULL)
250     return;
251 
252   if (path->type != PATH_SEGMENT_LIST || path->num_segments == 0)
253     return;
254 
255   if (path->num_segments == 0)
256     /* empty, so allocate a segment buffer */
257     {
258       path->segments = (plPathSegment *)
259 	_pl_xmalloc (DATAPOINTS_BUFSIZ * sizeof(plPathSegment));
260       path->segments_len = DATAPOINTS_BUFSIZ;
261     }
262 
263   if (path->num_segments == path->segments_len)
264     /* full, so reallocate */
265     {
266       path->segments = (plPathSegment *)
267 	_pl_xrealloc (path->segments,
268 			2 * path->segments_len * sizeof(plPathSegment));
269       path->segments_len *= 2;
270     }
271 
272   path->segments[path->num_segments].type = S_CUBIC;
273   path->segments[path->num_segments].p = p;
274   path->segments[path->num_segments].pc = pc;
275   path->segments[path->num_segments].pd = pd;
276   path->num_segments++;
277 }
278 
279 void
_add_arc(plPath * path,plPoint pc,plPoint p1)280 _add_arc (plPath *path, plPoint pc, plPoint p1)
281 {
282   if (path == (plPath *)NULL)
283     return;
284 
285   if (path->type != PATH_SEGMENT_LIST || path->num_segments == 0)
286     return;
287 
288   if (path->num_segments == 0)
289     /* empty, so allocate a segment buffer */
290     {
291       path->segments = (plPathSegment *)
292 	_pl_xmalloc (DATAPOINTS_BUFSIZ * sizeof(plPathSegment));
293       path->segments_len = DATAPOINTS_BUFSIZ;
294     }
295 
296   if (path->num_segments == path->segments_len)
297     /* full, so reallocate */
298     {
299       path->segments = (plPathSegment *)
300 	_pl_xrealloc (path->segments,
301 			2 * path->segments_len * sizeof(plPathSegment));
302       path->segments_len *= 2;
303     }
304 
305   path->segments[path->num_segments].type = S_ARC;
306   path->segments[path->num_segments].p = p1;
307   path->segments[path->num_segments].pc = pc;
308   path->num_segments++;
309 }
310 
311 void
_add_ellarc(plPath * path,plPoint pc,plPoint p1)312 _add_ellarc (plPath *path, plPoint pc, plPoint p1)
313 {
314   if (path == (plPath *)NULL)
315     return;
316 
317   if (path->type != PATH_SEGMENT_LIST || path->num_segments == 0)
318     return;
319 
320   if (path->num_segments == 0)
321     /* empty, so allocate a segment buffer */
322     {
323       path->segments = (plPathSegment *)
324 	_pl_xmalloc (DATAPOINTS_BUFSIZ * sizeof(plPathSegment));
325       path->segments_len = DATAPOINTS_BUFSIZ;
326     }
327 
328   if (path->num_segments == path->segments_len)
329     /* full, so reallocate */
330     {
331       path->segments = (plPathSegment *)
332 	_pl_xrealloc (path->segments,
333 			2 * path->segments_len * sizeof(plPathSegment));
334       path->segments_len *= 2;
335     }
336 
337   path->segments[path->num_segments].type = S_ELLARC;
338   path->segments[path->num_segments].p = p1;
339   path->segments[path->num_segments].pc = pc;
340   path->num_segments++;
341 }
342 
343 void
_add_box(plPath * path,plPoint p0,plPoint p1,bool clockwise)344 _add_box (plPath *path, plPoint p0, plPoint p1, bool clockwise)
345 {
346   if (path == (plPath *)NULL)
347     return;
348 
349   if (path->type != PATH_SEGMENT_LIST || path->num_segments > 0)
350     return;
351 
352   path->type = PATH_BOX;
353   path->p0 = p0;
354   path->p1 = p1;
355   path->clockwise = clockwise;
356 
357   path->llx = DMIN(path->llx, p0.x);
358   path->lly = DMIN(path->lly, p0.y);
359   path->urx = DMAX(path->urx, p0.x);
360   path->ury = DMAX(path->ury, p0.y);
361 
362   path->llx = DMIN(path->llx, p1.x);
363   path->lly = DMIN(path->lly, p1.y);
364   path->urx = DMAX(path->urx, p1.x);
365   path->ury = DMAX(path->ury, p1.y);
366 }
367 
368 void
_add_circle(plPath * path,plPoint pc,double radius,bool clockwise)369 _add_circle (plPath *path, plPoint pc, double radius, bool clockwise)
370 {
371   if (path == (plPath *)NULL)
372     return;
373 
374   if (path->type != PATH_SEGMENT_LIST || path->num_segments > 0)
375     return;
376 
377   path->type = PATH_CIRCLE;
378   path->pc = pc;
379   path->radius = radius;
380   path->clockwise = clockwise;
381 }
382 
383 void
_add_ellipse(plPath * path,plPoint pc,double rx,double ry,double angle,bool clockwise)384 _add_ellipse (plPath *path, plPoint pc, double rx, double ry, double angle, bool clockwise)
385 {
386   if (path == (plPath *)NULL)
387     return;
388 
389   if (path->type != PATH_SEGMENT_LIST || path->num_segments > 0)
390     return;
391 
392   path->type = PATH_ELLIPSE;
393   path->pc = pc;
394   path->rx = rx;
395   path->ry = ry;
396   path->angle = angle;
397   path->clockwise = clockwise;
398 }
399 
400 /* Draw a polygonal approximation to the circular arc from p0 to p1, with
401    center pc, by calling _fakearc(), which in turn repeatedly calls
402    _add_line().  It is assumed that p0 and p1 are distinct.  It is assumed
403    that pc is on the perpendicular bisector of the line segment joining
404    them, and that the graphics cursor is initially located at p0. */
405 void
_add_arc_as_lines(plPath * path,plPoint pc,plPoint p1)406 _add_arc_as_lines (plPath *path, plPoint pc, plPoint p1)
407 {
408   /* starting point */
409   plPoint p0;
410   /* bisection point of arc, and midpoint of chord */
411   plPoint pb, pm;
412   /* rotation matrix */
413   double m[4];
414   /* other variables */
415   plVector v, v0, v1;
416   double radius, sagitta;
417   double cross, orientation;
418   /* handcrafted relative chordal deviation table, for this arc */
419   double custom_chord_table[TABULATED_ARC_SUBDIVISIONS];
420 
421   if (path == (plPath *)NULL)
422     return;
423 
424   if (path->type != PATH_SEGMENT_LIST || path->num_segments == 0)
425     return;
426 
427   /* determine starting point */
428   p0 = path->segments[path->num_segments - 1].p;
429 
430   if (p0.x == p1.x && p0.y == p1.y)
431     /* zero-length arc, draw as zero-length line segment */
432     _add_line (path, p0);
433 
434   else
435     /* genuine polygonal approximation */
436     {
437       /* vectors from pc to p0, and pc to p1 */
438       v0.x = p0.x - pc.x;
439       v0.y = p0.y - pc.y;
440       v1.x = p1.x - pc.x;
441       v1.y = p1.y - pc.y;
442 
443       /* cross product, zero if points are collinear */
444       cross = v0.x * v1.y - v1.x * v0.y;
445 
446       /* Compute orientation.  Note libplot convention: if p0, p1, pc are
447 	 collinear then arc goes counterclockwise from p0 to p1. */
448       orientation = (cross >= 0.0 ? 1.0 : -1.0);
449 
450       radius = DIST(pc, p0);	/* radius is distance to p0 or p1 */
451 
452       pm.x = 0.5 * (p0.x + p1.x); /* midpoint of chord from p0 to p1 */
453       pm.y = 0.5 * (p0.y + p1.y);
454 
455       v.x = p1.x - p0.x;	/* chord vector from p0 to p1 */
456       v.y = p1.y - p0.y;
457 
458       _vscale(&v, radius);
459       pb.x = pc.x + orientation * v.y; /* bisection point of arc */
460       pb.y = pc.y - orientation * v.x;
461 
462       sagitta = DIST(pb, pm) / radius;
463 
464       /* fill in entries of chordal deviation table for this user-defined
465          sagitta */
466       _prepare_chord_table (sagitta, custom_chord_table);
467 
468       /* call _fakearc(), using for `rotation' matrix m[] a clockwise or
469 	 counterclockwise rotation by 90 degrees, depending on orientation */
470 
471       m[0] = 0.0, m[1] = orientation, m[2] = -orientation, m[3] = 0.0;
472       _fakearc (path, p0, p1, USER_DEFINED_ARC, custom_chord_table, m);
473     }
474 }
475 
476 /* Draw a polygonal approximation to a quarter-ellipse from p0 to p1, by
477    calling _fakearc(), which in turn repeatedly calls _add_line().  pc is
478    the center of the arc, and p0, p1, pc are assumed not to be collinear.
479    It is assumed that the graphics cursor is located at p0 when this
480    function is called.
481 
482    The control triangle for the elliptic arc will have vertices p0, p1, and
483    K = p0 + (p1 - pc) = p1 + (p0 - pc).  The arc will pass through p0 and
484    p1, and will be tangent at p0 to the edge from p0 to K, and at p1 to the
485    edge from p1 to K. */
486 void
_add_ellarc_as_lines(plPath * path,plPoint pc,plPoint p1)487 _add_ellarc_as_lines (plPath *path, plPoint pc, plPoint p1)
488 {
489   plPoint p0;
490   plVector v0, v1;
491   double cross;
492   double m[4];
493 
494   if (path == (plPath *)NULL)
495     return;
496 
497   if (path->type != PATH_SEGMENT_LIST || path->num_segments == 0)
498     return;
499 
500   /* determine starting point */
501   p0 = path->segments[path->num_segments - 1].p;
502 
503   /* vectors from pc to p0, and pc to p1 */
504   v0.x = p0.x - pc.x;
505   v0.y = p0.y - pc.y;
506   v1.x = p1.x - pc.x;
507   v1.y = p1.y - pc.y;
508 
509   /* cross product */
510   cross = v0.x * v1.y - v1.x * v0.y;
511   if (FROUND(cross) == 0.0)
512     /* collinear points, draw line segment from p0 to p1
513        (not quite right, could be bettered) */
514     _add_line (path, p1);
515   else
516     {
517       /* `rotation' matrix (it maps v0 -> -v1 and v1 -> v0) */
518       m[0] = - (v0.x * v0.y + v1.x * v1.y) / cross;
519       m[1] = (v0.x * v0.x + v1.x * v1.x) / cross;
520       m[2] = - (v0.y * v0.y + v1.y * v1.y) / cross;
521       m[3] = (v0.x * v0.y + v1.x * v1.y) / cross;
522 
523       /* draw polyline inscribed in the quarter-ellipse */
524       _fakearc (path, p0, p1, QUARTER_ARC, (double *)NULL, m);
525     }
526 }
527 
528 /* A function that approximates a circular arc by a cubic Bezier.  The
529    approximation used is a standard one.  E.g., a quarter circle extending
530    from (1,0) to (0,1), with center (0,0), would be approximated by a cubic
531    Bezier with control points (1,KAPPA) and (KAPPA,1).  Here KAPPA =
532    (4/3)[sqrt(2)-1] = 0.552284749825, approximately.  The cubic Bezier will
533    touch the quarter-circle along the line x=y.
534 
535    For a quarter-circle, the maximum relative error in r as a function of
536    theta is about 2.7e-4.  The error in r has the same sign, for all theta. */
537 
538 /* According to Berthold K. P. Horn <bkph@ai.mit.edu>, the general formula
539    for KAPPA, for a radius-1 circular arc (not necessary a quarter-circle),
540 
541    KAPPA = (4/3)sqrt[(1-cos H)/(1+cos H)]
542    	 = (4/3)[1-cos H]/[sin H] = (4/3)[sin H]/[1+cosH]
543 
544    where H is half the angle subtended by the arc.  H=45 degrees for a
545    quarter circle.  This is the formula we use. */
546 
547 /* Louis Vosloo <support@yandy.com> points out that for a quarter-circle,
548    the value 0.55228... for KAPPA is, for some purposes, sub-optimal.  By
549    dropping the requirement that the quarter-circle and the Bezier touch
550    each other along the symmetry line x=y, one can slightly decrease the
551    maximum relative error.  He says 0.5541... is the best possible choice.
552    He doesn't have an improved value of KAPPA for a general arc, though.  */
553 
554 void
_add_arc_as_bezier3(plPath * path,plPoint pc,plPoint p1)555 _add_arc_as_bezier3 (plPath *path, plPoint pc, plPoint p1)
556 {
557   plPoint p0;
558   plVector v0, v1;
559 
560   if (path == (plPath *)NULL)
561     return;
562 
563   if (path->type != PATH_SEGMENT_LIST || path->num_segments == 0)
564     return;
565 
566   /* determine starting point */
567   p0 = path->segments[path->num_segments - 1].p;
568 
569   /* vectors to starting, ending points */
570   v0.x = p0.x - pc.x;
571   v0.y = p0.y - pc.y;
572   v1.x = p1.x - pc.x;
573   v1.y = p1.y - pc.y;
574 
575   if ((v0.x == 0.0 && v0.y == 0.0) || (v1.x == 0.0 && v1.y == 0.0)
576       || (v0.x == v1.x && v0.y == v1.y))
577     /* degenerate case */
578     _add_line (path, p1);
579   else
580     /* normal case */
581     {
582       double oldangle, newangle, anglerange;
583       double cross;
584       int orientation;
585 
586       /* cross product, zero if points are collinear */
587       cross = v0.x * v1.y - v1.x * v0.y;
588 
589       /* Compute orientation.  Note libplot convention: if p0, p1, pc
590 	 are collinear then arc goes counterclockwise from p0 to p1. */
591       orientation = (cross >= 0.0 ? 1 : -1);
592 
593       /* compute signed subtended angle */
594       oldangle = _xatan2 (v0.y, v0.x);
595       newangle = _xatan2 (v1.y, v1.x);
596       anglerange = newangle - oldangle;
597       if (anglerange > M_PI)
598 	anglerange -= (2 * M_PI);
599       if (anglerange <= -(M_PI))
600 	anglerange += (2 * M_PI);
601 
602       if (FABS(anglerange) > 0.51 * M_PI)
603 	/* subtended angle > 0.51 * pi, so split arc in two and recurse,
604 	   since Bezier approximation isn't very good for angles much
605 	   greater than 90 degrees */
606 	{
607 	  double radius;
608 	  plPoint pb;
609 	  plVector v;
610 
611 	  radius = DIST(pc, p0); /* radius is distance to p0 or p1 */
612 
613 	  v.x = p1.x - p0.x;	/* chord vector from p0 to p1 */
614 	  v.y = p1.y - p0.y;
615 
616 	  _vscale(&v, radius);
617 	  pb.x = pc.x + orientation * v.y; /* bisection point of arc */
618 	  pb.y = pc.y - orientation * v.x;
619 
620 	  _add_arc_as_bezier3 (path, pc, pb);
621 	  _add_arc_as_bezier3 (path, pc, p1);
622 	}
623       else
624 	/* subtended angle <= 0.51 * pi, so a single Bezier suffices */
625 	{
626 	  double halfangle, sinhalf, coshalf, kappa;
627 	  plPoint pc_bezier3, pd_bezier3;
628 
629 	  halfangle = 0.5 * FABS(anglerange);
630 	  sinhalf = sin (halfangle);
631 	  coshalf = cos (halfangle);
632 	  /* compute kappa using either of two formulae, depending on
633 	     numerical stability */
634 	  if (FABS(sinhalf) < 0.5)
635 	    kappa = (4.0/3.0) * sinhalf / (1.0 + coshalf);
636 	  else
637 	    kappa = (4.0/3.0) * (1.0 - coshalf) / sinhalf;
638 
639 	  pc_bezier3.x = p0.x - kappa * orientation * v0.y;
640 	  pc_bezier3.y = p0.y + kappa * orientation * v0.x;
641 	  pd_bezier3.x = p1.x + kappa * orientation * v1.y;
642 	  pd_bezier3.y = p1.y - kappa * orientation * v1.x;
643 	  _add_bezier3 (path, pc_bezier3, pd_bezier3, p1);
644 	}
645     }
646 }
647 
648 #define KAPPA_FOR_QUARTER_CIRCLE 0.552284749825
649 
650 void
_add_ellarc_as_bezier3(plPath * path,plPoint pc,plPoint p1)651 _add_ellarc_as_bezier3 (plPath *path, plPoint pc, plPoint p1)
652 {
653   plPoint p0, pc_bezier3, pd_bezier3;
654   plVector v0, v1;
655 
656   if (path == (plPath *)NULL)
657     return;
658 
659   if (path->type != PATH_SEGMENT_LIST || path->num_segments == 0)
660     return;
661 
662   /* determine starting point */
663   p0 = path->segments[path->num_segments - 1].p;
664 
665   /* vectors to starting, ending points */
666   v0.x = p0.x - pc.x;
667   v0.y = p0.y - pc.y;
668   v1.x = p1.x - pc.x;
669   v1.y = p1.y - pc.y;
670 
671   /* replace by cubic Bezier, with computed control points */
672   pc_bezier3.x = p0.x + KAPPA_FOR_QUARTER_CIRCLE * v1.x;
673   pc_bezier3.y = p0.y + KAPPA_FOR_QUARTER_CIRCLE * v1.y;
674   pd_bezier3.x = p1.x + KAPPA_FOR_QUARTER_CIRCLE * v0.x;
675   pd_bezier3.y = p1.y + KAPPA_FOR_QUARTER_CIRCLE * v0.y;
676   _add_bezier3 (path, pc_bezier3, pd_bezier3, p1);
677 }
678 
679 /* Approximate a quadratic Bezier by a polyline: standard deCasteljau
680    bisection algorithm.  However, we stop subdividing when an appropriate
681    metric of the quadratic Bezier to be drawn is sufficiently small.  If
682    (p0,p1,p2) defines the quadratic Bezier, we require that the length of
683    p0-2*p1+p2 be less than REL_QUAD_FLATNESS times the distance between the
684    endpoints of the original Bezier. */
685 
686 void
_add_bezier2_as_lines(plPath * path,plPoint pc,plPoint p)687 _add_bezier2_as_lines (plPath *path, plPoint pc, plPoint p)
688 {
689   plPoint r0[MAX_NUM_BEZIER2_SUBDIVISIONS + 1], r1[MAX_NUM_BEZIER2_SUBDIVISIONS + 1], r2[MAX_NUM_BEZIER2_SUBDIVISIONS + 1];
690   int level[MAX_NUM_BEZIER2_SUBDIVISIONS + 1];
691   int n = 0;	/* index of top of stack, < MAX_NUM_BEZIER2_SUBDIVISIONS */
692   int segments_drawn = 0;
693   plPoint p0;
694   double sqdist, max_squared_length;
695 
696   if (path == (plPath *)NULL)
697     return;
698 
699   if (path->type != PATH_SEGMENT_LIST || path->num_segments == 0)
700     return;
701 
702   /* determine starting point */
703   p0 = path->segments[path->num_segments - 1].p;
704 
705   /* squared distance between p0 and p */
706   sqdist = (p.x - p0.x) * (p.x - p0.x) + (p.y - p0.y) * (p.y - p0.y);
707   max_squared_length = REL_QUAD_FLATNESS * REL_QUAD_FLATNESS * sqdist;
708 
709   r0[0] = p0;
710   r1[0] = pc;
711   r2[0] = p;
712   level[0] = 0;
713   while (n >= 0)		/* i.e. while stack is nonempty */
714     {
715       int current_level;
716       plPoint q0, q1, q2;
717 
718       current_level = level[n];
719       q0 = r0[n];
720       q1 = r1[n];
721       q2 = r2[n];
722 
723       if (current_level >= MAX_NUM_BEZIER2_SUBDIVISIONS)
724 	/* to avoid stack overflow, draw as line segment */
725 	{
726 	  _add_line (path, q2);
727 	  segments_drawn++;
728 	  n--;
729 	}
730       else
731 	/* maybe bisect the Bezier */
732 	{
733 	  plPoint qq0, qq1;
734 	  plPoint qqq0;
735 	  plVector vec1;
736 
737 	  vec1.x = q0.x - 2 * q1.x + q2.x;
738 	  vec1.y = q0.y - 2 * q1.y + q2.y;
739 
740 	  if (vec1.x * vec1.x + vec1.y * vec1.y < max_squared_length)
741 	    /* very flat Bezier, so draw as line segment */
742 	    {
743 	      _add_line (path, q2);
744 	      segments_drawn++;
745 	      n--;
746 	    }
747 	  else
748 	    /* split Bezier into pair and recurse */
749 	    /* level[n] >= n is an invariant */
750 	    {
751 	      qq0.x = MIDWAY(q0.x, q1.x);
752 	      qq0.y = MIDWAY(q0.y, q1.y);
753 	      qq1.x = MIDWAY(q1.x, q2.x);
754 	      qq1.y = MIDWAY(q1.y, q2.y);
755 
756 	      qqq0.x = MIDWAY(qq0.x, qq1.x);
757 	      qqq0.y = MIDWAY(qq0.y, qq1.y);
758 
759 	      /* first half, deal with next */
760 	      r0[n+1] = q0;
761 	      r1[n+1] = qq0;
762 	      r2[n+1] = qqq0;
763 	      level[n+1] = current_level + 1;
764 
765 	      /* second half, deal with later */
766 	      r0[n] = qqq0;
767 	      r1[n] = qq1;
768 	      r2[n] = q2;
769 	      level[n] = current_level + 1;
770 
771 	      n++;
772 	    }
773 	}
774     }
775 }
776 
777 /* Approximate a cubic Bezier by a polyline: standard deCasteljau bisection
778    algorithm.  However, we stop subdividing when an appropriate metric of
779    the cubic Bezier to be drawn is sufficiently small.  If (p0,p1,p2,p3)
780    defines the cubic Bezier, we require that the lengths of p0-2*p1+p2 and
781    p1-2*p2+p3 be less than REL_CUBIC_FLATNESS times the distance between
782    the endpoints of the original Bezier. */
783 
784 void
_add_bezier3_as_lines(plPath * path,plPoint pc,plPoint pd,plPoint p)785 _add_bezier3_as_lines (plPath *path, plPoint pc, plPoint pd, plPoint p)
786 {
787   plPoint r0[MAX_NUM_BEZIER3_SUBDIVISIONS + 1], r1[MAX_NUM_BEZIER3_SUBDIVISIONS + 1], r2[MAX_NUM_BEZIER3_SUBDIVISIONS + 1], r3[MAX_NUM_BEZIER3_SUBDIVISIONS + 1];
788   int level[MAX_NUM_BEZIER3_SUBDIVISIONS + 1];
789   int n = 0;	/* index of top of stack, < MAX_NUM_BEZIER3_SUBDIVISIONS */
790   int segments_drawn = 0;
791   plPoint p0;
792   double sqdist, max_squared_length;
793 
794   if (path == (plPath *)NULL)
795     return;
796 
797   if (path->type != PATH_SEGMENT_LIST || path->num_segments == 0)
798     return;
799 
800   /* determine starting point */
801   p0 = path->segments[path->num_segments - 1].p;
802 
803   /* squared distance between p0 and p */
804   sqdist = (p.x - p0.x) * (p.x - p0.x) + (p.y - p0.y) * (p.y - p0.y);
805   max_squared_length = REL_CUBIC_FLATNESS * REL_CUBIC_FLATNESS * sqdist;
806 
807   r0[0] = p0;
808   r1[0] = pc;
809   r2[0] = pd;
810   r3[0] = p;
811   level[0] = 0;
812 
813   while (n >= 0)		/* i.e. while stack is nonempty */
814     {
815       int current_level;
816       plPoint q0, q1, q2, q3;
817 
818       current_level = level[n];
819       q0 = r0[n];
820       q1 = r1[n];
821       q2 = r2[n];
822       q3 = r3[n];
823 
824       if (current_level >= MAX_NUM_BEZIER3_SUBDIVISIONS)
825 	/* draw line segment, to avoid stack overflow */
826 	{
827 	  _add_line (path, q3);
828 	  segments_drawn++;
829 	  n--;
830 	}
831       else
832 	/* maybe bisect the Bezier */
833 	{
834 	  plPoint qq0, qq1, qq2;
835 	  plPoint qqq0, qqq1;
836 	  plPoint qqqq0;
837 	  plVector vec1, vec2;
838 
839 	  vec1.x = q0.x - 2 * q1.x + q2.x;
840 	  vec1.y = q0.y - 2 * q1.y + q2.y;
841 	  vec2.x = q1.x - 2 * q2.x + q3.x;
842 	  vec2.y = q1.y - 2 * q2.y + q3.y;
843 
844 	  if (vec1.x * vec1.x + vec1.y * vec1.y < max_squared_length
845 	      && vec2.x * vec2.x + vec2.y * vec2.y < max_squared_length)
846 	    /* very flat Bezier, so draw as line segment */
847 	    {
848 	      _add_line (path, q3);
849 	      segments_drawn++;
850 	      n--;
851 	    }
852 	  else
853 	    /* split Bezier into pair and recurse */
854 	    /* level[n] >= n is an invariant */
855 	    {
856 	      qq0.x = MIDWAY(q0.x, q1.x);
857 	      qq0.y = MIDWAY(q0.y, q1.y);
858 	      qq1.x = MIDWAY(q1.x, q2.x);
859 	      qq1.y = MIDWAY(q1.y, q2.y);
860 	      qq2.x = MIDWAY(q2.x, q3.x);
861 	      qq2.y = MIDWAY(q2.y, q3.y);
862 
863 	      qqq0.x = MIDWAY(qq0.x, qq1.x);
864 	      qqq0.y = MIDWAY(qq0.y, qq1.y);
865 	      qqq1.x = MIDWAY(qq1.x, qq2.x);
866 	      qqq1.y = MIDWAY(qq1.y, qq2.y);
867 
868 	      qqqq0.x = MIDWAY(qqq0.x, qqq1.x);
869 	      qqqq0.y = MIDWAY(qqq0.y, qqq1.y);
870 
871 	      /* first half, deal with next */
872 	      level[n+1] = current_level + 1;
873 	      r0[n+1] = q0;
874 	      r1[n+1] = qq0;
875 	      r2[n+1] = qqq0;
876 	      r3[n+1] = qqqq0;
877 
878 	      /* second half, deal with later */
879 	      level[n] = current_level + 1;
880 	      r0[n] = qqqq0;
881 	      r1[n] = qqq1;
882 	      r2[n] = qq2;
883 	      r3[n] = q3;
884 
885 	      n++;
886 	    }
887 	}
888     }
889 }
890 
891 void
_add_box_as_lines(plPath * path,plPoint p0,plPoint p1,bool clockwise)892 _add_box_as_lines (plPath *path, plPoint p0, plPoint p1, bool clockwise)
893 {
894   bool x_move_is_first;
895   plPoint newpoint;
896 
897   if (path == (plPath *)NULL)
898     return;
899 
900   if (path->type != PATH_SEGMENT_LIST || path->num_segments > 0)
901     return;
902 
903   _add_moveto (path, p0);
904 
905   /* if counterclockwise, would first pen motion be in x direction? */
906   x_move_is_first = ((p1.x >= p0.x && p1.y >= p0.y)
907 		     || (p1.x < p0.x && p1.y < p0.y) ? true : false);
908 
909   if (clockwise)
910     /* take complement */
911     x_move_is_first = (x_move_is_first == true ? false : true);
912 
913   if (x_move_is_first)
914     {
915       newpoint.x = p1.x;
916       newpoint.y = p0.y;
917     }
918   else
919     {
920       newpoint.x = p0.x;
921       newpoint.y = p1.y;
922     }
923   _add_line (path, newpoint);
924 
925   _add_line (path, p1);
926 
927   if (x_move_is_first)
928     {
929       newpoint.x = p0.x;
930       newpoint.y = p1.y;
931     }
932   else
933     {
934       newpoint.x = p1.x;
935       newpoint.y = p0.y;
936     }
937   _add_line (path, newpoint);
938 
939   _add_line (path, p0);
940 
941   path->primitive = true;	/* flag as flattened primitive */
942 }
943 
944 void
_add_ellipse_as_bezier3s(plPath * path,plPoint pc,double rx,double ry,double angle,bool clockwise)945 _add_ellipse_as_bezier3s (plPath *path, plPoint pc, double rx, double ry, double angle, bool clockwise)
946 {
947   plPoint startpoint, newpoint;
948   double theta, costheta, sintheta;
949   double xc, yc;
950 
951   if (path == (plPath *)NULL)
952     return;
953 
954   if (path->type != PATH_SEGMENT_LIST || path->num_segments > 0)
955     return;
956 
957   /* draw ellipse by drawing four elliptic arcs */
958   theta = (M_PI / 180.0) * angle; /* convert to radians */
959   costheta = cos (theta);
960   sintheta = sin (theta);
961 
962   xc = pc.x;
963   yc = pc.y;
964   startpoint.x = xc + rx * costheta;
965   startpoint.y = yc + rx * sintheta;
966   _add_moveto (path, startpoint);
967 
968   if (clockwise)
969     {
970       newpoint.x = xc + ry * sintheta;
971       newpoint.y = yc - ry * costheta;
972     }
973   else
974     {
975       newpoint.x = xc - ry * sintheta;
976       newpoint.y = yc + ry * costheta;
977     }
978   _add_ellarc_as_bezier3 (path, pc, newpoint);
979 
980   newpoint.x = xc - rx * costheta;
981   newpoint.y = yc - rx * sintheta;
982   _add_ellarc_as_bezier3 (path, pc, newpoint);
983 
984   if (clockwise)
985     {
986       newpoint.x = xc - ry * sintheta;
987       newpoint.y = yc + ry * costheta;
988     }
989   else
990     {
991       newpoint.x = xc + ry * sintheta;
992       newpoint.y = yc - ry * costheta;
993     }
994   _add_ellarc_as_bezier3 (path, pc, newpoint);
995 
996   _add_ellarc_as_bezier3 (path, pc, startpoint);
997 
998   path->primitive = true;	/* flag as flattened primitive */
999 }
1000 
1001 void
_add_ellipse_as_ellarcs(plPath * path,plPoint pc,double rx,double ry,double angle,bool clockwise)1002 _add_ellipse_as_ellarcs (plPath *path, plPoint pc, double rx, double ry, double angle, bool clockwise)
1003 {
1004   plPoint startpoint, newpoint;
1005   double theta, costheta, sintheta;
1006   double xc, yc;
1007 
1008   if (path == (plPath *)NULL)
1009     return;
1010 
1011   if (path->type != PATH_SEGMENT_LIST || path->num_segments > 0)
1012     return;
1013 
1014   /* draw ellipse by drawing four elliptic arcs */
1015   theta = (M_PI / 180.0) * angle; /* convert to radians */
1016   costheta = cos (theta);
1017   sintheta = sin (theta);
1018 
1019   xc = pc.x;
1020   yc = pc.y;
1021   startpoint.x = xc + rx * costheta;
1022   startpoint.y = yc + rx * sintheta;
1023   _add_moveto (path, startpoint);
1024 
1025   if (clockwise)
1026     {
1027       newpoint.x = xc + ry * sintheta;
1028       newpoint.y = yc - ry * costheta;
1029     }
1030   else
1031     {
1032       newpoint.x = xc - ry * sintheta;
1033       newpoint.y = yc + ry * costheta;
1034     }
1035   _add_ellarc (path, pc, newpoint);
1036 
1037   newpoint.x = xc - rx * costheta;
1038   newpoint.y = yc - rx * sintheta;
1039   _add_ellarc (path, pc, newpoint);
1040 
1041   if (clockwise)
1042     {
1043       newpoint.x = xc - ry * sintheta;
1044       newpoint.y = yc + ry * costheta;
1045     }
1046   else
1047     {
1048       newpoint.x = xc + ry * sintheta;
1049       newpoint.y = yc - ry * costheta;
1050     }
1051   _add_ellarc (path, pc, newpoint);
1052 
1053   _add_ellarc (path, pc, startpoint);
1054 
1055   path->primitive = true;	/* flag as flattened primitive */
1056 }
1057 
1058 void
_add_ellipse_as_lines(plPath * path,plPoint pc,double rx,double ry,double angle,bool clockwise)1059 _add_ellipse_as_lines (plPath *path, plPoint pc, double rx, double ry, double angle, bool clockwise)
1060 {
1061   plPoint startpoint, newpoint;
1062   double theta, costheta, sintheta;
1063   double xc, yc;
1064 
1065   if (path == (plPath *)NULL)
1066     return;
1067 
1068   if (path->type != PATH_SEGMENT_LIST || path->num_segments > 0)
1069     return;
1070 
1071   /* draw ellipse by drawing four fake elliptic arcs */
1072   theta = (M_PI / 180.0) * angle; /* convert to radians */
1073   costheta = cos (theta);
1074   sintheta = sin (theta);
1075 
1076   xc = pc.x;
1077   yc = pc.y;
1078   startpoint.x = xc + rx * costheta;
1079   startpoint.y = yc + rx * sintheta;
1080   _add_moveto (path, startpoint);
1081 
1082   if (clockwise)
1083     {
1084       newpoint.x = xc + ry * sintheta;
1085       newpoint.y = yc - ry * costheta;
1086     }
1087   else
1088     {
1089       newpoint.x = xc - ry * sintheta;
1090       newpoint.y = yc + ry * costheta;
1091     }
1092   _add_ellarc_as_lines (path, pc, newpoint);
1093 
1094   newpoint.x = xc - rx * costheta;
1095   newpoint.y = yc - rx * sintheta;
1096   _add_ellarc_as_lines (path, pc, newpoint);
1097 
1098   if (clockwise)
1099     {
1100       newpoint.x = xc - ry * sintheta;
1101       newpoint.y = yc + ry * costheta;
1102     }
1103   else
1104     {
1105       newpoint.x = xc + ry * sintheta;
1106       newpoint.y = yc - ry * costheta;
1107     }
1108   _add_ellarc_as_lines (path, pc, newpoint);
1109 
1110   _add_ellarc_as_lines (path, pc, startpoint);
1111 
1112   path->primitive = true;	/* flag as flattened primitive */
1113 }
1114 
1115 void
_add_circle_as_bezier3s(plPath * path,plPoint pc,double radius,bool clockwise)1116 _add_circle_as_bezier3s (plPath *path, plPoint pc, double radius, bool clockwise)
1117 {
1118   if (path == (plPath *)NULL)
1119     return;
1120 
1121   _add_ellipse_as_bezier3s (path, pc, radius, radius, 0.0, clockwise);
1122   path->primitive = true;	/* flag as flattened primitive */
1123 }
1124 
1125 void
_add_circle_as_ellarcs(plPath * path,plPoint pc,double radius,bool clockwise)1126 _add_circle_as_ellarcs (plPath *path, plPoint pc, double radius, bool clockwise)
1127 {
1128   if (path == (plPath *)NULL)
1129     return;
1130 
1131   _add_ellipse_as_ellarcs (path, pc, radius, radius, 0.0, clockwise);
1132   path->primitive = true;	/* flag as flattened primitive */
1133 }
1134 
1135 void
_add_circle_as_lines(plPath * path,plPoint pc,double radius,bool clockwise)1136 _add_circle_as_lines (plPath *path, plPoint pc, double radius, bool clockwise)
1137 {
1138   if (path == (plPath *)NULL)
1139     return;
1140 
1141   _add_ellipse_as_lines (path, pc, radius, radius, 0.0, clockwise);
1142   path->primitive = true;	/* flag as flattened primitive */
1143 }
1144 
1145 /* The _fakearc() subroutine below, which is called by _add_arc_as_lines()
1146    and _add_ellarc_as_lines(), contains a remote descendent of the
1147    arc-drawing algorithm of Ken Turkowski <turk@apple.com> described in
1148    Graphics Gems V.  His algorithm is a recursive circle subdivision
1149    algorithm, which relies on the fact that if s and s' are the (chordal
1150    deviation)/radius associated to (respectively) an arc and a half-arc,
1151    then s' is approximately equal to s/4.  The exact formula is s' = 1 -
1152    sqrt (1 - s/2), which applies for all s in the meaningful range, i.e. 0
1153    <= s <= 2.
1154 
1155    Ken's algorithm rotates the chord of an arc by 90 degrees and scales it
1156    to have length s'.  The resulting vector will be the chordal deviation
1157    vector of the arc, which gives the midpoint of the arc, and hence the
1158    endpoints of each half of the arc.  So this drawing technique is
1159    recursive.
1160 
1161    The problem with this approach is that scaling a vector to a specified
1162    length requires a square root, so there are two square roots in each
1163    subdivision step.  One can attempt to remove one of them by noticing
1164    that the chord half-length h always satisfies h = sqrt(s * (2-s))).  So
1165    one can rotate the chord vector by 90 degrees, and multiply its length
1166    by s/2h, i.e., s/2sqrt(s * (2-s)), to get the chordal deviation vector.
1167    This factor still includes a square root though.  Also one still needs
1168    to compute a square root in order to proceed from one subdivision step
1169    to the next, i.e. to compute s' from s.
1170 
1171    We can get around the square root problem by drawing only circular arcs
1172    with subtended angle of 90 degrees (quarter-circles), or elliptic arcs
1173    that are obtained from such quarter-circles by affine transformations
1174    (so-called quarter-ellipses).  To draw the latter, we need only replace
1175    the 90 degree rotation matrix mentioned above by an affine
1176    transformation that maps v0->-v1 and v1->v0, where v0 = p0 - pc and v1 =
1177    p1 - pc are the displacement vectors from the center of the ellipse to
1178    the endpoints of the arc.  If we do this, we get an elliptic arc with p0
1179    and p1 as endpoints. The vectors v0 and v1 are said lie along conjugate
1180    diameters of the quarter-ellipse.
1181 
1182    So for drawing quarter-ellipses, the only initial value of s we need to
1183    consider is the one for a quarter-circle, which is 1-sqrt(1/2).  The
1184    successive values of s/2h that will be encountered, after each
1185    bisection, are pre-computed and stored in a lookup table, found in
1186    g_arc.h.
1187 
1188    This approach lets us avoid, completely, any computation of square roots
1189    during the drawing of quarter-circles and quarter-ellipses.  The only
1190    square roots we need are precomputed.  We don't need any floating point
1191    divisions in the main loop either.
1192 
1193    Of course for other angles than 90 degrees, we precompute a chord table
1194    and pass it to _fakearc().
1195 
1196    The implementation below does not use recursion (we use a local array,
1197    rather than the call stack, to store the sequence of generated
1198    points). */
1199 
1200 static void
_fakearc(plPath * path,plPoint p0,plPoint p1,int arc_type,const double * custom_chord_table,const double m[4])1201 _fakearc (plPath *path, plPoint p0, plPoint p1, int arc_type, const double *custom_chord_table, const double m[4])
1202 {
1203   plPoint p[NUM_ARC_SUBDIVISIONS + 1], q[NUM_ARC_SUBDIVISIONS + 1];
1204   int level[NUM_ARC_SUBDIVISIONS + 1];
1205   int n = 0;	/* index of top of stack, < NUM_ARC_SUBDIVISIONS */
1206   int segments_drawn = 0;
1207   const double *our_chord_table;
1208 
1209   if (arc_type == USER_DEFINED_ARC)
1210     our_chord_table = custom_chord_table;
1211   else				/* custom_chord_table arg ignored */
1212     our_chord_table = _chord_table[arc_type];
1213 
1214   p[0] = p0;
1215   q[0] = p1;
1216   level[0] = 0;
1217   while (n >= 0)		/* i.e. while stack is nonempty */
1218     {
1219       if (level[n] >= NUM_ARC_SUBDIVISIONS)
1220 	{			/* draw line segment */
1221 	  _add_line (path, q[n]);
1222 	  segments_drawn++;
1223 	  n--;
1224 	}
1225 
1226       else			/* bisect line segment */
1227 	{
1228 	  plVector v;
1229 	  plPoint pm, pb;
1230 
1231 	  v.x = q[n].x - p[n].x; /* chord = line segment from p[n] to q[n] */
1232 	  v.y = q[n].y - p[n].y;
1233 
1234 	  pm.x = p[n].x + 0.5 * v.x; /* midpoint of chord */
1235 	  pm.y = p[n].y + 0.5 * v.y;
1236 
1237 	  /* Compute bisection point.  If m=[0 1 -1 0] this just rotates
1238 	     the chord clockwise by 90 degrees, and scales it to yield the
1239 	     chordal deviation vector, which is used as an offset. */
1240 
1241 	  pb.x = pm.x +
1242 	    our_chord_table[level[n]] * (m[0] * v.x + m[1] * v.y);
1243 	  pb.y = pm.y +
1244 	    our_chord_table[level[n]] * (m[2] * v.x + m[3] * v.y);
1245 
1246 	  /* replace line segment by pair; level[n] >= n is an invariant */
1247 	  p[n+1] = p[n];
1248 	  q[n+1] = pb;		/* first half, deal with next */
1249 	  level[n+1] = level[n] + 1;
1250 
1251 	  p[n] = pb;
1252 	  q[n] = q[n];		/* second half, deal with later */
1253 	  level[n] = level[n] + 1;
1254 
1255 	  n++;
1256 	}
1257     }
1258 }
1259 
1260 /* prepare_chord_table() computes the list of chordal deviation factors
1261    that _fakearc() needs when it is employed to draw a circular arc of
1262    subtended angle other than the default angles it supports */
1263 static void
_prepare_chord_table(double sagitta,double custom_chord_table[TABULATED_ARC_SUBDIVISIONS])1264 _prepare_chord_table (double sagitta, double custom_chord_table[TABULATED_ARC_SUBDIVISIONS])
1265 {
1266   double half_chord_length;
1267   int i;
1268 
1269   half_chord_length = sqrt ( sagitta * (2.0 - sagitta) );
1270   for (i = 0; i < TABULATED_ARC_SUBDIVISIONS; i++)
1271     {
1272       custom_chord_table[i] = 0.5 * sagitta / half_chord_length;
1273       sagitta = 1.0 - sqrt (1.0 - 0.5 * sagitta);
1274       half_chord_length = 0.5 * half_chord_length / (1.0 - sagitta);
1275     }
1276 }
1277 
1278 /* Flatten a simple path into a path of segment list type, consisting only
1279    of line segments.
1280 
1281    As supplied, the path may be perfectly general: it may be a segment list
1282    (not all segments necessarily being line segments), or be a closed
1283    primitive (box/circle/ellipse).  If supplied path already consists only
1284    of line segments (with an initial moveto and possibly a final
1285    closepath), it is returned unchanged; this can be tested for by
1286    comparing pointers for equality.  If a new path is returned, it must be
1287    freed with _delete_plPath(). */
1288 
1289 plPath *
_flatten_path(const plPath * path)1290 _flatten_path (const plPath *path)
1291 {
1292   plPath *newpath;
1293 
1294   if (path == (plPath *)NULL)
1295     return (plPath *)NULL;
1296 
1297   switch (path->type)
1298     {
1299     case PATH_SEGMENT_LIST:
1300       {
1301 	bool do_flatten = false;
1302 	int i;
1303 
1304 	for (i = 0; i < path->num_segments; i++)
1305 	  {
1306 	    if (path->segments[i].type != S_MOVETO
1307 		&& path->segments[i].type != S_LINE
1308 		&& path->segments[i].type != S_CLOSEPATH)
1309 	      {
1310 		do_flatten = true;
1311 		break;
1312 	      }
1313 	  }
1314 
1315 	if (do_flatten == false)
1316 	  newpath = (plPath *)path; /* just return original path */
1317 	else
1318 	  {
1319 	    newpath = _new_plPath ();
1320 	    for (i = 0; i < path->num_segments; i++)
1321 	      {
1322 		switch ((int)(path->segments[i].type))
1323 		  {
1324 		  case (int)S_MOVETO:
1325 		    _add_moveto (newpath, path->segments[i].p);
1326 		    break;
1327 		  case (int)S_LINE:
1328 		    _add_line (newpath, path->segments[i].p);
1329 		    break;
1330 		  case (int)S_CLOSEPATH:
1331 		    _add_closepath (newpath);
1332 		    break;
1333 
1334 		    /* now, the types of segment we flatten: */
1335 
1336 		  case (int)S_ARC:
1337 		    _add_arc_as_lines (newpath,
1338 				       path->segments[i].pc,
1339 				       path->segments[i].p);
1340 		    break;
1341 		  case (int)S_ELLARC:
1342 		    _add_ellarc_as_lines (newpath,
1343 					  path->segments[i].pc,
1344 					  path->segments[i].p);
1345 		    break;
1346 		  case (int)S_QUAD:
1347 		    _add_bezier2_as_lines (newpath,
1348 					   path->segments[i].pc,
1349 					   path->segments[i].p);
1350 		    break;
1351 		  case (int)S_CUBIC:
1352 		    _add_bezier3_as_lines (newpath,
1353 					   path->segments[i].pc,
1354 					   path->segments[i].pd,
1355 					   path->segments[i].p);
1356 		    break;
1357 		  default:	/* shouldn't happen */
1358 		    break;
1359 		  }
1360 	      }
1361 	  }
1362 	break;
1363       }
1364     case PATH_CIRCLE:
1365       newpath = _new_plPath ();
1366       _add_circle_as_lines (newpath,
1367 			    path->pc, path->radius, path->clockwise);
1368       break;
1369     case PATH_ELLIPSE:
1370       newpath = _new_plPath ();
1371       _add_ellipse_as_lines (newpath,
1372 			     path->pc, path->rx, path->ry, path->angle,
1373 			     path->clockwise);
1374       break;
1375     case PATH_BOX:
1376       newpath = _new_plPath ();
1377       _add_box_as_lines (newpath, path->p0, path->p1, path->clockwise);
1378       break;
1379     default:			/* shouldn't happen */
1380       newpath = _new_plPath ();
1381       break;
1382     }
1383   return newpath;
1384 }
1385 
1386 /**********************************************************************/
1387 
1388 /* The code below exports the _merge_paths() function, which munges an
1389    array of plPath objects and returns a new array.  Heuristic
1390    "path-merging" of this sort is performed in g_endpath.c when filling a
1391    compound path (i.e., a multi-plPath path), if the output driver supports
1392    only the filling of single plPaths.  That is the case for nearly all of
1393    libplot's output drivers.
1394 
1395    `Child' paths are merged into their `parents', so each location in the
1396    returned array where a child was present will contain NULL.  Also, any
1397    non-child that had no children will be returned without modification.
1398 
1399    You should take this into account when freeing the returned array of
1400    plPaths.  Only the elements that are (1) non-NULL, and (2) differ from
1401    the corresponding elements in the originally passed array should have
1402    _delete_plPath() invoked on them.  The array as a whole may be
1403    deallocated by calling free().
1404 
1405    The _merge_paths() function was inspired by a similar function in
1406    Wolfgang Glunz's pstoedit, which was originally written by Burkhard
1407    Plaum <plaum@ipf.uni-stuttgart.de>. */
1408 
1409 /* Note: a well-formed plPath has the form:
1410    { moveto { line | arc }* { closepath }? }
1411 
1412    The _merge_paths function was written to merge _closed_ plPath's,
1413    i.e. ones whose endpoint is the same as the startpoint (possibly
1414    implicitly, i.e. closepath is allowed).  However, libplot applies it to
1415    open paths too, in which case an `implicit closepath' is added to the
1416    path to close it.
1417 
1418    NOTE: The current release of libplot does not yet support `closepath'
1419    segments at a higher level.  So we regard a pass-in plPath as `closed'
1420    if its last defining vertex is the same as the first.  THIS CONVENTION
1421    WILL GO AWAY. */
1422 
1423 /* ad hoc structure for an annotated plPath, in particular one that has
1424    been flattened into line segments and annotated; used only in this file,
1425    for merging purposes */
1426 
1427 typedef struct subpath_struct
1428 {
1429   plPathSegment *segments;	/* segment array */
1430   int num_segments;		/* number of segments */
1431 
1432   struct subpath_struct **parents; /* array of pointers to possible parents */
1433   struct subpath_struct *parent; /* pointer to parent path */
1434   struct subpath_struct **children; /* array of pointers to child paths */
1435   int num_children;		/* number of children */
1436 
1437   int num_outside;		/* number of subpaths outside this one */
1438 
1439   double llx, lly, urx, ury;    /* bounding box of the subpath */
1440   bool inserted;		/* subpath has been inserted into result? */
1441 } subpath;
1442 
1443 /* forward references */
1444 
1445 /* 0. ctors, dtors */
1446 static subpath * new_subpath (void);
1447 static subpath ** new_subpath_array (int n);
1448 static void delete_subpath (subpath *s);
1449 static void delete_subpath_array (subpath **s, int n);
1450 
1451 /* 1. functions that act on a subpath, i.e. an `annotated path' */
1452 static bool is_inside_of (const subpath *s, const subpath *other);
1453 static double _cheap_lower_bound_on_distance (const subpath *path1, const subpath *path2);
1454 static void linearize_subpath (subpath *s);
1455 static void read_into_subpath (subpath *s, const plPath *path);
1456 
1457 /* 2. miscellaneous */
1458 static void find_parents_in_subpath_list (subpath **annotated_paths, int num_paths);
1459 static void insert_subpath (plPathSegment *parent_segments, const plPathSegment *child_segments, int parent_size, int child_size, int parent_index, int child_index);
1460 static void _compute_closest (const plPathSegment *p1, const plPathSegment *p2, int size1, int size2, double *distance, int *index1, int *index2);
1461 
1462 /**********************************************************************/
1463 
1464 /* ctor for subpath class */
1465 static subpath *
new_subpath(void)1466 new_subpath (void)
1467 {
1468   subpath *s;
1469 
1470   s = (subpath *)_pl_xmalloc (sizeof (subpath));
1471 
1472   s->segments = (plPathSegment *)NULL;
1473   s->num_segments = 0;
1474   s->parents = (subpath **)NULL;
1475   s->parent = (subpath *)NULL;
1476   s->children = (subpath **)NULL;
1477   s->num_children = 0;
1478   s->num_outside = 0;
1479   s->llx = DBL_MAX;
1480   s->lly = DBL_MAX;
1481   s->urx = -DBL_MAX;
1482   s->ury = -DBL_MAX;
1483   s->inserted = false;
1484 
1485   return s;
1486 }
1487 
1488 /* corresponding ctor for a subpath array */
1489 static subpath **
new_subpath_array(int n)1490 new_subpath_array (int n)
1491 {
1492   int i;
1493   subpath **s;
1494 
1495   s = (subpath **)_pl_xmalloc (n * sizeof (subpath *));
1496   for (i = 0; i < n; i++)
1497     s[i] = new_subpath ();
1498 
1499   return s;
1500 }
1501 
1502 /* dtor for subpath class */
1503 static void
delete_subpath(subpath * s)1504 delete_subpath (subpath *s)
1505 {
1506   if (s)
1507     {
1508       if (s->segments)
1509 	free (s->segments);
1510       if (s->children)
1511 	free (s->children);
1512       if (s->parents)
1513 	free (s->parents);
1514 
1515       free (s);
1516     }
1517 }
1518 
1519 /* corresponding dtor for a subpath array */
1520 static void
delete_subpath_array(subpath ** s,int n)1521 delete_subpath_array (subpath **s, int n)
1522 {
1523   int i;
1524 
1525   if (s)
1526     {
1527       for (i = 0; i < n; i++)
1528 	delete_subpath (s[i]);
1529       free (s);
1530     }
1531 }
1532 
1533 /* replace every segment in a subpath by a lineto (invoked only on a child
1534    subpath, i.e. a subpath with an identified parent) */
1535 static void
linearize_subpath(subpath * s)1536 linearize_subpath (subpath *s)
1537 {
1538   /* replace first segment (moveto) with a lineto */
1539   s->segments[0].type = S_LINE;
1540 
1541   /* if final segment is a closepath, also replace with a lineto, back to
1542      point #0 */
1543   if (s->segments[s->num_segments-1].type == S_CLOSEPATH)
1544     {
1545       s->segments[s->num_segments-1].type = S_LINE;
1546       s->segments[s->num_segments-1].p = s->segments[0].p;
1547     }
1548 }
1549 
1550 /* Read a sequence of plPathSegments from a plPath into a previously empty
1551    annotated subpath.  (This is called only after the plPath has been
1552    flattened, so the segments include no arcs.)
1553 
1554    Because the way in which _merge_paths() is currently called in libplot,
1555    we need to handle the possibility that the plPath may not be closed.  If
1556    it isn't, we add a closepath.
1557 
1558    At present, we allow a final lineto to the start vertex to serve the
1559    same purpose.  THIS IS A LIBPLOT CONVENTION THAT WILL GO AWAY. */
1560 
1561 static void
read_into_subpath(subpath * s,const plPath * path)1562 read_into_subpath (subpath *s, const plPath *path)
1563 {
1564   bool need_to_close = false;
1565   int i;
1566 
1567   /* sanity check */
1568   if (path->type != PATH_SEGMENT_LIST)
1569     return;
1570 
1571   /* allocate space for segment array of subpath; add 1 extra slot for
1572      manual closure, if needed */
1573   s->segments = (plPathSegment *)_pl_xmalloc((path->num_segments + 1) * sizeof (plPathSegment));
1574   s->num_segments = path->num_segments;
1575 
1576   /* sanity check */
1577   if (path->num_segments == 0)
1578     return;
1579 
1580   /* Is this path closed?  If not, we'll close manually the annotated path
1581      that we'll construct.  WE CURRENTLY TREAT FINAL = INITIAL AS
1582      INDICATING CLOSURE. */
1583   if (path->segments[path->num_segments - 1].type != S_CLOSEPATH
1584       &&
1585       (path->segments[path->num_segments - 1].p.x != path->segments[0].p.x
1586        || path->segments[path->num_segments - 1].p.y != path->segments[0].p.y))
1587     need_to_close = true;
1588 
1589   /* copy the segments, updating bounding box to take each juncture point
1590      into account */
1591   for (i = 0; i < path->num_segments; i++)
1592     {
1593       plPathSegment e;
1594 
1595       e = path->segments[i];
1596       s->segments[i] = e;
1597 
1598       if (e.p.x < s->llx)
1599 	s->llx = e.p.x;
1600       if (e.p.y < s->lly)
1601 	s->lly = e.p.y;
1602       if (e.p.x > s->urx)
1603 	s->urx = e.p.x;
1604       if (e.p.y > s->ury)
1605 	s->ury = e.p.y;
1606     }
1607 
1608   if (need_to_close)
1609     {
1610 #if 0
1611       s->segments[path->num_segments].type = S_CLOSEPATH;
1612 #else  /* currently, use line segment instead of closepath */
1613       s->segments[path->num_segments].type = S_LINE;
1614 #endif
1615       s->segments[path->num_segments].p = path->segments[0].p;
1616       s->num_segments++;
1617     }
1618 }
1619 
1620 /* check if a subpath is inside another subpath */
1621 static bool
is_inside_of(const subpath * s,const subpath * other)1622 is_inside_of (const subpath *s, const subpath *other)
1623 {
1624   int inside = 0;
1625   int outside = 0;
1626   int i;
1627 
1628   /* if bbox fails to lie inside the other's bbox, false */
1629   if (!((s->llx >= other->llx) && (s->lly >= other->lly) &&
1630 	(s->urx <= other->urx) && (s->ury <= other->ury)))
1631     return false;
1632 
1633   /* otherwise, check all juncture points */
1634   for (i = 0; i < s->num_segments; i++)
1635     {
1636       bool point_is_inside;
1637 
1638       if (s->segments[i].type == S_CLOSEPATH)
1639 	/* should have i = num_segments - 1, no associated juncture point */
1640 	continue;
1641 
1642       /* Check if the vertex s->segments[i].p is inside `other'.  Could be
1643 	 done in a separate function, but we inline it for speed. */
1644       {
1645 	/* These two factors should be small positive floating-point
1646 	   numbers.  They should preferably be incommensurate, to minimize
1647 	   the probability of a degenerate case occurring: two line
1648 	   segments intersecting at the endpoint of one or the other. */
1649 #define SMALL_X_FACTOR (M_SQRT2 * M_PI)
1650 #define SMALL_Y_FACTOR (M_SQRT2 + M_PI)
1651 
1652 	/* argument of the now-inlined function (besides `other') */
1653 	plPoint p;
1654 	/* local variables of the now-inlined function */
1655 	int k, crossings;
1656 	/* (x1,y1) is effectively the point at infinity */
1657 	double x1, y1;
1658 	/* (x2,y2) is specified point */
1659 	double x2, y2;
1660 
1661 	/* argument of the now-inlined function (besides `other') */
1662 	p = s->segments[i].p;
1663 
1664 	/* (x1,y1) is effectively the point at infinity */
1665 	x1 = (DMAX(p.x, other->urx)
1666 	      + SMALL_X_FACTOR * (DMAX(p.x, other->urx)
1667 				  - DMIN(p.x, other->llx)));
1668 	y1 = (DMAX(p.y, other->ury)
1669 	      + SMALL_Y_FACTOR * (DMAX(p.y, other->ury)
1670 				  - DMIN(p.y, other->lly)));
1671 
1672 	/* (x2,y2) is specified point */
1673 	x2 = p.x;
1674 	y2 = p.y;
1675 
1676 	crossings = 0;
1677 	for (k = 0; k < other->num_segments; k++)
1678 	  {
1679 	    int j;
1680 	    double x3, y3, x4, y4, det, det1, det2;
1681 
1682 	    if (other->segments[k].type == S_CLOSEPATH) /* k > 0 */
1683 	      {
1684 		x3 = other->segments[k-1].p.x;
1685 		y3 = other->segments[k-1].p.y;
1686 	      }
1687 	    else
1688 	      {
1689 		x3 = other->segments[k].p.x;
1690 		y3 = other->segments[k].p.y;
1691 	      }
1692 
1693 	    j = (k == other->num_segments - 1 ? 0 : k + 1);
1694 	    if (other->segments[j].type == S_CLOSEPATH)
1695 	      continue;
1696 
1697 	    x4 = other->segments[j].p.x;
1698 	    y4 = other->segments[j].p.y;
1699 
1700 	    /* (x3,y3)-(x4,y4) is a line segment in the closed path */
1701 
1702 	    /* Check whether the line segments (x1,y1)-(x2,y2) and
1703 	       (x3-y3)-(x4,y4) cross each other.
1704 
1705 	       System to solve is:
1706 
1707 	       [p1 + (p2 - p1) * t1] - [p3 + (p4 - p3) * t2] = 0
1708 
1709 	       i.e.
1710 
1711 	       (x2 - x1) * t1 - (x4 - x3) * t2 = x3 - x1;
1712 	       (y2 - y1) * t1 - (y4 - y3) * t2 = y3 - y1;
1713 
1714 	       Solutions are: t1 = det1/det
1715 	                      t2 = det2/det
1716 
1717 	       The line segments cross each other (in their interiors) if
1718 	       0.0 < t1 < 1.0 and 0.0 < t2 < 1.0 */
1719 
1720 	    det = (x2 - x1) * (-(y4 - y3)) - (-(x4 - x3)) * (y2 - y1);
1721 	    if (det == 0.0)
1722 	      /* line segments are parallel; ignore the degenerate case
1723 		 that they might overlap */
1724 	      continue;
1725 
1726 	    det1 = (x3 - x1) * (-(y4 - y3)) - (-(x4 - x3)) * (y3 - y1);
1727 	    det2 = (x2 - x1) * (y3 - y1) - (x3 - x1) * (y2 - y1);
1728 
1729 	    if ((det<0.0 && (det1>0.0 || det2>0.0 || det1<det || det2<det))
1730 		||
1731 		(det>0.0 && (det1<0.0 || det2<0.0 || det1>det || det2>det)))
1732 	      /* solution for at least one of t1 and t2 is outside the
1733 		 interval [0,1], so line segments do not cross */
1734 	      continue;
1735 
1736 	    /* We ignore the possibility that t1, t2 are both in the interval
1737 	       [0,1], but
1738 	       (t1 == 0.0) || (t1 == 1.0) || (t2 == 0.0) || (t2 == 1.0).
1739 
1740 	       t1 == 0.0 should never happen, if p1 is effectively
1741 	       the point at infinity.
1742 
1743 	       So this degenerate case occurs only if the line segment
1744 	       (x1,y1)-(x2,y2) goes through either (x3,y3) or (x4,y4), or
1745 	       the specified point (x2,y2) lies on the line segment
1746 	       (x3,y3)-(x4,y4) that is part of the path. */
1747 
1748 	    crossings++;
1749 	  }
1750 
1751 	/* our determination of whether the point is inside the path;
1752 	   before we inlined this function, this was the return value */
1753 	point_is_inside = (crossings & 1) ? true : false;
1754       }
1755 
1756       /* increment inside,outside depending on whether or not the juncture
1757 	 point was inside the other path */
1758       if (point_is_inside)
1759 	inside++;
1760       else
1761 	outside++;
1762     }
1763 
1764   /* make a democratic decision as to whether the path as a whole is inside
1765      the other path */
1766   return (inside > outside ? true : false);
1767 }
1768 
1769 /* Find parent (if any) of each subpath in a list of subpaths.  When this
1770    is invoked, each subpath should consist of an initial moveto, at least
1771    one lineto, and a closepath (not currently enforced). */
1772 
1773 static void
find_parents_in_subpath_list(subpath ** annotated_paths,int num_paths)1774 find_parents_in_subpath_list (subpath **annotated_paths, int num_paths)
1775 {
1776   int i, j;
1777   subpath *parent;
1778 
1779   /* determine for each subpath the subpaths that are nominally outside it */
1780   for (i = 0; i < num_paths; i++)
1781     {
1782       annotated_paths[i]->parents = new_subpath_array (num_paths);
1783       for (j = 0; j < num_paths; j++)
1784 	{
1785 	  if (j != i)
1786 	    {
1787 	      if (is_inside_of (annotated_paths[i], annotated_paths[j]))
1788 		{
1789 		  annotated_paths[i]->parents[annotated_paths[i]->num_outside] =
1790 		    annotated_paths[j];
1791 		  annotated_paths[i]->num_outside++;
1792 		}
1793 	    }
1794 	}
1795     }
1796 
1797   /* Now find the real parent subpaths, i.e. the root subpaths.  A subpath
1798      is a parent subpath if the number of nominally-outside subpaths is
1799      even, and is a child subpath only if the number is odd.  An odd
1800      number, together with a failure to find a suitable potential parent,
1801      will flag a path as an isolate: technically a parent, but without
1802      children. */
1803 
1804   for (i = 0; i < num_paths; i++)
1805     {
1806       if ((annotated_paths[i]->num_outside & 1) == 0)
1807 	/* an even number of subpaths outside, definitely a parent
1808 	   (i.e. doesn't have a parent itself, may or may not have children) */
1809 	{
1810 	  /* allocate space for children (if any) */
1811 	  annotated_paths[i]->children = new_subpath_array (num_paths);
1812 	}
1813     }
1814 
1815   /* now determine which are children, and link them to their parents */
1816 
1817   for (i = 0; i < num_paths; i++)
1818     {
1819       if ((annotated_paths[i]->num_outside & 1) == 0)
1820 	/* even number outside, definitely a parent subpath (whether it has
1821            children remains to be determined) */
1822 	continue;
1823       else
1824 	/* odd number outside, possibly a child, so search linearly through
1825 	   possible parents until we get a hit; if so, this is a child; if
1826 	   not, this is an isolate (classed as a parent) */
1827 	{
1828 	  for (j = 0; j < annotated_paths[i]->num_outside; j++)
1829 	    {
1830 	      if (annotated_paths[i]->num_outside ==
1831 		  annotated_paths[i]->parents[j]->num_outside + 1)
1832 		/* number outside is one more than the number outside a
1833 		   potential parent; flag as a child, and add it to the
1834 		   parent's child list */
1835 		{
1836 		  parent = annotated_paths[i]->parents[j];
1837 		  annotated_paths[i]->parent = parent; /* give it a parent */
1838 		  parent->children[parent->num_children] = annotated_paths[i];
1839 		  parent->num_children++;
1840 		  break;
1841 		}
1842 	    }
1843 	}
1844     }
1845 }
1846 
1847 /* Compute closest vertices in two paths.  Indices of closest vertices, and
1848    (squared) distance between them, are returned via pointers.
1849 
1850    This is invoked in _merge_paths() only on paths that have been
1851    flattened, and have had the initial moveto and the optional final
1852    closepath replaced by line segments.  So when this is called, each
1853    segment type is S_LINE. */
1854 
1855 static void
_compute_closest(const plPathSegment * p1,const plPathSegment * p2,int size1,int size2,double * distance,int * index1,int * index2)1856 _compute_closest (const plPathSegment *p1, const plPathSegment *p2, int size1, int size2, double *distance, int *index1, int *index2)
1857 {
1858   int best_i = 0, best_j = 0;	/* keep compiler happy */
1859   double best_distance = DBL_MAX;
1860   int ii, jj;
1861 
1862   for (ii = 0; ii < size1; ii++)
1863     {
1864       plPoint point1;
1865 
1866       point1 = p1[ii].p;
1867       for (jj = 0; jj < size2; jj++)
1868 	{
1869 	  double tmp1, tmp2, distance;
1870 	  plPoint point2;
1871 
1872 	  point2 = p2[jj].p;
1873 	  tmp1 = point1.x - point2.x;
1874 	  tmp2 = point1.y - point2.y;
1875 	  distance = tmp1 * tmp1 + tmp2 * tmp2;
1876 	  if (distance < best_distance)
1877 	    {
1878 	      best_distance = distance;
1879 	      best_i = ii;
1880 	      best_j = jj;
1881 	    }
1882 	}
1883     }
1884 
1885   /* return the three quantities */
1886   *distance = best_distance;
1887   *index1 = best_i;
1888   *index2 = best_j;
1889 }
1890 
1891 /* Compute a cheap lower bound on the (squared) distance between two
1892    subpaths, by looking at their bounding boxes. */
1893 
1894 static double
_cheap_lower_bound_on_distance(const subpath * path1,const subpath * path2)1895 _cheap_lower_bound_on_distance (const subpath *path1, const subpath *path2)
1896 {
1897   double xdist = 0.0, ydist = 0.0, dist;
1898 
1899   if (path1->urx < path2->llx)
1900     xdist = path2->llx - path1->urx;
1901   else if (path2->urx < path1->llx)
1902     xdist = path1->llx - path2->urx;
1903 
1904   if (path1->ury < path2->lly)
1905     ydist = path2->lly - path1->ury;
1906   else if (path2->ury < path1->lly)
1907     ydist = path1->lly - path2->ury;
1908 
1909   dist = xdist * xdist + ydist * ydist;
1910 
1911   return dist;
1912 }
1913 
1914 /* Insert a closed child subpath into a closed parent, by connecting the
1915    two, twice, at a specified vertex of the parent path and a specified
1916    vertex of the child path.  This is the key function invoked by
1917    _merge_paths().
1918 
1919    Both paths are supplied as segment lists, and all segments are lines;
1920    the final segment of each is a line back to the starting point.  I.e.,
1921    for both subpaths, the final vertex duplicates the start vertex.  So we
1922    ignore the final vertex of the child (but not that of the parent).
1923    I.e. if the child vertices are numbered 0..child_size-1, we map the case
1924    child_index = child_size-1 to child_index = 0.
1925 
1926    The new path has parent_size + child_size + 1 vertices, of which the
1927    last is a repetition of the first. */
1928 
1929   /* INDEX MAP:
1930 
1931      PARENT -> NEW PATH
1932        i --> i                (if 0 <= i < parent_index + 1)
1933        i --> i+child_size+1   (if parent_index + 1 <= i < parent_size)
1934 
1935      CHILD -> NEW PATH
1936        i --> i+parent_index+child_size-child_index  (0 <= i < child_index+1)
1937        i --> i+parent_index-child_index+1   (child_index+1 <= i < child_size-1)
1938        		(0'th element of the child is same as child_size-1 element)
1939 
1940      NEW PATH                        CONTENTS
1941 
1942      0..parent_index
1943                                      0..parent_index of PARENT
1944      parent_index+1
1945                                      child_index of CHILD (i.e. ->join)
1946      parent_index+2..parent_index+child_size-child_index-1
1947                                      child_index+1..child_size-2 of CHILD
1948      parent_index+child_size-child_index..parent_index+child_size
1949                                      0..child_index of CHILD
1950      parent_index+child_size+1
1951                                      parent_index of PARENT (i.e. ->join)
1952      parent_index+child_size+2..parent_size+child_size
1953                                      parent_index+1..parent_size-1 of PARENT
1954 
1955   */
1956 
1957 /* Macros that map from vertices in the child path and the parent path, to
1958    vertices in the merged path.  Here the argument `i' is the index in the
1959    original path, and each macro evaluates to the index in the merger.  */
1960 
1961 /* The first macro should not be applied to i=child_size-1; as noted above,
1962    that vertex is equivalent to i=0, so apply it to i=0 instead. */
1963 
1964 #define CHILD_VERTEX_IN_MERGED_PATH(i,parent_index,parent_size,child_index,child_size) ((i) <= (child_index) ? (i) + (parent_index) + (child_size) - (child_index) : (i) + (parent_index) - (child_index) + 1)
1965 #define PARENT_VERTEX_IN_MERGED_PATH(i,parent_index,parent_size,child_index,child_size) ((i) <= (parent_index) ? (i) : (i) + (child_size) + 1)
1966 
1967 
1968 static void
insert_subpath(plPathSegment * parent,const plPathSegment * child,int parent_size,int child_size,int parent_index,int child_index)1969 insert_subpath (plPathSegment *parent, const plPathSegment *child, int parent_size, int child_size, int parent_index, int child_index)
1970 {
1971   int i;
1972   plPathSegment e1, e2;
1973   int src_index;
1974 
1975   /* map case when joining vertex is final vertex of child to case when
1976      it's the 0'th vertex */
1977   if (child_index == child_size - 1)
1978     child_index = 0;
1979 
1980   /* move up: add child_size+1 empty slots to parent path */
1981   for (i = parent_size - 1; i >= parent_index + 1; i--)
1982     parent[i + child_size + 1] = parent[i];
1983 
1984   /* add a line segment from specified vertex of parent path to specified
1985      vertex of child path */
1986   e1 = child[child_index];
1987   e1.type = S_LINE;		/* unnecessary */
1988   parent[parent_index + 1] = e1;
1989 
1990   /* copy vertices of child into parent, looping back to start in child if
1991      necessary; note we skip the last (i.e. child_size-1'th) vertex, since
1992      the 0'th vertex is the same */
1993   src_index = child_index;
1994   for (i = 0; i < child_size - 1; i++)
1995     {
1996       src_index++;
1997       if (src_index == child_size - 1)
1998 	src_index = 0;
1999       parent[parent_index + 2 + i] = child[src_index];
2000     }
2001 
2002   /* add a line segment back from specified vertex of child path to
2003      specified vertex of parent path */
2004   e2 = parent[parent_index];
2005   e2.type = S_LINE;
2006   parent[parent_index + child_size + 1] = e2;
2007 }
2008 
2009 /* The key function exported by this module, which is used by libplot for
2010    filling compound paths. */
2011 
2012 plPath **
_merge_paths(const plPath ** paths,int num_paths)2013 _merge_paths (const plPath **paths, int num_paths)
2014 {
2015   int i;
2016   subpath **annotated_paths;
2017   plPath **flattened_paths;
2018   plPath **merged_paths;
2019 
2020   /* flatten every path to a list of line segments (some paths may come
2021      back unaltered; will be able to compare pointers to check for that) */
2022   flattened_paths = (plPath **)_pl_xmalloc (num_paths * sizeof(plPath *));
2023   for (i = 0; i < num_paths; i++)
2024     {
2025       flattened_paths[i] = _flatten_path (paths[i]);
2026 #ifdef DEBUG
2027       fprintf (stderr, "path %d: %d segments, flattened to %d segments\n",
2028 	       i, paths[i]->num_segments, flattened_paths[i]->num_segments);
2029 #endif
2030     }
2031 
2032   /* Copy each flattened path into a corresponding annotated path
2033      (`subpath').  Manual closure, if necessary (see above) is performed,
2034      i.e. we always add a final closepath to close the path.  At this stage
2035      bounding boxes are computed. */
2036   annotated_paths = new_subpath_array (num_paths);
2037   for (i = 0; i < num_paths; i++)
2038     read_into_subpath (annotated_paths[i], flattened_paths[i]);
2039 
2040   /* Flattened paths no longer needed, so delete them carefully (some may
2041      be the same as the original paths, due to _flatten_path() having
2042      simply returned its argument) */
2043   for (i = 0; i < num_paths; i++)
2044     if (flattened_paths[i] != paths[i])
2045       _delete_plPath (flattened_paths[i]);
2046 
2047   /* determine which subpaths are parents, children */
2048   find_parents_in_subpath_list (annotated_paths, num_paths);
2049 
2050   /* in each child, replace each moveto/closepath by a lineto */
2051   for (i = 0; i < num_paths; i++)
2052     if (annotated_paths[i]->parent != (subpath *)NULL)
2053       /* child path */
2054       linearize_subpath (annotated_paths[i]);
2055 
2056   /* create array of merged paths: parent paths will have child paths
2057      merged into them, and child paths won't appear */
2058 
2059   /* allocate space for new array, to be returned */
2060   merged_paths = (plPath **)_pl_xmalloc (num_paths * sizeof(plPath *));
2061 
2062   for (i = 0; i < num_paths; i++)
2063     {
2064       int j, k, num_segments_in_merged_path;
2065       subpath *parent;
2066       plPath *merged_path;
2067       double *parent_to_child_distances;
2068       int *child_best_indices, *parent_best_indices;
2069 
2070       if (annotated_paths[i]->parent != (subpath *)NULL)
2071 	/* child path; original path will be merged into parent */
2072 	{
2073 	  merged_paths[i] = (plPath *)NULL;
2074 	  continue;
2075 	}
2076 
2077       if (annotated_paths[i]->num_children == 0)
2078 	/* no parent, but no children either, so no merging done; in output
2079 	   path array, place original unflattened path */
2080 	{
2081 	  merged_paths[i] = (plPath *)paths[i];
2082 	  continue;
2083 	}
2084 
2085       /* this path must be a parent, with one or more children to be merged
2086 	 into it; so create new empty `merged path' with segments array
2087 	 that will hold it, and the merged-in children */
2088       parent = annotated_paths[i];
2089       num_segments_in_merged_path = parent->num_segments;
2090       for (j = 0; j < parent->num_children; j++)
2091 	num_segments_in_merged_path
2092 	  += (parent->children[j]->num_segments + 1);
2093 
2094       merged_path = _new_plPath ();
2095       merged_path->segments = (plPathSegment *)_pl_xmalloc(num_segments_in_merged_path * sizeof (plPathSegment));
2096       merged_path->num_segments = 0;
2097       merged_path->segments_len = num_segments_in_merged_path;
2098 
2099       /* copy parent path into new empty path, i.e. initialize the merged
2100          path */
2101       for (j = 0; j < parent->num_segments; j++)
2102 	merged_path->segments[j] = parent->segments[j];
2103       merged_path->num_segments = parent->num_segments;
2104 
2105       /* Create temporary storage for `closest vertex pairs' and inter-path
2106 	 distances.  We first compute the shortest distance between each
2107 	 child path.  We also keep track of the shortest distance between
2108 	 each child and the merged path being constructed, and update it
2109 	 when any child is added.  */
2110 
2111       parent_to_child_distances = (double *)_pl_xmalloc(parent->num_children * sizeof (double));
2112       parent_best_indices = (int *)_pl_xmalloc(parent->num_children * sizeof (int));
2113       child_best_indices = (int *)_pl_xmalloc(parent->num_children * sizeof (int));
2114 
2115       /* compute closest vertices between merged path (i.e., right now, the
2116 	 parent) and any child; these arrays will be updated when any child
2117 	 is inserted into the merged path */
2118       for (j = 0; j < parent->num_children; j++)
2119 	_compute_closest (parent->segments,
2120 			  parent->children[j]->segments,
2121 			  parent->num_segments,
2122 			  parent->children[j]->num_segments,
2123 			  &(parent_to_child_distances[j]),
2124 			  &(parent_best_indices[j]),
2125 			  &(child_best_indices[j]));
2126 
2127       for (k = 0; k < parent->num_children; k++)
2128 	/* insert a child (the closest remaining one!) into the built-up
2129            merged path; and flag the child as having been inserted so that
2130            we don't pay attention to it thereafter */
2131 	{
2132 	  double min_distance;
2133 	  int closest = 0; /* keep compiler happy */
2134 	  double *new_parent_to_child_distances;
2135 	  int *new_child_best_indices, *new_parent_best_indices;
2136 
2137 	  /* allocate storage for arrays that will be used to update the
2138 	     three abovementioned arrays, with each pass through the loop */
2139 	  new_parent_to_child_distances = (double *)_pl_xmalloc(parent->num_children * sizeof (double));
2140 	  new_parent_best_indices = (int *)_pl_xmalloc(parent->num_children * sizeof (int));
2141 	  new_child_best_indices = (int *)_pl_xmalloc(parent->num_children * sizeof (int));
2142 
2143 	  /* initially, they're the same as the current arrays */
2144 	  for (j = 0; j < parent->num_children; j++)
2145 	    {
2146 	      new_parent_to_child_distances[j] = parent_to_child_distances[j];
2147 	      new_parent_best_indices[j] = parent_best_indices[j];
2148 	      new_child_best_indices[j] = child_best_indices[j];
2149 	    }
2150 
2151 	  /* find closest child to merged path, which has not yet been
2152              inserted */
2153 	  min_distance = DBL_MAX;
2154 	  for (j = 0; j < parent->num_children; j++)
2155 	    {
2156 	      if (parent->children[j]->inserted) /* ignore this child */
2157 		continue;
2158 
2159 	      if (parent_to_child_distances[j] < min_distance)
2160 		{
2161 		  closest = j;
2162 		  min_distance = parent_to_child_distances[j];
2163 		}
2164 	    }
2165 
2166 	  /* closest remaining child has index `closest'; it will be
2167 	     inserted into the current merged path */
2168 
2169 	  /* loop over all children, skipping inserted ones and also
2170 	     skipping `closest', the next child to be inserted */
2171 	  for (j = 0; j < parent->num_children; j++)
2172 	    {
2173 	      double inter_child_distance;
2174 	      int inter_child_best_index1, inter_child_best_index2;
2175 	      double lower_bound_on_inter_child_distance;
2176 	      bool compute_carefully;
2177 
2178 	      if (parent->children[j]->inserted) /* ignore */
2179 		continue;
2180 
2181 	      if (j == closest)	/* ignore */
2182 		continue;
2183 
2184 	      /* compute distance (and closest vertex pairs) between
2185 		 `closest' and the j'th child; result is only of interest
2186 		 if the distance is less than parent_to_child_distances[j],
2187 		 so we first compute a cheap lower bound on the result by
2188 		 looking at bounding boxes. */
2189 
2190 	      lower_bound_on_inter_child_distance =
2191 		_cheap_lower_bound_on_distance (parent->children[j],
2192 						parent->children[closest]);
2193 	      compute_carefully =
2194 		(lower_bound_on_inter_child_distance <
2195 		 parent_to_child_distances[j]) ? true : false;
2196 
2197 	      if (compute_carefully)
2198 		/* compute accurate inter-child distance; also which two
2199 		   vertices yield the minimum distance */
2200 		_compute_closest (parent->children[j]->segments,
2201 				  parent->children[closest]->segments,
2202 				  parent->children[j]->num_segments,
2203 				  parent->children[closest]->num_segments,
2204 				  &inter_child_distance,
2205 				  &inter_child_best_index1, /* vertex in j */
2206 				  &inter_child_best_index2); /* in `closest' */
2207 
2208 	      /* fill in j'th element of the new arrays
2209 		 parent_to_child_distances[], parent_best_indices[] and
2210 		 child_best_indices[] so as to take the insertion of the
2211 		 child into account; but we don't update the old arrays
2212 		 until we do the actual insertion */
2213 
2214 	      if (compute_carefully &&
2215 		  inter_child_distance < parent_to_child_distances[j])
2216 		/* j'th child is nearer to a vertex in `closest', the child
2217 		   to be inserted, than to any vertex in the current merged
2218 		   path, so all three arrays are affected */
2219 		{
2220 		  int nearest_index_in_closest_child;
2221 
2222 		  new_parent_to_child_distances[j] = inter_child_distance;
2223 		  new_child_best_indices[j] = inter_child_best_index1;
2224 		  nearest_index_in_closest_child = inter_child_best_index2;
2225 
2226 		  /* Compute new value of parent_best_indices[j], taking
2227 		     into account that `closest' will be inserted into the
2228 		     merged path, thereby remapping the relevant index in
2229 		     `closest'.  The macro doesn't perform correctly if its
2230 		     first arg takes the maximum possible value; so
2231 		     instead, we map that possibility to `0'.  See comment
2232 		     above, before the macro definition. */
2233 
2234 		  if (nearest_index_in_closest_child ==
2235 		      parent->children[closest]->num_segments - 1)
2236 		    nearest_index_in_closest_child = 0;
2237 		  new_parent_best_indices[j] =
2238 		    CHILD_VERTEX_IN_MERGED_PATH(nearest_index_in_closest_child,
2239 						parent_best_indices[closest],
2240 						merged_path->num_segments,
2241 						child_best_indices[closest],
2242 						parent->children[closest]->num_segments);
2243 		}
2244 	      else
2245 		/* j'th child is nearer to a vertex in the current merged
2246 		   path than to any vertex in `closest', the child to be
2247 		   inserted into the merged path */
2248 		{
2249 		  int nearest_index_in_parent;
2250 
2251 		  nearest_index_in_parent = parent_best_indices[j];
2252 
2253 		  /* compute new value of parent_best_indices[j], taking
2254 		     into account that `closest' will be inserted into the
2255 		     merged path, thereby remapping the relevant index in
2256 		     the merged path */
2257 		  new_parent_best_indices[j] =
2258 		    PARENT_VERTEX_IN_MERGED_PATH(nearest_index_in_parent,
2259 						 parent_best_indices[closest],
2260 						 merged_path->num_segments,
2261 						 child_best_indices[closest],
2262 						 parent->children[closest]->num_segments);
2263 		}
2264 	    }
2265 
2266 	  /* do the actual insertion, by adding a pair of lineto's between
2267              closest vertices; flag child as inserted */
2268 	  insert_subpath (merged_path->segments,
2269 			  parent->children[closest]->segments,
2270 			  merged_path->num_segments,
2271 			  parent->children[closest]->num_segments,
2272 			  parent_best_indices[closest],
2273 			  child_best_indices[closest]);
2274 	  merged_path->num_segments +=
2275 	    (parent->children[closest]->num_segments + 1);
2276 	  parent->children[closest]->inserted = true;
2277 
2278 	  /* update the old arrays to take insertion into account: replace
2279              them by the new ones */
2280 	  for (j = 0; j < parent->num_children; j++)
2281 	    {
2282 	      parent_to_child_distances[j] = new_parent_to_child_distances[j];
2283 	      parent_best_indices[j] = new_parent_best_indices[j];
2284 	      child_best_indices[j] = new_child_best_indices[j];
2285 	    }
2286 
2287 	  free (new_parent_to_child_distances);
2288 	  free (new_parent_best_indices);
2289 	  free (new_child_best_indices);
2290 	}
2291       /* End of loop over all children of parent subpath; all >=1 children
2292 	 have now been inserted into the parent, i.e. into the `merged
2293 	 path' which the parent initialized.  However, the merged path's
2294 	 segments are all lines; so change the first to a moveto. */
2295 
2296       merged_path->segments[0].type = S_MOVETO;
2297       merged_paths[i] = merged_path;
2298 
2299       /* NOTE: SHOULD ALSO REPLACE LAST LINE SEGMENT BY A CLOSEPATH! */
2300 
2301       /* delete temporary storage for `closest vertex pairs' and inter-path
2302          distances */
2303       free (parent_to_child_distances);
2304       free (parent_best_indices);
2305       free (child_best_indices);
2306     }
2307   /* end of loop over parent subpaths */
2308 
2309   /* no more annotated paths needed */
2310   delete_subpath_array (annotated_paths, num_paths);
2311 
2312   return merged_paths;
2313 }
2314