} while(0)
static int build_cell_shell(struct cmesh *mesh, const struct cmesh *orig,
- const struct frac_cell *cell)
+ struct frac_cell *cell)
{
- int i, j, k, nfaces, clipres;
+ int i, j, nfaces, clipres;
struct plane plane;
- struct poly poly, clipped;
+ struct poly poly, clipped, wallclipped;
struct vertex *vert;
+ int *delwall;
+ struct plane *cplanes;
+
+ /* array for marking wall polygons for deletion when they get clipped entirely */
+ delwall = alloca(cell->num_polys * sizeof *delwall);
+ memset(delwall, 0, cell->num_polys * sizeof *delwall);
+
+ /* array for pre-constructing the voronoi clipping planes */
+ cplanes = alloca(cell->num_polys * sizeof *cplanes);
+ for(i=0; i<cell->num_polys; i++) {
+ poly_plane(cell->polys + i, cplanes + i);
+ }
nfaces = cmesh_poly_count(orig);
for(i=0; i<nfaces; i++) {
}
for(j=0; j<cell->num_polys; j++) {
- poly_plane(cell->polys + j, &plane);
-
init_poly(&clipped);
- if((clipres = clip_poly(&clipped, &poly, &plane)) < 0) {
+ if((clipres = clip_poly(&clipped, &poly, cplanes + j)) < 0) {
destroy_poly(&clipped);
break;
}
+
+ /* if the plane clipped the polygon, and the two polygons intersect
+ * within their bounds, also clip the cell polygon by the original
+ * mesh polygon.
+ *
+ * TODO clipping with the polygon's plane is incorrect, and will lead
+ * to gaps in the cell walls when the surface is concave. We'll need
+ * to clip by the polygon itself, which can make the wall polygon
+ * concave, and will need to be split into multiple convex ones.
+ */
+ if(clipres == 0 && poly_poly(&poly, cell->polys + j)) {
+ poly_plane(&poly, &plane);
+ init_poly(&wallclipped);
+
+ if((clipres = clip_poly(&wallclipped, cell->polys + j, &plane)) < 0) {
+ /* mark for deletion */
+ delwall[j] = 1;
+ } else if(clipres == 0) {
+ destroy_poly(cell->polys + j);
+ cell->polys[j] = wallclipped;
+ } else {
+ destroy_poly(&wallclipped);
+ }
+ }
+
destroy_poly(&poly);
poly = clipped;
}
}
vert = poly.verts + 1;
- for(k=0; k<dynarr_size(poly.verts)-2; k++) {
+ for(j=0; j<dynarr_size(poly.verts)-2; j++) {
ADD_VERTEX(mesh, poly.verts);
ADD_VERTEX(mesh, vert); vert++;
ADD_VERTEX(mesh, vert);
}
destroy_poly(&poly);
}
+
+ /* remove deleted wall polygons */
+ for(i=0; i<cell->num_polys; i++) {
+ if(delwall[i]) {
+ struct poly tmp = cell->polys[i];
+ cell->polys[i] = cell->polys[--cell->num_polys];
+ destroy_poly(&tmp);
+ }
+ }
+
+ /* add wall polygons to the mesh */
+ for(i=0; i<cell->num_polys; i++) {
+ vert = cell->polys[i].verts + 1;
+ for(j=0; j<dynarr_size(cell->polys[i].verts)-2; j++) {
+ ADD_VERTEX(mesh, cell->polys[i].verts);
+ ADD_VERTEX(mesh, vert); vert++;
+ ADD_VERTEX(mesh, vert);
+ }
+ }
+
return 0;
}
return edges_clipped > 0 ? 0 : 1;
}
+
+int poly_poly(const struct poly *p1, const struct poly *p2)
+{
+ int i, vnum1, vnum2;
+ float t;
+ cgm_ray ray;
+
+ vnum1 = dynarr_size(p1->verts);
+ vnum2 = dynarr_size(p2->verts);
+
+ for(i=0; i<vnum1; i++) {
+ ray.origin = p1->verts[i].pos;
+ ray.dir = p1->verts[(i + 1) & vnum1].pos;
+ cgm_vsub(&ray.dir, &ray.origin);
+
+ if((t = ray_poly(&ray, p2)) >= 0.0f && t <= 1.0f) {
+ return 1;
+ }
+ }
+
+ for(i=0; i<vnum2; i++) {
+ ray.origin = p2->verts[i].pos;
+ ray.dir = p2->verts[(i + 1) & vnum2].pos;
+ cgm_vsub(&ray.dir, &ray.origin);
+
+ if((t = ray_poly(&ray, p1)) >= 0.0f && t <= 1.0f) {
+ return 1;
+ }
+ }
+
+ return 0;
+}