Example #1
0
/*------------------------------------------------------------------------------
  Remove all superfluous caps from polygon.

  If all you want to do is to stop garea, gspher et al from complaining,
  then use trim_poly(), not prune_poly().

  After suppressing obviously superfluous caps with trim_poly(),
  which makes garea et al happy, prune_poly applies garea to detect whether
  there are any redundant caps enclosing the entire polygon, in which case it
  removes those caps, in addition to removing caps suppressed by trim_poly().

  Null polygons are replaced with a single null cap.
  Note that a polygon with no caps is the whole sphere, not a null polygon.

   Input: poly is a pointer to a polygon.
	  mtol = initial angular tolerance in radians
		 within which to merge multiple intersections.
  Output: poly with all superfluous caps removed;
	  the number of caps is changed.
  Return value: -1 if error;
		0 if nothing changed;
		1 if something changed;
		2 if nothing changed, and polygon is null;
		3 if polygon was changed to null polygon.
*/
int prune_poly(polygon *poly, double mtol)
{
    int i, ier, ip, iret, jp, verb;
    double area, area_tot, cm, tol;

    /* first cut */
    iret = trim_poly(poly);

    /* trim_poly detected null polygon */
    if (iret >= 2) return(iret);

    /* area of intersection */
    tol = mtol;
    verb = 1;
    ier = garea(poly, &tol, verb, &area_tot);
    if (ier) return(-1);

    /* null polygon */
    if (area_tot == 0.) {
	poly->rp[0][0] = 0.;
	poly->rp[0][1] = 0.;
	poly->rp[0][2] = 1.;
	poly->cm[0] = 0.;
	poly->np = 1;
	return(3);
    }

    /* test whether suppressing cap changes area or not */
    verb = 0;
    for (ip = 0; ip < poly->np; ip++) {
	if (poly->cm[ip] >= 2.) continue;	/* cap is already superfluous */
	cm = poly->cm[ip];			/* save latitude */
	poly->cm[ip] = 2.;			/* suppress cap */
	tol = mtol;
	ier = garea(poly, &tol, verb, &area);	/* area sans cap */
	if (ier == -1) return(-1);
	if (ier || area != area_tot) {		/* cap affects area */
	    poly->cm[ip] = cm;			/* so restore cap */
	}
    }

    /* remove superfluous caps */
    ip = 0;
    for (jp = 0; jp < poly->np; jp++) {
	/* copy down cap */
	if (poly->cm[jp] < 2.) {
	    for (i = 0; i < 3; i++) {
		poly->rp[ip][i] = poly->rp[jp][i];
	    }
	    poly->cm[ip] = poly->cm[jp];
	    ip++;
	/* skip superfluous cap */
	} else {
	    iret = 1;
	}
    }
    poly->np = ip;

    return(iret);
}
Example #2
0
/*------------------------------------------------------------------------------
  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);
}
Example #3
0
/*------------------------------------------------------------------------------
  Partition a polygon by lassoing its connected boundaries with circles.

  Normally the input polygon poly would be a group polygon,
  all of whose connected boundaries belong to a single group.
  If the boundaries of the input polygon belong to more than one group,
  then the polygon is not simply-connected, and each non-simply-connected part
  of the polygon will contain two or more boundaries.
  The algorithm will attempt to lasso all these boundaries, even though
  lassoing boundaries of a non-simply-connected part of the polygon
  cannot partition the polygon.

  The routine attempts to lasso all the connected boundaries of a polygon,
  unless the polygon has only a single connected boundary.
  If the polygon has a single connected boundary, then
  the all_oneboundary option controls whether or not this boundary is lassoed.

  An attempted lasso is discarded if it lies fully inside or fully outside
  all the caps of the polygon.  It would be incorrect to retain a lasso
  that lies fully inside the polygon, and it would be superfluous to retain
  a lasso that fully encloses the polygon.
  In the normal case where the input polygon is a group polygon,
  a lasso can lie fully inside or outside the caps of the group polygon
  if the group polygon has a single connected boundary.

  If the input polygon has two or more connected boundaries none of which
  can be lassoed, then the force_split option controls whether the
  routine gives up, or else forcibly splits the input polygon into two parts,
  each of which will require further splitting.

   Input: poly is a polygon.
	  npolys = maximum number of polygons available in polys array.
	  mtol = initial angular tolerance within which to merge multiple intersections.
	  all_oneboundary = 2 to lasso all one-boundary polygons,
			    1 to lasso only those one-boundary polygons
			      with more caps than vertices,
			    0 never to lasso one-boundary polygons;
			    in all cases, all multi-boundary polygons are lassoed.
	  adjust_lasso = how to tighten lasso:
		       = 0 as tight as possible,
			 1 for balkanize,
			 2 for ransack.
	  force_split = 1 to force a polygon to be split
			  even if no boundary can be lassoed;
			0 otherwise.
  Output: polys[i], i = 0 to npoly-1, are the connected parts of poly;
              if return value = 0, then:
		  if *npoly = *npoly_try = 0, then:
		      input poly already consists of a single connected part
		      that needs no partitioning;
		  if *npoly = *npoly_try > 0, then:
		      poly was fully partitioned into its parts;
		  if *npoly < *npoly_try then:
		      poly was partially partitioned,
		      and poly[npoly - 1] contains the parts of poly
		      that were not partitioned successfully;
	      if return value = 1,
		    which can occur only if force_split = 1, then:
		    poly contains at least 2 connected boundaries,
		    none of which could be lassoed successfully,
		    and instead poly was split forcibly into two,
		    with the two parts in polys[0] and polys[1].
	  *npoly = number of polygons in polys;
		   if *npoly > npolys, then there was not enough space.
	  *npoly_try = attempted number of polygons.
  Return value: -1 if error occurred;
		 0 for a normal return;
		 1 if poly was split forcibly when no boundary could be lassoed;
		   can only occur if force_split = 1.
*/
int part_poly(polygon *poly, int npolys, polygon *polys[/*npolys*/], long double mtol, int all_oneboundary, int adjust_lasso, int force_split, int *npoly, int *npoly_try)
{
    /* number of extra caps to allocate to polygon, to allow for expansion */
#define DNP		4
    static polygon *extracap = 0x0;
    const int do_vcirc = 1;
    const int per = 0;
    const int nve = 2;
    const int itmax = 30;
    int dnp, found, i, ier, iev, ip, it, iv, ivm, ivmax_that, ivmax_this, ivmin_that, ivmin_this, nev, nev0, np, nret, nv, nvm;
    int *ipv, *gp, *ev;
    long double *angle;
    vec *ve, *vm;
    long double *cmvmin, *cmvmax, *cmpmin, *cmpmax;
    vec *vmax, *vmin;
    long double cmbest, cme, cmforce, dth, dthbest, dthforce, dthm, dthp, s, th, thm, tol;
    long double cmpmax_all, cmpmin_all, cmvmax_that, cmvmax_this, cmvmin_that, cmvmin_this, thmax_that, thmax_this, thmin_that, thmin_this;
    vec v, vmbest, vmforce;

    /* initialize return value to normal */
    nret = 0;

    /* initialize number of polygon parts in polys to zero */
    *npoly = 0;

    /* initialize attempted number of polygon parts to zero */
    *npoly_try = 0;

    /* vertices and centres of edges of polygon */
    tol = mtol;
    ier = gverts(poly, do_vcirc, &tol, per, nve, &nv, &ve, &angle, &ipv, &gp, &nev, &nev0, &ev);
    if (ier) return(-1);

    /* no boundaries */
    if (nev == 0) return(nret);

    /* polygon has just 1 connected boundary */
    if (nev == 1) {
        if (all_oneboundary == 0) {
            return(nret);
        } else if (all_oneboundary == 1) {
            /* polygon has not too many caps */
            if (poly->np <= nv + 1) return(nret);
        }
    }

    /* barycentres of connected boundaries of polygon */
    ier = vmidc(poly, nv, nve, ve, ipv, ev, &nvm, &vm);
    if (ier == -1) return(-1);

    /* number of polygons to try to split into */
    *npoly_try = nvm;

    /* initialize lasso to be used to force split */
    if (force_split) dthforce = -4.;

    /* attempt to partition polygon around each barycentre vm[ivm] */
    for (ivm = 0; ivm < nvm; ivm++) {

        /* initialize best lasso so far */
        if (force_split) dthbest = -4.;

        /* repeat until find isolating lasso */
        it = 0;
        do {

            /* points on each edge nearest to and farthest from vm[ivm] */
            ier = gvlims(poly, do_vcirc, &tol, vm[ivm], &nv, &vmin, &vmax, &cmvmin, &cmvmax, &cmpmin, &cmpmax, &ipv, &gp, &nev, &nev0, &ev);
            if (ier == -1) return(-1);
            if (ier) break;

            /* distances that exclude/enclose all circles */
            cmpmin_all = 2.;
            cmpmax_all = 0.;
            for (ip = 0; ip < poly->np; ip++) {
                if (cmpmin[ip] <= cmpmin_all) {
                    cmpmin_all = cmpmin[ip];
                }
                if (cmpmax[ip] >= cmpmax_all) {
                    cmpmax_all = cmpmax[ip];
                }
            }

            /* distances that exclude/enclose this connected boundary */
            ivmax_this = -1;
            ivmin_this = -1;
            cmvmin_this = 2.;
            cmvmax_this = 0.;
            for (iv = (ivm == 0)? 0 : ev[ivm - 1]; iv < ev[ivm]; iv++) {
                if (cmvmin[iv] <= cmvmin_this) {
                    ivmin_this = iv;
                    cmvmin_this = cmvmin[iv];
                }
                if (cmvmax[iv] >= cmvmax_this) {
                    ivmax_this = iv;
                    cmvmax_this = cmvmax[iv];
                }
            }

            /* distances that exclude/enclose other connected boundaries */
            ivmin_that = -1;
            ivmax_that = -1;
            cmvmin_that = 2.;
            cmvmax_that = 0.;
            for (iev = 0; iev < nev; iev++) {
                if (iev == ivm) continue;
                for (iv = (iev == 0)? 0 : ev[iev - 1]; iv < ev[iev]; iv++) {
                    if (cmvmin[iv] <= cmvmin_that) {
                        ivmin_that = iv;
                        cmvmin_that = cmvmin[iv];
                    }
                    if (cmvmax[iv] >= cmvmax_that) {
                        ivmax_that = iv;
                        cmvmax_that = cmvmax[iv];
                    }
                }
            }

            /* angles corresponding to cmmin_this, cmvmax_this, cmvmin_that, and cmvmax_that */
            thmin_this = 2. * asinl(sqrtl(cmvmin_this / 2.));
            thmax_this = 2. * asinl(sqrtl(cmvmax_this / 2.));
            thmin_that = 2. * asinl(sqrtl(cmvmin_that / 2.));
            thmax_that = 2. * asinl(sqrtl(cmvmax_that / 2.));

            dthp = thmin_that - thmax_this;
            dthm = thmin_this - thmax_that;

            dth = (dthp >= dthm)? dthp : dthm;

            /* found lasso that isolates this connected boundary of polygon */
            if (dth >= - tol) {

                /* if (it >= 10) printf("%21.15Lg %21.15Lg %21.15Lg %4d %2d%21.15Lg %21.15Lg %21.15Lg %21.15Lg %21.15Lg %21.15Lg\n", vm[ivm][0], vm[ivm][1], vm[ivm][2], ivm, it, thmin_this, thmax_this, thmin_that, thmax_that, dthp, dthm); */

                /* thmin_that >= thmax_this - tol */
                if (dthp >= dthm) {
                    /* isolating lasso */
                    th = (thmax_this + thmin_that) / 2.;
                    switch (adjust_lasso) {
                    /* as tight as possible */
                    case 0:
                        thm = thmax_this;
                        break;
                    /* for balkanize: tiny angles give garea problems */
                    case 1:
                        thm = thmax_this + .001;
                        break;
                    /* for ransack: want tight lasso */
                    case 2:
                        thm = thmax_this * 1.05;
                        break;
                    }
                    /* tighten lasso */
                    if (th > thm) th = thm;
                    if (th < PI) {
                        s = sinl(th / 2.);
                        cme = 2. * s * s;
                    } else {
                        cme = 2.;
                    }

                    /* discard lasso that completely encloses all circles */
                    if (cme >= cmpmax_all) {
                        /* printf("%21.15Lg %21.15Lg %21.15Lg %21.15Lg\n", vm[ivm][0], vm[ivm][1], vm[ivm][2], cme); */
                        /* decrement number of polygons to try for */
                        (*npoly_try)--;
                        /* break out of search loop */
                        break;
                    }

                    /* thmin_this >= thmax_that - tol */
                } else {
                    /* isolating lasso */
                    th = (thmax_that + thmin_this) / 2.;
                    switch (adjust_lasso) {
                    /* as tight as possible */
                    case 0:
                        thm = thmin_this;
                        break;
                    /* for balkanize: tiny angles give garea problems */
                    case 1:
                        thm = thmin_this - .001;
                        break;
                    /* for ransack: want tight lasso */
                    case 2:
                        thm = thmin_this / 1.05;
                        break;
                    }
                    /* tighten lasso */
                    if (th < thm) th = thm;
                    if (th > 0.) {
                        s = sinl(th / 2.);
                        cme = 2. * s * s;
                    } else {
                        cme = 0.;
                    }

                    /* discard lasso that completely encloses all circles */
                    if (cme <= cmpmin_all) {
                        /* printf("%21.15Lg %21.15Lg %21.15Lg %21.15Lg\n", vm[ivm][0], vm[ivm][1], vm[ivm][2], cme); */
                        /* decrement number of polygons to try for */
                        (*npoly_try)--;
                        /* break out of search loop */
                        break;
                    }

                    cme = - cme;

                }

                /* not enough polygons for a new one */
                if (*npoly >= npolys) {
                    (*npoly)++;
                    return(0);
                }

                /* put isolating lasso into new polygon */
                np = 1;
                dnp = DNP;
                ier = room_poly(&extracap, np, dnp, 0);
                if (ier == -1) goto out_of_memory;
                for (i = 0; i < 3; i++) {
                    extracap->rp[0][i] = vm[ivm][i];
                }

                extracap->cm[0] = cme;
                extracap->np = 1;

                /* make sure new polygon contains enough space */
                np = poly->np + 1;
                dnp = 0;
                ier = room_poly(&polys[*npoly], np, dnp, 0);
                if (ier == -1) goto out_of_memory;

                /* combination of poly with new circle */
                poly_poly(poly, extracap, polys[*npoly]);

                /* increment number of polygons */
                (*npoly)++;

                /* flag found isolating boundary */
                found = 1;

                /* failed to find isolating lasso */
            } else {

                dthp = thmin_that - thmin_this;
                dthm = thmax_this - thmax_that;

                if (dthp >= dthm) {
                    /* paranoid check that ivmax_this and ivmin_that were initialized */
                    if (ivmax_this == -1 || ivmin_that == -1) {
                        /* error should never happen */
                        fprintf(stderr, "partition_poly: ivmax_this = %d ivmin_that = %d should be in interval [0, %d]\n", ivmax_this, ivmin_that, nv);
                        return(-1);
                    }

                    /* record the best lasso so far */
                    if (force_split) {
                        if (dthp > dthbest) {
                            dthbest = dthp;
                            /* circle that does not enclose connected boundary,
                               but does exclude other connected boundaries */
                            th = (thmin_this + thmin_that) / 2.;
                            thm = thmin_that * .999;
                            if (th < thm) th = thm;
                            s = sinl(th / 2.);
                            cmbest = 2. * s * s;
                            for (i = 0; i < 3; i++) {
                                vmbest[i] = vm[ivm][i];
                            }
                        }
                    }

                    /* vector to this from that */
                    for (i = 0; i < 3; i++) {
                        v[i] = vmax[ivmax_this][i] - vmin[ivmin_that][i];
                    }
                    s = v[0] * v[0] + v[1] * v[1] + v[2] * v[2];
                    /* translate centre point along vector */
                    /* the 0.02 puts centre just beyond equal distance */
                    for (i = 0; i < 3; i++) {
                        v[i] = vm[ivm][i] + ((cmvmax_this - cmvmin_that) / s + 0.02 * (it + 1)) * v[i];
                    }
                    s = sqrtl(v[0] * v[0] + v[1] * v[1] + v[2] * v[2]);
                    for (i = 0; i < 3; i++) {
                        vm[ivm][i] = v[i] / s;
                    }

                } else {
                    /* paranoid check that ivmin_this and ivmax_that were initialized */
                    if (ivmin_this == -1 || ivmax_that == -1) {
                        /* error should never happen */
                        fprintf(stderr, "partition_poly: ivmin_this = %d ivmax_that = %d should be in interval [0, %d]\n", ivmin_this, ivmax_that, nv);
                        return(-1);
                    }

                    /* record the best lasso so far */
                    if (force_split) {
                        if (dthm > dthbest) {
                            dthbest = dthm;
                            /* circle that does not enclose connected boundary,
                               but does exclude other connected boundaries */
                            th = PI - (thmax_this + thmax_that) / 2.;
                            thm = (PI - thmax_that) * .999;
                            if (th < thm) th = thm;
                            s = cosl(th / 2.);
                            cmbest = - 2. * s * s;
                            for (i = 0; i < 3; i++) {
                                vmbest[i] = vm[ivm][i];
                            }
                        }
                    }

                    /* vector to that from this */
                    for (i = 0; i < 3; i++) {
                        v[i] = vmax[ivmax_that][i] - vmin[ivmin_this][i];
                    }
                    s = v[0] * v[0] + v[1] * v[1] + v[2] * v[2];
                    /* translate centre point along vector */
                    /* the 0.02 puts centre just beyond equal distance */
                    for (i = 0; i < 3; i++) {
                        v[i] = vm[ivm][i] + ((cmvmax_that - cmvmin_this) / s + 0.02 * (it + 1)) * v[i];
                    }
                    s = sqrtl(v[0] * v[0] + v[1] * v[1] + v[2] * v[2]);
                    for (i = 0; i < 3; i++) {
                        vm[ivm][i] = v[i] / s;
                    }

                }

                /* flag failed to find isolating boundary */
                found = 0;

            }

        } while (!found && it++ < itmax);

        /* record the best lasso so far */
        if (force_split && !found) {
            if (dthbest > dthforce) {
                dthforce = dthbest;
                cmforce = cmbest;
                for (i = 0; i < 3; i++) {
                    vmforce[i] = vmbest[i];
                }
            }
        }

    }

    /* no polygons were lassoed */
    if (*npoly == 0) {

        /* go with original polygon */
        if (*npoly_try <= 1) {
            *npoly_try = 0;
            return(nret);
        }

        /* split polygon along best circle so far, even though it is not a lasso */
        if (force_split) {
            /* not enough polygons for a new one */
            if (*npoly >= npolys) {
                (*npoly)++;
                return(0);
            }

            /* put circle into new polygon */
            np = 1;
            dnp = DNP;
            ier = room_poly(&extracap, np, dnp, 0);
            if (ier == -1) goto out_of_memory;
            for (i = 0; i < 3; i++) {
                extracap->rp[0][i] = vmforce[i];
            }
            extracap->cm[0] = cmforce;
            extracap->np = 1;

            /* make sure new polygon contains enough space */
            np = poly->np + 1;
            dnp = 0;
            ier = room_poly(&polys[*npoly], np, dnp, 0);
            if (ier == -1) goto out_of_memory;

            /* combination of polygon with new circle */
            poly_poly(poly, extracap, polys[*npoly]);

            /* increment number of polygons */
            (*npoly)++;

            /* flag that split was forced */
            nret = 1;
        }

    }

    /* if some polygons were lassoed and others not, add complement of all new caps to polygon */
    if (*npoly > 0 && *npoly < *npoly_try) {
        /* not enough polygons for a new one */
        if (*npoly >= npolys) {
            (*npoly)++;
            return(0);
        }

        /* put complement of all new caps into new polygon */
        np = *npoly;
        dnp = DNP;
        ier = room_poly(&extracap, np, dnp, 0);
        if (ier == -1) goto out_of_memory;
        for (np = 0; np < *npoly; np++) {
            ip = polys[np]->np - 1;
            for (i = 0; i < 3; i++) {
                extracap->rp[np][i] = polys[np]->rp[ip][i];
            }
            extracap->cm[np] = - polys[np]->cm[ip];
        }
        extracap->np = *npoly;

        /* make sure new polygon contains enough space */
        np = poly->np + *npoly;
        dnp = 0;
        ier = room_poly(&polys[*npoly], np, dnp, 0);
        if (ier == -1) goto out_of_memory;

        /* poly with complement of new caps from other polygons */
        poly_poly(poly, extracap, polys[*npoly]);

        /* increment number of polygons */
        (*npoly)++;
    }

    /* trim new polygons to suppress obviously coincident caps */
    for (ip = 0; ip < *npoly; ip++) {
        trim_poly(polys[ip]);
    }

    return(nret);

    /* ---------------- error returns ---------------- */
out_of_memory:
    fprintf(stderr, "part_poly: failed to allocate memory for polygon of %d caps\n", np + dnp);
    return(-1);
}
Example #4
0
File: snap.c Project: MCTwo/DEIMOS
/*------------------------------------------------------------------------------
  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);
}
Example #5
0
int rasterize(int nhealpix_poly, int npoly, polygon *polys[/*npoly*/], int nweights, long double weights[/*nweights*/])
{
  int min_pixel, max_pixel, ier, ier_h, ier_i, i, j, ipix, ipoly, begin_r, end_r, begin_m, end_m, verb, np, iprune;
  int *start_r, *start_m, *total_r, *total_m;
  long double *areas, area_h, area_i, tol;

  static polygon *polyint = 0x0;

  /* make sure weights are all zero for rasterizer pixels */
  for (i = 0; i < nhealpix_poly; i++) {
      polys[i]->weight = 0.;
  }

  /* allocate memory for rasterizer areas array */
  areas = (long double *) malloc(sizeof(long double) * (nweights));
  if (!areas) {
    fprintf(stderr, "rasterize: failed to allocate memory for %d long doubles\n", nweights);
    exit(1);
  }

  /* initialize rasterizer areas array to 0 */
  for (i = 0; i < nweights; i++) areas[i] = 0.;

  /* allow error messages from garea */
  verb = 1;

  /* find areas of rasterizer pixels for later use */
  for (i = 1; i <= nweights; i++) {
    for (j = 0; j < nhealpix_poly; j++) {
      if (polys[j]->id == i) {
        tol = mtol;
        ier_h = garea(polys[j], &tol, verb, &area_h);
        if (ier_h == 1) {
          fprintf(stderr, "fatal error in garea\n");
          exit(1);
        }
        if (ier_h == -1) {
          fprintf(stderr, "failed to allocate memory in garea\n");
          exit(1);
        }
        areas[i-1] += area_h;
      }
    }
  }

  /* sort arrays by pixel number */
  poly_sort(nhealpix_poly, polys, 'p');
  poly_sort(npoly-nhealpix_poly, &(polys[nhealpix_poly]), 'p');

  /* allocate memory for pixel info arrays start_r, start_m, total_r, and total_m */
  min_pixel = polys[0]->pixel;
  max_pixel = (polys[nhealpix_poly-1]->pixel+1>polys[npoly-1]->pixel+1)?(polys[nhealpix_poly-1]->pixel+1):(polys[npoly-1]->pixel+1);
  start_r = (int *) malloc(sizeof(int) * max_pixel);
  if (!start_r) {
    fprintf(stderr, "rasterize: failed to allocate memory for %d integers\n", max_pixel);
    return(-1);
  }
  start_m = (int *) malloc(sizeof(int) * max_pixel);
  if (!start_m) {
    fprintf(stderr, "rasterize: failed to allocate memory for %d integers\n", max_pixel);
    return(-1);
  }
  total_r = (int *) malloc(sizeof(int) * max_pixel);
  if (!total_r) {
    fprintf(stderr, "rasterize: failed to allocate memory for %d integers\n", max_pixel);
    return(-1);
  }
  total_m = (int *) malloc(sizeof(int) * max_pixel);
  if (!total_m) {
    fprintf(stderr, "rasterize: 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(nhealpix_poly, polys, max_pixel, start_r, total_r);
  if (ier == -1) {
    fprintf(stderr, "rasterize: error building pixel index lists for rasterizer polygons\n");
    return(-1);
  }

  ier = pixel_list(npoly-nhealpix_poly, &(polys[nhealpix_poly]), max_pixel, start_m, total_m);
  if (ier == -1) {
    fprintf(stderr, "rasterize: error building pixel index lists for input mask polygons\n");
    return(-1);
  }

  /* correction due to the start_m array's offset */
  for (i = min_pixel; i < max_pixel; i++) {
    start_m[i] += nhealpix_poly;
  }

  /* compute intersection of each input mask polygon with each rasterizer polygon */
  for (ipix = min_pixel; ipix < max_pixel; ipix++) {
    begin_r = start_r[ipix];
    end_r = start_r[ipix] + total_r[ipix];
    begin_m = start_m[ipix];
    end_m = start_m[ipix] + total_m[ipix];

    for (ipoly = begin_m; ipoly < end_m; ipoly++) {
      /* disregard any null polygons */
      if (!polys[ipoly]) continue;

      for (i = begin_r; i < end_r; i++) {

	/* make sure polyint contains enough space for intersection */
	np = polys[ipoly]->np + polys[i]->np;
	ier = room_poly(&polyint, np, DNP, 0);
	if (ier == -1) goto out_of_memory;

	poly_poly(polys[ipoly], polys[i], polyint);

	/* suppress coincident boundaries, to make garea happy */
	iprune = trim_poly(polyint);

	/* intersection of polys[ipoly] and polys[i] is null polygon */
	if (iprune >= 2) area_i = 0.;

	else {
	  tol = mtol;
	  ier_i = garea(polyint, &tol, verb, &area_i);
	  if (ier_i == 1) {
	    fprintf(stderr, "fatal error in garea\n");
	    return(-1);
	  }
	  if (ier_i == -1) {
	    fprintf(stderr, "failed to allocate memory in garea\n");
	    return(-1);
	  }
	}
	    
	weights[(polys[i]->id)-1] += (area_i)*(polys[ipoly]->weight);
      }
    }
  }

  for (i=0; i<nweights; i++) {
    if(areas[i]!=0){
      weights[i] = weights[i]/areas[i];
    }
    else{
      weights[i]=0;
      fprintf(stderr,"WARNING: rasterize: area of rasterizer polygon %d is zero.  Assigning zero weight.\n",i);
    }
  }

  return(i+1);

  /* ----- error return ----- */
  out_of_memory:
  fprintf(stderr, "rasterize: failed to allocate memory for polygon of %d caps\n", np + DNP);
  return(-1);

}
Example #6
0
/*------------------------------------------------------------------------------
  Make almost coincident caps of polygons coincide.

  Input:  fmt = pointer to format structure.
	  npoly = number of polygons to snap.
	  *poly[npoly] = array of npoly pointers to polygon structures.
	  selfsnap = 0 to snap edges of all polygons against each other,
		     1 to snap edges of polygons only against edges of same polygon.
	  axtol = angle in radians [actually 2 sin(angle/2)]:
		  if angle twixt polar axes of caps <= axtol,
		  then make axis of poly2 cap
		  exactly parallel to axis of poly1 cap.
	  btol = angle in radians:
		 if two axes of caps of poly1 and poly2 are parallel,
		 and if angle between latitudes of caps <= btol,
		 then make latitude of poly2 cap
		 exactly equal to latitude of poly1 cap.
	  thtol = edge tolerance in radians.
	  ytol = edge to length tolerance;
		 if the two vertices and centre point of an edge of poly2 are
		 all closer to a boundary of poly1 than the lesser of
		 (1) thtol, and
		 (2) ytol times the length of the edge,
		 and if in addition at least one of the three points lies
		 inside poly1 (sans said boundary),
		 then make boundary of the poly2 cap equal to that of poly1.
	  mtol = initial tolerance angle for multiple intersections in radians.
	  warnmax = number of times to advise about individual polygon edges being snapped.
  Output: adjusted caps of poly2 (i.e. poly2->rp, poly2->cm).
	  snapped_poly = array of 0 or 1 flagging which polygons were snapped.
			 set to 0x0 on input to ignore.
  Return value: number of caps adjusted.
*/
int snap_polys(format *fmt, int npoly, polygon *poly[/*npoly*/], int selfsnap, double axtol, double btol, double thtol, double ytol, double mtol, int warnmax, char snapped_poly[/*npoly*/])
{
    int dnadj, dnadjo, i, j, nadj, pass, snapped, stuck, warn;

    /* initialize snapped polygon flag to zero */
    if (snapped_poly) {
	for (i = 0; i < npoly; i++) snapped_poly[i] = 0;
    }

    nadj = 0;

    /* snap repeatedly, until no more caps snap together */
    pass = 0;
    stuck = 0;
    dnadj = 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; ((selfsnap)? j == i : j < npoly); j++) {
		    snapped = snap_poly(poly[i], poly[j], axtol, btol);
		    if (snapped) {
			if (warnmax) {
			    if (warn == 0)
				msg("snap_polys stage 1 pass %d: caps of the following polygons were snapped together:\n", pass);
			    if (warn < warnmax) {
				if (selfsnap) {
				    msg(" %d", (fmt->newid == 'o')? poly[i]->id : i);
				} else {
				    msg(" (%d %d)", (fmt->newid == 'o')? poly[i]->id : i, (fmt->newid == 'o')? poly[j]->id : j);
				}
			    } else if (warn == warnmax) {
				msg(" ... more\n");
			    }
			}
			if (snapped_poly) {
			    snapped_poly[i] = 1;
			    snapped_poly[j] = 1;
			}
			dnadj += snapped;
			warn++;
		    }
		}
	    }
	}
	if (warnmax > 0 && warn > 0 && warn <= warnmax) msg("\n");
	nadj += dnadj;
	if ((nadj > 0 || !selfsnap) && warnmax) msg("snap_polys stage 1 (axes, latitudes) pass %d: %d caps adjusted\n", pass, dnadj);
	/* avoid infinite loop */
	if (pass > 1 && dnadj >= dnadjo) stuck++;
    } while (dnadj && stuck < 2);
    if (dnadj) {
      if(poly[0]->pixel==0){
	fprintf(stderr, "snap_polys: seem to be stuck in a loop ... exit\n");
      }
      else{
	fprintf(stderr, "snap_polys stage 1: stuck in a loop in pixel %d. continuing ...\n",poly[0]->pixel);
      }
    }

    /* trim polygons */
    for (i = 0; i < npoly; i++) {
	trim_poly(poly[i]);
    }

    /* snap repeatedly, until no more caps snap together */
    pass = 0;
    stuck = 0;
    dnadj = 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 = ((selfsnap)? i : 0); ((selfsnap)? j == i : j < npoly); j++) {
		  snapped = snap_polyth(poly[i], poly[j], thtol, ytol, mtol);
		  if (snapped) {
			if (warnmax > 0) {
			    if (warn == 0)
				msg("snap_polys stage 2 pass %d: caps of the following polygons were snapped together:\n", pass);
			    if (warn < warnmax) {
				if (selfsnap) {
				    msg(" %d", (fmt->newid == 'o')? poly[i]->id : i);
				} else {
				    msg(" (%d %d)", (fmt->newid == 'o')? poly[i]->id : i, (fmt->newid == 'o')? poly[j]->id : j);
				}
			    } else if (warn == warnmax) {
				msg(" ... more\n");
			    }
			}
			if (snapped_poly) {
			    snapped_poly[i] = 1;
			    snapped_poly[j] = 1;
			}
			dnadj += snapped;
			warn++;
		    }
		}
	    }
	}
	if (warnmax > 0 && warn > 0 && warn <= warnmax) msg("\n");
	nadj += dnadj;
	if ((nadj > 0 || !selfsnap) && warnmax) msg("snap_polys stage 2 (edges) pass %d: %d caps adjusted\n", pass, dnadj);
	/* avoid infinite loop */
	if (pass > 1 && dnadj >= dnadjo) stuck++;
    } while (dnadj && stuck < 2);
    if (dnadj) {
      if(poly[0]->pixel==0){
	fprintf(stderr, "snap_polys: seem to be stuck in a loop ... exit\n");
      }
      else{
	fprintf(stderr, "snap_polys stage 2: stuck in a loop in pixel %d. continuing ...\n",poly[0]->pixel);
      }
    }
    return(nadj);
}
Example #7
0
/*------------------------------------------------------------------------------
  Snap edge of poly2 to cap boundary of poly1.
  Caps of poly2 are adjusted to equal those of poly1.

  Input:  poly1, poly2 = pointers to polygon structures.
	  thtol = edge tolerance in radians.
	  ytol = edge to length tolerance;
		 if the two vertices and centre point of an edge of poly2 are
		 all closer to a boundary of poly1 than the lesser of
		 (1) thtol, and
		 (2) ytol times the length of the edge,
		 and if in addition at least one of the three points lies
		 inside poly1 (sans said boundary),
		 then make boundary of the poly2 cap equal to that of poly1.
	  mtol = initial tolerance angle for multiple intersections in radians.
  Output: adjusted caps of poly2 (i.e. poly2->rp, poly2->cm).
  Return value: number of caps adjusted,
		or -1 if error occurred.
*/
int snap_polyth(polygon *poly1, polygon *poly2, double thtol, double ytol, double mtol)
{
    const int per = 0;
    const int nve = 2;

    int adjusted, do_vcirc, i, ier, in, ip1, ip2, iv, ivp, nadj, nev, nev0, nv;
    int *ipv, *gp, *ev;
    double cm, cm1, dth, dthmax, sp, tol;
    double *angle;
    vec *v, *ve;
        
    // vertices and centres of edges of poly2 
    do_vcirc = 0;
    tol = mtol;
    ier = gverts(poly2, do_vcirc, &tol, per, nve, &nv, &ve, &angle, &ipv, &gp, &nev, &nev0, &ev);
    if (ier != 0) return(-1);

    // convert angle of each edge to scalar length angle * sin(theta)
    for (iv = 0; iv < nv; iv++) {
	ip2 = ipv[iv];
	cm = fabs(poly2->cm[ip2]);
	angle[iv] = angle[iv] * sqrt(cm * (2. - cm));
    }

    nadj = 0;
    
    // for each edge of poly2 ... 
    for (iv = 0; iv < nv; iv++) {
	ivp = (iv + 1) % nv;
	ip2 = ipv[iv];
	
	// ... and each axis of poly1
	for (ip1 = 0; ip1 < poly1->np; ip1++) {
	    adjusted = 0;

	    // distance from edge of poly2 to cap of poly1
	    cm1 = poly1->cm[ip1];
            poly1->cm[ip1] = 2.;        // suppress cap of poly1
	    in = 0;
	    dthmax = 0.;
	    
	    for (i = 0; i < 3; i++) {
	      // vertex, centre point, vertex of edge of poly2
	      v = &ve[(iv * nve + i) % (nv * nve)];  //doesn't segfault without this line
	      in |= gptin(poly1, *v);	// in if any one point is in  doesn't segfault without this line
	      cm = cmij(*v, poly1->rp[ip1]); // doesn't segfault without this line
	      dth = 2. * (sqrt(cm/2.) - sqrt(fabs(cm1/2.)));
	      dth = fabs(dth);	// angle from point to cap of poly1
	      if (dth > dthmax) dthmax = dth;
	    }
            poly1->cm[ip1] = cm1;       // restore cap of poly1
	    
	      
	    // three points of poly2 edge are all close to boundary of poly1
	    
	    if (in && dthmax <= thtol && dthmax <= ytol * angle[iv]) {
	      sp = poly1->rp[ip1][0] * poly2->rp[ip2][0] + poly1->rp[ip1][1] * poly2->rp[ip2][1] + poly1->rp[ip1][2] * poly2->rp[ip2][2];
	      sp = (sp >= 0.)? 1. : -1.;
	      if (!(poly2->rp[ip2][0] == poly1->rp[ip1][0]
		    && poly2->rp[ip2][1] == poly1->rp[ip1][1]
		    && poly2->rp[ip2][2] == poly1->rp[ip1][2])) {
		// make axis of poly2 cap exactly equal to that of poly1 
		poly2->rp[ip2][0] = poly1->rp[ip1][0];
		poly2->rp[ip2][1] = poly1->rp[ip1][1];
		poly2->rp[ip2][2] = poly1->rp[ip1][2];
		adjusted = 1;
	      }
	      // set latitude of poly2 cap equal to that of poly1 
	      cm = (poly2->cm[ip2] >= 0.)?
		sp * fabs(poly1->cm[ip1]):
		- sp * fabs(poly1->cm[ip1]);
	      if (poly2->cm[ip2] != cm) {
		poly2->cm[ip2] = cm;
		adjusted = 1;
	      }
	      if (adjusted) nadj++;
	    }
	    
	}
    }

    // trim adjusted polygon
    if (nadj > 0) trim_poly(poly2);
    
    return(nadj);
}