Ejemplo n.º 1
0
/*------------------------------------------------------------------------------
  Points on polygon nearest to and farthest from unit direction vi,
  and minimum and maximum values of cm=1-cosl(theta)
  between polygon and unit vector vi.

  This is a c interface to fortran subroutine gvlim.

   Input: poly is a polygon.
	  vcirc = 1 to return vertices and midpoints also for bounding circles
		  which have no intersections;
		= 0 not so.
	  vi = unit vector.
	  nvmax = dimension of v[nvmax] and ev[nmax].
  Input/Output: *tol = angle within which to merge multiple intersections.
  Output: *nv = number of vertices.
	  vmin[nv], vmax[nv] = arrays giving nearest and farthest
		    points from unit vector vi on each edge.
	  cmvmin[nv], cmvmax[nv] = minimum and maximum cm=1-cosl(theta)
		    between each edge and unit vector vi.
	  cmpmin[np], cmvmax[np] = minimum and maximum cm=1-cosl(theta)
		    between each circle and unit vector vi.
	  ipv[nv] = cap number of vertices/edges;
		    that is, vertex v[i] and edge points ve[i]
		    lie on cap number ipv.
	  gp[np] = which group of intersecting circles each circle belongs to.
	  *nev = number of connected sequences of vertices.
	  *nev0 = number of bounding circles which have no intersections.
	  ev[nev] = end indices of each connected sequence of vertices.
  Return value:  0 if ok;
		 1 if fatal degenerate intersection of boundaries;
		-1 if failed to allocate memory.
*/
int gvlim(polygon *poly, int vcirc, long double *tol, vec vi, int nvmax, int *nv, vec vmin[/*nvmax*/], vec vmax[/*nvmax*/], long double cmvmin[/*nvmax*/], long double cmvmax[/*nvmax*/], long double cmpmin[/*poly->np*/], long double cmpmax[/*poly->np*/], int ipv[/*nvmax*/], int gp[/*poly->np*/], int *nev, int *nev0, int ev[/*nvmax*/])
{
    logical ldegen;
    /* work arrays */
    int *iord, *iwk;
    long double *phi, *wk;

    /* allocate memory for work arrays */
    iord = (int *) malloc(sizeof(int) * poly->np * 2);
    if (!iord) {
	fprintf(stderr, "gvlim: failed to allocate memory for %d ints\n", poly->np * 2);
	return(-1);
    }
    phi = (long double *) malloc(sizeof(long double) * poly->np * 2);
    if (!phi) {
	fprintf(stderr, "gvlim: failed to allocate memory for %d long doubles\n", poly->np * 2);
	return(-1);
    }
    iwk = (int *) malloc(sizeof(int) * nvmax * 4);
    if (!iwk) {
	fprintf(stderr, "gvlim: failed to allocate memory for %d ints\n", nvmax * 4);
	return(-1);
    }
    wk = (long double *) malloc(sizeof(long double) * nvmax);
    if (!wk) {
	fprintf(stderr, "gvlim: failed to allocate memory for %d long doubles\n", nvmax);
	return(-1);
    }

    /* fortran routine */
    gvlim_(vmin, vmax, cmvmin, cmvmax, cmpmin, cmpmax, ipv, gp, ev, &nvmax, nv, nev, nev0, poly->rp, poly->cm, &poly->np, vi, &vcirc, tol, phi, iord, wk, iwk, &ldegen);

    /* number of vertices exceeds putative maximum */
    if (poly->np >= 5 && *nv > 6 * (poly->np - 2)) {
	msg("CONGRATULATIONS!  YOU HAVE DISCOVERED A POLYGON WITH 5 OR MORE CAPS\n");
	msg("(IT HAS %d CAPS) THAT HAS MORE THAN %d VERTICES (IT HAS %d VERTICES).\n", poly->np, 6 * (poly->np - 2), *nv);
	msg("(Either that or you have found a bug.)\n");
	msg("PLEASE EMAIL ME [email protected] THE GOOD NEWS,\n");
	msg("ALONG WITH A POLYGON FILE CONTAINING THE POLYGON THAT DID IT.\n");
	msg("THANKS!\n");
	dump_poly(1, &poly);
	msg("AND THERE'S THE POLYGON FILE I'D LIKE YOU TO SEND.  THANKS!\n");
    }

    /* free work arrays */
    free(iord);
    free(phi);
    free(iwk);
    free(wk);

    /* fatal intersection of boundaries */
    if (ldegen) return(1);

    return(0);
}
Ejemplo n.º 2
0
/*------------------------------------------------------------------------------
  Partition group polygon into connected polygons
  by calling part_poly repeatedly until the group polygon is fully partitioned,
  or until partitioning fails.

  If the group polygon has two or more connected boundaries none of which
  can be lassoed, then the force_split option controls whether part_poly
  should be forced to split the polygon in two.
  If a split is forced, then each of the resulting two polygons is subjected
  to further partitioning, or is in turn forcibly split if necessary.
  If too many forcible splits occur, then it is assumed that the procedure
  is not converging, and the routine bails out.

   Input: gpoly is a polygon all of whose circles belong to a single group.
	  npolys = maximum number of polygons available in polys array.
	  mtol = parameter passed to part_poly.
	  all_oneboundary = parameter passed to part_poly.
	  adjust_lasso = parameter passed to part_poly.
	  force_split = 1 to force part_poly to split a polygon
			  even if no boundary can be lassoed;
			0 otherwise.
  Output: polys[i], i = 0 to *npoly-1, are the parts of gpoly;
	      if return value = 0, then:
		  if *npoly = 0, then:
		      input gpoly already consists of a single connected part
		      that needs no partitioning;
		  if *npoly > 0, then:
		      gpoly was fully partitioned into its parts;
	      if return value = 1, then:
		  if force_split = 0, then:
		      gpoly was partially partitioned,
		      and polys[*npoly-1] contains those parts of the
		      input gpoly that were not partitioned successfully;
		      in spite of the failure,
		      polys[i], i = 0 to *npoly-1
		      constitute a valid set of parts,
		      whose union equals the input gpoly;
		  if force_split = 1, then:
		      the attempt to partition gpoly was abandoned after
		      gpoly was forcibly split too many times;
		      polys[i], i = 0 to *npoly-1
		      contain the parts of gpoly obtained so far;
		      in spite of the failure,
		      polys[i], i = 0 to *npoly-1
		      constitute a valid set of parts,
		      whose union equals the input gpoly,
		      though some parts are disconnected.
	  *npoly = number of polygons in polys;
		   if *npoly > npolys, then there was not enough space.
  Return value: -1 if error occurred;
		 0 if gpoly was successfully partitioned;
		 1 if gpoly was not fully partitioned.
*/
int partition_gpoly(polygon *gpoly, int npolys, polygon *polys[/*npolys*/], long double mtol, int all_oneboundary, int adjust_lasso, int force_split, int *npoly)
{
    /* bail out if number of forcibly split polygons to partition exceeds this maximum */
#define	NFORCEMAX	200
    int dnpoly, dnpoly_try, iforce, ier, ipoly, iprune, jpoly, nforce;
    int do_poly[NFORCEMAX];
    polygon *poly;

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

    /* number of forcibly split polygons to partition */
    nforce = 0;

    /* partition these polygons */
    for (iforce = -1; iforce < nforce; iforce++) {

        /* start with input group polygon */
        if (iforce == -1) {
            poly = gpoly;
            /* subsequent polygons that have been split forcibly */
        } else {
            poly = polys[do_poly[iforce]];
        }

        /* partition polygon repeatedly, as long as progress is made */
        while (1) {
            /* partition polygon by lassoing its boundaries with circles */
            ier = part_poly(poly, npolys - *npoly, &polys[*npoly], mtol, all_oneboundary, adjust_lasso, force_split, &dnpoly, &dnpoly_try);
            if (ier == -1) return(-1);

            /* increment number of polygons made */
            *npoly += dnpoly;

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

            /* partitioning was partially successful */
            if (dnpoly > 0 && dnpoly < dnpoly_try && ier == 0) {
                /* move last polygon into poly and repeat */
                (*npoly)--;
                poly = polys[*npoly];
                polys[*npoly] = 0x0;

                /* partitioning succeeded, or failed completely */
            } else {
                /* poly was left unpartitioned, and is not the original group polygon */
                if (dnpoly == 0 && *npoly > 0) {
                    /* move poly into next polygon */
                    polys[*npoly] = poly;
                    /* nullify source of poly, if it is a forcibly split polygon */
                    if (iforce >= 0 && poly == polys[do_poly[iforce]]) polys[do_poly[iforce]] = 0x0;
                    (*npoly)++;
                }
                /* break out of loop */
                break;
            }
        }

        /* part_poly forcibly split polygon into two parts, which need further partitioning */
        if (ier == 1) {
            if (nforce + 2 <= NFORCEMAX) {
                for (ipoly = *npoly - 2; ipoly < *npoly; ipoly++) {
                    /* prune polygon that needs further partitioning */
                    iprune = prune_poly(polys[ipoly], mtol);
                    if (iprune == -1) {
                        fprintf(stderr, "partition_gpoly: failed to prune forcibly split part %d of polygon with input id %lld\n", nforce, polys[ipoly]->id);
                        goto error;
                    }
                    if (iprune >= 2) {
                        fprintf(stderr, "partition_poly: forcibly split part %d of polygon with input id %lld has zero area; should not happen; continuing ...\n", nforce, polys[ipoly]->id);
                        dump_poly(2, &polys[*npoly - 2]);
                        continue;
                    }
                    /* flag polygon for further partitioning */
                    do_poly[nforce] = ipoly;
                    nforce++;
                }

                /* too many forcible splits: bail out */
            } else {
                /* advise */
                msg("partition_gpoly: unable to lasso parts of a polygon even after it has been\n");
                msg("split forcibly many times; bailing out with %d polygon parts.\n", *npoly);
                msg("CONGRATULATIONS!  YOU HAVE FOUND A POLYGON THAT BEATS MANGLE.\n");
                msg("PLEASE EMAIL ME [email protected] THE GOOD NEWS\n");
                msg("ALONG WITH A POLYGON FILE CONTAINING THE POLYGON THAT DID IT.\n");
                /* dump the polygon to a polygon file */
                dump_poly(1, &gpoly);
                msg("AND THERE'S THE POLYGON FILE I'D LIKE YOU TO SEND.  THANKS!\n");
                /* number of forcibly split polygons that have been partitioned */
                nforce = iforce + 1;
                /* break out of partitioning loop */
                break;

            }
        }
    }

    /* flag that partitioning was only partially successful */
    if (dnpoly < dnpoly_try) ier = 1;

    /* remove forcibly split polygons that were partitioned */
    if (nforce > 0) {
        iforce = 0;
        jpoly = 0;
        for (ipoly = 0; ipoly < *npoly; ipoly++) {
            /* free forcibly split polygons */
            if (iforce < nforce && ipoly == do_poly[iforce]) {
                if (polys[ipoly]) free_poly(polys[ipoly]);
                iforce++;
                /* move down polygons */
            } else {
                polys[jpoly] = polys[ipoly];
                jpoly++;
            }
        }
        /* nullify vacated polygons */
        for (ipoly = jpoly; ipoly < *npoly; ipoly++) {
            polys[ipoly] = 0x0;
        }
        /* revise number of polygons */
        *npoly = jpoly;
    }

    return(ier);

    /* ---------------- error returns ---------------- */
error:
    return(-1);
}