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