1 /*
2 Copyright (c) 2002 Andrew Bird All rights reserved.
3 Distributed by Free Software Foundation, Inc.
4
5 This file is part of HP2xx.
6
7 HP2xx is distributed in the hope that it will be useful, but
8 WITHOUT ANY WARRANTY. No author or distributor accepts responsibility
9 to anyone for the consequences of using it or for whether it serves any
10 particular purpose or works at all, unless he says so in writing. Refer
11 to the GNU General Public License, Version 2 or later, for full details.
12
13 Everyone is granted permission to copy, modify and redistribute
14 HP2xx, but only under the conditions described in the GNU General Public
15 License. A copy of this license is supposed to have been
16 given to you along with HP2xx so you can know your rights and
17 responsibilities. It should be in a file named COPYING. Among other
18 things, the copyright notice and this notice must be preserved on all
19 copies.
20
21 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
22 */
23
24 #include <stdio.h>
25 #include <stdlib.h>
26 #include <math.h>
27
28 #include "bresnham.h"
29 #include "murphy.h"
30 #include "picbuf.h"
31 #include "hp2xx.h"
32 #include "hpgl.h"
33
34 static struct {
35 PEN_C color;
36 PicBuf *pb;
37 int u, v; /* delta x , delta y */
38 int ku, kt, kv, kd; /* loop constants */
39 int oct2;
40 int quad4;
41 DevPt last1, last2, first1, first2, temp;
42 } murphy;
43
44
45 /*#i fdef NORINT
46 #de fine lrint(a) ((long)(a+0.5))
47 #en dif
48 */
49
50 #define my_lrint(a) ((long)(a+0.5))
51
52 static void do_miter(int, DevPt, DevPt, DevPt, DevPt);
53
murphy_init(PicBuf * pb,PEN_C color)54 void murphy_init(PicBuf * pb, PEN_C color)
55 {
56 murphy.color = color; /* setup buffer / color info */
57 murphy.pb = pb;
58 }
59
murphy_paraline(DevPt pt,int d1)60 void murphy_paraline(DevPt pt, int d1)
61 { /* implements Figure 5B */
62 int p; /* pel counter, p=along line */
63 d1 = -d1;
64
65 for (p = 0; p <= murphy.u; p++) { /* test for end of parallel line */
66
67 plot_PicBuf(murphy.pb, &pt, murphy.color);
68
69 if (d1 <= murphy.kt) { /* square move */
70 if (murphy.oct2 == 0) {
71 pt.x++;
72 } else {
73 if (murphy.quad4 == 0) {
74 pt.y++;
75 } else {
76 pt.y--;
77 }
78 }
79 d1 += murphy.kv;
80 } else { /* diagonal move */
81 pt.x++;
82 if (murphy.quad4 == 0) {
83 pt.y++;
84 } else {
85 pt.y--;
86 }
87 d1 += murphy.kd;
88 }
89 }
90 murphy.temp = pt;
91 }
92
murphy_wideline(DevPt p0,DevPt p1,int width,int miter)93 void murphy_wideline(DevPt p0, DevPt p1, int width, int miter)
94 { /* implements figure 5A - draws lines parallel to ideal line */
95
96 float offset = width / 2.;
97
98 DevPt pt, ptx, ml1, ml2, ml1b, ml2b;
99
100 int d0, d1; /* difference terms d0=perpendicular to line, d1=along line */
101
102 int q; /* pel counter,q=perpendicular to line */
103 int tmp;
104
105 int dd; /* distance along line */
106 int tk; /* thickness threshold */
107 double ang; /* angle for initial point calculation */
108 /* Initialisation */
109 murphy.u = p1.x - p0.x; /* delta x */
110 murphy.v = p1.y - p0.y; /* delta y */
111
112 if (murphy.u < 0) { /* swap to make sure we are in quadrants 1 or 4 */
113 pt = p0;
114 p0 = p1;
115 p1 = pt;
116 murphy.u *= -1;
117 murphy.v *= -1;
118 }
119
120 if (murphy.v < 0) { /* swap to 1st quadrant and flag */
121 murphy.v *= -1;
122 murphy.quad4 = 1;
123 } else {
124 murphy.quad4 = 0;
125 }
126
127 if (murphy.v > murphy.u) { /* swap things if in 2 octant */
128 tmp = murphy.u;
129 murphy.u = murphy.v;
130 murphy.v = tmp;
131 murphy.oct2 = 1;
132 } else {
133 murphy.oct2 = 0;
134 }
135
136 murphy.ku = murphy.u + murphy.u; /* change in l for square shift */
137 murphy.kv = murphy.v + murphy.v; /* change in d for square shift */
138 murphy.kd = murphy.kv - murphy.ku; /* change in d for diagonal shift */
139 murphy.kt = murphy.u - murphy.kv; /* diag/square decision threshold */
140
141 d0 = 0;
142 d1 = 0;
143 dd = 0;
144
145 ang = atan((double) murphy.v / (double) murphy.u); /* calc new initial point - offset both sides of ideal */
146
147 if (murphy.oct2 == 0) {
148 pt.x = p0.x + my_lrint(offset * sin(ang));
149 if (murphy.quad4 == 0) {
150 pt.y = p0.y - my_lrint(offset * cos(ang));
151 } else {
152 pt.y = p0.y + my_lrint(offset * cos(ang));
153 }
154 } else {
155 pt.x = p0.x - my_lrint(offset * cos(ang));
156 if (murphy.quad4 == 0) {
157 pt.y = p0.y + my_lrint(offset * sin(ang));
158 } else {
159 pt.y = p0.y - my_lrint(offset * sin(ang));
160 }
161 }
162
163 tk = (int) (4. * HYPOT(pt.x - p0.x, pt.y - p0.y) * HYPOT(murphy.u, murphy.v)); /* used here for constant thickness line */
164
165 if (miter == 0) {
166 murphy.first1.x = -10000000;
167 murphy.first1.y = -10000000;
168 murphy.first2.x = -10000000;
169 murphy.first2.y = -10000000;
170 murphy.last1.x = -10000000;
171 murphy.last1.y = -10000000;
172 murphy.last2.x = -10000000;
173 murphy.last2.y = -10000000;
174 }
175 ptx = pt;
176
177 for (q = 0; dd <= tk; q++) { /* outer loop, stepping perpendicular to line */
178
179 murphy_paraline(pt, d1); /* call to inner loop - right edge */
180 if (q == 0) {
181 ml1 = pt;
182 ml1b = murphy.temp;
183 } else {
184 ml2 = pt;
185 ml2b = murphy.temp;
186 }
187 if (d0 < murphy.kt) { /* square move - M2 */
188 if (murphy.oct2 == 0) {
189 if (murphy.quad4 == 0) {
190 pt.y++;
191 } else {
192 pt.y--;
193 }
194 } else {
195 pt.x++;
196 }
197 } else { /* diagonal move */
198 dd += murphy.kv;
199 d0 -= murphy.ku;
200 if (d1 < murphy.kt) { /* normal diagonal - M3 */
201 if (murphy.oct2 == 0) {
202 pt.x--;
203 if (murphy.quad4 == 0) {
204 pt.y++;
205 } else {
206 pt.y--;
207 }
208 } else {
209 pt.x++;
210 if (murphy.quad4 == 0) {
211 pt.y--;
212 } else {
213 pt.y++;
214 }
215 }
216 d1 += murphy.kv;
217 } else { /* double square move, extra parallel line */
218 if (murphy.oct2 == 0) {
219 pt.x--;
220 } else {
221 if (murphy.quad4 == 0) {
222 pt.y--;
223 } else {
224 pt.y++;
225 }
226 }
227 d1 += murphy.kd;
228 if (dd > tk) {
229 do_miter(miter, ml1b, ml2b, ml1,
230 ml2);
231 return; /* breakout on the extra line */
232 }
233 murphy_paraline(pt, d1);
234 if (murphy.oct2 == 0) {
235 if (murphy.quad4 == 0) {
236 pt.y++;
237 } else {
238
239 pt.y--;
240 }
241 } else {
242 pt.x++;
243 }
244 }
245 }
246 dd += murphy.ku;
247 d0 += murphy.kv;
248 }
249
250 do_miter(miter, ml1b, ml2b, ml1, ml2);
251
252 }
253
do_miter(miter,ml1b,ml2b,ml1,ml2)254 static void do_miter(miter, ml1b, ml2b, ml1, ml2)
255 int miter;
256 DevPt ml1b, ml2b, ml1, ml2;
257
258 {
259 int ftmp1, ftmp2;
260 DevPt m1, m2, *p_act;
261 DevPt fi, la, cur;
262
263 if (miter > 1) {
264 if (murphy.first1.x != -10000000) {
265 fi.x = (murphy.first1.x + murphy.first2.x) / 2;
266 fi.y = (murphy.first1.y + murphy.first2.y) / 2;
267 la.x = (murphy.last1.x + murphy.last2.x) / 2;
268 la.y = (murphy.last1.y + murphy.last2.y) / 2;
269 cur.x = (ml1.x + ml2.x) / 2;
270 cur.y = (ml1.y + ml2.y) / 2;
271 ftmp1 =
272 (fi.x - cur.x) * (fi.x - cur.x) + (fi.y -
273 cur.y) *
274 (fi.y - cur.y);
275 ftmp2 =
276 (la.x - cur.x) * (la.x - cur.x) + (la.y -
277 cur.y) *
278 (la.y - cur.y);
279 if (ftmp1 <= ftmp2) {
280 m1 = murphy.first1;
281 m2 = murphy.first2;
282 } else {
283 m1 = murphy.last1;
284 m2 = murphy.last2;
285 }
286 ftmp2 =
287 (m2.x - ml2b.x) * (m2.x - ml2b.x) + (m2.y -
288 ml2b.y) *
289 (m2.y - ml2b.y);
290 ftmp1 =
291 (m2.x - ml2.x) * (m2.x - ml2.x) + (m2.y -
292 ml2.y) *
293 (m2.y - ml2.y);
294
295 if (abs(ftmp2) >= abs(ftmp1)) {
296 ftmp1 = ml2b.x;
297 ftmp2 = ml2b.y;
298 ml2b.x = ml2.x;
299 ml2b.y = ml2.y;
300 ml2.x = ftmp1;
301 ml2.y = ftmp2;
302 ftmp1 = ml1b.x;
303 ftmp2 = ml1b.y;
304 ml1b.x = ml1.x;
305 ml1b.y = ml1.y;
306 ml1.x = ftmp1;
307 ml1.y = ftmp2;
308 }
309
310 /*draw outline of miter segment */
311 p_act = bresenham_init(&m2, &m1);
312 do {
313 plot_PicBuf(murphy.pb, p_act,
314 murphy.color);
315 } while (bresenham_next() != BRESENHAM_ERR);
316
317 p_act = bresenham_init(&m1, &ml1b);
318 do {
319 plot_PicBuf(murphy.pb, p_act,
320 murphy.color);
321 } while (bresenham_next() != BRESENHAM_ERR);
322
323 p_act = bresenham_init(&ml1b, &ml2b);
324 do {
325 plot_PicBuf(murphy.pb, p_act,
326 murphy.color);
327 } while (bresenham_next() != BRESENHAM_ERR);
328
329 p_act = bresenham_init(&ml2b, &m2);
330 do {
331 plot_PicBuf(murphy.pb, p_act,
332 murphy.color);
333 } while (bresenham_next() != BRESENHAM_ERR);
334 polygon_PicBuf(m1, m2, ml1b, ml2b, murphy.color,
335 murphy.pb);
336 }
337 }
338 murphy.last2 = ml2;
339 murphy.last1 = ml1;
340 murphy.first1 = ml1b;
341 murphy.first2 = ml2b;
342 }
343