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