|
Graphviz
2.31.20130617.0446
|
00001 /* $Id$ $Revision$ */ 00002 /* vim:set shiftwidth=4 ts=8: */ 00003 00004 /************************************************************************* 00005 * Copyright (c) 2011 AT&T Intellectual Property 00006 * All rights reserved. This program and the accompanying materials 00007 * are made available under the terms of the Eclipse Public License v1.0 00008 * which accompanies this distribution, and is available at 00009 * http://www.eclipse.org/legal/epl-v10.html 00010 * 00011 * Contributors: See CVS logs. Details at http://www.graphviz.org/ 00012 *************************************************************************/ 00013 00014 00015 #include <stdlib.h> 00016 #include <stdio.h> 00017 #include <setjmp.h> 00018 #ifdef HAVE_MALLOC_H 00019 #include <malloc.h> 00020 #endif 00021 #include <limits.h> 00022 #include <math.h> 00023 #include "pathutil.h" 00024 00025 #ifdef DMALLOC 00026 #include "dmalloc.h" 00027 #endif 00028 00029 #define ISCCW 1 00030 #define ISCW 2 00031 #define ISON 3 00032 00033 #define DQ_FRONT 1 00034 #define DQ_BACK 2 00035 00036 #ifndef TRUE 00037 #define TRUE 1 00038 #define FALSE 0 00039 #endif 00040 00041 #define prerror(msg) \ 00042 fprintf (stderr, "libpath/%s:%d: %s\n", __FILE__, __LINE__, (msg)) 00043 00044 #define POINTSIZE sizeof (Ppoint_t) 00045 00046 typedef struct pointnlink_t { 00047 Ppoint_t *pp; 00048 struct pointnlink_t *link; 00049 } pointnlink_t; 00050 00051 #define POINTNLINKSIZE sizeof (pointnlink_t) 00052 #define POINTNLINKPSIZE sizeof (pointnlink_t *) 00053 00054 typedef struct tedge_t { 00055 pointnlink_t *pnl0p; 00056 pointnlink_t *pnl1p; 00057 struct triangle_t *ltp; 00058 struct triangle_t *rtp; 00059 } tedge_t; 00060 00061 typedef struct triangle_t { 00062 int mark; 00063 struct tedge_t e[3]; 00064 } triangle_t; 00065 00066 #define TRIANGLESIZE sizeof (triangle_t) 00067 00068 typedef struct deque_t { 00069 pointnlink_t **pnlps; 00070 int pnlpn, fpnlpi, lpnlpi, apex; 00071 } deque_t; 00072 00073 static jmp_buf jbuf; 00074 static pointnlink_t *pnls, **pnlps; 00075 static int pnln, pnll; 00076 00077 static triangle_t *tris; 00078 static int trin, tril; 00079 00080 static deque_t dq; 00081 00082 static Ppoint_t *ops; 00083 static int opn; 00084 00085 static void triangulate(pointnlink_t **, int); 00086 static int isdiagonal(int, int, pointnlink_t **, int); 00087 static void loadtriangle(pointnlink_t *, pointnlink_t *, pointnlink_t *); 00088 static void connecttris(int, int); 00089 static int marktripath(int, int); 00090 00091 static void add2dq(int, pointnlink_t *); 00092 static void splitdq(int, int); 00093 static int finddqsplit(pointnlink_t *); 00094 00095 static int ccw(Ppoint_t *, Ppoint_t *, Ppoint_t *); 00096 static int intersects(Ppoint_t *, Ppoint_t *, Ppoint_t *, Ppoint_t *); 00097 static int between(Ppoint_t *, Ppoint_t *, Ppoint_t *); 00098 static int pointintri(int, Ppoint_t *); 00099 00100 static void growpnls(int); 00101 static void growtris(int); 00102 static void growdq(int); 00103 static void growops(int); 00104 00105 /* Pshortestpath: 00106 * Find a shortest path contained in the polygon polyp going between the 00107 * points supplied in eps. The resulting polyline is stored in output. 00108 * Return 0 on success, -1 on bad input, -2 on memory allocation problem. 00109 */ 00110 int Pshortestpath(Ppoly_t * polyp, Ppoint_t * eps, Ppolyline_t * output) 00111 { 00112 int pi, minpi; 00113 double minx; 00114 Ppoint_t p1, p2, p3; 00115 int trii, trij, ftrii, ltrii; 00116 int ei; 00117 pointnlink_t epnls[2], *lpnlp, *rpnlp, *pnlp; 00118 triangle_t *trip; 00119 int splitindex; 00120 #ifdef DEBUG 00121 int pnli; 00122 #endif 00123 00124 if (setjmp(jbuf)) 00125 return -2; 00126 /* make space */ 00127 growpnls(polyp->pn); 00128 pnll = 0; 00129 tril = 0; 00130 growdq(polyp->pn * 2); 00131 dq.fpnlpi = dq.pnlpn / 2, dq.lpnlpi = dq.fpnlpi - 1; 00132 00133 /* make sure polygon is CCW and load pnls array */ 00134 for (pi = 0, minx = HUGE_VAL, minpi = -1; pi < polyp->pn; pi++) { 00135 if (minx > polyp->ps[pi].x) 00136 minx = polyp->ps[pi].x, minpi = pi; 00137 } 00138 p2 = polyp->ps[minpi]; 00139 p1 = polyp->ps[((minpi == 0) ? polyp->pn - 1 : minpi - 1)]; 00140 p3 = polyp->ps[((minpi == polyp->pn - 1) ? 0 : minpi + 1)]; 00141 if (((p1.x == p2.x && p2.x == p3.x) && (p3.y > p2.y)) || 00142 ccw(&p1, &p2, &p3) != ISCCW) { 00143 for (pi = polyp->pn - 1; pi >= 0; pi--) { 00144 if (pi < polyp->pn - 1 00145 && polyp->ps[pi].x == polyp->ps[pi + 1].x 00146 && polyp->ps[pi].y == polyp->ps[pi + 1].y) 00147 continue; 00148 pnls[pnll].pp = &polyp->ps[pi]; 00149 pnls[pnll].link = &pnls[pnll % polyp->pn]; 00150 pnlps[pnll] = &pnls[pnll]; 00151 pnll++; 00152 } 00153 } else { 00154 for (pi = 0; pi < polyp->pn; pi++) { 00155 if (pi > 0 && polyp->ps[pi].x == polyp->ps[pi - 1].x && 00156 polyp->ps[pi].y == polyp->ps[pi - 1].y) 00157 continue; 00158 pnls[pnll].pp = &polyp->ps[pi]; 00159 pnls[pnll].link = &pnls[pnll % polyp->pn]; 00160 pnlps[pnll] = &pnls[pnll]; 00161 pnll++; 00162 } 00163 } 00164 00165 #if DEBUG >= 1 00166 fprintf(stderr, "points\n%d\n", pnll); 00167 for (pnli = 0; pnli < pnll; pnli++) 00168 fprintf(stderr, "%f %f\n", pnls[pnli].pp->x, pnls[pnli].pp->y); 00169 #endif 00170 00171 /* generate list of triangles */ 00172 triangulate(pnlps, pnll); 00173 00174 #if DEBUG >= 2 00175 fprintf(stderr, "triangles\n%d\n", tril); 00176 for (trii = 0; trii < tril; trii++) 00177 for (ei = 0; ei < 3; ei++) 00178 fprintf(stderr, "%f %f\n", tris[trii].e[ei].pnl0p->pp->x, 00179 tris[trii].e[ei].pnl0p->pp->y); 00180 #endif 00181 00182 /* connect all pairs of triangles that share an edge */ 00183 for (trii = 0; trii < tril; trii++) 00184 for (trij = trii + 1; trij < tril; trij++) 00185 connecttris(trii, trij); 00186 00187 /* find first and last triangles */ 00188 for (trii = 0; trii < tril; trii++) 00189 if (pointintri(trii, &eps[0])) 00190 break; 00191 if (trii == tril) { 00192 prerror("source point not in any triangle"); 00193 return -1; 00194 } 00195 ftrii = trii; 00196 for (trii = 0; trii < tril; trii++) 00197 if (pointintri(trii, &eps[1])) 00198 break; 00199 if (trii == tril) { 00200 prerror("destination point not in any triangle"); 00201 return -1; 00202 } 00203 ltrii = trii; 00204 00205 /* mark the strip of triangles from eps[0] to eps[1] */ 00206 if (!marktripath(ftrii, ltrii)) { 00207 prerror("cannot find triangle path"); 00208 /* a straight line is better than failing */ 00209 growops(2); 00210 output->pn = 2; 00211 ops[0] = eps[0], ops[1] = eps[1]; 00212 output->ps = ops; 00213 return 0; 00214 } 00215 00216 /* if endpoints in same triangle, use a single line */ 00217 if (ftrii == ltrii) { 00218 growops(2); 00219 output->pn = 2; 00220 ops[0] = eps[0], ops[1] = eps[1]; 00221 output->ps = ops; 00222 return 0; 00223 } 00224 00225 /* build funnel and shortest path linked list (in add2dq) */ 00226 epnls[0].pp = &eps[0], epnls[0].link = NULL; 00227 epnls[1].pp = &eps[1], epnls[1].link = NULL; 00228 add2dq(DQ_FRONT, &epnls[0]); 00229 dq.apex = dq.fpnlpi; 00230 trii = ftrii; 00231 while (trii != -1) { 00232 trip = &tris[trii]; 00233 trip->mark = 2; 00234 00235 /* find the left and right points of the exiting edge */ 00236 for (ei = 0; ei < 3; ei++) 00237 if (trip->e[ei].rtp && trip->e[ei].rtp->mark == 1) 00238 break; 00239 if (ei == 3) { /* in last triangle */ 00240 if (ccw(&eps[1], dq.pnlps[dq.fpnlpi]->pp, 00241 dq.pnlps[dq.lpnlpi]->pp) == ISCCW) 00242 lpnlp = dq.pnlps[dq.lpnlpi], rpnlp = &epnls[1]; 00243 else 00244 lpnlp = &epnls[1], rpnlp = dq.pnlps[dq.lpnlpi]; 00245 } else { 00246 pnlp = trip->e[(ei + 1) % 3].pnl1p; 00247 if (ccw(trip->e[ei].pnl0p->pp, pnlp->pp, 00248 trip->e[ei].pnl1p->pp) == ISCCW) 00249 lpnlp = trip->e[ei].pnl1p, rpnlp = trip->e[ei].pnl0p; 00250 else 00251 lpnlp = trip->e[ei].pnl0p, rpnlp = trip->e[ei].pnl1p; 00252 } 00253 00254 /* update deque */ 00255 if (trii == ftrii) { 00256 add2dq(DQ_BACK, lpnlp); 00257 add2dq(DQ_FRONT, rpnlp); 00258 } else { 00259 if (dq.pnlps[dq.fpnlpi] != rpnlp 00260 && dq.pnlps[dq.lpnlpi] != rpnlp) { 00261 /* add right point to deque */ 00262 splitindex = finddqsplit(rpnlp); 00263 splitdq(DQ_BACK, splitindex); 00264 add2dq(DQ_FRONT, rpnlp); 00265 /* if the split is behind the apex, then reset apex */ 00266 if (splitindex > dq.apex) 00267 dq.apex = splitindex; 00268 } else { 00269 /* add left point to deque */ 00270 splitindex = finddqsplit(lpnlp); 00271 splitdq(DQ_FRONT, splitindex); 00272 add2dq(DQ_BACK, lpnlp); 00273 /* if the split is in front of the apex, then reset apex */ 00274 if (splitindex < dq.apex) 00275 dq.apex = splitindex; 00276 } 00277 } 00278 trii = -1; 00279 for (ei = 0; ei < 3; ei++) 00280 if (trip->e[ei].rtp && trip->e[ei].rtp->mark == 1) { 00281 trii = trip->e[ei].rtp - tris; 00282 break; 00283 } 00284 } 00285 00286 #if DEBUG >= 1 00287 fprintf(stderr, "polypath"); 00288 for (pnlp = &epnls[1]; pnlp; pnlp = pnlp->link) 00289 fprintf(stderr, " %f %f", pnlp->pp->x, pnlp->pp->y); 00290 fprintf(stderr, "\n"); 00291 #endif 00292 00293 for (pi = 0, pnlp = &epnls[1]; pnlp; pnlp = pnlp->link) 00294 pi++; 00295 growops(pi); 00296 output->pn = pi; 00297 for (pi = pi - 1, pnlp = &epnls[1]; pnlp; pi--, pnlp = pnlp->link) 00298 ops[pi] = *pnlp->pp; 00299 output->ps = ops; 00300 00301 return 0; 00302 } 00303 00304 /* triangulate polygon */ 00305 static void triangulate(pointnlink_t ** pnlps, int pnln) 00306 { 00307 int pnli, pnlip1, pnlip2; 00308 00309 if (pnln > 3) 00310 { 00311 for (pnli = 0; pnli < pnln; pnli++) 00312 { 00313 pnlip1 = (pnli + 1) % pnln; 00314 pnlip2 = (pnli + 2) % pnln; 00315 if (isdiagonal(pnli, pnlip2, pnlps, pnln)) 00316 { 00317 loadtriangle(pnlps[pnli], pnlps[pnlip1], pnlps[pnlip2]); 00318 for (pnli = pnlip1; pnli < pnln - 1; pnli++) 00319 pnlps[pnli] = pnlps[pnli + 1]; 00320 triangulate(pnlps, pnln - 1); 00321 return; 00322 } 00323 } 00324 prerror("triangulation failed"); 00325 } 00326 else 00327 loadtriangle(pnlps[0], pnlps[1], pnlps[2]); 00328 } 00329 00330 /* check if (i, i + 2) is a diagonal */ 00331 static int isdiagonal(int pnli, int pnlip2, pointnlink_t ** pnlps, 00332 int pnln) 00333 { 00334 int pnlip1, pnlim1, pnlj, pnljp1, res; 00335 00336 /* neighborhood test */ 00337 pnlip1 = (pnli + 1) % pnln; 00338 pnlim1 = (pnli + pnln - 1) % pnln; 00339 /* If P[pnli] is a convex vertex [ pnli+1 left of (pnli-1,pnli) ]. */ 00340 if (ccw(pnlps[pnlim1]->pp, pnlps[pnli]->pp, pnlps[pnlip1]->pp) == 00341 ISCCW) 00342 res = 00343 (ccw(pnlps[pnli]->pp, pnlps[pnlip2]->pp, pnlps[pnlim1]->pp) == 00344 ISCCW) 00345 && (ccw(pnlps[pnlip2]->pp, pnlps[pnli]->pp, pnlps[pnlip1]->pp) 00346 == ISCCW); 00347 /* Assume (pnli - 1, pnli, pnli + 1) not collinear. */ 00348 else 00349 res = (ccw(pnlps[pnli]->pp, pnlps[pnlip2]->pp, 00350 pnlps[pnlip1]->pp) == ISCW); 00351 if (!res) 00352 return FALSE; 00353 00354 /* check against all other edges */ 00355 for (pnlj = 0; pnlj < pnln; pnlj++) { 00356 pnljp1 = (pnlj + 1) % pnln; 00357 if (!((pnlj == pnli) || (pnljp1 == pnli) || 00358 (pnlj == pnlip2) || (pnljp1 == pnlip2))) 00359 if (intersects(pnlps[pnli]->pp, pnlps[pnlip2]->pp, 00360 pnlps[pnlj]->pp, pnlps[pnljp1]->pp)) 00361 return FALSE; 00362 } 00363 return TRUE; 00364 } 00365 00366 static void loadtriangle(pointnlink_t * pnlap, pointnlink_t * pnlbp, 00367 pointnlink_t * pnlcp) 00368 { 00369 triangle_t *trip; 00370 int ei; 00371 00372 /* make space */ 00373 if (tril >= trin) 00374 growtris(trin + 20); 00375 trip = &tris[tril++]; 00376 trip->mark = 0; 00377 trip->e[0].pnl0p = pnlap, trip->e[0].pnl1p = pnlbp, trip->e[0].rtp = 00378 NULL; 00379 trip->e[1].pnl0p = pnlbp, trip->e[1].pnl1p = pnlcp, trip->e[1].rtp = 00380 NULL; 00381 trip->e[2].pnl0p = pnlcp, trip->e[2].pnl1p = pnlap, trip->e[2].rtp = 00382 NULL; 00383 for (ei = 0; ei < 3; ei++) 00384 trip->e[ei].ltp = trip; 00385 } 00386 00387 /* connect a pair of triangles at their common edge (if any) */ 00388 static void connecttris(int tri1, int tri2) 00389 { 00390 triangle_t *tri1p, *tri2p; 00391 int ei, ej; 00392 00393 for (ei = 0; ei < 3; ei++) { 00394 for (ej = 0; ej < 3; ej++) { 00395 tri1p = &tris[tri1], tri2p = &tris[tri2]; 00396 if ((tri1p->e[ei].pnl0p->pp == tri2p->e[ej].pnl0p->pp && 00397 tri1p->e[ei].pnl1p->pp == tri2p->e[ej].pnl1p->pp) || 00398 (tri1p->e[ei].pnl0p->pp == tri2p->e[ej].pnl1p->pp && 00399 tri1p->e[ei].pnl1p->pp == tri2p->e[ej].pnl0p->pp)) 00400 tri1p->e[ei].rtp = tri2p, tri2p->e[ej].rtp = tri1p; 00401 } 00402 } 00403 } 00404 00405 /* find and mark path from trii, to trij */ 00406 static int marktripath(int trii, int trij) 00407 { 00408 int ei; 00409 00410 if (tris[trii].mark) 00411 return FALSE; 00412 tris[trii].mark = 1; 00413 if (trii == trij) 00414 return TRUE; 00415 for (ei = 0; ei < 3; ei++) 00416 if (tris[trii].e[ei].rtp && 00417 marktripath(tris[trii].e[ei].rtp - tris, trij)) 00418 return TRUE; 00419 tris[trii].mark = 0; 00420 return FALSE; 00421 } 00422 00423 /* add a new point to the deque, either front or back */ 00424 static void add2dq(int side, pointnlink_t * pnlp) 00425 { 00426 if (side == DQ_FRONT) { 00427 if (dq.lpnlpi - dq.fpnlpi >= 0) 00428 pnlp->link = dq.pnlps[dq.fpnlpi]; /* shortest path links */ 00429 dq.fpnlpi--; 00430 dq.pnlps[dq.fpnlpi] = pnlp; 00431 } else { 00432 if (dq.lpnlpi - dq.fpnlpi >= 0) 00433 pnlp->link = dq.pnlps[dq.lpnlpi]; /* shortest path links */ 00434 dq.lpnlpi++; 00435 dq.pnlps[dq.lpnlpi] = pnlp; 00436 } 00437 } 00438 00439 static void splitdq(int side, int index) 00440 { 00441 if (side == DQ_FRONT) 00442 dq.lpnlpi = index; 00443 else 00444 dq.fpnlpi = index; 00445 } 00446 00447 static int finddqsplit(pointnlink_t * pnlp) 00448 { 00449 int index; 00450 00451 for (index = dq.fpnlpi; index < dq.apex; index++) 00452 if (ccw(dq.pnlps[index + 1]->pp, dq.pnlps[index]->pp, pnlp->pp) == 00453 ISCCW) 00454 return index; 00455 for (index = dq.lpnlpi; index > dq.apex; index--) 00456 if (ccw(dq.pnlps[index - 1]->pp, dq.pnlps[index]->pp, pnlp->pp) == 00457 ISCW) 00458 return index; 00459 return dq.apex; 00460 } 00461 00462 /* ccw test: CCW, CW, or co-linear */ 00463 static int ccw(Ppoint_t * p1p, Ppoint_t * p2p, Ppoint_t * p3p) 00464 { 00465 double d; 00466 00467 d = ((p1p->y - p2p->y) * (p3p->x - p2p->x)) - 00468 ((p3p->y - p2p->y) * (p1p->x - p2p->x)); 00469 return (d > 0) ? ISCCW : ((d < 0) ? ISCW : ISON); 00470 } 00471 00472 /* line to line intersection */ 00473 static int intersects(Ppoint_t * pap, Ppoint_t * pbp, 00474 Ppoint_t * pcp, Ppoint_t * pdp) 00475 { 00476 int ccw1, ccw2, ccw3, ccw4; 00477 00478 if (ccw(pap, pbp, pcp) == ISON || ccw(pap, pbp, pdp) == ISON || 00479 ccw(pcp, pdp, pap) == ISON || ccw(pcp, pdp, pbp) == ISON) { 00480 if (between(pap, pbp, pcp) || between(pap, pbp, pdp) || 00481 between(pcp, pdp, pap) || between(pcp, pdp, pbp)) 00482 return TRUE; 00483 } else { 00484 ccw1 = (ccw(pap, pbp, pcp) == ISCCW) ? 1 : 0; 00485 ccw2 = (ccw(pap, pbp, pdp) == ISCCW) ? 1 : 0; 00486 ccw3 = (ccw(pcp, pdp, pap) == ISCCW) ? 1 : 0; 00487 ccw4 = (ccw(pcp, pdp, pbp) == ISCCW) ? 1 : 0; 00488 return (ccw1 ^ ccw2) && (ccw3 ^ ccw4); 00489 } 00490 return FALSE; 00491 } 00492 00493 /* is pbp between pap and pcp */ 00494 static int between(Ppoint_t * pap, Ppoint_t * pbp, Ppoint_t * pcp) 00495 { 00496 Ppoint_t p1, p2; 00497 00498 p1.x = pbp->x - pap->x, p1.y = pbp->y - pap->y; 00499 p2.x = pcp->x - pap->x, p2.y = pcp->y - pap->y; 00500 if (ccw(pap, pbp, pcp) != ISON) 00501 return FALSE; 00502 return (p2.x * p1.x + p2.y * p1.y >= 0) && 00503 (p2.x * p2.x + p2.y * p2.y <= p1.x * p1.x + p1.y * p1.y); 00504 } 00505 00506 static int pointintri(int trii, Ppoint_t * pp) 00507 { 00508 int ei, sum; 00509 00510 for (ei = 0, sum = 0; ei < 3; ei++) 00511 if (ccw(tris[trii].e[ei].pnl0p->pp, 00512 tris[trii].e[ei].pnl1p->pp, pp) != ISCW) 00513 sum++; 00514 return (sum == 3 || sum == 0); 00515 } 00516 00517 static void growpnls(int newpnln) 00518 { 00519 if (newpnln <= pnln) 00520 return; 00521 if (!pnls) { 00522 if (!(pnls = (pointnlink_t *) malloc(POINTNLINKSIZE * newpnln))) { 00523 prerror("cannot malloc pnls"); 00524 longjmp(jbuf,1); 00525 } 00526 if (!(pnlps = (pointnlink_t **) malloc(POINTNLINKPSIZE * newpnln))) { 00527 prerror("cannot malloc pnlps"); 00528 longjmp(jbuf,1); 00529 } 00530 } else { 00531 if (!(pnls = (pointnlink_t *) realloc((void *) pnls, 00532 POINTNLINKSIZE * newpnln))) { 00533 prerror("cannot realloc pnls"); 00534 longjmp(jbuf,1); 00535 } 00536 if (!(pnlps = (pointnlink_t **) realloc((void *) pnlps, 00537 POINTNLINKPSIZE * 00538 newpnln))) { 00539 prerror("cannot realloc pnlps"); 00540 longjmp(jbuf,1); 00541 } 00542 } 00543 pnln = newpnln; 00544 } 00545 00546 static void growtris(int newtrin) 00547 { 00548 if (newtrin <= trin) 00549 return; 00550 if (!tris) { 00551 if (!(tris = (triangle_t *) malloc(TRIANGLESIZE * newtrin))) { 00552 prerror("cannot malloc tris"); 00553 longjmp(jbuf,1); 00554 } 00555 } else { 00556 if (!(tris = (triangle_t *) realloc((void *) tris, 00557 TRIANGLESIZE * newtrin))) { 00558 prerror("cannot realloc tris"); 00559 longjmp(jbuf,1); 00560 } 00561 } 00562 trin = newtrin; 00563 } 00564 00565 static void growdq(int newdqn) 00566 { 00567 if (newdqn <= dq.pnlpn) 00568 return; 00569 if (!dq.pnlps) { 00570 if (! 00571 (dq.pnlps = 00572 (pointnlink_t **) malloc(POINTNLINKPSIZE * newdqn))) { 00573 prerror("cannot malloc dq.pnls"); 00574 longjmp(jbuf,1); 00575 } 00576 } else { 00577 if (!(dq.pnlps = (pointnlink_t **) realloc((void *) dq.pnlps, 00578 POINTNLINKPSIZE * 00579 newdqn))) { 00580 prerror("cannot realloc dq.pnls"); 00581 longjmp(jbuf,1); 00582 } 00583 } 00584 dq.pnlpn = newdqn; 00585 } 00586 00587 static void growops(int newopn) 00588 { 00589 if (newopn <= opn) 00590 return; 00591 if (!ops) { 00592 if (!(ops = (Ppoint_t *) malloc(POINTSIZE * newopn))) { 00593 prerror("cannot malloc ops"); 00594 longjmp(jbuf,1); 00595 } 00596 } else { 00597 if (!(ops = (Ppoint_t *) realloc((void *) ops, 00598 POINTSIZE * newopn))) { 00599 prerror("cannot realloc ops"); 00600 longjmp(jbuf,1); 00601 } 00602 } 00603 opn = newopn; 00604 }
1.7.5