File: 35_pict2e_output.patch

package info (click to toggle)
fig2dev 1%3A3.2.8b-3%2Bdeb12u2
  • links: PTS, VCS
  • area: main
  • in suites: bookworm
  • size: 4,008 kB
  • sloc: ansic: 37,618; sh: 7,021; makefile: 175; csh: 12
file content (232 lines) | stat: -rw-r--r-- 7,445 bytes parent folder | download
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])