/* See {salamic_slicer_Minetto.h} */ /* Last edited on 2016-04-21 18:47:23 by stolfilocal */ #define _GNU_SOURCE #include #include #include #include #include #include #include #include #include #include #include /* #include */ #include #include #include #include /* INTERNAL PROTOTYPES */ void salamic_slicer_Minetto_group_faces ( stmesh_t mesh, bool_t preSorted, int_vec_t *planeZ, bool_t uniform, stmesh_face_t f[], /* (OUT) Faces, sorted by group. */ uint32_t gstart[] /* (OUT) beg and end of each group. */ ); /* Fills {f[0..nf-1]} with all the faces of {mesh}, sorted by increasing slicing group. There are {ng = np+1} slicing groups, numbered {0..ng-1} or {0..np}. For {ig} in {1..np-1}, group {ig} has every face {t} that start between planes {ig-1} and {ig}, that is, such that {planeZ.e[ig-1] < t.minZ < planeZ.e[ig]}. Group 0 has all faces that start below the first plane ({t.minZ < planeZ.e[0]}) and group {np} has all faces that start after the last plane ({planeZ.e[np-1] < t.minZ}). Also sets {gstart[0..ng-1]} to indicate the beginning and end of each group in {f}. Namely, for any group {ig} in {0..ng-1}, the faces in group {ig} are {f[k0..k1-1]}, where {k0=gstart[ig]} and {k1=gstart[ig+1]}. Note that {gstart} must have {ng+1 = np+2} elements. Assumes (requires) that the {Z} coordinates of planes are distinct from the {Z}-coordinates of all mesh vertices; so that no vertex lies on a slicing plane. The flags {preSorted} and {uniform} can be set to save some processing time in special cases. If {preSorted} is true, the procedure assumes (requires) that the faces of {mesh} are already sorted by increasing {.minZ}. If {uniform} is true, it assumes that the slicing planes (if there is more than one) are uniformly spaced. */ void salamic_slicer_Minetto_group_faces_presorted ( stmesh_t mesh, int_vec_t *planeZ, stmesh_face_t f[], /* (OUT) Face indices, sorted by group. */ uint32_t gstart[] /* (OUT) Beg and end of each group. */ ); /* Same as {salamic_slicer_Minetto_group_faces}, for the special case that faces in {mesh} are already sorted by increasing {.minZ}. The planes may be arbitrarily spaced. */ void salamic_slicer_Minetto_group_faces_unsorted ( stmesh_t mesh, int_vec_t *planeZ, bool_t uniform, stmesh_face_t f[], /* (OUT) Face indices, sorted by group. */ uint32_t gstart[] /* (OUT) Beg and end of each group. */ ); /* Same as {salamic_slicer_Minetto_group_faces}, for the general case of unsorted faces. If {uniform} is true, assumes (and requires) that the slicing planes be uniformly spaced. */ void salamic_slicer_Minetto_face_group_sort ( stmesh_t mesh, uint32_t ng, /* Number of groups. */ uint32_t fgroup[], /* Group assigned to each face. */ stmesh_face_t f[], /* (OUT) Faces sorted by group. */ uint32_t gstart[] /* (OUT) Beg and end of each group. */ ); /* Sorts the {nf} faces of {mesh} into {ng} groups. Assumes that the groups are identified by /group indices/ in {0..ng-1}, and that each face of {mesh} with index {uxf} belongs to the group with index {fgroup[uxf]}. It stores the faces into {f[0..nf-1]}, sorted by increasing group index. The procedure also sets {gstart[0..ng]} to indicate the beginning and end of each group in {f}. Namely, for any group index {ig} in {0..ng-1}, the faces in group {ig} are {f[k0..k1-1]}, where {k0=gstart[ig]} and {k1=gstart[ig+1]}. Note that {gstart} must have {ng+1} elements, not {ng}. */ /* IMPLEMENTATIONS */ void salamic_slicer_Minetto_slice ( stmesh_t mesh, bool_t preSorted, int_vec_t *planeZ, bool_t uniform, char *closer, char *outPrefix, salamic_stats_t *st ) { uint32_t nf = stmesh_face_count(mesh); /* Number of triangles. */ uint32_t np = planeZ->ne; /* Number of slicing planes. */ uint32_t ng = np + 1; /* Number of face groups. */ float eps = stmesh_get_eps(mesh); bool_t verbose = TRUE; /* Sort the triangles by slicing group: */ stmesh_face_t *f = notnull(malloc(nf*sizeof(stmesh_face_t)), "no mem"); /* All faces, group-sorted */ uint32_t *gstart = notnull(malloc((ng+1)*sizeof(uint32_t)), "no mem"); /* Start of each group in {f}. */ salamic_slicer_Minetto_group_faces(mesh, preSorted, planeZ, uniform, f, gstart); /* Sweep over the mesh with a horizontal plane: */ stmesh_face_t *a = notnull(malloc(nf*sizeof(stmesh_face_t)), "no mem"); /* Active faces, group-sorted */ uint32_t na = 0; /* Number of active faces. */ uint32_t ixp; for (ixp = 0; ixp < np; ixp++) { /* Get the quantized Z-coordinate of next slicing plane: */ int32_t pZ = planeZ->e[ixp]; /* Get the corresponding group index {ig}: */ uint32_t ig = ixp; /* Append to the active list all faces in group {ig}: */ uint32_t na_plus = gstart[ig+1] - gstart[ig]; /* Number of faces in group. */ uint32_t kf; for (kf = gstart[ig]; kf < gstart[ig+1]; kf++) { assert(na < nf); a[na] = f[kf]; na++; } /* Remove from the active list all triangles that do not cross the plane: */ uint32_t na_new = 0; /* Faces that remain active: */ uint32_t ja; for (ja = 0; ja < na; ja++) { /* Get the next active face {f}: */ stmesh_face_t aj = a[ja]; int32_t minZ, maxZ; stmesh_face_get_zrange(aj, &minZ, &maxZ); assert(minZ < pZ); if (maxZ > pZ) { /* Still active, keep it: */ a[na_new] = aj; na_new++; } else { /* Became inactive, skip it: */ assert(maxZ < pZ); /* No vertices on slicing planes. */ } } uint32_t na_minus = na_new - na; /* Number of inactivated faces. */ na = na_new; if (verbose) { fprintf(stderr, " plane %4u at Z = %+11d (%+.8f mm): %u faces", ixp, pZ, pZ*(double)eps, na_new); fprintf(stderr, " (added %d removed %d)\n", na_plus, na_minus); } if (strcmp(closer, "NONE") != 0) { salamic_closer_close(mesh, pZ, na, a, closer, outPrefix, st); } } /* Free storage:*/ free(f); free(gstart); free(a); } void salamic_slicer_Minetto_group_faces ( stmesh_t mesh, bool_t preSorted, int_vec_t *planeZ, bool_t uniform, stmesh_face_t f[], /* (OUT) Face indices, sorted by group. */ uint32_t gstart[] /* (OUT) beg and end of each group. */ ) { if (preSorted) { salamic_slicer_Minetto_group_faces_presorted(mesh, planeZ, f, gstart); } else { salamic_slicer_Minetto_group_faces_unsorted(mesh, planeZ, uniform, f, gstart); } } void salamic_slicer_Minetto_group_faces_presorted ( stmesh_t mesh, int_vec_t *planeZ, stmesh_face_t f[], /* (OUT) Face indices, sorted by group. */ uint32_t gstart[] /* (OUT) Beg and end of each group. */ ) { uint32_t nf = stmesh_face_count(mesh); /* Number of triangles. */ uint32_t np = planeZ->ne; /* Number of planes. */ uint32_t ng = np + 1; /* Number of groups. */ /* Scan the faces in index order, noting the group breaks. */ assert(ng < INT32_MAX); /* Paranoia - so that we can use {int32_t} for {ig}. */ int32_t ig = -1; /* Index of current group. */ int32_t pZ = INT32_MIN; /* Quantized {Z} of plane {ig} */ int32_t minZ_next = INT32_MIN; /* Mininmum {.minZ} for next face. */ uint32_t uxf; for (uxf = 0; uxf < nf; uxf++) { /* Save the face the {f} list: */ f[uxf] = stmesh_get_face(mesh, uxf); /* Get the face record and its min{Z} coordinate {fZ}: */ int32_t fminZ, fmaxZ; stmesh_face_get_zrange(f[uxf], &fminZ, &fmaxZ); demand(fminZ >= minZ_next, "mesh faces are not pre-sorted by {.minZ}"); demand(fminZ < INT32_MAX, "excessive vertex {Z} coord"); /* Update {ig} so that {fminZ} is less than group's top coord {pZ}; set {gstart}: */ while (fminZ > pZ) { /* Get to next group: */ ig++; assert ((ig >= 0) && (ig < ng)); /* Group {ig} starts here: */ gstart[ig] = uxf; /* Get the group's max Z coordinate in {pZ}: */ if (ig < np) { int32_t pZ_new = planeZ->e[ig]; demand(pZ_new >= pZ + 2, "plane {Z} coords not properly spaced"); demand(pZ_new < INT32_MAX, "excessive plane {Z} coord"); pZ = pZ_new; } else { pZ = INT32_MAX; } } demand(fminZ < pZ, "bug: vertex lies on slicing plane"); minZ_next = fminZ; } /* Complete {gstart} if needed: */ while (ig < ng) { ig++; gstart[ig] = nf; } } void salamic_slicer_Minetto_group_faces_unsorted ( stmesh_t mesh, int_vec_t *planeZ, bool_t uniform, stmesh_face_t f[], /* OUT: Face indices, sorted by group. */ uint32_t gstart[] /* OUT: Beg and end of each group. */ ) { uint32_t nf = stmesh_face_count(mesh); /* Number of triangles. */ uint32_t np = planeZ->ne; /* Number of planes. */ uint32_t ng = np + 1; /* Number of groups. */ bool_t verbose = TRUE; /* Get quantized {Z} coordinates {bZ,eZ} of first and last planes: */ int32_t bZ = planeZ->e[0]; int32_t eZ = planeZ->e[np-1]; if (verbose) { fprintf(stderr, "grouping unsorted faces for %u slicing planes in %+d..%+d\n", np, bZ, eZ); } demand(eZ >= bZ, "invalid plane {Z} coordinates"); /* Get quantized step {dZ} of {Z} coordinate between planes, or 0 if not uniform: */ int32_t dZ; if ((uniform) && (np >= 2)) { dZ = planeZ->e[1] - bZ; demand((((eZ - bZ) % dZ) == 0), "plane spacing is not uniform"); demand((((eZ - bZ)/dZ) == np - 1), "inconsistent plane spacing"); } else { dZ = 0; } /* Assigns group index {fgroup[uxf]} to each face with index {uxf}: */ uint32_t *fgroup = notnull(malloc(nf*sizeof(uint32_t)), "no mem"); /* Group of each face. */ uint32_t uxf; for (uxf = 0; uxf < nf; uxf++) { /* Get the face record and its {.minZ} coordinate {fZ}: */ stmesh_face_t fk = stmesh_get_face(mesh, uxf); int32_t fminZ, fmaxZ; stmesh_face_get_zrange(fk, &fminZ, &fmaxZ); demand((fminZ & 1) == 0, "mesh vertices are not even"); /* Compute the group index {ig}: */ uint32_t ig; if (fminZ < bZ) { ig = 0; } else if (fminZ > eZ) { ig = np; } else { if (uniform) { ig = (fminZ - bZ)/dZ + 1; } else { ig = (uint32_t)binsearch_int32(fminZ, np, planeZ->e); } demand((ig >= 1) && (fminZ > planeZ->e[ig-1]), "bug: vertex on lower slicing plane"); demand((ig < np) && (fminZ < planeZ->e[ig]), "bug: vertex on upper slicing plane"); } assert(ig < ng); /* Save and count it: */ fgroup[uxf] = ig; } /* Put in {f[0..nf-1]} the face indices, sorted by group, and set {gstart[0..ng]}: */ salamic_slicer_Minetto_face_group_sort(mesh, ng, fgroup, f, gstart); free(fgroup); } void salamic_slicer_Minetto_face_group_sort ( stmesh_t mesh, uint32_t ng, /* Number of groups. */ uint32_t fgroup[], /* Group assigned to each face. */ stmesh_face_t f[], /* (OUT) Faces sorted by group. */ uint32_t gstart[] /* (OUT) Beg and end of each group. */ ) { uint32_t nf = stmesh_face_count(mesh); /* Number of triangles. */ /* Sort the face indices by group: */ stmesh_face_unx_t *uxf = notnull(malloc(nf*sizeof(stmesh_face_unx_t)), "no mem"); group_sort_uint32(nf, ng, fgroup, uxf, gstart); /* Pick the faces in that order: */ uint32_t k; for (k = 0; k < nf; k++) { f[k] = stmesh_get_face(mesh, uxf[k]); } /* Paranoia check: */ assert(gstart[ng] == nf); free(uxf); }