1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232
|
From: Thomas Loimer <thomas.loimer@tuwien.ac.at>
Date: Thu, 11 Aug 2022 16:43:11 +0200
Origin: upstream, https://sourceforge.net/p/mcj/fig2dev/ci/ed4d044
Bug: https://sourceforge.net/p/mcj/tickets/145/ https://sourceforge.net/p/mcj/tickets/148/
Subject: Pict2e output: Arcs ending at multiples of pi/4, #145, #148
For the pict2e output language, arcs are drawn by first constructing a circle
of the same radius, generated from a spline. A section corresponding to the
arc angle is then cut out from the line forming the circle. Find the end point
on the circle by comparing the short coordinate of each point with the sinus
or cosinus, respectively, of the end angle times the radius of the circle.
Comparing the long coordinate, apart from being a glancing intersection, may
fail, since the constructed spline slightly wobbles around the true radius.
Less than 1.5 promille, but enough to trigger an error, see tickets #145 and
#148.
--- a/fig2dev/dev/genpict2e.c
+++ b/fig2dev/dev/genpict2e.c
@@ -3,7 +3,7 @@
* Copyright (c) 1991 by Micah Beck
* Parts Copyright (c) 1985-1988 by Supoj Sutanthavibul
* Parts Copyright (c) 1989-2015 by Brian V. Smith
- * Parts Copyright (c) 2015-2020 by Thomas Loimer
+ * Parts Copyright (c) 2015-2022 by Thomas Loimer
*
* Any party obtaining a copy of these files is granted, free of charge, a
* full and unrestricted irrevocable, world-wide, paid up, royalty-free,
@@ -33,8 +33,7 @@
#include <string.h>
#include <math.h>
-#include "fig2dev.h" /* includes bool.h and object.h */
-//#include "object.h"
+#include "fig2dev.h" /* includes bool.h and object.h */
#include "bound.h"
#include "free.h" /* free_linestorage() */
#include "messages.h"
@@ -200,8 +199,6 @@ struct pict2earrow {
#define YDIR(y) -(y)
#define EQUAL(p,q) (p->x == q->x && p->y == q->y)
/* cast to double, to not have the integers overflow */
-#define LENGTH(p,q) sqrt(((double) (q->x - p->x))*(q->x - p->x) \
- + ((double)(q->y - p->y))*(q->y - p->y))
#define THICKNESS(T) (T <= THICK_SCALE ? 0.5*T : T - THICK_SCALE)
/* THICK_SCALE is of type float, see fig2dev.h */
/* #define round (int)... see fig2dev.h */
@@ -963,10 +960,12 @@ put_patternline(F_point *p, F_point *q,
double len, lenpq, dx, dy, cosl, sinl, digits, dlx[PAT_ND_2];
F_pos pstart, slope[PAT_ND_2];
+#define DISTANCE(p,q) sqrt(((double) (q->x - p->x))*(q->x - p->x) \
+ + ((double)(q->y - p->y))*(q->y - p->y))
/* put a remaining dash */
if (h1 < 0) {
len = pattern->d[dstart] + h1; /* the remaining length of the dash */
- while ((lenpq = LENGTH(p,q)) <= len) {
+ while ((lenpq = DISTANCE(p,q)) <= len) {
if (q->next == NULL)
return;
len -= lenpq;
@@ -990,12 +989,13 @@ put_patternline(F_point *p, F_point *q,
* |offset|
* wind forward through the points which lie within the offset
*/
- while ((lenpq = LENGTH(p,q)) <= h1) {
+ while ((lenpq = DISTANCE(p,q)) <= h1) {
if (q->next == NULL) return;
h1 -= lenpq;
p = q;
q = q->next;
}
+#undef DISTANCE
/* calculate the number of dash patterns
* ndp - the number of full dash patterns, that fit into this line segment */
@@ -2332,11 +2332,11 @@ static void
put_patternarc(
F_pos *c, /* center point */
double rad, /* radius */
- double da, /* arc angle */
+ double da, /* arc angle, must be positive */
double angle1, /* start angle */
F_arc *a)
{
- int i, cosa2, sina2, px;
+ int i, cosa2, sina2;
double a1, a2, rot, cosr, sinr;
F_spline s;
F_line *l;
@@ -2345,6 +2345,7 @@ put_patternarc(
F_control z[8];
struct d_pos u[8]; /* octagon points on the unit circle */
+ /* Create a x-spline approximating a circle */
get_xsplinepoints(z,u,1.025821);
/* scale the control points */
for (i = 0; i < 8; ++i) {
@@ -2376,41 +2377,57 @@ put_patternarc(
if (p == NULL)
return;
- /* the octagon runs in clockwise direction.
+ /*
+ * Walk along the spline, until the arc angle is covered.
+ * The octagon runs in clockwise direction.
* a1 is approx. 3*pi/8 (strangely, the control points for the octagon
- * start at 5*pi/8). If create_line_with_splines() changes, the
- * following breaks! */
+ * start at 5*pi/8). If the start point given by a1 changes, because
+ * create_line_with_splines() changes, the following breaks.
+ */
a1 = atan2(p->y, p->x);
a2 = a1 - da;
sinr = sin(a2);
cosr = cos(a2);
sina2 = round(rad*sinr);
cosa2 = round(rad*cosr);
- if (a2 >= M_PI_4)
- while (p->x < cosa2) {
- o[3].next = p;
- p = p->next;
- }
- else
- while (p->y > sina2) {
- o[3].next = p;
- p = p->next;
- }
- if (a2 < -M_PI_4)
- while (p->x > cosa2) {
- o[3].next = p;
- p = p->next;
- }
- if (a2 < -3. * M_PI_4)
- while (p->y < sina2) {
- o[3].next = p;
- p = p->next;
- }
- if (a2 < -5. * M_PI_4)
- while (p->x < cosa2) {
- o[3].next = p;
- p = p->next;
- }
+ /*
+ * Either walk forward to the next quadrant, or find the last point on
+ * the arc. Make sure, that the comparison is made on the short
+ * cathenuse. Comparison on the long cathenuse might fail, since the
+ * distance of the points on the spline wobbles around the radius of
+ * the approximated circle.
+ */
+#define WIND_FORWARD o[3].next = p; p = p->next
+ for (;;) {
+ if (a2 < M_PI_4) {
+ while (p->y > p->x) {WIND_FORWARD;}
+ } else {
+ while (p->x < cosa2) {WIND_FORWARD;}
+ break;
+ }
+ if (a2 < -M_PI_4) {
+ while (p->x > -p->y) {WIND_FORWARD;}
+ } else {
+ while (p->y > sina2) {WIND_FORWARD;}
+ break;
+ }
+ if (a2 < -3. * M_PI_4) {
+ while (p->y < p->x) {WIND_FORWARD;}
+ } else {
+ while (p->x > cosa2) {WIND_FORWARD;}
+ break;
+ }
+ if (a2 < -5. * M_PI_4) {
+ while (p->x < -p->y) {WIND_FORWARD;}
+ while (p->x < cosa2) {WIND_FORWARD;}
+ break;
+ } else {
+ while (p->y < sina2) {WIND_FORWARD;}
+ break;
+ }
+ }
+#undef WIND_FORWARD
+
/* re-use the octagon points o[]; o[0] might be the center point for
* pie-wedge arcs, o[1] is the point on the arc exactly at angle a2,
* o[2] is again the center point. Use o[3].next and o[4].next to
@@ -2442,10 +2459,11 @@ put_patternarc(
p = l->points;
while (p != NULL) {
- px = i * p->x;
- p->x = c->x + round(cosr * px - YDIR(sinr * p->y));
- p->y = c->y + round(sinr * px + YDIR(cosr * p->y));
- p = p->next;
+ int px;
+ px = i * p->x;
+ p->x = c->x + round(cosr * px - YDIR(sinr * p->y));
+ p->y = c->y + round(sinr * px + YDIR(cosr * p->y));
+ p = p->next;
}
if (a->type == T_PIE_WEDGE_ARC) {
--- a/fig2dev/tests/output.at
+++ b/fig2dev/tests/output.at
@@ -203,6 +203,31 @@ FIG_FILE_TOP
EOF], 0, ignore)
AT_CLEANUP
+AT_SETUP([arcs ending at multiples of pi/4, #145, #148])
+AT_KEYWORDS(pict2e arc read.c)
+# ticket #145
+AT_CHECK([fig2dev -L pict2e <<EOF
+FIG_FILE_TOP
+5 1 2 4 7 2 0 -1 0 0 0 0 1 1 7956 3420 6029 3765 5 84 3270 6254 2685
+ 1 1 2 120 240
+ 1 1 2 120 240
+EOF], 0, ignore)
+# ticket #148a
+AT_CHECK([fig2dev -L pict2e <<EOF
+FIG_FILE_TOP
+5 1 2 4 7 2 0 -1 0 0 0 0 1 1 7956 3420 6029 3765 5984 3270 9254 2685
+ 1 1 2 120 240
+ 1 1 2 120 240
+EOF], 0, ignore)
+# ticket #148b
+AT_CHECK([fig2dev -L pict2e <<EOF
+FIG_FILE_TOP
+5 1 2 4 7 2 0 -1 0 0 0 0 1 1 79E6 12003420 79196029 3765 5984 3270 6254 51752685
+ 1 1 2 120 240
+ 1 1 2 120 240
+EOF], 0, ignore)
+AT_CLEANUP
+
AT_BANNER([Test svg output language.])
AT_SETUP([compare patterns with template])
|