/contrib/groff/src/preproc/pic/common.cpp

https://bitbucket.org/freebsd/freebsd-head/ · C++ · 647 lines · 544 code · 44 blank · 59 comment · 78 complexity · 1bcaffaab9474619671ac1bc10349f3b MD5 · raw file

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