1 | /* $Id$ $Revision$ */ |
2 | /* vim:set shiftwidth=4 ts=8: */ |
3 | |
4 | /************************************************************************* |
5 | * Copyright (c) 2011 AT&T Intellectual Property |
6 | * All rights reserved. This program and the accompanying materials |
7 | * are made available under the terms of the Eclipse Public License v1.0 |
8 | * which accompanies this distribution, and is available at |
9 | * http://www.eclipse.org/legal/epl-v10.html |
10 | * |
11 | * Contributors: See CVS logs. Details at http://www.graphviz.org/ |
12 | *************************************************************************/ |
13 | |
14 | |
15 | #include <stdlib.h> |
16 | #include <stdio.h> |
17 | #include <setjmp.h> |
18 | #ifdef HAVE_MALLOC_H |
19 | #include <malloc.h> |
20 | #endif |
21 | #include <limits.h> |
22 | #include <math.h> |
23 | #include "pathutil.h" |
24 | |
25 | #ifdef DMALLOC |
26 | #include "dmalloc.h" |
27 | #endif |
28 | |
29 | #define ISCCW 1 |
30 | #define ISCW 2 |
31 | #define ISON 3 |
32 | |
33 | #define DQ_FRONT 1 |
34 | #define DQ_BACK 2 |
35 | |
36 | #ifndef TRUE |
37 | #define TRUE 1 |
38 | #define FALSE 0 |
39 | #endif |
40 | |
41 | #define prerror(msg) \ |
42 | fprintf (stderr, "libpath/%s:%d: %s\n", __FILE__, __LINE__, (msg)) |
43 | |
44 | #define POINTSIZE sizeof (Ppoint_t) |
45 | |
46 | typedef struct pointnlink_t { |
47 | Ppoint_t *pp; |
48 | struct pointnlink_t *link; |
49 | } pointnlink_t; |
50 | |
51 | #define POINTNLINKSIZE sizeof (pointnlink_t) |
52 | #define POINTNLINKPSIZE sizeof (pointnlink_t *) |
53 | |
54 | typedef struct tedge_t { |
55 | pointnlink_t *pnl0p; |
56 | pointnlink_t *pnl1p; |
57 | struct triangle_t *ltp; |
58 | struct triangle_t *rtp; |
59 | } tedge_t; |
60 | |
61 | typedef struct triangle_t { |
62 | int mark; |
63 | struct tedge_t e[3]; |
64 | } triangle_t; |
65 | |
66 | #define TRIANGLESIZE sizeof (triangle_t) |
67 | |
68 | typedef struct deque_t { |
69 | pointnlink_t **pnlps; |
70 | int pnlpn, fpnlpi, lpnlpi, apex; |
71 | } deque_t; |
72 | |
73 | static jmp_buf jbuf; |
74 | static pointnlink_t *pnls, **pnlps; |
75 | static int pnln, pnll; |
76 | |
77 | static triangle_t *tris; |
78 | static int trin, tril; |
79 | |
80 | static deque_t dq; |
81 | |
82 | static Ppoint_t *ops; |
83 | static int opn; |
84 | |
85 | static void triangulate(pointnlink_t **, int); |
86 | static int isdiagonal(int, int, pointnlink_t **, int); |
87 | static void loadtriangle(pointnlink_t *, pointnlink_t *, pointnlink_t *); |
88 | static void connecttris(int, int); |
89 | static int marktripath(int, int); |
90 | |
91 | static void add2dq(int, pointnlink_t *); |
92 | static void splitdq(int, int); |
93 | static int finddqsplit(pointnlink_t *); |
94 | |
95 | static int ccw(Ppoint_t *, Ppoint_t *, Ppoint_t *); |
96 | static int intersects(Ppoint_t *, Ppoint_t *, Ppoint_t *, Ppoint_t *); |
97 | static int between(Ppoint_t *, Ppoint_t *, Ppoint_t *); |
98 | static int pointintri(int, Ppoint_t *); |
99 | |
100 | static void growpnls(int); |
101 | static void growtris(int); |
102 | static void growdq(int); |
103 | static void growops(int); |
104 | |
105 | /* Pshortestpath: |
106 | * Find a shortest path contained in the polygon polyp going between the |
107 | * points supplied in eps. The resulting polyline is stored in output. |
108 | * Return 0 on success, -1 on bad input, -2 on memory allocation problem. |
109 | */ |
110 | int Pshortestpath(Ppoly_t * polyp, Ppoint_t * eps, Ppolyline_t * output) |
111 | { |
112 | int pi, minpi; |
113 | double minx; |
114 | Ppoint_t p1, p2, p3; |
115 | int trii, trij, ftrii, ltrii; |
116 | int ei; |
117 | pointnlink_t epnls[2], *lpnlp, *rpnlp, *pnlp; |
118 | triangle_t *trip; |
119 | int splitindex; |
120 | #ifdef DEBUG |
121 | int pnli; |
122 | #endif |
123 | |
124 | if (setjmp(jbuf)) |
125 | return -2; |
126 | /* make space */ |
127 | growpnls(polyp->pn); |
128 | pnll = 0; |
129 | tril = 0; |
130 | growdq(polyp->pn * 2); |
131 | dq.fpnlpi = dq.pnlpn / 2, dq.lpnlpi = dq.fpnlpi - 1; |
132 | |
133 | /* make sure polygon is CCW and load pnls array */ |
134 | for (pi = 0, minx = HUGE_VAL, minpi = -1; pi < polyp->pn; pi++) { |
135 | if (minx > polyp->ps[pi].x) |
136 | minx = polyp->ps[pi].x, minpi = pi; |
137 | } |
138 | p2 = polyp->ps[minpi]; |
139 | p1 = polyp->ps[((minpi == 0) ? polyp->pn - 1 : minpi - 1)]; |
140 | p3 = polyp->ps[((minpi == polyp->pn - 1) ? 0 : minpi + 1)]; |
141 | if (((p1.x == p2.x && p2.x == p3.x) && (p3.y > p2.y)) || |
142 | ccw(&p1, &p2, &p3) != ISCCW) { |
143 | for (pi = polyp->pn - 1; pi >= 0; pi--) { |
144 | if (pi < polyp->pn - 1 |
145 | && polyp->ps[pi].x == polyp->ps[pi + 1].x |
146 | && polyp->ps[pi].y == polyp->ps[pi + 1].y) |
147 | continue; |
148 | pnls[pnll].pp = &polyp->ps[pi]; |
149 | pnls[pnll].link = &pnls[pnll % polyp->pn]; |
150 | pnlps[pnll] = &pnls[pnll]; |
151 | pnll++; |
152 | } |
153 | } else { |
154 | for (pi = 0; pi < polyp->pn; pi++) { |
155 | if (pi > 0 && polyp->ps[pi].x == polyp->ps[pi - 1].x && |
156 | polyp->ps[pi].y == polyp->ps[pi - 1].y) |
157 | continue; |
158 | pnls[pnll].pp = &polyp->ps[pi]; |
159 | pnls[pnll].link = &pnls[pnll % polyp->pn]; |
160 | pnlps[pnll] = &pnls[pnll]; |
161 | pnll++; |
162 | } |
163 | } |
164 | |
165 | #if defined(DEBUG) && DEBUG >= 1 |
166 | fprintf(stderr, "points\n%d\n" , pnll); |
167 | for (pnli = 0; pnli < pnll; pnli++) |
168 | fprintf(stderr, "%f %f\n" , pnls[pnli].pp->x, pnls[pnli].pp->y); |
169 | #endif |
170 | |
171 | /* generate list of triangles */ |
172 | triangulate(pnlps, pnll); |
173 | |
174 | #if defined(DEBUG) && DEBUG >= 2 |
175 | fprintf(stderr, "triangles\n%d\n" , tril); |
176 | for (trii = 0; trii < tril; trii++) |
177 | for (ei = 0; ei < 3; ei++) |
178 | fprintf(stderr, "%f %f\n" , tris[trii].e[ei].pnl0p->pp->x, |
179 | tris[trii].e[ei].pnl0p->pp->y); |
180 | #endif |
181 | |
182 | /* connect all pairs of triangles that share an edge */ |
183 | for (trii = 0; trii < tril; trii++) |
184 | for (trij = trii + 1; trij < tril; trij++) |
185 | connecttris(trii, trij); |
186 | |
187 | /* find first and last triangles */ |
188 | for (trii = 0; trii < tril; trii++) |
189 | if (pointintri(trii, &eps[0])) |
190 | break; |
191 | if (trii == tril) { |
192 | prerror("source point not in any triangle" ); |
193 | return -1; |
194 | } |
195 | ftrii = trii; |
196 | for (trii = 0; trii < tril; trii++) |
197 | if (pointintri(trii, &eps[1])) |
198 | break; |
199 | if (trii == tril) { |
200 | prerror("destination point not in any triangle" ); |
201 | return -1; |
202 | } |
203 | ltrii = trii; |
204 | |
205 | /* mark the strip of triangles from eps[0] to eps[1] */ |
206 | if (!marktripath(ftrii, ltrii)) { |
207 | prerror("cannot find triangle path" ); |
208 | /* a straight line is better than failing */ |
209 | growops(2); |
210 | output->pn = 2; |
211 | ops[0] = eps[0], ops[1] = eps[1]; |
212 | output->ps = ops; |
213 | return 0; |
214 | } |
215 | |
216 | /* if endpoints in same triangle, use a single line */ |
217 | if (ftrii == ltrii) { |
218 | growops(2); |
219 | output->pn = 2; |
220 | ops[0] = eps[0], ops[1] = eps[1]; |
221 | output->ps = ops; |
222 | return 0; |
223 | } |
224 | |
225 | /* build funnel and shortest path linked list (in add2dq) */ |
226 | epnls[0].pp = &eps[0], epnls[0].link = NULL; |
227 | epnls[1].pp = &eps[1], epnls[1].link = NULL; |
228 | add2dq(DQ_FRONT, &epnls[0]); |
229 | dq.apex = dq.fpnlpi; |
230 | trii = ftrii; |
231 | while (trii != -1) { |
232 | trip = &tris[trii]; |
233 | trip->mark = 2; |
234 | |
235 | /* find the left and right points of the exiting edge */ |
236 | for (ei = 0; ei < 3; ei++) |
237 | if (trip->e[ei].rtp && trip->e[ei].rtp->mark == 1) |
238 | break; |
239 | if (ei == 3) { /* in last triangle */ |
240 | if (ccw(&eps[1], dq.pnlps[dq.fpnlpi]->pp, |
241 | dq.pnlps[dq.lpnlpi]->pp) == ISCCW) |
242 | lpnlp = dq.pnlps[dq.lpnlpi], rpnlp = &epnls[1]; |
243 | else |
244 | lpnlp = &epnls[1], rpnlp = dq.pnlps[dq.lpnlpi]; |
245 | } else { |
246 | pnlp = trip->e[(ei + 1) % 3].pnl1p; |
247 | if (ccw(trip->e[ei].pnl0p->pp, pnlp->pp, |
248 | trip->e[ei].pnl1p->pp) == ISCCW) |
249 | lpnlp = trip->e[ei].pnl1p, rpnlp = trip->e[ei].pnl0p; |
250 | else |
251 | lpnlp = trip->e[ei].pnl0p, rpnlp = trip->e[ei].pnl1p; |
252 | } |
253 | |
254 | /* update deque */ |
255 | if (trii == ftrii) { |
256 | add2dq(DQ_BACK, lpnlp); |
257 | add2dq(DQ_FRONT, rpnlp); |
258 | } else { |
259 | if (dq.pnlps[dq.fpnlpi] != rpnlp |
260 | && dq.pnlps[dq.lpnlpi] != rpnlp) { |
261 | /* add right point to deque */ |
262 | splitindex = finddqsplit(rpnlp); |
263 | splitdq(DQ_BACK, splitindex); |
264 | add2dq(DQ_FRONT, rpnlp); |
265 | /* if the split is behind the apex, then reset apex */ |
266 | if (splitindex > dq.apex) |
267 | dq.apex = splitindex; |
268 | } else { |
269 | /* add left point to deque */ |
270 | splitindex = finddqsplit(lpnlp); |
271 | splitdq(DQ_FRONT, splitindex); |
272 | add2dq(DQ_BACK, lpnlp); |
273 | /* if the split is in front of the apex, then reset apex */ |
274 | if (splitindex < dq.apex) |
275 | dq.apex = splitindex; |
276 | } |
277 | } |
278 | trii = -1; |
279 | for (ei = 0; ei < 3; ei++) |
280 | if (trip->e[ei].rtp && trip->e[ei].rtp->mark == 1) { |
281 | trii = trip->e[ei].rtp - tris; |
282 | break; |
283 | } |
284 | } |
285 | |
286 | #if defined(DEBUG) && DEBUG >= 1 |
287 | fprintf(stderr, "polypath" ); |
288 | for (pnlp = &epnls[1]; pnlp; pnlp = pnlp->link) |
289 | fprintf(stderr, " %f %f" , pnlp->pp->x, pnlp->pp->y); |
290 | fprintf(stderr, "\n" ); |
291 | #endif |
292 | |
293 | for (pi = 0, pnlp = &epnls[1]; pnlp; pnlp = pnlp->link) |
294 | pi++; |
295 | growops(pi); |
296 | output->pn = pi; |
297 | for (pi = pi - 1, pnlp = &epnls[1]; pnlp; pi--, pnlp = pnlp->link) |
298 | ops[pi] = *pnlp->pp; |
299 | output->ps = ops; |
300 | |
301 | return 0; |
302 | } |
303 | |
304 | /* triangulate polygon */ |
305 | static void triangulate(pointnlink_t ** pnlps, int pnln) |
306 | { |
307 | int pnli, pnlip1, pnlip2; |
308 | |
309 | if (pnln > 3) |
310 | { |
311 | for (pnli = 0; pnli < pnln; pnli++) |
312 | { |
313 | pnlip1 = (pnli + 1) % pnln; |
314 | pnlip2 = (pnli + 2) % pnln; |
315 | if (isdiagonal(pnli, pnlip2, pnlps, pnln)) |
316 | { |
317 | loadtriangle(pnlps[pnli], pnlps[pnlip1], pnlps[pnlip2]); |
318 | for (pnli = pnlip1; pnli < pnln - 1; pnli++) |
319 | pnlps[pnli] = pnlps[pnli + 1]; |
320 | triangulate(pnlps, pnln - 1); |
321 | return; |
322 | } |
323 | } |
324 | prerror("triangulation failed" ); |
325 | } |
326 | else |
327 | loadtriangle(pnlps[0], pnlps[1], pnlps[2]); |
328 | } |
329 | |
330 | /* check if (i, i + 2) is a diagonal */ |
331 | static int isdiagonal(int pnli, int pnlip2, pointnlink_t ** pnlps, |
332 | int pnln) |
333 | { |
334 | int pnlip1, pnlim1, pnlj, pnljp1, res; |
335 | |
336 | /* neighborhood test */ |
337 | pnlip1 = (pnli + 1) % pnln; |
338 | pnlim1 = (pnli + pnln - 1) % pnln; |
339 | /* If P[pnli] is a convex vertex [ pnli+1 left of (pnli-1,pnli) ]. */ |
340 | if (ccw(pnlps[pnlim1]->pp, pnlps[pnli]->pp, pnlps[pnlip1]->pp) == |
341 | ISCCW) |
342 | res = |
343 | (ccw(pnlps[pnli]->pp, pnlps[pnlip2]->pp, pnlps[pnlim1]->pp) == |
344 | ISCCW) |
345 | && (ccw(pnlps[pnlip2]->pp, pnlps[pnli]->pp, pnlps[pnlip1]->pp) |
346 | == ISCCW); |
347 | /* Assume (pnli - 1, pnli, pnli + 1) not collinear. */ |
348 | else |
349 | res = (ccw(pnlps[pnli]->pp, pnlps[pnlip2]->pp, |
350 | pnlps[pnlip1]->pp) == ISCW); |
351 | if (!res) |
352 | return FALSE; |
353 | |
354 | /* check against all other edges */ |
355 | for (pnlj = 0; pnlj < pnln; pnlj++) { |
356 | pnljp1 = (pnlj + 1) % pnln; |
357 | if (!((pnlj == pnli) || (pnljp1 == pnli) || |
358 | (pnlj == pnlip2) || (pnljp1 == pnlip2))) |
359 | if (intersects(pnlps[pnli]->pp, pnlps[pnlip2]->pp, |
360 | pnlps[pnlj]->pp, pnlps[pnljp1]->pp)) |
361 | return FALSE; |
362 | } |
363 | return TRUE; |
364 | } |
365 | |
366 | static void loadtriangle(pointnlink_t * pnlap, pointnlink_t * pnlbp, |
367 | pointnlink_t * pnlcp) |
368 | { |
369 | triangle_t *trip; |
370 | int ei; |
371 | |
372 | /* make space */ |
373 | if (tril >= trin) |
374 | growtris(trin + 20); |
375 | trip = &tris[tril++]; |
376 | trip->mark = 0; |
377 | trip->e[0].pnl0p = pnlap, trip->e[0].pnl1p = pnlbp, trip->e[0].rtp = |
378 | NULL; |
379 | trip->e[1].pnl0p = pnlbp, trip->e[1].pnl1p = pnlcp, trip->e[1].rtp = |
380 | NULL; |
381 | trip->e[2].pnl0p = pnlcp, trip->e[2].pnl1p = pnlap, trip->e[2].rtp = |
382 | NULL; |
383 | for (ei = 0; ei < 3; ei++) |
384 | trip->e[ei].ltp = trip; |
385 | } |
386 | |
387 | /* connect a pair of triangles at their common edge (if any) */ |
388 | static void connecttris(int tri1, int tri2) |
389 | { |
390 | triangle_t *tri1p, *tri2p; |
391 | int ei, ej; |
392 | |
393 | for (ei = 0; ei < 3; ei++) { |
394 | for (ej = 0; ej < 3; ej++) { |
395 | tri1p = &tris[tri1], tri2p = &tris[tri2]; |
396 | if ((tri1p->e[ei].pnl0p->pp == tri2p->e[ej].pnl0p->pp && |
397 | tri1p->e[ei].pnl1p->pp == tri2p->e[ej].pnl1p->pp) || |
398 | (tri1p->e[ei].pnl0p->pp == tri2p->e[ej].pnl1p->pp && |
399 | tri1p->e[ei].pnl1p->pp == tri2p->e[ej].pnl0p->pp)) |
400 | tri1p->e[ei].rtp = tri2p, tri2p->e[ej].rtp = tri1p; |
401 | } |
402 | } |
403 | } |
404 | |
405 | /* find and mark path from trii, to trij */ |
406 | static int marktripath(int trii, int trij) |
407 | { |
408 | int ei; |
409 | |
410 | if (tris[trii].mark) |
411 | return FALSE; |
412 | tris[trii].mark = 1; |
413 | if (trii == trij) |
414 | return TRUE; |
415 | for (ei = 0; ei < 3; ei++) |
416 | if (tris[trii].e[ei].rtp && |
417 | marktripath(tris[trii].e[ei].rtp - tris, trij)) |
418 | return TRUE; |
419 | tris[trii].mark = 0; |
420 | return FALSE; |
421 | } |
422 | |
423 | /* add a new point to the deque, either front or back */ |
424 | static void add2dq(int side, pointnlink_t * pnlp) |
425 | { |
426 | if (side == DQ_FRONT) { |
427 | if (dq.lpnlpi - dq.fpnlpi >= 0) |
428 | pnlp->link = dq.pnlps[dq.fpnlpi]; /* shortest path links */ |
429 | dq.fpnlpi--; |
430 | dq.pnlps[dq.fpnlpi] = pnlp; |
431 | } else { |
432 | if (dq.lpnlpi - dq.fpnlpi >= 0) |
433 | pnlp->link = dq.pnlps[dq.lpnlpi]; /* shortest path links */ |
434 | dq.lpnlpi++; |
435 | dq.pnlps[dq.lpnlpi] = pnlp; |
436 | } |
437 | } |
438 | |
439 | static void splitdq(int side, int index) |
440 | { |
441 | if (side == DQ_FRONT) |
442 | dq.lpnlpi = index; |
443 | else |
444 | dq.fpnlpi = index; |
445 | } |
446 | |
447 | static int finddqsplit(pointnlink_t * pnlp) |
448 | { |
449 | int index; |
450 | |
451 | for (index = dq.fpnlpi; index < dq.apex; index++) |
452 | if (ccw(dq.pnlps[index + 1]->pp, dq.pnlps[index]->pp, pnlp->pp) == |
453 | ISCCW) |
454 | return index; |
455 | for (index = dq.lpnlpi; index > dq.apex; index--) |
456 | if (ccw(dq.pnlps[index - 1]->pp, dq.pnlps[index]->pp, pnlp->pp) == |
457 | ISCW) |
458 | return index; |
459 | return dq.apex; |
460 | } |
461 | |
462 | /* ccw test: CCW, CW, or co-linear */ |
463 | static int ccw(Ppoint_t * p1p, Ppoint_t * p2p, Ppoint_t * p3p) |
464 | { |
465 | double d; |
466 | |
467 | d = ((p1p->y - p2p->y) * (p3p->x - p2p->x)) - |
468 | ((p3p->y - p2p->y) * (p1p->x - p2p->x)); |
469 | return (d > 0) ? ISCCW : ((d < 0) ? ISCW : ISON); |
470 | } |
471 | |
472 | /* line to line intersection */ |
473 | static int intersects(Ppoint_t * pap, Ppoint_t * pbp, |
474 | Ppoint_t * pcp, Ppoint_t * pdp) |
475 | { |
476 | int ccw1, ccw2, ccw3, ccw4; |
477 | |
478 | if (ccw(pap, pbp, pcp) == ISON || ccw(pap, pbp, pdp) == ISON || |
479 | ccw(pcp, pdp, pap) == ISON || ccw(pcp, pdp, pbp) == ISON) { |
480 | if (between(pap, pbp, pcp) || between(pap, pbp, pdp) || |
481 | between(pcp, pdp, pap) || between(pcp, pdp, pbp)) |
482 | return TRUE; |
483 | } else { |
484 | ccw1 = (ccw(pap, pbp, pcp) == ISCCW) ? 1 : 0; |
485 | ccw2 = (ccw(pap, pbp, pdp) == ISCCW) ? 1 : 0; |
486 | ccw3 = (ccw(pcp, pdp, pap) == ISCCW) ? 1 : 0; |
487 | ccw4 = (ccw(pcp, pdp, pbp) == ISCCW) ? 1 : 0; |
488 | return (ccw1 ^ ccw2) && (ccw3 ^ ccw4); |
489 | } |
490 | return FALSE; |
491 | } |
492 | |
493 | /* is pbp between pap and pcp */ |
494 | static int between(Ppoint_t * pap, Ppoint_t * pbp, Ppoint_t * pcp) |
495 | { |
496 | Ppoint_t p1, p2; |
497 | |
498 | p1.x = pbp->x - pap->x, p1.y = pbp->y - pap->y; |
499 | p2.x = pcp->x - pap->x, p2.y = pcp->y - pap->y; |
500 | if (ccw(pap, pbp, pcp) != ISON) |
501 | return FALSE; |
502 | return (p2.x * p1.x + p2.y * p1.y >= 0) && |
503 | (p2.x * p2.x + p2.y * p2.y <= p1.x * p1.x + p1.y * p1.y); |
504 | } |
505 | |
506 | static int pointintri(int trii, Ppoint_t * pp) |
507 | { |
508 | int ei, sum; |
509 | |
510 | for (ei = 0, sum = 0; ei < 3; ei++) |
511 | if (ccw(tris[trii].e[ei].pnl0p->pp, |
512 | tris[trii].e[ei].pnl1p->pp, pp) != ISCW) |
513 | sum++; |
514 | return (sum == 3 || sum == 0); |
515 | } |
516 | |
517 | static void growpnls(int newpnln) |
518 | { |
519 | if (newpnln <= pnln) |
520 | return; |
521 | if (!pnls) { |
522 | if (!(pnls = (pointnlink_t *) malloc(POINTNLINKSIZE * newpnln))) { |
523 | prerror("cannot malloc pnls" ); |
524 | longjmp(jbuf,1); |
525 | } |
526 | if (!(pnlps = (pointnlink_t **) malloc(POINTNLINKPSIZE * newpnln))) { |
527 | prerror("cannot malloc pnlps" ); |
528 | longjmp(jbuf,1); |
529 | } |
530 | } else { |
531 | if (!(pnls = (pointnlink_t *) realloc((void *) pnls, |
532 | POINTNLINKSIZE * newpnln))) { |
533 | prerror("cannot realloc pnls" ); |
534 | longjmp(jbuf,1); |
535 | } |
536 | if (!(pnlps = (pointnlink_t **) realloc((void *) pnlps, |
537 | POINTNLINKPSIZE * |
538 | newpnln))) { |
539 | prerror("cannot realloc pnlps" ); |
540 | longjmp(jbuf,1); |
541 | } |
542 | } |
543 | pnln = newpnln; |
544 | } |
545 | |
546 | static void growtris(int newtrin) |
547 | { |
548 | if (newtrin <= trin) |
549 | return; |
550 | if (!tris) { |
551 | if (!(tris = (triangle_t *) malloc(TRIANGLESIZE * newtrin))) { |
552 | prerror("cannot malloc tris" ); |
553 | longjmp(jbuf,1); |
554 | } |
555 | } else { |
556 | if (!(tris = (triangle_t *) realloc((void *) tris, |
557 | TRIANGLESIZE * newtrin))) { |
558 | prerror("cannot realloc tris" ); |
559 | longjmp(jbuf,1); |
560 | } |
561 | } |
562 | trin = newtrin; |
563 | } |
564 | |
565 | static void growdq(int newdqn) |
566 | { |
567 | if (newdqn <= dq.pnlpn) |
568 | return; |
569 | if (!dq.pnlps) { |
570 | if (! |
571 | (dq.pnlps = |
572 | (pointnlink_t **) malloc(POINTNLINKPSIZE * newdqn))) { |
573 | prerror("cannot malloc dq.pnls" ); |
574 | longjmp(jbuf,1); |
575 | } |
576 | } else { |
577 | if (!(dq.pnlps = (pointnlink_t **) realloc((void *) dq.pnlps, |
578 | POINTNLINKPSIZE * |
579 | newdqn))) { |
580 | prerror("cannot realloc dq.pnls" ); |
581 | longjmp(jbuf,1); |
582 | } |
583 | } |
584 | dq.pnlpn = newdqn; |
585 | } |
586 | |
587 | static void growops(int newopn) |
588 | { |
589 | if (newopn <= opn) |
590 | return; |
591 | if (!ops) { |
592 | if (!(ops = (Ppoint_t *) malloc(POINTSIZE * newopn))) { |
593 | prerror("cannot malloc ops" ); |
594 | longjmp(jbuf,1); |
595 | } |
596 | } else { |
597 | if (!(ops = (Ppoint_t *) realloc((void *) ops, |
598 | POINTSIZE * newopn))) { |
599 | prerror("cannot realloc ops" ); |
600 | longjmp(jbuf,1); |
601 | } |
602 | } |
603 | opn = newopn; |
604 | } |
605 | |