/* Last edited on 2015-11-15 17:35:58 by stolfilocal */ void stmesh_section_read_all_paths(FILE *rd, uint32_t nSegs, r2_vec_t *vP) { uint32_t np = 0; /* Number of points stored in {*vP}, including {(NAN,NAN)} delims. */ uint32_t ns = 0; /* Total number of segments already read. */ while (ns < nSegs) { /* Read the vertices of the path: */ uint32_t np_old = np; stmesh_section_read_path(rd, vP, &np); /* Get the number {nsk} of segments in the path: */ uint32_t npk = np - np_old; /* Number of points in path. */ assert(npk >= 2); uint32_t nsk = npk - 1; /* Number of segments in path. */ /* Append the path separator: */ r2_vec_expand(vP, np); vP->e[np] = (r2_t){{ NAN, NAN }}; np++; /* Count segments: */ ns = ns + nsk; } assert(ns == nSegs); r2_vec_trim(vP, np); } void stmesh_normalize_face_sides(stmesh_face_t *f); /* Rearranges the sides {f.ixside[0..2]} of face {f} so that {f.ixside[0]} is smallest possible, among all six oriented edge indices on the perimeter of {f}. */ uint32_t stmesh_utils_hash_bytes(void *x, size_t sz) { /* Jenkins's "one at a time" hash: */ ubyte *p = (ubyte *)x; uint32_t hash = 0, i; for(i = 0; i < sz; i++) { hash += (uint32_t)(*p); hash += (hash << 10); hash ^= (hash >> 6); } hash += (hash << 3); hash ^= (hash >> 11); hash += (hash << 15); return hash; } void stmesh_normalize_face_sides(stmesh_face_t *f) { stmesh_edge_ix_t ixemin = IX_NULL; /* Smallest oriented edge index in perimeter. */ int kmin = -1; /* Which of {f.ixside[0..2]} is {ixemin} or its reverse. */ bool_t rev = FALSE; /* Whether {ixemin} is {f.ixside[kmin]} or its reverse. */ int k; for (k = 0; k < 3; k++) { stmesh_edge_ix_t ixe = f->ixside[k]; if (ixe < ixemin) { ixemin = ixe; kmin = k; rev = FALSE; } stmesh_edge_ix_t jxe = EREV(ixe); if (jxe < ixemin) { ixemin = jxe; kmin = k; rev = TRUE; } } /* Cyclically permute {f.ixside[0..2]} to bring {f.ixside[kmin]} to {f.ixside[0]}: */ if (kmin == 1) { stmesh_edge_ix_t t = f->ixside[0]; f->ixside[0] = f->ixside[1]; f->ixside[1] = f->ixside[2]; f->ixside[2] = t; } else if (kmin == 2) { stmesh_edge_ix_t t = f->ixside[0]; f->ixside[0] = f->ixside[2]; f->ixside[2] = f->ixside[1]; f->ixside[1] = t; } if (rev) { /* Flip if required: */ f->ixside[0] = EREV(f->ixside[0]); stmesh_edge_ix_t t = f->ixside[1]; f->ixside[1] = EREV(f->ixside[2]); f->ixside[2] = EREV(t); } } typedef unsigned char ubyte; /* HASHING ARBITRARY DATA */ uint64_t stmesh_utils_hash_bytes(void *x, size_t sz); /* Returns an integer hash of the {sz} bytes starting at {*x}. */ typedef unsigned char ubyte; uint64_t stmesh_utils_hash_bytes(void *x, size_t sz) { /* FNV-1a algorithm: */ ubyte *p = (ubyte *)x; uint64_t hash = 14695981039346656037LU; size_t i; for(i = 0; i < sz; i++) { hash ^= (uint64_t)(*p); hash *= 1099511628211LU; p++; } return hash; } /* INDICES OF UNORIENTED EDGES, VERTICES, AND FACES. */ int stmesh_get_dbit_from_edge_ix(stmesh_edge_ix_t ixe); /* Returns the direction bit {d} of {ixe} (0 for natural, 1 for opposite to natural). */ stmesh_edge_ix_t stmesh_get_edge_ix_from_unx_dbit(stmesh_edge_unx_t uxe, int d); /* The index of the ORIENTED edge consisting of the UNORIENTED edge whose index is {uxe}, taken in the orientation {d} (0 for natural, 1 for reversed). */ stmesh_edge_unx_t stmesh_get_edge_unx_from_ix(stmesh_edge_ix_t ixe); /* Returns the index of the UNORIENTED edge underlying {ixe}. */ stmesh_face_unx_t stmesh_get_face_unx_from_ix(stmesh_face_ix_t ixf); /* The UNORIENTED index of the face underlying the ORIENTED face {ixf}. */ stmesh_face_ix_t stmesh_get_face_ix_from_unx_k_dbit(stmesh_face_unx_t uxf, int k, int d); /* The ORIENTED index of the face whose UNORIENTED index is {uxf}, whose base edge is {f.ixside[k]} progressing forwards (if {d = 0}), or the reverse of {ixside[k]}, progressing backwards (if {d = 1}). */ /* GETTING ADDRESSES */ stmesh_vert_rep_t *stmesh_get_vert_address(stmesh_t mesh, stmesh_vert_unx_t uxv); stmesh_edge_rep_t *stmesh_get_edge_address(stmesh_t mesh, stmesh_edge_unx_t uxe); stmesh_face_rep_t *stmesh_get_face_address(stmesh_t mesh, stmesh_face_unx_t uxf); /* These procedures return a pointer to the mesh element, given its UNORIENTED index. They also test whether the index is valid, and abort if not. */ // uint32_t stmesh_edge_degree_from_unx(stmesh_t mesh, stmesh_edge_unx_t uxe); // /* Returns the degree of the unoriented edge with index {uxe}, that is, the // number of faces that share it. */ int stmesh_find_edge_in_face(stmesh_face_t *f, stmesh_edge_ix_t ixe); /* Returns an index {k} in {0..2} such that {f->ixside[k]} is {ixe} or its reverse. If there is no such {k}, returns {-1}. */ #define EDGE_UNX(ixe) ((uint32_t)((ixe) >> 1)) #define EDGE_D(ixe) ((int)((ixe) & 1u)) #define FACE_UNF(ixf) ((uint32_t)((ixf) / 6u)) #define FACE_K(ixf) ((int)(((ixf) >> 1) % 3u)) #define FACE_D(ixf) ((int)((ixf) & 1u)) int stmesh_find_edge_in_face(stmesh_face_t *f, int32_t ixe) { int k; for (k = 0; k < 3; k++) { if (f->ixside[k] == ixe) { return k; } } return -1; } void stmesh_face_get_corners(stmesh_face_t f, stmesh_vert_t v[]) { stmesh_edge_t e[3]; stmesh_face_get_sides(f, e); /* Vertices {v[0]} and {v[1]} are the endpoints of edge {e[2]}: */ stmesh_edge_get_endpoints(e[2], &(v[0])); stmesh_vert_t ov = v[1]; /* Save for checking. */ /* Vertices {v[1]} and {v[2]} are the endpoints of base edge {e[0]}: */ stmesh_edge_get_endpoints(e[0], &(v[1])); assert(ov == v[1]); /* Paranoia: */ stmesh_vert_t u[2]; stmesh_edge_get_endpoints(e[1], u); assert(u[0] == v[2]); assert(u[1] == v[0]); } void stmesh_compute_edge_degrees(stmesh_t mesh); /* Computes the degree (number of incident faces) of each edge of {mesh}; that is, the number of distinct faces of {mesh} that are incident to the unoriented edge with index {uxe}. */ void stmesh_compute_edge_degrees(stmesh_t mesh) { uint32_t ne = mesh->ne; uint32_t nf = mesh->nf; /* Clear the edge degrees: */ stmesh_edge_unx_t uxe; for (uxe = 0; uxe < ne; uxe++) { stmesh_edge_t e = stmesh_get_edge(mesh, uxe); e->degree = 0; } /* Scan faces and accumulate on sides: */ stmesh_face_unx_t uxf; for (uxf = 0; uxf < nf; uxf++) { stmesh_face_t f = stmesh_get_face(mesh, uxf); /* Get the edges on the face {f}: */ stmesh_edge_t e[3]; stmesh_face_get_sides(f, e); /* Bump the degrees of those edges: */ int k; for (k = 0; k < 3; k++) { e[k]->degree++; } } } void stmesh_compute_bounding_box(stmesh_t mesh); /* Sets the bounding box {mesh.minP, mesh.maxP} to the low and high corners of the bounding box (the smallest box that contains all vertices, edges, and faces). */ void stmesh_recompute_box(stmesh_t mesh) { int32_t nv = mesh->nv; i3_t minP = (i3_t){{ INT32_MAX, INT32_MAX, INT32_MAX }}; i3_t maxP = (i3_t){{ INT32_MIN, INT32_MIN, INT32_MIN }}; int i; for (i = 0; i < nv; i++) { stmesh_vert_t vi = &(mesh->v[i]); i3_t *pi = &(vi->pos); int k; for (k = 0; k < 3; k++) { int32_t pik = pi->c[k]; if (pik < minP.c[k]) { minP.c[k] = pik; } if (pik > maxP.c[k]) { maxP.c[k] = pik; } } } mesh->minP = minP; mesh->maxP = maxP; }