void CSG::halfClassifyFaceGroups(const V2Set & /* shared_edges */,
                                  VertexClassification &vclass,
                                  carve::mesh::MeshSet<3> *poly_a,                           
                                  const carve::geom::RTreeNode<3, carve::mesh::Face<3> *> *poly_a_rtree,
                                  FLGroupList &a_loops_grouped,
                                  const detail::LoopEdges & /* a_edge_map */,
                                  carve::mesh::MeshSet<3> *poly_b,
                                  const carve::geom::RTreeNode<3, carve::mesh::Face<3> *> *poly_b_rtree,
                                  FLGroupList &b_loops_grouped,
                                  const detail::LoopEdges & /* b_edge_map */,
                                  std::list<std::pair<FaceClass, carve::mesh::MeshSet<3> *> > &b_out) {
   HalfClassifyFaceGroups classifier(b_out, hooks);
   GroupPoly group_poly(poly_b, b_out);
   performClassifyFaceGroups(
       a_loops_grouped,
       b_loops_grouped,
       vclass,
       poly_a,
       poly_a_rtree,
       poly_b,
       poly_b_rtree,
       classifier,
       group_poly,
       hooks);
 }
Example #2
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);
}