common.cpp revision 296373
1// -*- C++ -*- 2/* Copyright (C) 1989, 1990, 1991, 1992, 2003 Free Software Foundation, Inc. 3 Written by James Clark (jjc@jclark.com) 4 5This file is part of groff. 6 7groff is free software; you can redistribute it and/or modify it under 8the terms of the GNU General Public License as published by the Free 9Software Foundation; either version 2, or (at your option) any later 10version. 11 12groff is distributed in the hope that it will be useful, but WITHOUT ANY 13WARRANTY; without even the implied warranty of MERCHANTABILITY or 14FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 15for more details. 16 17You should have received a copy of the GNU General Public License along 18with groff; see the file COPYING. If not, write to the Free Software 19Foundation, 51 Franklin St - Fifth Floor, Boston, MA 02110-1301, USA. */ 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 ¢, double rad, 27 const line_type <) 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 ¢, double rad, 62 const line_type <) 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 ¢, 84 const position &z0, const position &z1, 85 const distance &dim, const line_type <) 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 ¢, const distance &dim, 125 const line_type <) 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 ¢, const distance &dim, 184 const line_type <) 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 ¢, 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 ¢, 251 const position &end, const line_type <) 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 ¢, 282 const position &end, const line_type <) 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 ¢, double rad, 309 double start_angle, double end_angle, 310 const line_type <) 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 ¢, const distance &dim, 322 double rad, const line_type <, double fill) 323{ 324 if (fill >= 0.0) 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 344void common_output::dashed_rounded_box(const position ¢, 345 const distance &dim, double rad, 346 const line_type <) 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 404void common_output::dash_arc(const position ¢, double rad, 405 double start_angle, double end_angle, 406 const line_type <, 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 443void common_output::dash_line(const position &start, const position &end, 444 const line_type <, 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 482void common_output::dotted_rounded_box(const position ¢, 483 const distance &dim, double rad, 484 const line_type <) 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 541void common_output::dot_arc(const position ¢, double rad, 542 double start_angle, double end_angle, 543 const line_type <, 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 567void common_output::dot_line(const position &start, const position &end, 568 const line_type <, 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 591void common_output::solid_rounded_box(const position ¢, 592 const distance &dim, double rad, 593 const line_type <) 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 626void common_output::filled_rounded_box(const position ¢, 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} 648