1114402Sru// -*- C++ -*- 2151497Sru/* Copyright (C) 1989, 1990, 1991, 1992, 2003 Free Software Foundation, Inc. 3114402Sru Written by James Clark (jjc@jclark.com) 4114402Sru 5114402SruThis file is part of groff. 6114402Sru 7114402Srugroff is free software; you can redistribute it and/or modify it under 8114402Sruthe terms of the GNU General Public License as published by the Free 9114402SruSoftware Foundation; either version 2, or (at your option) any later 10114402Sruversion. 11114402Sru 12114402Srugroff is distributed in the hope that it will be useful, but WITHOUT ANY 13114402SruWARRANTY; without even the implied warranty of MERCHANTABILITY or 14114402SruFITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 15114402Srufor more details. 16114402Sru 17114402SruYou should have received a copy of the GNU General Public License along 18114402Sruwith groff; see the file COPYING. If not, write to the Free Software 19151497SruFoundation, 51 Franklin St - Fifth Floor, Boston, MA 02110-1301, USA. */ 20114402Sru 21114402Sru#include "pic.h" 22114402Sru#include "common.h" 23114402Sru 24114402Sru// output a dashed circle as a series of arcs 25114402Sru 26114402Sruvoid common_output::dashed_circle(const position ¢, double rad, 27114402Sru const line_type <) 28114402Sru{ 29114402Sru assert(lt.type == line_type::dashed); 30114402Sru line_type slt = lt; 31114402Sru slt.type = line_type::solid; 32114402Sru double dash_angle = lt.dash_width/rad; 33114402Sru int ndashes; 34114402Sru double gap_angle; 35114402Sru if (dash_angle >= M_PI/4.0) { 36114402Sru if (dash_angle < M_PI/2.0) { 37114402Sru gap_angle = M_PI/2.0 - dash_angle; 38114402Sru ndashes = 4; 39114402Sru } 40114402Sru else if (dash_angle < M_PI) { 41114402Sru gap_angle = M_PI - dash_angle; 42114402Sru ndashes = 2; 43114402Sru } 44114402Sru else { 45114402Sru circle(cent, rad, slt, -1.0); 46114402Sru return; 47114402Sru } 48114402Sru } 49114402Sru else { 50114402Sru ndashes = 4*int(ceil(M_PI/(4.0*dash_angle))); 51114402Sru gap_angle = (M_PI*2.0)/ndashes - dash_angle; 52114402Sru } 53114402Sru for (int i = 0; i < ndashes; i++) { 54114402Sru double start_angle = i*(dash_angle+gap_angle) - dash_angle/2.0; 55114402Sru solid_arc(cent, rad, start_angle, start_angle + dash_angle, lt); 56114402Sru } 57114402Sru} 58114402Sru 59114402Sru// output a dotted circle as a series of dots 60114402Sru 61114402Sruvoid common_output::dotted_circle(const position ¢, double rad, 62114402Sru const line_type <) 63114402Sru{ 64114402Sru assert(lt.type == line_type::dotted); 65114402Sru double gap_angle = lt.dash_width/rad; 66114402Sru int ndots; 67114402Sru if (gap_angle >= M_PI/2.0) { 68114402Sru // always have at least 2 dots 69114402Sru gap_angle = M_PI; 70114402Sru ndots = 2; 71114402Sru } 72114402Sru else { 73114402Sru ndots = 4*int(M_PI/(2.0*gap_angle)); 74114402Sru gap_angle = (M_PI*2.0)/ndots; 75114402Sru } 76114402Sru double ang = 0.0; 77114402Sru for (int i = 0; i < ndots; i++, ang += gap_angle) 78114402Sru dot(cent + position(cos(ang), sin(ang))*rad, lt); 79114402Sru} 80114402Sru 81151497Sru// recursive function for dash drawing, used by dashed_ellipse 82151497Sru 83151497Sruvoid common_output::ellipse_arc(const position ¢, 84151497Sru const position &z0, const position &z1, 85151497Sru const distance &dim, const line_type <) 86151497Sru{ 87151497Sru assert(lt.type == line_type::solid); 88151497Sru assert(dim.x != 0 && dim.y != 0); 89151497Sru double eps = 0.0001; 90151497Sru position zml = (z0 + z1) / 2; 91151497Sru // apply affine transformation (from ellipse to circle) to compute angle 92151497Sru // of new position, then invert transformation to get exact position 93151497Sru double psi = atan2(zml.y / dim.y, zml.x / dim.x); 94151497Sru position zm = position(dim.x * cos(psi), dim.y * sin(psi)); 95151497Sru // to approximate the ellipse arc with one or more circle arcs, we 96151497Sru // first compute the radius of curvature in zm 97151497Sru double a_2 = dim.x * dim.x; 98151497Sru double a_4 = a_2 * a_2; 99151497Sru double b_2 = dim.y * dim.y; 100151497Sru double b_4 = b_2 * b_2; 101151497Sru double e_2 = a_2 - b_2; 102151497Sru double temp = a_4 * zm.y * zm.y + b_4 * zm.x * zm.x; 103151497Sru double rho = sqrt(temp / a_4 / b_4 * temp / a_4 / b_4 * temp); 104151497Sru // compute center of curvature circle 105151497Sru position M = position(e_2 * zm.x / a_2 * zm.x / a_2 * zm.x, 106151497Sru -e_2 * zm.y / b_2 * zm.y / b_2 * zm.y); 107151497Sru // compute distance between circle and ellipse arc at start and end 108151497Sru double phi0 = atan2(z0.y - M.y, z0.x - M.x); 109151497Sru double phi1 = atan2(z1.y - M.y, z1.x - M.x); 110151497Sru position M0 = position(rho * cos(phi0), rho * sin(phi0)) + M; 111151497Sru position M1 = position(rho * cos(phi1), rho * sin(phi1)) + M; 112151497Sru double dist0 = hypot(z0 - M0) / sqrt(z0 * z0); 113151497Sru double dist1 = hypot(z1 - M1) / sqrt(z1 * z1); 114151497Sru if (dist0 < eps && dist1 < eps) 115151497Sru solid_arc(M + cent, rho, phi0, phi1, lt); 116151497Sru else { 117151497Sru ellipse_arc(cent, z0, zm, dim, lt); 118151497Sru ellipse_arc(cent, zm, z1, dim, lt); 119151497Sru } 120151497Sru} 121151497Sru 122151497Sru// output a dashed ellipse as a series of arcs 123151497Sru 124151497Sruvoid common_output::dashed_ellipse(const position ¢, const distance &dim, 125151497Sru const line_type <) 126151497Sru{ 127151497Sru assert(lt.type == line_type::dashed); 128151497Sru double dim_x = dim.x / 2; 129151497Sru double dim_y = dim.y / 2; 130151497Sru line_type slt = lt; 131151497Sru slt.type = line_type::solid; 132151497Sru double dw = lt.dash_width; 133151497Sru // we use an approximation to compute the ellipse length (found in: 134151497Sru // Bronstein, Semendjajew, Taschenbuch der Mathematik) 135151497Sru double lambda = (dim.x - dim.y) / (dim.x + dim.y); 136151497Sru double le = M_PI / 2 * (dim.x + dim.y) 137151497Sru * ((64 - 3 * lambda * lambda * lambda * lambda ) 138151497Sru / (64 - 16 * lambda * lambda)); 139151497Sru // for symmetry we make nmax a multiple of 8 140151497Sru int nmax = 8 * int(le / dw / 8 + 0.5); 141151497Sru if (nmax < 8) { 142151497Sru nmax = 8; 143151497Sru dw = le / 8; 144151497Sru } 145151497Sru int ndash = nmax / 2; 146151497Sru double gapwidth = (le - dw * ndash) / ndash; 147151497Sru double l = 0; 148151497Sru position z = position(dim_x, 0); 149151497Sru position zdot = z; 150151497Sru int j = 0; 151151497Sru int jmax = int(10 / lt.dash_width); 152151497Sru for (int i = 0; i <= nmax; i++) { 153151497Sru position zold = z; 154151497Sru position zpre = zdot; 155151497Sru double ld = (int(i / 2) + 0.5) * dw + int((i + 1) / 2) * gapwidth; 156151497Sru double lold = 0; 157151497Sru double dl = 1; 158151497Sru // find next position for fixed arc length 159151497Sru while (l < ld) { 160151497Sru j++; 161151497Sru lold = l; 162151497Sru zold = z; 163151497Sru double phi = j * 2 * M_PI / jmax; 164151497Sru z = position(dim_x * cos(phi), dim_y * sin(phi)); 165151497Sru dl = hypot(z - zold); 166151497Sru l += dl; 167151497Sru } 168151497Sru // interpolate linearly between the last two points, 169151497Sru // using the length difference as the scaling factor 170151497Sru double delta = (ld - lold) / dl; 171151497Sru zdot = zold + (z - zold) * delta; 172151497Sru // compute angle of new position on the affine circle 173151497Sru // and use it to get the exact value on the ellipse 174151497Sru double psi = atan2(zdot.y / dim_y, zdot.x / dim_x); 175151497Sru zdot = position(dim_x * cos(psi), dim_y * sin(psi)); 176151497Sru if ((i % 2 == 0) && (i > 1)) 177151497Sru ellipse_arc(cent, zpre, zdot, dim / 2, slt); 178151497Sru } 179151497Sru} 180151497Sru 181151497Sru// output a dotted ellipse as a series of dots 182151497Sru 183151497Sruvoid common_output::dotted_ellipse(const position ¢, const distance &dim, 184151497Sru const line_type <) 185151497Sru{ 186151497Sru assert(lt.type == line_type::dotted); 187151497Sru double dim_x = dim.x / 2; 188151497Sru double dim_y = dim.y / 2; 189151497Sru line_type slt = lt; 190151497Sru slt.type = line_type::solid; 191151497Sru // we use an approximation to compute the ellipse length (found in: 192151497Sru // Bronstein, Semendjajew, Taschenbuch der Mathematik) 193151497Sru double lambda = (dim.x - dim.y) / (dim.x + dim.y); 194151497Sru double le = M_PI / 2 * (dim.x + dim.y) 195151497Sru * ((64 - 3 * lambda * lambda * lambda * lambda ) 196151497Sru / (64 - 16 * lambda * lambda)); 197151497Sru // for symmetry we make nmax a multiple of 4 198151497Sru int ndots = 4 * int(le / lt.dash_width / 4 + 0.5); 199151497Sru if (ndots < 4) 200151497Sru ndots = 4; 201151497Sru double l = 0; 202151497Sru position z = position(dim_x, 0); 203151497Sru int j = 0; 204151497Sru int jmax = int(10 / lt.dash_width); 205151497Sru for (int i = 1; i <= ndots; i++) { 206151497Sru position zold = z; 207151497Sru double lold = l; 208151497Sru double ld = i * le / ndots; 209151497Sru double dl = 1; 210151497Sru // find next position for fixed arc length 211151497Sru while (l < ld) { 212151497Sru j++; 213151497Sru lold = l; 214151497Sru zold = z; 215151497Sru double phi = j * 2 * M_PI / jmax; 216151497Sru z = position(dim_x * cos(phi), dim_y * sin(phi)); 217151497Sru dl = hypot(z - zold); 218151497Sru l += dl; 219151497Sru } 220151497Sru // interpolate linearly between the last two points, 221151497Sru // using the length difference as the scaling factor 222151497Sru double delta = (ld - lold) / dl; 223151497Sru position zdot = zold + (z - zold) * delta; 224151497Sru // compute angle of new position on the affine circle 225151497Sru // and use it to get the exact value on the ellipse 226151497Sru double psi = atan2(zdot.y / dim_y, zdot.x / dim_x); 227151497Sru zdot = position(dim_x * cos(psi), dim_y * sin(psi)); 228151497Sru dot(cent + zdot, slt); 229151497Sru } 230151497Sru} 231151497Sru 232114402Sru// return non-zero iff we can compute a center 233114402Sru 234114402Sruint compute_arc_center(const position &start, const position ¢, 235114402Sru const position &end, position *result) 236114402Sru{ 237114402Sru // This finds the point along the vector from start to cent that 238114402Sru // is equidistant between start and end. 239114402Sru distance c = cent - start; 240114402Sru distance e = end - start; 241114402Sru double n = c*e; 242114402Sru if (n == 0.0) 243114402Sru return 0; 244114402Sru *result = start + c*((e*e)/(2.0*n)); 245114402Sru return 1; 246114402Sru} 247114402Sru 248114402Sru// output a dashed arc as a series of arcs 249114402Sru 250114402Sruvoid common_output::dashed_arc(const position &start, const position ¢, 251114402Sru const position &end, const line_type <) 252114402Sru{ 253114402Sru assert(lt.type == line_type::dashed); 254114402Sru position c; 255114402Sru if (!compute_arc_center(start, cent, end, &c)) { 256114402Sru line(start, &end, 1, lt); 257114402Sru return; 258114402Sru } 259114402Sru distance start_offset = start - c; 260114402Sru distance end_offset = end - c; 261114402Sru double start_angle = atan2(start_offset.y, start_offset.x); 262114402Sru double end_angle = atan2(end_offset.y, end_offset.x); 263114402Sru double rad = hypot(c - start); 264114402Sru double dash_angle = lt.dash_width/rad; 265114402Sru double total_angle = end_angle - start_angle; 266114402Sru while (total_angle < 0) 267114402Sru total_angle += M_PI + M_PI; 268114402Sru if (total_angle <= dash_angle*2.0) { 269114402Sru solid_arc(cent, rad, start_angle, end_angle, lt); 270114402Sru return; 271114402Sru } 272114402Sru int ndashes = int((total_angle - dash_angle)/(dash_angle*2.0) + .5); 273114402Sru double dash_and_gap_angle = (total_angle - dash_angle)/ndashes; 274114402Sru for (int i = 0; i <= ndashes; i++) 275114402Sru solid_arc(cent, rad, start_angle + i*dash_and_gap_angle, 276114402Sru start_angle + i*dash_and_gap_angle + dash_angle, lt); 277114402Sru} 278114402Sru 279114402Sru// output a dotted arc as a series of dots 280114402Sru 281114402Sruvoid common_output::dotted_arc(const position &start, const position ¢, 282114402Sru const position &end, const line_type <) 283114402Sru{ 284114402Sru assert(lt.type == line_type::dotted); 285114402Sru position c; 286114402Sru if (!compute_arc_center(start, cent, end, &c)) { 287114402Sru line(start, &end, 1, lt); 288114402Sru return; 289114402Sru } 290114402Sru distance start_offset = start - c; 291114402Sru distance end_offset = end - c; 292114402Sru double start_angle = atan2(start_offset.y, start_offset.x); 293114402Sru double total_angle = atan2(end_offset.y, end_offset.x) - start_angle; 294114402Sru while (total_angle < 0) 295114402Sru total_angle += M_PI + M_PI; 296114402Sru double rad = hypot(c - start); 297114402Sru int ndots = int(total_angle/(lt.dash_width/rad) + .5); 298114402Sru if (ndots == 0) 299114402Sru dot(start, lt); 300114402Sru else { 301114402Sru for (int i = 0; i <= ndots; i++) { 302114402Sru double a = start_angle + (total_angle*i)/ndots; 303114402Sru dot(cent + position(cos(a), sin(a))*rad, lt); 304114402Sru } 305114402Sru } 306114402Sru} 307114402Sru 308114402Sruvoid common_output::solid_arc(const position ¢, double rad, 309114402Sru double start_angle, double end_angle, 310114402Sru const line_type <) 311114402Sru{ 312114402Sru line_type slt = lt; 313114402Sru slt.type = line_type::solid; 314114402Sru arc(cent + position(cos(start_angle), sin(start_angle))*rad, 315114402Sru cent, 316114402Sru cent + position(cos(end_angle), sin(end_angle))*rad, 317114402Sru slt); 318114402Sru} 319114402Sru 320114402Sru 321114402Sruvoid common_output::rounded_box(const position ¢, const distance &dim, 322114402Sru double rad, const line_type <, double fill) 323114402Sru{ 324114402Sru if (fill >= 0.0) 325114402Sru filled_rounded_box(cent, dim, rad, fill); 326114402Sru switch (lt.type) { 327114402Sru case line_type::invisible: 328114402Sru break; 329114402Sru case line_type::dashed: 330114402Sru dashed_rounded_box(cent, dim, rad, lt); 331114402Sru break; 332114402Sru case line_type::dotted: 333114402Sru dotted_rounded_box(cent, dim, rad, lt); 334114402Sru break; 335114402Sru case line_type::solid: 336114402Sru solid_rounded_box(cent, dim, rad, lt); 337114402Sru break; 338114402Sru default: 339114402Sru assert(0); 340114402Sru } 341114402Sru} 342114402Sru 343114402Sru 344114402Sruvoid common_output::dashed_rounded_box(const position ¢, 345114402Sru const distance &dim, double rad, 346114402Sru const line_type <) 347114402Sru{ 348114402Sru line_type slt = lt; 349114402Sru slt.type = line_type::solid; 350114402Sru 351114402Sru double hor_length = dim.x + (M_PI/2.0 - 2.0)*rad; 352114402Sru int n_hor_dashes = int(hor_length/(lt.dash_width*2.0) + .5); 353114402Sru double hor_gap_width = (n_hor_dashes != 0 354114402Sru ? hor_length/n_hor_dashes - lt.dash_width 355114402Sru : 0.0); 356114402Sru 357114402Sru double vert_length = dim.y + (M_PI/2.0 - 2.0)*rad; 358114402Sru int n_vert_dashes = int(vert_length/(lt.dash_width*2.0) + .5); 359114402Sru double vert_gap_width = (n_vert_dashes != 0 360114402Sru ? vert_length/n_vert_dashes - lt.dash_width 361114402Sru : 0.0); 362114402Sru // Note that each corner arc has to be split into two for dashing, 363114402Sru // because one part is dashed using vert_gap_width, and the other 364114402Sru // using hor_gap_width. 365114402Sru double offset = lt.dash_width/2.0; 366114402Sru dash_arc(cent + position(dim.x/2.0 - rad, -dim.y/2.0 + rad), rad, 367114402Sru -M_PI/4.0, 0, slt, lt.dash_width, vert_gap_width, &offset); 368114402Sru dash_line(cent + position(dim.x/2.0, -dim.y/2.0 + rad), 369114402Sru cent + position(dim.x/2.0, dim.y/2.0 - rad), 370114402Sru slt, lt.dash_width, vert_gap_width, &offset); 371114402Sru dash_arc(cent + position(dim.x/2.0 - rad, dim.y/2.0 - rad), rad, 372114402Sru 0, M_PI/4.0, slt, lt.dash_width, vert_gap_width, &offset); 373114402Sru 374114402Sru offset = lt.dash_width/2.0; 375114402Sru dash_arc(cent + position(dim.x/2.0 - rad, dim.y/2.0 - rad), rad, 376114402Sru M_PI/4.0, M_PI/2, slt, lt.dash_width, hor_gap_width, &offset); 377114402Sru dash_line(cent + position(dim.x/2.0 - rad, dim.y/2.0), 378114402Sru cent + position(-dim.x/2.0 + rad, dim.y/2.0), 379114402Sru slt, lt.dash_width, hor_gap_width, &offset); 380114402Sru dash_arc(cent + position(-dim.x/2.0 + rad, dim.y/2.0 - rad), rad, 381114402Sru M_PI/2, 3*M_PI/4.0, slt, lt.dash_width, hor_gap_width, &offset); 382114402Sru 383114402Sru offset = lt.dash_width/2.0; 384114402Sru dash_arc(cent + position(-dim.x/2.0 + rad, dim.y/2.0 - rad), rad, 385114402Sru 3.0*M_PI/4.0, M_PI, slt, lt.dash_width, vert_gap_width, &offset); 386114402Sru dash_line(cent + position(-dim.x/2.0, dim.y/2.0 - rad), 387114402Sru cent + position(-dim.x/2.0, -dim.y/2.0 + rad), 388114402Sru slt, lt.dash_width, vert_gap_width, &offset); 389114402Sru dash_arc(cent + position(-dim.x/2.0 + rad, -dim.y/2.0 + rad), rad, 390114402Sru M_PI, 5.0*M_PI/4.0, slt, lt.dash_width, vert_gap_width, &offset); 391114402Sru 392114402Sru offset = lt.dash_width/2.0; 393114402Sru dash_arc(cent + position(-dim.x/2.0 + rad, -dim.y/2.0 + rad), rad, 394114402Sru 5*M_PI/4.0, 3*M_PI/2.0, slt, lt.dash_width, hor_gap_width, &offset); 395114402Sru dash_line(cent + position(-dim.x/2.0 + rad, -dim.y/2.0), 396114402Sru cent + position(dim.x/2.0 - rad, -dim.y/2.0), 397114402Sru slt, lt.dash_width, hor_gap_width, &offset); 398114402Sru dash_arc(cent + position(dim.x/2.0 - rad, -dim.y/2.0 + rad), rad, 399114402Sru 3*M_PI/2, 7*M_PI/4, slt, lt.dash_width, hor_gap_width, &offset); 400114402Sru} 401114402Sru 402114402Sru// Used by dashed_rounded_box. 403114402Sru 404114402Sruvoid common_output::dash_arc(const position ¢, double rad, 405114402Sru double start_angle, double end_angle, 406114402Sru const line_type <, 407114402Sru double dash_width, double gap_width, 408114402Sru double *offsetp) 409114402Sru{ 410114402Sru double length = (end_angle - start_angle)*rad; 411114402Sru double pos = 0.0; 412114402Sru for (;;) { 413114402Sru if (*offsetp >= dash_width) { 414114402Sru double rem = dash_width + gap_width - *offsetp; 415114402Sru if (pos + rem > length) { 416114402Sru *offsetp += length - pos; 417114402Sru break; 418114402Sru } 419114402Sru else { 420114402Sru pos += rem; 421114402Sru *offsetp = 0.0; 422114402Sru } 423114402Sru } 424114402Sru else { 425114402Sru double rem = dash_width - *offsetp; 426114402Sru if (pos + rem > length) { 427114402Sru solid_arc(cent, rad, start_angle + pos/rad, end_angle, lt); 428114402Sru *offsetp += length - pos; 429114402Sru break; 430114402Sru } 431114402Sru else { 432114402Sru solid_arc(cent, rad, start_angle + pos/rad, 433114402Sru start_angle + (pos + rem)/rad, lt); 434114402Sru pos += rem; 435114402Sru *offsetp = dash_width; 436114402Sru } 437114402Sru } 438114402Sru } 439114402Sru} 440114402Sru 441114402Sru// Used by dashed_rounded_box. 442114402Sru 443114402Sruvoid common_output::dash_line(const position &start, const position &end, 444114402Sru const line_type <, 445114402Sru double dash_width, double gap_width, 446114402Sru double *offsetp) 447114402Sru{ 448114402Sru distance dist = end - start; 449114402Sru double length = hypot(dist); 450114402Sru if (length == 0.0) 451114402Sru return; 452114402Sru double pos = 0.0; 453114402Sru for (;;) { 454114402Sru if (*offsetp >= dash_width) { 455114402Sru double rem = dash_width + gap_width - *offsetp; 456114402Sru if (pos + rem > length) { 457114402Sru *offsetp += length - pos; 458114402Sru break; 459114402Sru } 460114402Sru else { 461114402Sru pos += rem; 462114402Sru *offsetp = 0.0; 463114402Sru } 464114402Sru } 465114402Sru else { 466114402Sru double rem = dash_width - *offsetp; 467114402Sru if (pos + rem > length) { 468114402Sru line(start + dist*(pos/length), &end, 1, lt); 469114402Sru *offsetp += length - pos; 470114402Sru break; 471114402Sru } 472114402Sru else { 473114402Sru position p(start + dist*((pos + rem)/length)); 474114402Sru line(start + dist*(pos/length), &p, 1, lt); 475114402Sru pos += rem; 476114402Sru *offsetp = dash_width; 477114402Sru } 478114402Sru } 479114402Sru } 480114402Sru} 481114402Sru 482114402Sruvoid common_output::dotted_rounded_box(const position ¢, 483114402Sru const distance &dim, double rad, 484114402Sru const line_type <) 485114402Sru{ 486114402Sru line_type slt = lt; 487114402Sru slt.type = line_type::solid; 488114402Sru 489114402Sru double hor_length = dim.x + (M_PI/2.0 - 2.0)*rad; 490114402Sru int n_hor_dots = int(hor_length/lt.dash_width + .5); 491114402Sru double hor_gap_width = (n_hor_dots != 0 492114402Sru ? hor_length/n_hor_dots 493114402Sru : lt.dash_width); 494114402Sru 495114402Sru double vert_length = dim.y + (M_PI/2.0 - 2.0)*rad; 496114402Sru int n_vert_dots = int(vert_length/lt.dash_width + .5); 497114402Sru double vert_gap_width = (n_vert_dots != 0 498114402Sru ? vert_length/n_vert_dots 499114402Sru : lt.dash_width); 500114402Sru double epsilon = lt.dash_width/(rad*100.0); 501114402Sru 502114402Sru double offset = 0.0; 503114402Sru dot_arc(cent + position(dim.x/2.0 - rad, -dim.y/2.0 + rad), rad, 504114402Sru -M_PI/4.0, 0, slt, vert_gap_width, &offset); 505114402Sru dot_line(cent + position(dim.x/2.0, -dim.y/2.0 + rad), 506114402Sru cent + position(dim.x/2.0, dim.y/2.0 - rad), 507114402Sru slt, vert_gap_width, &offset); 508114402Sru dot_arc(cent + position(dim.x/2.0 - rad, dim.y/2.0 - rad), rad, 509114402Sru 0, M_PI/4.0 - epsilon, slt, vert_gap_width, &offset); 510114402Sru 511114402Sru offset = 0.0; 512114402Sru dot_arc(cent + position(dim.x/2.0 - rad, dim.y/2.0 - rad), rad, 513114402Sru M_PI/4.0, M_PI/2, slt, hor_gap_width, &offset); 514114402Sru dot_line(cent + position(dim.x/2.0 - rad, dim.y/2.0), 515114402Sru cent + position(-dim.x/2.0 + rad, dim.y/2.0), 516114402Sru slt, hor_gap_width, &offset); 517114402Sru dot_arc(cent + position(-dim.x/2.0 + rad, dim.y/2.0 - rad), rad, 518114402Sru M_PI/2, 3*M_PI/4.0 - epsilon, slt, hor_gap_width, &offset); 519114402Sru 520114402Sru offset = 0.0; 521114402Sru dot_arc(cent + position(-dim.x/2.0 + rad, dim.y/2.0 - rad), rad, 522114402Sru 3.0*M_PI/4.0, M_PI, slt, vert_gap_width, &offset); 523114402Sru dot_line(cent + position(-dim.x/2.0, dim.y/2.0 - rad), 524114402Sru cent + position(-dim.x/2.0, -dim.y/2.0 + rad), 525114402Sru slt, vert_gap_width, &offset); 526114402Sru dot_arc(cent + position(-dim.x/2.0 + rad, -dim.y/2.0 + rad), rad, 527114402Sru M_PI, 5.0*M_PI/4.0 - epsilon, slt, vert_gap_width, &offset); 528114402Sru 529114402Sru offset = 0.0; 530114402Sru dot_arc(cent + position(-dim.x/2.0 + rad, -dim.y/2.0 + rad), rad, 531114402Sru 5*M_PI/4.0, 3*M_PI/2.0, slt, hor_gap_width, &offset); 532114402Sru dot_line(cent + position(-dim.x/2.0 + rad, -dim.y/2.0), 533114402Sru cent + position(dim.x/2.0 - rad, -dim.y/2.0), 534114402Sru slt, hor_gap_width, &offset); 535114402Sru dot_arc(cent + position(dim.x/2.0 - rad, -dim.y/2.0 + rad), rad, 536114402Sru 3*M_PI/2, 7*M_PI/4 - epsilon, slt, hor_gap_width, &offset); 537114402Sru} 538114402Sru 539114402Sru// Used by dotted_rounded_box. 540114402Sru 541114402Sruvoid common_output::dot_arc(const position ¢, double rad, 542114402Sru double start_angle, double end_angle, 543114402Sru const line_type <, double gap_width, 544114402Sru double *offsetp) 545114402Sru{ 546114402Sru double length = (end_angle - start_angle)*rad; 547114402Sru double pos = 0.0; 548114402Sru for (;;) { 549114402Sru if (*offsetp == 0.0) { 550114402Sru double ang = start_angle + pos/rad; 551114402Sru dot(cent + position(cos(ang), sin(ang))*rad, lt); 552114402Sru } 553114402Sru double rem = gap_width - *offsetp; 554114402Sru if (pos + rem > length) { 555114402Sru *offsetp += length - pos; 556114402Sru break; 557114402Sru } 558114402Sru else { 559114402Sru pos += rem; 560114402Sru *offsetp = 0.0; 561114402Sru } 562114402Sru } 563114402Sru} 564114402Sru 565114402Sru// Used by dotted_rounded_box. 566114402Sru 567114402Sruvoid common_output::dot_line(const position &start, const position &end, 568114402Sru const line_type <, double gap_width, 569114402Sru double *offsetp) 570114402Sru{ 571114402Sru distance dist = end - start; 572114402Sru double length = hypot(dist); 573114402Sru if (length == 0.0) 574114402Sru return; 575114402Sru double pos = 0.0; 576114402Sru for (;;) { 577114402Sru if (*offsetp == 0.0) 578114402Sru dot(start + dist*(pos/length), lt); 579114402Sru double rem = gap_width - *offsetp; 580114402Sru if (pos + rem > length) { 581114402Sru *offsetp += length - pos; 582114402Sru break; 583114402Sru } 584114402Sru else { 585114402Sru pos += rem; 586114402Sru *offsetp = 0.0; 587114402Sru } 588114402Sru } 589114402Sru} 590114402Sru 591114402Sruvoid common_output::solid_rounded_box(const position ¢, 592114402Sru const distance &dim, double rad, 593114402Sru const line_type <) 594114402Sru{ 595114402Sru position tem = cent - dim/2.0; 596114402Sru arc(tem + position(0.0, rad), 597114402Sru tem + position(rad, rad), 598114402Sru tem + position(rad, 0.0), 599114402Sru lt); 600114402Sru tem = cent + position(-dim.x/2.0, dim.y/2.0); 601114402Sru arc(tem + position(rad, 0.0), 602114402Sru tem + position(rad, -rad), 603114402Sru tem + position(0.0, -rad), 604114402Sru lt); 605114402Sru tem = cent + dim/2.0; 606114402Sru arc(tem + position(0.0, -rad), 607114402Sru tem + position(-rad, -rad), 608114402Sru tem + position(-rad, 0.0), 609114402Sru lt); 610114402Sru tem = cent + position(dim.x/2.0, -dim.y/2.0); 611114402Sru arc(tem + position(-rad, 0.0), 612114402Sru tem + position(-rad, rad), 613114402Sru tem + position(0.0, rad), 614114402Sru lt); 615114402Sru position end; 616114402Sru end = cent + position(-dim.x/2.0, dim.y/2.0 - rad); 617114402Sru line(cent - dim/2.0 + position(0.0, rad), &end, 1, lt); 618114402Sru end = cent + position(dim.x/2.0 - rad, dim.y/2.0); 619114402Sru line(cent + position(-dim.x/2.0 + rad, dim.y/2.0), &end, 1, lt); 620114402Sru end = cent + position(dim.x/2.0, -dim.y/2.0 + rad); 621114402Sru line(cent + position(dim.x/2.0, dim.y/2.0 - rad), &end, 1, lt); 622114402Sru end = cent + position(-dim.x/2.0 + rad, -dim.y/2.0); 623114402Sru line(cent + position(dim.x/2.0 - rad, -dim.y/2.0), &end, 1, lt); 624114402Sru} 625114402Sru 626114402Sruvoid common_output::filled_rounded_box(const position ¢, 627114402Sru const distance &dim, double rad, 628114402Sru double fill) 629114402Sru{ 630114402Sru line_type ilt; 631114402Sru ilt.type = line_type::invisible; 632114402Sru circle(cent + position(dim.x/2.0 - rad, dim.y/2.0 - rad), rad, ilt, fill); 633114402Sru circle(cent + position(-dim.x/2.0 + rad, dim.y/2.0 - rad), rad, ilt, fill); 634114402Sru circle(cent + position(-dim.x/2.0 + rad, -dim.y/2.0 + rad), rad, ilt, fill); 635114402Sru circle(cent + position(dim.x/2.0 - rad, -dim.y/2.0 + rad), rad, ilt, fill); 636114402Sru position vec[4]; 637114402Sru vec[0] = cent + position(dim.x/2.0, dim.y/2.0 - rad); 638114402Sru vec[1] = cent + position(-dim.x/2.0, dim.y/2.0 - rad); 639114402Sru vec[2] = cent + position(-dim.x/2.0, -dim.y/2.0 + rad); 640114402Sru vec[3] = cent + position(dim.x/2.0, -dim.y/2.0 + rad); 641114402Sru polygon(vec, 4, ilt, fill); 642114402Sru vec[0] = cent + position(dim.x/2.0 - rad, dim.y/2.0); 643114402Sru vec[1] = cent + position(-dim.x/2.0 + rad, dim.y/2.0); 644114402Sru vec[2] = cent + position(-dim.x/2.0 + rad, -dim.y/2.0); 645114402Sru vec[3] = cent + position(dim.x/2.0 - rad, -dim.y/2.0); 646114402Sru polygon(vec, 4, ilt, fill); 647114402Sru} 648