groff: update vendor branch to v1.20.1
[dragonfly.git] / contrib / groff / src / preproc / pic / common.cpp
CommitLineData
92d0a6a6 1// -*- C++ -*-
4d3e9548
JL
2/* Copyright (C) 1989, 1990, 1991, 1992, 2003, 2007, 2009
3 Free Software Foundation, Inc.
92d0a6a6
JR
4 Written by James Clark (jjc@jclark.com)
5
6This file is part of groff.
7
8groff is free software; you can redistribute it and/or modify it under
9the terms of the GNU General Public License as published by the Free
4d3e9548
JL
10Software Foundation, either version 3 of the License, or
11(at your option) any later version.
92d0a6a6
JR
12
13groff is distributed in the hope that it will be useful, but WITHOUT ANY
14WARRANTY; without even the implied warranty of MERCHANTABILITY or
15FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
16for more details.
17
4d3e9548
JL
18You should have received a copy of the GNU General Public License
19along with this program. If not, see <http://www.gnu.org/licenses/>. */
92d0a6a6
JR
20
21#include "pic.h"
22#include "common.h"
23
24// output a dashed circle as a series of arcs
25
26void 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
61void 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
83void 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
124void 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
183void 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
234int 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
250void 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
281void 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
308void 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
321void common_output::rounded_box(const position &cent, const distance &dim,
4d3e9548
JL
322 double rad, const line_type &lt,
323 double fill, char *color_fill)
92d0a6a6 324{
4d3e9548 325 if (fill >= 0.0 || color_fill)
92d0a6a6
JR
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
345void 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
405void 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
444void 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
483void 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
542void 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
568void 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
592void 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
627void 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}