/*------------------------------------------------------------------------------ Write mask data in circle format. Input: filename = name of file to write to; "" or "-" means write to standard output. fmt = pointer to format structure. polys = polygons to write. npolys = number of polygons. npolyw = number of polygons to write. Return value: number of polygons written, or -1 if error occurred. */ int wr_circ(char *filename, format *fmt, int npolys, polygon *polys[/*npolys*/], int npolyw) { char unit; char az_str[AZEL_STR_LEN], el_str[AZEL_STR_LEN], th_str[AZEL_STR_LEN]; int i, ier, ip, ipoly, nbadarea, npoly; double area, angle[3], tol; FILE *file; char *circle_fmt = "circle %d ( %d caps, %.15lg weight, %.15lf str):\n"; /* open filename for writing */ if (!filename || strcmp(filename, "-") == 0) { file = stdout; } else { file = fopen(filename, "w"); if (!file) { fprintf(stderr, "wr_circ: cannot open %s for writing\n", filename); return(-1); } } /* write number of polygons */ fprintf(file, "%d polygons\n", npolyw); /* write angular unit */ fprintf(file, "unit %c\n", fmt->outunitp); npoly = 0; nbadarea = 0; for (ipoly = 0; ipoly < npolys; ipoly++) { /* discard null polygons */ if (!polys[ipoly]) continue; /* area of polygon */ tol = mtol; ier = garea(polys[ipoly], &tol, verb, &area); if (ier == -1) return(-1); if (ier) { fprintf(stderr, "wr_circ: area of polygon %d is incorrect\n", polys[ipoly]->id); nbadarea++; } /* number of caps, weight, and area of polygon */ fprintf(file, circle_fmt, polys[ipoly]->id, polys[ipoly]->np, polys[ipoly]->weight, area); /* write boundaries of polygon */ for (ip = 0; ip < polys[ipoly]->np; ip++) { rpcm_to_circ(polys[ipoly]->rp[ip], &polys[ipoly]->cm[ip], angle); switch (fmt->outphase) { case '+': if (angle[0] < 0.) angle[0] += TWOPI; break; case '-': if (angle[0] > PI) angle[0] -= TWOPI; break; } for (i = 0; i < 3; i++) { unit = fmt->outunitp; if (i > 0 && fmt->outunitp == 'h') unit = 'd'; scale(&angle[i], 'r', unit); } wrangle(angle[0], fmt->outunitp, fmt->outprecision, AZEL_STR_LEN, az_str); wrangle(angle[1], fmt->outunitp, fmt->outprecision, AZEL_STR_LEN, el_str); wrangle(angle[2], (fmt->outunitp == 'h')? 'd' : fmt->outunitp, fmt->outprecision, AZEL_STR_LEN, th_str); fprintf(file, " %s %s %s", az_str, el_str, th_str); } fprintf(file, "\n"); /* increment polygon count */ npoly++; } /* warn about polygons with incorrect area */ if (nbadarea > 0) { msg("%d polygons have incorrect area, but kept\n", nbadarea); } /* advise */ msg("%d polygons written to %s\n", npoly, (file == stdout)? "output": filename); /* close file */ if (file != stdout) fclose(file); return(npoly); }
/*------------------------------------------------------------------------------ Discard polygons with weight or area outside specified limits. Input: polys = polygons. npolys = number of polygons. Return value: number of polygons retained, or -1 if error occurred. */ int discard_poly(int npolys, polygon *polys[/*npolys*/]) { int discard, ier, ipoly, nbadarea, noutarea, noutweight, npoly; double area, tol; if (is_weight_min || is_weight_max || is_area_min || is_area_max) { noutweight = 0; nbadarea = 0; noutarea = 0; for (ipoly = 0; ipoly < npolys; ipoly++) { discard = 0; /* discard polygons with weights outside interval */ if (is_weight_min && is_weight_max) { /* min <= max */ if (weight_min <= weight_max) { if (polys[ipoly]->weight < weight_min || polys[ipoly]->weight > weight_max) { discard = 1; } /* min > max */ } else { if (polys[ipoly]->weight < weight_min && polys[ipoly]->weight > weight_max) { discard = 1; } } } else if (is_weight_min) { if (polys[ipoly]->weight < weight_min) { discard = 1; } } else if (is_weight_max) { if (polys[ipoly]->weight > weight_max) { discard = 1; } } if (discard) { noutweight++; free_poly(polys[ipoly]); polys[ipoly] = 0x0; continue; } /* area of polygon */ tol = mtol; ier = garea(polys[ipoly], &tol, verb, &area); if (ier == -1) return(-1); if (ier) { nbadarea++; /* discard polygons with areas outside interval */ } else if (is_area_min && is_area_max) { /* min <= max */ if (area_min <= area_max) { if (area < area_min || area > area_max) { discard = 1; } /* min > max */ } else { if (area < area_min && area > area_max) { discard = 1; } } } else if (is_area_min) { if (area < area_min) { discard = 1; } } else if (is_area_max) { if (area > area_max) { discard = 1; } } if (discard) { noutarea++; free_poly(polys[ipoly]); polys[ipoly] = 0x0; continue; } } /* warn about discarded polygons */ if (noutweight > 0) { if (is_weight_min && is_weight_max) { if (weight_min < weight_max) { msg("%d polygons with weights outside [%g, %g] discarded\n", noutweight, weight_min, weight_max); } else { msg("%d polygons with weights inside (%g, %g) discarded\n", noutweight, weight_max, weight_min); } } else if (is_weight_min) { msg("%d polygons with weights < %g discarded\n", noutweight, weight_min); } else if (is_weight_max) { msg("%d polygons with weights > %g discarded\n", noutweight, weight_max); } } if (noutarea > 0) { if (is_area_min && is_area_max) { if (area_min < area_max) { msg("%d polygons with areas outside [%g, %g] discarded\n", noutarea, area_min, area_max); } else { msg("%d polygons with areas inside (%g, %g) discarded\n", noutarea, area_max, area_min); } } else if (is_area_min) { msg("%d polygons with areas < %g discarded\n", noutarea, area_min); } else if (is_area_max) { msg("%d polygons with areas > %g discarded\n", noutarea, area_max); } } } /* count non-null polygons */ npoly = 0; for (ipoly = 0; ipoly < npolys; ipoly++) { if (polys[ipoly]) npoly++; } return(npoly); }
/*------------------------------------------------------------------------------ Generate random az, el positions within mask defined by poly. The results are written to out_filename. Input: out_filename = name of file to write to; "" or "-" means write to standard output. fmt = pointer to format structure. npoly = number of polygons in poly array. npolysmax = maximum number of polygons in poly array. poly = array of pointers to polygons. mtol = initial tolerance angle for multiple intersections. Return value: number of random points generated, or -1 if error occurred. */ int ransack(char *out_filename, format *fmt, int npoly, int npolysmax, polygon *poly[/*npolysmax*/]) { /* number of extra caps to allocate to polygon, to allow for expansion */ #define DNP 4 /* length of state vector for random number generator */ #define STATELEN 256 static char state[STATELEN], stateo[STATELEN]; #define AZEL_STR_LEN 32 char output[] = "output"; char az_str[AZEL_STR_LEN], el_str[AZEL_STR_LEN]; int dnp, dnwl, i, idwidth, ier, in, inull, ip, ipmin, ipoly, iprune, irandom, lassoed, np, nwl, tries, verb, width, k; long long idmin,idmax; int *dlasso=0x0, *lasso=0x0; long double area, cmmin, cmi, phi, rpoly, si, tol, w, wcum, x, y, z; long double *wpoly; vec rp, xi, yi; azel v; char *out_fn; FILE *outfile; /* open out_filename for writing */ if (!out_filename || strcmp(out_filename, "-") == 0) { outfile = stdout; out_fn = output; } else { outfile = fopen(out_filename, "w"); if (!outfile) { fprintf(stderr, "ransack: cannot open %s for writing\n", out_filename); goto error; } out_fn = out_filename; } /* advise angular units */ if (fmt->outunit != fmt->inunit) { msg("units of output az, el angles will be "); switch (fmt->outunit) { #include "angunit.h" } msg("\n"); } /* initialize random number generator used by ransack() */ initstate(seed, state, STATELEN); /* initialize random number generator used by ikrand() */ initstate(seed, stateo, STATELEN); /* prune polygons, discarding those with zero weight * area */ msg("pruning %d polygons ...\n", npoly); ier = 0; inull = 0; np = 0; for (ipoly = 0; ipoly < npoly; ipoly++) { /* zero weight polygon */ if (poly[ipoly]->weight == 0.) { inull++; free_poly(poly[ipoly]); poly[ipoly] = 0x0; } else { /* prune polygon */ iprune = prune_poly(poly[ipoly], mtol); /* error */ if (iprune == -1) { ier++; free_poly(poly[ipoly]); poly[ipoly] = 0x0; fprintf(stderr, "ransack: failed to prune polygon %d; discard it\n", ipoly); /* goto error; */ /* zero area polygon */ } else if (iprune >= 2) { inull++; free_poly(poly[ipoly]); poly[ipoly] = 0x0; } else { np++; } } } /*copy down non-null polygons*/ k=0; for(ipoly = 0; ipoly < npoly; ipoly++){ if(poly[ipoly]){ poly[k++]=poly[ipoly]; } } /*after copying non-null polygons, k should be equal to np */ if(k!=np){ fprintf(stderr, "ransack: should be left with %d non-null polygons, but actually have %d\n",np,k); } /*nullify the rest of the array, but don't free, since pointers have been copied above*/ for(ipoly=np; ipoly < npoly; ipoly++){ poly[ipoly]=0x0; } if (ier > 0) { msg("discarding %d unprunable polygons\n", ier); } if (inull > 0) { msg("discarding %d polygons with zero weight * area\n", inull); } /* number of polygons with finite weight * area */ npoly = np; /* no polygons */ if (npoly == 0) { fprintf(stderr, "ransack: no polygons to generate random points inside!\n"); goto error; } /* pre-lasso polygons if there are many random points */ if (nrandom >= npoly) { msg("lassoing %d polygons ...\n", npoly); /* lasso each polygon */ np = npoly; for (ipoly = 0; ipoly < npoly; ipoly++) { ier = lasso_poly(&poly[ipoly], npolysmax - np, &poly[np], mtol, &dnp); if (ier == -1) { fprintf(stderr, "ransack: UHOH at polygon %lld; continuing ...\n", poly[ipoly]->id); } /* lassoed polygons are an improvement over original polygon */ if (dnp > 0) { /* check whether exceeded maximum number of polygons */ if (np + dnp > npolysmax) { fprintf(stderr, "ransack: total number of polygons exceeded maximum %d\n", npolysmax); fprintf(stderr, "if you need more space, enlarge NPOLYSMAX in defines.h, and recompile\n"); goto error; } /* decrement dnp by 1 */ dnp--; /* increment number of polygons */ np += dnp; /* move last polygon part into poly[ipoly] */ free_poly(poly[ipoly]); poly[ipoly] = poly[np]; poly[np] = 0x0; } } /* revised number of polygons */ npoly = np; /* flag that all polygons have been lassoed */ lassoed = 1; /* two few random points to make it worth pre-lassoing */ } else { /* flag that all polygons have not been lassoed */ lassoed = 0; } /* allocate memory for wpoly array */ nwl = npoly; wpoly = (long double *) malloc(sizeof(long double) * nwl); if (!wpoly) { fprintf(stderr, "ransack: failed to allocate memory for %d long doubles\n", nwl); goto error; } if (!lassoed) { /* allocate memory for lasso and dlasso arrays */ lasso = (int *) malloc(sizeof(int) * nwl); if (!lasso) { fprintf(stderr, "ransack: failed to allocate memory for %d ints\n", nwl); goto error; } dlasso = (int *) malloc(sizeof(int) * nwl); if (!dlasso) { fprintf(stderr, "ransack: failed to allocate memory for %d ints\n", nwl); goto error; } /* initialize dlasso array to zero */ for (ipoly = 0; ipoly < nwl; ipoly++) dlasso[ipoly] = 0; } /* largest width of polygon id number */ idmin = 0; idmax = 0; for (ipoly = 0; ipoly < npoly; ipoly++) { if (poly[ipoly]->id < idmin) idmin = poly[ipoly]->id; if (poly[ipoly]->id > idmax) idmax = poly[ipoly]->id; } idmin = ((idmin < 0)? floorl(log10l((long double)-idmin)) + 2 : 1); idmax = ((idmax > 0)? floorl(log10l((long double)idmax)) + 1 : 1); idwidth = ((idmin > idmax)? idmin : idmax); /* write header */ wrangle(0., fmt->outunit, fmt->outprecision, AZEL_STR_LEN, az_str); width = strlen(az_str); if (fmt->outunit == 'h') { sprintf(az_str, "az(hms)"); sprintf(el_str, "el(dms)"); } else { sprintf(az_str, "az(%c)", fmt->outunit); sprintf(el_str, "el(%c)", fmt->outunit); } fprintf(outfile, "%*s\t%*s\t%*s\n", width, az_str, width, el_str, idwidth, "id"); /* accept error messages from garea */ /* unprunable polygons were already discarded, so garea should give no errors */ verb = 1; /* cumulative area times weight of polygons */ w = 0.; for (ipoly = 0; ipoly < npoly; ipoly++) { /* skip null polygons */ if (poly[ipoly]) { /* area of polygon */ tol = mtol; ier = garea(poly[ipoly], &tol, verb, &area); if (ier) goto error; /* accumulate weight times area */ w += poly[ipoly]->weight * area; } wpoly[ipoly] = w; } wcum = w; /* random points */ if (strcmp(out_fn, output) != 0) { msg("generating %d random points from seed %u in %d polygons ...\n", nrandom, seed, npoly); } for (irandom = 0; irandom < nrandom; irandom++) { /* random number in interval [0, 1) wcum */ setstate(state); rpoly = drandom() * wcum; setstate(stateo); /* which polygon to put random point in */ ipoly = search(npoly, wpoly, rpoly); /* guard against roundoff */ if (ipoly >= npoly) { fprintf(stderr, "ransack: %d should be < %d (i.e. %.15Lg < %.15Lg)\n", ipoly, npoly, rpoly, wpoly[npoly - 1]); ipoly = npoly - 1; } /* all polygons have not been lassoed */ if (!lassoed) { /* polygon has not yet been lassoed */ if (dlasso[ipoly] == 0) { /* lasso polygon */ ier = lasso_poly(&poly[ipoly], npolysmax - np, &poly[np], mtol, &dnp); if (ier == -1) { fprintf(stderr, "ransack: UHOH at polygon %lld; continuing ...\n", poly[ipoly]->id); } /* go with original polygon */ if (dnp == 0) { /* lasso, dlasso */ lasso[ipoly] = ipoly; dlasso[ipoly] = 1; /* lassoed polygons are an improvement over original */ } else { /* check whether exceeded maximum number of polygons */ if (np + dnp > npolysmax) { fprintf(stderr, "ransack: total number of polygons exceeded maximum %d\n", npolysmax); fprintf(stderr, "if you need more space, enlarge NPOLYSMAX in defines.h, and recompile\n"); goto error; } /* just one lassoed polygon */ if (dnp == 1) { /* move last polygon part into poly[ipoly] */ free_poly(poly[ipoly]); poly[ipoly] = poly[np]; poly[np] = 0x0; /* lasso, dlasso */ lasso[ipoly] = ipoly; dlasso[ipoly] = 1; /* more than one lassoed polygon */ } else { /* enlarge memory for wpoly, lasso, and dlasso arrays */ if (np + dnp > nwl) { dnwl = dnp + 1024; wpoly = (long double *) realloc(wpoly, sizeof(long double) * (nwl + dnwl)); if (!wpoly) { fprintf(stderr, "ransack: failed to reallocate memory for %d long doubles\n", nwl + dnwl); goto error; } lasso = (int *) realloc(lasso, sizeof(int) * (nwl + dnwl)); if (!lasso) { fprintf(stderr, "ransack: failed to reallocate memory for %d ints\n", nwl + dnwl); goto error; } dlasso = (int *) realloc(dlasso, sizeof(int) * (nwl + dnwl)); if (!dlasso) { fprintf(stderr, "ransack: failed to reallocate memory for %d ints\n", nwl + dnwl); goto error; } /* initialize new part of lasso and dlasso arrays to inconsistent values */ for (ipoly = nwl; ipoly < nwl + dnwl; ipoly++) lasso[ipoly] = 1; for (ipoly = nwl; ipoly < nwl + dnwl; ipoly++) dlasso[ipoly] = 0; /* revised size of wpoly, lasso, and dlasso arrays */ nwl += dnwl; } /* lasso, dlasso */ lasso[ipoly] = np; dlasso[ipoly] = dnp; /* cumulative weight times area of lassoed polygons */ w = (ipoly == 0)? 0. : wpoly[ipoly-1]; for (ip = np; ip < np + dnp; ip++) { /* area of polygon */ tol = mtol; ier = garea(poly[ip], &tol, verb, &area); if (ier) goto error; /* accumulate area times weight */ w += poly[ip]->weight * area; wpoly[ip] = w; } /* increment number of polygons */ np += dnp; } } } /* polygon was partitioned into at least two */ if (dlasso[ipoly] >= 2) { /* which polygon to put random point in */ ip = search(dlasso[ipoly], &wpoly[lasso[ipoly]], rpoly); /* guard against roundoff */ if (ip >= lasso[ipoly] + dlasso[ipoly]) { fprintf(stderr, "ransack: %d should be < %d (i.e. %.15Lg < %.15Lg)\n", ip, lasso[ipoly] + dlasso[ipoly], rpoly, wpoly[lasso[ipoly] + dlasso[ipoly] - 1]); ip = lasso[ipoly] + dlasso[ipoly] - 1; } /* revised polygon number to put random point in */ ipoly = ip; } } /* smallest cap of polygon */ cmminf(poly[ipoly], &ipmin, &cmmin); /* random point within polygon */ tries = 0; do { tries++; /* random point within smallest cap */ setstate(state); phi = TWOPI * drandom(); cmi = cmmin * drandom(); setstate(stateo); /* coordinates of random point in cap frame */ si=sqrtl(cmi * (2. - cmi)); x = si * cosl(phi); y = si * sinl(phi); z = 1. - cmi; /* polygon has caps */ if (poly[ipoly]->np > 0) { if (poly[ipoly]->cm[ipmin] < 0.) z = -z; /* Cartesian axes with z-axis along cap axis */ gaxisi_(poly[ipoly]->rp[ipmin], xi, yi); /* coordinates of random point */ for (i = 0; i < 3; i++) rp[i] = x * xi[i] + y * yi[i] + z * poly[ipoly]->rp[ipmin][i]; /* whether random point is inside polygon */ in = gptin(poly[ipoly], rp); /* polygon has no caps, so is the whole sphere */ } else { rp[0] = x; rp[1] = y; rp[2] = z; in = 1; } } while (!in); /* convert unit vector to az, el */ rp_to_azel(rp, &v); v.az -= floorl(v.az / TWOPI) * TWOPI; /* convert az and el from radians to output units */ scale_azel(&v, 'r', fmt->outunit); /* write result */ wrangle(v.az, fmt->outunit, fmt->outprecision, AZEL_STR_LEN, az_str); wrangle(v.el, fmt->outunit, fmt->outprecision, AZEL_STR_LEN, el_str); fprintf(outfile, "%s\t%s\t%*lld\n", az_str, el_str, idwidth, poly[ipoly]->id); /* fprintf(outfile, "%s %s %d %d %d %Lg %Lg %Lg %Lg %d %d\n", az_str, el_str, irandom, ipoly, tries, wcum, rpoly / wcum, area, TWOPI * cmmin / area, ipmin, poly[ipoly]->np); */ } /* advise */ if (outfile != stdout) { msg("ransack: %d random positions written to %s\n", nrandom, out_fn); } return(nrandom); /* error returns */ error: return(-1); }
/*------------------------------------------------------------------------------ Take pixelized polygons, find the average weight within each pixel, and return a set of polygons consisting of the pixels weighted with the average weight. Input: poly = array of pointers to polygons. npoly = pointer to number of polygons. Output: polys = array of pointers to polygons; Return value: number of polygons discarded by pixelmapping, or -1 if error occurred. */ int pixelmap(int *npoly, polygon *poly[/**npoly*/]) { int i, j, nadj, k, kstart,kend,numpix; int *start; int *total; int *parent_pixels; int begin, end, p,max_pixel,min_pixel, ier, verb,res1,res2; long double tol,area, tot_area; long double *av_weight; long double *av_weight0; poly_sort(*npoly,poly,'p'); min_pixel = poly[0]->pixel; max_pixel = poly[*npoly-1]->pixel+1; res1=get_res(min_pixel,scheme); res2=get_res(max_pixel,scheme); if(res1<res_max){ fprintf(stderr,"pixelmap: there are pixels in the mask with a lower resolution than the desired pixelmap resolution %d. The desired pixelmap resolution can be set with the -P option.\n",res_max); fprintf(stderr,"Before using pixelmap, use pixelize with the -P0,r option to pixelize the entire mask to the desired resolution r.\n"); return(-1); } /* allocate memory for pixel info arrays start and total */ start = (int *) malloc(sizeof(int) * max_pixel); if (!start) { fprintf(stderr, "pixelmap: failed to allocate memory for %d integers\n", max_pixel); return(-1); } total = (int *) malloc(sizeof(int) * max_pixel); if (!total) { fprintf(stderr, "pixelmap: failed to allocate memory for %d integers\n", max_pixel); return(-1); } /* build lists of starting indices of each pixel and total number of polygons in each pixel*/ ier=pixel_list(*npoly, poly, max_pixel, start, total); if (ier == -1) { fprintf(stderr, "pixelmap: error building pixel index lists\n"); return(-1); } //allocate memory for parent pixels array parent_pixels = (int *) malloc(sizeof(int) * (res2+1)); if (!parent_pixels) { fprintf(stderr, "pixelmap: failed to allocate memory for %d integers\n", res2+1); return(-1); } //kstart=number of first pixel at desired output resolution //kend=number of last pixel at desired output resolution if(res_max==-1){ kstart=pixel_start(res1,scheme); kend=pixel_start(res2+1,scheme)-1; } else{ kstart=pixel_start(res_max,scheme); kend=pixel_start(res_max+1,scheme)-1; } av_weight0= (long double *) malloc(sizeof(long double) * (kend-kstart+1) ); if (!av_weight0) { fprintf(stderr, "pixelmap: failed to allocate memory for %d integers\n", kend-kstart+1 ); return(-1); } //make av_weight an array indexed by the pixel number av_weight=av_weight0-kstart; //set av_weight array to 0 initially for(k=kstart;k<=kend;k++){ av_weight[k]=0; } nadj = 0; verb=1; /*find average weight of polygons within each pixel*/ for(p=min_pixel;p<max_pixel;p++){ begin=start[p]; end=start[p]+total[p]; ier=get_parent_pixels(p,parent_pixels,scheme); if(ier) return(-1); //set k to the pixel at the desired output resolution, or to the pixel number if using //existing resolution k=(res_max==-1) ? p : parent_pixels[res_max]; for (i = begin; i < end; i++) { if (!poly[i]) continue; tol=mtol; ier = garea(poly[i], &tol, verb, &area); if(ier==1 || ier == -1){ fprintf(stderr, "error %d in garea in polygon %d\n", ier, poly[i]->id); continue; } av_weight[k]+=poly[i]->weight * area; } } //replace polygons in input array with non-zero weight pixels j=0; for(k=kstart;k<=kend;k++){ if(av_weight[k]==0) continue; free_poly(poly[j]); poly[j]=get_pixel(k,scheme); tol=mtol; ier = garea(poly[j], &tol, verb, &tot_area); if(ier==1 || ier == -1){ fprintf(stderr, "pixelmap: error in garea in pixel %d\n",p); continue; } poly[j]->weight=av_weight[k]/tot_area; j++; if(j> *npoly ){ fprintf(stderr,"pixelmap: number of pixels with non-zero weight exceeds number of polygons.\n"); fprintf(stderr, "Try running unify on your mask to remove zero-weight polygons before using pixelmap.\n"); } } numpix=j; for(j=numpix; j< *npoly; j++){ free_poly(poly[j]); poly[j] = 0x0; nadj++; } *npoly=numpix; free(start); free(total); free(parent_pixels); free(av_weight0); /* assign new polygon id numbers */ if (fmt.newid == 'n') { for (i = 0; i < *npoly; i++) { poly[i]->id = i; } } if (fmt.newid == 'p') { for (i = 0; i < *npoly; i++) { poly[i]->id = poly[i]->pixel; } } /* advise */ msg("pixelmap: %d pixels in map\n", numpix); return(nadj); }
/*------------------------------------------------------------------------------ If poly1 overlaps poly2, split poly1 into two parts. If poly3 is null on input, then the appropriate return value is returned, but poly1 is not actually split. Input: *poly1, poly2 are 2 polygons. mtol = initial angular tolerance within which to merge multiple intersections. Output: If **poly3 is not null on input, then: *poly1 and *poly3 are 2 split polygons of poly1, if poly1 is split, with *poly1 the part outside poly2, and *poly3 the part intersecting poly2; *poly1 and *poly3 remain untouched if poly1 is not split. If **poly3 is null on input, then *poly1 remains untouched. Return value: -1 = error occurred; 0 = poly1 and poly2 have zero intersection; 1 = poly2 fully encloses poly1; 2 = poly2 splits poly1 into two. */ int split_poly(polygon **poly1, polygon *poly2, polygon **poly3, long double mtol) { static polygon *poly = 0x0, *poly4 = 0x0; int ier, ip, iprune, np, np1, verb; long double area, area_tot, cm, tol,area1,area3,area4; /* poly2 is whole sphere, therefore contains poly1 */ if (poly2->np == 0){ return(1); } /* make sure poly contains enough space for intersection */ np = (*poly1)->np + poly2->np; ier = room_poly(&poly, np, DNP, 0); if (ier == -1) goto out_of_memory; /* intersection of poly1 and poly2 */ poly_poly(*poly1, poly2, poly); /* suppress coincident boundaries, to make garea happy */ iprune = trim_poly(poly); /* intersection of poly1 and poly2 is null polygon */ if (iprune >= 2) return(0); /* area of intersection */ tol = mtol; verb = 1; ier = garea(poly, &tol, verb, &area_tot); if (ier) goto error; /* poly1 and poly2 have zero intersection */ if (area_tot == 0.) return(0); /* area of poly1 */ tol = mtol; verb = 1; ier = garea(*poly1, &tol, verb, &area1); if (ier) goto error; /* number of caps of poly1 */ np1 = (*poly1)->np; /* find boundary of poly2 which intersects poly1 */ verb = 0; for (ip = 0; ip < poly2->np; ip++) { cm = poly->cm[np1 + ip]; poly->cm[np1 + ip] = 2.; /* suppress boundary to be tested */ tol = mtol; ier = garea(poly, &tol, verb, &area); /* area of intersection sans boundary */ poly->cm[np1 + ip] = cm; /* restore tested boundary */ if (area > area_tot) { /* boundary intersects poly1 */ /* poly2 splits poly1, but do not actually split */ if (!poly3) return(2); /* number of caps of poly1 with extra boundary */ np = np1 + 1; /* make sure poly3 contains enough space */ ier = room_poly(poly3, np, DNP, 0); if (ier == -1) goto out_of_memory; /* poly3 is intersection of poly1 and ip'th cap of poly2 */ poly_polyn(*poly1, poly2, ip, 1, *poly3); /* prune poly3 */ iprune = prune_poly(*poly3, mtol); if (iprune == -1) goto error; /* poly3 may be null because of roundoff: skip to next cap */ if (iprune >= 2) continue; /* area of poly3 */ tol = mtol; verb = 1; ier = garea(*poly3, &tol, verb, &area3); if (ier) goto error; /* check to make sure area of poly3 is less than poly1; if not, skip to next cap*/ if(area3>=area1) continue; /* make sure poly4 contains enough space */ ier = room_poly(&poly4, np, DNP, 1); if (ier == -1) goto out_of_memory; /* poly4 is intersection of poly1 and complement of ip'th cap of poly2 */ poly_polyn(*poly1, poly2, ip, -1, poly4); /* prune poly4 */ iprune = prune_poly(poly4, mtol); if (iprune == -1) goto error; /* poly4 may be null because of roundoff: skip to next cap */ if (iprune >= 2) continue; /* area of poly4 */ tol = mtol; verb = 1; ier = garea(poly4, &tol, verb, &area4); if (ier) goto error; /* check to make sure area of poly3 is less than poly1; if not, skip to next cap*/ if(area4>=area1) continue; /* make sure poly1 contains enough space */ np = poly4->np; ier = room_poly(poly1, np, DNP, 0); if (ier == -1) goto out_of_memory; /* copy poly4 into poly1 */ copy_poly(poly4, *poly1); /* poly1 successfully split into poly1 and poly3 */ return(2); } else if (area < area_tot) { /* area should be >= area_tot because suppressing a boundary of poly should always increase its area; but this can happen because of roundoff */ //fprintf(stderr, "split_poly: area %.16Lg of polygon with boundary %d suppressed should be >= area %.16Lg of polygon\n", area, ip, area_tot); } } /* poly2 contains poly1 */ return(1); /* ---------------- error returns ---------------- */ error: return(-1); out_of_memory: fprintf(stderr, "split_poly: failed to allocate memory for polygon of %d caps\n", np + DNP); return(-1); }