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 ¢, double rad, 29 const line_type <) 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 ¢, double rad, 64 const line_type <) 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 ¢, 86 const position &z0, const position &z1, 87 const distance &dim, const line_type <) 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 ¢, const distance &dim, 127 const line_type <) 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 ¢, const distance &dim, 186 const line_type <) 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 ¢, 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 ¢, 253 const position &end, const line_type <) 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 ¢, 284 const position &end, const line_type <) 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 ¢, double rad, 311 double start_angle, double end_angle, 312 const line_type <) 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 ¢, const distance &dim, 324 double rad, const line_type <, 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 ¢, 347 const distance &dim, double rad, 348 const line_type <) 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 ¢, double rad, 407 double start_angle, double end_angle, 408 const line_type <, 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 <, 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 ¢, 485 const distance &dim, double rad, 486 const line_type <) 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 ¢, double rad, 544 double start_angle, double end_angle, 545 const line_type <, 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 <, 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 ¢, 594 const distance &dim, double rad, 595 const line_type <) 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 ¢, 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