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