Esempio n. 1
0
/*------------------------------------------------------------------------------
  Determine whether the first vertex in vert
  is closer to the nearest vertex or to the nearest antivertex of poly.

  Return value: 0 or 1 as first vertex of vert is closer to the nearest
		       vertex or antivertex of poly;
		-1 if error.
*/
int antivert(vertices *vert, polygon *poly)
{
    const int do_vcirc = 0, nve = 1, per = 0;
    int anti, ier, iv, nev, nev0, nv;
    int *ipv, *gp, *ev;
    double cm, cmmax, cmmin, tol;
    double *angle;
    vec rp;
    vec *ve;

    /* vert has no vertices */
    if (vert->nv == 0) return(0);

    /* vertices of polygon */
    tol = mtol;
    ier = gverts(poly, do_vcirc, &tol, per, nve, &nv, &ve, &angle, &ipv, &gp, &nev, &nev0, &ev);

    /* error */
    if (ier) return(-1);

    /* poly has less than 3 vertices */
    if (nv < 3) return(0);

    /* convert first vertex to unit vector */
    azel_to_rp(&vert->v[0], rp);

    cmmin = 2.;
    cmmax = 0.;
    for (iv = 0; iv < nv; iv++) {
	cm = cmij(rp, ve[iv]);
	if (cm < cmmin) cmmin = cm;
	if (cm > cmmax) cmmax = cm;
    }
    anti = ((cmmin + cmmax <= 2.)? 0 : 1);

    return(anti);
}
Esempio n. 2
0
/*------------------------------------------------------------------------------
  Weight polygons.

   Input: poly = array of pointers to polygons.
	  npoly = pointer to number of polygons.
	  survey = name of survey, or of filename containing list of weights.
  Output: polys = array of pointers to polygons;
  Return value: number of polygons weighted,
		or -1 if error occurred.
*/
int weight(int npoly, polygon *poly[/*npoly*/], char *survey)
{
    const int per = 0;
    const int nve = 2;

    int do_vcirc, i, imid, ipoly, iverts, ivm, nev, nev0, nomid, nv, nvm, nzero;
    int *ipv, *gp, *ev;
    long double tol;
    long double *angle;
    vec *ve, *vm;
    azel v;

    nomid = 0;
    nzero = 0;
    for (ipoly = 0; ipoly < npoly; ipoly++) {
	/* vertices of polygon */
	do_vcirc = 0;
	tol = mtol;
	iverts = gverts(poly[ipoly], do_vcirc, &tol, per, nve, &nv, &ve, &angle, &ipv, &gp, &nev, &nev0, &ev);
	if (iverts != 0) return(-1);
	/* point somewhere in the middle of the polygon */
	imid = vmid(poly[ipoly], tol, nv, nve, ve, ipv, ev, &nvm, &vm);
	if (imid == -1) return(-1);
	/* check found a point inside the polygon */
	imid = 0;
	for (ivm = 0; ivm < nvm; ivm++) {
	    if (vm[ivm][0] != 0. || vm[ivm][1] != 0. || vm[ivm][2] != 0.) {
		imid = 1;
		if (ivm > 0) for (i = 0; i < 3; i++) vm[0][i] = vm[ivm][i];
		break;
	    }
	}
	/* found a point */
        if (imid == 1) {
	    /* convert unit vector to az, el */
	    rp_to_azel(*vm, &v);
	    /* scale angles from radians to degrees */
	    scale_azel(&v, 'r', 'd');
	    /* weight at that point */
	    poly[ipoly]->weight = weight_fn(v.az, v.el, survey);
	    if (poly[ipoly]->weight == 0.) nzero++;
	/* failed to find a point */
	} else {
	  //call weight_fn to stay in right place in weight file if reading from weights from a file
	    weight_fn(v.az, v.el, survey);
	    if (nomid == 0) msg("weight: failed to find interior point for the following polygons:\n");
	    msg(" %lld", (fmt.newid == 'n')? (long long)ipoly+fmt.idstart : poly[ipoly]->id);
	    nomid++;
	}
    }
    if (nomid > 0) msg("\n");
    if (nomid > 0) {
	msg("weight: failed to find interior point for %d polygons\n", nomid);
        msg("FAILURE TO FIND INTERIOR POINT PROBABLY MEANS YOU HAVE A WEIRD-SHAPED POLYGON.\n");
	msg("PLEASE FILL IN THE CORRECT WEIGHT BY HAND.\n");
    }

    /* assign new polygon id numbers in place of inherited ids */
    if (fmt.newid == 'n') {
	for (ipoly = 0; ipoly < npoly; ipoly++) {
	  poly[ipoly]->id = (long long)ipoly+fmt.idstart;
	}
    }

    if (fmt.newid == 'p') {
      for (ipoly = 0; ipoly < npoly; ipoly++) {
	poly[ipoly]->id = (long long)poly[ipoly]->pixel;
      }
    }

    /* warn about zero weights */
    if (nzero > 0) msg("weight: %d polygons have zero weight\n", nzero);

    return(npoly);
}
Esempio n. 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);
}
Esempio n. 4
0
/*------------------------------------------------------------------------------
  Partition disconnected polygon into connected polygons.
  Identifies the groups of boundaries of the polygon
  (two circles are friends, belonging to the same group, if they intersect,
  and friends of friends are friends),
  calls partition_gpoly to partition each group polygon into its parts,
  and combines parts from each group.

  The value of the flag overwrite_original determines whether the
  original polygon in poly is overwritten or not.

   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.
	  overwrite_original = 2 to overwrite original polygon poly in all cases,
				 whether or not partitioning succeeds;
			       1 to overwrite poly only if partitioning succeeds;
			       0 never to overwrite original poly.
  Output: (*poly and) polys[i], i = 0 to *npoly-1, are the parts of *poly.
	  *npoly = number of polygons in polys;
		   if *npoly > npolys, then there was not enough space.
  Return value: -1 if error occurred;
		 0 if *poly was fully partitioned into its parts;
		 1 if *poly was partially partioned;
		   the parts of *poly constitute a valid set of parts,
		   whose union equals the input *poly,
		   though some parts are disconnected.
*/
int partition_poly(polygon **poly, int npolys, polygon *polys[/*npolys*/], long double mtol, int all_oneboundary, int adjust_lasso, int force_split, int overwrite_original, int *npoly)
{
    const int do_vcirc = 1;
    const int per = 0;
    const int nve = 2;
    int dnp, dnpoly, ier, iev, igp, ip, ipoly, jpoly, kpoly, nev, nev0, ngp, np, nret, nv, verb;
    long double area, areag, atol, tol;
    int *ipv, *gp_tmp, *ev;
    long double *angle;
    vec *ve;
    /* work arrays */
    int *gp = 0x0, *gpg = 0x0;
    polygon *gpoly = 0x0;

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

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

    /* call gverts to determine which groups connected boundaries belong to */
    tol = mtol;
    ier = gverts(*poly, do_vcirc, &tol, per, nve, &nv, &ve, &angle, &ipv, &gp_tmp, &nev, &nev0, &ev);
    if (ier) goto error;

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

    /* polygon has 1 connected boundary, and not too many caps */
    if (!all_oneboundary && nev == 1 && (*poly)->np <= nv + 1) return(0);

    /* allocate memory for gp and gpg */
    gp = (int *) malloc(sizeof(int) * (*poly)->np);
    if (!gp) {
        fprintf(stderr, "partition_poly: failed to allocate memory for %d ints\n", (*poly)->np);
        return(-1);
    }
    gpg = (int *) malloc(sizeof(int) * (*poly)->np);
    if (!gpg) {
        fprintf(stderr, "partition_poly: failed to allocate memory for %d ints\n", (*poly)->np);
        return(-1);
    }

    /* copy group numbers, because they will be destroyed by subsequent call to gverts() */
    for (ip = 0; ip < (*poly)->np; ip++) {
        gp[ip] = gp_tmp[ip];
    }

    /* distinct groups */
    ngp = 0;
    for (iev = 0; iev < nev; iev++) {
        if (ngp == 0 || gp[ipv[ev[iev] - 1]] != gpg[ngp - 1]) {
            gpg[ngp] = gp[ipv[ev[iev] - 1]];
            ngp++;
        }
    }

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

    /* each group of connected boundaries */
    for (igp = 0; igp < ngp; igp++) {

        /* polygon contains only one group of connected boundaries */
        if (ngp == 1) {
            /* point group polygon gpoly at original polygon */
            gpoly = *poly;

            /* polygon contains more than one group of connected boundaries */
        } else {
            /* make sure group polygon gpoly contains enough space */
            np = (*poly)->np;
            dnp = 0;
            ier = room_poly(&gpoly, np, dnp, 0);
            if (ier == -1) goto out_of_memory;

            /* make group polygon */
            group_poly(*poly, gp, gpg[igp], gpoly);

        }

        /* partition group polygon */
        ier = partition_gpoly(gpoly, npolys - *npoly, &polys[*npoly], tol, all_oneboundary, adjust_lasso, force_split, &dnpoly);
        if (ier == -1) goto error;

        /* flag that partitioning was only partly successful */
        if (ier == 1) nret = 1;

        /* just one group */
        if (ngp == 1) {
            /* number of polygon parts */
            *npoly = dnpoly;

            /* not enough polygons */
            if (*npoly > npolys) return(0);

            /* two or more groups */
        } else {
            /* first group */
            if (igp == 0) {
                if (dnpoly == 0) {
                    /* not enough polygons */
                    if (*npoly >= npolys) {
                        (*npoly)++;
                        return(0);
                    }

                    /* move group polygon into cumulative polygon polys[*npoly] */
                    free_poly(polys[*npoly]);
                    polys[*npoly] = gpoly;
                    gpoly = 0x0;
                    (*npoly)++;
                } else {
                    *npoly = dnpoly;
                }

                /* subsequent groups */
            } else {
                dnp = DNP;

                /* index of next polygon after cumulative and group polygons */
                kpoly = *npoly + dnpoly;

                /* accumulate polygons */
                for (ipoly = 0; ipoly < *npoly; ipoly++) {

                    /* area of cumulative polygon polys[ipoly] */
                    atol = tol;
                    ier = garea(polys[ipoly], &atol, verb, &area);
                    if (ier) goto error;

                    /* not enough polygons */
                    if (kpoly >= npolys) {
                        *npoly = kpoly + 1;
                        return(0);
                    }

                    /* intersection of cumulative polygon polys[ipoly] with group polygon gpoly */
                    np = polys[ipoly]->np + gpoly->np;
                    ier = room_poly(&polys[kpoly], np, dnp, 0);
                    if (ier == -1) goto out_of_memory;
                    poly_poly(polys[ipoly], gpoly, polys[kpoly]);

                    /* area of intersection of cumulative polygon polys[ipoly] with group polygon gpoly */
                    ier = garea(polys[kpoly], &atol, verb, &areag);
                    if (ier) goto error;

                    /* paranoid check: group polygon gpoly does not intersect cumulative polygon polys[ipoly]: should not happen */
                    if (areag == 0.) {
                        fprintf(stderr, "partition_poly: group %d does not intersect part %d of polygon with input id %lld; should not happen; continuing ...\n", igp, ipoly, polys[ipoly]->id);
                        /* goto error; */
                        /* group polygon gpoly encloses cumulative polygon polys[ipoly], so offers no further constraint */
                    } else if (areag == area) {
                        continue;
                    }

                    /* group polygon was not partitioned */
                    if (dnpoly == 0) {
                        /* replace cumulative polygon polys[ipoly] with intersection polygon polys[kpoly] */
                        free_poly(polys[ipoly]);
                        polys[ipoly] = polys[kpoly];
                        polys[kpoly] = 0x0;

                        /* group polygon was partitioned */
                    } else {
                        /* intersect cumulative polygon polys[ipoly] with each part of group polygon */
                        for (jpoly = *npoly; jpoly < *npoly + dnpoly; jpoly++) {
                            /* not enough polygons */
                            if (kpoly >= npolys) {
                                *npoly = kpoly + 1;
                                return(0);
                            }
                            np = polys[ipoly]->np + polys[jpoly]->np;
                            ier = room_poly(&polys[kpoly], np, dnp, 0);
                            if (ier == -1) goto out_of_memory;
                            poly_poly(polys[ipoly], polys[jpoly], polys[kpoly]);
                            /* increment number of polygons */
                            kpoly++;
                        }

                        /* replace cumulative polygon polys[ipoly] with last intersected part polys[kpoly - 1] */
                        free_poly(polys[ipoly]);
                        kpoly--;
                        polys[ipoly] = polys[kpoly];
                        polys[kpoly] = 0x0;

                    }

                }

                if (dnpoly > 0) {
                    /* free parts of group polygon */
                    for (jpoly = *npoly; jpoly < *npoly + dnpoly; jpoly++) {
                        free_poly(polys[jpoly]);
                    }
                    /* decrement number of polygons */
                    kpoly -= dnpoly;
                    /* move down cumulative polygons */
                    for (ipoly = *npoly; ipoly < kpoly; ipoly++) {
                        polys[ipoly] = polys[ipoly + dnpoly];
                    }
                    /* nullify vacated polygons */
                    for (ipoly = kpoly; ipoly < kpoly + dnpoly; ipoly++) {
                        polys[ipoly] = 0x0;
                    }
                }

                /* revised number of polygons */
                *npoly = kpoly;

            }

        }

    }

    /* polygon contains just one group of connected boundaries */
    if (ngp == 1) {
        /* point original polygon at group polygon */
        *poly = gpoly;

        /* polygon contains more than one group of connected boundaries */
    } else {
        /* free group polygon */
        free_poly(gpoly);

    }

    /* move final polygon part to poly */
    if (*npoly > 0
            && (overwrite_original == 2
                || (overwrite_original == 1 && ier == 0))) {

        /* free input poly */
        free_poly(*poly);

        /* point poly at last polygon part */
        *poly = polys[*npoly - 1];

        /* nullify last polygon part */
        polys[*npoly - 1] = 0x0;

        /* decrement number of polygons */
        (*npoly)--;
    }

    if (gp) free(gp);
    if (gpg) free(gpg);

    return(nret);

    /* ---------------- error returns ---------------- */
error:
    if (gp) free(gp);
    if (gpg) free(gpg);
    return(-1);

out_of_memory:
    fprintf(stderr, "partition_poly: failed to allocate memory for polygon of %d caps\n", np + dnp);
    if (gp) free(gp);
    if (gpg) free(gpg);
    return(-1);
}
Esempio n. 5
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);
}
Esempio n. 6
0
/*------------------------------------------------------------------------------
  Write midpoints.

  Input: filename = name of file to write to;
  "" or "-" means write to standard output.
  fmt = pointer to format structure.
  polys = polygons to write.
  npolys = number of polygons.
  npolyw = number of polygons to write.
  Return value: number of polygons written,
  or -1 if error occurred.
*/
int wr_midpoint(char *filename, format *fmt, int npolys, polygon *polys[/*npolys*/], int npolyw)
{
  const int per = 0;
  const int nve = 2;
  const int do_vcirc = 0;
  char az_str[AZEL_STR_LEN], el_str[AZEL_STR_LEN];
  int i, idmin, idmax, idwidth, ier, imid, ipoly, ivm, nev, nev0, npoly, nv, nvm, width;
  int *ipv, *gp, *ev;
  double tol;
  double *angle;
  vec *ve, *vm;
  azel v;
  FILE *file;

  /* open filename for writing */
  if (!filename || strcmp(filename, "-") == 0) {
    file = stdout;
  } else {
    file = fopen(filename, "w");
    if (!file) {
	    fprintf(stderr, "wr_midpoint: cannot open %s for writing\n", filename);
	    return(-1);
    }
  }

  /* largest width of polygon id number */
  idmin = 0;
  idmax = 0;
  for (ipoly = 0; ipoly < npolys; ipoly++) {
    if (!polys[ipoly]) continue;
    if (polys[ipoly]->id < idmin) idmin = polys[ipoly]->id;
    if (polys[ipoly]->id > idmax) idmax = polys[ipoly]->id;
  }
  idmin = ((idmin < 0)? floor(log10((double)-idmin)) + 2 : 1);
  idmax = ((idmax > 0)? floor(log10((double)idmax)) + 1 : 1);
  idwidth = ((idmin > idmax)? idmin : idmax);

  /* write header */
  wrangle(0., fmt->outunitp, fmt->outprecision, AZEL_STR_LEN, az_str);
  width = strlen(az_str);
  if (fmt->outunitp == 'h') {
    sprintf(az_str, "az(hms)");
    sprintf(el_str, "el(dms)");
  } else {
    sprintf(az_str, "az(%c)", fmt->outunitp);
    sprintf(el_str, "el(%c)", fmt->outunitp);
  }
  fprintf(file, "midpoint of %d polygons\n", npolyw);
  fprintf(file, "%*s %*s %*s\n", width, az_str, width, el_str, idwidth, "id");

  npoly = 0;
  for (ipoly = 0; ipoly < npolys; ipoly++) {
    /* discard null polygons */
    if (!polys[ipoly]) continue;

    /* point somewhere in the middle of the polygon */
    tol = mtol;
    ier = gverts(polys[ipoly], do_vcirc, &tol, per, nve, &nv, &ve, &angle, &ipv, &gp, &nev, &nev0, &ev);
    if (ier == -1) return(-1);
    imid = vmid(polys[ipoly], tol, nv, nve, ve, ipv, ev, &nvm, &vm);
    if (imid == -1) return(-1);
    /* check found a point inside the polygon */
    imid = 0;
    for (ivm = 0; ivm < nvm; ivm++) {
	    if (vm[ivm][0] != 0. || vm[ivm][1] != 0. || vm[ivm][2] != 0.) {
        imid = 1;
        if (ivm > 0) for (i = 0; i < 3; i++) vm[0][i] = vm[ivm][i];
        break;
	    }
    }
    /* found a point */
    if (imid == 1) {
	    rp_to_azel(vm[0], &v);
	    switch (fmt->outphase) {
	    case '+':	if (v.az < 0.) v.az += TWOPI;	break;
	    case '-':	if (v.az > PI) v.az -= TWOPI;	break;
	    }
	    scale_azel(&v, 'r', fmt->outunitp);
    }

    /* write midpoint of polygon */
    wrangle(v.az, fmt->outunitp, fmt->outprecision, AZEL_STR_LEN, az_str);
    wrangle(v.el, fmt->outunitp, fmt->outprecision, AZEL_STR_LEN, el_str);
    fprintf(file, "%s %s %*d\n", az_str, el_str, idwidth, polys[ipoly]->id);

    /* increment polygon count */
    npoly++;
  }

  /* advise */
  msg("%d midpoints written to %s\n",
      npoly, (file == stdout)? "output": filename);

  /* close file */
  if (file != stdout) fclose(file);

  return(npoly);
}
Esempio n. 7
0
/*------------------------------------------------------------------------------
  Write mask data in edges or vertices format.

  Input: filename = name of file to write to;
  "" or "-" means write to standard output.
  fmt = pointer to format structure.
  polys = polygons to write.
  npolys = number of polygons.
  npolyw = number of polygons to write.
  Return value: number of polygons written,
  or -1 if error occurred.
*/
int wr_edge(char *filename, format *fmt, int npolys, polygon *polys[/*npolys*/], int npolyw)
{
  const int per = 0;
  const int nve = 2;
  const char *edges_fmt = "edges %d ( %d points/edge, %d edges, %.15lg weight, %s %s mid):\n";
  const char *graphics_fmt = "graphics %d ( %d points, %d edges, %.15lg weight, %s %s mid):\n";
  const char *vertices_fmt = "vertices %d ( %d vertices, %.15lg weight, %s %s mid):\n";
  char az_str[AZEL_STR_LEN], el_str[AZEL_STR_LEN];
  int do_vcirc, i, ier, imid, ipoly, iv, ive, ivm, jv, manybounds, nbadverts, nev, nev0, npoly, npt, nv, nvm;
  int *ipv, *gp, *ev;
  double azo, tol;
  double *angle;
  vec *ve, *vm;
  azel v;
  FILE *file;

  /* open filename for writing */
  if (!filename || strcmp(filename, "-") == 0) {
    file = stdout;
  } else {
    file = fopen(filename, "w");
    if (!file) {
	    fprintf(stderr, "wr_edge: cannot open %s for writing\n", filename);
	    return(-1);
    }
  }

  /* whether to write vertices also for circles with no intersections */
  if (strcmp(fmt->out, "vertices") == 0) {
    do_vcirc = 0;
  } else {
    do_vcirc = 1;
  }

  /* write number of polygons */
  fprintf(file, "%d polygons\n", npolyw);

  /* write angular unit */
  fprintf(file, "unit %c\n", fmt->outunitp);

  manybounds = 0;
  npoly = 0;
  nbadverts = 0;
  for (ipoly = 0; ipoly < npolys; ipoly++) {
    /* discard null polygons */
    if (!polys[ipoly]) continue;

    /* point somewhere in the middle of the polygon */
    tol = mtol;
    ier = gverts(polys[ipoly], do_vcirc, &tol, per, nve, &nv, &ve, &angle, &ipv, &gp, &nev, &nev0, &ev);
    if (ier == -1) return(-1);
    imid = vmid(polys[ipoly], tol, nv, nve, ve, ipv, ev, &nvm, &vm);
    if (imid == -1) return(-1);
    /* check found a point inside the polygon */
    imid = 0;
    for (ivm = 0; ivm < nvm; ivm++) {
	    if (vm[ivm][0] != 0. || vm[ivm][1] != 0. || vm[ivm][2] != 0.) {
        imid = 1;
        if (ivm > 0) for (i = 0; i < 3; i++) vm[0][i] = vm[ivm][i];
        break;
	    }
    }
    /* found a point */
    if (imid == 1) {
	    rp_to_azel(vm[0], &v);
	    switch (fmt->outphase) {
	    case '+':	if (v.az < 0.) v.az += TWOPI;	break;
	    case '-':	if (v.az > PI) v.az -= TWOPI;	break;
	    }
	    scale_azel(&v, 'r', fmt->outunitp);
    }

    /* points on edges of polygon */
    tol = mtol;
    ier = gverts(polys[ipoly], do_vcirc, &tol, fmt->outper, fmt->outnve, &nv, &ve, &angle, &ipv, &gp, &nev, &nev0, &ev);
    if (ier == -1) return(-1);
    if (ier) {
	    nbadverts++;
	    continue;
    }

    /* warn about multi-boundary polygon */
    if (nev > 1) {
	    if (WARNMAX > 0 && manybounds == 0) {
        msg("the following polygons have > 1 boundary (not simply-connected)\n");
        msg("   separate boundaries will be split over separate lines:\n");
	    }
	    if (manybounds < WARNMAX) {
        msg(" %d", polys[ipoly]->id);
	    } else if (manybounds == WARNMAX) {
        msg(" ... more\n");
	    }
	    manybounds++;
    }

    /* count number of points */
    npt = 0;
    for (iv = jv = 0; iv < nv; jv++) {
	    for (; iv < ev[jv]; iv++) {
        for (ive = 0; ive < fmt->outnve; ive++) {
          i = iv * fmt->outnve + ive;
          if (ve[i][0] == 0. && ve[i][1] == 0. && ve[i][2] == 0.) break;
          npt++;
        }
	    }
    }

    /* number of edges, weight, and midpoint of polygon */
    wrangle(v.az, fmt->outunitp, fmt->outprecision, AZEL_STR_LEN, az_str);
    wrangle(v.el, fmt->outunitp, fmt->outprecision, AZEL_STR_LEN, el_str);
    if (strcmp(fmt->out, "edges") == 0) {
	    fprintf(file, edges_fmt,
              polys[ipoly]->id, fmt->outnve, nv, polys[ipoly]->weight, az_str, el_str);
    } else if (strcmp(fmt->out, "graphics") == 0) {
	    fprintf(file, graphics_fmt,
              polys[ipoly]->id, npt, nv, polys[ipoly]->weight, az_str, el_str);
    } else {
	    fprintf(file, vertices_fmt,
              polys[ipoly]->id, nv, polys[ipoly]->weight, az_str, el_str);
    }

    /* write points, splitting separate boundaries over separate lines */
    for (iv = jv = 0; iv < nv; jv++) {
	    for (; iv < ev[jv]; iv++) {
        for (ive = 0; ive < fmt->outnve; ive++) {
          i = iv * fmt->outnve + ive;
          if (ve[i][0] == 0. && ve[i][1] == 0. && ve[i][2] == 0.) break;
          /* convert unit vector to azel vertex */
          rp_to_azel(ve[i], &v);
          /* set azimuth of first point */
          if (iv == 0 && ive == 0) {
            switch (fmt->outphase) {
            case '+':	if (v.az < 0.) v.az += TWOPI;	break;
            case '-':	if (v.az > PI) v.az -= TWOPI;	break;
            }
            /* phase azimuth of each subsequent point to the previous point */
          } else {
            v.az -= rint((v.az - azo) / TWOPI) * TWOPI;
          }
          azo = v.az;
          scale_azel(&v, 'r', fmt->outunitp);
          wrangle(v.az, fmt->outunitp, fmt->outprecision, AZEL_STR_LEN, az_str);
          wrangle(v.el, fmt->outunitp, fmt->outprecision, AZEL_STR_LEN, el_str);
          fprintf(file, " %s %s", az_str, el_str);
        }
	    }
	    fprintf(file, "\n");
    }
    /* increment polygon count */
    npoly++;
  }
  /* warn about multi-boundary polygon */
  if (WARNMAX > 0 && manybounds > 0 && manybounds <= WARNMAX) msg("\n");
  if (manybounds > 0) msg("%d polygons had more than one boundary (not simply-connected)\n", manybounds);

  /* warn about polygons producing fatal error */
  if (nbadverts > 0) {
    msg("%d polygons producing fatal error in gvert discarded\n");
  }

  /* advise */
  msg("%d polygons written to %s\n",
      npoly, (file == stdout)? "output": filename);

  /* close file */
  if (file != stdout) fclose(file);

  return(npoly);
}