Imported Upstream version 1.22.4
[platform/upstream/groff.git] / src / preproc / pic / common.cpp
1 // -*- C++ -*-
2 /* Copyright (C) 1989-2018 Free Software Foundation, Inc.
3      Written by James Clark (jjc@jclark.com)
4
5 This file is part of groff.
6
7 groff is free software; you can redistribute it and/or modify it under
8 the terms of the GNU General Public License as published by the Free
9 Software Foundation, either version 3 of the License, or
10 (at your option) any later version.
11
12 groff is distributed in the hope that it will be useful, but WITHOUT ANY
13 WARRANTY; without even the implied warranty of MERCHANTABILITY or
14 FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
15 for more details.
16
17 You should have received a copy of the GNU General Public License
18 along with this program.  If not, see <http://www.gnu.org/licenses/>. */
19
20 #include "pic.h"
21 #include "common.h"
22
23 // output a dashed circle as a series of arcs
24
25 void common_output::dashed_circle(const position &cent, double rad,
26                                   const line_type &lt)
27 {
28   assert(lt.type == line_type::dashed);
29   line_type slt = lt;
30   slt.type = line_type::solid;
31   double dash_angle = lt.dash_width/rad;
32   int ndashes;
33   double gap_angle;
34   if (dash_angle >= M_PI/4.0) {
35     if (dash_angle < M_PI/2.0) {
36       gap_angle = M_PI/2.0 - dash_angle;
37       ndashes = 4;
38     }
39     else if (dash_angle < M_PI) {
40       gap_angle = M_PI - dash_angle;
41       ndashes = 2;
42     }
43     else {
44       circle(cent, rad, slt, -1.0);
45       return;
46     }
47   }
48   else {
49     ndashes = 4*int(ceil(M_PI/(4.0*dash_angle)));
50     gap_angle = (M_PI*2.0)/ndashes - dash_angle;
51   }
52   for (int i = 0; i < ndashes; i++) {
53     double start_angle = i*(dash_angle+gap_angle) - dash_angle/2.0;
54     solid_arc(cent, rad, start_angle, start_angle + dash_angle, lt);
55   }
56 }
57
58 // output a dotted circle as a series of dots
59
60 void common_output::dotted_circle(const position &cent, double rad,
61                                   const line_type &lt)
62 {
63   assert(lt.type == line_type::dotted);
64   double gap_angle = lt.dash_width/rad;
65   int ndots;
66   if (gap_angle >= M_PI/2.0) {
67     // always have at least 2 dots
68     gap_angle = M_PI;
69     ndots = 2;
70   }
71   else {
72     ndots = 4*int(M_PI/(2.0*gap_angle));
73     gap_angle = (M_PI*2.0)/ndots;
74   }
75   double ang = 0.0;
76   for (int i = 0; i < ndots; i++, ang += gap_angle)
77     dot(cent + position(cos(ang), sin(ang))*rad, lt);
78 }
79
80 // recursive function for dash drawing, used by dashed_ellipse
81
82 void common_output::ellipse_arc(const position &cent,
83                                 const position &z0, const position &z1,
84                                 const distance &dim, const line_type &lt)
85 {
86   assert(lt.type == line_type::solid);
87   assert(dim.x != 0 && dim.y != 0);
88   double eps = 0.0001;
89   position zml = (z0 + z1) / 2;
90   // apply affine transformation (from ellipse to circle) to compute angle
91   // of new position, then invert transformation to get exact position
92   double psi = atan2(zml.y / dim.y, zml.x / dim.x);
93   position zm = position(dim.x * cos(psi), dim.y * sin(psi));
94   // to approximate the ellipse arc with one or more circle arcs, we
95   // first compute the radius of curvature in zm
96   double a_2 = dim.x * dim.x;
97   double a_4 = a_2 * a_2;
98   double b_2 = dim.y * dim.y;
99   double b_4 = b_2 * b_2;
100   double e_2 = a_2 - b_2;
101   double temp = a_4 * zm.y * zm.y + b_4 * zm.x * zm.x;
102   double rho = sqrt(temp / a_4 / b_4 * temp / a_4 / b_4 * temp);
103   // compute center of curvature circle
104   position M = position(e_2 * zm.x / a_2 * zm.x / a_2 * zm.x,
105                         -e_2 * zm.y / b_2 * zm.y / b_2 * zm.y);
106   // compute distance between circle and ellipse arc at start and end
107   double phi0 = atan2(z0.y - M.y, z0.x - M.x);
108   double phi1 = atan2(z1.y - M.y, z1.x - M.x);
109   position M0 = position(rho * cos(phi0), rho * sin(phi0)) + M;
110   position M1 = position(rho * cos(phi1), rho * sin(phi1)) + M;
111   double dist0 = hypot(z0 - M0) / sqrt(z0 * z0);
112   double dist1 = hypot(z1 - M1) / sqrt(z1 * z1);
113   if (dist0 < eps && dist1 < eps)
114     solid_arc(M + cent, rho, phi0, phi1, lt);
115   else {
116     ellipse_arc(cent, z0, zm, dim, lt);
117     ellipse_arc(cent, zm, z1, dim, lt);
118   }
119 }
120
121 // output a dashed ellipse as a series of arcs
122
123 void common_output::dashed_ellipse(const position &cent, const distance &dim,
124                                    const line_type &lt)
125 {
126   assert(lt.type == line_type::dashed);
127   double dim_x = dim.x / 2;
128   double dim_y = dim.y / 2;
129   line_type slt = lt;
130   slt.type = line_type::solid;
131   double dw = lt.dash_width;
132   // we use an approximation to compute the ellipse length (found in:
133   // Bronstein, Semendjajew, Taschenbuch der Mathematik)
134   double lambda = (dim.x - dim.y) / (dim.x + dim.y);
135   double le = M_PI / 2 * (dim.x + dim.y)
136               * ((64 - 3 * lambda * lambda * lambda * lambda )
137                  / (64 - 16 * lambda * lambda));
138   // for symmetry we make nmax a multiple of 8
139   int nmax = 8 * int(le / dw / 8 + 0.5);
140   if (nmax < 8) {
141     nmax = 8;
142     dw = le / 8;
143   }
144   int ndash = nmax / 2;
145   double gapwidth = (le - dw * ndash) / ndash;
146   double l = 0;
147   position z = position(dim_x, 0);
148   position zdot = z;
149   int j = 0;
150   int jmax = int(10 / lt.dash_width);
151   for (int i = 0; i <= nmax; i++) {
152     position zold = z;
153     position zpre = zdot;
154     double ld = (int(i / 2) + 0.5) * dw + int((i + 1) / 2) * gapwidth;
155     double lold = 0;
156     double dl = 1;
157     // find next position for fixed arc length
158     while (l < ld) {
159       j++;
160       lold = l;
161       zold = z;
162       double phi = j * 2 * M_PI / jmax;
163       z = position(dim_x * cos(phi), dim_y * sin(phi));
164       dl = hypot(z - zold);
165       l += dl;
166     }
167     // interpolate linearly between the last two points,
168     // using the length difference as the scaling factor
169     double delta = (ld - lold) / dl;
170     zdot = zold + (z - zold) * delta;
171     // compute angle of new position on the affine circle
172     // and use it to get the exact value on the ellipse
173     double psi = atan2(zdot.y / dim_y, zdot.x / dim_x);
174     zdot = position(dim_x * cos(psi), dim_y * sin(psi));
175     if ((i % 2 == 0) && (i > 1))
176       ellipse_arc(cent, zpre, zdot, dim / 2, slt);
177   }
178 }
179
180 // output a dotted ellipse as a series of dots
181
182 void common_output::dotted_ellipse(const position &cent, const distance &dim,
183                                    const line_type &lt)
184 {
185   assert(lt.type == line_type::dotted);
186   double dim_x = dim.x / 2;
187   double dim_y = dim.y / 2;
188   line_type slt = lt;
189   slt.type = line_type::solid;
190   // we use an approximation to compute the ellipse length (found in:
191   // Bronstein, Semendjajew, Taschenbuch der Mathematik)
192   double lambda = (dim.x - dim.y) / (dim.x + dim.y);
193   double le = M_PI / 2 * (dim.x + dim.y)
194               * ((64 - 3 * lambda * lambda * lambda * lambda )
195                  / (64 - 16 * lambda * lambda));
196   // for symmetry we make nmax a multiple of 4
197   int ndots = 4 * int(le / lt.dash_width / 4 + 0.5);
198   if (ndots < 4)
199     ndots = 4;
200   double l = 0;
201   position z = position(dim_x, 0);
202   int j = 0;
203   int jmax = int(10 / lt.dash_width);
204   for (int i = 1; i <= ndots; i++) {
205     position zold = z;
206     double lold = l;
207     double ld = i * le / ndots;
208     double dl = 1;
209     // find next position for fixed arc length
210     while (l < ld) {
211       j++;
212       lold = l;
213       zold = z;
214       double phi = j * 2 * M_PI / jmax;
215       z = position(dim_x * cos(phi), dim_y * sin(phi));
216       dl = hypot(z - zold);
217       l += dl;
218     }
219     // interpolate linearly between the last two points,
220     // using the length difference as the scaling factor
221     double delta = (ld - lold) / dl;
222     position zdot = zold + (z - zold) * delta;
223     // compute angle of new position on the affine circle
224     // and use it to get the exact value on the ellipse
225     double psi = atan2(zdot.y / dim_y, zdot.x / dim_x);
226     zdot = position(dim_x * cos(psi), dim_y * sin(psi));
227     dot(cent + zdot, slt);
228   }
229 }
230
231 // return non-zero iff we can compute a center
232
233 int compute_arc_center(const position &start, const position &cent,
234                        const position &end, position *result)
235 {
236   // This finds the point along the vector from start to cent that
237   // is equidistant between start and end.
238   distance c = cent - start;
239   distance e = end - start;
240   double n = c*e;
241   if (n == 0.0)
242     return 0;
243   *result = start + c*((e*e)/(2.0*n));
244   return 1;
245 }
246
247 // output a dashed arc as a series of arcs
248
249 void common_output::dashed_arc(const position &start, const position &cent,
250                                const position &end, const line_type &lt)
251 {
252   assert(lt.type == line_type::dashed);
253   position c;
254   if (!compute_arc_center(start, cent, end, &c)) {
255     line(start, &end, 1, lt);
256     return;
257   }
258   distance start_offset = start - c;
259   distance end_offset = end - c;
260   double start_angle = atan2(start_offset.y, start_offset.x);
261   double end_angle = atan2(end_offset.y, end_offset.x);
262   double rad = hypot(c - start);
263   double dash_angle = lt.dash_width/rad;
264   double total_angle = end_angle - start_angle;
265   while (total_angle < 0)
266     total_angle += M_PI + M_PI;
267   if (total_angle <= dash_angle*2.0) {
268     solid_arc(cent, rad, start_angle, end_angle, lt);
269     return;
270   }
271   int ndashes = int((total_angle - dash_angle)/(dash_angle*2.0) + .5);
272   double dash_and_gap_angle = (total_angle - dash_angle)/ndashes;
273   for (int i = 0; i <= ndashes; i++)
274     solid_arc(cent, rad, start_angle + i*dash_and_gap_angle,
275               start_angle + i*dash_and_gap_angle + dash_angle, lt);
276 }
277
278 // output a dotted arc as a series of dots
279
280 void common_output::dotted_arc(const position &start, const position &cent,
281                                const position &end, const line_type &lt)
282 {
283   assert(lt.type == line_type::dotted);
284   position c;
285   if (!compute_arc_center(start, cent, end, &c)) {
286     line(start, &end, 1, lt);
287     return;
288   }
289   distance start_offset = start - c;
290   distance end_offset = end - c;
291   double start_angle = atan2(start_offset.y, start_offset.x);
292   double total_angle = atan2(end_offset.y, end_offset.x) - start_angle;
293   while (total_angle < 0)
294     total_angle += M_PI + M_PI;
295   double rad = hypot(c - start);
296   int ndots = int(total_angle/(lt.dash_width/rad) + .5);
297   if (ndots == 0)
298     dot(start, lt);
299   else {
300     for (int i = 0; i <= ndots; i++) {
301       double a = start_angle + (total_angle*i)/ndots;
302       dot(cent + position(cos(a), sin(a))*rad, lt);
303     }
304   }
305 }
306
307 void common_output::solid_arc(const position &cent, double rad,
308                               double start_angle, double end_angle,
309                               const line_type &lt)
310 {
311   line_type slt = lt;
312   slt.type = line_type::solid;
313   arc(cent + position(cos(start_angle), sin(start_angle))*rad,
314       cent,
315       cent + position(cos(end_angle), sin(end_angle))*rad,
316       slt);
317 }
318
319
320 void common_output::rounded_box(const position &cent, const distance &dim,
321                                 double rad, const line_type &lt,
322                                 double fill, char *color_fill)
323 {
324   if (fill >= 0.0 || color_fill)
325     filled_rounded_box(cent, dim, rad, fill);
326   switch (lt.type) {
327   case line_type::invisible:
328     break;
329   case line_type::dashed:
330     dashed_rounded_box(cent, dim, rad, lt);
331     break;
332   case line_type::dotted:
333     dotted_rounded_box(cent, dim, rad, lt);
334     break;
335   case line_type::solid:
336     solid_rounded_box(cent, dim, rad, lt);
337     break;
338   default:
339     assert(0);
340   }
341 }
342
343
344 void common_output::dashed_rounded_box(const position &cent,
345                                        const distance &dim, double rad,
346                                        const line_type &lt)
347 {
348   line_type slt = lt;
349   slt.type = line_type::solid;
350
351   double hor_length = dim.x + (M_PI/2.0 - 2.0)*rad;
352   int n_hor_dashes = int(hor_length/(lt.dash_width*2.0) + .5);
353   double hor_gap_width = (n_hor_dashes != 0
354                           ? hor_length/n_hor_dashes - lt.dash_width
355                           : 0.0);
356
357   double vert_length = dim.y + (M_PI/2.0 - 2.0)*rad;
358   int n_vert_dashes = int(vert_length/(lt.dash_width*2.0) + .5);
359   double vert_gap_width = (n_vert_dashes != 0
360                            ? vert_length/n_vert_dashes - lt.dash_width
361                            : 0.0);
362   // Note that each corner arc has to be split into two for dashing,
363   // because one part is dashed using vert_gap_width, and the other
364   // using hor_gap_width.
365   double offset = lt.dash_width/2.0;
366   dash_arc(cent + position(dim.x/2.0 - rad, -dim.y/2.0 + rad), rad,
367            -M_PI/4.0, 0, slt, lt.dash_width, vert_gap_width, &offset);
368   dash_line(cent + position(dim.x/2.0, -dim.y/2.0 + rad),
369             cent + position(dim.x/2.0, dim.y/2.0 - rad),
370             slt, lt.dash_width, vert_gap_width, &offset);
371   dash_arc(cent + position(dim.x/2.0 - rad, dim.y/2.0 - rad), rad,
372            0, M_PI/4.0, slt, lt.dash_width, vert_gap_width, &offset);
373
374   offset = lt.dash_width/2.0;
375   dash_arc(cent + position(dim.x/2.0 - rad, dim.y/2.0 - rad), rad,
376            M_PI/4.0, M_PI/2, slt, lt.dash_width, hor_gap_width, &offset);
377   dash_line(cent + position(dim.x/2.0 - rad, dim.y/2.0),
378             cent + position(-dim.x/2.0 + rad, dim.y/2.0),
379             slt, lt.dash_width, hor_gap_width, &offset);
380   dash_arc(cent + position(-dim.x/2.0 + rad, dim.y/2.0 - rad), rad,
381            M_PI/2, 3*M_PI/4.0, slt, lt.dash_width, hor_gap_width, &offset);
382
383   offset = lt.dash_width/2.0;
384   dash_arc(cent + position(-dim.x/2.0 + rad, dim.y/2.0 - rad), rad,
385            3.0*M_PI/4.0, M_PI, slt, lt.dash_width, vert_gap_width, &offset);
386   dash_line(cent + position(-dim.x/2.0, dim.y/2.0 - rad),
387             cent + position(-dim.x/2.0, -dim.y/2.0 + rad),
388             slt, lt.dash_width, vert_gap_width, &offset);
389   dash_arc(cent + position(-dim.x/2.0 + rad, -dim.y/2.0 + rad), rad,
390            M_PI, 5.0*M_PI/4.0, slt, lt.dash_width, vert_gap_width, &offset);
391
392   offset = lt.dash_width/2.0;
393   dash_arc(cent + position(-dim.x/2.0 + rad, -dim.y/2.0 + rad), rad,
394            5*M_PI/4.0, 3*M_PI/2.0, slt, lt.dash_width, hor_gap_width, &offset);
395   dash_line(cent + position(-dim.x/2.0 + rad, -dim.y/2.0),
396             cent + position(dim.x/2.0 - rad, -dim.y/2.0),
397             slt, lt.dash_width, hor_gap_width, &offset);
398   dash_arc(cent + position(dim.x/2.0 - rad, -dim.y/2.0 + rad), rad,
399            3*M_PI/2, 7*M_PI/4, slt, lt.dash_width, hor_gap_width, &offset);
400 }
401
402 // Used by dashed_rounded_box.
403
404 void common_output::dash_arc(const position &cent, double rad,
405                              double start_angle, double end_angle,
406                              const line_type &lt,
407                              double dash_width, double gap_width,
408                              double *offsetp)
409 {
410   double length = (end_angle - start_angle)*rad;
411   double pos = 0.0;
412   for (;;) {
413     if (*offsetp >= dash_width) {
414       double rem = dash_width + gap_width - *offsetp;
415       if (pos + rem > length) {
416         *offsetp += length - pos;
417         break;
418       }
419       else {
420         pos += rem;
421         *offsetp = 0.0;
422       }
423     }
424     else {
425       double rem = dash_width  - *offsetp;
426       if (pos + rem > length) {
427         solid_arc(cent, rad, start_angle + pos/rad, end_angle, lt);
428         *offsetp += length - pos;
429         break;
430       }
431       else {
432         solid_arc(cent, rad, start_angle + pos/rad,
433                   start_angle + (pos + rem)/rad, lt);
434         pos += rem;
435         *offsetp = dash_width;
436       }
437     }
438   }
439 }
440
441 // Used by dashed_rounded_box.
442
443 void common_output::dash_line(const position &start, const position &end,
444                               const line_type &lt,
445                               double dash_width, double gap_width,
446                               double *offsetp)
447 {
448   distance dist = end - start;
449   double length = hypot(dist);
450   if (length == 0.0)
451     return;
452   double pos = 0.0;
453   for (;;) {
454     if (*offsetp >= dash_width) {
455       double rem = dash_width + gap_width - *offsetp;
456       if (pos + rem > length) {
457         *offsetp += length - pos;
458         break;
459       }
460       else {
461         pos += rem;
462         *offsetp = 0.0;
463       }
464     }
465     else {
466       double rem = dash_width  - *offsetp;
467       if (pos + rem > length) {
468         line(start + dist*(pos/length), &end, 1, lt);
469         *offsetp += length - pos;
470         break;
471       }
472       else {
473         position p(start + dist*((pos + rem)/length));
474         line(start + dist*(pos/length), &p, 1, lt);
475         pos += rem;
476         *offsetp = dash_width;
477       }
478     }
479   }
480 }
481
482 void common_output::dotted_rounded_box(const position &cent,
483                                        const distance &dim, double rad,
484                                        const line_type &lt)
485 {
486   line_type slt = lt;
487   slt.type = line_type::solid;
488
489   double hor_length = dim.x + (M_PI/2.0 - 2.0)*rad;
490   int n_hor_dots = int(hor_length/lt.dash_width + .5);
491   double hor_gap_width = (n_hor_dots != 0
492                           ? hor_length/n_hor_dots
493                           : lt.dash_width);
494
495   double vert_length = dim.y + (M_PI/2.0 - 2.0)*rad;
496   int n_vert_dots = int(vert_length/lt.dash_width + .5);
497   double vert_gap_width = (n_vert_dots != 0
498                            ? vert_length/n_vert_dots
499                            : lt.dash_width);
500   double epsilon = lt.dash_width/(rad*100.0);
501
502   double offset = 0.0;
503   dot_arc(cent + position(dim.x/2.0 - rad, -dim.y/2.0 + rad), rad,
504            -M_PI/4.0, 0, slt, vert_gap_width, &offset);
505   dot_line(cent + position(dim.x/2.0, -dim.y/2.0 + rad),
506             cent + position(dim.x/2.0, dim.y/2.0 - rad),
507             slt, vert_gap_width, &offset);
508   dot_arc(cent + position(dim.x/2.0 - rad, dim.y/2.0 - rad), rad,
509            0, M_PI/4.0 - epsilon, slt, vert_gap_width, &offset);
510
511   offset = 0.0;
512   dot_arc(cent + position(dim.x/2.0 - rad, dim.y/2.0 - rad), rad,
513            M_PI/4.0, M_PI/2, slt, hor_gap_width, &offset);
514   dot_line(cent + position(dim.x/2.0 - rad, dim.y/2.0),
515             cent + position(-dim.x/2.0 + rad, dim.y/2.0),
516             slt, hor_gap_width, &offset);
517   dot_arc(cent + position(-dim.x/2.0 + rad, dim.y/2.0 - rad), rad,
518            M_PI/2, 3*M_PI/4.0 - epsilon, slt, hor_gap_width, &offset);
519
520   offset = 0.0;
521   dot_arc(cent + position(-dim.x/2.0 + rad, dim.y/2.0 - rad), rad,
522            3.0*M_PI/4.0, M_PI, slt, vert_gap_width, &offset);
523   dot_line(cent + position(-dim.x/2.0, dim.y/2.0 - rad),
524             cent + position(-dim.x/2.0, -dim.y/2.0 + rad),
525             slt, vert_gap_width, &offset);
526   dot_arc(cent + position(-dim.x/2.0 + rad, -dim.y/2.0 + rad), rad,
527            M_PI, 5.0*M_PI/4.0 - epsilon, slt, vert_gap_width, &offset);
528
529   offset = 0.0;
530   dot_arc(cent + position(-dim.x/2.0 + rad, -dim.y/2.0 + rad), rad,
531            5*M_PI/4.0, 3*M_PI/2.0, slt, hor_gap_width, &offset);
532   dot_line(cent + position(-dim.x/2.0 + rad, -dim.y/2.0),
533             cent + position(dim.x/2.0 - rad, -dim.y/2.0),
534             slt, hor_gap_width, &offset);
535   dot_arc(cent + position(dim.x/2.0 - rad, -dim.y/2.0 + rad), rad,
536            3*M_PI/2, 7*M_PI/4 - epsilon, slt, hor_gap_width, &offset);
537 }
538
539 // Used by dotted_rounded_box.
540
541 void common_output::dot_arc(const position &cent, double rad,
542                             double start_angle, double end_angle,
543                             const line_type &lt, double gap_width,
544                             double *offsetp)
545 {
546   double length = (end_angle - start_angle)*rad;
547   double pos = 0.0;
548   for (;;) {
549     if (*offsetp == 0.0) {
550       double ang = start_angle + pos/rad;
551       dot(cent + position(cos(ang), sin(ang))*rad, lt);
552     }
553     double rem = gap_width - *offsetp;
554     if (pos + rem > length) {
555       *offsetp += length - pos;
556       break;
557     }
558     else {
559       pos += rem;
560       *offsetp = 0.0;
561     }
562   }
563 }
564
565 // Used by dotted_rounded_box.
566
567 void common_output::dot_line(const position &start, const position &end,
568                              const line_type &lt, double gap_width,
569                              double *offsetp)
570 {
571   distance dist = end - start;
572   double length = hypot(dist);
573   if (length == 0.0)
574     return;
575   double pos = 0.0;
576   for (;;) {
577     if (*offsetp == 0.0)
578       dot(start + dist*(pos/length), lt);
579     double rem = gap_width - *offsetp;
580     if (pos + rem > length) {
581       *offsetp += length - pos;
582       break;
583     }
584     else {
585       pos += rem;
586       *offsetp = 0.0;
587     }
588   }
589 }
590
591 void common_output::solid_rounded_box(const position &cent,
592                                       const distance &dim, double rad,
593                                       const line_type &lt)
594 {
595   position tem = cent - dim/2.0;
596   arc(tem + position(0.0, rad),
597       tem + position(rad, rad),
598       tem + position(rad, 0.0),
599       lt);
600   tem = cent + position(-dim.x/2.0, dim.y/2.0);
601   arc(tem + position(rad, 0.0),
602       tem + position(rad, -rad),
603       tem + position(0.0, -rad),
604       lt);
605   tem = cent + dim/2.0;
606   arc(tem + position(0.0, -rad),
607       tem + position(-rad, -rad),
608       tem + position(-rad, 0.0),
609       lt);
610   tem = cent + position(dim.x/2.0, -dim.y/2.0);
611   arc(tem + position(-rad, 0.0),
612       tem + position(-rad, rad),
613       tem + position(0.0, rad),
614       lt);
615   position end;
616   end = cent + position(-dim.x/2.0, dim.y/2.0 - rad);
617   line(cent - dim/2.0 + position(0.0, rad), &end, 1, lt);
618   end = cent + position(dim.x/2.0 - rad, dim.y/2.0);
619   line(cent + position(-dim.x/2.0 + rad, dim.y/2.0), &end, 1, lt);
620   end = cent + position(dim.x/2.0, -dim.y/2.0 + rad);
621   line(cent + position(dim.x/2.0, dim.y/2.0 - rad), &end, 1, lt);
622   end = cent + position(-dim.x/2.0 + rad, -dim.y/2.0);
623   line(cent + position(dim.x/2.0 - rad, -dim.y/2.0), &end, 1, lt);
624 }
625
626 void common_output::filled_rounded_box(const position &cent,
627                                        const distance &dim, double rad,
628                                        double fill)
629 {
630   line_type ilt;
631   ilt.type = line_type::invisible;
632   circle(cent + position(dim.x/2.0 - rad, dim.y/2.0 - rad), rad, ilt, fill);
633   circle(cent + position(-dim.x/2.0 + rad, dim.y/2.0 - rad), rad, ilt, fill);
634   circle(cent + position(-dim.x/2.0 + rad, -dim.y/2.0 + rad), rad, ilt, fill);
635   circle(cent + position(dim.x/2.0 - rad, -dim.y/2.0 + rad), rad, ilt, fill);
636   position vec[4];
637   vec[0] = cent + position(dim.x/2.0, dim.y/2.0 - rad);
638   vec[1] = cent + position(-dim.x/2.0, dim.y/2.0 - rad);
639   vec[2] = cent + position(-dim.x/2.0, -dim.y/2.0 + rad);
640   vec[3] = cent + position(dim.x/2.0, -dim.y/2.0 + rad);
641   polygon(vec, 4, ilt, fill);
642   vec[0] = cent + position(dim.x/2.0 - rad, dim.y/2.0);
643   vec[1] = cent + position(-dim.x/2.0 + rad, dim.y/2.0);
644   vec[2] = cent + position(-dim.x/2.0 + rad, -dim.y/2.0);
645   vec[3] = cent + position(dim.x/2.0 - rad, -dim.y/2.0);
646   polygon(vec, 4, ilt, fill);
647 }