/*------------------------------------------------------------------------------ Intersect polygons of poly1 with any polygon(s) of poly2 having the same id number. This subroutine implements the -n option of poly2poly. */ int intersect_poly(int npoly1, polygon *poly1[/*npoly1*/], int npoly2, polygon *poly2[/*npoly2*/], long double mtol) { int ier, inull, iprune, i, j, k, np; /* intersect each poly1 with any poly2 having same id number */ for (i = 0; i < npoly1; i++) { for (j = 0; j < npoly2; j++) { if (poly1[i]->id == poly2[j]->id && poly1[i]->pixel == poly2[j]->pixel ) { /* make sure poly1 contains enough space for intersection */ np = poly1[i]->np + poly2[j]->np; ier = room_poly(&poly1[i], np, 0, 1); if (ier == -1) goto out_of_memory; /* intersection of poly1 and poly2 */ poly_poly(poly1[i], poly2[j], poly1[i]); } } } /* free poly2 polygons */ for (j = 0; j < npoly2; j++) { free_poly(poly2[j]); poly2[j] = 0x0; } /* prune poly1 polygons */ j = 0; inull = 0; for (i = 0; i < npoly1; i++) { iprune = prune_poly(poly1[i], mtol); if (iprune == -1) { fprintf(stderr, "intersect_poly: failed to prune polygon %lld; continuing ...\n", (fmt.newid == 'o')? poly1[i]->id : (long long)j+fmt.idstart); } if (iprune >= 2) { free_poly(poly1[i]); poly1[i] = 0x0; inull++; } else { j++; } } /*copy down non-null polygons*/ k=0; for(i = 0; i < npoly1; i++){ if(poly1[i]){ poly1[k++]=poly1[i]; } } /*after copying non-null polygons, k should be equal to j */ if(k!=j){ fprintf(stderr, "intersect_poly: should be left with %d non-null polygons, but actually have %d\n",j,k); } /*nullify the rest of the array, but don't free, since pointers have been copied above*/ for(i=j; i < npoly1; i++){ poly1[i]=0x0; } if (inull > 0) msg("%d intersected polygons have zero area, and are being discarded\n", inull); npoly1 = j; return(npoly1); /* ---------------- error returns ---------------- */ out_of_memory: fprintf(stderr, "intersect_poly: failed to allocate memory for polygon of %d caps\n", np); return(-1); }
/*------------------------------------------------------------------------------ Pixelize: split polygons against a pre-defined pixel map such that each polygon is in only one pixel Input: npoly = number of polygons. poly = array of pointers to polygons. npolys = maximum number of output polygons. Output: polys = array of pointers to polygons. Return value: number of disjoint connected polygons, or -1 if error occurred. */ int pixelize(int npoly, polygon *poly[/*npoly*/], int npolys, polygon *polys[/*npolys*/]) { /* part_poly should lasso one-boundary polygons only if they have too many caps */ #define ALL_ONEBOUNDARY 1 /* how part_poly should tighten lasso */ #define ADJUST_LASSO 1 /* part_poly should force polygon to be split even if no part can be lassoed */ #define FORCE_SPLIT 1 /* partition_poly should overwrite all original polygons */ #define OVERWRITE_ORIGINAL 2 #define WARNMAX 8 char *snapped_polys = 0x0; int isnap,j, nadj; int dn, dnp, failed, i, ier, inull, ip, iprune, m, n, np; msg("pruning input polygons\n"); /* start by pruning all input polygons */ np = 0; inull = 0; for (i = 0; i < npoly; i++) { iprune = prune_poly(poly[i], mtol); /* error */ if (iprune == -1) { fprintf(stderr, "pixelize: initial prune failed at polygon %lld\n", poly[i]->id); return(-1); } /* zero area polygon */ if (iprune >= 2) { if (WARNMAX > 0 && inull == 0) msg("warning from pixelize: the following polygons have zero area & are being discarded:\n"); if (inull < WARNMAX) { msg(" %lld", (fmt.newid == 'o')? poly[i]->id : (long long)i+fmt.idstart); } else if (inull == WARNMAX) { msg(" ... more\n"); } inull++; } else { np++; } } if (WARNMAX > 0 && inull > 0 && inull <= WARNMAX) msg("\n"); if (inull > 0) { msg("pixelize: %d polygons with zero area are being discarded.\n", inull); } /* number of polygons */ msg("pixelizing %d polygons ...\n", np); /* set all input polygons to be in pixel 0 (whole sky)*/ inull=0; for (i = 0; i < npoly; i++) { if(poly[i]->pixel!=0){ poly[i]->pixel = 0; if(WARNMAX>0 && inull ==0) msg("warning from pixelize: following polygons are being re-set to be in pixel 0:\n"); if (inull < WARNMAX) { msg(" %lld", (fmt.newid == 'o')? poly[i]->id : (long long)i+fmt.idstart); } else if (inull == WARNMAX) { msg(" ... more\n"); } inull++; } } if (WARNMAX > 0 && inull > 0 && inull <= WARNMAX) msg("\n"); if (inull > 0) { msg("pixelize: %d polygons have been re-set to be in pixel 0.\n", inull); } /* nullify all output polygons */ for (i = 0; i < npolys; i++) { polys[i] = 0x0; } msg("pixelize stage 1 (fragment each polygon so it is in only one pixel):\n"); /*call recursive pixel_loop to split polygons into pixels*/ n=pixel_loop(0,npoly,poly,npolys,polys); if(n==-1) return(-1); dnp=n-np; np=n; msg("added %d polygons to make %d\n", dnp, np); /* partition disconnected polygons into connected parts */ msg("pixelize stage 2 (partition disconnected polygons into connected parts):\n"); m = n; dnp = 0; ip = 0; failed = 0; for (i = 0; i < m; i++) { /* skip null polygons */ if (!polys[i] || (polys[i]->np > 0 && polys[i]->cm[0] == 0.)) continue; /* partition disconnected polygons */ ier = partition_poly(&polys[i], npolys - n, &polys[n], mtol, ALL_ONEBOUNDARY, ADJUST_LASSO, FORCE_SPLIT, OVERWRITE_ORIGINAL, &dn); /* error */ if (ier == -1) { fprintf(stderr, "pixelize: UHOH at polygon %lld; continuing ...\n", (fmt.newid == 'o')? polys[i]->id : (long long)ip+fmt.idstart); continue; /* return(-1); */ /* failed to partition polygon into desired number of parts */ } else if (ier == 1) { fprintf(stderr, "pixelize: failed to partition polygon %lld fully; partitioned it into %d parts\n", (fmt.newid == 'o')? polys[i]->id : (long long)ip+fmt.idstart, dn + 1); failed++; } /* increment index of next subset of fragments */ n += dn; /* increment polygon count */ np += dn; dnp += dn; /* check whether exceeded maximum number of polygons */ if (n > npolys) { fprintf(stderr, "pixelize: total number of polygons exceeded maximum %d\n", npoly + npolys); fprintf(stderr, "if you need more space, enlarge NPOLYSMAX in defines.h, and recompile\n"); return(-1); } ip++; } msg("added %d polygons to make %d\n", dnp, np); if (failed > 0) { msg("pixelize: failed to split %d polygons into desired number of connected parts\n", failed); msg(".............................................................................\n"); msg("Failure to split polygon probably means:\n"); msg("either (1) you forgot to run snap on all your input polygon files;\n"); msg(" or (2) the polygon is too small for the numerics to cope with;\n"); msg(" or (3) you have a weird-shaped polygon.\n"); msg("You may ignore this warning message if the weights of polygons in the input\n"); msg("polygon file(s) are already correct, and you do not want to reweight them.\n"); msg("Similarly, you may ignore this warning message if you do want to reweight the\n"); msg("polygons, but the weights of the different parts of each unsplit polygon are\n"); msg("the same. If you want to reweight the different parts of an unsplit polygon\n"); msg("with different weights, then you will need to split that polygon by hand.\n"); msg("Whatever the case, the output file of pixelized polygons constitutes\n"); msg("a valid mask with each polygon in only one pixel, and is safe to use.\n"); msg(".............................................................................\n"); } /* // prune msg("pruning ... \n"); j = 0; inull = 0; for (i = 0; i < n; i++) { iprune = prune_poly(polys[i], mtol); if (iprune == -1) { fprintf(stderr, "pixelize: failed to prune polygon %lld; continuing ...\n", (fmt.newid == 'o')? polys[i]->id : (long long)j+fmt.idstart); return(-1); } if (iprune >= 2) { free_poly(polys[i]); polys[i] = 0x0; inull++; } else { polys[j] = polys[i]; j++; } } if (inull > 0) msg("pixelize: %d pixelized polygons have zero area, and are being discarded\n", inull); n = j; //allocate snapped_polys array snapped_polys = (char *) malloc(sizeof(char) * n); if (!snapped_polys) { fprintf(stderr, "pixelize: failed to allocate memory for %d characters\n", n); return(-1); } //snap edges of each polygon selfsnap = 1; nadj = snap_polys(&fmt, n, polys, selfsnap, axtol, btol, thtol, ytol, mtol, WARNMAX, snapped_polys); if(nadj==-1){ msg("pixelize: error snapping pixelized polygons\n"); return(-1); } //number of polygons whose edges were snapped isnap = 0; for (i = 0; i < n; i++) if (snapped_polys[i]) isnap++; if (isnap > 0) msg("pixelize: edges of %d pixelized polygons were snapped\n", isnap); //prune snapped polygons j = 0; inull = 0; for (i = 0; i < n; i++) { if (snapped_polys[i]) { iprune = prune_poly(polys[i], mtol); if (iprune == -1) { fprintf(stderr, "pixelize: failed to prune polygon %lld; continuing ...\n", (fmt.newid == 'o')? polys[i]->id : (long long)j+fmt.idstart); // return(-1); } if (iprune >= 2) { free_poly(polys[i]); polys[i] = 0x0; inull++; } else { polys[j] = polys[i]; j++; } } else { polys[j] = polys[i]; j++; } } if (inull > 0) msg("pixelize: %d snapped polygons have zero area, and are being discarded\n", inull); n = j; //free snapped_polys array free(snapped_polys); */ if(n!=-1){ /* sort polygons by pixel number */ poly_sort(n, polys, 'p'); } /* assign new polygon id numbers in place of inherited ids */ if (fmt.newid == 'n') { for (i = 0; i < n; i++) { polys[i]->id = (long long)i+fmt.idstart; } } if (fmt.newid == 'p') { for (i = 0; i < n; i++) { polys[i]->id = (long long)polys[i]->pixel; } } return(n); }
int pixel_loop(int pix, int n, polygon *input[/*n*/], int out_max, polygon *output[/*out_max*/]){ int *child_pix,children; int i,j,k,m,out,nout; int ier, iprune, np; polygon *pixel; polygon **poly; //allocate memory for work array of polygon pointers poly=(polygon **) malloc(sizeof(polygon *) * n); if(!poly){ fprintf(stderr, "pixel_loop: failed to allocate memory for %d polygon pointers\n",n); return(-1); } // allocate memory for child_pix array if(pix==0 && scheme=='d'){ child_pix=(int *) malloc(sizeof(int) * 117); children=117; if(!child_pix){ fprintf(stderr, "pixel_loop: failed to allocate memory for 117 integers\n"); return(-1); } } else{ child_pix=(int *) malloc(sizeof(int) * 4); children=4; if(!child_pix){ fprintf(stderr, "pixel_loop: failed to allocate memory for %d integers\n", 4); return(-1); } } get_child_pixels(pix, child_pix, scheme); out=0; for(i=0;i<children;i++){ /*get the current child pixel*/ pixel=get_pixel(child_pix[i], scheme); if(!pixel){ fprintf(stderr, "error in pixel_loop: could not get pixel %d\n", child_pix[i]); return(-1); } /*loop through input polygons to find the ones that overlap with current child pixel*/ for(j=0;j<n;j++){ /* skip null polygons */ if (input[j]->np > 0 && input[j]->cm[0] == 0.){ poly[j] = 0x0; continue; } np=input[j]->np+pixel->np; poly[j]=new_poly(np); if(!poly[j]){ fprintf(stderr, "error in pixel_loop: failed to allocate memory for polygon of %d caps\n", np); return(-1); } /*set poly[j] to the intersection of input[j] and current child pixel*/ poly_poly(input[j],pixel,poly[j]); poly[j]->pixel=pixel->pixel; iprune = prune_poly(poly[j], mtol); if (iprune == -1) { fprintf(stderr, "pixelize: failed to prune polygon for pixel %d; continuing ...\n", poly[j]->pixel); //return(-1); } /*if polygon is null, get rid of it*/ if (iprune >= 2) { free_poly(poly[j]); poly[j] = 0x0; } } /*copy down non-null polygons*/ k=0; for(j=0;j<n;j++){ if(poly[j]){ poly[k++]=poly[j]; } } m=k; /*nullify the rest of the array, but don't free, since pointers have been copied above*/ for(j=m;j<n;j++){ poly[j]=0x0; } /*if we're below the max resolution, recursively call pixel_loop on the current child pixel */ if(m>polys_per_pixel && get_res(child_pix[i],scheme)<res_max){ //printf("calling pixel loop for pixel %d with %d polygons\n",child_pix[i],m); nout=pixel_loop(child_pix[i],m,poly,out_max-out,&output[out]); if(nout==-1) return(-1); out+=nout; } else{ for(k=0;k<m;k++){ /* check whether exceeded maximum number of polygons */ if (out >= out_max) { fprintf(stderr, "pixel_loop: total number of polygons exceeded maximum %d\n", NPOLYSMAX); fprintf(stderr, "if you need more space, enlarge NPOLYSMAX in defines.h, and recompile\n"); return(-1); } /*make sure output polygon has enough room */ ier = room_poly(&output[out], poly[k]->np, DNP, 0); if (ier == -1) { fprintf(stderr, "error in pixel_loop: failed to allocate memory for polygon of %d caps\n", poly[i]->np + DNP); return(-1); } /*copy polygon to output array*/ copy_poly(poly[k],output[out]); out++; } } /*free up memory for next child pixel*/ free_poly(pixel); for(j=0;j<n;j++){ free_poly(poly[j]); } } free(child_pix); free(poly); return out; }
/*------------------------------------------------------------------------------ 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, double mtol, char bmethod) { static polygon *poly = 0x0, *poly4 = 0x0; int ier, ip, iprune, np, np1, verb; double area, area_tot, cm, tol; /* poly2 is whole sphere, therefore contains poly1 */ if (poly2->np == 0){ /* set weight according to balkanization scheme: */ if(bmethod=='l'){ //do nothing - this is the default behavior } else if(bmethod=='a'){ (*poly1)->weight=(*poly1)->weight + poly2->weight; } else if(bmethod=='n'){ (*poly1)->weight=((*poly1)->weight > poly2->weight)? poly2->weight : (*poly1)->weight ; } else if(bmethod=='x'){ (*poly1)->weight=((*poly1)->weight > poly2->weight)? (*poly1)->weight : poly2->weight ; } else{ fprintf(stderr, "error in split_poly: balkanize method %c not recognized.\n", bmethod); return(-1); } 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); /* 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; /* 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; /* 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 */ /* set weight according to balkanization scheme: */ if(bmethod=='l'){ //do nothing - this is the default behavior } else if(bmethod=='a'){ (*poly3)->weight=(*poly1)->weight + poly2->weight; } else if(bmethod=='n'){ (*poly3)->weight=((*poly1)->weight > poly2->weight)? poly2->weight : (*poly1)->weight ; } else if(bmethod=='x'){ (*poly3)->weight=((*poly1)->weight > poly2->weight)? (*poly1)->weight : poly2->weight ; } else{ fprintf(stderr, "error in split_poly: balkanize method %c not recognized.\n", bmethod); return(-1); } 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 %.16g of polygon with boundary %d suppressed should be >= area %.16g of polygon\n", area, ip, area_tot); } } /* poly2 contains poly1 */ /* set weight according to balkanization scheme: */ if(bmethod=='l'){ //do nothing - this is the default behavior } else if(bmethod=='a'){ (*poly1)->weight=(*poly1)->weight + poly2->weight; } else if(bmethod=='n'){ (*poly1)->weight=((*poly1)->weight > poly2->weight)? poly2->weight : (*poly1)->weight ; } else if(bmethod=='x'){ (*poly1)->weight=((*poly1)->weight > poly2->weight)? (*poly1)->weight : poly2->weight ; } else{ fprintf(stderr, "error in split_poly: balkanize method %c not recognized.\n", bmethod); return(-1); } 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); }
/*------------------------------------------------------------------------------ Make almost coincident caps of polygons coincide. Input: npoly = number of polygons to snap. *poly[npoly] = array of npoly pointers to polygon structures. Return value: number of caps adjusted. */ int snap(int npoly, polygon *poly[/*npoly*/]) { #define WARNMAX 8 int i, j, ip, inull, iprune, nadj, dnadj, warnmax; int *start; int *total; int p, max_pixel, ier; long double r; /* start by sorting polygons by pixel number*/ poly_sort(npoly,poly,'p'); /* allocate memory for pixel info arrays start and total */ /* if only self-snapping, don't use pixelization */ max_pixel=(selfsnap)? 1 : poly[npoly-1]->pixel+1; start = (int *) malloc(sizeof(int) * max_pixel); if (!start) { fprintf(stderr, "snap_polys: failed to allocate memory for %d integers\n", max_pixel); return(-1); } total = (int *) malloc(sizeof(int) * max_pixel); if (!total) { fprintf(stderr, "snap_polys: failed to allocate memory for %d integers\n", max_pixel); return(-1); } /* if we're only doing self-snapping, don't use the pixelization info */ if(selfsnap){ start[0]=0; total[0]=npoly; } else{ /* 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, "snap: error building pixel index lists\n"); return(-1); } } /*turn off warning messages if using more than one pixel*/ warnmax= (max_pixel<=1) ? WARNMAX : 0; /* ensure that rp is a unit vector for all polygon caps*/ for (i = 0; i < npoly; i++) { for(ip=0; ip<poly[i]->np; ip++){ r = 0.; for (j = 0; j < 3; j++) r += poly[i]->rp[ip][j] * poly[i]->rp[ip][j]; if (r != 1.) { r = sqrt(r); for (j = 0; j < 3; j++) poly[i]->rp[ip][j] /= r; } } } /* snap edges of polygons to each other */ nadj=0; for(p=0;p<max_pixel;p++){ if(total[p]==0) continue; dnadj=snap_polys(&fmt, total[p], &poly[start[p]], selfsnap, axtol, btol, thtol, ytol, mtol,((selfsnap)? warnmax : warnmax/2),0x0); if(dnadj==-1) return(-1); nadj+=dnadj; } /* prune polygons */ inull = 0; for (i = 0; i < npoly; i++) { iprune = prune_poly(poly[i], mtol); if (iprune >= 2) { if (WARNMAX > 0 && inull == 0) msg("warning from snap: the following polygons have zero area:\n"); if (inull < WARNMAX) { msg(" %d", (fmt.newid == 'o')? poly[i]->id : i); } else if (inull == WARNMAX) { msg(" ... more\n"); } inull++; } } if (WARNMAX > 0 && inull > 0 && inull <= WARNMAX) msg("\n"); if (inull > 0) msg("snap: %d snapped polygons have zero area (but are being retained)\n", inull); /* 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; } } msg("snap: total of %d caps adjusted\n", nadj); return(nadj); }
/*------------------------------------------------------------------------------ Balkanize overlapping polygons into many disjoint connected polygons. Input: npoly = number of polygons. poly = array of pointers to polygons. npolys = maximum number of output polygons. mtol = tolerance angle for multiple intersections. fmt = pointer to format structure. axtol, btol, thtol, ytol = tolerance angles (see documentation). Output: polys = array of pointers to polygons. Return value: number of disjoint connected polygons, or -1 if error occurred. */ int balkanize(int npoly, polygon *poly[/*npoly*/], int npolys, polygon *polys[/*npolys*/], long double mtol, format *fmt, long double axtol, long double btol, long double thtol, long double ytol) { /* part_poly should lasso one-boundary polygons only if they have too many caps */ #define ALL_ONEBOUNDARY 1 /* how part_poly should tighten lasso */ #define ADJUST_LASSO 1 /* part_poly should force polygon to be split even if no part can be lassoed */ #define FORCE_SPLIT 1 /* partition_poly should overwrite all original polygons */ #define OVERWRITE_ORIGINAL 2 #define WARNMAX 8 char *snapped_polys = 0x0; int discard, dm, dn, dnp, failed, i, ier, inull, isnap, ip, iprune, j, k, m, n, nadj, np, selfsnap; int *start; int *total; int begin, end, p, max_pixel; long double tol; poly_sort(npoly, poly, 'p'); /* allocate memory for pixel info arrays start and total */ max_pixel=poly[npoly-1]->pixel+1; start = (int *) malloc(sizeof(int) * max_pixel); if (!start) { fprintf(stderr, "balkanize: failed to allocate memory for %d integers\n", max_pixel); return(-1); } total = (int *) malloc(sizeof(int) * max_pixel); if (!total) { fprintf(stderr, "balkanize: 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, "balkanize: error building pixel index lists\n"); return(-1); } /* start by pruning all input polygons */ np = 0; inull = 0; for (i = 0; i < npoly; i++) { tol = mtol; iprune = prune_poly(poly[i], tol); /* error */ if (iprune == -1) { fprintf(stderr, "balkanize: initial prune failed at polygon %d\n", poly[i]->id); return(-1); } /* zero area polygon */ if (iprune >= 2) { if (WARNMAX > 0 && inull == 0) msg("warning from balkanize: following polygons have zero area & are being discarded:\n"); if (inull < WARNMAX) { msg(" %lld", (fmt->newid == 'o')? poly[i]->id : (long long)i); } else if (inull == WARNMAX) { msg(" ... more\n"); } inull++; } else { np++; } } if (WARNMAX > 0 && inull > 0 && inull <= WARNMAX) msg("\n"); if (inull > 0) { msg("balkanize: %d polygons with zero area are being discarded;\n", inull); } /* number of polygons */ msg("balkanizing %d polygons ...\n", np); /* nullify all output polygons */ for (i = 0; i < npolys; i++) { polys[i] = 0x0; } /* m = starting index of current set of fragments of i'th polygon dm = number of current set of fragments of i'th polygon n = starting index of new subset of fragments of i'th polygon dn = number of new subset of fragments of i'th polygon */ msg("balkanize stage 1 (fragment into non-overlapping polygons):\n"); n = 0; dnp = 0; ip = 0; /* go through each pixel and fragment each polygon against the other polygons in its pixel */ for(p=0;p<max_pixel;p++){ begin=start[p]; end=start[p]+total[p]; /* too many polygons */ if (n >= npolys) break; /* fragment each polygon in turn */ for (i = begin; i < end; i++) { /* skip null polygons */ if (poly[i]->np > 0 && poly[i]->cm[0] == 0.) continue; /* update indices */ m = n; dm = 1; n = m + dm; /* make sure output polygon has enough room */ ier = room_poly(&polys[m], poly[i]->np, DNP, 0); if (ier == -1) { fprintf(stderr, "balkanize: failed to allocate memory for polygon of %d caps\n", poly[i]->np + DNP); return(-1); } /* copy polygon i into output polygon */ copy_poly(poly[i], polys[m]); /* fragment successively against other polygons */ for (j = begin; j < end; j++) { /* skip self, or null polygons */ if (j == i || (poly[j]->np > 0 && poly[j]->cm[0] == 0.)) continue; /* keep only one copy of the intersection of i & j */ /* intersection inherits weight of polygon being fragmented, so keeping later polygon ensures intersection inherits weight of later polygon */ if (i < j) { discard = 1; } else { discard = 0; } /* fragment each part of i'th polygon */ for (k = m; k < m + dm; k++) { /* skip null polygons */ if (!polys[k] || (polys[k]->np > 0 && polys[k]->cm[0] == 0.)) continue; /* fragment */ tol = mtol; dn = fragment_poly(&polys[k], poly[j], discard, npolys - n, &polys[n], tol, bmethod); /* error */ if (dn == -1) { fprintf(stderr, "balkanize: UHOH at polygon %lld; continuing ...\n", (fmt->newid == 'o')? polys[i]->id : (long long)ip); continue; /* return(-1); */ } /* increment index of next subset of fragments */ n += dn; /* increment polygon count */ np += dn; dnp += dn; if (!polys[k]) { np--; dnp--; } /* check whether exceeded maximum number of polygons */ //printf("(1) n = %d\n", n); if (n > npolys) { fprintf(stderr, "(1) balkanize: total number of polygons (= %d) exceeded maximum %d\n", npoly + n, npoly + npolys); fprintf(stderr, "if you need more space, enlarge NPOLYSMAX in defines.h, and recompile\n"); fprintf(stderr, "currently, dn = %d, np = %d, dnp = %d, poly[%d]->id = %lld, poly[%d]->pixel = %d\n", dn, np, dnp, i, poly[i]->id, i, poly[i]->pixel); n = npolys; #ifdef CARRY_ON_REGARDLESS break; #else return(-1); #endif } } /* copy down non-null polygons */ dm = 0; for (k = m; k < n; k++) { if (polys[k]) { polys[m + dm] = polys[k]; dm++; } } /* nullify but don't free, because freeing polys[k] will free polys[m + dm] */ for (k = m + dm; k < n; k++) { polys[k] = 0x0; } n = m + dm; if (dm == 0) break; } /* too many polygons */ if (n >= npolys) break; ip++; } } free(start); free(total); msg("added %d polygons to make %d\n", dnp, np); // partition disconnected polygons into connected parts msg("balkanize stage 2 (partition disconnected polygons into connected parts):\n"); m = n; dnp = 0; ip = 0; failed = 0; for (i = 0; i < m; i++) { // skip null polygons if (!polys[i] || (polys[i]->np > 0 && polys[i]->cm[0] == 0.)) continue; // partition disconnected polygons tol = mtol; ier = partition_poly(&polys[i], npolys - n, &polys[n], tol, ALL_ONEBOUNDARY, ADJUST_LASSO, FORCE_SPLIT, OVERWRITE_ORIGINAL, &dn); // error if (ier == -1) { fprintf(stderr, "balkanize: UHOH at polygon %lld; continuing ...\n", (fmt->newid == 'o')? polys[i]->id : (long long)ip); continue; // return(-1); // failed to partition polygon into desired number of parts } else if (ier == 1) { fprintf(stderr, "balkanize: failed to partition polygon %lld fully; partitioned it into %d parts\n", (fmt->newid == 'o')? polys[i]->id : (long long)ip, dn + 1); failed++; } // increment index of next subset of fragments n += dn; // increment polygon count np += dn; dnp += dn; // check whether exceeded maximum number of polygons //printf("(2) n = %d\n", n); if (n > npolys) { fprintf(stderr, "(2) balkanize: total number of polygons (= %d) exceeded maximum %d\n", n + npoly, npoly + npolys); fprintf(stderr, "if you need more space, enlarge NPOLYSMAX in defines.h, and recompile\n"); n = npolys; #ifdef CARRY_ON_REGARDLESS break; #else return(-1); #endif } ip++; } msg("added %d polygons to make %d\n", dnp, np); if (failed > 0) { msg("balkanize: failed to split %d polygons into desired number of connected parts\n", failed); msg(".............................................................................\n"); msg("Failure to split polygon probably means:\n"); msg("either (1) you forgot to run snap on all your input polygon files;\n"); msg(" or (2) the polygon is too small for the numerics to cope with;\n"); msg(" or (3) you have a weird-shaped polygon.\n"); msg("You may ignore this warning message if the weights of polygons in the input\n"); msg("polygon file(s) are already correct, and you do not want to reweight them.\n"); msg("Similarly, you may ignore this warning message if you do want to reweight the\n"); msg("polygons, but the weights of the different parts of each unsplit polygon are\n"); msg("the same. If you want to reweight the different parts of an unsplit polygon\n"); msg("with different weights, then you will need to split that polygon by hand.\n"); msg("Whatever the case, the output file of balkanized polygons constitutes\n"); msg("a valid mask of non-overlapping polygons, which is safe to use.\n"); msg(".............................................................................\n"); } /* prune */ j = 0; inull = 0; for (i = 0; i < n; i++) { tol = mtol; iprune = prune_poly(polys[i], tol); if (iprune == -1) { fprintf(stderr, "balkanize: failed to prune polygon %lld; continuing ...\n", (fmt->newid == 'o')? polys[i]->id : (long long)j); /* return(-1); */ } if (iprune >= 2) { free_poly(polys[i]); polys[i] = 0x0; inull++; } else { polys[j] = polys[i]; j++; } } if (inull > 0) msg("balkanize: %d balkanized polygons have zero area, and are being discarded\n", inull); n = j; /* // allocate snapped_polys array snapped_polys = (char *) malloc(sizeof(char) * n); if (!snapped_polys) { fprintf(stderr, "balkanize: failed to allocate memory for %d characters\n", n); return(-1); } //snap edges of each polygon selfsnap = 1; nadj = snap_polys(fmt, n, polys, selfsnap, axtol, btol, thtol, ytol, mtol, WARNMAX, snapped_polys); if(nadj==-1){ msg("balkanize: error snapping balkanized polygons\n"); return(-1); } // number of polygons whose edges were snapped isnap = 0; for (i = 0; i < n; i++) if (snapped_polys[i]) isnap++; if (isnap > 0) msg("balkanize: edges of %d balkanized polygons were snapped\n", isnap); // prune snapped polygons j = 0; inull = 0; for (i = 0; i < n; i++) { if (snapped_polys[i]) { iprune = prune_poly(polys[i], mtol); if (iprune == -1) { fprintf(stderr, "balkanize: failed to prune polygon %lld; continuing ...\n", (fmt->newid == 'o')? polys[i]->id : (long long)j); // return(-1); } if (iprune >= 2) { free_poly(polys[i]); polys[i] = 0x0; inull++; } else { polys[j] = polys[i]; j++; } } else { polys[j] = polys[i]; j++; } } if (inull > 0) msg("balkanize: %d snapped polygons have zero area, and are being discarded\n", inull); n = j; // free snapped_polys array free(snapped_polys); */ if(n!=-1){ /* sort polygons by pixel number */ poly_sort(n, polys,'p'); msg("balkanize: balkans contain %d polygons\n", n); } /* assign new polygon id numbers in place of inherited ids */ if (fmt->newid == 'n') { for (i = 0; i < n; i++) { polys[i]->id = (long long)i; } } if (fmt->newid == 'p') { for (i = 0; i < n; i++) { polys[i]->id = (long long)polys[i]->pixel; } } return(n); }
/*------------------------------------------------------------------------------ Partition group polygon into connected polygons by calling part_poly repeatedly until the group polygon is fully partitioned, or until partitioning fails. If the group polygon has two or more connected boundaries none of which can be lassoed, then the force_split option controls whether part_poly should be forced to split the polygon in two. If a split is forced, then each of the resulting two polygons is subjected to further partitioning, or is in turn forcibly split if necessary. If too many forcible splits occur, then it is assumed that the procedure is not converging, and the routine bails out. Input: gpoly is a polygon all of whose circles belong to a single group. npolys = maximum number of polygons available in polys array. mtol = parameter passed to part_poly. all_oneboundary = parameter passed to part_poly. adjust_lasso = parameter passed to part_poly. force_split = 1 to force part_poly to split a polygon even if no boundary can be lassoed; 0 otherwise. Output: polys[i], i = 0 to *npoly-1, are the parts of gpoly; if return value = 0, then: if *npoly = 0, then: input gpoly already consists of a single connected part that needs no partitioning; if *npoly > 0, then: gpoly was fully partitioned into its parts; if return value = 1, then: if force_split = 0, then: gpoly was partially partitioned, and polys[*npoly-1] contains those parts of the input gpoly that were not partitioned successfully; in spite of the failure, polys[i], i = 0 to *npoly-1 constitute a valid set of parts, whose union equals the input gpoly; if force_split = 1, then: the attempt to partition gpoly was abandoned after gpoly was forcibly split too many times; polys[i], i = 0 to *npoly-1 contain the parts of gpoly obtained so far; in spite of the failure, polys[i], i = 0 to *npoly-1 constitute a valid set of parts, whose union equals the input gpoly, though some parts are disconnected. *npoly = number of polygons in polys; if *npoly > npolys, then there was not enough space. Return value: -1 if error occurred; 0 if gpoly was successfully partitioned; 1 if gpoly was not fully partitioned. */ int partition_gpoly(polygon *gpoly, int npolys, polygon *polys[/*npolys*/], long double mtol, int all_oneboundary, int adjust_lasso, int force_split, int *npoly) { /* bail out if number of forcibly split polygons to partition exceeds this maximum */ #define NFORCEMAX 200 int dnpoly, dnpoly_try, iforce, ier, ipoly, iprune, jpoly, nforce; int do_poly[NFORCEMAX]; polygon *poly; /* initialize number of polygon parts in polys to zero */ *npoly = 0; /* number of forcibly split polygons to partition */ nforce = 0; /* partition these polygons */ for (iforce = -1; iforce < nforce; iforce++) { /* start with input group polygon */ if (iforce == -1) { poly = gpoly; /* subsequent polygons that have been split forcibly */ } else { poly = polys[do_poly[iforce]]; } /* partition polygon repeatedly, as long as progress is made */ while (1) { /* partition polygon by lassoing its boundaries with circles */ ier = part_poly(poly, npolys - *npoly, &polys[*npoly], mtol, all_oneboundary, adjust_lasso, force_split, &dnpoly, &dnpoly_try); if (ier == -1) return(-1); /* increment number of polygons made */ *npoly += dnpoly; /* not enough polygons */ if (*npoly > npolys) return(0); /* partitioning was partially successful */ if (dnpoly > 0 && dnpoly < dnpoly_try && ier == 0) { /* move last polygon into poly and repeat */ (*npoly)--; poly = polys[*npoly]; polys[*npoly] = 0x0; /* partitioning succeeded, or failed completely */ } else { /* poly was left unpartitioned, and is not the original group polygon */ if (dnpoly == 0 && *npoly > 0) { /* move poly into next polygon */ polys[*npoly] = poly; /* nullify source of poly, if it is a forcibly split polygon */ if (iforce >= 0 && poly == polys[do_poly[iforce]]) polys[do_poly[iforce]] = 0x0; (*npoly)++; } /* break out of loop */ break; } } /* part_poly forcibly split polygon into two parts, which need further partitioning */ if (ier == 1) { if (nforce + 2 <= NFORCEMAX) { for (ipoly = *npoly - 2; ipoly < *npoly; ipoly++) { /* prune polygon that needs further partitioning */ iprune = prune_poly(polys[ipoly], mtol); if (iprune == -1) { fprintf(stderr, "partition_gpoly: failed to prune forcibly split part %d of polygon with input id %lld\n", nforce, polys[ipoly]->id); goto error; } if (iprune >= 2) { fprintf(stderr, "partition_poly: forcibly split part %d of polygon with input id %lld has zero area; should not happen; continuing ...\n", nforce, polys[ipoly]->id); dump_poly(2, &polys[*npoly - 2]); continue; } /* flag polygon for further partitioning */ do_poly[nforce] = ipoly; nforce++; } /* too many forcible splits: bail out */ } else { /* advise */ msg("partition_gpoly: unable to lasso parts of a polygon even after it has been\n"); msg("split forcibly many times; bailing out with %d polygon parts.\n", *npoly); msg("CONGRATULATIONS! YOU HAVE FOUND A POLYGON THAT BEATS MANGLE.\n"); msg("PLEASE EMAIL ME [email protected] THE GOOD NEWS\n"); msg("ALONG WITH A POLYGON FILE CONTAINING THE POLYGON THAT DID IT.\n"); /* dump the polygon to a polygon file */ dump_poly(1, &gpoly); msg("AND THERE'S THE POLYGON FILE I'D LIKE YOU TO SEND. THANKS!\n"); /* number of forcibly split polygons that have been partitioned */ nforce = iforce + 1; /* break out of partitioning loop */ break; } } } /* flag that partitioning was only partially successful */ if (dnpoly < dnpoly_try) ier = 1; /* remove forcibly split polygons that were partitioned */ if (nforce > 0) { iforce = 0; jpoly = 0; for (ipoly = 0; ipoly < *npoly; ipoly++) { /* free forcibly split polygons */ if (iforce < nforce && ipoly == do_poly[iforce]) { if (polys[ipoly]) free_poly(polys[ipoly]); iforce++; /* move down polygons */ } else { polys[jpoly] = polys[ipoly]; jpoly++; } } /* nullify vacated polygons */ for (ipoly = jpoly; ipoly < *npoly; ipoly++) { polys[ipoly] = 0x0; } /* revise number of polygons */ *npoly = jpoly; } return(ier); /* ---------------- error returns ---------------- */ error: return(-1); }
/*------------------------------------------------------------------------------ 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); }
/*------------------------------------------------------------------------------ Make almost coincident caps of polygons coincide. Return value: number of caps adjusted. */ int snap(int npoly, polygon *poly[/*npoly*/]) { #define WARNMAX 8 int dnadj, dnadjo, i, inull, iprune, j, nadj, pass, snapped, stuck, warn; nadj = 0; /* snap repeatedly, until no more caps snap together */ pass = 0; stuck = 0; do { /* snap caps of each pair of polygons in turn, including self-pairs */ pass++; dnadjo = dnadj; dnadj = 0; warn = 0; if (axtol >= 0. || btol >= 0.) { for (i = 0; i < npoly; i++) { for (j = i; j < npoly; j++) { snapped = snap_poly(poly[i], poly[j], axtol, btol); if (snapped) { if (WARNMAX/2 > 0 && warn == 0) msg("snap stage 1 pass %d: caps of the following polygons were snapped together:\n", pass); if (warn < WARNMAX/2) { msg(" (%d %d)", (fmt.newid == 'o')? poly[i]->id : i, (fmt.newid == 'o')? poly[j]->id : j); } else if (warn == WARNMAX/2) { msg(" ... more\n"); } dnadj += snapped; warn++; } } } } if (WARNMAX/2 > 0 && warn > 0 && warn <= WARNMAX/2) msg("\n"); msg("snap stage 1 (axes, latitudes) pass %d: %d caps adjusted\n", pass, dnadj); nadj += dnadj; /* avoid infinite loop */ if (pass > 1 && dnadj >= dnadjo) stuck++; } while (dnadj && stuck < 2); if (dnadj) { fprintf(stderr, "seem to be stuck in a loop ... exit\n"); } /* trim polygons */ for (i = 0; i < npoly; i++) { trim_poly(poly[i]); } /* snap repeatedly, until no more caps snap together */ pass = 0; stuck = 0; do { /* snap edges of each polygon to caps of each polygon in turn */ pass++; dnadjo = dnadj; dnadj = 0; warn = 0; if (thtol >= 0. && ytol >= 0.) { for (i = 0; i < npoly; i++) { for (j = 0; j < npoly; j++) { snapped = snap_polyth(poly[i], poly[j], thtol, ytol, mtol); if (snapped) { if (WARNMAX/2 > 0 && warn == 0) msg("snap stage 2 pass %d: caps of the following polygons were snapped together:\n", pass); if (warn < WARNMAX/2) { msg(" (%d %d)", (fmt.newid == 'o')? poly[i]->id : i, (fmt.newid == 'o')? poly[j]->id : j); } else if (warn == WARNMAX/2) { msg(" ... more\n"); } dnadj += snapped; warn++; } } } } if (WARNMAX/2 > 0 && warn > 0 && warn <= WARNMAX/2) msg("\n"); msg("snap stage 2 (edges) pass %d: %d caps adjusted\n", pass, dnadj); nadj += dnadj; /* avoid infinite loop */ if (pass > 1 && dnadj >= dnadjo) stuck++; } while (dnadj && stuck < 2); if (dnadj) { fprintf(stderr, "seem to be stuck in a loop ... exit\n"); } /* prune polygons */ inull = 0; for (i = 0; i < npoly; i++) { iprune = prune_poly(poly[i], mtol); if (iprune >= 2) { if (WARNMAX > 0 && inull == 0) msg("warning from snap: the following polygons have zero area:\n"); if (inull < WARNMAX) { msg(" %d", (fmt.newid == 'o')? poly[i]->id : i); } else if (inull == WARNMAX) { msg(" ... more\n"); } inull++; } } if (WARNMAX > 0 && inull > 0 && inull <= WARNMAX) msg("\n"); if (inull > 0) msg("snap: %d snapped polygons have zero area (but are being retained)\n", inull); /* assign new polygon id numbers */ if (fmt.newid == 'n') { for (i = 0; i < npoly; i++) { poly[i]->id = i; } } msg("snap: total of %d caps adjusted\n", nadj); return(nadj); }
int grow_poly(polygon **poly, int npolys, polygon *polys[/*npolys*/], long double grow_angle, long double mtol, int *np){ int i, ip, jp, iret, ier, dn; long double s, cmi, cm_new,theta, theta_new, tol; polygon *poly1= 0x0; /* part_poly should lasso all one-boundary polygons */ #define ALL_ONEBOUNDARY 2 /* how part_poly should tighten lasso */ #define ADJUST_LASSO 2 /* part_poly should force polygon to be split even if no part can be lassoed */ #define FORCE_SPLIT 1 /* partition_poly should overwrite all original polygons */ #define OVERWRITE_ORIGINAL 2 if((*poly)->pixel!=0){ fprintf(stderr, "Error: input polygon is pixelized. The grow function can only be applied to non-pixelized polygons."); return(-1); } *np=0; // partition disconnected polygons tol = mtol; ier = partition_poly(poly, npolys, polys, tol, ALL_ONEBOUNDARY, ADJUST_LASSO, FORCE_SPLIT, OVERWRITE_ORIGINAL, &dn); // error if (ier == -1) { fprintf(stderr, "grow: UHOH at polygon %lld; continuing ...\n",polys[i]->id); // return(-1); // failed to partition polygon into desired number of parts } else if (ier == 1) { fprintf(stderr, "grow: failed to partition polygon %lld fully; partitioned it into %d parts\n", (*poly)->id, dn + 1); } *np+=dn; // check whether exceeded maximum number of polygons //printf("(2) n = %d\n", n); if (*np > npolys) { fprintf(stderr, "grow: total number of polygons exceeded maximum\n"); fprintf(stderr, "if you need more space, enlarge NPOLYSMAX in defines.h, and recompile\n"); return(-1); } for(i=-1; i<*np; i++){ if(i=-1) poly1=(*poly); else poly1=polys[i]; for (ip = 0; ip < poly1->np; ip++) { cmi=poly1->cm[ip]; //convert cm into an angle s = sqrtl(fabsl(cmi) / 2.); if (s > 1.) s = 1.; theta = 2. * asinl(s); theta=(cmi >= 0.)? theta : -theta; theta_new=theta+grow_angle; // if growing angle has caused cap to encompass whole sphere, set cm_new=2 to make it superfluous if(theta>=0 && theta_new>=PI) cm_new=2.; else if(theta<0 && theta_new>=0) cm_new=2.; // if growing angle (with a negative value for grow_angle) has shrunk cap to less than nothing, make polygon null else if(theta>=0 && theta_new<0) cm_new=0.; else if(theta<0 && theta_new<=-PI) cm_new=0.; // otherwise convert normally else{ /* 1 - cosl(radius) = 2 sin^2(radius/2) */ s = sinl(theta_new / 2.); cm_new = s * s * 2.; cm_new = (theta_new >= 0.)? cm_new : -cm_new; } poly1->cm[ip]=cm_new; } tol=mtol; iret=prune_poly(poly1,tol); } return(iret); }