From 5bd0d227f50909086233a3304d6fbc9bb7f750cd Mon Sep 17 00:00:00 2001 From: Imad Date: Sun, 22 Sep 2024 05:40:58 +0200 Subject: [PATCH 01/86] XCore AdaptMesh: TriangulateFaces + GeneratePrisms --- .../AdaptMesh/AdaptMesh_GeneratePrisms.cpp | 29 ++ .../XCore/XCore/AdaptMesh/AdaptMesh_Init.cpp | 2 + .../XCore/AdaptMesh/AdaptMesh_TagFaces.cpp | 34 ++ .../AdaptMesh/AdaptMesh_TriangulateFaces.cpp | 30 ++ Cassiopee/XCore/XCore/AdaptMesh/Hexa.h | 19 +- Cassiopee/XCore/XCore/AdaptMesh/Mesh.h | 31 +- Cassiopee/XCore/XCore/AdaptMesh/MeshIO.cpp | 8 +- Cassiopee/XCore/XCore/AdaptMesh/MeshInit.cpp | 2 + .../XCore/XCore/AdaptMesh/MeshRefine.cpp | 84 +++-- .../XCore/XCore/AdaptMesh/MeshTriangulate.cpp | 317 ++++++++++++++++++ Cassiopee/XCore/XCore/AdaptMesh/Mpi.h | 6 +- Cassiopee/XCore/XCore/AdaptMesh/Q6.cpp | 2 + Cassiopee/XCore/XCore/AdaptMesh/Q9.cpp | 8 +- Cassiopee/XCore/XCore/PyTree.py | 18 + .../XCore/XCore/extractFacesFromPointTag.cpp | 63 ++++ .../IntersectMesh_ExtractFaceSet.cpp | 31 ++ Cassiopee/XCore/XCore/xcore.cpp | 7 +- Cassiopee/XCore/XCore/xcore.h | 12 +- Cassiopee/XCore/srcs.py | 19 +- 19 files changed, 644 insertions(+), 78 deletions(-) create mode 100644 Cassiopee/XCore/XCore/AdaptMesh/AdaptMesh_GeneratePrisms.cpp create mode 100644 Cassiopee/XCore/XCore/AdaptMesh/AdaptMesh_TagFaces.cpp create mode 100644 Cassiopee/XCore/XCore/AdaptMesh/AdaptMesh_TriangulateFaces.cpp create mode 100644 Cassiopee/XCore/XCore/AdaptMesh/MeshTriangulate.cpp create mode 100644 Cassiopee/XCore/XCore/extractFacesFromPointTag.cpp create mode 100644 Cassiopee/XCore/XCore/intersectMesh/IntersectMesh_ExtractFaceSet.cpp diff --git a/Cassiopee/XCore/XCore/AdaptMesh/AdaptMesh_GeneratePrisms.cpp b/Cassiopee/XCore/XCore/AdaptMesh/AdaptMesh_GeneratePrisms.cpp new file mode 100644 index 000000000..215c89247 --- /dev/null +++ b/Cassiopee/XCore/XCore/AdaptMesh/AdaptMesh_GeneratePrisms.cpp @@ -0,0 +1,29 @@ +#include "Mesh.h" + +PyObject *K_XCORE::AdaptMesh_GeneratePrisms(PyObject *self, PyObject *args) +{ + PyObject *AMESH, *FACES; + if (!PYPARSETUPLE_(args, OO_, &AMESH, &FACES)) { + RAISE("Bad input."); + return NULL; + } + + if (!PyCapsule_IsValid(AMESH, "AdaptMesh")) { + RAISE("Bad AdaptMesh hook."); + return NULL; + } + + E_Int *faces; + E_Int nf; + E_Int ret = K_NUMPY::getFromNumpyArray(FACES, faces, nf, true); + if (ret != 1) { + RAISE("Bad face list."); + return NULL; + } + + Mesh *M = (Mesh *)PyCapsule_GetPointer(AMESH, "AdaptMesh"); + + Mesh_generate_prisms(M, faces, nf); + + return Py_None; +} diff --git a/Cassiopee/XCore/XCore/AdaptMesh/AdaptMesh_Init.cpp b/Cassiopee/XCore/XCore/AdaptMesh/AdaptMesh_Init.cpp index a327ed29f..00e57e1db 100644 --- a/Cassiopee/XCore/XCore/AdaptMesh/AdaptMesh_Init.cpp +++ b/Cassiopee/XCore/XCore/AdaptMesh/AdaptMesh_Init.cpp @@ -240,6 +240,8 @@ PyObject *K_XCORE::AdaptMesh_Init(PyObject *self, PyObject *args) M->cref = IntArray(M->nc); M->fref = IntArray(M->nf); + M->ftag = IntArray(M->nf); + // Clean-up Karray_free_ngon(karray); diff --git a/Cassiopee/XCore/XCore/AdaptMesh/AdaptMesh_TagFaces.cpp b/Cassiopee/XCore/XCore/AdaptMesh/AdaptMesh_TagFaces.cpp new file mode 100644 index 000000000..6e5221eb0 --- /dev/null +++ b/Cassiopee/XCore/XCore/AdaptMesh/AdaptMesh_TagFaces.cpp @@ -0,0 +1,34 @@ +#include "Mesh.h" + +PyObject *K_XCORE::AdaptMesh_TagFaces(PyObject *self, PyObject *args) +{ + PyObject *AMESH, *FACES; + if (!PYPARSETUPLE_(args, OO_, &AMESH, &FACES)) { + RAISE("Bad input."); + return NULL; + } + + if (!PyCapsule_IsValid(AMESH, "AdaptMesh")) { + RAISE("Bad AdaptMesh hook."); + return NULL; + } + + E_Int *faces; + E_Int NF; + E_Int ret = K_NUMPY::getFromNumpyArray(FACES, faces, NF, true); + if (ret != 1) { + RAISE("Bad face list."); + return NULL; + } + + Mesh *M = (Mesh *)PyCapsule_GetPointer(AMESH, "AdaptMesh"); + + assert(M->ftag); + memset(M->ftag, 0, M->nf * sizeof(E_Int)); + + for (E_Int i = 0; i < NF; i++) { + M->ftag[faces[i]] = 1; + } + + return Py_None; +} diff --git a/Cassiopee/XCore/XCore/AdaptMesh/AdaptMesh_TriangulateFaces.cpp b/Cassiopee/XCore/XCore/AdaptMesh/AdaptMesh_TriangulateFaces.cpp new file mode 100644 index 000000000..6f660ca6a --- /dev/null +++ b/Cassiopee/XCore/XCore/AdaptMesh/AdaptMesh_TriangulateFaces.cpp @@ -0,0 +1,30 @@ +#include "Mesh.h" + +PyObject *K_XCORE::AdaptMesh_TriangulateFaces(PyObject *self, PyObject *args) +{ + PyObject *AMESH, *FACES; + + if (!PYPARSETUPLE_(args, OO_, &AMESH, &FACES)) { + RAISE("Wrong input."); + return NULL; + } + + if (!PyCapsule_IsValid(AMESH, "AdaptMesh")) { + RAISE("Bad mesh hook."); + return NULL; + } + + E_Int *faces; + E_Int NF; + E_Int ret = K_NUMPY::getFromNumpyArray(FACES, faces, NF, true); + if (ret != 1) { + RAISE("Bad face list."); + return NULL; + } + + Mesh *M = (Mesh *)PyCapsule_GetPointer(AMESH, "AdaptMesh"); + + Mesh_triangulate_faces(M, faces, NF); + + return Py_None; +} diff --git a/Cassiopee/XCore/XCore/AdaptMesh/Hexa.h b/Cassiopee/XCore/XCore/AdaptMesh/Hexa.h index 93921bffa..1deed754c 100644 --- a/Cassiopee/XCore/XCore/AdaptMesh/Hexa.h +++ b/Cassiopee/XCore/XCore/AdaptMesh/Hexa.h @@ -33,23 +33,6 @@ void H18_reorder(E_Int hexa, Mesh *M); E_Int check_canon_hexa(E_Int hexa, Mesh *M); -inline -void update_shell_pe(E_Int hexa, Mesh *M) -{ - const auto &children = M->cchildren.at(hexa); - - for (E_Int cid : children) { - E_Int *child = Mesh_get_cell(M, cid); - - for (E_Int j = 0; j < 6; j++) { - E_Int face = child[4*j]; - - if (M->owner[face] == hexa) M->owner[face] = cid; - else if (M->neigh[face] == hexa) M->neigh[face] = cid; - } - } -} - inline void update_range_and_stride(Mesh *M, E_Int hexa, E_Int cpos, E_Int nchildren) { @@ -68,4 +51,4 @@ void update_range_and_stride(Mesh *M, E_Int hexa, E_Int cpos, E_Int nchildren) crange[j] = 1; } } -} \ No newline at end of file +} diff --git a/Cassiopee/XCore/XCore/AdaptMesh/Mesh.h b/Cassiopee/XCore/XCore/AdaptMesh/Mesh.h index a66f72f4d..6086f21ce 100644 --- a/Cassiopee/XCore/XCore/AdaptMesh/Mesh.h +++ b/Cassiopee/XCore/XCore/AdaptMesh/Mesh.h @@ -166,6 +166,8 @@ struct Mesh { E_Int *xneis; E_Int *cneis; + E_Int *ftag; + Mesh(); }; @@ -352,6 +354,10 @@ void Mesh_get_ref_entities(Mesh *M, std::vector &ref_cells, void Mesh_resize_for_refinement(Mesh *M, const std::vector &ref_cells, const std::vector &ref_faces, const std::set &ref_edges); +void Mesh_resize_face_data(Mesh *M, E_Int new_nf); + +void Mesh_resize_cell_data(Mesh *M, E_Int new_nc); + void Mesh_sort_ref_entities_by_level(Mesh *M, std::vector &ref_cells, std::vector &ref_faces, std::set &ref_edges); @@ -369,6 +375,23 @@ void Mesh_refine_iso(Mesh *M, std::vector &ref_cells, void Mesh_refine_dir(Mesh *M, std::vector &ref_cells, std::vector &ref_faces, std::set &ref_edges); +inline +void update_shell_pe(E_Int parent, Mesh *M) +{ + const auto &children = M->cchildren.at(parent); + + for (E_Int cid : children) { + E_Int *child = Mesh_get_cell(M, cid); + + for (E_Int j = 0; j < M->cstride[cid]; j++) { + E_Int face = child[4*j]; + + if (M->owner[face] == parent) M->owner[face] = cid; + else if (M->neigh[face] == parent) M->neigh[face] = cid; + } + } +} + inline void Mesh_update_face_range_and_stride(Mesh *M, E_Int quad, E_Int fpos, E_Int nchild) { @@ -404,4 +427,10 @@ void Mesh_refine_or_get_edge_center(Mesh *M, E_Int p, E_Int q, E_Int &node) } else { node = it->second; } -} \ No newline at end of file +} + +void Mesh_triangulate_face(Mesh *M, E_Int fid); +void Mesh_triangulate_faces(Mesh *M, E_Int *faces, E_Int nf); + +void Mesh_face_to_prism(Mesh *M, E_Int fid); +void Mesh_generate_prisms(Mesh *M, E_Int *faces, E_Int nf); diff --git a/Cassiopee/XCore/XCore/AdaptMesh/MeshIO.cpp b/Cassiopee/XCore/XCore/AdaptMesh/MeshIO.cpp index 8714a4c01..a3c46e5c5 100644 --- a/Cassiopee/XCore/XCore/AdaptMesh/MeshIO.cpp +++ b/Cassiopee/XCore/XCore/AdaptMesh/MeshIO.cpp @@ -576,7 +576,9 @@ PyObject *export_conformal_mesh(Mesh *M) for (E_Int j = 0; j < M->fstride[i]; j++) { E_Int *pn = face + 2*j; - for (E_Int k = 0; k < frange[j]; k++) *ptr++ = pn[k] + 1; + for (E_Int k = 0; k < frange[j]; k++) { + *ptr++ = pn[k] + 1; + } } } @@ -606,7 +608,9 @@ PyObject *export_conformal_mesh(Mesh *M) for (E_Int j = 0; j < M->cstride[i]; j++) { E_Int *pf = cell + 4*j; - for (E_Int k = 0; k < crange[j]; k++) *ptr++ = pf[k] + 1; + for (E_Int k = 0; k < crange[j]; k++) { + *ptr++ = pf[k] + 1; + } } } diff --git a/Cassiopee/XCore/XCore/AdaptMesh/MeshInit.cpp b/Cassiopee/XCore/XCore/AdaptMesh/MeshInit.cpp index e3025d9ff..f057c290f 100644 --- a/Cassiopee/XCore/XCore/AdaptMesh/MeshInit.cpp +++ b/Cassiopee/XCore/XCore/AdaptMesh/MeshInit.cpp @@ -82,6 +82,8 @@ Mesh::Mesh() l2gc = l2gf = NULL; xneis = cneis = NULL; + + ftag = NULL; } Mesh *Mesh_from_Karray(Karray *karray) diff --git a/Cassiopee/XCore/XCore/AdaptMesh/MeshRefine.cpp b/Cassiopee/XCore/XCore/AdaptMesh/MeshRefine.cpp index 21fcb7101..1e89d44df 100644 --- a/Cassiopee/XCore/XCore/AdaptMesh/MeshRefine.cpp +++ b/Cassiopee/XCore/XCore/AdaptMesh/MeshRefine.cpp @@ -67,6 +67,51 @@ void Mesh_get_ref_entities(Mesh *M, std::vector &ref_cells, } } +void Mesh_resize_face_data(Mesh *M, E_Int new_nf) +{ + M->faces = (E_Int *)XRESIZE(M->faces, (8 * new_nf) * sizeof(E_Int)); + M->frange = (E_Int *)XRESIZE(M->frange, (4 * new_nf) * sizeof(E_Int)); + M->fstride = (E_Int *)XRESIZE(M->fstride, new_nf * sizeof(E_Int)); + + for (E_Int i = 8*M->nf; i < 8*new_nf; i++) M->faces[i] = -1; + for (E_Int i = 4*M->nf; i < 4*new_nf; i++) M->frange[i] = -1; + for (E_Int i = M->nf; i < new_nf; i++) M->fstride[i] = -1; + + M->owner = (E_Int *)XRESIZE(M->owner, new_nf * sizeof(E_Int)); + M->neigh = (E_Int *)XRESIZE(M->neigh, new_nf * sizeof(E_Int)); + + for (E_Int i = M->nf; i < new_nf; i++) { + M->owner[i] = -1; + M->neigh[i] = -1; + } + + M->ftype = (E_Int *)XRESIZE(M->ftype, new_nf * sizeof(E_Int)); + M->flevel = (E_Int *)XRESIZE(M->flevel, new_nf * sizeof(E_Int)); + + M->fref = (E_Int *)XRESIZE(M->fref, new_nf * sizeof(E_Int)); + for (E_Int i = M->nf; i < new_nf; i++) M->fref[i] = 0; + + M->fparent = (E_Int *)XRESIZE(M->fparent, new_nf * sizeof(E_Int)); + for (E_Int i = M->nf; i < new_nf; i++) M->fparent[i] = -1; + + M->ftag = (E_Int *)XRESIZE(M->ftag, new_nf * sizeof(E_Int)); + for (E_Int i = M->nf; i < new_nf; i++) M->ftag[i] = -1; +} + +void Mesh_resize_cell_data(Mesh *M, E_Int new_nc) +{ + M->cells = (E_Int *)XRESIZE(M->cells, (24 * new_nc) * sizeof(E_Int)); + M->crange = (E_Int *)XRESIZE(M->crange, (6 * new_nc) * sizeof(E_Int)); + M->cstride = (E_Int *)XRESIZE(M->cstride, new_nc * sizeof(E_Int)); + + for (E_Int i = 24*M->nc; i < 24*new_nc; i++) M->cells[i] = -1; + for (E_Int i = 6*M->nc; i < 6*new_nc; i++) M->crange[i] = -1; + for (E_Int i = M->nc; i < new_nc; i++) M->cstride[i] = -1; + + M->ctype = (E_Int *)XRESIZE(M->ctype, new_nc * sizeof(E_Int)); + M->clevel = (E_Int *)XRESIZE(M->clevel, new_nc * sizeof(E_Int)); +} + void Mesh_resize_for_refinement(Mesh *M, const std::vector &ref_cells, const std::vector &ref_faces, const std::set &ref_edges) { @@ -94,41 +139,8 @@ void Mesh_resize_for_refinement(Mesh *M, const std::vector &ref_cells, M->Y = (E_Float *)XRESIZE(M->Y, new_np * sizeof(E_Float)); M->Z = (E_Float *)XRESIZE(M->Z, new_np * sizeof(E_Float)); - M->faces = (E_Int *)XRESIZE(M->faces, (8 * new_nf) * sizeof(E_Int)); - M->frange = (E_Int *)XRESIZE(M->frange, (4 * new_nf) * sizeof(E_Int)); - M->fstride = (E_Int *)XRESIZE(M->fstride, new_nf * sizeof(E_Int)); - - for (E_Int i = 8*M->nf; i < 8*new_nf; i++) M->faces[i] = -1; - for (E_Int i = 4*M->nf; i < 4*new_nf; i++) M->frange[i] = -1; - for (E_Int i = M->nf; i < new_nf; i++) M->fstride[i] = -1; - - M->cells = (E_Int *)XRESIZE(M->cells, (24 * new_nc) * sizeof(E_Int)); - M->crange = (E_Int *)XRESIZE(M->crange, (6 * new_nc) * sizeof(E_Int)); - M->cstride = (E_Int *)XRESIZE(M->cstride, new_nc * sizeof(E_Int)); - - for (E_Int i = 24*M->nc; i < 24*new_nc; i++) M->cells[i] = -1; - for (E_Int i = 6*M->nc; i < 6*new_nc; i++) M->crange[i] = -1; - for (E_Int i = M->nc; i < new_nc; i++) M->cstride[i] = -1; - - M->owner = (E_Int *)XRESIZE(M->owner, new_nf * sizeof(E_Int)); - M->neigh = (E_Int *)XRESIZE(M->neigh, new_nf * sizeof(E_Int)); - - for (E_Int i = M->nf; i < new_nf; i++) { - M->owner[i] = -1; - M->neigh[i] = -1; - } - - M->ftype = (E_Int *)XRESIZE(M->ftype, new_nf * sizeof(E_Int)); - M->flevel = (E_Int *)XRESIZE(M->flevel, new_nf * sizeof(E_Int)); - - M->ctype = (E_Int *)XRESIZE(M->ctype, new_nc * sizeof(E_Int)); - M->clevel = (E_Int *)XRESIZE(M->clevel, new_nc * sizeof(E_Int)); - - M->fref = (E_Int *)XRESIZE(M->fref, new_nf * sizeof(E_Int)); - for (E_Int i = M->nf; i < new_nf; i++) M->fref[i] = 0; - - M->fparent = (E_Int *)XRESIZE(M->fparent, new_nf * sizeof(E_Int)); - for (E_Int i = M->nf; i < new_nf; i++) M->fparent[i] = -1; + Mesh_resize_face_data(M, new_nf); + Mesh_resize_cell_data(M, new_nc); } void Mesh_sort_ref_entities_by_level(Mesh *M, @@ -140,4 +152,4 @@ void Mesh_sort_ref_entities_by_level(Mesh *M, std::sort(ref_cells.begin(), ref_cells.end(), [&] (E_Int i, E_Int j) { return M->clevel[i] < M->clevel[j]; }); -} \ No newline at end of file +} diff --git a/Cassiopee/XCore/XCore/AdaptMesh/MeshTriangulate.cpp b/Cassiopee/XCore/XCore/AdaptMesh/MeshTriangulate.cpp new file mode 100644 index 000000000..2cc53939a --- /dev/null +++ b/Cassiopee/XCore/XCore/AdaptMesh/MeshTriangulate.cpp @@ -0,0 +1,317 @@ +#include "Mesh.h" +#include "Hexa.h" + +void Mesh_face_to_prism(Mesh *M, E_Int fid) +{ + E_Int hexa = M->owner[fid]; + assert(M->ctype[hexa] == HEXA); + + // Make fid the bottom face + E_Int *cell = Mesh_get_cell(M, hexa); + E_Int pos = Get_pos(fid, cell, 24); + assert(pos != -1); + assert(pos % 4 == 0); + + Right_shift(cell, pos, 24); + assert(cell[0] == fid); + E_Int *crange = Mesh_get_crange(M, hexa); + Right_shift(crange, pos/4, 6); + + // Get the top and left face + // Top face shares no point, left face shares p0 and p3 + + E_Int *quad = Mesh_get_face(M, fid); + + E_Int map[4]; + for (E_Int i = 0; i < 4; i++) + map[i] = quad[2*i]; + E_Int reorient = Mesh_get_reorient(M, fid, hexa, normalIn_H[0]); + E_Int BOT[2] = {fid, M->nf}; + if (reorient) { + std::swap(map[1], map[3]); + std::swap(BOT[0], BOT[1]); + } + + E_Int top, lft, rgt, fro, bck; + + for (E_Int i = 1; i < 6; i++) { + E_Int f = cell[4*i]; + E_Int *face = Mesh_get_face(M, f); + E_Int common[4] = {0, 0, 0, 0}; + + for (E_Int j = 0; j < 8; j += 2) { + E_Int p = face[j]; + for (E_Int k = 0; k < 4; k++) { + if (p == map[k]) { + common[k] = 1; + break; + } + } + } + + if (common[0] && common[3]) lft = f; + else if (common[1] && common[2]) rgt = f; + else if (common[1] && common[0]) fro = f; + else if (common[2] && common[3]) bck = f; + else top = f; + + } + + assert(top != -1); + assert(lft != -1); + assert(rgt != -1); + assert(fro != -1); + assert(bck != -1); + + // Setup the canon config + + E_Int NODES[8] = {}; + for (E_Int i = 0; i < 4; i++) + NODES[i] = map[i]; + + E_Int local[4]; + + // Align left with bottom + + E_Int *pn = Mesh_get_face(M, lft); + for (E_Int i = 0; i < 4; i++) local[i] = pn[2*i]; + pos = Get_pos(NODES[0], local, 4); + assert(pos != -1); + assert(pos % 2 == 0); + Right_shift(local, pos, 4); + assert(local[0] == NODES[0]); + reorient = Mesh_get_reorient(M, lft, hexa, normalIn_H[2]); + if (reorient) std::swap(local[1], local[3]); + assert(local[1] == NODES[3]); + NODES[4] = local[3]; + NODES[7] = local[2]; + + // Align top with left + pn = Mesh_get_face(M, top); + for (E_Int i = 0; i < 4; i++) local[i] = pn[2*i]; + pos = Get_pos(NODES[4], local, 4); + assert(pos != -1); + assert(pos % 2 == 0); + Right_shift(local, pos, 4); + assert(local[0] == NODES[4]); + E_Int TOP[2] = {top, M->nf+1}; + reorient = Mesh_get_reorient(M, top, hexa, normalIn_H[1]); + if (reorient) { + std::swap(local[1], local[3]); + if (pos == 0 || pos == 3) std::swap(TOP[0], TOP[1]); + } else { + if (pos == 2 || pos == 3) std::swap(TOP[0], TOP[1]); + } + assert(local[3] == NODES[7]); + NODES[5] = local[1]; + NODES[6] = local[2]; + + // Triangulate bottom + M->fstride[fid] = 3; + quad = Mesh_get_face(M, fid); + E_Int *qrange = Mesh_get_frange(M, fid); + qrange[2] = 1; + + M->fstride[M->nf] = 3; + E_Int *tri = Mesh_get_face(M, M->nf); + tri[0] = quad[6]; tri[2] = quad[0]; tri[4] = quad[4]; + E_Int *trange = Mesh_get_frange(M, M->nf); + trange[0] = qrange[3]; trange[1] = 1; trange[2] = qrange[2]; + + // Triangulate top + M->fstride[top] = 3; + quad = Mesh_get_face(M, top); + qrange = Mesh_get_frange(M, top); + qrange[2] = 1; + + M->fstride[M->nf+1] = 3; + tri = Mesh_get_face(M, M->nf+1); + tri[0] = quad[6]; tri[2] = quad[0]; tri[4] = quad[4]; + trange = Mesh_get_frange(M, M->nf+1); + trange[0] = qrange[3]; trange[1] = 1; trange[2] = qrange[2]; + + // Update face info + M->fref[fid] = M->fref[top] = FACE_REFINED; + M->fref[M->nf] = M->fref[M->nf+1] = FACE_NEW; + M->flevel[M->nf] = M->flevel[fid]; + M->flevel[M->nf+1] = M->flevel[top]; + M->ftag[M->nf] = M->ftag[fid]; + M->ftag[M->nf+1] = M->ftag[top]; + M->fparent[M->nf] = M->nf; + M->fparent[M->nf+1] = M->nf+1; + M->owner[M->nf] = M->owner[fid]; + M->neigh[M->nf] = M->neigh[fid]; + M->owner[M->nf+1] = M->owner[top]; + M->neigh[M->nf+1] = M->neigh[top]; + + + // Conformize parent cells + E_Int ret, own, nei; + + M->fchildren[fid] = {fid, M->nf}; + M->fchildren[top] = {top, M->nf+1}; + + // fid + ret = Mesh_conformize_cell_face(M, hexa, fid, M->nf, 2); + assert(ret == 0); + nei = M->neigh[fid]; + assert(nei == -1); + /* + if (nei != -1) { + ret = Mesh_conformize_cell_face(M, nei, hexa, M->nf, 2); + assert(ret == 0); + } + */ + + // top + own = M->owner[top]; + ret = Mesh_conformize_cell_face(M, own, top, M->nf+1, 2); + assert(ret == 0); + nei = M->neigh[top]; + if (nei != -1) { + ret = Mesh_conformize_cell_face(M, nei, top, M->nf+1, 2); + assert(ret == 0); + } + + // Set internal face in ngon + + E_Int *iquad = Mesh_get_face(M, M->nf+2); + iquad[0] = NODES[0]; iquad[2] = NODES[2]; + iquad[4] = NODES[6]; iquad[6] = NODES[4]; + + // Set internal face stride, range and state + E_Int *irange = Mesh_get_frange(M, M->nf+2); + for (E_Int i = 0; i < 4; i++) irange[i] = 1; + M->fstride[M->nf+2] = 4; + M->fref[M->nf+2] = FACE_NEW; + + // Make the first prism + E_Int *prism = Mesh_get_cell(M, hexa); + prism[0] = BOT[0]; prism[4] = TOP[0]; + prism[8] = M->nf+2; prism[12] = rgt; + prism[16] = fro; + + // Make the second prism + prism = Mesh_get_cell(M, M->nc); + prism[0] = BOT[1]; prism[4] = TOP[1]; + prism[8] = bck; prism[12] = M->nf+2; + prism[16] = lft; + + // Update ranges and strides + + M->cstride[hexa] = 5; + M->cstride[M->nc] = 5; + + E_Int *hrange = Mesh_get_crange(M, hexa); + + E_Int *prange = Mesh_get_crange(M, M->nc); + prange[0] = 1; prange[1] = 1; prange[2] = hrange[5]; + prange[3] = 1; prange[4] = hrange[2]; + + hrange[0] = 1; hrange[1] = 1; hrange[2] = 1; + + // Update adaptation info + + M->clevel[M->nc] = M->clevel[hexa]; + M->ctype[M->nc] = M->ctype[hexa] = PENTA; + + M->cchildren[hexa] = {hexa, M->nc}; + + // Set shell faces owns and neis + + update_shell_pe(hexa, M); + + // Set PE pf internal face + + M->owner[M->nf+2] = M->nc; + M->neigh[M->nf+2] = hexa; + + M->nc++; + M->nf += 3; +} + +void Mesh_generate_prisms(Mesh *M, E_Int *faces, E_Int nf) +{ + E_Int new_nf = M->nf + 3*nf; + E_Int new_nc = M->nc + nf; + + Mesh_resize_face_data(M, new_nf); + Mesh_resize_cell_data(M, new_nc); + + for (E_Int i = 0; i < nf; i++) { + E_Int fid = faces[i]; + Mesh_face_to_prism(M, fid); + } + + Mesh_update_bpatches(M); + + // TODO(Imad): parallel consequences +} + +void Mesh_triangulate_face(Mesh *M, E_Int fid) +{ + M->ftag[M->nf] = M->ftag[fid]; + + // Get quad data + E_Int *quad = Mesh_get_face(M, fid); + E_Int *qrange = Mesh_get_frange(M, fid); + + // Create the second triangle + E_Int *tri = Mesh_get_face(M, M->nf); + E_Int *trange = Mesh_get_frange(M, M->nf); + + M->fstride[M->nf] = 3; + tri[0] = quad[4]; tri[1] = quad[5]; + tri[2] = quad[6]; tri[3] = quad[7]; + tri[4] = quad[0]; assert(tri[5] == -1); + trange[0] = qrange[2]; + trange[1] = qrange[4]; + trange[2] = 1; + + // Update first quad -> triangle + M->fstride[fid] = 3; + qrange[2] = 1; + + // Conformize parent elements + E_Int own = M->owner[fid]; + E_Int ret = Mesh_conformize_cell_face(M, own, fid, M->nf, 2); + assert(ret == 0); + + E_Int nei = M->neigh[fid]; + assert(nei == -1); + if (nei != -1) { + ret = Mesh_conformize_cell_face(M, nei, fid, M->nf, 2); + assert(ret == 0); + } + + M->owner[M->nf] = own; + M->neigh[M->nf] = nei; + + M->flevel[M->nf] = M->flevel[fid]; + M->ftype[M->nf] = M->ftype[fid] = TRI; + M->fparent[M->nf] = M->nf; + + M->fref[fid] = FACE_REFINED; + M->fref[M->nf] = FACE_NEW; + M->fchildren[fid] = {fid, M->nf}; + + M->nf++; +} + +void Mesh_triangulate_faces(Mesh *M, E_Int *faces, E_Int nf) +{ + E_Int new_nf = M->nf + nf; + + Mesh_resize_face_data(M, new_nf); + + for (E_Int i = 0; i < nf; i++) { + E_Int fid = faces[i]; + assert(M->ftag[fid] == 1); + assert(M->fstride[fid] == 4); + Mesh_triangulate_face(M, fid); + } + + Mesh_update_bpatches(M); + + // TODO(Imad): parallel consequences +} diff --git a/Cassiopee/XCore/XCore/AdaptMesh/Mpi.h b/Cassiopee/XCore/XCore/AdaptMesh/Mpi.h index 9dfc0bb72..c3c76a7c6 100644 --- a/Cassiopee/XCore/XCore/AdaptMesh/Mpi.h +++ b/Cassiopee/XCore/XCore/AdaptMesh/Mpi.h @@ -13,12 +13,12 @@ #define MPI_Isend(a, b, c, d, e, f, g) #define MPI_Irecv(a, b, c, d, e, f, g) -#define MPI_Waitall(a) +#define MPI_Waitall(a) (void) #define MPI_Barrier(a) #define MPI_Allreduce(a, b, c, d, e, f) -#define MPI_Waitall(a, b, c) +#define MPI_Waitall(a, b, c) (void) #define MPI_Scan(a, b, c, d, e, f) -#endif \ No newline at end of file +#endif diff --git a/Cassiopee/XCore/XCore/AdaptMesh/Q6.cpp b/Cassiopee/XCore/XCore/AdaptMesh/Q6.cpp index 039aa2705..02fc61323 100644 --- a/Cassiopee/XCore/XCore/AdaptMesh/Q6.cpp +++ b/Cassiopee/XCore/XCore/AdaptMesh/Q6.cpp @@ -147,6 +147,8 @@ E_Int Q6_refine(E_Int quad, Mesh *M) M->fparent[M->nf] = quad; + M->ftag[M->nf] = M->ftag[quad]; + // Increment face/edge/point count M->nf += 1; diff --git a/Cassiopee/XCore/XCore/AdaptMesh/Q9.cpp b/Cassiopee/XCore/XCore/AdaptMesh/Q9.cpp index a51327403..3b7ad22ca 100644 --- a/Cassiopee/XCore/XCore/AdaptMesh/Q9.cpp +++ b/Cassiopee/XCore/XCore/AdaptMesh/Q9.cpp @@ -145,10 +145,14 @@ E_Int Q9_refine(E_Int quad, Mesh *M) M->fchildren[quad] = {quad, M->nf, M->nf+1, M->nf+2}; - M->fparent[M->nf] = quad; + M->fparent[M->nf] = quad; M->fparent[M->nf+1] = quad; M->fparent[M->nf+2] = quad; + M->ftag[M->nf] = M->ftag[quad]; + M->ftag[M->nf+1] = M->ftag[quad]; + M->ftag[M->nf+2] = M->ftag[quad]; + // Increment face/edge/point count M->nf += 3; M->np += 1; @@ -161,4 +165,4 @@ void Q4_reorder(E_Int *pn, E_Int reorient, E_Int i0, E_Int local[4]) for (E_Int i = 0; i < 4; i++) local[i] = pn[i]; Right_shift(local, i0, 4); if (reorient) std::swap(local[1], local[3]); -} \ No newline at end of file +} diff --git a/Cassiopee/XCore/XCore/PyTree.py b/Cassiopee/XCore/XCore/PyTree.py index 28a101566..698431621 100644 --- a/Cassiopee/XCore/XCore/PyTree.py +++ b/Cassiopee/XCore/XCore/PyTree.py @@ -91,6 +91,15 @@ def AdaptMesh_ExtractCellRanges(AM): def AdaptMesh_ExtractHaloCellLevels(AM): return xcore.AdaptMesh_ExtractHaloCellLevels(AM) +def AdaptMesh_TagFaces(AM, faces): + return xcore.AdaptMesh_TagFaces(AM, faces) + +def AdaptMesh_TriangulateFaces(AM, faces): + return xcore.AdaptMesh_TriangulateFaces(AM, faces) + +def AdaptMesh_GeneratePrisms(AM, faces): + return xcore.AdaptMesh_GeneratePrisms(AM, faces) + ################################################################################ @@ -389,6 +398,9 @@ def intersectMesh(IM, slave): return ts +def IntersectMesh_ExtractFaceSet(AM): + return xcore.IntersectMesh_ExtractFaceSet(AM) + def extractCell(a, cid): z = I.getZones(a)[0] @@ -398,3 +410,9 @@ def extractCell(a, cid): return zmo +def extractFacesFromPointTag(t, tag_name): + z = I.getZones(t)[0] + tag = I.getNodeFromName(z, tag_name) + if tag is None: raise ValueError(tag_name + 'not found') + arr = C.getFields(I.__GridCoordinates__, z, api=3)[0] + return xcore.extractFacesFromPointTag(arr, tag[1]) diff --git a/Cassiopee/XCore/XCore/extractFacesFromPointTag.cpp b/Cassiopee/XCore/XCore/extractFacesFromPointTag.cpp new file mode 100644 index 000000000..cf116f44e --- /dev/null +++ b/Cassiopee/XCore/XCore/extractFacesFromPointTag.cpp @@ -0,0 +1,63 @@ +#include "AdaptMesh/Karray.h" + +PyObject *K_XCORE::extractFacesFromPointTag(PyObject *self, PyObject *args) +{ + PyObject *ARR, *TAG; + if (!PYPARSETUPLE_(args, OO_, &ARR, &TAG)) { + RAISE("Bad input."); + return NULL; + } + + Karray karray; + E_Int ret = Karray_parse_ngon(ARR, karray); + if (ret != 0) return NULL; + + E_Float *tag = NULL; + E_Int nfld, size; + ret = K_NUMPY::getFromNumpyArray(TAG, tag, size, nfld, true); + if (ret != 1 || nfld != 1 || size != karray.npoints()) { + RAISE("Bad input tag."); + Karray_free_ngon(karray); + return NULL; + } + + // Count the faces to extract + E_Int nf = 0; + + for (E_Int fid = 0; fid < karray.nfaces(); fid++) { + E_Int np; + E_Int *pn = karray.get_face(fid, np); + E_Int i; + for (i = 0; i < np; i++) { + if (tag[pn[i]-1] != 1.0) { + break; + } + } + if (i == np) + nf++; + } + + // Allocate + npy_intp dims[2]; + dims[1] = 1; + dims[0] = (npy_intp)nf; + + PyArrayObject *out = (PyArrayObject *)PyArray_SimpleNew(1, dims, E_NPY_INT); + E_Int *pf = (E_Int *)PyArray_DATA(out); + E_Int *ptr = pf; + + for (E_Int fid = 0; fid < karray.nfaces(); fid++) { + E_Int np; + E_Int *pn = karray.get_face(fid, np); + E_Int i; + for (i = 0; i < np; i++) { + if (tag[pn[i]-1] != 1.0) { + break; + } + } + if (i == np) + *ptr++ = fid; + } + + return (PyObject *)out; +} diff --git a/Cassiopee/XCore/XCore/intersectMesh/IntersectMesh_ExtractFaceSet.cpp b/Cassiopee/XCore/XCore/intersectMesh/IntersectMesh_ExtractFaceSet.cpp new file mode 100644 index 000000000..e9b31a3c9 --- /dev/null +++ b/Cassiopee/XCore/XCore/intersectMesh/IntersectMesh_ExtractFaceSet.cpp @@ -0,0 +1,31 @@ +#include "mesh.h" + +PyObject *K_XCORE::IntersectMesh_ExtractFaceSet(PyObject *self, PyObject *args) +{ + PyObject *IMESH; + if (!PYPARSETUPLE_(args, O_, &IMESH)) { + RAISE("Bad input."); + return NULL; + } + + if (!PyCapsule_IsValid(IMESH, "IntersectMesh")) { + RAISE("Bad IntersectMesh hook."); + return NULL; + } + + IMesh *M = (IMesh *)PyCapsule_GetPointer(IMESH, "IntersectMesh"); + + // Allocate + npy_intp dims[2]; + dims[1] = 1; + dims[0] = (npy_intp)M->faces_to_tri.size(); + + PyArrayObject *out = (PyArrayObject *)PyArray_SimpleNew(1, dims, E_NPY_INT); + E_Int *pf = (E_Int *)PyArray_DATA(out); + E_Int *ptr = pf; + + for (const E_Int fid : M->faces_to_tri) + *ptr++ = fid; + + return (PyObject *)out; +} diff --git a/Cassiopee/XCore/XCore/xcore.cpp b/Cassiopee/XCore/XCore/xcore.cpp index 17a36e8da..4b855f185 100644 --- a/Cassiopee/XCore/XCore/xcore.cpp +++ b/Cassiopee/XCore/XCore/xcore.cpp @@ -38,12 +38,14 @@ static PyMethodDef Pyxcore [] = {"AdaptMesh_Adapt", K_XCORE::AdaptMesh_Adapt, METH_VARARGS}, {"AdaptMesh_ExtractMesh", K_XCORE::AdaptMesh_ExtractMesh, METH_VARARGS}, {"AdaptMesh_Exit", K_XCORE::AdaptMesh_Exit, METH_VARARGS}, - {"AdaptMesh_ExtractOwners", K_XCORE::AdaptMesh_ExtractOwners, METH_VARARGS}, {"AdaptMesh_ExtractNeighbours", K_XCORE::AdaptMesh_ExtractNeighbours, METH_VARARGS}, {"AdaptMesh_ExtractCellLevels", K_XCORE::AdaptMesh_ExtractCellLevels, METH_VARARGS}, {"AdaptMesh_ExtractCellRanges", K_XCORE::AdaptMesh_ExtractCellRanges, METH_VARARGS}, {"AdaptMesh_ExtractHaloCellLevels", K_XCORE::AdaptMesh_ExtractHaloCellLevels, METH_VARARGS}, + {"AdaptMesh_TagFaces", K_XCORE::AdaptMesh_TagFaces, METH_VARARGS}, + {"AdaptMesh_TriangulateFaces", K_XCORE::AdaptMesh_TriangulateFaces, METH_VARARGS}, + {"AdaptMesh_GeneratePrisms", K_XCORE::AdaptMesh_GeneratePrisms, METH_VARARGS}, {"intersectMesh", K_XCORE::intersectMesh, METH_VARARGS}, {"removeIntersectingKPlanes", K_XCORE::removeIntersectingKPlanes, METH_VARARGS}, @@ -53,8 +55,11 @@ static PyMethodDef Pyxcore [] = {"IntersectMesh_TriangulateFaceSet", K_XCORE::IntersectMesh_TriangulateFaceSet, METH_VARARGS}, {"IntersectMesh_ExtractMesh", K_XCORE::IntersectMesh_ExtractMesh, METH_VARARGS}, {"IntersectMesh_Exit", K_XCORE::IntersectMesh_Exit, METH_VARARGS}, + {"IntersectMesh_ExtractFaceSet", K_XCORE::IntersectMesh_ExtractFaceSet, METH_VARARGS}, {"extractCell", K_XCORE::extractCell, METH_VARARGS}, + + {"extractFacesFromPointTag", K_XCORE::extractFacesFromPointTag, METH_VARARGS}, {NULL, NULL} }; diff --git a/Cassiopee/XCore/XCore/xcore.h b/Cassiopee/XCore/XCore/xcore.h index 03a1c2634..f7487c57c 100644 --- a/Cassiopee/XCore/XCore/xcore.h +++ b/Cassiopee/XCore/XCore/xcore.h @@ -45,22 +45,19 @@ namespace K_XCORE PyObject *exchangeFields(PyObject *self, PyObject *args); PyObject *AdaptMesh_Init(PyObject *self, PyObject *args); - PyObject *AdaptMesh_AssignRefData(PyObject *self, PyObject *args); - PyObject *AdaptMesh_LoadBalance(PyObject *self, PyObject *args); - PyObject *AdaptMesh_Adapt(PyObject *self, PyObject *args); - PyObject *AdaptMesh_ExtractMesh(PyObject *self, PyObject *args); - PyObject *AdaptMesh_Exit(PyObject *self, PyObject *args); - PyObject *AdaptMesh_ExtractOwners(PyObject *self, PyObject *args); PyObject *AdaptMesh_ExtractNeighbours(PyObject *self, PyObject *args); PyObject *AdaptMesh_ExtractCellLevels(PyObject *self, PyObject *args); PyObject *AdaptMesh_ExtractCellRanges(PyObject *self, PyObject *args); PyObject *AdaptMesh_ExtractHaloCellLevels(PyObject *self, PyObject *args); + PyObject *AdaptMesh_TagFaces(PyObject *self, PyObject *args); + PyObject *AdaptMesh_TriangulateFaces(PyObject *self, PyObject *args); + PyObject *AdaptMesh_GeneratePrisms(PyObject *self, PyObject *args); PyObject *intersectMesh(PyObject *self, PyObject *args); PyObject *removeIntersectingKPlanes(PyObject *self, PyObject *args); @@ -70,8 +67,11 @@ namespace K_XCORE PyObject *IntersectMesh_ExtractMesh(PyObject *self, PyObject *args); PyObject *IntersectMesh_TriangulateFaceSet(PyObject *self, PyObject *args); PyObject *IntersectMesh_Exit(PyObject *self, PyObject *args); + PyObject *IntersectMesh_ExtractFaceSet(PyObject *self, PyObject *args); PyObject *extractCell(PyObject *self, PyObject *args); + + PyObject *extractFacesFromPointTag(PyObject *self, PyObject *args); } #endif diff --git a/Cassiopee/XCore/srcs.py b/Cassiopee/XCore/srcs.py index 63a8a5686..556bba5a1 100644 --- a/Cassiopee/XCore/srcs.py +++ b/Cassiopee/XCore/srcs.py @@ -29,7 +29,7 @@ 'XCore/intersectMesh/IntersectMesh_TriangulateFaceSet.cpp', 'XCore/intersectMesh/IntersectMesh_ExtractMesh.cpp', 'XCore/intersectMesh/IntersectMesh_Exit.cpp', - 'XCore/intersectMesh/DDA.cpp', + 'XCore/intersectMesh/IntersectMesh_ExtractFaceSet.cpp', 'XCore/intersectMesh/intersectMesh.cpp', 'XCore/intersectMesh/removeIntersectingKPlanes.cpp', @@ -58,6 +58,7 @@ 'XCore/intersectMesh/ray.cpp', 'XCore/intersectMesh/karray.cpp', 'XCore/intersectMesh/meshExport.cpp', + 'XCore/intersectMesh/DDA.cpp', 'XCore/AdaptMesh/AdaptMesh_Init.cpp', @@ -65,36 +66,36 @@ 'XCore/AdaptMesh/AdaptMesh_AssignRefData.cpp', 'XCore/AdaptMesh/AdaptMesh_Adapt.cpp', 'XCore/AdaptMesh/AdaptMesh_Exit.cpp', - 'XCore/AdaptMesh/AdaptMesh_ExtractData.cpp', - + 'XCore/AdaptMesh/AdaptMesh_TagFaces.cpp', + 'XCore/AdaptMesh/AdaptMesh_TriangulateFaces.cpp', + 'XCore/AdaptMesh/AdaptMesh_GeneratePrisms.cpp', + 'XCore/AdaptMesh/MeshInit.cpp', 'XCore/AdaptMesh/MeshOrient.cpp', 'XCore/AdaptMesh/MeshClean.cpp', 'XCore/AdaptMesh/MeshTopo.cpp', 'XCore/AdaptMesh/MeshIO.cpp', 'XCore/AdaptMesh/MeshSmooth.cpp', - 'XCore/AdaptMesh/MeshConnectivity.cpp', 'XCore/AdaptMesh/MeshConformize.cpp', 'XCore/AdaptMesh/MeshRefine.cpp', 'XCore/AdaptMesh/MeshIso.cpp', 'XCore/AdaptMesh/MeshDir.cpp', + 'XCore/AdaptMesh/MeshTriangulate.cpp', 'XCore/AdaptMesh/H27.cpp', 'XCore/AdaptMesh/H18.cpp', 'XCore/AdaptMesh/Tetra.cpp', 'XCore/AdaptMesh/Penta.cpp', 'XCore/AdaptMesh/Pyra.cpp', - 'XCore/AdaptMesh/Q9.cpp', 'XCore/AdaptMesh/Q6.cpp', - 'XCore/AdaptMesh/Tri.cpp', - 'XCore/AdaptMesh/Edge.cpp', - - 'XCore/AdaptMesh/Karray.cpp' + 'XCore/AdaptMesh/Karray.cpp', + + 'XCore/extractFacesFromPointTag.cpp', ] if mpi: # source that requires mpi cpp_srcs += [ From 1f9f3b331f33007b8dc96d6b3bfbfafb8a90eb76 Mon Sep 17 00:00:00 2001 From: Imad Date: Sun, 22 Sep 2024 05:49:17 +0200 Subject: [PATCH 02/86] Added Vim swap files to gitignore --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index 974e6d8e8..c8fc035f9 100644 --- a/.gitignore +++ b/.gitignore @@ -56,5 +56,6 @@ Data* out_foam/ chm000* out.step +*.swp tools/MigrationSVN From 09d342d778c026eebc7f4da06579a47dff40ffae Mon Sep 17 00:00:00 2001 From: Imad Date: Sun, 22 Sep 2024 19:41:44 +0200 Subject: [PATCH 03/86] XCore AdaptMesh: point localization --- .../XCore/AdaptMesh/AdaptMesh_AdaptGeom.cpp | 313 ++++++++++++++++++ .../XCore/XCore/AdaptMesh/AdaptMesh_Init.cpp | 2 + .../XCore/AdaptMesh/AdaptMesh_TagFaces.cpp | 39 +++ Cassiopee/XCore/XCore/AdaptMesh/Mesh.h | 6 +- Cassiopee/XCore/XCore/AdaptMesh/MeshClean.cpp | 7 + Cassiopee/XCore/XCore/AdaptMesh/MeshInit.cpp | 4 +- .../XCore/XCore/AdaptMesh/MeshTriangulate.cpp | 8 +- Cassiopee/XCore/XCore/PyTree.py | 6 + Cassiopee/XCore/XCore/xcore.cpp | 2 + Cassiopee/XCore/XCore/xcore.h | 2 + Cassiopee/XCore/srcs.py | 1 + 11 files changed, 385 insertions(+), 5 deletions(-) create mode 100644 Cassiopee/XCore/XCore/AdaptMesh/AdaptMesh_AdaptGeom.cpp diff --git a/Cassiopee/XCore/XCore/AdaptMesh/AdaptMesh_AdaptGeom.cpp b/Cassiopee/XCore/XCore/AdaptMesh/AdaptMesh_AdaptGeom.cpp new file mode 100644 index 000000000..ad2950bb6 --- /dev/null +++ b/Cassiopee/XCore/XCore/AdaptMesh/AdaptMesh_AdaptGeom.cpp @@ -0,0 +1,313 @@ +#include "Mesh.h" +#include "common/mem.h" + +void point_print(E_Float px, E_Float py, E_Float pz) +{ + FILE *fh = fopen("point", "w"); + assert(fh); + fprintf(fh, "POINTS\n"); + fprintf(fh, "1\n"); + fprintf(fh, "%f %f %f\n", px, py, pz); + fclose(fh); +} + +struct ArrayI { + E_Int count; + E_Int *ptr; +}; + +void Mesh_extract_faces_from_ftag(Mesh *M, ArrayI *fids) +{ + fids->count = 0; + + for (E_Int i = 0; i < M->nf; i++) { + fids->count += (M->ftag[i] == 1); + } + + fids->ptr = (E_Int *)XMALLOC(fids->count * sizeof(E_Int)); + E_Int *ptr = fids->ptr; + + for (E_Int i = 0; i < M->nf; i++) { + if (M->ftag[i] == 1) + *ptr++ = i; + } +} + +void Mesh_extract_points_from_ftag(Mesh *M, ArrayI *pids) +{ + // WARNING(Imad): ptag is reset here + memset(M->ptag, 0, M->np * sizeof(E_Int)); + pids->count = 0; + + for (E_Int fid = 0; fid < M->nf; fid++) { + if (M->ftag[fid] != 1) continue; + E_Int *face = Mesh_get_face(M, fid); + E_Int *frange = Mesh_get_frange(M, fid); + for (E_Int i = 0; i < M->fstride[fid]; i++) { + E_Int *pn = face + 2*i; + for (E_Int j = 0; j < frange[i]; j++) { + E_Int pid = pn[j]; + pids->count += (M->ptag[pid] == 0); + M->ptag[pid] = 1; + } + } + } + + pids->ptr = (E_Int *)XMALLOC(pids->count * sizeof(E_Int)); + E_Int *ptr = pids->ptr; + + for (E_Int pid = 0; pid < M->np; pid++) { + if (M->ptag[pid] == 1) + *ptr++ = pid; + } +} + +struct Box2D { + E_Float xmin, ymin; + E_Float xmax, ymax; +}; + +Box2D Mesh_box2D_faces(Mesh *M, ArrayI *fids) +{ + E_Float xmin, ymin, xmax, ymax; + xmin = ymin = 0xFFFFFFFF; + xmax = ymax = -xmin; + + for (E_Int i = 0; i < fids->count; i++) { + E_Int fid = fids->ptr[i]; + E_Int *face = Mesh_get_face(M, fid); + E_Int *frange = Mesh_get_frange(M, fid); + for (E_Int j = 0; j < M->fstride[fid]; j++) { + E_Int *pn = face + 2*j; + for (E_Int k = 0; k < frange[j]; k++) { + E_Int pid = pn[k]; + if (M->X[pid] < xmin) xmin = M->X[pid]; + if (M->Y[pid] < ymin) ymin = M->Y[pid]; + if (M->X[pid] > xmax) xmax = M->X[pid]; + if (M->Y[pid] > ymax) ymax = M->Y[pid]; + } + } + } + + // Safety + xmax = xmax + (xmax - xmin)*0.01; + ymax = ymax + (ymax - ymin)*0.01; + + return { xmin, ymin, xmax, ymax }; +} + +#define MAX_FACES_PER_GRID 8 + +struct GridFaces { + E_Int ptr[MAX_FACES_PER_GRID]; + E_Int count; +}; + +#define GRIDX 64 +#define GRIDY 64 + +void Mesh_2D_grid_faces(Mesh *M, ArrayI *mfaces, Box2D box2D, + GridFaces grid_faces[GRIDX][GRIDY]) +{ + E_Float HX = (box2D.xmax - box2D.xmin) / GRIDX; + E_Float HY = (box2D.ymax - box2D.ymin) / GRIDY; + + for (E_Int i = 0; i < mfaces->count; i++) { + E_Int fid = mfaces->ptr[i]; + E_Int *face = Mesh_get_face(M, fid); + E_Int *frange = Mesh_get_frange(M, fid); + + E_Int minX = GRIDX, maxX = -1; + E_Int minY = GRIDY, maxY = -1; + for (E_Int j = 0; j < M->fstride[fid]; j++) { + E_Int *pn = face + 2*j; + for (E_Int k = 0; k < frange[j]; k++) { + E_Int pid = pn[k]; + E_Int grid_x = (M->X[pid] - box2D.xmin) / HX; + E_Int grid_y = (M->Y[pid] - box2D.ymin) / HY; + assert(grid_x >= 0 && grid_x < GRIDX); + assert(grid_y >= 0 && grid_y < GRIDY); + if (grid_x < minX) minX = grid_x; + if (grid_y < minY) minY = grid_y; + if (grid_x > maxX) maxX = grid_x; + if (grid_y > maxY) maxY = grid_y; + } + } + + for (E_Int grid_x = minX; grid_x <= maxX; grid_x++) { + for (E_Int grid_y = minY; grid_y <= maxY; grid_y++) { + GridFaces *grid = &grid_faces[grid_x][grid_y]; + if (grid->count >= MAX_FACES_PER_GRID) { + fprintf(stderr, "Grid is too coarse, refine it!\n"); + abort(); + } + grid->ptr[grid->count++] = i; // We need the index in mfaces, not the id + } + } + } +} + +struct TriBary { + E_Float UX, UY; + E_Float VX, VY; + E_Float UU, VV, UV; + E_Float inv_denom; +}; + +void Mesh_locate_spoints_in_mtris +( + Mesh *S, ArrayI *spoints, + Mesh *M, ArrayI *mtris, + Box2D box2D, GridFaces grid_faces[GRIDX][GRIDY], E_Int *sploc) +{ + // Compute the mtris dot products once + TriBary *tri_barys = (TriBary *)XMALLOC(mtris->count * sizeof(TriBary)); + for (E_Int i = 0; i < mtris->count; i++) { + E_Int tid = mtris->ptr[i]; + assert(M->ftype[tid] == TRI); + E_Int *tri = Mesh_get_face(M, tid); + E_Int A = tri[0], B = tri[2], C = tri[4]; + + E_Float ux = (M->X[B] - M->X[A]); + E_Float uy = (M->Y[B] - M->Y[A]); + E_Float vx = (M->X[C] - M->X[A]); + E_Float vy = (M->Y[C] - M->Y[A]); + + tri_barys[i].UX = ux; + tri_barys[i].UY = uy; + + tri_barys[i].VX = vx; + tri_barys[i].VY = vy; + + tri_barys[i].UU = ux*ux + uy*uy; + tri_barys[i].VV = vx*vx + vy*vy; + tri_barys[i].UV = ux*vx + uy*vy; + + tri_barys[i].inv_denom = 1.0 / (tri_barys[i].UU * tri_barys[i].VV - + tri_barys[i].UV * tri_barys[i].UV); + } + + E_Float HX = (box2D.xmax - box2D.xmin) / GRIDX; + E_Float HY = (box2D.ymax - box2D.ymin) / GRIDY; + + memset(sploc, -1, mtris->count * sizeof(E_Int)); + + for (E_Int i = 0; i < spoints->count; i++) { + E_Int spid = spoints->ptr[i]; + E_Float px = S->X[spid]; + E_Float py = S->Y[spid]; + E_Int grid_x = (px - box2D.xmin) / HX; + E_Int grid_y = (py - box2D.ymin) / HY; + assert(grid_x >= 0); + assert(grid_x < GRIDX); + assert(grid_y >= 0); + assert(grid_y < GRIDY); + GridFaces *grid = &grid_faces[grid_x][grid_y]; + + if (grid->count == 0) { + fprintf(stderr, "No faces found in point grid!\n"); + abort(); + }; + + for (E_Int j = 0; j < grid->count; j++) { + E_Int tidx = grid->ptr[j]; + E_Int tid = mtris->ptr[tidx]; + assert(M->ftype[tid] == TRI); + + E_Int *tri = Mesh_get_face(M, tid); + E_Int A = tri[0]; + E_Float DX = px - M->X[A]; + E_Float DY = py - M->Y[A]; + + TriBary *tb = &tri_barys[tidx]; + + E_Float d20 = DX*tb->UX + DY*tb->UY; + E_Float d21 = DX*tb->VX + DY*tb->VY; + + E_Float u = (tb->VV*d20 - tb->UV*d21) * tb->inv_denom; + E_Float v = (tb->UU*d21 - tb->UV*d20) * tb->inv_denom; + + if (u >= 0.0 && v >= 0.0 && (u + v) <= 1.0) { + sploc[i] = tid; + break; + } + } + + if (sploc[i] == -1) { + fprintf(stderr, "Failed to locate point %d!\n", spid); + abort(); + } + } + + + +} + +PyObject *K_XCORE::AdaptMesh_AdaptGeom(PyObject *self, PyObject *args) +{ + PyObject *AMESH, *SMESH; + + if (!PYPARSETUPLE_(args, OO_, &AMESH, &SMESH)) { + RAISE("Wrong input."); + return NULL; + } + + if (!PyCapsule_IsValid(AMESH, "AdaptMesh")) { + RAISE("Bad first AdaptMesh hook."); + return NULL; + } + + if (!PyCapsule_IsValid(SMESH, "AdaptMesh")) { + RAISE("Bad second AdaptMesh hook."); + return NULL; + } + + Mesh *M = (Mesh *)PyCapsule_GetPointer(AMESH, "AdaptMesh"); + Mesh *S = (Mesh *)PyCapsule_GetPointer(SMESH, "AdaptMesh"); + + // Refine M volumetric wrt to S tagged faces point cloud + // Refine S surfacic wrt to M tagged faces point cloud + + E_Int ref_M = 0, ref_S = 0; + E_Int iter = 0; + + do { + iter++; + + // Sfaces are tagged + ArrayI spoints; + Mesh_extract_points_from_ftag(S, &spoints); + + // Spoints must belong to one of the tagged Mfaces + // All the tagged faces must be triangles + ArrayI mtris; + Mesh_extract_faces_from_ftag(M, &mtris); + + // Box the mfaces + Box2D box2D = Mesh_box2D_faces(M, &mtris); + + // Grid the mfaces + GridFaces grid_faces[GRIDX][GRIDY] = {0}; + Mesh_2D_grid_faces(M, &mtris, box2D, grid_faces); + + // Locate spoints in mfaces + E_Int *sploc = (E_Int *)XMALLOC(spoints.count * sizeof(E_Int)); + Mesh_locate_spoints_in_mtris + ( + S, &spoints, + M, &mtris, + box2D, grid_faces, + sploc + ); + + + + + + XFREE(spoints.ptr); + XFREE(mtris.ptr); + XFREE(sploc); + } while (ref_S); + + return Py_None; +} diff --git a/Cassiopee/XCore/XCore/AdaptMesh/AdaptMesh_Init.cpp b/Cassiopee/XCore/XCore/AdaptMesh/AdaptMesh_Init.cpp index 00e57e1db..c0cb00b75 100644 --- a/Cassiopee/XCore/XCore/AdaptMesh/AdaptMesh_Init.cpp +++ b/Cassiopee/XCore/XCore/AdaptMesh/AdaptMesh_Init.cpp @@ -240,7 +240,9 @@ PyObject *K_XCORE::AdaptMesh_Init(PyObject *self, PyObject *args) M->cref = IntArray(M->nc); M->fref = IntArray(M->nf); + M->ctag = IntArray(M->nc); M->ftag = IntArray(M->nf); + M->ptag = IntArray(M->np); // Clean-up diff --git a/Cassiopee/XCore/XCore/AdaptMesh/AdaptMesh_TagFaces.cpp b/Cassiopee/XCore/XCore/AdaptMesh/AdaptMesh_TagFaces.cpp index 6e5221eb0..3e796a8da 100644 --- a/Cassiopee/XCore/XCore/AdaptMesh/AdaptMesh_TagFaces.cpp +++ b/Cassiopee/XCore/XCore/AdaptMesh/AdaptMesh_TagFaces.cpp @@ -1,5 +1,44 @@ #include "Mesh.h" +PyObject *K_XCORE::AdaptMesh_ExtractTaggedFaces(PyObject *self, PyObject *args) +{ + PyObject *AMESH; + if (!PYPARSETUPLE_(args, O_, &AMESH)) { + RAISE("Bad input."); + return NULL; + } + + if (!PyCapsule_IsValid(AMESH, "AdaptMesh")) { + RAISE("Bad AdaptMesh hook."); + return NULL; + } + + Mesh *M = (Mesh *)PyCapsule_GetPointer(AMESH, "AdaptMesh"); + + assert(M->ftag); + + E_Int count = 0; + + for (E_Int i = 0; i < M->nf; i++) { + count += (M->ftag[i] == 1); + } + + npy_intp dims[2]; + dims[1] = 1; + dims[0] = (npy_intp)count; + + PyArrayObject *out = (PyArrayObject *)PyArray_SimpleNew(1, dims, E_NPY_INT); + E_Int *pf = (E_Int *)PyArray_DATA(out); + E_Int *ptr = pf; + + for (E_Int fid = 0; fid < M->nf; fid++) { + if (M->ftag[fid] == 1) + *ptr++ = fid; + } + + return (PyObject *)out; +} + PyObject *K_XCORE::AdaptMesh_TagFaces(PyObject *self, PyObject *args) { PyObject *AMESH, *FACES; diff --git a/Cassiopee/XCore/XCore/AdaptMesh/Mesh.h b/Cassiopee/XCore/XCore/AdaptMesh/Mesh.h index 6086f21ce..9cf840ba0 100644 --- a/Cassiopee/XCore/XCore/AdaptMesh/Mesh.h +++ b/Cassiopee/XCore/XCore/AdaptMesh/Mesh.h @@ -165,8 +165,10 @@ struct Mesh { E_Int *xneis; E_Int *cneis; - + + E_Int *ctag; E_Int *ftag; + E_Int *ptag; Mesh(); }; @@ -323,6 +325,8 @@ void Mesh_reset_adaptation_data(Mesh *M); void Mesh_reset_parallel_data(Mesh *M); +void Mesh_reset_tags(Mesh *M); + void Mesh_free(Mesh *M); diff --git a/Cassiopee/XCore/XCore/AdaptMesh/MeshClean.cpp b/Cassiopee/XCore/XCore/AdaptMesh/MeshClean.cpp index 590404f26..fedd5f6e8 100644 --- a/Cassiopee/XCore/XCore/AdaptMesh/MeshClean.cpp +++ b/Cassiopee/XCore/XCore/AdaptMesh/MeshClean.cpp @@ -113,6 +113,13 @@ void Mesh_reset_parallel_data(Mesh *M) XFREE(M->cneis); } +void Mesh_reset_tags(Mesh *M) +{ + XFREE(M->ctag); + XFREE(M->ftag); + XFREE(M->ptag); +} + void Mesh_free(Mesh *M) { Mesh_reset_base_data(M); diff --git a/Cassiopee/XCore/XCore/AdaptMesh/MeshInit.cpp b/Cassiopee/XCore/XCore/AdaptMesh/MeshInit.cpp index f057c290f..7710a0c12 100644 --- a/Cassiopee/XCore/XCore/AdaptMesh/MeshInit.cpp +++ b/Cassiopee/XCore/XCore/AdaptMesh/MeshInit.cpp @@ -82,8 +82,10 @@ Mesh::Mesh() l2gc = l2gf = NULL; xneis = cneis = NULL; - + + ctag = NULL; ftag = NULL; + ptag = NULL; } Mesh *Mesh_from_Karray(Karray *karray) diff --git a/Cassiopee/XCore/XCore/AdaptMesh/MeshTriangulate.cpp b/Cassiopee/XCore/XCore/AdaptMesh/MeshTriangulate.cpp index 2cc53939a..2218b5f5b 100644 --- a/Cassiopee/XCore/XCore/AdaptMesh/MeshTriangulate.cpp +++ b/Cassiopee/XCore/XCore/AdaptMesh/MeshTriangulate.cpp @@ -143,6 +143,8 @@ void Mesh_face_to_prism(Mesh *M, E_Int fid) M->neigh[M->nf] = M->neigh[fid]; M->owner[M->nf+1] = M->owner[top]; M->neigh[M->nf+1] = M->neigh[top]; + M->ftype[fid] = M->ftype[M->nf] = TRI; + M->ftype[top] = M->ftype[M->nf+1] = TRI; // Conformize parent cells @@ -249,9 +251,7 @@ void Mesh_generate_prisms(Mesh *M, E_Int *faces, E_Int nf) } void Mesh_triangulate_face(Mesh *M, E_Int fid) -{ - M->ftag[M->nf] = M->ftag[fid]; - +{ // Get quad data E_Int *quad = Mesh_get_face(M, fid); E_Int *qrange = Mesh_get_frange(M, fid); @@ -294,6 +294,8 @@ void Mesh_triangulate_face(Mesh *M, E_Int fid) M->fref[fid] = FACE_REFINED; M->fref[M->nf] = FACE_NEW; M->fchildren[fid] = {fid, M->nf}; + + M->ftag[M->nf] = M->ftag[fid]; M->nf++; } diff --git a/Cassiopee/XCore/XCore/PyTree.py b/Cassiopee/XCore/XCore/PyTree.py index 698431621..56812a911 100644 --- a/Cassiopee/XCore/XCore/PyTree.py +++ b/Cassiopee/XCore/XCore/PyTree.py @@ -100,6 +100,12 @@ def AdaptMesh_TriangulateFaces(AM, faces): def AdaptMesh_GeneratePrisms(AM, faces): return xcore.AdaptMesh_GeneratePrisms(AM, faces) +def AdaptMesh_AdaptGeom(AM, AS): + return xcore.AdaptMesh_AdaptGeom(AM, AS) + +def AdaptMesh_ExtractTaggedFaces(AM): + return xcore.AdaptMesh_ExtractTaggedFaces(AM) + ################################################################################ diff --git a/Cassiopee/XCore/XCore/xcore.cpp b/Cassiopee/XCore/XCore/xcore.cpp index 4b855f185..9684e7ee4 100644 --- a/Cassiopee/XCore/XCore/xcore.cpp +++ b/Cassiopee/XCore/XCore/xcore.cpp @@ -46,6 +46,8 @@ static PyMethodDef Pyxcore [] = {"AdaptMesh_TagFaces", K_XCORE::AdaptMesh_TagFaces, METH_VARARGS}, {"AdaptMesh_TriangulateFaces", K_XCORE::AdaptMesh_TriangulateFaces, METH_VARARGS}, {"AdaptMesh_GeneratePrisms", K_XCORE::AdaptMesh_GeneratePrisms, METH_VARARGS}, + {"AdaptMesh_AdaptGeom", K_XCORE::AdaptMesh_AdaptGeom, METH_VARARGS}, + {"AdaptMesh_ExtractTaggedFaces", K_XCORE::AdaptMesh_ExtractTaggedFaces, METH_VARARGS}, {"intersectMesh", K_XCORE::intersectMesh, METH_VARARGS}, {"removeIntersectingKPlanes", K_XCORE::removeIntersectingKPlanes, METH_VARARGS}, diff --git a/Cassiopee/XCore/XCore/xcore.h b/Cassiopee/XCore/XCore/xcore.h index f7487c57c..91512c42a 100644 --- a/Cassiopee/XCore/XCore/xcore.h +++ b/Cassiopee/XCore/XCore/xcore.h @@ -58,6 +58,8 @@ namespace K_XCORE PyObject *AdaptMesh_TagFaces(PyObject *self, PyObject *args); PyObject *AdaptMesh_TriangulateFaces(PyObject *self, PyObject *args); PyObject *AdaptMesh_GeneratePrisms(PyObject *self, PyObject *args); + PyObject *AdaptMesh_AdaptGeom(PyObject *self, PyObject *args); + PyObject *AdaptMesh_ExtractTaggedFaces(PyObject *self, PyObject *args); PyObject *intersectMesh(PyObject *self, PyObject *args); PyObject *removeIntersectingKPlanes(PyObject *self, PyObject *args); diff --git a/Cassiopee/XCore/srcs.py b/Cassiopee/XCore/srcs.py index 556bba5a1..24b751592 100644 --- a/Cassiopee/XCore/srcs.py +++ b/Cassiopee/XCore/srcs.py @@ -70,6 +70,7 @@ 'XCore/AdaptMesh/AdaptMesh_TagFaces.cpp', 'XCore/AdaptMesh/AdaptMesh_TriangulateFaces.cpp', 'XCore/AdaptMesh/AdaptMesh_GeneratePrisms.cpp', + 'XCore/AdaptMesh/AdaptMesh_AdaptGeom.cpp', 'XCore/AdaptMesh/MeshInit.cpp', 'XCore/AdaptMesh/MeshOrient.cpp', From f4926bfc11c2b81cfb1bf500a3a3b39bf9e0b8e1 Mon Sep 17 00:00:00 2001 From: Imad Date: Sun, 22 Sep 2024 22:03:01 +0200 Subject: [PATCH 04/86] XCore AdaptMesh: WIP --- .../XCore/AdaptMesh/AdaptMesh_AdaptGeom.cpp | 118 ++++++++++++++++-- 1 file changed, 105 insertions(+), 13 deletions(-) diff --git a/Cassiopee/XCore/XCore/AdaptMesh/AdaptMesh_AdaptGeom.cpp b/Cassiopee/XCore/XCore/AdaptMesh/AdaptMesh_AdaptGeom.cpp index ad2950bb6..2d90b3e13 100644 --- a/Cassiopee/XCore/XCore/AdaptMesh/AdaptMesh_AdaptGeom.cpp +++ b/Cassiopee/XCore/XCore/AdaptMesh/AdaptMesh_AdaptGeom.cpp @@ -35,8 +35,8 @@ void Mesh_extract_faces_from_ftag(Mesh *M, ArrayI *fids) void Mesh_extract_points_from_ftag(Mesh *M, ArrayI *pids) { - // WARNING(Imad): ptag is reset here - memset(M->ptag, 0, M->np * sizeof(E_Int)); + E_Int *ptag = (E_Int *)XMALLOC(M->np * sizeof(E_Int)); + memset(ptag, 0, M->np * sizeof(E_Int)); pids->count = 0; for (E_Int fid = 0; fid < M->nf; fid++) { @@ -47,8 +47,8 @@ void Mesh_extract_points_from_ftag(Mesh *M, ArrayI *pids) E_Int *pn = face + 2*i; for (E_Int j = 0; j < frange[i]; j++) { E_Int pid = pn[j]; - pids->count += (M->ptag[pid] == 0); - M->ptag[pid] = 1; + pids->count += (ptag[pid] == 0); + ptag[pid] = 1; } } } @@ -57,9 +57,11 @@ void Mesh_extract_points_from_ftag(Mesh *M, ArrayI *pids) E_Int *ptr = pids->ptr; for (E_Int pid = 0; pid < M->np; pid++) { - if (M->ptag[pid] == 1) + if (ptag[pid] == 1) *ptr++ = pid; } + + XFREE(ptag); } struct Box2D { @@ -154,11 +156,20 @@ struct TriBary { E_Float inv_denom; }; +#define MAX_FACES_PER_POINT 8 + +struct PointFaces { + E_Int count; + E_Int ptr[MAX_FACES_PER_POINT]; +}; + void Mesh_locate_spoints_in_mtris ( Mesh *S, ArrayI *spoints, Mesh *M, ArrayI *mtris, - Box2D box2D, GridFaces grid_faces[GRIDX][GRIDY], E_Int *sploc) + Box2D box2D, GridFaces grid_faces[GRIDX][GRIDY], + PointFaces *sploc +) { // Compute the mtris dot products once TriBary *tri_barys = (TriBary *)XMALLOC(mtris->count * sizeof(TriBary)); @@ -183,14 +194,18 @@ void Mesh_locate_spoints_in_mtris tri_barys[i].VV = vx*vx + vy*vy; tri_barys[i].UV = ux*vx + uy*vy; - tri_barys[i].inv_denom = 1.0 / (tri_barys[i].UU * tri_barys[i].VV - - tri_barys[i].UV * tri_barys[i].UV); + tri_barys[i].inv_denom = (tri_barys[i].UU * tri_barys[i].VV - + tri_barys[i].UV * tri_barys[i].UV); + + assert(tri_barys[i].inv_denom != 0.0); + + tri_barys[i].inv_denom = 1.0 / tri_barys[i].inv_denom; } E_Float HX = (box2D.xmax - box2D.xmin) / GRIDX; E_Float HY = (box2D.ymax - box2D.ymin) / GRIDY; - memset(sploc, -1, mtris->count * sizeof(E_Int)); + memset(sploc, 0, spoints->count * sizeof(PointFaces)); for (E_Int i = 0; i < spoints->count; i++) { E_Int spid = spoints->ptr[i]; @@ -209,6 +224,8 @@ void Mesh_locate_spoints_in_mtris abort(); }; + PointFaces *pfaces = &sploc[i]; + for (E_Int j = 0; j < grid->count; j++) { E_Int tidx = grid->ptr[j]; E_Int tid = mtris->ptr[tidx]; @@ -228,21 +245,57 @@ void Mesh_locate_spoints_in_mtris E_Float v = (tb->UU*d21 - tb->UV*d20) * tb->inv_denom; if (u >= 0.0 && v >= 0.0 && (u + v) <= 1.0) { - sploc[i] = tid; - break; + if (pfaces->count >= MAX_FACES_PER_POINT) { + fprintf(stderr, "MAX_FACES_PER_POINT reached!\n"); + abort(); + } + pfaces->ptr[pfaces->count++] = tid; } } - if (sploc[i] == -1) { + if (pfaces->count == 0) { fprintf(stderr, "Failed to locate point %d!\n", spid); abort(); } } +} + +#define MAX_POINTS_PER_TRI 1 + +void extract_faces_by_threshold +( + const PointFaces *sploc, E_Int spcount, + const ArrayI *mtris, + ArrayI *faces, + E_Int threshold +) +{ + E_Int *ftag = (E_Int *)XMALLOC(mtris->count * sizeof(E_Int)); + memset(ftag, 0, mtris->count * sizeof(E_Int)); + + for (E_Int i = 0; i < spcount; i++) { + const PointFaces *pfaces = &sploc[i]; + for (E_Int j = 0; j < pfaces->count; j++) + ftag[pfaces->ptr[j]]++; + } + + faces->count = 0; + for (E_Int i = 0; i < mtris->count; i++) { + if (ftag[i] > threshold) + faces->count++; + } + faces->ptr = (E_Int *)XMALLOC(faces->count * sizeof(E_Int)); + E_Int *ptr = faces->ptr; + for (E_Int i = 0; i < mtris->count; i++) { + if (ftag[i] > threshold) + *ptr++ = mtris->ptr[i]; + } } + PyObject *K_XCORE::AdaptMesh_AdaptGeom(PyObject *self, PyObject *args) { PyObject *AMESH, *SMESH; @@ -291,7 +344,7 @@ PyObject *K_XCORE::AdaptMesh_AdaptGeom(PyObject *self, PyObject *args) Mesh_2D_grid_faces(M, &mtris, box2D, grid_faces); // Locate spoints in mfaces - E_Int *sploc = (E_Int *)XMALLOC(spoints.count * sizeof(E_Int)); + PointFaces *sploc = (PointFaces *)XMALLOC(spoints.count * sizeof(PointFaces)); Mesh_locate_spoints_in_mtris ( S, &spoints, @@ -300,6 +353,45 @@ PyObject *K_XCORE::AdaptMesh_AdaptGeom(PyObject *self, PyObject *args) sploc ); + // Isolate triangles that contain more than MAX_POINTS_PER_TRI spoints + ArrayI rtris; + extract_faces_by_threshold + ( + sploc, spoints.count, + &mtris, &rtris, + MAX_POINTS_PER_TRI + ); + + /* + // We need the connectivity graph of the skin faces + Mesh_make_skin_graph(M); + + // Smooth out face refinement across the neighbouring skin faces + // We start from rfaces, which are all triangles + // Smoothing will yield: + // - neighbour triangles which need to be refined (set A) + // - neighbour quads which need to be turned into triangles (set B) + // The face owners of set A are prisms, they need to be refined + // The face owners of set B are still hexas -> update them into prisms + + ArrayI tfaces, qfaces; + Mesh_smooth_skin_refinement(M, &rfaces, &tfaces, &qfaces); + + // Turn qfaces owners into two prisms each + Mesh_generate_prisms(M, qfaces.ptr, qfaces.count); + + // Isolate refinement prisms + ArrayI rprisms; + Mesh_isolate_ref_prisms(M, &rfaces, &qfaces, &tfaces); + + // Smooth out cell refinement across the neighbouring cells + Mesh_smooth_cell_refinement(M, &rprisms); + */ + + + + + From 417c7d3fa30599e5b1e7543aac10f2a0c870f17b Mon Sep 17 00:00:00 2001 From: imadhammani Date: Mon, 23 Sep 2024 19:24:46 +0200 Subject: [PATCH 05/86] XCore AdaptMesh: BVH --- .../XCore/AdaptMesh/AdaptMesh_AdaptGeom.cpp | 560 +++++++++++------- Cassiopee/XCore/XCore/AdaptMesh/Mesh.h | 8 +- 2 files changed, 334 insertions(+), 234 deletions(-) diff --git a/Cassiopee/XCore/XCore/AdaptMesh/AdaptMesh_AdaptGeom.cpp b/Cassiopee/XCore/XCore/AdaptMesh/AdaptMesh_AdaptGeom.cpp index 2d90b3e13..51d52e3c3 100644 --- a/Cassiopee/XCore/XCore/AdaptMesh/AdaptMesh_AdaptGeom.cpp +++ b/Cassiopee/XCore/XCore/AdaptMesh/AdaptMesh_AdaptGeom.cpp @@ -1,7 +1,21 @@ #include "Mesh.h" #include "common/mem.h" -void point_print(E_Float px, E_Float py, E_Float pz) +struct Point { + E_Float x, y, z; +}; + +void points_write(const char *fname, const std::vector &P) +{ + FILE *fh = fopen(fname, "w"); + assert(fh); + fprintf(fh, "POINTS\n"); + fprintf(fh, "%zu\n", P.size()); + for (auto p : P) fprintf(fh, "%f %f %f\n", p.x, p.y, p.z); + fclose(fh); +} + +void point_write(E_Float px, E_Float py, E_Float pz) { FILE *fh = fopen("point", "w"); assert(fh); @@ -11,28 +25,16 @@ void point_print(E_Float px, E_Float py, E_Float pz) fclose(fh); } +void point_write(const Point p) +{ + return point_write(p.x, p.y, p.z); +} + struct ArrayI { E_Int count; E_Int *ptr; }; -void Mesh_extract_faces_from_ftag(Mesh *M, ArrayI *fids) -{ - fids->count = 0; - - for (E_Int i = 0; i < M->nf; i++) { - fids->count += (M->ftag[i] == 1); - } - - fids->ptr = (E_Int *)XMALLOC(fids->count * sizeof(E_Int)); - E_Int *ptr = fids->ptr; - - for (E_Int i = 0; i < M->nf; i++) { - if (M->ftag[i] == 1) - *ptr++ = i; - } -} - void Mesh_extract_points_from_ftag(Mesh *M, ArrayI *pids) { E_Int *ptag = (E_Int *)XMALLOC(M->np * sizeof(E_Int)); @@ -64,234 +66,354 @@ void Mesh_extract_points_from_ftag(Mesh *M, ArrayI *pids) XFREE(ptag); } -struct Box2D { - E_Float xmin, ymin; - E_Float xmax, ymax; +struct FaceSort { + E_Int fid; + E_Float fc[3]; + E_Float UX, UY, UZ; + E_Float VX, VY, VZ; + E_Float UU, VV, UV; + E_Float inv_denom; + E_Float xa, ya, za; }; -Box2D Mesh_box2D_faces(Mesh *M, ArrayI *fids) +void Mesh_extract_faces_from_ftag(const Mesh *M, FaceSort **mfaces, + E_Int *mcount) { - E_Float xmin, ymin, xmax, ymax; - xmin = ymin = 0xFFFFFFFF; - xmax = ymax = -xmin; + E_Int count = 0; - for (E_Int i = 0; i < fids->count; i++) { - E_Int fid = fids->ptr[i]; - E_Int *face = Mesh_get_face(M, fid); - E_Int *frange = Mesh_get_frange(M, fid); - for (E_Int j = 0; j < M->fstride[fid]; j++) { - E_Int *pn = face + 2*j; - for (E_Int k = 0; k < frange[j]; k++) { - E_Int pid = pn[k]; - if (M->X[pid] < xmin) xmin = M->X[pid]; - if (M->Y[pid] < ymin) ymin = M->Y[pid]; - if (M->X[pid] > xmax) xmax = M->X[pid]; - if (M->Y[pid] > ymax) ymax = M->Y[pid]; - } + for (E_Int i = 0; i < M->nf; i++) { + count += (M->ftag[i] == 1); + } + + *mfaces = (FaceSort *)XMALLOC(count * sizeof(FaceSort)); + + *mcount = count; + + count = 0; + + for (E_Int i = 0; i < M->nf; i++) { + if (M->ftag[i] == 1) { + assert(M->ftype[i] == TRI); + (*mfaces)[count++].fid = i; } } - // Safety - xmax = xmax + (xmax - xmin)*0.01; - ymax = ymax + (ymax - ymin)*0.01; + assert(*mcount == count); +} + +void FaceSort_compute_data(const Mesh *M, FaceSort *mfaces, E_Int mcount) +{ + for (E_Int i = 0; i < mcount; i++) { + FaceSort *face = &mfaces[i]; + + E_Int tid = face->fid; + assert(M->ftype[tid] == TRI); + + E_Int *tri = Mesh_get_face(M, tid); + E_Int A = tri[0], B = tri[2], C = tri[4]; + + face->UX = (M->X[B] - M->X[A]); + face->UY = (M->Y[B] - M->Y[A]); + face->UZ = (M->Z[B] - M->Z[A]); + + face->VX = (M->X[C] - M->X[A]); + face->VY = (M->Y[C] - M->Y[A]); + face->VZ = (M->Z[C] - M->Z[A]); - return { xmin, ymin, xmax, ymax }; + face->UU = face->UX*face->UX + face->UY*face->UY + face->UZ*face->UZ; + face->VV = face->VX*face->VX + face->VY*face->VY + face->VZ*face->VZ; + face->UV = face->UX*face->VX + face->UY*face->VY + face->UZ*face->VZ; + + face->inv_denom = face->UU*face->VV - face->UV*face->UV; + + assert(face->inv_denom != 0.0); + + face->inv_denom = 1.0 / face->inv_denom; + + face->fc[0] = (M->X[A] + M->X[B] + M->X[C]) / 3.0; + face->fc[1] = (M->Y[A] + M->Y[B] + M->Y[C]) / 3.0; + face->fc[2] = (M->Z[A] + M->Z[B] + M->Z[C]) / 3.0; + + // Store A + face->xa = M->X[A]; + face->ya = M->Y[A]; + face->za = M->Z[A]; + } } -#define MAX_FACES_PER_GRID 8 +/* +#define MAX_POINTS_PER_TRI 1 -struct GridFaces { - E_Int ptr[MAX_FACES_PER_GRID]; - E_Int count; +void extract_faces_by_threshold +( + const PointFaces *sploc, E_Int spcount, + const ArrayI *mtris, + ArrayI *faces, + E_Int threshold +) +{ + E_Int *ftag = (E_Int *)XMALLOC(mtris->count * sizeof(E_Int)); + memset(ftag, 0, mtris->count * sizeof(E_Int)); + + for (E_Int i = 0; i < spcount; i++) { + const PointFaces *pfaces = &sploc[i]; + for (E_Int j = 0; j < pfaces->count; j++) + ftag[pfaces->ptr[j]]++; + } + + faces->count = 0; + + for (E_Int i = 0; i < mtris->count; i++) { + if (ftag[i] > threshold) + faces->count++; + } + + faces->ptr = (E_Int *)XMALLOC(faces->count * sizeof(E_Int)); + E_Int *ptr = faces->ptr; + + for (E_Int i = 0; i < mtris->count; i++) { + if (ftag[i] > threshold) + *ptr++ = mtris->ptr[i]; + } +} +*/ + +struct Box3 { + E_Float xmin, ymin, zmin; + E_Float xmax, ymax, zmax; }; -#define GRIDX 64 -#define GRIDY 64 +inline +bool Box3_in_Box3(const Box3 small, const Box3 big) +{ + return (big.xmin <= small.xmin) && (big.xmax >= small.xmax) && + (big.ymin <= small.ymin) && (big.ymax >= small.ymax) && + (big.zmin <= small.zmin) && (big.zmax >= small.zmax); +} + +struct BVH_node { + Box3 box; + E_Int start, end; + BVH_node *left; + BVH_node *right; +}; -void Mesh_2D_grid_faces(Mesh *M, ArrayI *mfaces, Box2D box2D, - GridFaces grid_faces[GRIDX][GRIDY]) +Box3 Box3_make +( + const Mesh *M, + const FaceSort *mfaces, + E_Int start, E_Int end +) { - E_Float HX = (box2D.xmax - box2D.xmin) / GRIDX; - E_Float HY = (box2D.ymax - box2D.ymin) / GRIDY; + E_Float xmin, ymin, zmin, xmax, ymax, zmax; + xmin = ymin = zmin = FLT_MAX; + xmax = ymax = zmax = -FLT_MAX; - for (E_Int i = 0; i < mfaces->count; i++) { - E_Int fid = mfaces->ptr[i]; + for (E_Int i = start; i < end; i++) { + E_Int fid = mfaces[i].fid; E_Int *face = Mesh_get_face(M, fid); E_Int *frange = Mesh_get_frange(M, fid); - - E_Int minX = GRIDX, maxX = -1; - E_Int minY = GRIDY, maxY = -1; + assert(M->fstride[fid] == 3); + assert(M->ftype[fid] == TRI); for (E_Int j = 0; j < M->fstride[fid]; j++) { E_Int *pn = face + 2*j; + assert(frange[j] == 1); for (E_Int k = 0; k < frange[j]; k++) { E_Int pid = pn[k]; - E_Int grid_x = (M->X[pid] - box2D.xmin) / HX; - E_Int grid_y = (M->Y[pid] - box2D.ymin) / HY; - assert(grid_x >= 0 && grid_x < GRIDX); - assert(grid_y >= 0 && grid_y < GRIDY); - if (grid_x < minX) minX = grid_x; - if (grid_y < minY) minY = grid_y; - if (grid_x > maxX) maxX = grid_x; - if (grid_y > maxY) maxY = grid_y; - } - } + if (M->X[pid] < xmin) xmin = M->X[pid]; + if (M->Y[pid] < ymin) ymin = M->Y[pid]; + if (M->Z[pid] < zmin) zmin = M->Z[pid]; - for (E_Int grid_x = minX; grid_x <= maxX; grid_x++) { - for (E_Int grid_y = minY; grid_y <= maxY; grid_y++) { - GridFaces *grid = &grid_faces[grid_x][grid_y]; - if (grid->count >= MAX_FACES_PER_GRID) { - fprintf(stderr, "Grid is too coarse, refine it!\n"); - abort(); - } - grid->ptr[grid->count++] = i; // We need the index in mfaces, not the id + if (M->X[pid] > xmax) xmax = M->X[pid]; + if (M->Y[pid] > ymax) ymax = M->Y[pid]; + if (M->Z[pid] > zmax) zmax = M->Z[pid]; } } } -} -struct TriBary { - E_Float UX, UY; - E_Float VX, VY; - E_Float UU, VV, UV; - E_Float inv_denom; -}; + //printf("Before: {%f %f %f} {%f %f %f}\n",) -#define MAX_FACES_PER_POINT 8 + // Safety + E_Float dx = (xmax - xmin) * 0.01; + E_Float dy = (ymax - ymin) * 0.01; + E_Float dz = (zmax - zmin) * 0.01; + E_Float Xmin = xmin - dx; + E_Float Ymin = ymin - dy; + E_Float Zmin = zmin - dz; + E_Float Xmax = xmax + dx; + E_Float Ymax = ymax + dy; + E_Float Zmax = zmax + dz; + + return {Xmin, Ymin, Zmin, Xmax, Ymax, Zmax}; +} -struct PointFaces { - E_Int count; - E_Int ptr[MAX_FACES_PER_POINT]; -}; +static int idx = 0; -void Mesh_locate_spoints_in_mtris -( - Mesh *S, ArrayI *spoints, - Mesh *M, ArrayI *mtris, - Box2D box2D, GridFaces grid_faces[GRIDX][GRIDY], - PointFaces *sploc -) +BVH_node *BVH_create_node(const Box3 *box, E_Int start, E_Int end, + BVH_node *left, BVH_node *right) { - // Compute the mtris dot products once - TriBary *tri_barys = (TriBary *)XMALLOC(mtris->count * sizeof(TriBary)); - for (E_Int i = 0; i < mtris->count; i++) { - E_Int tid = mtris->ptr[i]; - assert(M->ftype[tid] == TRI); - E_Int *tri = Mesh_get_face(M, tid); - E_Int A = tri[0], B = tri[2], C = tri[4]; + BVH_node *node = (BVH_node *)XMALLOC(sizeof(BVH_node)); + node->box = *box; + node->start = start; + node->end = end; + node->left = left; + node->right = right; + //printf("%d -> %f %f %f %f %f %f\n", idx, box->xmin, box->ymin, box->zmin, + // box->xmax, box->ymax, box->zmax); + //idx++; + return node; +} - E_Float ux = (M->X[B] - M->X[A]); - E_Float uy = (M->Y[B] - M->Y[A]); - E_Float vx = (M->X[C] - M->X[A]); - E_Float vy = (M->Y[C] - M->Y[A]); +#define MAX_FACES_PER_BVH_LEAF 10 - tri_barys[i].UX = ux; - tri_barys[i].UY = uy; +void Box3_clamp(const Box3 *parent, Box3 *child) +{ + child->xmin = std::max(parent->xmin, child->xmin); + child->ymin = std::max(parent->ymin, child->ymin); + child->zmin = std::max(parent->zmin, child->zmin); + child->xmax = std::min(parent->xmax, child->xmax); + child->ymax = std::min(parent->ymax, child->ymax); + child->zmax = std::min(parent->zmax, child->zmax); +} - tri_barys[i].VX = vx; - tri_barys[i].VY = vy; +BVH_node *BVH_make(const Mesh *M, FaceSort *mfaces, E_Int start, E_Int end, + const Box3 *parent_box) +{ + Box3 box = Box3_make(M, mfaces, start, end); + Box3_clamp(parent_box, &box); + assert(Box3_in_Box3(box, *parent_box)); - tri_barys[i].UU = ux*ux + uy*uy; - tri_barys[i].VV = vx*vx + vy*vy; - tri_barys[i].UV = ux*vx + uy*vy; + E_Int count = end - start; + if (count <= MAX_FACES_PER_BVH_LEAF) { + return BVH_create_node(&box, start, end, NULL, NULL); + } - tri_barys[i].inv_denom = (tri_barys[i].UU * tri_barys[i].VV - - tri_barys[i].UV * tri_barys[i].UV); + E_Float dx = box.xmax - box.xmin; + E_Float dy = box.ymax - box.ymin; + E_Float dz = box.zmax - box.zmin; - assert(tri_barys[i].inv_denom != 0.0); + E_Int dim = -1; - tri_barys[i].inv_denom = 1.0 / tri_barys[i].inv_denom; + if (dx >= dy && dx >= dz) { + dim = 0; + } else if (dy >= dz) { + dim = 1; + } else { + dim = 2; } - E_Float HX = (box2D.xmax - box2D.xmin) / GRIDX; - E_Float HY = (box2D.ymax - box2D.ymin) / GRIDY; + std::sort(mfaces + start, mfaces + end, + [&](const FaceSort &fi, const FaceSort &fj) + { + return fi.fc[dim] < fj.fc[dim]; + }); + + E_Int mid = start + count/2; - memset(sploc, 0, spoints->count * sizeof(PointFaces)); + BVH_node *left = BVH_make(M, mfaces, start, mid, &box); + BVH_node *right = BVH_make(M, mfaces, mid, end, &box); - for (E_Int i = 0; i < spoints->count; i++) { - E_Int spid = spoints->ptr[i]; - E_Float px = S->X[spid]; - E_Float py = S->Y[spid]; - E_Int grid_x = (px - box2D.xmin) / HX; - E_Int grid_y = (py - box2D.ymin) / HY; - assert(grid_x >= 0); - assert(grid_x < GRIDX); - assert(grid_y >= 0); - assert(grid_y < GRIDY); - GridFaces *grid = &grid_faces[grid_x][grid_y]; - - if (grid->count == 0) { - fprintf(stderr, "No faces found in point grid!\n"); - abort(); - }; + assert(Box3_in_Box3(left->box, box)); + assert(Box3_in_Box3(right->box, box)); - PointFaces *pfaces = &sploc[i]; + return BVH_create_node(&box, start, end, left, right); +} - for (E_Int j = 0; j < grid->count; j++) { - E_Int tidx = grid->ptr[j]; - E_Int tid = mtris->ptr[tidx]; - assert(M->ftype[tid] == TRI); +#define MAX_FACES_PER_POINT 8 - E_Int *tri = Mesh_get_face(M, tid); - E_Int A = tri[0]; - E_Float DX = px - M->X[A]; - E_Float DY = py - M->Y[A]; +struct PointFaces { + E_Int count; + E_Int ptr[MAX_FACES_PER_POINT]; +}; - TriBary *tb = &tri_barys[tidx]; +#define TOL 1e-12 - E_Float d20 = DX*tb->UX + DY*tb->UY; - E_Float d21 = DX*tb->VX + DY*tb->VY; +bool Point_in_FaceSort(const Point *p, const FaceSort *f) +{ + E_Float DX = p->x - f->xa; + E_Float DY = p->y - f->ya; + E_Float DZ = p->z - f->za; + + E_Float d20 = DX*f->UX + DY*f->UY + DZ*f->UZ; + E_Float d21 = DX*f->VX + DY*f->VY + DZ*f->VZ; - E_Float u = (tb->VV*d20 - tb->UV*d21) * tb->inv_denom; - E_Float v = (tb->UU*d21 - tb->UV*d20) * tb->inv_denom; + E_Float u = (f->VV*d20 - f->UV*d21) * f->inv_denom; + if (u < -TOL || u > 1.0 + TOL) return false; - if (u >= 0.0 && v >= 0.0 && (u + v) <= 1.0) { - if (pfaces->count >= MAX_FACES_PER_POINT) { - fprintf(stderr, "MAX_FACES_PER_POINT reached!\n"); - abort(); - } - pfaces->ptr[pfaces->count++] = tid; - } - } + E_Float v = (f->UU*d21 - f->UV*d20) * f->inv_denom; + if (v < -TOL || v > 1.0 + TOL) return false; - if (pfaces->count == 0) { - fprintf(stderr, "Failed to locate point %d!\n", spid); - abort(); - } - } + E_Float w = 1.0 - (u + v); + if (w < -TOL || w > 1.0 + TOL) return false; + + return true; } -#define MAX_POINTS_PER_TRI 1 +bool Point_in_Box3D(const Point *p, const Box3 *box) +{ + return (p->x >= box->xmin) && (p->x <= box->xmax) && + (p->y >= box->ymin) && (p->y <= box->ymax) && + (p->z >= box->zmin) && (p->z <= box->zmax); +} -void extract_faces_by_threshold +void BVH_locate_point ( - const PointFaces *sploc, E_Int spcount, - const ArrayI *mtris, - ArrayI *faces, - E_Int threshold + const BVH_node *node, + const FaceSort *mfaces, + const Point *p, + PointFaces *pfaces ) { - E_Int *ftag = (E_Int *)XMALLOC(mtris->count * sizeof(E_Int)); - memset(ftag, 0, mtris->count * sizeof(E_Int)); + if (node->left == NULL && node->right == NULL) { + for (E_Int i = node->start; i < node->end; i++) { + const FaceSort *mface = &mfaces[i]; - for (E_Int i = 0; i < spcount; i++) { - const PointFaces *pfaces = &sploc[i]; - for (E_Int j = 0; j < pfaces->count; j++) - ftag[pfaces->ptr[j]]++; + if (Point_in_FaceSort(p, mface)) { + if (pfaces->count >= MAX_FACES_PER_POINT) { + fprintf(stderr, + "bvh_locate: MAX_FACES_PER_POINT exceeded!\n"); + abort(); + } + pfaces->ptr[pfaces->count++] = i; //mface->fid; + } + } + return; } - faces->count = 0; + assert(node->left && node->right); + assert(Box3_in_Box3(node->left->box, node->box)); + assert(Box3_in_Box3(node->right->box, node->box)); - for (E_Int i = 0; i < mtris->count; i++) { - if (ftag[i] > threshold) - faces->count++; - } + bool in_box = Point_in_Box3D(p, &node->box); + + if (!in_box) + return; - faces->ptr = (E_Int *)XMALLOC(faces->count * sizeof(E_Int)); - E_Int *ptr = faces->ptr; + BVH_locate_point(node->left, mfaces, p, pfaces); + BVH_locate_point(node->right, mfaces, p, pfaces); +} - for (E_Int i = 0; i < mtris->count; i++) { - if (ftag[i] > threshold) - *ptr++ = mtris->ptr[i]; +void locate_spoints_in_mtris +( + const Mesh *S, + const ArrayI *spoints, + const FaceSort *mfaces, + const BVH_node *bvh, + PointFaces *sploc +) +{ + for (E_Int i = 0; i < spoints->count; i++) { + E_Int spid = spoints->ptr[i]; + const Point p = {S->X[spid], S->Y[spid], S->Z[spid]}; + PointFaces *pfaces = &sploc[i]; + assert(Point_in_Box3D(&p, &bvh->box)); + BVH_locate_point(bvh, mfaces, &p, pfaces); + if (pfaces->count == 0) { + fprintf(stderr, "bvh_locate: failed at point index %d (%d)!\n", + i, spid); + point_write(p); + abort(); + } } } @@ -327,65 +449,46 @@ PyObject *K_XCORE::AdaptMesh_AdaptGeom(PyObject *self, PyObject *args) do { iter++; - // Sfaces are tagged + // Extract spoints from tagged sfaces ArrayI spoints; Mesh_extract_points_from_ftag(S, &spoints); // Spoints must belong to one of the tagged Mfaces - // All the tagged faces must be triangles - ArrayI mtris; - Mesh_extract_faces_from_ftag(M, &mtris); + FaceSort *mfaces = NULL; + E_Int mcount = 0; + Mesh_extract_faces_from_ftag(M, &mfaces, &mcount); + assert(mfaces); - // Box the mfaces - Box2D box2D = Mesh_box2D_faces(M, &mtris); - - // Grid the mfaces - GridFaces grid_faces[GRIDX][GRIDY] = {0}; - Mesh_2D_grid_faces(M, &mtris, box2D, grid_faces); + // Compute their centroids + FaceSort_compute_data(M, mfaces, mcount); + + // Build a BVH for mfaces + const Box3 huge = {-FLT_MAX, -FLT_MAX, -FLT_MAX, + FLT_MAX, FLT_MAX, FLT_MAX}; + BVH_node *bvh = BVH_make(M, mfaces, 0, mcount, &huge); + assert(bvh->start == 0); + assert(bvh->end == mcount); // Locate spoints in mfaces - PointFaces *sploc = (PointFaces *)XMALLOC(spoints.count * sizeof(PointFaces)); - Mesh_locate_spoints_in_mtris + PointFaces *sploc = + (PointFaces *)XMALLOC(spoints.count * sizeof(PointFaces)); + memset(sploc, 0, spoints.count * sizeof(PointFaces)); + locate_spoints_in_mtris ( S, &spoints, - M, &mtris, - box2D, grid_faces, + mfaces, bvh, sploc ); - // Isolate triangles that contain more than MAX_POINTS_PER_TRI spoints - ArrayI rtris; + /* + // Isolate faces that contain more than MAX_POINTS_PER_FACE spoints + ArrayI rfaces; extract_faces_by_threshold ( sploc, spoints.count, &mtris, &rtris, MAX_POINTS_PER_TRI ); - - /* - // We need the connectivity graph of the skin faces - Mesh_make_skin_graph(M); - - // Smooth out face refinement across the neighbouring skin faces - // We start from rfaces, which are all triangles - // Smoothing will yield: - // - neighbour triangles which need to be refined (set A) - // - neighbour quads which need to be turned into triangles (set B) - // The face owners of set A are prisms, they need to be refined - // The face owners of set B are still hexas -> update them into prisms - - ArrayI tfaces, qfaces; - Mesh_smooth_skin_refinement(M, &rfaces, &tfaces, &qfaces); - - // Turn qfaces owners into two prisms each - Mesh_generate_prisms(M, qfaces.ptr, qfaces.count); - - // Isolate refinement prisms - ArrayI rprisms; - Mesh_isolate_ref_prisms(M, &rfaces, &qfaces, &tfaces); - - // Smooth out cell refinement across the neighbouring cells - Mesh_smooth_cell_refinement(M, &rprisms); */ @@ -393,13 +496,10 @@ PyObject *K_XCORE::AdaptMesh_AdaptGeom(PyObject *self, PyObject *args) + // FREE - - - XFREE(spoints.ptr); - XFREE(mtris.ptr); - XFREE(sploc); } while (ref_S); + return Py_None; } diff --git a/Cassiopee/XCore/XCore/AdaptMesh/Mesh.h b/Cassiopee/XCore/XCore/AdaptMesh/Mesh.h index 9cf840ba0..ee406bbb4 100644 --- a/Cassiopee/XCore/XCore/AdaptMesh/Mesh.h +++ b/Cassiopee/XCore/XCore/AdaptMesh/Mesh.h @@ -228,19 +228,19 @@ E_Int Mesh_get_sizeNFace(Mesh *M) } inline -E_Int *Mesh_get_face(Mesh *M, E_Int fid) +E_Int *Mesh_get_face(const Mesh *M, E_Int fid) { return &M->faces[8*fid]; } inline -E_Int *Mesh_get_frange(Mesh *M, E_Int fid) +E_Int *Mesh_get_frange(const Mesh *M, E_Int fid) { return &M->frange[4*fid]; } inline -E_Int *Mesh_get_fedges(Mesh *M, E_Int fid) +E_Int *Mesh_get_fedges(const Mesh *M, E_Int fid) { return &M->fedg[8*fid]; } @@ -261,7 +261,7 @@ E_Int Mesh_get_sizeNGon(Mesh *M) inline -void Mesh_get_fpoints(Mesh *M, E_Int fid, E_Int &np, E_Int pts[8]) +void Mesh_get_fpoints(const Mesh *M, E_Int fid, E_Int &np, E_Int pts[8]) { np = 0; E_Int *face = Mesh_get_face(M, fid); From 9dfe84726f2e4065b25b07633618a7176021d634 Mon Sep 17 00:00:00 2001 From: Imad Date: Tue, 24 Sep 2024 01:02:46 +0200 Subject: [PATCH 06/86] XCore AdaptMesh: skin graph --- .../XCore/AdaptMesh/AdaptMesh_AdaptGeom.cpp | 284 ++++++++++++++---- 1 file changed, 228 insertions(+), 56 deletions(-) diff --git a/Cassiopee/XCore/XCore/AdaptMesh/AdaptMesh_AdaptGeom.cpp b/Cassiopee/XCore/XCore/AdaptMesh/AdaptMesh_AdaptGeom.cpp index 51d52e3c3..59770d006 100644 --- a/Cassiopee/XCore/XCore/AdaptMesh/AdaptMesh_AdaptGeom.cpp +++ b/Cassiopee/XCore/XCore/AdaptMesh/AdaptMesh_AdaptGeom.cpp @@ -141,43 +141,6 @@ void FaceSort_compute_data(const Mesh *M, FaceSort *mfaces, E_Int mcount) } } -/* -#define MAX_POINTS_PER_TRI 1 - -void extract_faces_by_threshold -( - const PointFaces *sploc, E_Int spcount, - const ArrayI *mtris, - ArrayI *faces, - E_Int threshold -) -{ - E_Int *ftag = (E_Int *)XMALLOC(mtris->count * sizeof(E_Int)); - memset(ftag, 0, mtris->count * sizeof(E_Int)); - - for (E_Int i = 0; i < spcount; i++) { - const PointFaces *pfaces = &sploc[i]; - for (E_Int j = 0; j < pfaces->count; j++) - ftag[pfaces->ptr[j]]++; - } - - faces->count = 0; - - for (E_Int i = 0; i < mtris->count; i++) { - if (ftag[i] > threshold) - faces->count++; - } - - faces->ptr = (E_Int *)XMALLOC(faces->count * sizeof(E_Int)); - E_Int *ptr = faces->ptr; - - for (E_Int i = 0; i < mtris->count; i++) { - if (ftag[i] > threshold) - *ptr++ = mtris->ptr[i]; - } -} -*/ - struct Box3 { E_Float xmin, ymin, zmin; E_Float xmax, ymax, zmax; @@ -231,23 +194,21 @@ Box3 Box3_make } } - //printf("Before: {%f %f %f} {%f %f %f}\n",) - // Safety E_Float dx = (xmax - xmin) * 0.01; E_Float dy = (ymax - ymin) * 0.01; E_Float dz = (zmax - zmin) * 0.01; - E_Float Xmin = xmin - dx; - E_Float Ymin = ymin - dy; - E_Float Zmin = zmin - dz; - E_Float Xmax = xmax + dx; - E_Float Ymax = ymax + dy; - E_Float Zmax = zmax + dz; - - return {Xmin, Ymin, Zmin, Xmax, Ymax, Zmax}; + xmin -= dx; + ymin -= dy; + zmin -= dz; + xmax += dx; + ymax += dy; + zmax += dz; + + return {xmin, ymin, zmin, xmax, ymax, zmax}; } -static int idx = 0; +//static int idx = 0; BVH_node *BVH_create_node(const Box3 *box, E_Int start, E_Int end, BVH_node *left, BVH_node *right) @@ -417,6 +378,211 @@ void locate_spoints_in_mtris } } +#define MAX_POINTS_PER_FACE 1 + +void extract_faces_by_threshold +( + const PointFaces *sploc, E_Int spcount, + const FaceSort *mtris, E_Int mcount, + const E_Int threshold, + ArrayI *faces +) +{ + E_Int *ftag = (E_Int *)XMALLOC(mcount * sizeof(E_Int)); + memset(ftag, 0, mcount * sizeof(E_Int)); + + for (E_Int i = 0; i < spcount; i++) { + const PointFaces *pfaces = &sploc[i]; + for (E_Int j = 0; j < pfaces->count; j++) + ftag[pfaces->ptr[j]]++; + } + + faces->count = 0; + + for (E_Int i = 0; i < mcount; i++) { + if (ftag[i] > threshold) + faces->count++; + } + + faces->ptr = (E_Int *)XMALLOC(faces->count * sizeof(E_Int)); + E_Int *ptr = faces->ptr; + + for (E_Int i = 0; i < mcount; i++) { + if (ftag[i] > threshold) + *ptr++ = mtris[i].fid; + } +} + +struct SkinGraph { + E_Int nf; + E_Int *skin; + E_Int *xadj; + E_Int *fpts; + E_Int *fnei; +}; + +void Mesh_extract_skin(const Mesh *M, E_Int *count, E_Int **skin) +{ + *count = 0; + + for (E_Int fid = 0; fid < M->nf; fid++) { + *count += (M->neigh[fid] == -1); + } + + *skin = (E_Int *)XMALLOC(*count * sizeof(E_Int)); + E_Int *ptr = *skin; + + for (E_Int fid = 0; fid < M->nf; fid++) { + if (M->neigh[fid] == -1) + *ptr++ = fid; + } +} + +void Mesh_make_skin_connectivity(const Mesh *M, SkinGraph *skin_graph) +{ + // Count + skin_graph->xadj = (E_Int *)XMALLOC((skin_graph->nf+1) * sizeof(E_Int)); + E_Int *xadj = skin_graph->xadj; + xadj[0] = 0; + + for (E_Int i = 0; i < skin_graph->nf; i++) { + E_Int fid = skin_graph->skin[i]; + const E_Int *frange = Mesh_get_frange(M, fid); + xadj[i+1] = 0; + for (E_Int j = 0; j < M->fstride[fid]; j++) + xadj[i+1] += frange[j]; + xadj[i+1] += xadj[i]; + } + + skin_graph->fpts = (E_Int *)XMALLOC(xadj[skin_graph->nf] * sizeof(E_Int)); + + // Populate + E_Int *ptr = skin_graph->fpts; + + for (E_Int i = 0; i < skin_graph->nf; i++) { + E_Int fid = skin_graph->skin[i]; + const E_Int *face = Mesh_get_face(M, fid); + const E_Int *frange = Mesh_get_frange(M, fid); + for (E_Int j = 0; j < M->fstride[fid]; j++) { + const E_Int *pn = face + 2*j; + for (E_Int k = 0; k < frange[j]; k++) + *ptr++ = pn[k]; + } + } +} + +struct EdgeNode { + E_Int p, q; + E_Int i, j; + E_Int posi, posj; + EdgeNode *next; +}; + +EdgeNode *make_edge_node(E_Int p, E_Int q, E_Int i, E_Int posi) +{ + EdgeNode *node = (EdgeNode *)XMALLOC(sizeof(EdgeNode)); + node->p = p < q ? p : q; + node->q = p < q ? q : p; + node->i = i; + node->posi = posi; + node->j = -1; + node->posj = -1; + node->next = NULL; + return node; +} + +EdgeNode *find_edge_node(EdgeNode **ht, E_Int hsize, E_Int p, E_Int q) +{ + E_Int p_ = p < q ? p : q; + E_Int q_ = p < q ? q : p; + E_Int bucket = p_ % hsize; + EdgeNode *current = ht[bucket]; + + while (current) { + E_Int P = current->p, Q = current->q; + if (P == p_ && Q == q_) { + return current; + } + current = current->next; + } + + return NULL; +} + +void insert_edge_node(EdgeNode *node, const E_Int hsize, EdgeNode **ht) +{ + assert(node->p < node->q); + E_Int bucket = node->p % hsize; + EdgeNode *current = ht[bucket]; + + if (current) { + EdgeNode *tmp = current; + ht[bucket] = node; + node->next = tmp; + } else { + ht[bucket] = node; + } +} + +void Mesh_make_skin_neighbours(const Mesh *M, SkinGraph *skin_graph) +{ + E_Int nf = skin_graph->nf; + const E_Int *xadj = skin_graph->xadj; + const E_Int *fpts = skin_graph->fpts; + + skin_graph->fnei = (E_Int *)XMALLOC(xadj[nf] * sizeof(E_Int)); + E_Int *fnei = skin_graph->fnei; + memset(fnei, -1, xadj[nf] * sizeof(E_Int)); + + EdgeNode **ht = (EdgeNode **)XMALLOC(nf * sizeof(EdgeNode *)); + memset(ht, 0, nf * sizeof(EdgeNode *)); + + for (E_Int i = 0; i < nf; i++) { + E_Int start = xadj[i]; + E_Int np = xadj[i+1] - start; + const E_Int *pn = &fpts[start]; + for (E_Int j = 0; j < np; j++) { + E_Int p = pn[j]; + E_Int q = pn[(j+1)%np]; + EdgeNode *node = find_edge_node(ht, nf, p, q); + if (node) { + assert(node->i != -1); + assert(node->posi != -1); + assert(node->j == -1); + assert(node->posj == -1); + node->j = i; + node->posj = j; + } else { + node = make_edge_node(p, q, i, j); + insert_edge_node(node, nf, ht); + } + } + } + + for (E_Int i = 0; i < nf; i++) { + EdgeNode *node = ht[i]; + while (node) { + E_Int pi = xadj[node->i] + node->posi; + assert(fnei[pi] == -1); + fnei[pi] = node->j; + + E_Int pj = xadj[node->j] + node->posj; + assert(fnei[pj] == -1); + fnei[pj] = node->i; + + node = node->next; + } + } +} + +void Mesh_make_skin_graph(Mesh *M, SkinGraph *skin_graph) +{ + Mesh_extract_skin(M, &skin_graph->nf, &skin_graph->skin); + Mesh_make_skin_connectivity(M, skin_graph); + Mesh_make_skin_neighbours(M, skin_graph); +} + + PyObject *K_XCORE::AdaptMesh_AdaptGeom(PyObject *self, PyObject *args) { @@ -443,7 +609,8 @@ PyObject *K_XCORE::AdaptMesh_AdaptGeom(PyObject *self, PyObject *args) // Refine M volumetric wrt to S tagged faces point cloud // Refine S surfacic wrt to M tagged faces point cloud - E_Int ref_M = 0, ref_S = 0; + //E_Int ref_M = 0; + E_Int ref_S = 0; E_Int iter = 0; do { @@ -453,10 +620,12 @@ PyObject *K_XCORE::AdaptMesh_AdaptGeom(PyObject *self, PyObject *args) ArrayI spoints; Mesh_extract_points_from_ftag(S, &spoints); + /* // Spoints must belong to one of the tagged Mfaces FaceSort *mfaces = NULL; E_Int mcount = 0; Mesh_extract_faces_from_ftag(M, &mfaces, &mcount); + printf("Mfaces: %d\n", mcount); assert(mfaces); // Compute their centroids @@ -466,8 +635,6 @@ PyObject *K_XCORE::AdaptMesh_AdaptGeom(PyObject *self, PyObject *args) const Box3 huge = {-FLT_MAX, -FLT_MAX, -FLT_MAX, FLT_MAX, FLT_MAX, FLT_MAX}; BVH_node *bvh = BVH_make(M, mfaces, 0, mcount, &huge); - assert(bvh->start == 0); - assert(bvh->end == mcount); // Locate spoints in mfaces PointFaces *sploc = @@ -480,18 +647,23 @@ PyObject *K_XCORE::AdaptMesh_AdaptGeom(PyObject *self, PyObject *args) sploc ); - /* // Isolate faces that contain more than MAX_POINTS_PER_FACE spoints ArrayI rfaces; extract_faces_by_threshold ( sploc, spoints.count, - &mtris, &rtris, - MAX_POINTS_PER_TRI + mfaces, mcount, + MAX_POINTS_PER_FACE, + &rfaces ); - */ - + printf("Refinement faces: %d\n", rfaces.count); + */ + + // We need the skin connectivity graph + SkinGraph skin_graph; + Mesh_make_skin_graph(M, &skin_graph); + printf("Skin: %d faces\n", skin_graph.nf); From 9ead563dac5ee5f5d18d0e2291710e59d41ad562 Mon Sep 17 00:00:00 2001 From: imadhammani Date: Tue, 24 Sep 2024 13:11:55 +0200 Subject: [PATCH 07/86] XCore AdaptMesh: BVH the whole skin --- .../XCore/AdaptMesh/AdaptMesh_AdaptGeom.cpp | 394 ++++++++++++++---- 1 file changed, 321 insertions(+), 73 deletions(-) diff --git a/Cassiopee/XCore/XCore/AdaptMesh/AdaptMesh_AdaptGeom.cpp b/Cassiopee/XCore/XCore/AdaptMesh/AdaptMesh_AdaptGeom.cpp index 59770d006..903af61a4 100644 --- a/Cassiopee/XCore/XCore/AdaptMesh/AdaptMesh_AdaptGeom.cpp +++ b/Cassiopee/XCore/XCore/AdaptMesh/AdaptMesh_AdaptGeom.cpp @@ -1,6 +1,8 @@ #include "Mesh.h" #include "common/mem.h" +// TODO(Imad): sorting routines + struct Point { E_Float x, y, z; }; @@ -317,73 +319,12 @@ bool Point_in_Box3D(const Point *p, const Box3 *box) (p->z >= box->zmin) && (p->z <= box->zmax); } -void BVH_locate_point -( - const BVH_node *node, - const FaceSort *mfaces, - const Point *p, - PointFaces *pfaces -) -{ - if (node->left == NULL && node->right == NULL) { - for (E_Int i = node->start; i < node->end; i++) { - const FaceSort *mface = &mfaces[i]; - - if (Point_in_FaceSort(p, mface)) { - if (pfaces->count >= MAX_FACES_PER_POINT) { - fprintf(stderr, - "bvh_locate: MAX_FACES_PER_POINT exceeded!\n"); - abort(); - } - pfaces->ptr[pfaces->count++] = i; //mface->fid; - } - } - return; - } - - assert(node->left && node->right); - assert(Box3_in_Box3(node->left->box, node->box)); - assert(Box3_in_Box3(node->right->box, node->box)); - - bool in_box = Point_in_Box3D(p, &node->box); - - if (!in_box) - return; - - BVH_locate_point(node->left, mfaces, p, pfaces); - BVH_locate_point(node->right, mfaces, p, pfaces); -} - -void locate_spoints_in_mtris -( - const Mesh *S, - const ArrayI *spoints, - const FaceSort *mfaces, - const BVH_node *bvh, - PointFaces *sploc -) -{ - for (E_Int i = 0; i < spoints->count; i++) { - E_Int spid = spoints->ptr[i]; - const Point p = {S->X[spid], S->Y[spid], S->Z[spid]}; - PointFaces *pfaces = &sploc[i]; - assert(Point_in_Box3D(&p, &bvh->box)); - BVH_locate_point(bvh, mfaces, &p, pfaces); - if (pfaces->count == 0) { - fprintf(stderr, "bvh_locate: failed at point index %d (%d)!\n", - i, spid); - point_write(p); - abort(); - } - } -} - #define MAX_POINTS_PER_FACE 1 void extract_faces_by_threshold ( const PointFaces *sploc, E_Int spcount, - const FaceSort *mtris, E_Int mcount, + const E_Int *skin, E_Int mcount, const E_Int threshold, ArrayI *faces ) @@ -409,7 +350,7 @@ void extract_faces_by_threshold for (E_Int i = 0; i < mcount; i++) { if (ftag[i] > threshold) - *ptr++ = mtris[i].fid; + *ptr++ = skin[i]; } } @@ -575,14 +516,296 @@ void Mesh_make_skin_neighbours(const Mesh *M, SkinGraph *skin_graph) } } -void Mesh_make_skin_graph(Mesh *M, SkinGraph *skin_graph) +void Mesh_make_skin_graph(const Mesh *M, SkinGraph *skin_graph) { Mesh_extract_skin(M, &skin_graph->nf, &skin_graph->skin); Mesh_make_skin_connectivity(M, skin_graph); Mesh_make_skin_neighbours(M, skin_graph); } +struct Vec3f { + E_Float x, y, z; +}; + +void Mesh_make_face_centers(const Mesh *M, const E_Int nf, const E_Int *skin, + Vec3f **fc) +{ + *fc = (Vec3f *)XMALLOC(nf * sizeof(Vec3f)); + Vec3f *ptr = *fc; + + for (E_Int i = 0; i < nf; i++) { + E_Int fid = skin[i]; + const E_Int *face = Mesh_get_face(M, fid); + const E_Int *frange = Mesh_get_frange(M, fid); + ptr[i].x = ptr[i].y = ptr[i].z = 0.0; + E_Int np = 0; + for (E_Int j = 0; j < M->fstride[fid]; j++) { + const E_Int *pn = face + 2*j; + for (E_Int k = 0; k < frange[j]; k++) { + ptr[i].x += M->X[pn[k]]; + ptr[i].y += M->Y[pn[k]]; + ptr[i].z += M->Z[pn[k]]; + np++; + } + } + ptr[i].x /= np; ptr[i].y /= np; ptr[i].z /= np; + } +} + +Box3 Box3_make +( + const Mesh *M, + const E_Int *skin, + const E_Int *indices, + E_Int start, E_Int end +) +{ + E_Float xmin, ymin, zmin, xmax, ymax, zmax; + xmin = ymin = zmin = FLT_MAX; + xmax = ymax = zmax = -FLT_MAX; + + for (E_Int i = start; i < end; i++) { + E_Int fid = skin[indices[i]]; + E_Int *face = Mesh_get_face(M, fid); + E_Int *frange = Mesh_get_frange(M, fid); + for (E_Int j = 0; j < M->fstride[fid]; j++) { + E_Int *pn = face + 2*j; + for (E_Int k = 0; k < frange[j]; k++) { + E_Int pid = pn[k]; + if (M->X[pid] < xmin) xmin = M->X[pid]; + if (M->Y[pid] < ymin) ymin = M->Y[pid]; + if (M->Z[pid] < zmin) zmin = M->Z[pid]; + + if (M->X[pid] > xmax) xmax = M->X[pid]; + if (M->Y[pid] > ymax) ymax = M->Y[pid]; + if (M->Z[pid] > zmax) zmax = M->Z[pid]; + } + } + } + + // Safety + E_Float dx = (xmax - xmin) * 0.01; + E_Float dy = (ymax - ymin) * 0.01; + E_Float dz = (zmax - zmin) * 0.01; + xmin -= dx; + ymin -= dy; + zmin -= dz; + xmax += dx; + ymax += dy; + zmax += dz; + + return {xmin, ymin, zmin, xmax, ymax, zmax}; +} + +BVH_node *BVH_make(const Mesh *M, const E_Int *skin, const Vec3f *fc, + E_Int *indices, E_Int start, E_Int end, const Box3 *parent_box) +{ + Box3 box = Box3_make(M, skin, indices, start, end); + Box3_clamp(parent_box, &box); + assert(Box3_in_Box3(box, *parent_box)); + + E_Int count = end - start; + if (count <= MAX_FACES_PER_BVH_LEAF) { + return BVH_create_node(&box, start, end, NULL, NULL); + } + + E_Float dx = box.xmax - box.xmin; + E_Float dy = box.ymax - box.ymin; + E_Float dz = box.zmax - box.zmin; + + E_Int dim = -1; + + if (dx >= dy && dx >= dz) { + dim = 0; + } else if (dy >= dz) { + dim = 1; + } else { + dim = 2; + } + + std::sort(indices + start, indices + end, + [&](const E_Int i, const E_Int j) + { + E_Float *fci = (E_Float *)(&fc[i]); + E_Float *fcj = (E_Float *)(&fc[j]); + return fci[dim] < fcj[dim]; + }); + + E_Int mid = start + count/2; + + BVH_node *left = BVH_make(M, skin, fc, indices, start, mid, &box); + BVH_node *right = BVH_make(M, skin, fc, indices, mid, end, &box); + + assert(Box3_in_Box3(left->box, box)); + assert(Box3_in_Box3(right->box, box)); + + return BVH_create_node(&box, start, end, left, right); +} + +bool point_in_tri(E_Float px, E_Float py, E_Float pz, + E_Float ax, E_Float ay, E_Float az, + E_Float bx, E_Float by, E_Float bz, + E_Float cx, E_Float cy, E_Float cz) +{ + // Normal vector to the plane + E_Float Y[3] = {bx-ax, by-ay, bz-az}; + E_Float Z[3] = {cx-ax, cy-ay, cz-az}; + E_Float N[3]; + K_MATH::cross(Y, Z, N); + + E_Float X[3] = {px-ax, py-ay, pz-az}; + + E_Float dp = K_MATH::dot(N, X, 3); + + // Is the point on the plane? + if (dp < -TOL || dp > TOL) return 0; + + E_Float x1 = K_MATH::dot(X, Y, 3); + E_Float y1 = K_MATH::dot(Y, Y, 3); + E_Float z1 = K_MATH::dot(Z, Y, 3); + E_Float x2 = K_MATH::dot(X, Z, 3); + E_Float y2 = K_MATH::dot(Y, Z, 3); + E_Float z2 = K_MATH::dot(Z, Z, 3); + + E_Float u = (x1*z2 - x2*z1) / (y1*z2 - y2*z1); + if (u < -TOL || u > 1 + TOL) return false; + + E_Float v = (-x1*y2 + x2*y1) / (y1*z2 - y2*z1); + if (v < -TOL || v > 1 + TOL) return false; + + E_Float w = 1 - u - v; + if (w < -TOL || w > 1 + TOL) return false; + + return true; +} + +bool Mesh_point_in_tri(const Mesh *M, const Point *p, E_Int tid) +{ + const E_Int *face = Mesh_get_face(M, tid); + E_Int A = face[0], B = face[2], C = face[4]; + return point_in_tri(p->x, p->y, p->z, + M->X[A], M->Y[A], M->Z[A], + M->X[B], M->Y[B], M->Z[B], + M->X[C], M->Y[C], M->Z[C]); +} + +bool Mesh_point_in_quad(const Mesh *M, const Point *p, E_Int qid) +{ + // TODO(Imad): maybe compute face centers once in pre-pass + // Star the quad into 4 triangles + E_Float O[3] = {0.0, 0.0, 0.0}; + const E_Int *face = Mesh_get_face(M, qid); + E_Int A = face[0], B = face[2], C = face[4], D = face[6]; + O[0] = (M->X[A] + M->X[B] + M->X[C] + M->X[D]) * 0.25; + O[1] = (M->Y[A] + M->Y[B] + M->Y[C] + M->Y[D]) * 0.25; + O[2] = (M->Z[A] + M->Z[B] + M->Z[C] + M->Z[D]) * 0.25; + + bool hit = false; + + // First triangle + hit = point_in_tri(p->x, p->y, p->z, + O[0], O[1], O[2], + M->X[A], M->Y[A], M->Z[A], + M->X[B], M->Y[B], M->Z[B]); + if (hit) return true; + + // Second triangle + hit = point_in_tri(p->x, p->y, p->z, + O[0], O[1], O[2], + M->X[B], M->Y[B], M->Z[B], + M->X[C], M->Y[C], M->Z[C]); + if (hit) return true; + + + // Third triangle + hit = point_in_tri(p->x, p->y, p->z, + O[0], O[1], O[2], + M->X[C], M->Y[C], M->Z[C], + M->X[D], M->Y[D], M->Z[D]); + if (hit) return true; + + // Fourth triangle + hit = point_in_tri(p->x, p->y, p->z, + O[0], O[1], O[2], + M->X[D], M->Y[D], M->Z[D], + M->X[A], M->Y[A], M->Z[A]); + if (hit) return true; + + return false; +} + +bool Mesh_point_in_face(const Mesh *M, const Point *p, E_Int fid) +{ + if (M->ftype[fid] == QUAD) return Mesh_point_in_quad(M, p, fid); + assert(M->ftype[fid] == TRI); + return Mesh_point_in_tri(M, p, fid); +} + +void BVH_locate_point +( + const BVH_node *node, + const Mesh *M, + const E_Int *skin, + const E_Int *indices, + const Point *p, + PointFaces *pfaces +) +{ + if (node->left == NULL && node->right == NULL) { + for (E_Int i = node->start; i < node->end; i++) { + E_Int fid = skin[indices[i]]; + + if (Mesh_point_in_face(M, p, fid)) { + if (pfaces->count >= MAX_FACES_PER_POINT) { + fprintf(stderr, + "bvh_locate: MAX_FACES_PER_POINT exceeded!\n"); + abort(); + } + pfaces->ptr[pfaces->count++] = i; + } + } + return; + } + + assert(node->left && node->right); + assert(Box3_in_Box3(node->left->box, node->box)); + assert(Box3_in_Box3(node->right->box, node->box)); + + bool in_box = Point_in_Box3D(p, &node->box); + + if (!in_box) + return; + + BVH_locate_point(node->left, M, skin, indices, p, pfaces); + BVH_locate_point(node->right, M, skin, indices, p, pfaces); +} + +void locate_spoints_in_mskin +( + const Mesh *S, + const ArrayI *spoints, + const Mesh *M, + const E_Int *skin, + const E_Int *indices, + const BVH_node *bvh, + PointFaces *sploc +) +{ + for (E_Int i = 0; i < spoints->count; i++) { + E_Int spid = spoints->ptr[i]; + const Point p = {S->X[spid], S->Y[spid], S->Z[spid]}; + PointFaces *pfaces = &sploc[i]; + assert(Point_in_Box3D(&p, &bvh->box)); + BVH_locate_point(bvh, M, skin, indices, &p, pfaces); + if (pfaces->count == 0) { + fprintf(stderr, "bvh_locate: failed at point index %d (%d)!\n", + i, spid); + point_write(p); + abort(); + } + } +} PyObject *K_XCORE::AdaptMesh_AdaptGeom(PyObject *self, PyObject *args) { @@ -647,25 +870,50 @@ PyObject *K_XCORE::AdaptMesh_AdaptGeom(PyObject *self, PyObject *args) sploc ); + + + + */ + + // We need the skin connectivity graph + SkinGraph skin_graph; + Mesh_make_skin_graph(M, &skin_graph); + printf("Skin: %d faces\n", skin_graph.nf); + + // BVH the skin + Vec3f *skin_fc; + Mesh_make_face_centers(M, skin_graph.nf, skin_graph.skin, &skin_fc); + E_Int *indices = (E_Int *)XMALLOC(skin_graph.nf * sizeof(E_Int)); + for (E_Int i = 0; i < skin_graph.nf; i++) indices[i] = i; + const Box3 huge = {-FLT_MAX, -FLT_MAX, -FLT_MAX, + FLT_MAX, FLT_MAX, FLT_MAX}; + BVH_node *bvh = BVH_make(M, skin_graph.skin, skin_fc, indices, 0, + skin_graph.nf, &huge); + puts("ok bvh"); + + // Locate spoints in skin + PointFaces *sploc = + (PointFaces *)XMALLOC(spoints.count * sizeof(PointFaces)); + memset(sploc, 0, spoints.count * sizeof(PointFaces)); + locate_spoints_in_mskin + ( + S, &spoints, + M, skin_graph.skin, indices, + bvh, + sploc + ); + // Isolate faces that contain more than MAX_POINTS_PER_FACE spoints ArrayI rfaces; extract_faces_by_threshold ( sploc, spoints.count, - mfaces, mcount, + skin_graph.skin, skin_graph.nf, MAX_POINTS_PER_FACE, &rfaces ); printf("Refinement faces: %d\n", rfaces.count); - */ - - // We need the skin connectivity graph - SkinGraph skin_graph; - Mesh_make_skin_graph(M, &skin_graph); - printf("Skin: %d faces\n", skin_graph.nf); - - // FREE From be4244abf1ce29cf4a9c3af2721690ec2276525c Mon Sep 17 00:00:00 2001 From: imadhammani Date: Tue, 24 Sep 2024 13:46:22 +0200 Subject: [PATCH 08/86] XCore AdaptMesh: fixed mesh_smooth_cref_local --- Cassiopee/XCore/XCore/AdaptMesh/MeshSmooth.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/Cassiopee/XCore/XCore/AdaptMesh/MeshSmooth.cpp b/Cassiopee/XCore/XCore/AdaptMesh/MeshSmooth.cpp index d48810d6c..e574f6004 100644 --- a/Cassiopee/XCore/XCore/AdaptMesh/MeshSmooth.cpp +++ b/Cassiopee/XCore/XCore/AdaptMesh/MeshSmooth.cpp @@ -61,11 +61,12 @@ E_Int Mesh_smooth_cref_local(Mesh *M) E_Int neis[24]; Mesh_get_cneis(M, cid, nn, neis); - E_Int incr_cell = M->cref[cid] + M->clevel[cid]; + //E_Int incr_cell = M->cref[cid] + M->clevel[cid]; for (E_Int i = 0; i < nn; i++) { E_Int nei = neis[i]; + E_Int incr_cell = M->cref[cid] + M->clevel[cid]; E_Int incr_nei = M->cref[nei] + M->clevel[nei]; E_Int diff = abs(incr_nei - incr_cell); @@ -74,7 +75,8 @@ E_Int Mesh_smooth_cref_local(Mesh *M) E_Int cell_to_mod = incr_cell > incr_nei ? nei : cid; - M->cref[cell_to_mod] += 1; + M->cref[cell_to_mod] += diff-1; + //M->cref[cell_to_mod] += 1; stk.push(cell_to_mod); } From 20221092195c60821646ec7c1cf32c2bd8a0d62f Mon Sep 17 00:00:00 2001 From: imadhammani Date: Tue, 24 Sep 2024 17:58:48 +0200 Subject: [PATCH 09/86] XCore AdaptMesh: refactoring --- .../XCore/XCore/AdaptMesh/AdaptMesh_Init.cpp | 7 +- Cassiopee/XCore/XCore/AdaptMesh/H27.cpp | 20 ++++++ Cassiopee/XCore/XCore/AdaptMesh/Hexa.h | 23 +----- Cassiopee/XCore/XCore/AdaptMesh/Mesh.h | 70 ++++++++++++++++++- Cassiopee/XCore/XCore/AdaptMesh/MeshDir.cpp | 57 --------------- .../XCore/XCore/AdaptMesh/MeshRefine.cpp | 2 +- .../XCore/XCore/AdaptMesh/MeshSmooth.cpp | 19 ++--- Cassiopee/XCore/XCore/AdaptMesh/Q6.cpp | 1 + Cassiopee/XCore/XCore/AdaptMesh/Q9.cpp | 13 ++++ Cassiopee/XCore/XCore/AdaptMesh/Quad.h | 16 +---- 10 files changed, 121 insertions(+), 107 deletions(-) diff --git a/Cassiopee/XCore/XCore/AdaptMesh/AdaptMesh_Init.cpp b/Cassiopee/XCore/XCore/AdaptMesh/AdaptMesh_Init.cpp index c0cb00b75..6f732deeb 100644 --- a/Cassiopee/XCore/XCore/AdaptMesh/AdaptMesh_Init.cpp +++ b/Cassiopee/XCore/XCore/AdaptMesh/AdaptMesh_Init.cpp @@ -237,8 +237,11 @@ PyObject *K_XCORE::AdaptMesh_Init(PyObject *self, PyObject *args) M->fparent = IntArray(M->nf); for (E_Int i = 0; i < M->nf; i++) M->fparent[i] = i; - M->cref = IntArray(M->nc); - M->fref = IntArray(M->nf); + //M->cref = IntArray(M->nc); + //M->fref = IntArray(M->nf); + + M->cref = NULL; + M->fref = NULL; M->ctag = IntArray(M->nc); M->ftag = IntArray(M->nf); diff --git a/Cassiopee/XCore/XCore/AdaptMesh/H27.cpp b/Cassiopee/XCore/XCore/AdaptMesh/H27.cpp index 1eec0864a..1347b98f7 100644 --- a/Cassiopee/XCore/XCore/AdaptMesh/H27.cpp +++ b/Cassiopee/XCore/XCore/AdaptMesh/H27.cpp @@ -1,5 +1,6 @@ #include "Hexa.h" #include "Quad.h" +#include "Mesh.h" void H27_refine(E_Int hexa, Mesh *M) { @@ -1515,4 +1516,23 @@ E_Int check_canon_hexa(E_Int hexa, Mesh *M) assert(local[3] == NODES[7]); return 0; +} + +void update_range_and_stride(Mesh *M, E_Int hexa, E_Int cpos, E_Int nchildren) +{ + E_Int *crange = Mesh_get_crange(M, hexa); + for (E_Int i = 0; i < M->cstride[hexa]; i++) { + crange[i] = 1; + } + + for (E_Int i = 0; i < nchildren; i++) { + E_Int child = cpos + i; + + M->cstride[child] = M->cstride[hexa]; + + crange = Mesh_get_crange(M, child); + for (E_Int j = 0; j < M->cstride[child]; j++) { + crange[j] = 1; + } + } } \ No newline at end of file diff --git a/Cassiopee/XCore/XCore/AdaptMesh/Hexa.h b/Cassiopee/XCore/XCore/AdaptMesh/Hexa.h index 1deed754c..b2275e915 100644 --- a/Cassiopee/XCore/XCore/AdaptMesh/Hexa.h +++ b/Cassiopee/XCore/XCore/AdaptMesh/Hexa.h @@ -19,7 +19,8 @@ #pragma once #include "common/common.h" -#include "Mesh.h" + +struct Mesh; const E_Int normalIn_H[6] = {1, 0, 1, 0, 1, 0}; @@ -33,22 +34,4 @@ void H18_reorder(E_Int hexa, Mesh *M); E_Int check_canon_hexa(E_Int hexa, Mesh *M); -inline -void update_range_and_stride(Mesh *M, E_Int hexa, E_Int cpos, E_Int nchildren) -{ - E_Int *crange = Mesh_get_crange(M, hexa); - for (E_Int i = 0; i < M->cstride[hexa]; i++) { - crange[i] = 1; - } - - for (E_Int i = 0; i < nchildren; i++) { - E_Int child = cpos + i; - - M->cstride[child] = M->cstride[hexa]; - - crange = Mesh_get_crange(M, child); - for (E_Int j = 0; j < M->cstride[child]; j++) { - crange[j] = 1; - } - } -} +void update_range_and_stride(Mesh *M, E_Int hexa, E_Int cpos, E_Int nchildren); diff --git a/Cassiopee/XCore/XCore/AdaptMesh/Mesh.h b/Cassiopee/XCore/XCore/AdaptMesh/Mesh.h index ee406bbb4..75220eaf1 100644 --- a/Cassiopee/XCore/XCore/AdaptMesh/Mesh.h +++ b/Cassiopee/XCore/XCore/AdaptMesh/Mesh.h @@ -24,6 +24,8 @@ #include "xcore.h" #include "common/common.h" +#include "Quad.h" +#include "Hexa.h" #define HEXA 0 #define TETRA 1 @@ -37,6 +39,9 @@ #define FACE_REFINED 1 #define FACE_NEW 2 +#define ISO 0 +#define DIR 1 + struct Karray; struct BPatch { @@ -177,8 +182,6 @@ struct Mesh { E_Int Mesh_set_cells_for_2D(Mesh *M); -void Mesh_get_cneis(Mesh *M, E_Int cid, E_Int &nn, E_Int neis[24]); - E_Int Mesh_set_face_types(Mesh *M); E_Int Mesh_set_cell_types(Mesh *M); @@ -201,6 +204,15 @@ void Mesh_update_global_face_ids(Mesh *M); E_Int Mesh_get_global_face_count(Mesh *M); +void Mesh_get_cneis(Mesh *M, E_Int cid, E_Int &nn, E_Int neis[24]); + +inline +E_Int Mesh_get_cnei(Mesh *M, E_Int cid, E_Int fid) +{ + assert(cid == M->owner[fid] || cid == M->neigh[fid]); + return (M->owner[fid] == cid) ? M->neigh[fid] : M->owner[fid]; +} + inline E_Int *Mesh_get_cell(Mesh *M, E_Int cid) { @@ -433,6 +445,60 @@ void Mesh_refine_or_get_edge_center(Mesh *M, E_Int p, E_Int q, E_Int &node) } } +inline +void refine_cell_dir(E_Int cell, Mesh *M) +{ + switch (M->ctype[cell]) { + case HEXA: + H18_refine(cell, M); + break; + default: + assert(0); + break; + } +} + +inline +void refine_face_dir(E_Int face, E_Int pattern, Mesh *M) +{ + switch (M->ftype[face]) { + case QUAD: { + if (pattern == ISO) Q9_refine(face, M); + else Q6_refine(face, M); + break; + } + default: + assert(0); + break; + } +} + +inline +E_Int get_face_pattern(E_Int fid, Mesh *M) +{ + E_Int own = M->owner[fid]; + E_Int fpos = -1; + E_Int *cell = Mesh_get_cell(M, own); + E_Int *crange = Mesh_get_crange(M, own); + + for (E_Int j = 0; j < M->cstride[own] && fpos == -1; j++) { + E_Int *pf = cell + 4*j; + for (E_Int k = 0; k < crange[j]; k++) { + E_Int face = pf[k]; + if (face == fid) { + fpos = j; + assert(k == 0); + break; + } + } + } + + assert(fpos != -1); + + if (fpos == 0 || fpos == 1) return ISO; + return DIR; +} + void Mesh_triangulate_face(Mesh *M, E_Int fid); void Mesh_triangulate_faces(Mesh *M, E_Int *faces, E_Int nf); diff --git a/Cassiopee/XCore/XCore/AdaptMesh/MeshDir.cpp b/Cassiopee/XCore/XCore/AdaptMesh/MeshDir.cpp index 31a6655f9..f776a96c3 100644 --- a/Cassiopee/XCore/XCore/AdaptMesh/MeshDir.cpp +++ b/Cassiopee/XCore/XCore/AdaptMesh/MeshDir.cpp @@ -22,63 +22,6 @@ #include "Quad.h" #include "Edge.h" -#define ISO 0 -#define DIR 1 - -static inline -void refine_cell_dir(E_Int cell, Mesh *M) -{ - switch (M->ctype[cell]) { - case HEXA: - H18_refine(cell, M); - break; - default: - assert(0); - break; - } -} - -static inline -void refine_face_dir(E_Int face, E_Int pattern, Mesh *M) -{ - switch (M->ftype[face]) { - case QUAD: { - if (pattern == ISO) Q9_refine(face, M); - else Q6_refine(face, M); - break; - } - default: - assert(0); - break; - } -} - -static inline -E_Int get_face_pattern(E_Int fid, Mesh *M) -{ - E_Int own = M->owner[fid]; - E_Int fpos = -1; - E_Int *cell = Mesh_get_cell(M, own); - E_Int *crange = Mesh_get_crange(M, own); - - for (E_Int j = 0; j < M->cstride[own] && fpos == -1; j++) { - E_Int *pf = cell + 4*j; - for (E_Int k = 0; k < crange[j]; k++) { - E_Int face = pf[k]; - if (face == fid) { - fpos = j; - assert(k == 0); - break; - } - } - } - - assert(fpos != -1); - - if (fpos == 0 || fpos == 1) return ISO; - return DIR; -} - void Mesh_refine_dir(Mesh *M, std::vector &ref_cells, std::vector &ref_faces, std::set &ref_edges) { diff --git a/Cassiopee/XCore/XCore/AdaptMesh/MeshRefine.cpp b/Cassiopee/XCore/XCore/AdaptMesh/MeshRefine.cpp index 1e89d44df..c22e8fc29 100644 --- a/Cassiopee/XCore/XCore/AdaptMesh/MeshRefine.cpp +++ b/Cassiopee/XCore/XCore/AdaptMesh/MeshRefine.cpp @@ -119,7 +119,7 @@ void Mesh_resize_for_refinement(Mesh *M, const std::vector &ref_cells, E_Int cell_incr = ref_cells.size() * 7; - // 3 new faces per refined faces + 13 new faces per refined cell + // 3 new faces per refined face + 12 new faces per refined cell E_Int face_incr = ref_faces.size() * 3 + ref_cells.size() * 12; diff --git a/Cassiopee/XCore/XCore/AdaptMesh/MeshSmooth.cpp b/Cassiopee/XCore/XCore/AdaptMesh/MeshSmooth.cpp index e574f6004..1f1d7fb93 100644 --- a/Cassiopee/XCore/XCore/AdaptMesh/MeshSmooth.cpp +++ b/Cassiopee/XCore/XCore/AdaptMesh/MeshSmooth.cpp @@ -21,26 +21,22 @@ #include "Mesh.h" #include "common/mem.h" -inline -E_Int Mesh_get_cnei(Mesh *M, E_Int cid, E_Int fid) -{ - assert(cid == M->owner[fid] || cid == M->neigh[fid]); - return (M->owner[fid] == cid) ? M->neigh[fid] : M->owner[fid]; -} - void Mesh_get_cneis(Mesh *M, E_Int cid, E_Int &nn, E_Int neis[24]) { E_Int *cell = Mesh_get_cell(M, cid); E_Int *crange = Mesh_get_crange(M, cid); E_Int cstride = M->cstride[cid]; + nn = 0; + for (E_Int i = 0; i < cstride; i++) { E_Int *pf = cell + 4*i; for (E_Int j = 0; j < crange[i]; j++) { E_Int face = pf[j]; E_Int nei = Mesh_get_cnei(M, cid, face); - if (nei != -1) neis[nn++] = nei; + if (nei != -1 && nei != neis[nn]) + neis[nn++] = nei; } } } @@ -57,8 +53,7 @@ E_Int Mesh_smooth_cref_local(Mesh *M) E_Int cid = stk.top(); stk.pop(); - E_Int nn = 0; - E_Int neis[24]; + E_Int nn, neis[24]; Mesh_get_cneis(M, cid, nn, neis); //E_Int incr_cell = M->cref[cid] + M->clevel[cid]; @@ -75,8 +70,8 @@ E_Int Mesh_smooth_cref_local(Mesh *M) E_Int cell_to_mod = incr_cell > incr_nei ? nei : cid; - M->cref[cell_to_mod] += diff-1; - //M->cref[cell_to_mod] += 1; + //M->cref[cell_to_mod] += diff-1; + M->cref[cell_to_mod] += 1; stk.push(cell_to_mod); } diff --git a/Cassiopee/XCore/XCore/AdaptMesh/Q6.cpp b/Cassiopee/XCore/XCore/AdaptMesh/Q6.cpp index 02fc61323..1030c4c9e 100644 --- a/Cassiopee/XCore/XCore/AdaptMesh/Q6.cpp +++ b/Cassiopee/XCore/XCore/AdaptMesh/Q6.cpp @@ -17,6 +17,7 @@ along with Cassiopee. If not, see . */ #include "Quad.h" +#include "Mesh.h" E_Int Q6_refine(E_Int quad, Mesh *M) { diff --git a/Cassiopee/XCore/XCore/AdaptMesh/Q9.cpp b/Cassiopee/XCore/XCore/AdaptMesh/Q9.cpp index 3b7ad22ca..4545ceea3 100644 --- a/Cassiopee/XCore/XCore/AdaptMesh/Q9.cpp +++ b/Cassiopee/XCore/XCore/AdaptMesh/Q9.cpp @@ -17,6 +17,7 @@ along with Cassiopee. If not, see . */ #include "Quad.h" +#include "Mesh.h" E_Int Q9_refine(E_Int quad, Mesh *M) { @@ -166,3 +167,15 @@ void Q4_reorder(E_Int *pn, E_Int reorient, E_Int i0, E_Int local[4]) Right_shift(local, i0, 4); if (reorient) std::swap(local[1], local[3]); } + +void refine_face_iso(E_Int face, Mesh *M) +{ + switch (M->ftype[face]) { + case QUAD: + Q9_refine(face, M); + break; + default: + assert(0); + break; + } +} \ No newline at end of file diff --git a/Cassiopee/XCore/XCore/AdaptMesh/Quad.h b/Cassiopee/XCore/XCore/AdaptMesh/Quad.h index b5f99ad07..1035ddca7 100644 --- a/Cassiopee/XCore/XCore/AdaptMesh/Quad.h +++ b/Cassiopee/XCore/XCore/AdaptMesh/Quad.h @@ -19,7 +19,8 @@ #pragma once #include "common/common.h" -#include "Mesh.h" + +struct Mesh; E_Int Q9_refine(E_Int quad, Mesh *M); @@ -27,15 +28,4 @@ E_Int Q6_refine(E_Int quad, Mesh *M); void Q4_reorder(E_Int *pn, E_Int reorient, E_Int i0, E_Int local[4]); -inline -void refine_face_iso(E_Int face, Mesh *M) -{ - switch (M->ftype[face]) { - case QUAD: - Q9_refine(face, M); - break; - default: - assert(0); - break; - } -} \ No newline at end of file +void refine_face_iso(E_Int face, Mesh *M); From f9fdbc699d6d79dec9423783d6095261acc18195 Mon Sep 17 00:00:00 2001 From: imadhammani Date: Tue, 24 Sep 2024 18:00:02 +0200 Subject: [PATCH 10/86] XCore AdaptMesh: need to precompute face refinement direction for non-isotropic adaptation --- .../XCore/AdaptMesh/AdaptMesh_AdaptGeom.cpp | 428 ++++++++++++++++-- 1 file changed, 382 insertions(+), 46 deletions(-) diff --git a/Cassiopee/XCore/XCore/AdaptMesh/AdaptMesh_AdaptGeom.cpp b/Cassiopee/XCore/XCore/AdaptMesh/AdaptMesh_AdaptGeom.cpp index 903af61a4..770983537 100644 --- a/Cassiopee/XCore/XCore/AdaptMesh/AdaptMesh_AdaptGeom.cpp +++ b/Cassiopee/XCore/XCore/AdaptMesh/AdaptMesh_AdaptGeom.cpp @@ -350,7 +350,7 @@ void extract_faces_by_threshold for (E_Int i = 0; i < mcount; i++) { if (ftag[i] > threshold) - *ptr++ = skin[i]; + *ptr++ = i;//skin[i]; } } @@ -528,27 +528,24 @@ struct Vec3f { }; void Mesh_make_face_centers(const Mesh *M, const E_Int nf, const E_Int *skin, - Vec3f **fc) + Vec3f *fc) { - *fc = (Vec3f *)XMALLOC(nf * sizeof(Vec3f)); - Vec3f *ptr = *fc; - for (E_Int i = 0; i < nf; i++) { E_Int fid = skin[i]; const E_Int *face = Mesh_get_face(M, fid); const E_Int *frange = Mesh_get_frange(M, fid); - ptr[i].x = ptr[i].y = ptr[i].z = 0.0; + fc[i].x = fc[i].y = fc[i].z = 0.0; E_Int np = 0; for (E_Int j = 0; j < M->fstride[fid]; j++) { const E_Int *pn = face + 2*j; for (E_Int k = 0; k < frange[j]; k++) { - ptr[i].x += M->X[pn[k]]; - ptr[i].y += M->Y[pn[k]]; - ptr[i].z += M->Z[pn[k]]; + fc[i].x += M->X[pn[k]]; + fc[i].y += M->Y[pn[k]]; + fc[i].z += M->Z[pn[k]]; np++; } } - ptr[i].x /= np; ptr[i].y /= np; ptr[i].z /= np; + fc[i].x /= np; fc[i].y /= np; fc[i].z /= np; } } @@ -807,6 +804,291 @@ void locate_spoints_in_mskin } } +void smooth_skin_ref_data(const SkinGraph *skin_graph, E_Int *fdat) +{ + E_Int nf = skin_graph->nf; + E_Int stack_size = 3*nf; + E_Int *fstack = (E_Int *)XMALLOC(stack_size * sizeof(E_Int)); + memset(fstack, -1, stack_size * sizeof(E_Int)); + + E_Int l = 0; + + for (E_Int i = 0; i < nf; i++) { + if (fdat[i] > 0) + fstack[l++] = i; + } + + const E_Int *xadj = skin_graph->xadj; + const E_Int *fnei = skin_graph->fnei; + + while (--l >= 0) { + E_Int fid = fstack[l]; + + E_Int start = xadj[fid]; + E_Int nneis = xadj[fid+1] - start; + const E_Int *neis = &fnei[start]; + for (E_Int i = 0; i < nneis; i++) { + E_Int nei = neis[i]; + E_Int incr_nei = fdat[nei]; + E_Int incr_fid = fdat[fid]; + E_Int diff = abs(incr_nei - incr_fid); + if (diff <= 1) continue; + E_Int idx_to_modify = incr_fid > incr_nei ? nei : fid; + fdat[idx_to_modify] += diff-1; + l++; + assert(l < stack_size); + fstack[l] = idx_to_modify; + } + } + + XFREE(fstack); +} + +void init_skin_refinement_cells(const SkinGraph *skin_graph, + const E_Int *fdat, Mesh *M, E_Int *rcount) +{ + E_Int nf = skin_graph->nf; + E_Int count = 0; + + for (E_Int i = 0; i < nf; i++) { + if (fdat[i] > 0) { + E_Int fid = skin_graph->skin[i]; + E_Int own = M->owner[fid]; + // If cref[own] != 0, H18 is impossible, refinement has to be H27. + assert(M->cref[own] == 0); + M->cref[own] = 1; + count++; + } + } + + *rcount = count; +} + +/* +void Mesh_extract_refinement_cells(const Mesh *M, ArrayI *rcells) +{ + rcells->count = 0; + + for (E_Int cid = 0; cid < M->nc; cid++) { + rcells->count += (M->cref[cid] > 0); + } + + rcells->ptr = (E_Int *)XMALLOC(rcells->count * sizeof(E_Int)); + E_Int *ptr = rcells->ptr; + + for (E_Int cid = 0; cid < M->nc; cid++) { + if (M->cref[cid] > 0) + *ptr++ = cid; + } +} +*/ + +void smooth_cell_refinement_data(Mesh *M) +{ + E_Int nc = M->nc; + E_Int stack_size = 3*nc; + E_Int *cstack = (E_Int *)XMALLOC(stack_size * sizeof(E_Int)); + memset(cstack, -1, stack_size * sizeof(E_Int)); + + E_Int l = 0; + + for (E_Int cid = 0; cid < nc; cid++) { + if (M->cref[cid] > 0) + cstack[l++] = cid; + } + + while (--l >= 0) { + E_Int cid = cstack[l]; + + E_Int nn, neis[24]; + Mesh_get_cneis(M, cid, nn, neis); + + for (E_Int i = 0; i < nn; i++) { + E_Int nei = neis[i]; + E_Int incr_nei = M->cref[nei] + M->clevel[nei]; + E_Int incr_cid = M->cref[cid] + M->clevel[cid]; + E_Int diff = abs(incr_nei - incr_cid); + if (diff <= 1) continue; + E_Int idx_to_modify = incr_cid > incr_nei ? nei : cid; + M->cref[idx_to_modify] += 1; + l++; + assert(l < stack_size); + cstack[l] = idx_to_modify; + } + } +} + +static +void Mesh_set_face_as_cell_bottom(Mesh *M, E_Int fid, E_Int cid) +{ + // Make fid the bottom face + E_Int *cell = Mesh_get_cell(M, cid); + E_Int size = 4*M->cstride[cid]; + E_Int pos = Get_pos(fid, cell, size); + assert(pos != -1); + assert(pos % 4 == 0); + Right_shift(cell, pos, size); + assert(cell[0] == fid); + E_Int *crange = Mesh_get_crange(M, cid); + Right_shift(crange, pos/4, M->cstride[cid]); +} + +void reorder_cells_for_H18(const SkinGraph *skin_graph, const E_Int *indices, + const ArrayI *rfaces, Mesh *M) +{ + for (E_Int i = 0; i < rfaces->count; i++) { + E_Int idx_in_skin = indices[rfaces->ptr[i]]; + E_Int fid = skin_graph->skin[idx_in_skin]; + E_Int own = M->owner[fid]; + assert(M->cref[own] == 1); + + while (M->cref[own] == 1) { + Mesh_set_face_as_cell_bottom(M, fid, own); + // Get the top face + fid = Mesh_get_cell(M, own)[4]; + // Get the top neighbour + own = Mesh_get_cnei(M, own, fid); + } + } +} + +void assign_face_refinement_data(Mesh *M) +{ + for (E_Int cid = 0; cid < M->nc; cid++) { + if (M->cref[cid] == 0) continue; + assert(M->cref[cid] == 1); + + E_Int *cell = Mesh_get_cell(M, cid); + E_Int *crange = Mesh_get_crange(M, cid); + E_Int cstride = M->cstride[cid]; + E_Int clvl = M->clevel[cid]; + + for (E_Int i = 0; i < cstride; i++) { + E_Int *pf = cell + 4*i; + + for (E_Int j = 0; j < crange[i]; j++) { + E_Int face = pf[j]; + if (M->fref[face] == 1) continue; + + E_Int flvl = M->flevel[face]; + + assert(flvl >= clvl); + + if (flvl == clvl) M->fref[face] = 1; + } + } + } +} + +// TODO(Imad): isotropic resizing for now + +void Mesh_isolate_refinement_entities(Mesh *M, ArrayI *rcells, ArrayI *rfaces) +{ + rcells->count = 0; + for (E_Int cid = 0; cid < M->nc; cid++) { + rcells->count += (M->cref[cid] == 1); + } + rcells->ptr = (E_Int *)XMALLOC(rcells->count * sizeof(E_Int)); + E_Int *ptr = rcells->ptr; + for (E_Int cid = 0; cid < M->nc; cid++) { + if (M->cref[cid] > 0) { + assert(M->cref[cid] == 1); + *ptr++ = cid; + } + } + + rfaces->count = 0; + for (E_Int fid = 0; fid < M->nf; fid++) { + rfaces->count += (M->fref[fid] == 1); + } + rfaces->ptr = (E_Int *)XMALLOC(rfaces->count * sizeof(E_Int)); + ptr = rfaces->ptr; + for (E_Int fid = 0; fid < M->nf; fid++) { + if (M->fref[fid] > 0) { + assert(M->fref[fid] == 1); + *ptr++ = fid; + } + } +} + +void Mesh_resize(Mesh *M, const ArrayI *rcells, const ArrayI *rfaces) +{ + // 7 new cells per refined cells + E_Int cell_incr = rcells->count * 7; + // 3 new faces per refined face + 12 new faces per refined cell + E_Int face_incr = rfaces->count * 3 + rcells->count * 12; + // Estimate point increase + E_Int point_incr = 2 * face_incr; + + E_Int new_nc = M->nc + cell_incr; + E_Int new_nf = M->nf + face_incr; + E_Int new_np = M->np + point_incr; + + M->X = (E_Float *)XRESIZE(M->X, new_np * sizeof(E_Float)); + M->Y = (E_Float *)XRESIZE(M->Y, new_np * sizeof(E_Float)); + M->Z = (E_Float *)XRESIZE(M->Z, new_np * sizeof(E_Float)); + + Mesh_resize_face_data(M, new_nf); + Mesh_resize_cell_data(M, new_nc); +} + +void Mesh_refine_dir(Mesh *M, ArrayI *ref_cells, ArrayI *ref_faces) +{ + std::set levelset; + + for (E_Int i = 0; i < ref_cells->count; i++) { + levelset.insert(M->clevel[ref_cells->ptr[i]]); + } + + for (E_Int i = 0; i < ref_faces->count; i++) { + levelset.insert(M->flevel[ref_faces->ptr[i]]); + } + + std::vector levels; + for (E_Int level : levelset) levels.push_back(level); + std::sort(levels.begin(), levels.end()); + + std::reverse(ref_cells->ptr, ref_cells->ptr + ref_cells->count); + std::reverse(ref_faces->ptr, ref_faces->ptr + ref_faces->count); + + E_Int cells_left = ref_cells->count-1; + E_Int faces_left = ref_faces->count-1; + + for (E_Int level : levels) { + while (faces_left >= 0 && M->flevel[ref_faces->ptr[faces_left]] == level) { + E_Int face = ref_faces->ptr[faces_left]; + E_Int pattern = get_face_pattern(face, M); + faces_left--; + refine_face_dir(face, pattern, M); + } + + while (cells_left >= 0 && M->clevel[ref_cells->ptr[cells_left]] == level) { + E_Int cell = ref_cells->ptr[cells_left]; + cells_left--; + refine_cell_dir(cell, M); + } + } +} + +/* +void get_face_refinement_direction(const Mesh *M, const ArrayI *rcells, + const ArrayI *rfaces) +{ + for (E_Int i = 0; i < rfaces->count; i++) { + E_Int fid = rfaces->ptr[i]; + E_Int own = M->owner[fid]; + + // TODO(Imad): improve + H18_reorder(own, M); + + E_Int *cell = M->get_cell(M, own); + + E_Int bot = cell[0]; + + } +} +*/ + PyObject *K_XCORE::AdaptMesh_AdaptGeom(PyObject *self, PyObject *args) { PyObject *AMESH, *SMESH; @@ -829,6 +1111,11 @@ PyObject *K_XCORE::AdaptMesh_AdaptGeom(PyObject *self, PyObject *args) Mesh *M = (Mesh *)PyCapsule_GetPointer(AMESH, "AdaptMesh"); Mesh *S = (Mesh *)PyCapsule_GetPointer(SMESH, "AdaptMesh"); + if (M->npc > 1) { + RAISE("AdaptGeom is sequential."); + return NULL; + } + // Refine M volumetric wrt to S tagged faces point cloud // Refine S surfacic wrt to M tagged faces point cloud @@ -843,53 +1130,21 @@ PyObject *K_XCORE::AdaptMesh_AdaptGeom(PyObject *self, PyObject *args) ArrayI spoints; Mesh_extract_points_from_ftag(S, &spoints); - /* - // Spoints must belong to one of the tagged Mfaces - FaceSort *mfaces = NULL; - E_Int mcount = 0; - Mesh_extract_faces_from_ftag(M, &mfaces, &mcount); - printf("Mfaces: %d\n", mcount); - assert(mfaces); - - // Compute their centroids - FaceSort_compute_data(M, mfaces, mcount); - - // Build a BVH for mfaces - const Box3 huge = {-FLT_MAX, -FLT_MAX, -FLT_MAX, - FLT_MAX, FLT_MAX, FLT_MAX}; - BVH_node *bvh = BVH_make(M, mfaces, 0, mcount, &huge); - - // Locate spoints in mfaces - PointFaces *sploc = - (PointFaces *)XMALLOC(spoints.count * sizeof(PointFaces)); - memset(sploc, 0, spoints.count * sizeof(PointFaces)); - locate_spoints_in_mtris - ( - S, &spoints, - mfaces, bvh, - sploc - ); - - - - - */ - // We need the skin connectivity graph SkinGraph skin_graph; Mesh_make_skin_graph(M, &skin_graph); printf("Skin: %d faces\n", skin_graph.nf); // BVH the skin - Vec3f *skin_fc; - Mesh_make_face_centers(M, skin_graph.nf, skin_graph.skin, &skin_fc); + Vec3f *skin_fc = (Vec3f *)XMALLOC(skin_graph.nf * sizeof(Vec3f)); + Mesh_make_face_centers(M, skin_graph.nf, skin_graph.skin, skin_fc); E_Int *indices = (E_Int *)XMALLOC(skin_graph.nf * sizeof(E_Int)); for (E_Int i = 0; i < skin_graph.nf; i++) indices[i] = i; const Box3 huge = {-FLT_MAX, -FLT_MAX, -FLT_MAX, FLT_MAX, FLT_MAX, FLT_MAX}; BVH_node *bvh = BVH_make(M, skin_graph.skin, skin_fc, indices, 0, skin_graph.nf, &huge); - puts("ok bvh"); + puts("BVH constructed"); // Locate spoints in skin PointFaces *sploc = @@ -902,6 +1157,7 @@ PyObject *K_XCORE::AdaptMesh_AdaptGeom(PyObject *self, PyObject *args) bvh, sploc ); + puts("Points located"); // Isolate faces that contain more than MAX_POINTS_PER_FACE spoints ArrayI rfaces; @@ -912,14 +1168,94 @@ PyObject *K_XCORE::AdaptMesh_AdaptGeom(PyObject *self, PyObject *args) MAX_POINTS_PER_FACE, &rfaces ); - + puts("Refinement faces isolated"); printf("Refinement faces: %d\n", rfaces.count); + // Smooth face refinement data + E_Int *fdat = (E_Int *)XMALLOC(skin_graph.nf * sizeof(E_Int)); + memset(fdat, 0, skin_graph.nf * sizeof(E_Int)); + for (E_Int i = 0; i < rfaces.count; i++) { + E_Int idx_in_skin = indices[rfaces.ptr[i]]; + E_Int fid = skin_graph.skin[idx_in_skin]; + fdat[idx_in_skin] = M->flevel[fid] + 1; + } + smooth_skin_ref_data(&skin_graph, fdat); + E_Int smooth_nfref = 0; + for (E_Int i = 0; i < rfaces.count; i++) { + E_Int idx_in_skin = indices[rfaces.ptr[i]]; + E_Int fid = skin_graph.skin[idx_in_skin]; + fdat[idx_in_skin] -= M->flevel[fid]; + if (fdat[idx_in_skin] > 0) smooth_nfref++; + } + puts("Face refinement smoothed out"); + printf("Smooth refinement face count: %d\n", smooth_nfref); + + /* + npy_intp dims[2]; + dims[1] = 1; + dims[0] = (npy_intp)smooth_nfref; + PyArrayObject *FACES = (PyArrayObject *)PyArray_SimpleNew(1, dims, E_NPY_INT); + + E_Int *pf = (E_Int *)PyArray_DATA(FACES); + E_Int *ptr = pf; + for (E_Int i = 0; i < skin_graph.nf; i++) { + if (fdat[i] > 0) { + *ptr++ = skin_graph.skin[i]+1; + } + } + return (PyObject *)FACES; + */ + + // Allocate + M->cref = (E_Int *)XRESIZE(M->cref, M->nc * sizeof(E_Int)); + memset(M->cref, 0, M->nc * sizeof(E_Int)); + + // Cells + E_Int ref_cell_count; + init_skin_refinement_cells(&skin_graph, fdat, M, &ref_cell_count); + printf("Refinement cells: %d\n", ref_cell_count); + + // Smooth cell refinement data + smooth_cell_refinement_data(M); + puts("Cell refinement smoothed out"); + + // Setup bottom/top face chain + reorder_cells_for_H18(&skin_graph, indices, &rfaces, M); + + // Assign refinement data + M->fref = (E_Int *)XRESIZE(M->fref, M->nf * sizeof(E_Int)); + memset(M->fref, 0, M->nf * sizeof(E_Int)); + assign_face_refinement_data(M); + + // Isolate cells/faces to be refined + ArrayI ref_cells, ref_faces; + Mesh_isolate_refinement_entities(M, &ref_cells, &ref_faces); + printf("Refinement cells: %d\n", ref_cells.count); + printf("Refinement faces: %d\n", ref_faces.count); + + // Resize for refinement + Mesh_resize(M, &ref_cells, &ref_faces); + puts("Mesh resized for refinement"); + + // Sort entities by refinement level + std::sort(ref_cells.ptr, ref_cells.ptr + ref_cells.count, + [&] (E_Int i, E_Int j) { return M->clevel[i] < M->clevel[j]; }); + puts("Refinement cells sorted"); + std::sort(ref_faces.ptr, ref_faces.ptr + ref_faces.count, + [&] (E_Int i, E_Int j) { return M->flevel[i] < M->flevel[j]; }); + puts("Refinement faces sorted"); + + // Refine + //Mesh_refine_dir(M, &ref_cells, &ref_faces); + + + // FREE } while (ref_S); + return Py_None; } From e6e7dcc6eeccd272797f258fdcb1abbe67d3d5dd Mon Sep 17 00:00:00 2001 From: Imad Date: Tue, 24 Sep 2024 21:49:37 +0200 Subject: [PATCH 11/86] XCore AdaptMesh: fixed H18 reordering --- Cassiopee/XCore/XCore/AdaptMesh/H18.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Cassiopee/XCore/XCore/AdaptMesh/H18.cpp b/Cassiopee/XCore/XCore/AdaptMesh/H18.cpp index d11a57d03..00c1e436d 100644 --- a/Cassiopee/XCore/XCore/AdaptMesh/H18.cpp +++ b/Cassiopee/XCore/XCore/AdaptMesh/H18.cpp @@ -653,7 +653,7 @@ void H18_reorder(E_Int hexa, Mesh *M) Right_shift(local, i0, 8); E_Int reorient = Mesh_get_reorient(M, RGT[0], hexa, normalIn_H[3]); if (reorient) std::reverse(local+1, local+8); - assert(local[0] == NODES[0]); + assert(local[0] == NODES[1]); assert(local[1] == NODES[9]); assert(local[2] == NODES[2]); NODES[6] = local[4]; @@ -932,4 +932,4 @@ void H18_reorder(E_Int hexa, Mesh *M) assert(local[6] == NODES[7]); assert(local[7] == NODES[13]); } -} \ No newline at end of file +} From f2c701759ef5e521540881475fc068dae9b20573 Mon Sep 17 00:00:00 2001 From: Imad Date: Wed, 25 Sep 2024 01:45:53 +0200 Subject: [PATCH 12/86] XCore AdaptMesh: first refinement pass OK --- .../XCore/AdaptMesh/AdaptMesh_AdaptGeom.cpp | 392 ++++++++++++++++-- .../XCore/XCore/AdaptMesh/AdaptMesh_Init.cpp | 4 +- Cassiopee/XCore/XCore/AdaptMesh/H27.cpp | 3 +- Cassiopee/XCore/XCore/AdaptMesh/Hexa.h | 3 + Cassiopee/XCore/XCore/AdaptMesh/Mesh.h | 1 + Cassiopee/XCore/XCore/AdaptMesh/MeshClean.cpp | 1 + Cassiopee/XCore/XCore/AdaptMesh/MeshDir.cpp | 43 +- Cassiopee/XCore/XCore/AdaptMesh/MeshInit.cpp | 1 + Cassiopee/XCore/XCore/common/common.h | 2 - 9 files changed, 413 insertions(+), 37 deletions(-) diff --git a/Cassiopee/XCore/XCore/AdaptMesh/AdaptMesh_AdaptGeom.cpp b/Cassiopee/XCore/XCore/AdaptMesh/AdaptMesh_AdaptGeom.cpp index 770983537..7b0d5ea06 100644 --- a/Cassiopee/XCore/XCore/AdaptMesh/AdaptMesh_AdaptGeom.cpp +++ b/Cassiopee/XCore/XCore/AdaptMesh/AdaptMesh_AdaptGeom.cpp @@ -1032,6 +1032,348 @@ void Mesh_resize(Mesh *M, const ArrayI *rcells, const ArrayI *rfaces) Mesh_resize_cell_data(M, new_nc); } +#define DIR_ISO 0 +#define DIR_X 1 +#define DIR_Y 2 + +void prepare_cell_ordering_and_face_refinement_patterns(Mesh *M, + const ArrayI *rcells, const ArrayI *rfaces) +{ + for (E_Int i = 0; i < rcells->count; i++) { + E_Int cid = rcells->ptr[i]; + assert(M->cref[cid] == 1); + if (M->clevel[cid] == 0) { + H18_reorder(cid, M); + assert(check_canon_hexa(cid, M) == 0); + } + } + + for (E_Int i = 0; i < rfaces->count; i++) { + E_Int fid = rfaces->ptr[i]; + if (M->flevel[fid] > 0) continue; + + E_Int cid = M->owner[fid]; + if (M->cref[cid] == 0) + cid = M->neigh[fid]; + + assert(cid != -1); + assert(M->cref[cid] == 1); + + E_Int *cell = Mesh_get_cell(M, cid); + E_Int *crange = Mesh_get_crange(M, cid); + + E_Int pos = Get_pos(fid, cell, 4*M->cstride[cid]); + E_Int side = pos / 4; + E_Int *face = Mesh_get_face(M, fid); + + if (side == 0 || side == 1) { + M->fpattern[fid] = DIR_ISO; + } else { + + // Reconstruct bottom + E_Int map[4]; + E_Int bot = cell[0]; + E_Int N0 = Mesh_get_face(M, bot)[0]; + reconstruct_quad(M, cid, cell, crange[0], normalIn_H[0], N0, map); + + M->fpattern[fid] = DIR_ISO; + + E_Int i0; + E_Int reorient; + + if (side == 2) { + + E_Int np, lpts[8]; + for (E_Int j = 0; j < 8; j++) lpts[j] = -1; + Mesh_get_fpoints(M, fid, np, lpts); + + // Must share map[0] && map[3] + i0 = Get_pos(map[3], face, 8); + assert(i0 != -1); + i0 = Get_pos(map[0], face, 8); + assert(i0 != -1); + reorient = Mesh_get_reorient(M, fid, cid, normalIn_H[side]); + + } else if (side == 3) { + + // Must share map[1] && map[2] + i0 = Get_pos(map[2], face, 8); + assert(i0 != -1); + i0 = Get_pos(map[1], face, 8); + assert(i0 != -1); + reorient = Mesh_get_reorient(M, fid, cid, normalIn_H[side]); + + } else if (side == 4) { + + // Must share map[1] && map[0] + i0 = Get_pos(map[0], face, 8); + assert(i0 != -1); + i0 = Get_pos(map[1], face, 8); + assert(i0 != -1); + reorient = Mesh_get_reorient(M, fid, cid, normalIn_H[side]); + + } else if (side == 5) { + + // Must share map[2] && map[3] + i0 = Get_pos(map[3], face, 8); + assert(i0 != -1); + i0 = Get_pos(map[2], face, 8); + assert(i0 != -1); + reorient = Mesh_get_reorient(M, fid, cid, normalIn_H[side]); + + } else { + assert(0); + } + + + i0 /= 2; + + assert(i0 == 0 || i0 == 1 || i0 == 2 || i0 == 3); + + if (reorient == 0) { + if (i0 == 0 || i0 == 2) M->fpattern[fid] = DIR_X; + else M->fpattern[fid] = DIR_Y; + } else { + if (i0 == 0 || i0 == 2) M->fpattern[fid] = DIR_Y; + else M->fpattern[fid] = DIR_X; + } + + assert(M->fpattern[fid] != DIR_ISO); + + /* + bool swap_1 = (reorient == 0) && (i0 == 1 || i0 == 3); + bool swap_2 = (reorient == 1) && (i0 == 0 || i0 == 2); + + if (swap_1 || swap_2) M->fpattern[fid] = DIR_Y; + */ + } + } +} + +E_Int refine_quad_X(E_Int quad, Mesh *M) +{ + assert(M->fref[quad] == 1); + E_Int NODES[8]; + + E_Int *fpts = Mesh_get_face(M, quad); + E_Int *frange = Mesh_get_frange(M, quad); + + // BOT + NODES[0] = fpts[0]; + if (frange[0] == 2) { + NODES[4] = fpts[1]; + } else { + E_Int p = fpts[0]; + E_Int q = fpts[2]; + Mesh_refine_or_get_edge_center(M, p, q, NODES[4]); + } + + // RGT + NODES[1] = fpts[2]; + NODES[5] = fpts[3]; + + // TOP + NODES[2] = fpts[4]; + if (frange[2] == 2) { + NODES[6] = fpts[5]; + } else { + E_Int p = fpts[4]; + E_Int q = fpts[6]; + Mesh_refine_or_get_edge_center(M, p, q, NODES[6]); + } + + // LFT + NODES[3] = fpts[6]; + NODES[7] = fpts[7]; + + + // Second child + fpts = Mesh_get_face(M, M->nf); + fpts[0] = NODES[4]; + fpts[1] = -1; + fpts[2] = NODES[1]; + fpts[3] = NODES[5]; + fpts[4] = NODES[2]; + fpts[5] = -1; + fpts[6] = NODES[6]; + fpts[7] = -1; + + // First child replaces quad + fpts = Mesh_get_face(M, quad); + fpts[0] = NODES[0]; + fpts[1] = -1; + fpts[2] = NODES[4]; + fpts[3] = -1; + fpts[4] = NODES[6]; + fpts[5] = -1; + fpts[6] = NODES[3]; + fpts[7] = NODES[7]; + + // Update ranges and strides + Mesh_update_face_range_and_stride(M, quad, M->nf, 1); + + // Conformize parent cells + + E_Int own = M->owner[quad]; + + assert(M->clevel[own] == M->flevel[quad]); + + if (Mesh_conformize_cell_face(M, own, quad, M->nf, 2) != 0) return 1; + + E_Int nei = M->neigh[quad]; + + if (nei != -1) { + assert(M->clevel[nei] == M->flevel[quad]); + + if (Mesh_conformize_cell_face(M, nei, quad, M->nf, 2) != 0) return 1; + } + + for (E_Int i = 0; i < 1; i++) { + M->owner[M->nf+i] = own; + M->neigh[M->nf+i] = nei; + } + + // Update adaptation info + M->flevel[quad]++; + + assert(M->fref[quad] == FACE_REFINED); + + for (E_Int i = 0; i < 1; i++) { + E_Int fid = M->nf + i; + + M->flevel[fid] = M->flevel[quad]; + M->ftype[fid] = M->ftype[quad]; + + M->fref[fid] = FACE_NEW; + } + + M->fchildren[quad] = {quad, M->nf}; + + M->fparent[M->nf] = quad; + + M->ftag[M->nf] = M->ftag[quad]; + + // Increment face/edge/point count + M->nf += 1; + + return 0; +} + +E_Int refine_quad_Y(E_Int quad, Mesh *M) +{ + assert(M->fref[quad] == 1); + E_Int NODES[8]; + + E_Int *fpts = Mesh_get_face(M, quad); + E_Int *frange = Mesh_get_frange(M, quad); + + // BOT + NODES[0] = fpts[0]; + NODES[4] = fpts[1]; + + // RGT + NODES[1] = fpts[2]; + if (frange[1] == 2) { + NODES[5] = fpts[3]; + } else { + E_Int p = fpts[2]; + E_Int q = fpts[4]; + Mesh_refine_or_get_edge_center(M, p, q, NODES[5]); + } + + // TOP + NODES[2] = fpts[4]; + NODES[6] = fpts[5]; + + // LFT + NODES[3] = fpts[6]; + if (frange[3] == 2) { + NODES[7] = fpts[7]; + } else { + E_Int p = fpts[6]; + E_Int q = fpts[0]; + Mesh_refine_or_get_edge_center(M, p, q, NODES[7]); + } + + // Second child + fpts = Mesh_get_face(M, M->nf); + fpts[0] = NODES[7]; + fpts[1] = -1; + fpts[2] = NODES[5]; + fpts[3] = -1; + fpts[4] = NODES[2]; + fpts[5] = NODES[6]; + fpts[6] = NODES[3]; + fpts[7] = -1; + + // First child replaces quad + fpts = Mesh_get_face(M, quad); + fpts[0] = NODES[0]; + fpts[1] = NODES[4]; + fpts[2] = NODES[1]; + fpts[3] = -1; + fpts[4] = NODES[5]; + fpts[5] = -1; + fpts[6] = NODES[7]; + fpts[7] = -1; + + // Update ranges and strides + Mesh_update_face_range_and_stride(M, quad, M->nf, 1); + + // Conformize parent cells + + E_Int own = M->owner[quad]; + + assert(M->clevel[own] == M->flevel[quad]); + + if (Mesh_conformize_cell_face(M, own, quad, M->nf, 2) != 0) return 1; + + E_Int nei = M->neigh[quad]; + + if (nei != -1) { + assert(M->clevel[nei] == M->flevel[quad]); + + if (Mesh_conformize_cell_face(M, nei, quad, M->nf, 2) != 0) return 1; + } + + for (E_Int i = 0; i < 1; i++) { + M->owner[M->nf+i] = own; + M->neigh[M->nf+i] = nei; + } + + // Update adaptation info + M->flevel[quad]++; + + assert(M->fref[quad] == FACE_REFINED); + + for (E_Int i = 0; i < 1; i++) { + E_Int fid = M->nf + i; + + M->flevel[fid] = M->flevel[quad]; + M->ftype[fid] = M->ftype[quad]; + + M->fref[fid] = FACE_NEW; + } + + M->fchildren[quad] = {quad, M->nf}; + + M->fparent[M->nf] = quad; + + M->ftag[M->nf] = M->ftag[quad]; + + // Increment face/edge/point count + M->nf += 1; + + return 0; +} + +E_Int refine_quad_dir(E_Int fid, Mesh *M) +{ + if (M->fpattern[fid] == DIR_X) return refine_quad_X(fid, M); + if (M->fpattern[fid] == DIR_Y) return refine_quad_Y(fid, M); + return Q9_refine(fid, M); +} + void Mesh_refine_dir(Mesh *M, ArrayI *ref_cells, ArrayI *ref_faces) { std::set levelset; @@ -1048,8 +1390,8 @@ void Mesh_refine_dir(Mesh *M, ArrayI *ref_cells, ArrayI *ref_faces) for (E_Int level : levelset) levels.push_back(level); std::sort(levels.begin(), levels.end()); - std::reverse(ref_cells->ptr, ref_cells->ptr + ref_cells->count); - std::reverse(ref_faces->ptr, ref_faces->ptr + ref_faces->count); + //std::reverse(ref_cells->ptr, ref_cells->ptr + ref_cells->count); + //std::reverse(ref_faces->ptr, ref_faces->ptr + ref_faces->count); E_Int cells_left = ref_cells->count-1; E_Int faces_left = ref_faces->count-1; @@ -1057,9 +1399,8 @@ void Mesh_refine_dir(Mesh *M, ArrayI *ref_cells, ArrayI *ref_faces) for (E_Int level : levels) { while (faces_left >= 0 && M->flevel[ref_faces->ptr[faces_left]] == level) { E_Int face = ref_faces->ptr[faces_left]; - E_Int pattern = get_face_pattern(face, M); faces_left--; - refine_face_dir(face, pattern, M); + refine_quad_dir(face, M); } while (cells_left >= 0 && M->clevel[ref_cells->ptr[cells_left]] == level) { @@ -1070,25 +1411,6 @@ void Mesh_refine_dir(Mesh *M, ArrayI *ref_cells, ArrayI *ref_faces) } } -/* -void get_face_refinement_direction(const Mesh *M, const ArrayI *rcells, - const ArrayI *rfaces) -{ - for (E_Int i = 0; i < rfaces->count; i++) { - E_Int fid = rfaces->ptr[i]; - E_Int own = M->owner[fid]; - - // TODO(Imad): improve - H18_reorder(own, M); - - E_Int *cell = M->get_cell(M, own); - - E_Int bot = cell[0]; - - } -} -*/ - PyObject *K_XCORE::AdaptMesh_AdaptGeom(PyObject *self, PyObject *args) { PyObject *AMESH, *SMESH; @@ -1219,9 +1541,6 @@ PyObject *K_XCORE::AdaptMesh_AdaptGeom(PyObject *self, PyObject *args) smooth_cell_refinement_data(M); puts("Cell refinement smoothed out"); - // Setup bottom/top face chain - reorder_cells_for_H18(&skin_graph, indices, &rfaces, M); - // Assign refinement data M->fref = (E_Int *)XRESIZE(M->fref, M->nf * sizeof(E_Int)); memset(M->fref, 0, M->nf * sizeof(E_Int)); @@ -1233,20 +1552,34 @@ PyObject *K_XCORE::AdaptMesh_AdaptGeom(PyObject *self, PyObject *args) printf("Refinement cells: %d\n", ref_cells.count); printf("Refinement faces: %d\n", ref_faces.count); + // Setup bottom/top face chain + reorder_cells_for_H18(&skin_graph, indices, &rfaces, M); + + // Prepare cell ordering and face refinement direction + M->fpattern = (E_Int *)XMALLOC(M->nf * sizeof(E_Int)); + memset(M->fpattern, -1, M->nf * sizeof(E_Int)); + prepare_cell_ordering_and_face_refinement_patterns(M, &ref_cells, + &ref_faces); + // Resize for refinement Mesh_resize(M, &ref_cells, &ref_faces); puts("Mesh resized for refinement"); // Sort entities by refinement level std::sort(ref_cells.ptr, ref_cells.ptr + ref_cells.count, - [&] (E_Int i, E_Int j) { return M->clevel[i] < M->clevel[j]; }); + [&] (E_Int i, E_Int j) { return M->clevel[i] > M->clevel[j]; }); puts("Refinement cells sorted"); std::sort(ref_faces.ptr, ref_faces.ptr + ref_faces.count, - [&] (E_Int i, E_Int j) { return M->flevel[i] < M->flevel[j]; }); + [&] (E_Int i, E_Int j) { return M->flevel[i] > M->flevel[j]; }); puts("Refinement faces sorted"); // Refine - //Mesh_refine_dir(M, &ref_cells, &ref_faces); + printf("Cells before refinement: %d\n", M->nc); + printf("Faces before refinement: %d\n", M->nf); + Mesh_refine_dir(M, &ref_cells, &ref_faces); + + printf("Cells after refinement: %d\n", M->nc); + printf("Faces after refinement: %d\n", M->nf); @@ -1256,6 +1589,7 @@ PyObject *K_XCORE::AdaptMesh_AdaptGeom(PyObject *self, PyObject *args) } while (ref_S); + Mesh_conformize_face_edge(M); return Py_None; } diff --git a/Cassiopee/XCore/XCore/AdaptMesh/AdaptMesh_Init.cpp b/Cassiopee/XCore/XCore/AdaptMesh/AdaptMesh_Init.cpp index 6f732deeb..99815e42e 100644 --- a/Cassiopee/XCore/XCore/AdaptMesh/AdaptMesh_Init.cpp +++ b/Cassiopee/XCore/XCore/AdaptMesh/AdaptMesh_Init.cpp @@ -237,11 +237,9 @@ PyObject *K_XCORE::AdaptMesh_Init(PyObject *self, PyObject *args) M->fparent = IntArray(M->nf); for (E_Int i = 0; i < M->nf; i++) M->fparent[i] = i; - //M->cref = IntArray(M->nc); - //M->fref = IntArray(M->nf); - M->cref = NULL; M->fref = NULL; + M->fpattern = NULL; M->ctag = IntArray(M->nc); M->ftag = IntArray(M->nf); diff --git a/Cassiopee/XCore/XCore/AdaptMesh/H27.cpp b/Cassiopee/XCore/XCore/AdaptMesh/H27.cpp index 1347b98f7..5940975d5 100644 --- a/Cassiopee/XCore/XCore/AdaptMesh/H27.cpp +++ b/Cassiopee/XCore/XCore/AdaptMesh/H27.cpp @@ -1350,7 +1350,6 @@ void H27_reorder(E_Int hexa, Mesh *M) } } -static void reconstruct_quad(Mesh *M, E_Int hexa, E_Int *fids, E_Int crange, E_Int normalIn, E_Int NODE, E_Int pn[4]) { @@ -1535,4 +1534,4 @@ void update_range_and_stride(Mesh *M, E_Int hexa, E_Int cpos, E_Int nchildren) crange[j] = 1; } } -} \ No newline at end of file +} diff --git a/Cassiopee/XCore/XCore/AdaptMesh/Hexa.h b/Cassiopee/XCore/XCore/AdaptMesh/Hexa.h index b2275e915..3276e05b8 100644 --- a/Cassiopee/XCore/XCore/AdaptMesh/Hexa.h +++ b/Cassiopee/XCore/XCore/AdaptMesh/Hexa.h @@ -32,6 +32,9 @@ void H18_refine(E_Int hexa, Mesh *M); void H18_reorder(E_Int hexa, Mesh *M); +void reconstruct_quad(Mesh *M, E_Int hexa, E_Int *fids, E_Int crange, E_Int normalIn, + E_Int NODE, E_Int pn[4]); + E_Int check_canon_hexa(E_Int hexa, Mesh *M); void update_range_and_stride(Mesh *M, E_Int hexa, E_Int cpos, E_Int nchildren); diff --git a/Cassiopee/XCore/XCore/AdaptMesh/Mesh.h b/Cassiopee/XCore/XCore/AdaptMesh/Mesh.h index 75220eaf1..374e8c809 100644 --- a/Cassiopee/XCore/XCore/AdaptMesh/Mesh.h +++ b/Cassiopee/XCore/XCore/AdaptMesh/Mesh.h @@ -130,6 +130,7 @@ struct Mesh { E_Int *cref; E_Int *fref; + E_Int *fpattern; E_Int *clevel; E_Int *flevel; diff --git a/Cassiopee/XCore/XCore/AdaptMesh/MeshClean.cpp b/Cassiopee/XCore/XCore/AdaptMesh/MeshClean.cpp index fedd5f6e8..2dd786d3d 100644 --- a/Cassiopee/XCore/XCore/AdaptMesh/MeshClean.cpp +++ b/Cassiopee/XCore/XCore/AdaptMesh/MeshClean.cpp @@ -78,6 +78,7 @@ void Mesh_reset_adaptation_data(Mesh *M) XFREE(M->cref); XFREE(M->fref); + XFREE(M->fpattern); XFREE(M->clevel); XFREE(M->flevel); diff --git a/Cassiopee/XCore/XCore/AdaptMesh/MeshDir.cpp b/Cassiopee/XCore/XCore/AdaptMesh/MeshDir.cpp index f776a96c3..f271e4398 100644 --- a/Cassiopee/XCore/XCore/AdaptMesh/MeshDir.cpp +++ b/Cassiopee/XCore/XCore/AdaptMesh/MeshDir.cpp @@ -56,4 +56,45 @@ void Mesh_refine_dir(Mesh *M, std::vector &ref_cells, refine_cell_dir(cell, M); } } -} \ No newline at end of file +} + +/* +void Mesh_prepare_cell_ordering_and_face_refinement_patterns(Mesh *M, + const ArrayI *rcells, const ArrayI *rfaces, ArrayI *fpatterns) +{ + for (E_Int i = 0; i < rcells->count; i++) { + H18_reorder(rcells->ptr[i], M); + } + + fpatterns->count = rfaces->count; + fpatterns->ptr = (E_Int *)XMALLOC(rfaces->count * sizeof(E_Int)); + + for (E_Int i = 0; i < rfaces->count; i++) { + E_Int fid = rfaces->ptr[i]; + E_Int own = M->owner[fid]; + + E_Int *cell = Mesh_get_cell(M, own); + + E_Int pos = Get_pos(fid, cell, 4*M->cstride[own]); + E_Int side = pos / 4; + E_Int idx = pos % 4; + + if (side == 0 || side == 1) { + fpatterns->ptr[i] = ISO; + } else if (side == 2) { + + } else if (side == 3) { + + + } else if (side == 4) { + + + } else if (side == 5) { + + + } else { + + } + } +} +*/ diff --git a/Cassiopee/XCore/XCore/AdaptMesh/MeshInit.cpp b/Cassiopee/XCore/XCore/AdaptMesh/MeshInit.cpp index 7710a0c12..52cb714d9 100644 --- a/Cassiopee/XCore/XCore/AdaptMesh/MeshInit.cpp +++ b/Cassiopee/XCore/XCore/AdaptMesh/MeshInit.cpp @@ -54,6 +54,7 @@ Mesh::Mesh() cref = NULL; fref = NULL; + fpattern = NULL; clevel = NULL; flevel = NULL; diff --git a/Cassiopee/XCore/XCore/common/common.h b/Cassiopee/XCore/XCore/common/common.h index 9d8e2a712..af290d1af 100644 --- a/Cassiopee/XCore/XCore/common/common.h +++ b/Cassiopee/XCore/XCore/common/common.h @@ -54,8 +54,6 @@ E_Int Get_pos(E_Int e, E_Int *pn, E_Int size) if (pn[i] == e) return i; } - assert(0); - return -1; } From 82686dd5f09e95aa5cdee2ce2261da1c3bf6c6f5 Mon Sep 17 00:00:00 2001 From: Imad Date: Wed, 25 Sep 2024 14:27:19 +0200 Subject: [PATCH 13/86] XCore AdaptMesh: extracted smoothed refinement faces at iteration 2 --- .../XCore/AdaptMesh/AdaptMesh_AdaptGeom.cpp | 95 +++++++++++++------ 1 file changed, 67 insertions(+), 28 deletions(-) diff --git a/Cassiopee/XCore/XCore/AdaptMesh/AdaptMesh_AdaptGeom.cpp b/Cassiopee/XCore/XCore/AdaptMesh/AdaptMesh_AdaptGeom.cpp index 7b0d5ea06..2c0fe8582 100644 --- a/Cassiopee/XCore/XCore/AdaptMesh/AdaptMesh_AdaptGeom.cpp +++ b/Cassiopee/XCore/XCore/AdaptMesh/AdaptMesh_AdaptGeom.cpp @@ -804,7 +804,7 @@ void locate_spoints_in_mskin } } -void smooth_skin_ref_data(const SkinGraph *skin_graph, E_Int *fdat) +void smooth_skin_ref_data(Mesh *M, const SkinGraph *skin_graph, E_Int *fdat) { E_Int nf = skin_graph->nf; E_Int stack_size = 3*nf; @@ -829,8 +829,8 @@ void smooth_skin_ref_data(const SkinGraph *skin_graph, E_Int *fdat) const E_Int *neis = &fnei[start]; for (E_Int i = 0; i < nneis; i++) { E_Int nei = neis[i]; - E_Int incr_nei = fdat[nei]; - E_Int incr_fid = fdat[fid]; + E_Int incr_nei = fdat[nei] + M->flevel[skin_graph->skin[nei]]; + E_Int incr_fid = fdat[fid] + M->flevel[skin_graph->skin[fid]]; E_Int diff = abs(incr_nei - incr_fid); if (diff <= 1) continue; E_Int idx_to_modify = incr_fid > incr_nei ? nei : fid; @@ -1411,6 +1411,29 @@ void Mesh_refine_dir(Mesh *M, ArrayI *ref_cells, ArrayI *ref_faces) } } +void BVH_free(BVH_node *node) +{ + if (node == NULL) return; + + BVH_free(node->left); + BVH_free(node->right); + + XFREE(node); +} + +void ArrayI_free(ArrayI *arr) +{ + XFREE(arr->ptr); +} + +void SkinGraph_free(SkinGraph *skin_graph) +{ + XFREE(skin_graph->skin); + XFREE(skin_graph->xadj); + XFREE(skin_graph->fpts); + XFREE(skin_graph->fnei); +} + PyObject *K_XCORE::AdaptMesh_AdaptGeom(PyObject *self, PyObject *args) { PyObject *AMESH, *SMESH; @@ -1447,6 +1470,7 @@ PyObject *K_XCORE::AdaptMesh_AdaptGeom(PyObject *self, PyObject *args) do { iter++; + printf("iter: %d\n", iter); // Extract spoints from tagged sfaces ArrayI spoints; @@ -1468,6 +1492,7 @@ PyObject *K_XCORE::AdaptMesh_AdaptGeom(PyObject *self, PyObject *args) skin_graph.nf, &huge); puts("BVH constructed"); + // Locate spoints in skin PointFaces *sploc = (PointFaces *)XMALLOC(spoints.count * sizeof(PointFaces)); @@ -1481,6 +1506,7 @@ PyObject *K_XCORE::AdaptMesh_AdaptGeom(PyObject *self, PyObject *args) ); puts("Points located"); + // Isolate faces that contain more than MAX_POINTS_PER_FACE spoints ArrayI rfaces; extract_faces_by_threshold @@ -1493,40 +1519,39 @@ PyObject *K_XCORE::AdaptMesh_AdaptGeom(PyObject *self, PyObject *args) puts("Refinement faces isolated"); printf("Refinement faces: %d\n", rfaces.count); + // Smooth face refinement data E_Int *fdat = (E_Int *)XMALLOC(skin_graph.nf * sizeof(E_Int)); memset(fdat, 0, skin_graph.nf * sizeof(E_Int)); for (E_Int i = 0; i < rfaces.count; i++) { E_Int idx_in_skin = indices[rfaces.ptr[i]]; - E_Int fid = skin_graph.skin[idx_in_skin]; - fdat[idx_in_skin] = M->flevel[fid] + 1; + fdat[idx_in_skin] = 1; } - smooth_skin_ref_data(&skin_graph, fdat); + smooth_skin_ref_data(M, &skin_graph, fdat); + puts("Face refinement smoothed out"); + E_Int smooth_nfref = 0; - for (E_Int i = 0; i < rfaces.count; i++) { - E_Int idx_in_skin = indices[rfaces.ptr[i]]; - E_Int fid = skin_graph.skin[idx_in_skin]; - fdat[idx_in_skin] -= M->flevel[fid]; - if (fdat[idx_in_skin] > 0) smooth_nfref++; + for (E_Int i = 0; i < skin_graph.nf; i++) { + if (fdat[i] > 0) smooth_nfref++; } - puts("Face refinement smoothed out"); printf("Smooth refinement face count: %d\n", smooth_nfref); - /* - npy_intp dims[2]; - dims[1] = 1; - dims[0] = (npy_intp)smooth_nfref; - PyArrayObject *FACES = (PyArrayObject *)PyArray_SimpleNew(1, dims, E_NPY_INT); - - E_Int *pf = (E_Int *)PyArray_DATA(FACES); - E_Int *ptr = pf; - for (E_Int i = 0; i < skin_graph.nf; i++) { - if (fdat[i] > 0) { - *ptr++ = skin_graph.skin[i]+1; + if (iter == 2) { + npy_intp dims[2]; + dims[1] = 1; + dims[0] = (npy_intp)smooth_nfref; + PyArrayObject *FACES = (PyArrayObject *)PyArray_SimpleNew(1, dims, E_NPY_INT); + + E_Int *pf = (E_Int *)PyArray_DATA(FACES); + E_Int *ptr = pf; + for (E_Int i = 0; i < skin_graph.nf; i++) { + if (fdat[i] > 0) { + *ptr++ = skin_graph.skin[i]+1; + } } + //puts(""); + return (PyObject *)FACES; } - return (PyObject *)FACES; - */ // Allocate M->cref = (E_Int *)XRESIZE(M->cref, M->nc * sizeof(E_Int)); @@ -1536,6 +1561,7 @@ PyObject *K_XCORE::AdaptMesh_AdaptGeom(PyObject *self, PyObject *args) E_Int ref_cell_count; init_skin_refinement_cells(&skin_graph, fdat, M, &ref_cell_count); printf("Refinement cells: %d\n", ref_cell_count); + if (ref_cell_count == 0) break; // Smooth cell refinement data smooth_cell_refinement_data(M); @@ -1556,7 +1582,7 @@ PyObject *K_XCORE::AdaptMesh_AdaptGeom(PyObject *self, PyObject *args) reorder_cells_for_H18(&skin_graph, indices, &rfaces, M); // Prepare cell ordering and face refinement direction - M->fpattern = (E_Int *)XMALLOC(M->nf * sizeof(E_Int)); + M->fpattern = (E_Int *)XRESIZE(M->fpattern, M->nf * sizeof(E_Int)); memset(M->fpattern, -1, M->nf * sizeof(E_Int)); prepare_cell_ordering_and_face_refinement_patterns(M, &ref_cells, &ref_faces); @@ -1580,16 +1606,29 @@ PyObject *K_XCORE::AdaptMesh_AdaptGeom(PyObject *self, PyObject *args) printf("Cells after refinement: %d\n", M->nc); printf("Faces after refinement: %d\n", M->nf); + + Mesh_conformize_face_edge(M); + puts(""); + + BVH_free(bvh); + ArrayI_free(&spoints); + ArrayI_free(&ref_cells); + ArrayI_free(&ref_faces); + ArrayI_free(&rfaces); + SkinGraph_free(&skin_graph); + XFREE(fdat); + XFREE(sploc); + XFREE(indices); + XFREE(skin_fc); // FREE - } while (ref_S); + } while (1); - Mesh_conformize_face_edge(M); return Py_None; } From b94b9d57b5ca6b9c474f499395226279b88ff124 Mon Sep 17 00:00:00 2001 From: imadhammani Date: Thu, 26 Sep 2024 13:42:34 +0200 Subject: [PATCH 14/86] XCore AdaptMesh: OK directional refinement --- .../XCore/AdaptMesh/AdaptMesh_AdaptGeom.cpp | 1176 +++-------------- .../XCore/XCore/AdaptMesh/AdaptMesh_Init.cpp | 3 +- Cassiopee/XCore/XCore/AdaptMesh/Array.cpp | 7 + Cassiopee/XCore/XCore/AdaptMesh/Array.h | 10 + Cassiopee/XCore/XCore/AdaptMesh/BVH.cpp | 160 +++ Cassiopee/XCore/XCore/AdaptMesh/BVH.h | 37 + Cassiopee/XCore/XCore/AdaptMesh/Box.cpp | 106 ++ Cassiopee/XCore/XCore/AdaptMesh/Box.h | 36 + Cassiopee/XCore/XCore/AdaptMesh/FaceSort.cpp | 42 + Cassiopee/XCore/XCore/AdaptMesh/FaceSort.h | 17 + Cassiopee/XCore/XCore/AdaptMesh/H18.cpp | 7 + Cassiopee/XCore/XCore/AdaptMesh/Mesh.h | 31 + .../XCore/XCore/AdaptMesh/MeshExtract.cpp | 265 ++++ Cassiopee/XCore/XCore/AdaptMesh/MeshIO.cpp | 2 +- Cassiopee/XCore/XCore/AdaptMesh/MeshIso.cpp | 90 -- .../XCore/XCore/AdaptMesh/MeshLocate.cpp | 64 + .../XCore/XCore/AdaptMesh/MeshRefine.cpp | 3 + Cassiopee/XCore/XCore/AdaptMesh/Point.cpp | 129 ++ Cassiopee/XCore/XCore/AdaptMesh/Point.h | 41 + Cassiopee/XCore/XCore/AdaptMesh/Q9.cpp | 5 + Cassiopee/XCore/XCore/AdaptMesh/Skin.cpp | 10 + Cassiopee/XCore/XCore/AdaptMesh/Skin.h | 15 + Cassiopee/XCore/XCore/AdaptMesh/Vec.h | 5 + Cassiopee/XCore/XCore/AdaptMesh/constants.cpp | 3 + Cassiopee/XCore/XCore/AdaptMesh/constants.h | 5 + Cassiopee/XCore/srcs.py | 12 + 26 files changed, 1194 insertions(+), 1087 deletions(-) create mode 100644 Cassiopee/XCore/XCore/AdaptMesh/Array.cpp create mode 100644 Cassiopee/XCore/XCore/AdaptMesh/Array.h create mode 100644 Cassiopee/XCore/XCore/AdaptMesh/BVH.cpp create mode 100644 Cassiopee/XCore/XCore/AdaptMesh/BVH.h create mode 100644 Cassiopee/XCore/XCore/AdaptMesh/Box.cpp create mode 100644 Cassiopee/XCore/XCore/AdaptMesh/Box.h create mode 100644 Cassiopee/XCore/XCore/AdaptMesh/FaceSort.cpp create mode 100644 Cassiopee/XCore/XCore/AdaptMesh/FaceSort.h create mode 100644 Cassiopee/XCore/XCore/AdaptMesh/MeshExtract.cpp create mode 100644 Cassiopee/XCore/XCore/AdaptMesh/MeshLocate.cpp create mode 100644 Cassiopee/XCore/XCore/AdaptMesh/Point.cpp create mode 100644 Cassiopee/XCore/XCore/AdaptMesh/Point.h create mode 100644 Cassiopee/XCore/XCore/AdaptMesh/Skin.cpp create mode 100644 Cassiopee/XCore/XCore/AdaptMesh/Skin.h create mode 100644 Cassiopee/XCore/XCore/AdaptMesh/Vec.h create mode 100644 Cassiopee/XCore/XCore/AdaptMesh/constants.cpp create mode 100644 Cassiopee/XCore/XCore/AdaptMesh/constants.h diff --git a/Cassiopee/XCore/XCore/AdaptMesh/AdaptMesh_AdaptGeom.cpp b/Cassiopee/XCore/XCore/AdaptMesh/AdaptMesh_AdaptGeom.cpp index 2c0fe8582..db43ab458 100644 --- a/Cassiopee/XCore/XCore/AdaptMesh/AdaptMesh_AdaptGeom.cpp +++ b/Cassiopee/XCore/XCore/AdaptMesh/AdaptMesh_AdaptGeom.cpp @@ -1,783 +1,14 @@ #include "Mesh.h" #include "common/mem.h" +#include "Array.h" +#include "Point.h" +#include "BVH.h" +#include "Point.h" +#include "Skin.h" +#include "Vec.h" // TODO(Imad): sorting routines -struct Point { - E_Float x, y, z; -}; - -void points_write(const char *fname, const std::vector &P) -{ - FILE *fh = fopen(fname, "w"); - assert(fh); - fprintf(fh, "POINTS\n"); - fprintf(fh, "%zu\n", P.size()); - for (auto p : P) fprintf(fh, "%f %f %f\n", p.x, p.y, p.z); - fclose(fh); -} - -void point_write(E_Float px, E_Float py, E_Float pz) -{ - FILE *fh = fopen("point", "w"); - assert(fh); - fprintf(fh, "POINTS\n"); - fprintf(fh, "1\n"); - fprintf(fh, "%f %f %f\n", px, py, pz); - fclose(fh); -} - -void point_write(const Point p) -{ - return point_write(p.x, p.y, p.z); -} - -struct ArrayI { - E_Int count; - E_Int *ptr; -}; - -void Mesh_extract_points_from_ftag(Mesh *M, ArrayI *pids) -{ - E_Int *ptag = (E_Int *)XMALLOC(M->np * sizeof(E_Int)); - memset(ptag, 0, M->np * sizeof(E_Int)); - pids->count = 0; - - for (E_Int fid = 0; fid < M->nf; fid++) { - if (M->ftag[fid] != 1) continue; - E_Int *face = Mesh_get_face(M, fid); - E_Int *frange = Mesh_get_frange(M, fid); - for (E_Int i = 0; i < M->fstride[fid]; i++) { - E_Int *pn = face + 2*i; - for (E_Int j = 0; j < frange[i]; j++) { - E_Int pid = pn[j]; - pids->count += (ptag[pid] == 0); - ptag[pid] = 1; - } - } - } - - pids->ptr = (E_Int *)XMALLOC(pids->count * sizeof(E_Int)); - E_Int *ptr = pids->ptr; - - for (E_Int pid = 0; pid < M->np; pid++) { - if (ptag[pid] == 1) - *ptr++ = pid; - } - - XFREE(ptag); -} - -struct FaceSort { - E_Int fid; - E_Float fc[3]; - E_Float UX, UY, UZ; - E_Float VX, VY, VZ; - E_Float UU, VV, UV; - E_Float inv_denom; - E_Float xa, ya, za; -}; - -void Mesh_extract_faces_from_ftag(const Mesh *M, FaceSort **mfaces, - E_Int *mcount) -{ - E_Int count = 0; - - for (E_Int i = 0; i < M->nf; i++) { - count += (M->ftag[i] == 1); - } - - *mfaces = (FaceSort *)XMALLOC(count * sizeof(FaceSort)); - - *mcount = count; - - count = 0; - - for (E_Int i = 0; i < M->nf; i++) { - if (M->ftag[i] == 1) { - assert(M->ftype[i] == TRI); - (*mfaces)[count++].fid = i; - } - } - - assert(*mcount == count); -} - -void FaceSort_compute_data(const Mesh *M, FaceSort *mfaces, E_Int mcount) -{ - for (E_Int i = 0; i < mcount; i++) { - FaceSort *face = &mfaces[i]; - - E_Int tid = face->fid; - assert(M->ftype[tid] == TRI); - - E_Int *tri = Mesh_get_face(M, tid); - E_Int A = tri[0], B = tri[2], C = tri[4]; - - face->UX = (M->X[B] - M->X[A]); - face->UY = (M->Y[B] - M->Y[A]); - face->UZ = (M->Z[B] - M->Z[A]); - - face->VX = (M->X[C] - M->X[A]); - face->VY = (M->Y[C] - M->Y[A]); - face->VZ = (M->Z[C] - M->Z[A]); - - face->UU = face->UX*face->UX + face->UY*face->UY + face->UZ*face->UZ; - face->VV = face->VX*face->VX + face->VY*face->VY + face->VZ*face->VZ; - face->UV = face->UX*face->VX + face->UY*face->VY + face->UZ*face->VZ; - - face->inv_denom = face->UU*face->VV - face->UV*face->UV; - - assert(face->inv_denom != 0.0); - - face->inv_denom = 1.0 / face->inv_denom; - - face->fc[0] = (M->X[A] + M->X[B] + M->X[C]) / 3.0; - face->fc[1] = (M->Y[A] + M->Y[B] + M->Y[C]) / 3.0; - face->fc[2] = (M->Z[A] + M->Z[B] + M->Z[C]) / 3.0; - - // Store A - face->xa = M->X[A]; - face->ya = M->Y[A]; - face->za = M->Z[A]; - } -} - -struct Box3 { - E_Float xmin, ymin, zmin; - E_Float xmax, ymax, zmax; -}; - -inline -bool Box3_in_Box3(const Box3 small, const Box3 big) -{ - return (big.xmin <= small.xmin) && (big.xmax >= small.xmax) && - (big.ymin <= small.ymin) && (big.ymax >= small.ymax) && - (big.zmin <= small.zmin) && (big.zmax >= small.zmax); -} - -struct BVH_node { - Box3 box; - E_Int start, end; - BVH_node *left; - BVH_node *right; -}; - -Box3 Box3_make -( - const Mesh *M, - const FaceSort *mfaces, - E_Int start, E_Int end -) -{ - E_Float xmin, ymin, zmin, xmax, ymax, zmax; - xmin = ymin = zmin = FLT_MAX; - xmax = ymax = zmax = -FLT_MAX; - - for (E_Int i = start; i < end; i++) { - E_Int fid = mfaces[i].fid; - E_Int *face = Mesh_get_face(M, fid); - E_Int *frange = Mesh_get_frange(M, fid); - assert(M->fstride[fid] == 3); - assert(M->ftype[fid] == TRI); - for (E_Int j = 0; j < M->fstride[fid]; j++) { - E_Int *pn = face + 2*j; - assert(frange[j] == 1); - for (E_Int k = 0; k < frange[j]; k++) { - E_Int pid = pn[k]; - if (M->X[pid] < xmin) xmin = M->X[pid]; - if (M->Y[pid] < ymin) ymin = M->Y[pid]; - if (M->Z[pid] < zmin) zmin = M->Z[pid]; - - if (M->X[pid] > xmax) xmax = M->X[pid]; - if (M->Y[pid] > ymax) ymax = M->Y[pid]; - if (M->Z[pid] > zmax) zmax = M->Z[pid]; - } - } - } - - // Safety - E_Float dx = (xmax - xmin) * 0.01; - E_Float dy = (ymax - ymin) * 0.01; - E_Float dz = (zmax - zmin) * 0.01; - xmin -= dx; - ymin -= dy; - zmin -= dz; - xmax += dx; - ymax += dy; - zmax += dz; - - return {xmin, ymin, zmin, xmax, ymax, zmax}; -} - -//static int idx = 0; - -BVH_node *BVH_create_node(const Box3 *box, E_Int start, E_Int end, - BVH_node *left, BVH_node *right) -{ - BVH_node *node = (BVH_node *)XMALLOC(sizeof(BVH_node)); - node->box = *box; - node->start = start; - node->end = end; - node->left = left; - node->right = right; - //printf("%d -> %f %f %f %f %f %f\n", idx, box->xmin, box->ymin, box->zmin, - // box->xmax, box->ymax, box->zmax); - //idx++; - return node; -} - -#define MAX_FACES_PER_BVH_LEAF 10 - -void Box3_clamp(const Box3 *parent, Box3 *child) -{ - child->xmin = std::max(parent->xmin, child->xmin); - child->ymin = std::max(parent->ymin, child->ymin); - child->zmin = std::max(parent->zmin, child->zmin); - child->xmax = std::min(parent->xmax, child->xmax); - child->ymax = std::min(parent->ymax, child->ymax); - child->zmax = std::min(parent->zmax, child->zmax); -} - -BVH_node *BVH_make(const Mesh *M, FaceSort *mfaces, E_Int start, E_Int end, - const Box3 *parent_box) -{ - Box3 box = Box3_make(M, mfaces, start, end); - Box3_clamp(parent_box, &box); - assert(Box3_in_Box3(box, *parent_box)); - - E_Int count = end - start; - if (count <= MAX_FACES_PER_BVH_LEAF) { - return BVH_create_node(&box, start, end, NULL, NULL); - } - - E_Float dx = box.xmax - box.xmin; - E_Float dy = box.ymax - box.ymin; - E_Float dz = box.zmax - box.zmin; - - E_Int dim = -1; - - if (dx >= dy && dx >= dz) { - dim = 0; - } else if (dy >= dz) { - dim = 1; - } else { - dim = 2; - } - - std::sort(mfaces + start, mfaces + end, - [&](const FaceSort &fi, const FaceSort &fj) - { - return fi.fc[dim] < fj.fc[dim]; - }); - - E_Int mid = start + count/2; - - BVH_node *left = BVH_make(M, mfaces, start, mid, &box); - BVH_node *right = BVH_make(M, mfaces, mid, end, &box); - - assert(Box3_in_Box3(left->box, box)); - assert(Box3_in_Box3(right->box, box)); - - return BVH_create_node(&box, start, end, left, right); -} - -#define MAX_FACES_PER_POINT 8 - -struct PointFaces { - E_Int count; - E_Int ptr[MAX_FACES_PER_POINT]; -}; - -#define TOL 1e-12 - -bool Point_in_FaceSort(const Point *p, const FaceSort *f) -{ - E_Float DX = p->x - f->xa; - E_Float DY = p->y - f->ya; - E_Float DZ = p->z - f->za; - - E_Float d20 = DX*f->UX + DY*f->UY + DZ*f->UZ; - E_Float d21 = DX*f->VX + DY*f->VY + DZ*f->VZ; - - E_Float u = (f->VV*d20 - f->UV*d21) * f->inv_denom; - if (u < -TOL || u > 1.0 + TOL) return false; - - E_Float v = (f->UU*d21 - f->UV*d20) * f->inv_denom; - if (v < -TOL || v > 1.0 + TOL) return false; - - E_Float w = 1.0 - (u + v); - if (w < -TOL || w > 1.0 + TOL) return false; - - return true; -} - -bool Point_in_Box3D(const Point *p, const Box3 *box) -{ - return (p->x >= box->xmin) && (p->x <= box->xmax) && - (p->y >= box->ymin) && (p->y <= box->ymax) && - (p->z >= box->zmin) && (p->z <= box->zmax); -} - -#define MAX_POINTS_PER_FACE 1 - -void extract_faces_by_threshold -( - const PointFaces *sploc, E_Int spcount, - const E_Int *skin, E_Int mcount, - const E_Int threshold, - ArrayI *faces -) -{ - E_Int *ftag = (E_Int *)XMALLOC(mcount * sizeof(E_Int)); - memset(ftag, 0, mcount * sizeof(E_Int)); - - for (E_Int i = 0; i < spcount; i++) { - const PointFaces *pfaces = &sploc[i]; - for (E_Int j = 0; j < pfaces->count; j++) - ftag[pfaces->ptr[j]]++; - } - - faces->count = 0; - - for (E_Int i = 0; i < mcount; i++) { - if (ftag[i] > threshold) - faces->count++; - } - - faces->ptr = (E_Int *)XMALLOC(faces->count * sizeof(E_Int)); - E_Int *ptr = faces->ptr; - - for (E_Int i = 0; i < mcount; i++) { - if (ftag[i] > threshold) - *ptr++ = i;//skin[i]; - } -} - -struct SkinGraph { - E_Int nf; - E_Int *skin; - E_Int *xadj; - E_Int *fpts; - E_Int *fnei; -}; - -void Mesh_extract_skin(const Mesh *M, E_Int *count, E_Int **skin) -{ - *count = 0; - - for (E_Int fid = 0; fid < M->nf; fid++) { - *count += (M->neigh[fid] == -1); - } - - *skin = (E_Int *)XMALLOC(*count * sizeof(E_Int)); - E_Int *ptr = *skin; - - for (E_Int fid = 0; fid < M->nf; fid++) { - if (M->neigh[fid] == -1) - *ptr++ = fid; - } -} - -void Mesh_make_skin_connectivity(const Mesh *M, SkinGraph *skin_graph) -{ - // Count - skin_graph->xadj = (E_Int *)XMALLOC((skin_graph->nf+1) * sizeof(E_Int)); - E_Int *xadj = skin_graph->xadj; - xadj[0] = 0; - - for (E_Int i = 0; i < skin_graph->nf; i++) { - E_Int fid = skin_graph->skin[i]; - const E_Int *frange = Mesh_get_frange(M, fid); - xadj[i+1] = 0; - for (E_Int j = 0; j < M->fstride[fid]; j++) - xadj[i+1] += frange[j]; - xadj[i+1] += xadj[i]; - } - - skin_graph->fpts = (E_Int *)XMALLOC(xadj[skin_graph->nf] * sizeof(E_Int)); - - // Populate - E_Int *ptr = skin_graph->fpts; - - for (E_Int i = 0; i < skin_graph->nf; i++) { - E_Int fid = skin_graph->skin[i]; - const E_Int *face = Mesh_get_face(M, fid); - const E_Int *frange = Mesh_get_frange(M, fid); - for (E_Int j = 0; j < M->fstride[fid]; j++) { - const E_Int *pn = face + 2*j; - for (E_Int k = 0; k < frange[j]; k++) - *ptr++ = pn[k]; - } - } -} - -struct EdgeNode { - E_Int p, q; - E_Int i, j; - E_Int posi, posj; - EdgeNode *next; -}; - -EdgeNode *make_edge_node(E_Int p, E_Int q, E_Int i, E_Int posi) -{ - EdgeNode *node = (EdgeNode *)XMALLOC(sizeof(EdgeNode)); - node->p = p < q ? p : q; - node->q = p < q ? q : p; - node->i = i; - node->posi = posi; - node->j = -1; - node->posj = -1; - node->next = NULL; - return node; -} - -EdgeNode *find_edge_node(EdgeNode **ht, E_Int hsize, E_Int p, E_Int q) -{ - E_Int p_ = p < q ? p : q; - E_Int q_ = p < q ? q : p; - E_Int bucket = p_ % hsize; - EdgeNode *current = ht[bucket]; - - while (current) { - E_Int P = current->p, Q = current->q; - if (P == p_ && Q == q_) { - return current; - } - current = current->next; - } - - return NULL; -} - -void insert_edge_node(EdgeNode *node, const E_Int hsize, EdgeNode **ht) -{ - assert(node->p < node->q); - E_Int bucket = node->p % hsize; - EdgeNode *current = ht[bucket]; - - if (current) { - EdgeNode *tmp = current; - ht[bucket] = node; - node->next = tmp; - } else { - ht[bucket] = node; - } -} - -void Mesh_make_skin_neighbours(const Mesh *M, SkinGraph *skin_graph) -{ - E_Int nf = skin_graph->nf; - const E_Int *xadj = skin_graph->xadj; - const E_Int *fpts = skin_graph->fpts; - - skin_graph->fnei = (E_Int *)XMALLOC(xadj[nf] * sizeof(E_Int)); - E_Int *fnei = skin_graph->fnei; - memset(fnei, -1, xadj[nf] * sizeof(E_Int)); - - EdgeNode **ht = (EdgeNode **)XMALLOC(nf * sizeof(EdgeNode *)); - memset(ht, 0, nf * sizeof(EdgeNode *)); - - for (E_Int i = 0; i < nf; i++) { - E_Int start = xadj[i]; - E_Int np = xadj[i+1] - start; - const E_Int *pn = &fpts[start]; - for (E_Int j = 0; j < np; j++) { - E_Int p = pn[j]; - E_Int q = pn[(j+1)%np]; - EdgeNode *node = find_edge_node(ht, nf, p, q); - if (node) { - assert(node->i != -1); - assert(node->posi != -1); - assert(node->j == -1); - assert(node->posj == -1); - node->j = i; - node->posj = j; - } else { - node = make_edge_node(p, q, i, j); - insert_edge_node(node, nf, ht); - } - } - } - - for (E_Int i = 0; i < nf; i++) { - EdgeNode *node = ht[i]; - while (node) { - E_Int pi = xadj[node->i] + node->posi; - assert(fnei[pi] == -1); - fnei[pi] = node->j; - - E_Int pj = xadj[node->j] + node->posj; - assert(fnei[pj] == -1); - fnei[pj] = node->i; - - node = node->next; - } - } -} - -void Mesh_make_skin_graph(const Mesh *M, SkinGraph *skin_graph) -{ - Mesh_extract_skin(M, &skin_graph->nf, &skin_graph->skin); - Mesh_make_skin_connectivity(M, skin_graph); - Mesh_make_skin_neighbours(M, skin_graph); -} - -struct Vec3f { - E_Float x, y, z; -}; - -void Mesh_make_face_centers(const Mesh *M, const E_Int nf, const E_Int *skin, - Vec3f *fc) -{ - for (E_Int i = 0; i < nf; i++) { - E_Int fid = skin[i]; - const E_Int *face = Mesh_get_face(M, fid); - const E_Int *frange = Mesh_get_frange(M, fid); - fc[i].x = fc[i].y = fc[i].z = 0.0; - E_Int np = 0; - for (E_Int j = 0; j < M->fstride[fid]; j++) { - const E_Int *pn = face + 2*j; - for (E_Int k = 0; k < frange[j]; k++) { - fc[i].x += M->X[pn[k]]; - fc[i].y += M->Y[pn[k]]; - fc[i].z += M->Z[pn[k]]; - np++; - } - } - fc[i].x /= np; fc[i].y /= np; fc[i].z /= np; - } -} - -Box3 Box3_make -( - const Mesh *M, - const E_Int *skin, - const E_Int *indices, - E_Int start, E_Int end -) -{ - E_Float xmin, ymin, zmin, xmax, ymax, zmax; - xmin = ymin = zmin = FLT_MAX; - xmax = ymax = zmax = -FLT_MAX; - - for (E_Int i = start; i < end; i++) { - E_Int fid = skin[indices[i]]; - E_Int *face = Mesh_get_face(M, fid); - E_Int *frange = Mesh_get_frange(M, fid); - - for (E_Int j = 0; j < M->fstride[fid]; j++) { - E_Int *pn = face + 2*j; - for (E_Int k = 0; k < frange[j]; k++) { - E_Int pid = pn[k]; - if (M->X[pid] < xmin) xmin = M->X[pid]; - if (M->Y[pid] < ymin) ymin = M->Y[pid]; - if (M->Z[pid] < zmin) zmin = M->Z[pid]; - - if (M->X[pid] > xmax) xmax = M->X[pid]; - if (M->Y[pid] > ymax) ymax = M->Y[pid]; - if (M->Z[pid] > zmax) zmax = M->Z[pid]; - } - } - } - - // Safety - E_Float dx = (xmax - xmin) * 0.01; - E_Float dy = (ymax - ymin) * 0.01; - E_Float dz = (zmax - zmin) * 0.01; - xmin -= dx; - ymin -= dy; - zmin -= dz; - xmax += dx; - ymax += dy; - zmax += dz; - - return {xmin, ymin, zmin, xmax, ymax, zmax}; -} - -BVH_node *BVH_make(const Mesh *M, const E_Int *skin, const Vec3f *fc, - E_Int *indices, E_Int start, E_Int end, const Box3 *parent_box) -{ - Box3 box = Box3_make(M, skin, indices, start, end); - Box3_clamp(parent_box, &box); - assert(Box3_in_Box3(box, *parent_box)); - - E_Int count = end - start; - if (count <= MAX_FACES_PER_BVH_LEAF) { - return BVH_create_node(&box, start, end, NULL, NULL); - } - - E_Float dx = box.xmax - box.xmin; - E_Float dy = box.ymax - box.ymin; - E_Float dz = box.zmax - box.zmin; - - E_Int dim = -1; - - if (dx >= dy && dx >= dz) { - dim = 0; - } else if (dy >= dz) { - dim = 1; - } else { - dim = 2; - } - - std::sort(indices + start, indices + end, - [&](const E_Int i, const E_Int j) - { - E_Float *fci = (E_Float *)(&fc[i]); - E_Float *fcj = (E_Float *)(&fc[j]); - return fci[dim] < fcj[dim]; - }); - - E_Int mid = start + count/2; - - BVH_node *left = BVH_make(M, skin, fc, indices, start, mid, &box); - BVH_node *right = BVH_make(M, skin, fc, indices, mid, end, &box); - - assert(Box3_in_Box3(left->box, box)); - assert(Box3_in_Box3(right->box, box)); - - return BVH_create_node(&box, start, end, left, right); -} - -bool point_in_tri(E_Float px, E_Float py, E_Float pz, - E_Float ax, E_Float ay, E_Float az, - E_Float bx, E_Float by, E_Float bz, - E_Float cx, E_Float cy, E_Float cz) -{ - // Normal vector to the plane - E_Float Y[3] = {bx-ax, by-ay, bz-az}; - E_Float Z[3] = {cx-ax, cy-ay, cz-az}; - E_Float N[3]; - K_MATH::cross(Y, Z, N); - - E_Float X[3] = {px-ax, py-ay, pz-az}; - - E_Float dp = K_MATH::dot(N, X, 3); - - // Is the point on the plane? - if (dp < -TOL || dp > TOL) return 0; - - E_Float x1 = K_MATH::dot(X, Y, 3); - E_Float y1 = K_MATH::dot(Y, Y, 3); - E_Float z1 = K_MATH::dot(Z, Y, 3); - E_Float x2 = K_MATH::dot(X, Z, 3); - E_Float y2 = K_MATH::dot(Y, Z, 3); - E_Float z2 = K_MATH::dot(Z, Z, 3); - - E_Float u = (x1*z2 - x2*z1) / (y1*z2 - y2*z1); - if (u < -TOL || u > 1 + TOL) return false; - - E_Float v = (-x1*y2 + x2*y1) / (y1*z2 - y2*z1); - if (v < -TOL || v > 1 + TOL) return false; - - E_Float w = 1 - u - v; - if (w < -TOL || w > 1 + TOL) return false; - - return true; -} - -bool Mesh_point_in_tri(const Mesh *M, const Point *p, E_Int tid) -{ - const E_Int *face = Mesh_get_face(M, tid); - E_Int A = face[0], B = face[2], C = face[4]; - return point_in_tri(p->x, p->y, p->z, - M->X[A], M->Y[A], M->Z[A], - M->X[B], M->Y[B], M->Z[B], - M->X[C], M->Y[C], M->Z[C]); -} - -bool Mesh_point_in_quad(const Mesh *M, const Point *p, E_Int qid) -{ - // TODO(Imad): maybe compute face centers once in pre-pass - // Star the quad into 4 triangles - E_Float O[3] = {0.0, 0.0, 0.0}; - const E_Int *face = Mesh_get_face(M, qid); - E_Int A = face[0], B = face[2], C = face[4], D = face[6]; - O[0] = (M->X[A] + M->X[B] + M->X[C] + M->X[D]) * 0.25; - O[1] = (M->Y[A] + M->Y[B] + M->Y[C] + M->Y[D]) * 0.25; - O[2] = (M->Z[A] + M->Z[B] + M->Z[C] + M->Z[D]) * 0.25; - - bool hit = false; - - // First triangle - hit = point_in_tri(p->x, p->y, p->z, - O[0], O[1], O[2], - M->X[A], M->Y[A], M->Z[A], - M->X[B], M->Y[B], M->Z[B]); - if (hit) return true; - - // Second triangle - hit = point_in_tri(p->x, p->y, p->z, - O[0], O[1], O[2], - M->X[B], M->Y[B], M->Z[B], - M->X[C], M->Y[C], M->Z[C]); - if (hit) return true; - - - // Third triangle - hit = point_in_tri(p->x, p->y, p->z, - O[0], O[1], O[2], - M->X[C], M->Y[C], M->Z[C], - M->X[D], M->Y[D], M->Z[D]); - if (hit) return true; - - // Fourth triangle - hit = point_in_tri(p->x, p->y, p->z, - O[0], O[1], O[2], - M->X[D], M->Y[D], M->Z[D], - M->X[A], M->Y[A], M->Z[A]); - if (hit) return true; - - return false; -} - -bool Mesh_point_in_face(const Mesh *M, const Point *p, E_Int fid) -{ - if (M->ftype[fid] == QUAD) return Mesh_point_in_quad(M, p, fid); - assert(M->ftype[fid] == TRI); - return Mesh_point_in_tri(M, p, fid); -} - -void BVH_locate_point -( - const BVH_node *node, - const Mesh *M, - const E_Int *skin, - const E_Int *indices, - const Point *p, - PointFaces *pfaces -) -{ - if (node->left == NULL && node->right == NULL) { - for (E_Int i = node->start; i < node->end; i++) { - E_Int fid = skin[indices[i]]; - - if (Mesh_point_in_face(M, p, fid)) { - if (pfaces->count >= MAX_FACES_PER_POINT) { - fprintf(stderr, - "bvh_locate: MAX_FACES_PER_POINT exceeded!\n"); - abort(); - } - pfaces->ptr[pfaces->count++] = i; - } - } - return; - } - - assert(node->left && node->right); - assert(Box3_in_Box3(node->left->box, node->box)); - assert(Box3_in_Box3(node->right->box, node->box)); - - bool in_box = Point_in_Box3D(p, &node->box); - - if (!in_box) - return; - - BVH_locate_point(node->left, M, skin, indices, p, pfaces); - BVH_locate_point(node->right, M, skin, indices, p, pfaces); -} - void locate_spoints_in_mskin ( const Mesh *S, @@ -798,35 +29,37 @@ void locate_spoints_in_mskin if (pfaces->count == 0) { fprintf(stderr, "bvh_locate: failed at point index %d (%d)!\n", i, spid); - point_write(p); + point_write(&p); abort(); } } } +#include + void smooth_skin_ref_data(Mesh *M, const SkinGraph *skin_graph, E_Int *fdat) { E_Int nf = skin_graph->nf; - E_Int stack_size = 3*nf; - E_Int *fstack = (E_Int *)XMALLOC(stack_size * sizeof(E_Int)); - memset(fstack, -1, stack_size * sizeof(E_Int)); - E_Int l = 0; + std::stack stk; for (E_Int i = 0; i < nf; i++) { if (fdat[i] > 0) - fstack[l++] = i; + stk.push(i); } const E_Int *xadj = skin_graph->xadj; const E_Int *fnei = skin_graph->fnei; - while (--l >= 0) { - E_Int fid = fstack[l]; + while (!stk.empty()) { + + E_Int fid = stk.top(); + stk.pop(); E_Int start = xadj[fid]; E_Int nneis = xadj[fid+1] - start; const E_Int *neis = &fnei[start]; + for (E_Int i = 0; i < nneis; i++) { E_Int nei = neis[i]; E_Int incr_nei = fdat[nei] + M->flevel[skin_graph->skin[nei]]; @@ -835,13 +68,9 @@ void smooth_skin_ref_data(Mesh *M, const SkinGraph *skin_graph, E_Int *fdat) if (diff <= 1) continue; E_Int idx_to_modify = incr_fid > incr_nei ? nei : fid; fdat[idx_to_modify] += diff-1; - l++; - assert(l < stack_size); - fstack[l] = idx_to_modify; + stk.push(idx_to_modify); } } - - XFREE(fstack); } void init_skin_refinement_cells(const SkinGraph *skin_graph, @@ -864,41 +93,20 @@ void init_skin_refinement_cells(const SkinGraph *skin_graph, *rcount = count; } -/* -void Mesh_extract_refinement_cells(const Mesh *M, ArrayI *rcells) -{ - rcells->count = 0; - - for (E_Int cid = 0; cid < M->nc; cid++) { - rcells->count += (M->cref[cid] > 0); - } - - rcells->ptr = (E_Int *)XMALLOC(rcells->count * sizeof(E_Int)); - E_Int *ptr = rcells->ptr; - - for (E_Int cid = 0; cid < M->nc; cid++) { - if (M->cref[cid] > 0) - *ptr++ = cid; - } -} -*/ - void smooth_cell_refinement_data(Mesh *M) { E_Int nc = M->nc; - E_Int stack_size = 3*nc; - E_Int *cstack = (E_Int *)XMALLOC(stack_size * sizeof(E_Int)); - memset(cstack, -1, stack_size * sizeof(E_Int)); - E_Int l = 0; + std::stack stk; for (E_Int cid = 0; cid < nc; cid++) { if (M->cref[cid] > 0) - cstack[l++] = cid; + stk.push(cid); } - while (--l >= 0) { - E_Int cid = cstack[l]; + while (!stk.empty()) { + E_Int cid = stk.top(); + stk.pop(); E_Int nn, neis[24]; Mesh_get_cneis(M, cid, nn, neis); @@ -910,15 +118,12 @@ void smooth_cell_refinement_data(Mesh *M) E_Int diff = abs(incr_nei - incr_cid); if (diff <= 1) continue; E_Int idx_to_modify = incr_cid > incr_nei ? nei : cid; - M->cref[idx_to_modify] += 1; - l++; - assert(l < stack_size); - cstack[l] = idx_to_modify; + M->cref[idx_to_modify] += diff-1; + stk.push(idx_to_modify); } } } -static void Mesh_set_face_as_cell_bottom(Mesh *M, E_Int fid, E_Int cid) { // Make fid the bottom face @@ -933,25 +138,6 @@ void Mesh_set_face_as_cell_bottom(Mesh *M, E_Int fid, E_Int cid) Right_shift(crange, pos/4, M->cstride[cid]); } -void reorder_cells_for_H18(const SkinGraph *skin_graph, const E_Int *indices, - const ArrayI *rfaces, Mesh *M) -{ - for (E_Int i = 0; i < rfaces->count; i++) { - E_Int idx_in_skin = indices[rfaces->ptr[i]]; - E_Int fid = skin_graph->skin[idx_in_skin]; - E_Int own = M->owner[fid]; - assert(M->cref[own] == 1); - - while (M->cref[own] == 1) { - Mesh_set_face_as_cell_bottom(M, fid, own); - // Get the top face - fid = Mesh_get_cell(M, own)[4]; - // Get the top neighbour - own = Mesh_get_cnei(M, own, fid); - } - } -} - void assign_face_refinement_data(Mesh *M) { for (E_Int cid = 0; cid < M->nc; cid++) { @@ -1032,124 +218,6 @@ void Mesh_resize(Mesh *M, const ArrayI *rcells, const ArrayI *rfaces) Mesh_resize_cell_data(M, new_nc); } -#define DIR_ISO 0 -#define DIR_X 1 -#define DIR_Y 2 - -void prepare_cell_ordering_and_face_refinement_patterns(Mesh *M, - const ArrayI *rcells, const ArrayI *rfaces) -{ - for (E_Int i = 0; i < rcells->count; i++) { - E_Int cid = rcells->ptr[i]; - assert(M->cref[cid] == 1); - if (M->clevel[cid] == 0) { - H18_reorder(cid, M); - assert(check_canon_hexa(cid, M) == 0); - } - } - - for (E_Int i = 0; i < rfaces->count; i++) { - E_Int fid = rfaces->ptr[i]; - if (M->flevel[fid] > 0) continue; - - E_Int cid = M->owner[fid]; - if (M->cref[cid] == 0) - cid = M->neigh[fid]; - - assert(cid != -1); - assert(M->cref[cid] == 1); - - E_Int *cell = Mesh_get_cell(M, cid); - E_Int *crange = Mesh_get_crange(M, cid); - - E_Int pos = Get_pos(fid, cell, 4*M->cstride[cid]); - E_Int side = pos / 4; - E_Int *face = Mesh_get_face(M, fid); - - if (side == 0 || side == 1) { - M->fpattern[fid] = DIR_ISO; - } else { - - // Reconstruct bottom - E_Int map[4]; - E_Int bot = cell[0]; - E_Int N0 = Mesh_get_face(M, bot)[0]; - reconstruct_quad(M, cid, cell, crange[0], normalIn_H[0], N0, map); - - M->fpattern[fid] = DIR_ISO; - - E_Int i0; - E_Int reorient; - - if (side == 2) { - - E_Int np, lpts[8]; - for (E_Int j = 0; j < 8; j++) lpts[j] = -1; - Mesh_get_fpoints(M, fid, np, lpts); - - // Must share map[0] && map[3] - i0 = Get_pos(map[3], face, 8); - assert(i0 != -1); - i0 = Get_pos(map[0], face, 8); - assert(i0 != -1); - reorient = Mesh_get_reorient(M, fid, cid, normalIn_H[side]); - - } else if (side == 3) { - - // Must share map[1] && map[2] - i0 = Get_pos(map[2], face, 8); - assert(i0 != -1); - i0 = Get_pos(map[1], face, 8); - assert(i0 != -1); - reorient = Mesh_get_reorient(M, fid, cid, normalIn_H[side]); - - } else if (side == 4) { - - // Must share map[1] && map[0] - i0 = Get_pos(map[0], face, 8); - assert(i0 != -1); - i0 = Get_pos(map[1], face, 8); - assert(i0 != -1); - reorient = Mesh_get_reorient(M, fid, cid, normalIn_H[side]); - - } else if (side == 5) { - - // Must share map[2] && map[3] - i0 = Get_pos(map[3], face, 8); - assert(i0 != -1); - i0 = Get_pos(map[2], face, 8); - assert(i0 != -1); - reorient = Mesh_get_reorient(M, fid, cid, normalIn_H[side]); - - } else { - assert(0); - } - - - i0 /= 2; - - assert(i0 == 0 || i0 == 1 || i0 == 2 || i0 == 3); - - if (reorient == 0) { - if (i0 == 0 || i0 == 2) M->fpattern[fid] = DIR_X; - else M->fpattern[fid] = DIR_Y; - } else { - if (i0 == 0 || i0 == 2) M->fpattern[fid] = DIR_Y; - else M->fpattern[fid] = DIR_X; - } - - assert(M->fpattern[fid] != DIR_ISO); - - /* - bool swap_1 = (reorient == 0) && (i0 == 1 || i0 == 3); - bool swap_2 = (reorient == 1) && (i0 == 0 || i0 == 2); - - if (swap_1 || swap_2) M->fpattern[fid] = DIR_Y; - */ - } - } -} - E_Int refine_quad_X(E_Int quad, Mesh *M) { assert(M->fref[quad] == 1); @@ -1253,6 +321,8 @@ E_Int refine_quad_X(E_Int quad, Mesh *M) M->ftag[M->nf] = M->ftag[quad]; + M->fpattern[M->nf] = M->fpattern[quad]; + // Increment face/edge/point count M->nf += 1; @@ -1361,6 +431,8 @@ E_Int refine_quad_Y(E_Int quad, Mesh *M) M->ftag[M->nf] = M->ftag[quad]; + M->fpattern[M->nf] = M->fpattern[quad]; + // Increment face/edge/point count M->nf += 1; @@ -1400,6 +472,7 @@ void Mesh_refine_dir(Mesh *M, ArrayI *ref_cells, ArrayI *ref_faces) while (faces_left >= 0 && M->flevel[ref_faces->ptr[faces_left]] == level) { E_Int face = ref_faces->ptr[faces_left]; faces_left--; + assert(M->fpattern[face] != -1); refine_quad_dir(face, M); } @@ -1411,29 +484,6 @@ void Mesh_refine_dir(Mesh *M, ArrayI *ref_cells, ArrayI *ref_faces) } } -void BVH_free(BVH_node *node) -{ - if (node == NULL) return; - - BVH_free(node->left); - BVH_free(node->right); - - XFREE(node); -} - -void ArrayI_free(ArrayI *arr) -{ - XFREE(arr->ptr); -} - -void SkinGraph_free(SkinGraph *skin_graph) -{ - XFREE(skin_graph->skin); - XFREE(skin_graph->xadj); - XFREE(skin_graph->fpts); - XFREE(skin_graph->fnei); -} - PyObject *K_XCORE::AdaptMesh_AdaptGeom(PyObject *self, PyObject *args) { PyObject *AMESH, *SMESH; @@ -1467,7 +517,7 @@ PyObject *K_XCORE::AdaptMesh_AdaptGeom(PyObject *self, PyObject *args) //E_Int ref_M = 0; E_Int ref_S = 0; E_Int iter = 0; - + E_Int max_iter = 10; do { iter++; printf("iter: %d\n", iter); @@ -1477,7 +527,7 @@ PyObject *K_XCORE::AdaptMesh_AdaptGeom(PyObject *self, PyObject *args) Mesh_extract_points_from_ftag(S, &spoints); // We need the skin connectivity graph - SkinGraph skin_graph; + SkinGraph skin_graph = {0}; Mesh_make_skin_graph(M, &skin_graph); printf("Skin: %d faces\n", skin_graph.nf); @@ -1509,17 +559,160 @@ PyObject *K_XCORE::AdaptMesh_AdaptGeom(PyObject *self, PyObject *args) // Isolate faces that contain more than MAX_POINTS_PER_FACE spoints ArrayI rfaces; - extract_faces_by_threshold + PointFaces_extract_by_threshold ( sploc, spoints.count, skin_graph.skin, skin_graph.nf, - MAX_POINTS_PER_FACE, + 1, // threshold &rfaces ); puts("Refinement faces isolated"); printf("Refinement faces: %d\n", rfaces.count); + if (rfaces.count == 0) break; + + if (iter == 1) { + // We need the skin face normals + Mesh_SkinGraph_compute_normals(M, &skin_graph); + + E_Int *xadj = skin_graph.xadj; + E_Int *fpts = skin_graph.fpts; + E_Int *fnei = skin_graph.fnei; + Vec3f *fnml = skin_graph.fnml; + + // Traverse the skin in breadth-first fashion + bool *visited = (bool *)XMALLOC(skin_graph.nf * sizeof(bool)); + memset(visited, 0, skin_graph.nf * sizeof(bool)); + + E_Int *fqueue = (E_Int *)XMALLOC(skin_graph.nf * sizeof(E_Int)); + memset(fqueue, -1, skin_graph.nf * sizeof(E_Int)); + + // Start from the first rface + E_Int fseed = indices[rfaces.ptr[0]]; - + E_Int front = 0, rear = 0; + fqueue[rear++] = fseed; + + visited[fseed] = true; + E_Int nvisited = 1; + + while (front != rear) { + E_Int fid = fqueue[front++]; + + E_Int start = xadj[fid]; + E_Int end = xadj[fid+1]; + E_Int stride = end - start; + E_Int *pp = &fpts[start]; + E_Int *pn = &fnei[start]; + + Vec3f *fid_nml = &fnml[fid]; + + for (E_Int i = 0; i < stride; i++) { + E_Int nei = pn[i]; + if (visited[nei]) continue; + + Vec3f *nei_nml = &fnml[nei]; + E_Float dp = K_MATH::dot((E_Float *)fid_nml, (E_Float *)nei_nml, 3); + assert(dp >= 0.0); + dp = std::max(dp, -1.0); + dp = std::min(dp, 1.0); + E_Float theta = acos(dp) * 180.0 / K_MATH::PI; + + if (theta < 60.0 || theta > 120.0) { + visited[nei] = true; + fqueue[rear++] = nei; + nvisited++; + } + } + } + + /* + { + npy_intp dims[2]; + dims[1] = 1; + dims[0] = (npy_intp)nvisited; + PyArrayObject *FACES = (PyArrayObject *)PyArray_SimpleNew(1, dims, E_NPY_INT); + + E_Int *pf = (E_Int *)PyArray_DATA(FACES); + E_Int *ptr = pf; + for (E_Int i = 0; i < skin_graph.nf; i++) { + if (visited[i]) { + *ptr++ = skin_graph.skin[i]+1; + } + } + + return (PyObject *)FACES; + } + */ + + // Set the base patch + E_Int cvisit = 0; + for (E_Int i = 0; i < skin_graph.nf; i++) { + if (visited[i] == 0) continue; + + E_Int fid = skin_graph.skin[i]; + E_Int cid = M->owner[fid]; + + while (cid != -1) { + cvisit++; + Mesh_set_face_as_cell_bottom(M, fid, cid); + H18_reorder(cid, M); + assert(check_canon_hexa(cid, M) == 0); + + E_Int *cell = Mesh_get_cell(M, cid); + + E_Int map[4]; + E_Int *face = Mesh_get_face(M, fid); + for (E_Int j = 0; j < 4; j++) map[j] = face[2*j]; + E_Int reorient = Mesh_get_reorient(M, fid, cid, normalIn_H[0]); + if (reorient) std::swap(map[1], map[3]); + + for (E_Int j = 0; j < 6; j++) { + fid = cell[4*j]; + + if (M->fpattern[fid] != -1) continue; + + if (j == 0 || j == 1) { + M->fpattern[fid] = DIR_ISO; + } else { + + E_Int i0; + reorient = Mesh_get_reorient(M, fid, cid, normalIn_H[j]); + face = Mesh_get_face(M, fid); + + M->fpattern[fid] = DIR_X; + + if (j == 2) { + i0 = Get_pos(map[0], face, 8); + } else if (j == 3) { + i0 = Get_pos(map[1], face, 8); + } else if (j == 4) { + i0 = Get_pos(map[1], face, 8); + } else if (j == 5) { + i0 = Get_pos(map[2], face, 8); + } + + assert(i0 != -1); + i0 /= 2; + + if ((reorient == 0 && (i0 == 1 || i0 == 3)) || + (reorient == 1 && (i0 == 0 || i0 == 2))) { + M->fpattern[fid] = DIR_Y; + } + } + } + + // Step to top adjacent cell + fid = cell[4]; + cid = Mesh_get_cnei(M, cid, fid); + } + } + + assert(cvisit = M->nc); + + XFREE(visited); + XFREE(fqueue); + } + // Smooth face refinement data E_Int *fdat = (E_Int *)XMALLOC(skin_graph.nf * sizeof(E_Int)); memset(fdat, 0, skin_graph.nf * sizeof(E_Int)); @@ -1536,7 +729,8 @@ PyObject *K_XCORE::AdaptMesh_AdaptGeom(PyObject *self, PyObject *args) } printf("Smooth refinement face count: %d\n", smooth_nfref); - if (iter == 2) { + /* + if (iter == 1) { npy_intp dims[2]; dims[1] = 1; dims[0] = (npy_intp)smooth_nfref; @@ -1552,6 +746,7 @@ PyObject *K_XCORE::AdaptMesh_AdaptGeom(PyObject *self, PyObject *args) //puts(""); return (PyObject *)FACES; } + */ // Allocate M->cref = (E_Int *)XRESIZE(M->cref, M->nc * sizeof(E_Int)); @@ -1577,15 +772,6 @@ PyObject *K_XCORE::AdaptMesh_AdaptGeom(PyObject *self, PyObject *args) Mesh_isolate_refinement_entities(M, &ref_cells, &ref_faces); printf("Refinement cells: %d\n", ref_cells.count); printf("Refinement faces: %d\n", ref_faces.count); - - // Setup bottom/top face chain - reorder_cells_for_H18(&skin_graph, indices, &rfaces, M); - - // Prepare cell ordering and face refinement direction - M->fpattern = (E_Int *)XRESIZE(M->fpattern, M->nf * sizeof(E_Int)); - memset(M->fpattern, -1, M->nf * sizeof(E_Int)); - prepare_cell_ordering_and_face_refinement_patterns(M, &ref_cells, - &ref_faces); // Resize for refinement Mesh_resize(M, &ref_cells, &ref_faces); @@ -1626,7 +812,7 @@ PyObject *K_XCORE::AdaptMesh_AdaptGeom(PyObject *self, PyObject *args) // FREE - } while (1); + } while (iter < max_iter); diff --git a/Cassiopee/XCore/XCore/AdaptMesh/AdaptMesh_Init.cpp b/Cassiopee/XCore/XCore/AdaptMesh/AdaptMesh_Init.cpp index 99815e42e..8dc1094e4 100644 --- a/Cassiopee/XCore/XCore/AdaptMesh/AdaptMesh_Init.cpp +++ b/Cassiopee/XCore/XCore/AdaptMesh/AdaptMesh_Init.cpp @@ -239,7 +239,8 @@ PyObject *K_XCORE::AdaptMesh_Init(PyObject *self, PyObject *args) M->cref = NULL; M->fref = NULL; - M->fpattern = NULL; + M->fpattern = (E_Int *)XMALLOC(M->nf * sizeof(E_Int)); + memset(M->fpattern, -1, M->nf * sizeof(E_Int)); M->ctag = IntArray(M->nc); M->ftag = IntArray(M->nf); diff --git a/Cassiopee/XCore/XCore/AdaptMesh/Array.cpp b/Cassiopee/XCore/XCore/AdaptMesh/Array.cpp new file mode 100644 index 000000000..ab3497d30 --- /dev/null +++ b/Cassiopee/XCore/XCore/AdaptMesh/Array.cpp @@ -0,0 +1,7 @@ +#include "Array.h" +#include "common/mem.h" + +void ArrayI_free(ArrayI *arr) +{ + XFREE(arr->ptr); +} \ No newline at end of file diff --git a/Cassiopee/XCore/XCore/AdaptMesh/Array.h b/Cassiopee/XCore/XCore/AdaptMesh/Array.h new file mode 100644 index 000000000..bf440937d --- /dev/null +++ b/Cassiopee/XCore/XCore/AdaptMesh/Array.h @@ -0,0 +1,10 @@ +#pragma once + +#include "xcore.h" + +struct ArrayI { + E_Int count; + E_Int *ptr; +}; + +void ArrayI_free(ArrayI *arr); \ No newline at end of file diff --git a/Cassiopee/XCore/XCore/AdaptMesh/BVH.cpp b/Cassiopee/XCore/XCore/AdaptMesh/BVH.cpp new file mode 100644 index 000000000..8555f887f --- /dev/null +++ b/Cassiopee/XCore/XCore/AdaptMesh/BVH.cpp @@ -0,0 +1,160 @@ +#include "BVH.h" +#include "Mesh.h" +#include "FaceSort.h" +#include "Point.h" +#include "common/mem.h" +#include "Vec.h" + +#define MAX_FACES_PER_BVH_LEAF 10 + +BVH_node *BVH_create_node(const Box3 *box, E_Int start, E_Int end, + BVH_node *left, BVH_node *right) +{ + BVH_node *node = (BVH_node *)XMALLOC(sizeof(BVH_node)); + node->box = *box; + node->start = start; + node->end = end; + node->left = left; + node->right = right; + //printf("%d -> %f %f %f %f %f %f\n", idx, box->xmin, box->ymin, box->zmin, + // box->xmax, box->ymax, box->zmax); + //idx++; + return node; +} + +BVH_node *BVH_make(const Mesh *M, FaceSort *mfaces, E_Int start, E_Int end, + const Box3 *parent_box) +{ + Box3 box = Box3_make(M, mfaces, start, end); + Box3_clamp(parent_box, &box); + assert(Box3_in_Box3(box, *parent_box)); + + E_Int count = end - start; + if (count <= MAX_FACES_PER_BVH_LEAF) { + return BVH_create_node(&box, start, end, NULL, NULL); + } + + E_Float dx = box.xmax - box.xmin; + E_Float dy = box.ymax - box.ymin; + E_Float dz = box.zmax - box.zmin; + + E_Int dim = -1; + + if (dx >= dy && dx >= dz) { + dim = 0; + } else if (dy >= dz) { + dim = 1; + } else { + dim = 2; + } + + std::sort(mfaces + start, mfaces + end, + [&](const FaceSort &fi, const FaceSort &fj) + { + return fi.fc[dim] < fj.fc[dim]; + }); + + E_Int mid = start + count/2; + + BVH_node *left = BVH_make(M, mfaces, start, mid, &box); + BVH_node *right = BVH_make(M, mfaces, mid, end, &box); + + assert(Box3_in_Box3(left->box, box)); + assert(Box3_in_Box3(right->box, box)); + + return BVH_create_node(&box, start, end, left, right); +} + +BVH_node *BVH_make(const Mesh *M, const E_Int *skin, const Vec3f *fc, + E_Int *indices, E_Int start, E_Int end, const Box3 *parent_box) +{ + Box3 box = Box3_make(M, skin, indices, start, end); + Box3_clamp(parent_box, &box); + assert(Box3_in_Box3(box, *parent_box)); + + E_Int count = end - start; + if (count <= MAX_FACES_PER_BVH_LEAF) { + return BVH_create_node(&box, start, end, NULL, NULL); + } + + E_Float dx = box.xmax - box.xmin; + E_Float dy = box.ymax - box.ymin; + E_Float dz = box.zmax - box.zmin; + + E_Int dim = -1; + + if (dx >= dy && dx >= dz) { + dim = 0; + } else if (dy >= dz) { + dim = 1; + } else { + dim = 2; + } + + std::sort(indices + start, indices + end, + [&](const E_Int i, const E_Int j) + { + E_Float *fci = (E_Float *)(&fc[i]); + E_Float *fcj = (E_Float *)(&fc[j]); + return fci[dim] < fcj[dim]; + }); + + E_Int mid = start + count/2; + + BVH_node *left = BVH_make(M, skin, fc, indices, start, mid, &box); + BVH_node *right = BVH_make(M, skin, fc, indices, mid, end, &box); + + assert(Box3_in_Box3(left->box, box)); + assert(Box3_in_Box3(right->box, box)); + + return BVH_create_node(&box, start, end, left, right); +} + +void BVH_locate_point +( + const BVH_node *node, + const Mesh *M, + const E_Int *skin, + const E_Int *indices, + const Point *p, + PointFaces *pfaces +) +{ + if (node->left == NULL && node->right == NULL) { + for (E_Int i = node->start; i < node->end; i++) { + E_Int fid = skin[indices[i]]; + + if (Mesh_point_in_face(M, p, fid)) { + if (pfaces->count >= MAX_FACES_PER_POINT) { + fprintf(stderr, + "bvh_locate: MAX_FACES_PER_POINT exceeded!\n"); + abort(); + } + pfaces->ptr[pfaces->count++] = i; + } + } + return; + } + + assert(node->left && node->right); + assert(Box3_in_Box3(node->left->box, node->box)); + assert(Box3_in_Box3(node->right->box, node->box)); + + bool in_box = Point_in_Box3D(p, &node->box); + + if (!in_box) + return; + + BVH_locate_point(node->left, M, skin, indices, p, pfaces); + BVH_locate_point(node->right, M, skin, indices, p, pfaces); +} + +void BVH_free(BVH_node *node) +{ + if (node == NULL) return; + + BVH_free(node->left); + BVH_free(node->right); + + XFREE(node); +}; \ No newline at end of file diff --git a/Cassiopee/XCore/XCore/AdaptMesh/BVH.h b/Cassiopee/XCore/XCore/AdaptMesh/BVH.h new file mode 100644 index 000000000..18ada3203 --- /dev/null +++ b/Cassiopee/XCore/XCore/AdaptMesh/BVH.h @@ -0,0 +1,37 @@ +#pragma once + +#include "Box.h" + +struct Mesh; +struct FaceSort; +struct Vec3f; +struct Point; +struct PointFaces; + +struct BVH_node { + Box3 box; + E_Int start, end; + BVH_node *left; + BVH_node *right; +}; + +BVH_node *BVH_create_node(const Box3 *box, E_Int start, E_Int end, + BVH_node *left, BVH_node *right); + +BVH_node *BVH_make(const Mesh *M, FaceSort *mfaces, E_Int start, E_Int end, + const Box3 *parent_box); + +BVH_node *BVH_make(const Mesh *M, const E_Int *skin, const Vec3f *fc, + E_Int *indices, E_Int start, E_Int end, const Box3 *parent_box); + +void BVH_locate_point +( + const BVH_node *node, + const Mesh *M, + const E_Int *skin, + const E_Int *indices, + const Point *p, + PointFaces *pfaces +); + +void BVH_free(BVH_node *node); \ No newline at end of file diff --git a/Cassiopee/XCore/XCore/AdaptMesh/Box.cpp b/Cassiopee/XCore/XCore/AdaptMesh/Box.cpp new file mode 100644 index 000000000..7d41e2ec6 --- /dev/null +++ b/Cassiopee/XCore/XCore/AdaptMesh/Box.cpp @@ -0,0 +1,106 @@ +#include "Box.h" +#include "Mesh.h" +#include "FaceSort.h" + +Box3 Box3_make +( + const Mesh *M, + const FaceSort *mfaces, + E_Int start, E_Int end +) +{ + E_Float xmin, ymin, zmin, xmax, ymax, zmax; + xmin = ymin = zmin = FLT_MAX; + xmax = ymax = zmax = -FLT_MAX; + + for (E_Int i = start; i < end; i++) { + E_Int fid = mfaces[i].fid; + E_Int *face = Mesh_get_face(M, fid); + E_Int *frange = Mesh_get_frange(M, fid); + assert(M->fstride[fid] == 3); + assert(M->ftype[fid] == TRI); + for (E_Int j = 0; j < M->fstride[fid]; j++) { + E_Int *pn = face + 2*j; + assert(frange[j] == 1); + for (E_Int k = 0; k < frange[j]; k++) { + E_Int pid = pn[k]; + if (M->X[pid] < xmin) xmin = M->X[pid]; + if (M->Y[pid] < ymin) ymin = M->Y[pid]; + if (M->Z[pid] < zmin) zmin = M->Z[pid]; + + if (M->X[pid] > xmax) xmax = M->X[pid]; + if (M->Y[pid] > ymax) ymax = M->Y[pid]; + if (M->Z[pid] > zmax) zmax = M->Z[pid]; + } + } + } + + // Safety + E_Float dx = (xmax - xmin) * 0.01; + E_Float dy = (ymax - ymin) * 0.01; + E_Float dz = (zmax - zmin) * 0.01; + xmin -= dx; + ymin -= dy; + zmin -= dz; + xmax += dx; + ymax += dy; + zmax += dz; + + return {xmin, ymin, zmin, xmax, ymax, zmax}; +} + +void Box3_clamp(const Box3 *parent, Box3 *child) +{ + child->xmin = std::max(parent->xmin, child->xmin); + child->ymin = std::max(parent->ymin, child->ymin); + child->zmin = std::max(parent->zmin, child->zmin); + child->xmax = std::min(parent->xmax, child->xmax); + child->ymax = std::min(parent->ymax, child->ymax); + child->zmax = std::min(parent->zmax, child->zmax); +} + +Box3 Box3_make +( + const Mesh *M, + const E_Int *skin, + const E_Int *indices, + E_Int start, E_Int end +) +{ + E_Float xmin, ymin, zmin, xmax, ymax, zmax; + xmin = ymin = zmin = FLT_MAX; + xmax = ymax = zmax = -FLT_MAX; + + for (E_Int i = start; i < end; i++) { + E_Int fid = skin[indices[i]]; + E_Int *face = Mesh_get_face(M, fid); + E_Int *frange = Mesh_get_frange(M, fid); + + for (E_Int j = 0; j < M->fstride[fid]; j++) { + E_Int *pn = face + 2*j; + for (E_Int k = 0; k < frange[j]; k++) { + E_Int pid = pn[k]; + if (M->X[pid] < xmin) xmin = M->X[pid]; + if (M->Y[pid] < ymin) ymin = M->Y[pid]; + if (M->Z[pid] < zmin) zmin = M->Z[pid]; + + if (M->X[pid] > xmax) xmax = M->X[pid]; + if (M->Y[pid] > ymax) ymax = M->Y[pid]; + if (M->Z[pid] > zmax) zmax = M->Z[pid]; + } + } + } + + // Safety + E_Float dx = (xmax - xmin) * 0.01; + E_Float dy = (ymax - ymin) * 0.01; + E_Float dz = (zmax - zmin) * 0.01; + xmin -= dx; + ymin -= dy; + zmin -= dz; + xmax += dx; + ymax += dy; + zmax += dz; + + return {xmin, ymin, zmin, xmax, ymax, zmax}; +} \ No newline at end of file diff --git a/Cassiopee/XCore/XCore/AdaptMesh/Box.h b/Cassiopee/XCore/XCore/AdaptMesh/Box.h new file mode 100644 index 000000000..91470a3ad --- /dev/null +++ b/Cassiopee/XCore/XCore/AdaptMesh/Box.h @@ -0,0 +1,36 @@ +#pragma once + +#include "xcore.h" + +struct Mesh; +struct FaceSort; + +struct Box3 { + E_Float xmin, ymin, zmin; + E_Float xmax, ymax, zmax; +}; + +inline +bool Box3_in_Box3(const Box3 small, const Box3 big) +{ + return (big.xmin <= small.xmin) && (big.xmax >= small.xmax) && + (big.ymin <= small.ymin) && (big.ymax >= small.ymax) && + (big.zmin <= small.zmin) && (big.zmax >= small.zmax); +} + +Box3 Box3_make +( + const Mesh *M, + const FaceSort *mfaces, + E_Int start, E_Int end +); + +Box3 Box3_make +( + const Mesh *M, + const E_Int *skin, + const E_Int *indices, + E_Int start, E_Int end +); + +void Box3_clamp(const Box3 *parent, Box3 *child); \ No newline at end of file diff --git a/Cassiopee/XCore/XCore/AdaptMesh/FaceSort.cpp b/Cassiopee/XCore/XCore/AdaptMesh/FaceSort.cpp new file mode 100644 index 000000000..5157baf13 --- /dev/null +++ b/Cassiopee/XCore/XCore/AdaptMesh/FaceSort.cpp @@ -0,0 +1,42 @@ +#include "FaceSort.h" +#include "Mesh.h" + +void FaceSort_compute_data(const Mesh *M, FaceSort *mfaces, E_Int mcount) +{ + for (E_Int i = 0; i < mcount; i++) { + FaceSort *face = &mfaces[i]; + + E_Int tid = face->fid; + assert(M->ftype[tid] == TRI); + + E_Int *tri = Mesh_get_face(M, tid); + E_Int A = tri[0], B = tri[2], C = tri[4]; + + face->UX = (M->X[B] - M->X[A]); + face->UY = (M->Y[B] - M->Y[A]); + face->UZ = (M->Z[B] - M->Z[A]); + + face->VX = (M->X[C] - M->X[A]); + face->VY = (M->Y[C] - M->Y[A]); + face->VZ = (M->Z[C] - M->Z[A]); + + face->UU = face->UX*face->UX + face->UY*face->UY + face->UZ*face->UZ; + face->VV = face->VX*face->VX + face->VY*face->VY + face->VZ*face->VZ; + face->UV = face->UX*face->VX + face->UY*face->VY + face->UZ*face->VZ; + + face->inv_denom = face->UU*face->VV - face->UV*face->UV; + + assert(face->inv_denom != 0.0); + + face->inv_denom = 1.0 / face->inv_denom; + + face->fc[0] = (M->X[A] + M->X[B] + M->X[C]) / 3.0; + face->fc[1] = (M->Y[A] + M->Y[B] + M->Y[C]) / 3.0; + face->fc[2] = (M->Z[A] + M->Z[B] + M->Z[C]) / 3.0; + + // Store A + face->xa = M->X[A]; + face->ya = M->Y[A]; + face->za = M->Z[A]; + } +} \ No newline at end of file diff --git a/Cassiopee/XCore/XCore/AdaptMesh/FaceSort.h b/Cassiopee/XCore/XCore/AdaptMesh/FaceSort.h new file mode 100644 index 000000000..bacbac758 --- /dev/null +++ b/Cassiopee/XCore/XCore/AdaptMesh/FaceSort.h @@ -0,0 +1,17 @@ +#pragma once + +#include "xcore.h" + +struct Mesh; + +struct FaceSort { + E_Int fid; + E_Float fc[3]; + E_Float UX, UY, UZ; + E_Float VX, VY, VZ; + E_Float UU, VV, UV; + E_Float inv_denom; + E_Float xa, ya, za; +}; + +void FaceSort_compute_data(const Mesh *M, FaceSort *mfaces, E_Int mcount); \ No newline at end of file diff --git a/Cassiopee/XCore/XCore/AdaptMesh/H18.cpp b/Cassiopee/XCore/XCore/AdaptMesh/H18.cpp index 00c1e436d..f53836132 100644 --- a/Cassiopee/XCore/XCore/AdaptMesh/H18.cpp +++ b/Cassiopee/XCore/XCore/AdaptMesh/H18.cpp @@ -21,6 +21,7 @@ void H18_refine(E_Int hexa, Mesh *M) { + // This should be replaced by get_ordered_data... H18_reorder(hexa, M); E_Int *cell = Mesh_get_cell(M, hexa); @@ -269,6 +270,12 @@ void H18_refine(E_Int hexa, Mesh *M) M->fref[fid] = FACE_NEW; } + // Update patterns + M->fpattern[M->nf] = DIR_X; + M->fpattern[M->nf+1] = DIR_X; + M->fpattern[M->nf+2] = DIR_X; + M->fpattern[M->nf+3] = DIR_X; + // Assemble children E_Int *child = NULL; diff --git a/Cassiopee/XCore/XCore/AdaptMesh/Mesh.h b/Cassiopee/XCore/XCore/AdaptMesh/Mesh.h index 374e8c809..df8ededdb 100644 --- a/Cassiopee/XCore/XCore/AdaptMesh/Mesh.h +++ b/Cassiopee/XCore/XCore/AdaptMesh/Mesh.h @@ -42,7 +42,15 @@ #define ISO 0 #define DIR 1 +#define DIR_ISO 0 +#define DIR_X 1 +#define DIR_Y 2 + struct Karray; +struct SkinGraph; +struct Point; +struct Vec3f; +struct ArrayI; struct BPatch { E_Int gid; @@ -505,3 +513,26 @@ void Mesh_triangulate_faces(Mesh *M, E_Int *faces, E_Int nf); void Mesh_face_to_prism(Mesh *M, E_Int fid); void Mesh_generate_prisms(Mesh *M, E_Int *faces, E_Int nf); + +/* Extract */ + +void Mesh_extract_skin(const Mesh *M, E_Int *count, E_Int **skin); + +void Mesh_make_skin_connectivity(const Mesh *M, SkinGraph *skin_graph); + +void Mesh_make_skin_graph(const Mesh *M, SkinGraph *skin_graph); + +void Mesh_make_face_centers(const Mesh *M, const E_Int nf, const E_Int *skin, + Vec3f *fc); + +void Mesh_extract_points_from_ftag(const Mesh *M, ArrayI *pids); + +void Mesh_SkinGraph_compute_normals(const Mesh *M, SkinGraph *skin_graph); + +/* Locate */ + +bool Mesh_point_in_tri(const Mesh *M, const Point *p, E_Int tid); + +bool Mesh_point_in_quad(const Mesh *M, const Point *p, E_Int qid); + +bool Mesh_point_in_face(const Mesh *M, const Point *p, E_Int fid); \ No newline at end of file diff --git a/Cassiopee/XCore/XCore/AdaptMesh/MeshExtract.cpp b/Cassiopee/XCore/XCore/AdaptMesh/MeshExtract.cpp new file mode 100644 index 000000000..0116bf53e --- /dev/null +++ b/Cassiopee/XCore/XCore/AdaptMesh/MeshExtract.cpp @@ -0,0 +1,265 @@ +#include "Mesh.h" +#include "Skin.h" +#include "common/mem.h" +#include "Array.h" +#include "FaceSort.h" +#include "Vec.h" + +void Mesh_extract_points_from_ftag(const Mesh *M, ArrayI *pids) +{ + E_Int *ptag = (E_Int *)XMALLOC(M->np * sizeof(E_Int)); + memset(ptag, 0, M->np * sizeof(E_Int)); + pids->count = 0; + + for (E_Int fid = 0; fid < M->nf; fid++) { + if (M->ftag[fid] != 1) continue; + E_Int *face = Mesh_get_face(M, fid); + E_Int *frange = Mesh_get_frange(M, fid); + for (E_Int i = 0; i < M->fstride[fid]; i++) { + E_Int *pn = face + 2*i; + for (E_Int j = 0; j < frange[i]; j++) { + E_Int pid = pn[j]; + pids->count += (ptag[pid] == 0); + ptag[pid] = 1; + } + } + } + + pids->ptr = (E_Int *)XMALLOC(pids->count * sizeof(E_Int)); + E_Int *ptr = pids->ptr; + + for (E_Int pid = 0; pid < M->np; pid++) { + if (ptag[pid] == 1) + *ptr++ = pid; + } + + XFREE(ptag); +} + +void Mesh_extract_faces_from_ftag(const Mesh *M, FaceSort **mfaces, + E_Int *mcount) +{ + E_Int count = 0; + + for (E_Int i = 0; i < M->nf; i++) { + count += (M->ftag[i] == 1); + } + + *mfaces = (FaceSort *)XMALLOC(count * sizeof(FaceSort)); + + *mcount = count; + + count = 0; + + for (E_Int i = 0; i < M->nf; i++) { + if (M->ftag[i] == 1) { + assert(M->ftype[i] == TRI); + (*mfaces)[count++].fid = i; + } + } + + assert(*mcount == count); +} + +void Mesh_extract_skin(const Mesh *M, E_Int *count, E_Int **skin) +{ + *count = 0; + + for (E_Int fid = 0; fid < M->nf; fid++) { + *count += (M->neigh[fid] == -1); + } + + *skin = (E_Int *)XMALLOC(*count * sizeof(E_Int)); + E_Int *ptr = *skin; + + for (E_Int fid = 0; fid < M->nf; fid++) { + if (M->neigh[fid] == -1) + *ptr++ = fid; + } +} + +void Mesh_make_skin_connectivity(const Mesh *M, SkinGraph *skin_graph) +{ + // Count + skin_graph->xadj = (E_Int *)XMALLOC((skin_graph->nf+1) * sizeof(E_Int)); + E_Int *xadj = skin_graph->xadj; + xadj[0] = 0; + + for (E_Int i = 0; i < skin_graph->nf; i++) { + E_Int fid = skin_graph->skin[i]; + const E_Int *frange = Mesh_get_frange(M, fid); + xadj[i+1] = 0; + for (E_Int j = 0; j < M->fstride[fid]; j++) + xadj[i+1] += frange[j]; + xadj[i+1] += xadj[i]; + } + + skin_graph->fpts = (E_Int *)XMALLOC(xadj[skin_graph->nf] * sizeof(E_Int)); + + // Populate + E_Int *ptr = skin_graph->fpts; + + for (E_Int i = 0; i < skin_graph->nf; i++) { + E_Int fid = skin_graph->skin[i]; + const E_Int *face = Mesh_get_face(M, fid); + const E_Int *frange = Mesh_get_frange(M, fid); + for (E_Int j = 0; j < M->fstride[fid]; j++) { + const E_Int *pn = face + 2*j; + for (E_Int k = 0; k < frange[j]; k++) + *ptr++ = pn[k]; + } + } +} + +struct EdgeNode { + E_Int p, q; + E_Int i, j; + E_Int posi, posj; + EdgeNode *next; +}; + +EdgeNode *make_edge_node(E_Int p, E_Int q, E_Int i, E_Int posi) +{ + EdgeNode *node = (EdgeNode *)XMALLOC(sizeof(EdgeNode)); + node->p = p < q ? p : q; + node->q = p < q ? q : p; + node->i = i; + node->posi = posi; + node->j = -1; + node->posj = -1; + node->next = NULL; + return node; +} + +EdgeNode *find_edge_node(EdgeNode **ht, E_Int hsize, E_Int p, E_Int q) +{ + E_Int p_ = p < q ? p : q; + E_Int q_ = p < q ? q : p; + E_Int bucket = p_ % hsize; + EdgeNode *current = ht[bucket]; + + while (current) { + E_Int P = current->p, Q = current->q; + if (P == p_ && Q == q_) { + return current; + } + current = current->next; + } + + return NULL; +} + +void insert_edge_node(EdgeNode *node, const E_Int hsize, EdgeNode **ht) +{ + assert(node->p < node->q); + E_Int bucket = node->p % hsize; + EdgeNode *current = ht[bucket]; + + if (current) { + EdgeNode *tmp = current; + ht[bucket] = node; + node->next = tmp; + } else { + ht[bucket] = node; + } +} + +void Mesh_make_skin_neighbours(const Mesh *M, SkinGraph *skin_graph) +{ + E_Int nf = skin_graph->nf; + const E_Int *xadj = skin_graph->xadj; + const E_Int *fpts = skin_graph->fpts; + + skin_graph->fnei = (E_Int *)XMALLOC(xadj[nf] * sizeof(E_Int)); + E_Int *fnei = skin_graph->fnei; + memset(fnei, -1, xadj[nf] * sizeof(E_Int)); + + EdgeNode **ht = (EdgeNode **)XMALLOC(nf * sizeof(EdgeNode *)); + memset(ht, 0, nf * sizeof(EdgeNode *)); + + for (E_Int i = 0; i < nf; i++) { + E_Int start = xadj[i]; + E_Int np = xadj[i+1] - start; + const E_Int *pn = &fpts[start]; + for (E_Int j = 0; j < np; j++) { + E_Int p = pn[j]; + E_Int q = pn[(j+1)%np]; + EdgeNode *node = find_edge_node(ht, nf, p, q); + if (node) { + assert(node->i != -1); + assert(node->posi != -1); + assert(node->j == -1); + assert(node->posj == -1); + node->j = i; + node->posj = j; + } else { + node = make_edge_node(p, q, i, j); + insert_edge_node(node, nf, ht); + } + } + } + + for (E_Int i = 0; i < nf; i++) { + EdgeNode *node = ht[i]; + while (node) { + E_Int pi = xadj[node->i] + node->posi; + assert(fnei[pi] == -1); + fnei[pi] = node->j; + + E_Int pj = xadj[node->j] + node->posj; + assert(fnei[pj] == -1); + fnei[pj] = node->i; + + node = node->next; + } + } +} + +void Mesh_make_skin_graph(const Mesh *M, SkinGraph *skin_graph) +{ + Mesh_extract_skin(M, &skin_graph->nf, &skin_graph->skin); + Mesh_make_skin_connectivity(M, skin_graph); + Mesh_make_skin_neighbours(M, skin_graph); +} + +void Mesh_make_face_centers(const Mesh *M, const E_Int nf, const E_Int *skin, + Vec3f *fc) +{ + for (E_Int i = 0; i < nf; i++) { + E_Int fid = skin[i]; + const E_Int *face = Mesh_get_face(M, fid); + const E_Int *frange = Mesh_get_frange(M, fid); + fc[i].x = fc[i].y = fc[i].z = 0.0; + E_Int np = 0; + for (E_Int j = 0; j < M->fstride[fid]; j++) { + const E_Int *pn = face + 2*j; + for (E_Int k = 0; k < frange[j]; k++) { + fc[i].x += M->X[pn[k]]; + fc[i].y += M->Y[pn[k]]; + fc[i].z += M->Z[pn[k]]; + np++; + } + } + fc[i].x /= np; fc[i].y /= np; fc[i].z /= np; + } +} + +void Mesh_SkinGraph_compute_normals(const Mesh *M, SkinGraph *skin_graph) +{ + assert(!skin_graph->fnml); + skin_graph->fnml = (Vec3f *)XMALLOC(skin_graph->nf * sizeof(Vec3f)); + + for (E_Int i = 0; i < skin_graph->nf; i++) { + E_Int fid = skin_graph->skin[i]; + E_Int *face = Mesh_get_face(M, fid); + E_Int A = face[0], B = face[2], C = face[4]; + E_Float U[3] = {M->X[B]-M->X[A], M->Y[B]-M->Y[A], M->Z[B]-M->Z[A]}; + E_Float V[3] = {M->X[C]-M->X[A], M->Y[C]-M->Y[A], M->Z[C]-M->Z[A]}; + Vec3f *N = &skin_graph->fnml[i]; + K_MATH::cross(U, V, (E_Float *)N); + E_Float NORM = K_MATH::norm((E_Float *)N, 3); + N->x /= NORM; + N->y /= NORM; + N->z /= NORM; + } +} \ No newline at end of file diff --git a/Cassiopee/XCore/XCore/AdaptMesh/MeshIO.cpp b/Cassiopee/XCore/XCore/AdaptMesh/MeshIO.cpp index a3c46e5c5..d4f9b3fa8 100644 --- a/Cassiopee/XCore/XCore/AdaptMesh/MeshIO.cpp +++ b/Cassiopee/XCore/XCore/AdaptMesh/MeshIO.cpp @@ -692,4 +692,4 @@ PyObject *Mesh_export_karray(Mesh *M, E_Int conformize) if (conformize) return export_conformal_mesh(M); return export_BE_mesh(M); -} +} \ No newline at end of file diff --git a/Cassiopee/XCore/XCore/AdaptMesh/MeshIso.cpp b/Cassiopee/XCore/XCore/AdaptMesh/MeshIso.cpp index e9185869e..9b181c6f9 100644 --- a/Cassiopee/XCore/XCore/AdaptMesh/MeshIso.cpp +++ b/Cassiopee/XCore/XCore/AdaptMesh/MeshIso.cpp @@ -69,93 +69,3 @@ void Mesh_refine_iso(Mesh *M, std::vector &ref_cells, } } } - -/* -void Mesh_refine_iso(Mesh *M, std::vector &ref_cells, - std::vector &ref_faces, std::set &ref_edges) -{ - // Adapt the cells that do not need face adaptation - - if (ref_faces.empty()) { - for (E_Int cell : ref_cells) refine_cell_iso(cell, M); - - return; - } - - // Adapt the faces that are not linked to local cells - - if (ref_cells.empty()) { - for (E_Int face : ref_faces) refine_face_iso(face, M); - - return; - } - - // Refine first cells whose level is less than the smallest ref_face level - // Note(Imad): the faces are pre-sorted by increasing level - - E_Int min_flvl = M->flevel[ref_faces[0]]; - - // Refine the "lagging" cells - - E_Int cell_start = 0; - - while (M->clevel[ref_cells[cell_start]] < min_flvl) { - refine_cell_iso(ref_cells[cell_start], M); - cell_start++; - } - - // Now refine lagging faces - - E_Int min_clvl = M->clevel[ref_cells[cell_start]]; - - E_Int face_start = 0; - - while (M->flevel[ref_faces[face_start]] < min_clvl) { - refine_face_iso(ref_faces[face_start], M); - face_start++; - } - - - // At this point the remaining ref faces/cells should be at the same level - - E_Int cells_left = (E_Int)ref_cells.size() - cell_start; - E_Int faces_left = (E_Int)ref_faces.size() - face_start; - - // Refine faces and cells, by increasing level - - E_Int current_lvl = M->clevel[ref_cells[cell_start]]; - - while (cells_left || faces_left) { - - while (faces_left) { - - // Break early if refinement would overstep current level - - if (M->flevel[ref_faces[face_start]] > current_lvl) break; - - E_Int face = ref_faces[face_start]; - - refine_face_iso(face, M); - - face_start++; - faces_left--; - } - - while (cells_left) { - - // Break early if refinement would overstep current level - - if (M->clevel[ref_cells[cell_start]] > current_lvl) break; - - E_Int cell = ref_cells[cell_start]; - - refine_cell_iso(cell, M); - - cell_start++; - cells_left--; - } - - current_lvl++; - } -} -*/ \ No newline at end of file diff --git a/Cassiopee/XCore/XCore/AdaptMesh/MeshLocate.cpp b/Cassiopee/XCore/XCore/AdaptMesh/MeshLocate.cpp new file mode 100644 index 000000000..0bc5cf428 --- /dev/null +++ b/Cassiopee/XCore/XCore/AdaptMesh/MeshLocate.cpp @@ -0,0 +1,64 @@ +#include "Mesh.h" +#include "Point.h" + +bool Mesh_point_in_tri(const Mesh *M, const Point *p, E_Int tid) +{ + const E_Int *face = Mesh_get_face(M, tid); + E_Int A = face[0], B = face[2], C = face[4]; + return point_in_tri(p->x, p->y, p->z, + M->X[A], M->Y[A], M->Z[A], + M->X[B], M->Y[B], M->Z[B], + M->X[C], M->Y[C], M->Z[C]); +} + +bool Mesh_point_in_quad(const Mesh *M, const Point *p, E_Int qid) +{ + // TODO(Imad): maybe compute face centers once in pre-pass + // Star the quad into 4 triangles + E_Float O[3] = {0.0, 0.0, 0.0}; + const E_Int *face = Mesh_get_face(M, qid); + E_Int A = face[0], B = face[2], C = face[4], D = face[6]; + O[0] = (M->X[A] + M->X[B] + M->X[C] + M->X[D]) * 0.25; + O[1] = (M->Y[A] + M->Y[B] + M->Y[C] + M->Y[D]) * 0.25; + O[2] = (M->Z[A] + M->Z[B] + M->Z[C] + M->Z[D]) * 0.25; + + bool hit = false; + + // First triangle + hit = point_in_tri(p->x, p->y, p->z, + O[0], O[1], O[2], + M->X[A], M->Y[A], M->Z[A], + M->X[B], M->Y[B], M->Z[B]); + if (hit) return true; + + // Second triangle + hit = point_in_tri(p->x, p->y, p->z, + O[0], O[1], O[2], + M->X[B], M->Y[B], M->Z[B], + M->X[C], M->Y[C], M->Z[C]); + if (hit) return true; + + + // Third triangle + hit = point_in_tri(p->x, p->y, p->z, + O[0], O[1], O[2], + M->X[C], M->Y[C], M->Z[C], + M->X[D], M->Y[D], M->Z[D]); + if (hit) return true; + + // Fourth triangle + hit = point_in_tri(p->x, p->y, p->z, + O[0], O[1], O[2], + M->X[D], M->Y[D], M->Z[D], + M->X[A], M->Y[A], M->Z[A]); + if (hit) return true; + + return false; +} + +bool Mesh_point_in_face(const Mesh *M, const Point *p, E_Int fid) +{ + if (M->ftype[fid] == QUAD) return Mesh_point_in_quad(M, p, fid); + assert(M->ftype[fid] == TRI); + return Mesh_point_in_tri(M, p, fid); +} \ No newline at end of file diff --git a/Cassiopee/XCore/XCore/AdaptMesh/MeshRefine.cpp b/Cassiopee/XCore/XCore/AdaptMesh/MeshRefine.cpp index c22e8fc29..45be05d12 100644 --- a/Cassiopee/XCore/XCore/AdaptMesh/MeshRefine.cpp +++ b/Cassiopee/XCore/XCore/AdaptMesh/MeshRefine.cpp @@ -96,6 +96,9 @@ void Mesh_resize_face_data(Mesh *M, E_Int new_nf) M->ftag = (E_Int *)XRESIZE(M->ftag, new_nf * sizeof(E_Int)); for (E_Int i = M->nf; i < new_nf; i++) M->ftag[i] = -1; + + M->fpattern = (E_Int *)XRESIZE(M->fpattern, new_nf * sizeof(E_Int)); + for (E_Int i = M->nf; i < new_nf; i++) M->fpattern[i] = -1; } void Mesh_resize_cell_data(Mesh *M, E_Int new_nc) diff --git a/Cassiopee/XCore/XCore/AdaptMesh/Point.cpp b/Cassiopee/XCore/XCore/AdaptMesh/Point.cpp new file mode 100644 index 000000000..720399840 --- /dev/null +++ b/Cassiopee/XCore/XCore/AdaptMesh/Point.cpp @@ -0,0 +1,129 @@ +#include "Point.h" +#include "constants.h" +#include "FaceSort.h" +#include "Box.h" +#include "Array.h" +#include "common/mem.h" + +bool point_in_tri(E_Float px, E_Float py, E_Float pz, + E_Float ax, E_Float ay, E_Float az, + E_Float bx, E_Float by, E_Float bz, + E_Float cx, E_Float cy, E_Float cz) +{ + // Normal vector to the plane + E_Float Y[3] = {bx-ax, by-ay, bz-az}; + E_Float Z[3] = {cx-ax, cy-ay, cz-az}; + E_Float N[3]; + K_MATH::cross(Y, Z, N); + + E_Float X[3] = {px-ax, py-ay, pz-az}; + + E_Float dp = K_MATH::dot(N, X, 3); + + // Is the point on the plane? + if (dp < -TOL || dp > TOL) return 0; + + E_Float x1 = K_MATH::dot(X, Y, 3); + E_Float y1 = K_MATH::dot(Y, Y, 3); + E_Float z1 = K_MATH::dot(Z, Y, 3); + E_Float x2 = K_MATH::dot(X, Z, 3); + E_Float y2 = K_MATH::dot(Y, Z, 3); + E_Float z2 = K_MATH::dot(Z, Z, 3); + + E_Float u = (x1*z2 - x2*z1) / (y1*z2 - y2*z1); + if (u < -TOL || u > 1 + TOL) return false; + + E_Float v = (-x1*y2 + x2*y1) / (y1*z2 - y2*z1); + if (v < -TOL || v > 1 + TOL) return false; + + E_Float w = 1 - u - v; + if (w < -TOL || w > 1 + TOL) return false; + + return true; +} + +bool Point_in_FaceSort(const Point *p, const FaceSort *f) +{ + E_Float DX = p->x - f->xa; + E_Float DY = p->y - f->ya; + E_Float DZ = p->z - f->za; + + E_Float d20 = DX*f->UX + DY*f->UY + DZ*f->UZ; + E_Float d21 = DX*f->VX + DY*f->VY + DZ*f->VZ; + + E_Float u = (f->VV*d20 - f->UV*d21) * f->inv_denom; + if (u < -TOL || u > 1.0 + TOL) return false; + + E_Float v = (f->UU*d21 - f->UV*d20) * f->inv_denom; + if (v < -TOL || v > 1.0 + TOL) return false; + + E_Float w = 1.0 - (u + v); + if (w < -TOL || w > 1.0 + TOL) return false; + + return true; +} + +bool Point_in_Box3D(const Point *p, const Box3 *box) +{ + return (p->x >= box->xmin) && (p->x <= box->xmax) && + (p->y >= box->ymin) && (p->y <= box->ymax) && + (p->z >= box->zmin) && (p->z <= box->zmax); +} + +void PointFaces_extract_by_threshold +( + const PointFaces *sploc, E_Int spcount, + const E_Int *skin, E_Int mcount, + const E_Int threshold, + ArrayI *faces +) +{ + E_Int *ftag = (E_Int *)XMALLOC(mcount * sizeof(E_Int)); + memset(ftag, 0, mcount * sizeof(E_Int)); + + for (E_Int i = 0; i < spcount; i++) { + const PointFaces *pfaces = &sploc[i]; + for (E_Int j = 0; j < pfaces->count; j++) + ftag[pfaces->ptr[j]]++; + } + + faces->count = 0; + + for (E_Int i = 0; i < mcount; i++) { + if (ftag[i] > threshold) + faces->count++; + } + + faces->ptr = (E_Int *)XMALLOC(faces->count * sizeof(E_Int)); + E_Int *ptr = faces->ptr; + + for (E_Int i = 0; i < mcount; i++) { + if (ftag[i] > threshold) + *ptr++ = i;//skin[i]; + } +} + +void points_write(const char *fname, const std::vector &P) +{ + FILE *fh = fopen(fname, "w"); + assert(fh); + fprintf(fh, "POINTS\n"); + fprintf(fh, "%zu\n", P.size()); + for (auto p : P) fprintf(fh, "%f %f %f\n", p.x, p.y, p.z); + fclose(fh); +} + +void point_write(E_Float px, E_Float py, E_Float pz) +{ + FILE *fh = fopen("point", "w"); + assert(fh); + fprintf(fh, "POINTS\n"); + fprintf(fh, "1\n"); + fprintf(fh, "%f %f %f\n", px, py, pz); + fclose(fh); +} + +void point_write(const Point *p) +{ + return point_write(p->x, p->y, p->z); +} \ No newline at end of file diff --git a/Cassiopee/XCore/XCore/AdaptMesh/Point.h b/Cassiopee/XCore/XCore/AdaptMesh/Point.h new file mode 100644 index 000000000..188651dd5 --- /dev/null +++ b/Cassiopee/XCore/XCore/AdaptMesh/Point.h @@ -0,0 +1,41 @@ +#pragma once + +#include "xcore.h" + +struct Box3; +struct FaceSort; +struct ArrayI; + +#define MAX_FACES_PER_POINT 8 + +struct Point { + E_Float x, y, z; +}; + +struct PointFaces { + E_Int count; + E_Int ptr[MAX_FACES_PER_POINT]; +}; + +bool point_in_tri(E_Float px, E_Float py, E_Float pz, + E_Float ax, E_Float ay, E_Float az, + E_Float bx, E_Float by, E_Float bz, + E_Float cx, E_Float cy, E_Float cz); + +bool Point_in_Box3D(const Point *p, const Box3 *box); + +bool Point_in_FaceSort(const Point *p, const FaceSort *f); + +void PointFaces_extract_by_threshold +( + const PointFaces *sploc, E_Int spcount, + const E_Int *skin, E_Int mcount, + const E_Int threshold, + ArrayI *faces +); + +void points_write(const char *fname, const std::vector &P); + +void point_write(E_Float px, E_Float py, E_Float pz); + +void point_write(const Point *p); \ No newline at end of file diff --git a/Cassiopee/XCore/XCore/AdaptMesh/Q9.cpp b/Cassiopee/XCore/XCore/AdaptMesh/Q9.cpp index 4545ceea3..64b4ab5e9 100644 --- a/Cassiopee/XCore/XCore/AdaptMesh/Q9.cpp +++ b/Cassiopee/XCore/XCore/AdaptMesh/Q9.cpp @@ -154,6 +154,11 @@ E_Int Q9_refine(E_Int quad, Mesh *M) M->ftag[M->nf+1] = M->ftag[quad]; M->ftag[M->nf+2] = M->ftag[quad]; + assert(M->fpattern[quad] == DIR_ISO); + M->fpattern[M->nf] = M->fpattern[quad]; + M->fpattern[M->nf+1] = M->fpattern[quad]; + M->fpattern[M->nf+2] = M->fpattern[quad]; + // Increment face/edge/point count M->nf += 3; M->np += 1; diff --git a/Cassiopee/XCore/XCore/AdaptMesh/Skin.cpp b/Cassiopee/XCore/XCore/AdaptMesh/Skin.cpp new file mode 100644 index 000000000..bfd995ede --- /dev/null +++ b/Cassiopee/XCore/XCore/AdaptMesh/Skin.cpp @@ -0,0 +1,10 @@ +#include "Skin.h" +#include "common/mem.h" + +void SkinGraph_free(SkinGraph *skin_graph) +{ + XFREE(skin_graph->skin); + XFREE(skin_graph->xadj); + XFREE(skin_graph->fpts); + XFREE(skin_graph->fnei); +} diff --git a/Cassiopee/XCore/XCore/AdaptMesh/Skin.h b/Cassiopee/XCore/XCore/AdaptMesh/Skin.h new file mode 100644 index 000000000..2b581023a --- /dev/null +++ b/Cassiopee/XCore/XCore/AdaptMesh/Skin.h @@ -0,0 +1,15 @@ +#pragma once + +#include "xcore.h" +#include "Vec.h" + +struct SkinGraph { + E_Int nf; + E_Int *skin; + E_Int *xadj; + E_Int *fpts; + E_Int *fnei; + Vec3f *fnml; +}; + +void SkinGraph_free(SkinGraph *skin_graph); diff --git a/Cassiopee/XCore/XCore/AdaptMesh/Vec.h b/Cassiopee/XCore/XCore/AdaptMesh/Vec.h new file mode 100644 index 000000000..0298d729d --- /dev/null +++ b/Cassiopee/XCore/XCore/AdaptMesh/Vec.h @@ -0,0 +1,5 @@ +#pragma once + +struct Vec3f { + E_Float x, y, z; +}; \ No newline at end of file diff --git a/Cassiopee/XCore/XCore/AdaptMesh/constants.cpp b/Cassiopee/XCore/XCore/AdaptMesh/constants.cpp new file mode 100644 index 000000000..94b4257db --- /dev/null +++ b/Cassiopee/XCore/XCore/AdaptMesh/constants.cpp @@ -0,0 +1,3 @@ +#include "constants.h" + +const E_Float TOL = 1e-12; \ No newline at end of file diff --git a/Cassiopee/XCore/XCore/AdaptMesh/constants.h b/Cassiopee/XCore/XCore/AdaptMesh/constants.h new file mode 100644 index 000000000..5dc00742e --- /dev/null +++ b/Cassiopee/XCore/XCore/AdaptMesh/constants.h @@ -0,0 +1,5 @@ +#pragma once + +#include "xcore.h" + +extern const E_Float TOL; \ No newline at end of file diff --git a/Cassiopee/XCore/srcs.py b/Cassiopee/XCore/srcs.py index 24b751592..f0364dddf 100644 --- a/Cassiopee/XCore/srcs.py +++ b/Cassiopee/XCore/srcs.py @@ -96,6 +96,18 @@ 'XCore/AdaptMesh/Edge.cpp', 'XCore/AdaptMesh/Karray.cpp', + 'XCore/AdaptMesh/BVH.cpp', + 'XCore/AdaptMesh/Box.cpp', + 'XCore/AdaptMesh/FaceSort.cpp', + 'XCore/AdaptMesh/MeshExtract.cpp', + 'XCore/AdaptMesh/MeshLocate.cpp', + 'XCore/AdaptMesh/Point.cpp', + 'XCore/AdaptMesh/constants.cpp', + 'XCore/AdaptMesh/Skin.cpp', + 'XCore/AdaptMesh/Array.cpp', + + + 'XCore/extractFacesFromPointTag.cpp', ] if mpi: # source that requires mpi From 8fb1ff60926b122e9a77528f5ee0dcf09633ba6c Mon Sep 17 00:00:00 2001 From: imadhammani Date: Thu, 26 Sep 2024 17:29:36 +0200 Subject: [PATCH 15/86] XCore AdaptMesh: DynMesh --- .../XCore/AdaptMesh/AdaptMesh_AdaptGeom.cpp | 425 ++++++++++++------ Cassiopee/XCore/XCore/AdaptMesh/Array.cpp | 7 + Cassiopee/XCore/XCore/AdaptMesh/Array.h | 4 +- Cassiopee/XCore/XCore/AdaptMesh/BVH.cpp | 132 +++++- Cassiopee/XCore/XCore/AdaptMesh/BVH.h | 21 +- Cassiopee/XCore/XCore/AdaptMesh/Box.cpp | 82 ++++ Cassiopee/XCore/XCore/AdaptMesh/Box.h | 20 +- Cassiopee/XCore/XCore/AdaptMesh/DynMesh.cpp | 214 +++++++++ Cassiopee/XCore/XCore/AdaptMesh/DynMesh.h | 152 +++++++ .../XCore/XCore/AdaptMesh/DynMeshTopo.cpp | 332 ++++++++++++++ .../XCore/XCore/AdaptMesh/MeshExtract.cpp | 108 +---- .../XCore/XCore/AdaptMesh/MeshLocate.cpp | 10 +- Cassiopee/XCore/XCore/AdaptMesh/Point.cpp | 4 +- Cassiopee/XCore/XCore/AdaptMesh/Point.h | 2 +- Cassiopee/XCore/XCore/AdaptMesh/Skin.cpp | 108 +++++ Cassiopee/XCore/XCore/AdaptMesh/Skin.h | 2 + Cassiopee/XCore/XCore/PyTree.py | 26 +- Cassiopee/XCore/srcs.py | 3 + 18 files changed, 1393 insertions(+), 259 deletions(-) create mode 100644 Cassiopee/XCore/XCore/AdaptMesh/DynMesh.cpp create mode 100644 Cassiopee/XCore/XCore/AdaptMesh/DynMesh.h create mode 100644 Cassiopee/XCore/XCore/AdaptMesh/DynMeshTopo.cpp diff --git a/Cassiopee/XCore/XCore/AdaptMesh/AdaptMesh_AdaptGeom.cpp b/Cassiopee/XCore/XCore/AdaptMesh/AdaptMesh_AdaptGeom.cpp index db43ab458..9eead3040 100644 --- a/Cassiopee/XCore/XCore/AdaptMesh/AdaptMesh_AdaptGeom.cpp +++ b/Cassiopee/XCore/XCore/AdaptMesh/AdaptMesh_AdaptGeom.cpp @@ -6,36 +6,66 @@ #include "Point.h" #include "Skin.h" #include "Vec.h" +#include "DynMesh.h" +#include // TODO(Imad): sorting routines -void locate_spoints_in_mskin +void locate_points_in_skin ( - const Mesh *S, - const ArrayI *spoints, - const Mesh *M, + const Mesh *source, + const ArrayI *points, + const DynMesh *target, const E_Int *skin, const E_Int *indices, const BVH_node *bvh, - PointFaces *sploc + PointFaces *ploc ) { - for (E_Int i = 0; i < spoints->count; i++) { - E_Int spid = spoints->ptr[i]; - const Point p = {S->X[spid], S->Y[spid], S->Z[spid]}; - PointFaces *pfaces = &sploc[i]; - assert(Point_in_Box3D(&p, &bvh->box)); - BVH_locate_point(bvh, M, skin, indices, &p, pfaces); + for (E_Int i = 0; i < points->count; i++) { + E_Int pid = points->ptr[i]; + const Point p = {source->X[pid], source->Y[pid], source->Z[pid]}; + PointFaces *pfaces = &ploc[i]; + //assert(Point_in_Box3D(&p, &bvh->box)); + BVH_locate_point(bvh, target, skin, indices, &p, pfaces); + /* if (pfaces->count == 0) { fprintf(stderr, "bvh_locate: failed at point index %d (%d)!\n", i, spid); point_write(&p); abort(); } + */ } } -#include +void locate_points_in_skin +( + const DynMesh *source, + const ArrayI *points, + const Mesh *target, + const E_Int *skin, + const E_Int *indices, + const BVH_node *bvh, + PointFaces *ploc +) +{ + for (E_Int i = 0; i < points->count; i++) { + E_Int pid = points->ptr[i]; + const Point p = {source->X[pid], source->Y[pid], source->Z[pid]}; + PointFaces *pfaces = &ploc[i]; + //assert(Point_in_Box3D(&p, &bvh->box)); + BVH_locate_point(bvh, target, skin, indices, &p, pfaces); + /* + if (pfaces->count == 0) { + fprintf(stderr, "bvh_locate: failed at point index %d (%d)!\n", + i, spid); + point_write(&p); + abort(); + } + */ + } +} void smooth_skin_ref_data(Mesh *M, const SkinGraph *skin_graph, E_Int *fdat) { @@ -484,11 +514,13 @@ void Mesh_refine_dir(Mesh *M, ArrayI *ref_cells, ArrayI *ref_faces) } } +#include "Karray.h" + PyObject *K_XCORE::AdaptMesh_AdaptGeom(PyObject *self, PyObject *args) { - PyObject *AMESH, *SMESH; + PyObject *AMESH, *SLAVE, *TAGGED_FACES; - if (!PYPARSETUPLE_(args, OO_, &AMESH, &SMESH)) { + if (!PYPARSETUPLE_(args, OOO_, &AMESH, &SLAVE, &TAGGED_FACES)) { RAISE("Wrong input."); return NULL; } @@ -498,33 +530,60 @@ PyObject *K_XCORE::AdaptMesh_AdaptGeom(PyObject *self, PyObject *args) return NULL; } - if (!PyCapsule_IsValid(SMESH, "AdaptMesh")) { - RAISE("Bad second AdaptMesh hook."); - return NULL; - } - Mesh *M = (Mesh *)PyCapsule_GetPointer(AMESH, "AdaptMesh"); - Mesh *S = (Mesh *)PyCapsule_GetPointer(SMESH, "AdaptMesh"); if (M->npc > 1) { RAISE("AdaptGeom is sequential."); return NULL; } + Karray sarray; + + E_Int ret; + + ret = Karray_parse_ngon(SLAVE, sarray); + + if (ret != 0) { + RAISE("Bad slave mesh."); + return NULL; + } + + puts("Preparing meshes for intersection..."); + + // Check slave point tags + E_Int *tagged_faces = NULL; + E_Int tag_size = -1; + ret = K_NUMPY::getFromNumpyArray(TAGGED_FACES, tagged_faces, tag_size, true); + if (ret != 1) { + Karray_free_ngon(sarray); + RAISE("Bad slave points tag."); + return NULL; + } + + // Init slave mesh + DynMesh S(&sarray); + S.orient_skin(OUT); + for (E_Int i = 0; i < tag_size; i++) { + S.ftag[tagged_faces[i]] = 1; + } + // Refine M volumetric wrt to S tagged faces point cloud // Refine S surfacic wrt to M tagged faces point cloud - //E_Int ref_M = 0; - E_Int ref_S = 0; E_Int iter = 0; E_Int max_iter = 10; + E_Int ref_count_M, ref_count_S; + do { iter++; - printf("iter: %d\n", iter); + + /************************** M refinement **************************/ + + printf("\niter: %d\n", iter); // Extract spoints from tagged sfaces ArrayI spoints; - Mesh_extract_points_from_ftag(S, &spoints); + S.extract_points_from_ftag(&spoints); // We need the skin connectivity graph SkinGraph skin_graph = {0}; @@ -547,29 +606,15 @@ PyObject *K_XCORE::AdaptMesh_AdaptGeom(PyObject *self, PyObject *args) PointFaces *sploc = (PointFaces *)XMALLOC(spoints.count * sizeof(PointFaces)); memset(sploc, 0, spoints.count * sizeof(PointFaces)); - locate_spoints_in_mskin + locate_points_in_skin ( - S, &spoints, + &S, &spoints, M, skin_graph.skin, indices, bvh, sploc ); puts("Points located"); - - // Isolate faces that contain more than MAX_POINTS_PER_FACE spoints - ArrayI rfaces; - PointFaces_extract_by_threshold - ( - sploc, spoints.count, - skin_graph.skin, skin_graph.nf, - 1, // threshold - &rfaces - ); - puts("Refinement faces isolated"); - printf("Refinement faces: %d\n", rfaces.count); - if (rfaces.count == 0) break; - if (iter == 1) { // We need the skin face normals Mesh_SkinGraph_compute_normals(M, &skin_graph); @@ -586,8 +631,8 @@ PyObject *K_XCORE::AdaptMesh_AdaptGeom(PyObject *self, PyObject *args) E_Int *fqueue = (E_Int *)XMALLOC(skin_graph.nf * sizeof(E_Int)); memset(fqueue, -1, skin_graph.nf * sizeof(E_Int)); - // Start from the first rface - E_Int fseed = indices[rfaces.ptr[0]]; + // Start from the first mface + E_Int fseed = indices[sploc[0].ptr[0]]; E_Int front = 0, rear = 0; fqueue[rear++] = fseed; @@ -625,30 +670,15 @@ PyObject *K_XCORE::AdaptMesh_AdaptGeom(PyObject *self, PyObject *args) } } - /* - { - npy_intp dims[2]; - dims[1] = 1; - dims[0] = (npy_intp)nvisited; - PyArrayObject *FACES = (PyArrayObject *)PyArray_SimpleNew(1, dims, E_NPY_INT); - - E_Int *pf = (E_Int *)PyArray_DATA(FACES); - E_Int *ptr = pf; - for (E_Int i = 0; i < skin_graph.nf; i++) { - if (visited[i]) { - *ptr++ = skin_graph.skin[i]+1; - } - } - - return (PyObject *)FACES; - } - */ - // Set the base patch E_Int cvisit = 0; for (E_Int i = 0; i < skin_graph.nf; i++) { if (visited[i] == 0) continue; + // Tag this face for later + assert(M->ftag[skin_graph.skin[i]] == 0); + M->ftag[skin_graph.skin[i]] = 1; + E_Int fid = skin_graph.skin[i]; E_Int cid = M->owner[fid]; @@ -712,107 +742,220 @@ PyObject *K_XCORE::AdaptMesh_AdaptGeom(PyObject *self, PyObject *args) XFREE(visited); XFREE(fqueue); } + + // Isolate faces that contain more than MAX_POINTS_PER_FACE spoints + ArrayI rfaces; + PointFaces_extract_by_threshold + ( + sploc, spoints.count, + skin_graph.skin, skin_graph.nf, + 1, // threshold + &rfaces + ); + puts("Refinement faces isolated"); + printf("Refinement faces: %d\n", rfaces.count); + ref_count_M = rfaces.count; + + if (rfaces.count > 0) { - // Smooth face refinement data - E_Int *fdat = (E_Int *)XMALLOC(skin_graph.nf * sizeof(E_Int)); - memset(fdat, 0, skin_graph.nf * sizeof(E_Int)); - for (E_Int i = 0; i < rfaces.count; i++) { - E_Int idx_in_skin = indices[rfaces.ptr[i]]; - fdat[idx_in_skin] = 1; + // Smooth face refinement data + E_Int *fdat = (E_Int *)XMALLOC(skin_graph.nf * sizeof(E_Int)); + memset(fdat, 0, skin_graph.nf * sizeof(E_Int)); + for (E_Int i = 0; i < rfaces.count; i++) { + E_Int idx_in_skin = indices[rfaces.ptr[i]]; + fdat[idx_in_skin] = 1; + } + smooth_skin_ref_data(M, &skin_graph, fdat); + puts("Face refinement smoothed out"); + + E_Int smooth_nfref = 0; + for (E_Int i = 0; i < skin_graph.nf; i++) { + if (fdat[i] > 0) smooth_nfref++; + } + printf("Smooth refinement face count: %d\n", smooth_nfref); + + // Allocate + M->cref = (E_Int *)XRESIZE(M->cref, M->nc * sizeof(E_Int)); + memset(M->cref, 0, M->nc * sizeof(E_Int)); + + // Cells + E_Int ref_cell_count; + init_skin_refinement_cells(&skin_graph, fdat, M, &ref_cell_count); + printf("Refinement cells: %d\n", ref_cell_count); + if (ref_cell_count == 0) break; + + // Smooth cell refinement data + smooth_cell_refinement_data(M); + puts("Cell refinement smoothed out"); + + // Assign refinement data + M->fref = (E_Int *)XRESIZE(M->fref, M->nf * sizeof(E_Int)); + memset(M->fref, 0, M->nf * sizeof(E_Int)); + assign_face_refinement_data(M); + + // Isolate cells/faces to be refined + ArrayI ref_cells, ref_faces; + Mesh_isolate_refinement_entities(M, &ref_cells, &ref_faces); + printf("Refinement cells: %d\n", ref_cells.count); + printf("Refinement faces: %d\n", ref_faces.count); + + // Resize for refinement + Mesh_resize(M, &ref_cells, &ref_faces); + puts("Mesh resized for refinement"); + + // Sort entities by refinement level + std::sort(ref_cells.ptr, ref_cells.ptr + ref_cells.count, + [&] (E_Int i, E_Int j) { return M->clevel[i] > M->clevel[j]; }); + puts("Refinement cells sorted"); + std::sort(ref_faces.ptr, ref_faces.ptr + ref_faces.count, + [&] (E_Int i, E_Int j) { return M->flevel[i] > M->flevel[j]; }); + puts("Refinement faces sorted"); + + // Refine + printf("Cells before refinement: %d\n", M->nc); + printf("Faces before refinement: %d\n", M->nf); + Mesh_refine_dir(M, &ref_cells, &ref_faces); + + printf("Cells after refinement: %d\n", M->nc); + printf("Faces after refinement: %d\n", M->nf); + + Mesh_conformize_face_edge(M); + + ArrayI_free(&ref_cells); + ArrayI_free(&ref_faces); + XFREE(fdat); } - smooth_skin_ref_data(M, &skin_graph, fdat); - puts("Face refinement smoothed out"); + + BVH_free(bvh); + ArrayI_free(&rfaces); + ArrayI_free(&spoints); - E_Int smooth_nfref = 0; - for (E_Int i = 0; i < skin_graph.nf; i++) { - if (fdat[i] > 0) smooth_nfref++; + XFREE(sploc); + XFREE(indices); + XFREE(skin_fc); + SkinGraph_free(&skin_graph); + + /************************** S refinement **************************/ + + // Extract mpoints from tagged mfaces + ArrayI mpoints; + Mesh_extract_points_from_ftag(M, &mpoints); + printf("mpoints: %d\n", mpoints); + + //if (iter == 10) + { + std::vector points; + for (E_Int i = 0; i < mpoints.count; i++) { + E_Int p = mpoints.ptr[i]; + Point point = {M->X[p], M->Y[p], M->Z[p]}; + points.push_back(point); + } + points_write("mpoints", points); } - printf("Smooth refinement face count: %d\n", smooth_nfref); - /* - if (iter == 1) { + // We need the skin connectivity graph + skin_graph = {0}; + S.make_skin_graph(&skin_graph); + printf("Skin: %d faces\n", skin_graph.nf); + + // BVH the skin + skin_fc = (Vec3f *)XCALLOC(skin_graph.nf, sizeof(Vec3f)); + S.make_face_centers(skin_graph.nf, skin_graph.skin, skin_fc); + indices = (E_Int *)XMALLOC(skin_graph.nf * sizeof(E_Int)); + for (E_Int i = 0; i < skin_graph.nf; i++) indices[i] = i; + bvh = BVH_make(&S, skin_graph.skin, skin_fc, indices, 0, + skin_graph.nf, &huge); + puts("BVH constructed"); + + // Locate mpoints in skin + PointFaces *mploc = + (PointFaces *)XCALLOC(mpoints.count, sizeof(PointFaces)); + locate_points_in_skin + ( + M, &mpoints, + &S, skin_graph.skin, indices, + bvh, + mploc + ); + puts("Points located"); + + // Isolate faces that contain more than MAX_POINTS_PER_FACE mpoints + PointFaces_extract_by_threshold + ( + mploc, mpoints.count, + skin_graph.skin, skin_graph.nf, + 1, // threshold + &rfaces + ); + puts("Refinement faces isolated"); + printf("Refinement faces: %d\n", rfaces.count); + ref_count_S = rfaces.count; + + if (iter == 2) + { npy_intp dims[2]; + + // faces array dims[1] = 1; - dims[0] = (npy_intp)smooth_nfref; + dims[0] = (npy_intp)rfaces.count; + PyArrayObject *FACES = (PyArrayObject *)PyArray_SimpleNew(1, dims, E_NPY_INT); - E_Int *pf = (E_Int *)PyArray_DATA(FACES); E_Int *ptr = pf; - for (E_Int i = 0; i < skin_graph.nf; i++) { - if (fdat[i] > 0) { - *ptr++ = skin_graph.skin[i]+1; - } + + for (E_Int j = 0; j < rfaces.count; j++) { + *ptr++ = skin_graph.skin[indices[rfaces.ptr[j]]]+1; } - //puts(""); + return (PyObject *)FACES; } - */ - - // Allocate - M->cref = (E_Int *)XRESIZE(M->cref, M->nc * sizeof(E_Int)); - memset(M->cref, 0, M->nc * sizeof(E_Int)); - - // Cells - E_Int ref_cell_count; - init_skin_refinement_cells(&skin_graph, fdat, M, &ref_cell_count); - printf("Refinement cells: %d\n", ref_cell_count); - if (ref_cell_count == 0) break; - - // Smooth cell refinement data - smooth_cell_refinement_data(M); - puts("Cell refinement smoothed out"); - - // Assign refinement data - M->fref = (E_Int *)XRESIZE(M->fref, M->nf * sizeof(E_Int)); - memset(M->fref, 0, M->nf * sizeof(E_Int)); - assign_face_refinement_data(M); - - // Isolate cells/faces to be refined - ArrayI ref_cells, ref_faces; - Mesh_isolate_refinement_entities(M, &ref_cells, &ref_faces); - printf("Refinement cells: %d\n", ref_cells.count); - printf("Refinement faces: %d\n", ref_faces.count); - - // Resize for refinement - Mesh_resize(M, &ref_cells, &ref_faces); - puts("Mesh resized for refinement"); - - // Sort entities by refinement level - std::sort(ref_cells.ptr, ref_cells.ptr + ref_cells.count, - [&] (E_Int i, E_Int j) { return M->clevel[i] > M->clevel[j]; }); - puts("Refinement cells sorted"); - std::sort(ref_faces.ptr, ref_faces.ptr + ref_faces.count, - [&] (E_Int i, E_Int j) { return M->flevel[i] > M->flevel[j]; }); - puts("Refinement faces sorted"); - - // Refine - printf("Cells before refinement: %d\n", M->nc); - printf("Faces before refinement: %d\n", M->nf); - Mesh_refine_dir(M, &ref_cells, &ref_faces); - printf("Cells after refinement: %d\n", M->nc); - printf("Faces after refinement: %d\n", M->nf); + if (rfaces.count > 0) { - Mesh_conformize_face_edge(M); - puts(""); + // Smooth face refinement data + E_Int *fdat = (E_Int *)XMALLOC(skin_graph.nf * sizeof(E_Int)); + memset(fdat, 0, skin_graph.nf * sizeof(E_Int)); + for (E_Int i = 0; i < rfaces.count; i++) { + E_Int idx_in_skin = indices[rfaces.ptr[i]]; + fdat[idx_in_skin] = 1; + } + S.smooth_skin_ref_data(&skin_graph, fdat); + puts("Face refinement smoothed out"); + + // Assign refinement data + S.fref.resize(M->nf, 0); + E_Int smooth_nfref = 0; + for (E_Int i = 0; i < skin_graph.nf; i++) { + if (fdat[i] > 0) { + E_Int fid = skin_graph.skin[i]; + S.fref[fid] = 1; + smooth_nfref++; + } + } + printf("Smooth refinement face count: %d\n", smooth_nfref); + + /* + // Isolate refinement faces + ArrayI ref_faces; + Mesh_isolate_refinement_faces(S, &ref_faces); + printf("Refinement faces: %d\n", ref_faces.count); + assert(ref_faces.count == smooth_nfref); + + // Resize for refinement + E_Int face_incr = ref_faces.count * 3; + E_Int new_nf = S->nf + face_incr; + E_Int new_np = S->np + face_incr; + Mesh_resize_face_data(S, S->nf + ref_faces.count * 3); + Mesh_resize_point_data(S, ref_faces.count * 2); + */ + } - BVH_free(bvh); - ArrayI_free(&spoints); - ArrayI_free(&ref_cells); - ArrayI_free(&ref_faces); - ArrayI_free(&rfaces); - SkinGraph_free(&skin_graph); - XFREE(fdat); - XFREE(sploc); - XFREE(indices); - XFREE(skin_fc); - // FREE - } while (iter < max_iter); + } while (iter < max_iter && (ref_count_M > 0 || ref_count_S > 0)); diff --git a/Cassiopee/XCore/XCore/AdaptMesh/Array.cpp b/Cassiopee/XCore/XCore/AdaptMesh/Array.cpp index ab3497d30..a5e0f0889 100644 --- a/Cassiopee/XCore/XCore/AdaptMesh/Array.cpp +++ b/Cassiopee/XCore/XCore/AdaptMesh/Array.cpp @@ -3,5 +3,12 @@ void ArrayI_free(ArrayI *arr) { + arr->count = 0; XFREE(arr->ptr); +} + +void ArrayI_alloc(ArrayI *arr, E_Int nelem) +{ + arr->count = nelem; + arr->ptr = (E_Int *)XMALLOC(nelem * sizeof(E_Int)); } \ No newline at end of file diff --git a/Cassiopee/XCore/XCore/AdaptMesh/Array.h b/Cassiopee/XCore/XCore/AdaptMesh/Array.h index bf440937d..cd73faf5b 100644 --- a/Cassiopee/XCore/XCore/AdaptMesh/Array.h +++ b/Cassiopee/XCore/XCore/AdaptMesh/Array.h @@ -7,4 +7,6 @@ struct ArrayI { E_Int *ptr; }; -void ArrayI_free(ArrayI *arr); \ No newline at end of file +void ArrayI_free(ArrayI *arr); + +void ArrayI_alloc(ArrayI *arr, E_Int nelem); \ No newline at end of file diff --git a/Cassiopee/XCore/XCore/AdaptMesh/BVH.cpp b/Cassiopee/XCore/XCore/AdaptMesh/BVH.cpp index 8555f887f..0bbb99021 100644 --- a/Cassiopee/XCore/XCore/AdaptMesh/BVH.cpp +++ b/Cassiopee/XCore/XCore/AdaptMesh/BVH.cpp @@ -4,6 +4,7 @@ #include "Point.h" #include "common/mem.h" #include "Vec.h" +#include "DynMesh.h" #define MAX_FACES_PER_BVH_LEAF 10 @@ -157,4 +158,133 @@ void BVH_free(BVH_node *node) BVH_free(node->right); XFREE(node); -}; \ No newline at end of file +}; + +/* DynMesh */ + +BVH_node *BVH_make(const DynMesh *M, FaceSort *mfaces, E_Int start, E_Int end, + const Box3 *parent_box) +{ + Box3 box = Box3_make(M, mfaces, start, end); + Box3_clamp(parent_box, &box); + assert(Box3_in_Box3(box, *parent_box)); + + E_Int count = end - start; + if (count <= MAX_FACES_PER_BVH_LEAF) { + return BVH_create_node(&box, start, end, NULL, NULL); + } + + E_Float dx = box.xmax - box.xmin; + E_Float dy = box.ymax - box.ymin; + E_Float dz = box.zmax - box.zmin; + + E_Int dim = -1; + + if (dx >= dy && dx >= dz) { + dim = 0; + } else if (dy >= dz) { + dim = 1; + } else { + dim = 2; + } + + std::sort(mfaces + start, mfaces + end, + [&](const FaceSort &fi, const FaceSort &fj) + { + return fi.fc[dim] < fj.fc[dim]; + }); + + E_Int mid = start + count/2; + + BVH_node *left = BVH_make(M, mfaces, start, mid, &box); + BVH_node *right = BVH_make(M, mfaces, mid, end, &box); + + assert(Box3_in_Box3(left->box, box)); + assert(Box3_in_Box3(right->box, box)); + + return BVH_create_node(&box, start, end, left, right); +} + +BVH_node *BVH_make(const DynMesh *M, const E_Int *skin, const Vec3f *fc, + E_Int *indices, E_Int start, E_Int end, const Box3 *parent_box) +{ + Box3 box = Box3_make(M, skin, indices, start, end); + Box3_clamp(parent_box, &box); + assert(Box3_in_Box3(box, *parent_box)); + + E_Int count = end - start; + if (count <= MAX_FACES_PER_BVH_LEAF) { + return BVH_create_node(&box, start, end, NULL, NULL); + } + + E_Float dx = box.xmax - box.xmin; + E_Float dy = box.ymax - box.ymin; + E_Float dz = box.zmax - box.zmin; + + E_Int dim = -1; + + if (dx >= dy && dx >= dz) { + dim = 0; + } else if (dy >= dz) { + dim = 1; + } else { + dim = 2; + } + + std::sort(indices + start, indices + end, + [&](const E_Int i, const E_Int j) + { + E_Float *fci = (E_Float *)(&fc[i]); + E_Float *fcj = (E_Float *)(&fc[j]); + return fci[dim] < fcj[dim]; + }); + + E_Int mid = start + count/2; + + BVH_node *left = BVH_make(M, skin, fc, indices, start, mid, &box); + BVH_node *right = BVH_make(M, skin, fc, indices, mid, end, &box); + + assert(Box3_in_Box3(left->box, box)); + assert(Box3_in_Box3(right->box, box)); + + return BVH_create_node(&box, start, end, left, right); +} + +void BVH_locate_point +( + const BVH_node *node, + const DynMesh *M, + const E_Int *skin, + const E_Int *indices, + const Point *p, + PointFaces *pfaces +) +{ + if (node->left == NULL && node->right == NULL) { + for (E_Int i = node->start; i < node->end; i++) { + E_Int fid = skin[indices[i]]; + + if (M->point_in_face(p, fid)) { + if (pfaces->count >= MAX_FACES_PER_POINT) { + fprintf(stderr, + "bvh_locate: MAX_FACES_PER_POINT exceeded!\n"); + abort(); + } + pfaces->ptr[pfaces->count++] = i; + } + } + return; + } + + assert(node->left && node->right); + assert(Box3_in_Box3(node->left->box, node->box)); + assert(Box3_in_Box3(node->right->box, node->box)); + + bool in_box = Point_in_Box3D(p, &node->box); + + if (!in_box) + return; + + BVH_locate_point(node->left, M, skin, indices, p, pfaces); + BVH_locate_point(node->right, M, skin, indices, p, pfaces); +} \ No newline at end of file diff --git a/Cassiopee/XCore/XCore/AdaptMesh/BVH.h b/Cassiopee/XCore/XCore/AdaptMesh/BVH.h index 18ada3203..5a840f1af 100644 --- a/Cassiopee/XCore/XCore/AdaptMesh/BVH.h +++ b/Cassiopee/XCore/XCore/AdaptMesh/BVH.h @@ -7,6 +7,7 @@ struct FaceSort; struct Vec3f; struct Point; struct PointFaces; +struct DynMesh; struct BVH_node { Box3 box; @@ -34,4 +35,22 @@ void BVH_locate_point PointFaces *pfaces ); -void BVH_free(BVH_node *node); \ No newline at end of file +void BVH_free(BVH_node *node); + +/* DynMesh */ + +BVH_node *BVH_make(const DynMesh *M, FaceSort *mfaces, E_Int start, E_Int end, + const Box3 *parent_box); + +BVH_node *BVH_make(const DynMesh *M, const E_Int *skin, const Vec3f *fc, + E_Int *indices, E_Int start, E_Int end, const Box3 *parent_box); + +void BVH_locate_point +( + const BVH_node *node, + const DynMesh *M, + const E_Int *skin, + const E_Int *indices, + const Point *p, + PointFaces *pfaces +); \ No newline at end of file diff --git a/Cassiopee/XCore/XCore/AdaptMesh/Box.cpp b/Cassiopee/XCore/XCore/AdaptMesh/Box.cpp index 7d41e2ec6..4f490b7ec 100644 --- a/Cassiopee/XCore/XCore/AdaptMesh/Box.cpp +++ b/Cassiopee/XCore/XCore/AdaptMesh/Box.cpp @@ -1,6 +1,7 @@ #include "Box.h" #include "Mesh.h" #include "FaceSort.h" +#include "DynMesh.h" Box3 Box3_make ( @@ -102,5 +103,86 @@ Box3 Box3_make ymax += dy; zmax += dz; + return {xmin, ymin, zmin, xmax, ymax, zmax}; +} + +/* DynMesh */ + +Box3 Box3_make +( + const DynMesh *M, + const FaceSort *mfaces, + E_Int start, E_Int end +) +{ + E_Float xmin, ymin, zmin, xmax, ymax, zmax; + xmin = ymin = zmin = FLT_MAX; + xmax = ymax = zmax = -FLT_MAX; + + for (E_Int i = start; i < end; i++) { + E_Int fid = mfaces[i].fid; + const auto &pn = M->F[fid]; + + for (E_Int pid : pn) { + if (M->X[pid] < xmin) xmin = M->X[pid]; + if (M->Y[pid] < ymin) ymin = M->Y[pid]; + if (M->Z[pid] < zmin) zmin = M->Z[pid]; + if (M->X[pid] > xmax) xmax = M->X[pid]; + if (M->Y[pid] > ymax) ymax = M->Y[pid]; + if (M->Z[pid] > zmax) zmax = M->Z[pid]; + } + } + + // Safety + E_Float dx = (xmax - xmin) * 0.01; + E_Float dy = (ymax - ymin) * 0.01; + E_Float dz = (zmax - zmin) * 0.01; + xmin -= dx; + ymin -= dy; + zmin -= dz; + xmax += dx; + ymax += dy; + zmax += dz; + + return {xmin, ymin, zmin, xmax, ymax, zmax}; +} + +Box3 Box3_make +( + const DynMesh *M, + const E_Int *skin, + const E_Int *indices, + E_Int start, E_Int end +) +{ + E_Float xmin, ymin, zmin, xmax, ymax, zmax; + xmin = ymin = zmin = FLT_MAX; + xmax = ymax = zmax = -FLT_MAX; + + for (E_Int i = start; i < end; i++) { + E_Int fid = skin[indices[i]]; + const auto &pn = M->F[fid]; + + for (E_Int pid : pn) { + if (M->X[pid] < xmin) xmin = M->X[pid]; + if (M->Y[pid] < ymin) ymin = M->Y[pid]; + if (M->Z[pid] < zmin) zmin = M->Z[pid]; + if (M->X[pid] > xmax) xmax = M->X[pid]; + if (M->Y[pid] > ymax) ymax = M->Y[pid]; + if (M->Z[pid] > zmax) zmax = M->Z[pid]; + } + } + + // Safety + E_Float dx = (xmax - xmin) * 0.01; + E_Float dy = (ymax - ymin) * 0.01; + E_Float dz = (zmax - zmin) * 0.01; + xmin -= dx; + ymin -= dy; + zmin -= dz; + xmax += dx; + ymax += dy; + zmax += dz; + return {xmin, ymin, zmin, xmax, ymax, zmax}; } \ No newline at end of file diff --git a/Cassiopee/XCore/XCore/AdaptMesh/Box.h b/Cassiopee/XCore/XCore/AdaptMesh/Box.h index 91470a3ad..b7fd38f6a 100644 --- a/Cassiopee/XCore/XCore/AdaptMesh/Box.h +++ b/Cassiopee/XCore/XCore/AdaptMesh/Box.h @@ -4,6 +4,7 @@ struct Mesh; struct FaceSort; +struct DynMesh; struct Box3 { E_Float xmin, ymin, zmin; @@ -33,4 +34,21 @@ Box3 Box3_make E_Int start, E_Int end ); -void Box3_clamp(const Box3 *parent, Box3 *child); \ No newline at end of file +void Box3_clamp(const Box3 *parent, Box3 *child); + +/* DynMesh */ + +Box3 Box3_make +( + const DynMesh *M, + const FaceSort *mfaces, + E_Int start, E_Int end +); + +Box3 Box3_make +( + const DynMesh *M, + const E_Int *skin, + const E_Int *indices, + E_Int start, E_Int end +); \ No newline at end of file diff --git a/Cassiopee/XCore/XCore/AdaptMesh/DynMesh.cpp b/Cassiopee/XCore/XCore/AdaptMesh/DynMesh.cpp new file mode 100644 index 000000000..dc68f1e7e --- /dev/null +++ b/Cassiopee/XCore/XCore/AdaptMesh/DynMesh.cpp @@ -0,0 +1,214 @@ +#include "DynMesh.h" +#include "Karray.h" +#include "Array.h" +#include "Skin.h" +#include "Vec.h" +#include "Point.h" +#include "common/mem.h" + +DynMesh::DynMesh(Karray *karray) +{ + np = karray->npoints(); + nf = karray->nfaces(); + nc = karray->ncells(); + + X.resize(np); + Y.resize(np); + Z.resize(np); + memcpy(X.data(), karray->X(), np * sizeof(E_Float)); + memcpy(Y.data(), karray->Y(), np * sizeof(E_Float)); + memcpy(Z.data(), karray->Z(), np * sizeof(E_Float)); + + F.reserve(nf); + + for (E_Int i = 0; i < nf; i++) { + E_Int np = -1; + E_Int *pn = karray->get_face(i, np); + std::vector points(np); + for (E_Int j = 0; j < np; j++) + points[j] = pn[j] - 1; + F.push_back(points); + } + + C.reserve(nc); + for (E_Int i = 0; i < nc; i++) { + E_Int nf = -1; + E_Int *pf = karray->get_cell(i, nf); + std::vector faces(nf); + for (E_Int j = 0; j < nf; j++) + faces[j] = pf[j] - 1; + C.push_back(faces); + } + + ftag.resize(nf, 0); + + owner.resize(nf, -1); + neigh.resize(nf, -1); + for (E_Int cid = 0; cid < nc; cid++) { + const auto &pf = C[cid]; + for (E_Int fid : pf) { + if (owner[fid] == -1) owner[fid] = cid; + else neigh[fid] = cid; + } + } +} + +void DynMesh::extract_points_from_ftag(ArrayI *pids) +{ + E_Int *ptag = (E_Int *)XMALLOC(np * sizeof(E_Int)); + memset(ptag, 0, np * sizeof(E_Int)); + pids->count = 0; + + for (E_Int fid = 0; fid < nf; fid++) { + if (ftag[fid] != 1) continue; + const auto &pn = F[fid]; + + for (E_Int pid : pn) { + pids->count += (ptag[pid] == 0); + ptag[pid] = 1; + } + } + + pids->ptr = (E_Int *)XMALLOC(pids->count * sizeof(E_Int)); + E_Int *ptr = pids->ptr; + + for (E_Int pid = 0; pid < np; pid++) { + if (ptag[pid] == 1) + *ptr++ = pid; + } + + XFREE(ptag); +} + +void DynMesh::extract_skin(E_Int *count, E_Int **skin) +{ + *count = 0; + + for (E_Int fid = 0; fid < nf; fid++) { + *count += (neigh[fid] == -1); + } + + *skin = (E_Int *)XMALLOC(*count * sizeof(E_Int)); + E_Int *ptr = *skin; + + for (E_Int fid = 0; fid < nf; fid++) { + if (neigh[fid] == -1) + *ptr++ = fid; + } +} + +void DynMesh::make_skin_connectivity(SkinGraph *skin_graph) +{ + // Count + skin_graph->xadj = (E_Int *)XMALLOC((skin_graph->nf+1) * sizeof(E_Int)); + E_Int *xadj = skin_graph->xadj; + xadj[0] = 0; + + for (E_Int i = 0; i < skin_graph->nf; i++) { + E_Int fid = skin_graph->skin[i]; + xadj[i+1] = F[fid].size(); + xadj[i+1] += xadj[i]; + } + + skin_graph->fpts = (E_Int *)XMALLOC(xadj[skin_graph->nf] * sizeof(E_Int)); + + // Populate + E_Int *ptr = skin_graph->fpts; + + for (E_Int i = 0; i < skin_graph->nf; i++) { + E_Int fid = skin_graph->skin[i]; + const auto &pn = F[fid]; + for (E_Int p : pn) { + *ptr++ = p; + } + } +} + +void DynMesh::make_skin_graph(SkinGraph *skin_graph) +{ + extract_skin(&skin_graph->nf, &skin_graph->skin); + make_skin_connectivity(skin_graph); + SkinGraph_make_skin_neighbours(skin_graph); +} + +void DynMesh::make_face_centers(const E_Int NF, const E_Int *skin, + Vec3f *fc) +{ + for (E_Int i = 0; i < NF; i++) { + fc[i].x = fc[i].y = fc[i].z = 0.0; + E_Int fid = skin[i]; + const auto &pn = F[fid]; + for (E_Int p : pn) { + fc[i].x += X[p]; + fc[i].y += Y[p]; + fc[i].z += Z[p]; + } + fc[i].x /= pn.size(); fc[i].y /= pn.size(); fc[i].z /= pn.size(); + } +} + +bool DynMesh::point_in_tri(const Point *p, E_Int tid) const +{ + const auto &pn = F[tid]; + E_Int A = pn[0], B = pn[1], C = pn[2]; + return Point_in_tri(p->x, p->y, p->z, + X[A], Y[A], Z[A], + X[B], Y[B], Z[B], + X[C], Y[C], Z[C]); +} + +bool DynMesh::point_in_quad(const Point *p, E_Int qid) const +{ + // TODO(Imad): maybe compute face centers once in pre-pass + // Star the quad into 4 triangles + E_Float O[3] = {0.0, 0.0, 0.0}; + const auto &pn = F[qid]; + E_Int A = pn[0], B = pn[1], C = pn[2], D = pn[3]; + O[0] = (X[A] + X[B] + X[C] + X[D]) * 0.25; + O[1] = (Y[A] + Y[B] + Y[C] + Y[D]) * 0.25; + O[2] = (Z[A] + Z[B] + Z[C] + Z[D]) * 0.25; + + bool hit = false; + + // First triangle + hit = Point_in_tri(p->x, p->y, p->z, + O[0], O[1], O[2], + X[A], Y[A], Z[A], + X[B], Y[B], Z[B]); + if (hit) return true; + + // Second triangle + hit = Point_in_tri(p->x, p->y, p->z, + O[0], O[1], O[2], + X[B], Y[B], Z[B], + X[C], Y[C], Z[C]); + if (hit) return true; + + + // Third triangle + hit = Point_in_tri(p->x, p->y, p->z, + O[0], O[1], O[2], + X[C], Y[C], Z[C], + X[D], Y[D], Z[D]); + if (hit) return true; + + // Fourth triangle + hit = Point_in_tri(p->x, p->y, p->z, + O[0], O[1], O[2], + X[D], Y[D], Z[D], + X[A], Y[A], Z[A]); + if (hit) return true; + + return false; +} + +bool DynMesh::point_in_face(const Point *p, E_Int fid) const +{ + if (F[fid].size() == 4) return point_in_quad(p, fid); + return point_in_tri(p, fid); +} + +void DynMesh::smooth_skin_ref_data(SkinGraph *skin_graph, E_Int *fdat) +{ + assert(0); +} diff --git a/Cassiopee/XCore/XCore/AdaptMesh/DynMesh.h b/Cassiopee/XCore/XCore/AdaptMesh/DynMesh.h new file mode 100644 index 000000000..ad58e44d7 --- /dev/null +++ b/Cassiopee/XCore/XCore/AdaptMesh/DynMesh.h @@ -0,0 +1,152 @@ +#pragma once + +#include +#include +#include + +#include "xcore.h" +#include "common/common.h" + +struct Karray; +struct ArrayI; +struct SkinGraph; +struct Vec3f; +struct Point; + +#define OUT 0 +#define IN 1 + +struct uEdge { + E_Int p, q; + + uEdge(E_Int P, E_Int Q) + { + p = std::min(P, Q); + q = std::max(P, Q); + } + + bool operator<(const uEdge &E) const + { + return (p < E.p) || (p == E.p && q < E.q); + } +}; + +struct DynMesh { + E_Int np, ne, nf, nc; + + std::vector X, Y, Z; + + std::vector> F; + + std::vector> C; + + std::vector owner, neigh; + + std::vector skin; + + std::vector ftag; + + std::vector fref; + + DynMesh(); + + DynMesh(Karray *karray); + + void extract_points_from_ftag(ArrayI *points); + + void make_skin_graph(SkinGraph *skin_graph); + + void make_face_centers(const E_Int NF, const E_Int *skin, + Vec3f *fc); + + void smooth_skin_ref_data(SkinGraph *skin_graph, E_Int *fdat); + + bool point_in_tri(const Point *p, E_Int tid) const; + + bool point_in_quad(const Point *p, E_Int qid) const; + + bool point_in_face(const Point *p, E_Int fid) const; + + E_Int orient_skin(E_Int normal_direction); + + void extract_skin(E_Int *count, E_Int **skin); + + void make_skin_connectivity(SkinGraph *skin_graph); + + void make_skin_neighbours(SkinGraph *skin_graph); + + + inline bool face_is_quad(E_Int face) const { return F[face].size() == 4; } + + inline bool face_is_tri(E_Int face) const { return F[face].size() == 3; } + + void write_ngon(const char *fname); + + void write_faces(const char *fname, const std::vector &faces) const; + + void write_face(const char *fname, E_Int fid) const; + + // Adaptation + void init_adaptation_data(); + + std::vector smooth_ref_data( + const std::map> &sensor); + + std::vector prepare_for_refinement( + const std::vector &ref_data); + + std::set factive; + std::map> fchildren; + std::vector flevel; + + std::map ecenter; + + size_t refine(const DynMesh &S); + + inline bool face_is_active(E_Int face) const + { return factive.find(face) != factive.end(); } + + void refine_faces(const std::vector &ref_faces); + + void resize_point_data(size_t nref_faces); + + void resize_face_data(size_t nref_faces); + + void refine_quad(E_Int quad); + + void refine_tri(E_Int tri); + + DynMesh extract_conformized(); + + void get_fleaves(E_Int face, std::vector &fleaves); + + PyObject *export_karray(E_Int remove_periodic = 0); + + PyObject *export_karray_orig(); + + PyObject *export_karray_periodic(); + + /* TOPO */ + + + + void flag_and_get_external_faces(std::vector &fflags, + std::vector &efaces); + + void extract_nface_of_kept_pgs(const std::vector &kept_pgs, + std::vector &NFACE, std::vector &cxadj, + std::vector &cells); + + void flag_marked_external_cells(const std::vector &cells, + const std::vector &fflags, std::vector &cflags); + + void flag_all_external_cells(const std::vector &fflags, + std::vector &cflags); + + E_Int orient_boundary(E_Int ncells, E_Int *efadj, E_Int *exadj, E_Int nefaces, + E_Int *fneis, E_Int *efaces, std::vector &forient, + const std::vector &cflags, const std::vector &fflags, + E_Int *cells, E_Int normal_direction); + + void compute_cell_volume(E_Int cell, E_Float &vol, E_Int refIdx); +}; diff --git a/Cassiopee/XCore/XCore/AdaptMesh/DynMeshTopo.cpp b/Cassiopee/XCore/XCore/AdaptMesh/DynMeshTopo.cpp new file mode 100644 index 000000000..2964e64df --- /dev/null +++ b/Cassiopee/XCore/XCore/AdaptMesh/DynMeshTopo.cpp @@ -0,0 +1,332 @@ +#include "DynMesh.h" + +#define OUT 0 +#define IN 1 + +#define INTERNAL 0 +#define EXTERNAL 1 + +#define DSMALL 1e-14 + +E_Int DynMesh::orient_skin(E_Int normal_direction) +{ + // flag external cells and faces + std::vector fflags, efaces; + flag_and_get_external_faces(fflags, efaces); + + // extract external faces connectivity + std::vector fadj; + std::vector xadj(1, 0); + for (E_Int i = 0; i < nf; i++) { + if (fflags[i] == EXTERNAL) { + const auto &pn = F[i]; + xadj.push_back(pn.size()); + for (size_t j = 0; j < pn.size(); j++) fadj.push_back(pn[j]); + } + } + + E_Int nefaces = (E_Int)efaces.size(); + + if (skin.size()) { + assert(efaces.size() == skin.size()); + } + + for (E_Int i = 0; i < nefaces; i++) xadj[i+1] += xadj[i]; + + // build skin neighbourhood + std::vector fneighbours; + K_CONNECT::build_face_neighbourhood(fadj, xadj, fneighbours); + + // color the faces by connex part + std::vector colors(xadj.size()-1); + E_Int nconnex = K_CONNECT::colorConnexParts(&fneighbours[0], &xadj[0], + nefaces, &colors[0]); + + //printf("orient_boundary(): connex parts: " SF_D_ "\n", nconnex); + + assert(efaces.size() == xadj.size()-1); + std::vector forient(nefaces, 0); + std::vector cflags; + E_Int ret = 0; + + if (nconnex > 1) { + // extract nconnex nface-ngon for separate orientation + for (E_Int color = 0; color < nconnex; color++) { + std::vector keep_pgs(nf, false); + for (E_Int i = 0; i < nefaces; i++) { + keep_pgs[efaces[i]] = (colors[i] == color); + } + + // extract nface corresponding to kept faces + std::vector NFACE, cxadj(1, 0), cells; + extract_nface_of_kept_pgs(keep_pgs, NFACE, cxadj, cells); + + std::vector cflags; + flag_marked_external_cells(cells, fflags, cflags); + + ret |= orient_boundary((E_Int)cells.size(), + &fadj[0], &xadj[0], nefaces, &fneighbours[0], &efaces[0], + forient, cflags, fflags, &cells[0], normal_direction); + } + } else { + std::vector cflags; + flag_all_external_cells(fflags, cflags); + ret = orient_boundary(nc, &fadj[0], &xadj[0], nefaces, &fneighbours[0], + &efaces[0], forient, cflags, fflags, NULL, normal_direction); + } + + // Apply orientation + E_Int nrev = 0; + for (E_Int i = 0; i < nefaces; i++) { + if (forient[i] == -1) { + E_Int face = efaces[i]; // 0-based + auto &pn = F[face]; + std::reverse(pn.begin(), pn.end()); + nrev++; + } + } + + //printf("orient_boundary(): reversed " SF_D_ " faces\n", nrev); + + return ret; +} + +void DynMesh::flag_and_get_external_faces(std::vector &fflags, + std::vector &efaces) +{ + std::vector face_count(nf, 0); + + // Loop through the elements and increment face_count + for (E_Int i = 0; i < nc; i++) { + const auto &pf = C[i]; + for (E_Int face : pf) face_count[face]++; + } + + // External faces are those with a count equal to 1 + fflags.resize(nf); + + for (E_Int i = 0; i < nf; i++) { + if (face_count[i] == 1) { + fflags[i] = EXTERNAL; + efaces.push_back(i); + } else { + fflags[i] = INTERNAL; + } + } +} + +void DynMesh::extract_nface_of_kept_pgs(const std::vector &kept_pgs, + std::vector &NFACE, std::vector &xadj, + std::vector &cells) +{ + NFACE.clear(); + xadj.resize(1, 0); + cells.clear(); + + for (E_Int i = 0; i < nc; i++) { + const auto &pf = C[i]; + bool keep = false; + for (size_t j = 0; j < pf.size() && !keep; j++) keep = kept_pgs[pf[j]]; + if (keep) { + cells.push_back(i); + xadj.push_back(pf.size()); + for (size_t j = 0; j < pf.size(); j++) NFACE.push_back(pf[j]); + } + } + + for (size_t i = 0; i < xadj.size(); i++) xadj[i+1] += xadj[i]; +} + +void DynMesh::flag_marked_external_cells(const std::vector &cells, + const std::vector &fflags, std::vector &cflags) +{ + // External cells are those with at least one external face + cflags.resize(cells.size(), INTERNAL); + + for (size_t i = 0; i < cells.size(); i++) { + E_Int cell = cells[i]; + const auto &pf = C[cell]; + for (size_t j = 0; j < pf.size(); j++) { + E_Int face = pf[j]; + if (fflags[face] == EXTERNAL) { + cflags[i] = EXTERNAL; + break; + } + } + } +} + +E_Int DynMesh::orient_boundary(E_Int ncells, E_Int *efadj, E_Int *efxadj, + E_Int nefaces, E_Int *fneis, E_Int *efaces, std::vector &forient, + const std::vector &cflags, const std::vector &fflags, + E_Int *cells, E_Int normal_direction) +{ + // Look for a cell whose volume is unambiguously computed + E_Float cvol = 0.0; + E_Int seed = -1; + E_Int refPG = -1; + E_Int refIdx = -1; + + while (++seed < ncells) { + if (cflags[seed] != EXTERNAL) continue; + + E_Int cid = (cells != NULL) ? cells[seed] : seed; + + const auto &pf = C[cid]; + refPG = -1; + E_Int local_idx = -1; + for (size_t j = 0; j < pf.size(); j++) { + E_Int face = pf[j]; + if (fflags[face] == EXTERNAL) { + refPG = face; + local_idx = j; + break; + } + } + + if (refPG == -1) { + fprintf(stderr, "orient_boundary(): couldn't find an external face " + "within external cell " SF_D_ "\n", cid); + return 1; + } + + // Look for index of refPG in efaces (0-based) + refIdx = -1; + for (E_Int i = 0; i < nefaces; i++) { + if (efaces[i] == refPG) { + refIdx = i; + break; + } + } + + if (refIdx == -1) { + fprintf(stderr, "orient_boundary(): couldn't find reference face " + SF_D_ " in external faces list\n", refPG); + return 1; + } + + // Set orientation of refPG to +1. + // Reorient seed's faces based on orientation of refPG. + // Compute cvol, the volume of seed. + // If cvol > 0, orientation of all faces including refPG, is outwards + // Otherwise, set orientation of refPG to -1. + + compute_cell_volume(cid, cvol, local_idx); + + if (fabs(cvol) < DSMALL) continue; + + // set reference orientation of refPG and exit + forient[refIdx] = (cvol > 0.0) ? 1 : -1; + + if (normal_direction == IN) forient[refIdx] = -forient[refIdx]; + + break; + } + + if (seed >= ncells) { + fprintf(stderr, "orient_boundary_ngon(): couldn't find reference " + "polyhedron\n"); + assert(0); + return 1; + } + + // propagate + K_CONNECT::reversi_connex(efadj, efxadj, nefaces, fneis, refIdx, forient); + + return 0; +} + +void DynMesh::compute_cell_volume(E_Int cell, E_Float &vol, E_Int refIdx) +{ + // Orient the faces coherently + std::vector NGON; + std::vector INDPG(1, 0); + const auto &pf = C[cell]; + E_Int stride = (E_Int)pf.size(); + + for (E_Int i = 0; i < stride; i++) { + E_Int face = pf[i]; + const auto &pn = F[face]; + E_Int np = pn.size(); + INDPG.push_back(np); + for (E_Int j = 0; j < np; j++) NGON.push_back(pn[j]); + } + + for (E_Int i = 0; i < stride; i++) INDPG[i+1] += INDPG[i]; + + // Fix orientation of first face + std::vector orient(stride); + orient[refIdx] = 1; + std::vector neis(NGON.size()); + K_CONNECT::build_face_neighbourhood(NGON, INDPG, neis); + K_CONNECT::reversi_connex(&NGON[0], &INDPG[0], stride, &neis[0], refIdx, + orient); + + // Apply orientation in local NGON + for (E_Int i = 0; i < stride; i++) { + if (orient[i] == -1) { + E_Int start = INDPG[i]; + E_Int np = INDPG[i+1] - start; + E_Int *pn = &NGON[start]; + std::reverse(pn+1, pn+np); + } + } + + // Compute faces area and center + std::vector faceAreas(3*stride, 0.0); + std::vector faceCenters(3*stride, 0.0); + + for (E_Int i = 0; i < stride; i++) { + E_Int face = pf[i]; + E_Float *fa = &faceAreas[3*i]; + E_Float *fc = &faceCenters[3*i]; + E_Int np = INDPG[i+1]-INDPG[i]; + E_Int *pn = &NGON[INDPG[i]]; + for (E_Int j = 0; j < np; j++) pn[j] += 1; + K_METRIC::compute_face_center_and_area(face, np, pn, X.data(), Y.data(), + Z.data(), fc, fa); + } + + // Estimate cell centroid as average of face centers + E_Float cc[3] = {0,0,0}; + for (E_Int i = 0; i < stride; i++) { + E_Float *fc = &faceCenters[3*i]; + for (E_Int j = 0; j < 3; j++) cc[j] += fc[j]; + } + for (E_Int i = 0; i < 3; i++) cc[i] /= stride; + + // Compute cell volume + vol = 0.0; + + for (E_Int i = 0; i < stride; i++) { + E_Float *fa = &faceAreas[3*i]; + E_Float *fc = &faceCenters[3*i]; + + // Compute 3*face-pyramid volume contribution + E_Float d[3] = {fc[0]-cc[0], fc[1]-cc[1], fc[2]-cc[2]}; + //E_Float pyr3Vol = K_MATH::dot(fa, fc, 3); + E_Float pyr3Vol = K_MATH::dot(fa, d, 3); + + vol += pyr3Vol; + } + + vol *= K_MATH::ONE_THIRD; +} + +void DynMesh::flag_all_external_cells(const std::vector &fflags, + std::vector &cflags) +{ + // External cells are those with at least one external face + cflags.resize(nc, INTERNAL); + for (E_Int i = 0; i < nc; i++) { + const auto &pf = C[i]; + E_Int stride = (E_Int)pf.size(); + for (E_Int j = 0; j < stride; j++) { + E_Int face = pf[j]; + if (fflags[face] == EXTERNAL) { + cflags[i] = EXTERNAL; + break; + } + } + } +} \ No newline at end of file diff --git a/Cassiopee/XCore/XCore/AdaptMesh/MeshExtract.cpp b/Cassiopee/XCore/XCore/AdaptMesh/MeshExtract.cpp index 0116bf53e..b19541d1b 100644 --- a/Cassiopee/XCore/XCore/AdaptMesh/MeshExtract.cpp +++ b/Cassiopee/XCore/XCore/AdaptMesh/MeshExtract.cpp @@ -61,6 +61,7 @@ void Mesh_extract_faces_from_ftag(const Mesh *M, FaceSort **mfaces, assert(*mcount == count); } +static void Mesh_extract_skin(const Mesh *M, E_Int *count, E_Int **skin) { *count = 0; @@ -78,6 +79,7 @@ void Mesh_extract_skin(const Mesh *M, E_Int *count, E_Int **skin) } } +static void Mesh_make_skin_connectivity(const Mesh *M, SkinGraph *skin_graph) { // Count @@ -111,115 +113,11 @@ void Mesh_make_skin_connectivity(const Mesh *M, SkinGraph *skin_graph) } } -struct EdgeNode { - E_Int p, q; - E_Int i, j; - E_Int posi, posj; - EdgeNode *next; -}; - -EdgeNode *make_edge_node(E_Int p, E_Int q, E_Int i, E_Int posi) -{ - EdgeNode *node = (EdgeNode *)XMALLOC(sizeof(EdgeNode)); - node->p = p < q ? p : q; - node->q = p < q ? q : p; - node->i = i; - node->posi = posi; - node->j = -1; - node->posj = -1; - node->next = NULL; - return node; -} - -EdgeNode *find_edge_node(EdgeNode **ht, E_Int hsize, E_Int p, E_Int q) -{ - E_Int p_ = p < q ? p : q; - E_Int q_ = p < q ? q : p; - E_Int bucket = p_ % hsize; - EdgeNode *current = ht[bucket]; - - while (current) { - E_Int P = current->p, Q = current->q; - if (P == p_ && Q == q_) { - return current; - } - current = current->next; - } - - return NULL; -} - -void insert_edge_node(EdgeNode *node, const E_Int hsize, EdgeNode **ht) -{ - assert(node->p < node->q); - E_Int bucket = node->p % hsize; - EdgeNode *current = ht[bucket]; - - if (current) { - EdgeNode *tmp = current; - ht[bucket] = node; - node->next = tmp; - } else { - ht[bucket] = node; - } -} - -void Mesh_make_skin_neighbours(const Mesh *M, SkinGraph *skin_graph) -{ - E_Int nf = skin_graph->nf; - const E_Int *xadj = skin_graph->xadj; - const E_Int *fpts = skin_graph->fpts; - - skin_graph->fnei = (E_Int *)XMALLOC(xadj[nf] * sizeof(E_Int)); - E_Int *fnei = skin_graph->fnei; - memset(fnei, -1, xadj[nf] * sizeof(E_Int)); - - EdgeNode **ht = (EdgeNode **)XMALLOC(nf * sizeof(EdgeNode *)); - memset(ht, 0, nf * sizeof(EdgeNode *)); - - for (E_Int i = 0; i < nf; i++) { - E_Int start = xadj[i]; - E_Int np = xadj[i+1] - start; - const E_Int *pn = &fpts[start]; - for (E_Int j = 0; j < np; j++) { - E_Int p = pn[j]; - E_Int q = pn[(j+1)%np]; - EdgeNode *node = find_edge_node(ht, nf, p, q); - if (node) { - assert(node->i != -1); - assert(node->posi != -1); - assert(node->j == -1); - assert(node->posj == -1); - node->j = i; - node->posj = j; - } else { - node = make_edge_node(p, q, i, j); - insert_edge_node(node, nf, ht); - } - } - } - - for (E_Int i = 0; i < nf; i++) { - EdgeNode *node = ht[i]; - while (node) { - E_Int pi = xadj[node->i] + node->posi; - assert(fnei[pi] == -1); - fnei[pi] = node->j; - - E_Int pj = xadj[node->j] + node->posj; - assert(fnei[pj] == -1); - fnei[pj] = node->i; - - node = node->next; - } - } -} - void Mesh_make_skin_graph(const Mesh *M, SkinGraph *skin_graph) { Mesh_extract_skin(M, &skin_graph->nf, &skin_graph->skin); Mesh_make_skin_connectivity(M, skin_graph); - Mesh_make_skin_neighbours(M, skin_graph); + SkinGraph_make_skin_neighbours(skin_graph); } void Mesh_make_face_centers(const Mesh *M, const E_Int nf, const E_Int *skin, diff --git a/Cassiopee/XCore/XCore/AdaptMesh/MeshLocate.cpp b/Cassiopee/XCore/XCore/AdaptMesh/MeshLocate.cpp index 0bc5cf428..7e27b2dc4 100644 --- a/Cassiopee/XCore/XCore/AdaptMesh/MeshLocate.cpp +++ b/Cassiopee/XCore/XCore/AdaptMesh/MeshLocate.cpp @@ -5,7 +5,7 @@ bool Mesh_point_in_tri(const Mesh *M, const Point *p, E_Int tid) { const E_Int *face = Mesh_get_face(M, tid); E_Int A = face[0], B = face[2], C = face[4]; - return point_in_tri(p->x, p->y, p->z, + return Point_in_tri(p->x, p->y, p->z, M->X[A], M->Y[A], M->Z[A], M->X[B], M->Y[B], M->Z[B], M->X[C], M->Y[C], M->Z[C]); @@ -25,14 +25,14 @@ bool Mesh_point_in_quad(const Mesh *M, const Point *p, E_Int qid) bool hit = false; // First triangle - hit = point_in_tri(p->x, p->y, p->z, + hit = Point_in_tri(p->x, p->y, p->z, O[0], O[1], O[2], M->X[A], M->Y[A], M->Z[A], M->X[B], M->Y[B], M->Z[B]); if (hit) return true; // Second triangle - hit = point_in_tri(p->x, p->y, p->z, + hit = Point_in_tri(p->x, p->y, p->z, O[0], O[1], O[2], M->X[B], M->Y[B], M->Z[B], M->X[C], M->Y[C], M->Z[C]); @@ -40,14 +40,14 @@ bool Mesh_point_in_quad(const Mesh *M, const Point *p, E_Int qid) // Third triangle - hit = point_in_tri(p->x, p->y, p->z, + hit = Point_in_tri(p->x, p->y, p->z, O[0], O[1], O[2], M->X[C], M->Y[C], M->Z[C], M->X[D], M->Y[D], M->Z[D]); if (hit) return true; // Fourth triangle - hit = point_in_tri(p->x, p->y, p->z, + hit = Point_in_tri(p->x, p->y, p->z, O[0], O[1], O[2], M->X[D], M->Y[D], M->Z[D], M->X[A], M->Y[A], M->Z[A]); diff --git a/Cassiopee/XCore/XCore/AdaptMesh/Point.cpp b/Cassiopee/XCore/XCore/AdaptMesh/Point.cpp index 720399840..9e2c014af 100644 --- a/Cassiopee/XCore/XCore/AdaptMesh/Point.cpp +++ b/Cassiopee/XCore/XCore/AdaptMesh/Point.cpp @@ -5,7 +5,7 @@ #include "Array.h" #include "common/mem.h" -bool point_in_tri(E_Float px, E_Float py, E_Float pz, +bool Point_in_tri(E_Float px, E_Float py, E_Float pz, E_Float ax, E_Float ay, E_Float az, E_Float bx, E_Float by, E_Float bz, E_Float cx, E_Float cy, E_Float cz) @@ -101,6 +101,8 @@ void PointFaces_extract_by_threshold if (ftag[i] > threshold) *ptr++ = i;//skin[i]; } + + XFREE(ftag); } void points_write(const char *fname, const std::vector &P) diff --git a/Cassiopee/XCore/XCore/AdaptMesh/Point.h b/Cassiopee/XCore/XCore/AdaptMesh/Point.h index 188651dd5..a738a3166 100644 --- a/Cassiopee/XCore/XCore/AdaptMesh/Point.h +++ b/Cassiopee/XCore/XCore/AdaptMesh/Point.h @@ -17,7 +17,7 @@ struct PointFaces { E_Int ptr[MAX_FACES_PER_POINT]; }; -bool point_in_tri(E_Float px, E_Float py, E_Float pz, +bool Point_in_tri(E_Float px, E_Float py, E_Float pz, E_Float ax, E_Float ay, E_Float az, E_Float bx, E_Float by, E_Float bz, E_Float cx, E_Float cy, E_Float cz); diff --git a/Cassiopee/XCore/XCore/AdaptMesh/Skin.cpp b/Cassiopee/XCore/XCore/AdaptMesh/Skin.cpp index bfd995ede..e7f0c4d7e 100644 --- a/Cassiopee/XCore/XCore/AdaptMesh/Skin.cpp +++ b/Cassiopee/XCore/XCore/AdaptMesh/Skin.cpp @@ -3,8 +3,116 @@ void SkinGraph_free(SkinGraph *skin_graph) { + skin_graph->nf = 0; XFREE(skin_graph->skin); XFREE(skin_graph->xadj); XFREE(skin_graph->fpts); XFREE(skin_graph->fnei); } + +struct EdgeNode { + E_Int p, q; + E_Int i, j; + E_Int posi, posj; + EdgeNode *next; +}; + +static +EdgeNode *make_edge_node(E_Int p, E_Int q, E_Int i, E_Int posi) +{ + EdgeNode *node = (EdgeNode *)XMALLOC(sizeof(EdgeNode)); + node->p = p < q ? p : q; + node->q = p < q ? q : p; + node->i = i; + node->posi = posi; + node->j = -1; + node->posj = -1; + node->next = NULL; + return node; +} + +static +EdgeNode *find_edge_node(EdgeNode **ht, E_Int hsize, E_Int p, E_Int q) +{ + E_Int p_ = p < q ? p : q; + E_Int q_ = p < q ? q : p; + E_Int bucket = p_ % hsize; + EdgeNode *current = ht[bucket]; + + while (current) { + E_Int P = current->p, Q = current->q; + if (P == p_ && Q == q_) { + return current; + } + current = current->next; + } + + return NULL; +} + +static +void insert_edge_node(EdgeNode *node, const E_Int hsize, EdgeNode **ht) +{ + assert(node->p < node->q); + E_Int bucket = node->p % hsize; + EdgeNode *current = ht[bucket]; + + if (current) { + EdgeNode *tmp = current; + ht[bucket] = node; + node->next = tmp; + } else { + ht[bucket] = node; + } +} + +void SkinGraph_make_skin_neighbours(SkinGraph *skin_graph) +{ + E_Int nf = skin_graph->nf; + const E_Int *xadj = skin_graph->xadj; + const E_Int *fpts = skin_graph->fpts; + + skin_graph->fnei = (E_Int *)XMALLOC(xadj[nf] * sizeof(E_Int)); + E_Int *fnei = skin_graph->fnei; + memset(fnei, -1, xadj[nf] * sizeof(E_Int)); + + EdgeNode **ht = (EdgeNode **)XMALLOC(nf * sizeof(EdgeNode *)); + memset(ht, 0, nf * sizeof(EdgeNode *)); + + for (E_Int i = 0; i < nf; i++) { + E_Int start = xadj[i]; + E_Int np = xadj[i+1] - start; + const E_Int *pn = &fpts[start]; + for (E_Int j = 0; j < np; j++) { + E_Int p = pn[j]; + E_Int q = pn[(j+1)%np]; + EdgeNode *node = find_edge_node(ht, nf, p, q); + if (node) { + assert(node->i != -1); + assert(node->posi != -1); + assert(node->j == -1); + assert(node->posj == -1); + node->j = i; + node->posj = j; + } else { + node = make_edge_node(p, q, i, j); + insert_edge_node(node, nf, ht); + } + } + } + + for (E_Int i = 0; i < nf; i++) { + EdgeNode *node = ht[i]; + while (node) { + E_Int pi = xadj[node->i] + node->posi; + assert(fnei[pi] == -1); + fnei[pi] = node->j; + + E_Int pj = xadj[node->j] + node->posj; + assert(fnei[pj] == -1); + fnei[pj] = node->i; + + node = node->next; + } + } +} \ No newline at end of file diff --git a/Cassiopee/XCore/XCore/AdaptMesh/Skin.h b/Cassiopee/XCore/XCore/AdaptMesh/Skin.h index 2b581023a..6f89d1d31 100644 --- a/Cassiopee/XCore/XCore/AdaptMesh/Skin.h +++ b/Cassiopee/XCore/XCore/AdaptMesh/Skin.h @@ -13,3 +13,5 @@ struct SkinGraph { }; void SkinGraph_free(SkinGraph *skin_graph); + +void SkinGraph_make_skin_neighbours(SkinGraph *skin_graph); diff --git a/Cassiopee/XCore/XCore/PyTree.py b/Cassiopee/XCore/XCore/PyTree.py index 56812a911..4f0500b3f 100644 --- a/Cassiopee/XCore/XCore/PyTree.py +++ b/Cassiopee/XCore/XCore/PyTree.py @@ -100,8 +100,30 @@ def AdaptMesh_TriangulateFaces(AM, faces): def AdaptMesh_GeneratePrisms(AM, faces): return xcore.AdaptMesh_GeneratePrisms(AM, faces) -def AdaptMesh_AdaptGeom(AM, AS): - return xcore.AdaptMesh_AdaptGeom(AM, AS) +def AdaptMesh_AdaptGeom(AM, slave, tagged_faces): + zs = I.getZones(slave)[0] + s = C.getFields(I.__GridCoordinates__, zs, api=3)[0] + + keep = I.getNodeFromName(zs, 'keep') + + return xcore.AdaptMesh_AdaptGeom(AM, s, tagged_faces) + + ''' + s, spatch = xcore.AdaptMesh_AdaptGeom(AM, s, tagged_faces) + + zso = I.createZoneNode("S_adapted", s) + + zbcs = I.createUniqueChild(zso, 'ZoneBC', 'ZoneBC_t') + + I.newBC(name="intersection_patch", pointList=spatch, family='UserDefined', parent=zbcs) + + ts = C.newPyTree(["S_adapted", zso]) + + if keep is not None: + C._cpVars(slave, 'centers:keep', ts, 'centers:keep') + + return ts + ''' def AdaptMesh_ExtractTaggedFaces(AM): return xcore.AdaptMesh_ExtractTaggedFaces(AM) diff --git a/Cassiopee/XCore/srcs.py b/Cassiopee/XCore/srcs.py index f0364dddf..84a5385ba 100644 --- a/Cassiopee/XCore/srcs.py +++ b/Cassiopee/XCore/srcs.py @@ -106,6 +106,9 @@ 'XCore/AdaptMesh/Skin.cpp', 'XCore/AdaptMesh/Array.cpp', + 'XCore/AdaptMesh/DynMesh.cpp', + 'XCore/AdaptMesh/DynMeshTopo.cpp', + 'XCore/extractFacesFromPointTag.cpp', From 443fe28546379fc065ba38f449e89a37ebfefe0f Mon Sep 17 00:00:00 2001 From: imadhammani Date: Thu, 26 Sep 2024 17:34:07 +0200 Subject: [PATCH 16/86] XCore AdaptMesh: example script --- Cassiopee/XCore/XCore/AdaptMesh/test.py | 87 +++++++++++++++++++++++++ 1 file changed, 87 insertions(+) create mode 100644 Cassiopee/XCore/XCore/AdaptMesh/test.py diff --git a/Cassiopee/XCore/XCore/AdaptMesh/test.py b/Cassiopee/XCore/XCore/AdaptMesh/test.py new file mode 100644 index 000000000..0c65abca5 --- /dev/null +++ b/Cassiopee/XCore/XCore/AdaptMesh/test.py @@ -0,0 +1,87 @@ +import Converter.PyTree as C +import Generator.PyTree as G +import Transform.PyTree as T +import XCore.PyTree as X +import Converter.Internal as I +import Converter.elsAProfile as elsAProfile +import numpy as np +import Connector.PyTree as Conn +import Intersector.PyTree as XOR +import Post.PyTree as P + +TOL_match = 1e-7 +TOL_recover = 1e-11 +rot_angle = 2.*np.pi/36. + +# MASTER + +m = C.convertFile2PyTree("data/maillage_veine.cgns") + +(BCs_m, BCNames_m, BCTypes_m) = C.getBCs(m) +families_m = I.getNodesFromType2(m, 'Family_t') + +m = C.convertArray2NGon(m) +m = T.merge(m) + +# rotate master + +rot_center = (0.,0.,0.) +rot_axis = (1.,0.,0.) + +r1 = T.rotate(m, rot_center, rot_axis, rot_angle * 180. / np.pi) +r2 = T.rotate(m, rot_center, rot_axis, -rot_angle * 180. / np.pi) + +# define helper tags + +C._initVars(m, 'centers:keep', 1.0) +C._initVars(r1, 'centers:keep', 0.0) +C._initVars(r2, 'centers:keep', 0.0) + +# merge + +zm = I.getZones(m)[0] +zr1 = I.getZones(r1)[0] +zr2 = I.getZones(r2)[0] +mm = T.merge([zm, zr1, zr2]) + +# SLAVE + +s = C.convertFile2PyTree("data/maillage_fente_axi.cgns") + +(BCs_s, BCNames_s, BCTypes_s) = C.getBCs(s) +families_s = I.getNodesFromType2(s, 'Family_t') + +# rotate slave + +s1 = T.rotate(s, rot_center, rot_axis, -rot_angle * 180. / np.pi) + +# REMOVE INTERSECTING PLANES + +IM = X.IntersectMesh_Init(mm) +sp = X.removeIntersectingKPlanes(IM, s) +sp = T.merge(sp) +C._initVars(sp, 'centers:keep', 1.0) + +sp1 = X.removeIntersectingKPlanes(IM, s1) +sp1 = T.merge(sp1) +C._initVars(sp1, 'centers:keep', 0.0) + +zp = I.getZones(sp)[0] +zp1 = I.getZones(sp1)[0] +sp = T.merge([zp, zp1]) +C.convertPyTree2File(sp, "sp.cgns") +sfaces = X.extractFacesFromPointTag(sp, "tag") + +# AdaptGeom + +AM = X.AdaptMesh_Init(mm) + +sfaces = X.AdaptMesh_AdaptGeom(AM, sp, sfaces) +cont = I.createUniqueChild(I.getZones(sp)[0], 'ZoneBC', 'ZoneBC_t') +I.newBC(name='CONTACT', pointList=sfaces, btype='BCWall', parent=cont) +C.convertPyTree2File(sp, "sp.cgns") + +mp = X.AdaptMesh_ExtractMesh(AM) +C.convertPyTree2File(mp, "mp.cgns") + +#C.convertPyTree2File(si, "si.cgns") From 6a7871ee2c0fdb78d74771a66947bf0144e910b5 Mon Sep 17 00:00:00 2001 From: imadhammani Date: Thu, 26 Sep 2024 19:28:59 +0200 Subject: [PATCH 17/86] XCore AdaptMesh: buggy skin graph neighbours --- .../XCore/AdaptMesh/AdaptMesh_AdaptGeom.cpp | 124 ++---- Cassiopee/XCore/XCore/AdaptMesh/DynMesh.cpp | 367 +++++++++++++++++- Cassiopee/XCore/XCore/AdaptMesh/DynMesh.h | 49 +-- Cassiopee/XCore/XCore/AdaptMesh/Mesh.h | 5 + .../XCore/XCore/AdaptMesh/MeshExtract.cpp | 2 - .../XCore/XCore/AdaptMesh/MeshSmooth.cpp | 32 ++ Cassiopee/XCore/XCore/AdaptMesh/Skin.cpp | 86 +++- Cassiopee/XCore/XCore/AdaptMesh/Skin.h | 9 + Cassiopee/XCore/XCore/PyTree.py | 8 +- .../XCore/XCore/intersectMesh/meshExport.cpp | 1 - Cassiopee/XCore/XCore/intersectMesh/smesh.cpp | 6 +- 11 files changed, 555 insertions(+), 134 deletions(-) diff --git a/Cassiopee/XCore/XCore/AdaptMesh/AdaptMesh_AdaptGeom.cpp b/Cassiopee/XCore/XCore/AdaptMesh/AdaptMesh_AdaptGeom.cpp index 9eead3040..54d39903b 100644 --- a/Cassiopee/XCore/XCore/AdaptMesh/AdaptMesh_AdaptGeom.cpp +++ b/Cassiopee/XCore/XCore/AdaptMesh/AdaptMesh_AdaptGeom.cpp @@ -67,42 +67,6 @@ void locate_points_in_skin } } -void smooth_skin_ref_data(Mesh *M, const SkinGraph *skin_graph, E_Int *fdat) -{ - E_Int nf = skin_graph->nf; - - std::stack stk; - - for (E_Int i = 0; i < nf; i++) { - if (fdat[i] > 0) - stk.push(i); - } - - const E_Int *xadj = skin_graph->xadj; - const E_Int *fnei = skin_graph->fnei; - - while (!stk.empty()) { - - E_Int fid = stk.top(); - stk.pop(); - - E_Int start = xadj[fid]; - E_Int nneis = xadj[fid+1] - start; - const E_Int *neis = &fnei[start]; - - for (E_Int i = 0; i < nneis; i++) { - E_Int nei = neis[i]; - E_Int incr_nei = fdat[nei] + M->flevel[skin_graph->skin[nei]]; - E_Int incr_fid = fdat[fid] + M->flevel[skin_graph->skin[fid]]; - E_Int diff = abs(incr_nei - incr_fid); - if (diff <= 1) continue; - E_Int idx_to_modify = incr_fid > incr_nei ? nei : fid; - fdat[idx_to_modify] += diff-1; - stk.push(idx_to_modify); - } - } -} - void init_skin_refinement_cells(const SkinGraph *skin_graph, const E_Int *fdat, Mesh *M, E_Int *rcount) { @@ -123,37 +87,6 @@ void init_skin_refinement_cells(const SkinGraph *skin_graph, *rcount = count; } -void smooth_cell_refinement_data(Mesh *M) -{ - E_Int nc = M->nc; - - std::stack stk; - - for (E_Int cid = 0; cid < nc; cid++) { - if (M->cref[cid] > 0) - stk.push(cid); - } - - while (!stk.empty()) { - E_Int cid = stk.top(); - stk.pop(); - - E_Int nn, neis[24]; - Mesh_get_cneis(M, cid, nn, neis); - - for (E_Int i = 0; i < nn; i++) { - E_Int nei = neis[i]; - E_Int incr_nei = M->cref[nei] + M->clevel[nei]; - E_Int incr_cid = M->cref[cid] + M->clevel[cid]; - E_Int diff = abs(incr_nei - incr_cid); - if (diff <= 1) continue; - E_Int idx_to_modify = incr_cid > incr_nei ? nei : cid; - M->cref[idx_to_modify] += diff-1; - stk.push(idx_to_modify); - } - } -} - void Mesh_set_face_as_cell_bottom(Mesh *M, E_Int fid, E_Int cid) { // Make fid the bottom face @@ -566,6 +499,8 @@ PyObject *K_XCORE::AdaptMesh_AdaptGeom(PyObject *self, PyObject *args) for (E_Int i = 0; i < tag_size; i++) { S.ftag[tagged_faces[i]] = 1; } + //S.init_adaptation_data(tagged_faces, tag_size); + S.init_adaptation_data(); // Refine M volumetric wrt to S tagged faces point cloud // Refine S surfacic wrt to M tagged faces point cloud @@ -620,7 +555,6 @@ PyObject *K_XCORE::AdaptMesh_AdaptGeom(PyObject *self, PyObject *args) Mesh_SkinGraph_compute_normals(M, &skin_graph); E_Int *xadj = skin_graph.xadj; - E_Int *fpts = skin_graph.fpts; E_Int *fnei = skin_graph.fnei; Vec3f *fnml = skin_graph.fnml; @@ -646,7 +580,6 @@ PyObject *K_XCORE::AdaptMesh_AdaptGeom(PyObject *self, PyObject *args) E_Int start = xadj[fid]; E_Int end = xadj[fid+1]; E_Int stride = end - start; - E_Int *pp = &fpts[start]; E_Int *pn = &fnei[start]; Vec3f *fid_nml = &fnml[fid]; @@ -657,7 +590,7 @@ PyObject *K_XCORE::AdaptMesh_AdaptGeom(PyObject *self, PyObject *args) Vec3f *nei_nml = &fnml[nei]; E_Float dp = K_MATH::dot((E_Float *)fid_nml, (E_Float *)nei_nml, 3); - assert(dp >= 0.0); + //assert(dp >= 0.0); dp = std::max(dp, -1.0); dp = std::min(dp, 1.0); E_Float theta = acos(dp) * 180.0 / K_MATH::PI; @@ -737,7 +670,7 @@ PyObject *K_XCORE::AdaptMesh_AdaptGeom(PyObject *self, PyObject *args) } } - assert(cvisit = M->nc); + assert(cvisit == M->nc); XFREE(visited); XFREE(fqueue); @@ -765,7 +698,7 @@ PyObject *K_XCORE::AdaptMesh_AdaptGeom(PyObject *self, PyObject *args) E_Int idx_in_skin = indices[rfaces.ptr[i]]; fdat[idx_in_skin] = 1; } - smooth_skin_ref_data(M, &skin_graph, fdat); + SkinGraph_smooth_ref_data(&skin_graph, fdat, M); puts("Face refinement smoothed out"); E_Int smooth_nfref = 0; @@ -785,7 +718,7 @@ PyObject *K_XCORE::AdaptMesh_AdaptGeom(PyObject *self, PyObject *args) if (ref_cell_count == 0) break; // Smooth cell refinement data - smooth_cell_refinement_data(M); + Mesh_smooth_cell_refinement_data(M); puts("Cell refinement smoothed out"); // Assign refinement data @@ -840,9 +773,9 @@ PyObject *K_XCORE::AdaptMesh_AdaptGeom(PyObject *self, PyObject *args) // Extract mpoints from tagged mfaces ArrayI mpoints; Mesh_extract_points_from_ftag(M, &mpoints); - printf("mpoints: %d\n", mpoints); + printf("mpoints: %d\n", mpoints.count); - //if (iter == 10) + /*if (iter == 10) { std::vector points; for (E_Int i = 0; i < mpoints.count; i++) { @@ -852,6 +785,7 @@ PyObject *K_XCORE::AdaptMesh_AdaptGeom(PyObject *self, PyObject *args) } points_write("mpoints", points); } + */ // We need the skin connectivity graph skin_graph = {0}; @@ -891,6 +825,7 @@ PyObject *K_XCORE::AdaptMesh_AdaptGeom(PyObject *self, PyObject *args) printf("Refinement faces: %d\n", rfaces.count); ref_count_S = rfaces.count; + /* if (iter == 2) { npy_intp dims[2]; @@ -909,6 +844,7 @@ PyObject *K_XCORE::AdaptMesh_AdaptGeom(PyObject *self, PyObject *args) return (PyObject *)FACES; } + */ if (rfaces.count > 0) { @@ -919,45 +855,55 @@ PyObject *K_XCORE::AdaptMesh_AdaptGeom(PyObject *self, PyObject *args) E_Int idx_in_skin = indices[rfaces.ptr[i]]; fdat[idx_in_skin] = 1; } - S.smooth_skin_ref_data(&skin_graph, fdat); + SkinGraph_smooth_ref_data(&skin_graph, fdat, &S); puts("Face refinement smoothed out"); // Assign refinement data - S.fref.resize(M->nf, 0); + S.fref.resize(S.nf, 0); E_Int smooth_nfref = 0; for (E_Int i = 0; i < skin_graph.nf; i++) { if (fdat[i] > 0) { E_Int fid = skin_graph.skin[i]; + assert(S.face_is_active(fid)); S.fref[fid] = 1; smooth_nfref++; } } printf("Smooth refinement face count: %d\n", smooth_nfref); - /* // Isolate refinement faces ArrayI ref_faces; - Mesh_isolate_refinement_faces(S, &ref_faces); + S.prepare_for_refinement(&ref_faces); printf("Refinement faces: %d\n", ref_faces.count); assert(ref_faces.count == smooth_nfref); - // Resize for refinement - E_Int face_incr = ref_faces.count * 3; - E_Int new_nf = S->nf + face_incr; - E_Int new_np = S->np + face_incr; - Mesh_resize_face_data(S, S->nf + ref_faces.count * 3); - Mesh_resize_point_data(S, ref_faces.count * 2); - */ - } - + // Refine + S.refine_faces(&ref_faces); + XFREE(fdat); + ArrayI_free(&ref_faces); + } // FREE + BVH_free(bvh); + ArrayI_free(&rfaces); + ArrayI_free(&mpoints); + XFREE(mploc); + XFREE(indices); + XFREE(skin_fc); + SkinGraph_free(&skin_graph); + } while (iter < max_iter && (ref_count_M > 0 || ref_count_S > 0)); - + S = S.extract_conformized(); + + PyObject *Sout = S.export_karray(); + + Karray_free_ngon(sarray); + + return Sout; return Py_None; } diff --git a/Cassiopee/XCore/XCore/AdaptMesh/DynMesh.cpp b/Cassiopee/XCore/XCore/AdaptMesh/DynMesh.cpp index dc68f1e7e..d8c3c365d 100644 --- a/Cassiopee/XCore/XCore/AdaptMesh/DynMesh.cpp +++ b/Cassiopee/XCore/XCore/AdaptMesh/DynMesh.cpp @@ -5,6 +5,10 @@ #include "Vec.h" #include "Point.h" #include "common/mem.h" +#include + +DynMesh::DynMesh() +{} DynMesh::DynMesh(Karray *karray) { @@ -59,7 +63,7 @@ void DynMesh::extract_points_from_ftag(ArrayI *pids) memset(ptag, 0, np * sizeof(E_Int)); pids->count = 0; - for (E_Int fid = 0; fid < nf; fid++) { + for (E_Int fid : factive) { if (ftag[fid] != 1) continue; const auto &pn = F[fid]; @@ -84,14 +88,14 @@ void DynMesh::extract_skin(E_Int *count, E_Int **skin) { *count = 0; - for (E_Int fid = 0; fid < nf; fid++) { + for (E_Int fid : factive) { *count += (neigh[fid] == -1); } *skin = (E_Int *)XMALLOC(*count * sizeof(E_Int)); E_Int *ptr = *skin; - for (E_Int fid = 0; fid < nf; fid++) { + for (E_Int fid : factive) { if (neigh[fid] == -1) *ptr++ = fid; } @@ -100,6 +104,7 @@ void DynMesh::extract_skin(E_Int *count, E_Int **skin) void DynMesh::make_skin_connectivity(SkinGraph *skin_graph) { // Count + printf("skin count: %d\n", skin_graph->nf); skin_graph->xadj = (E_Int *)XMALLOC((skin_graph->nf+1) * sizeof(E_Int)); E_Int *xadj = skin_graph->xadj; xadj[0] = 0; @@ -122,6 +127,8 @@ void DynMesh::make_skin_connectivity(SkinGraph *skin_graph) *ptr++ = p; } } + + assert(ptr - skin_graph->fpts == xadj[skin_graph->nf]); } void DynMesh::make_skin_graph(SkinGraph *skin_graph) @@ -137,6 +144,7 @@ void DynMesh::make_face_centers(const E_Int NF, const E_Int *skin, for (E_Int i = 0; i < NF; i++) { fc[i].x = fc[i].y = fc[i].z = 0.0; E_Int fid = skin[i]; + assert(face_is_active(fid)); const auto &pn = F[fid]; for (E_Int p : pn) { fc[i].x += X[p]; @@ -208,7 +216,356 @@ bool DynMesh::point_in_face(const Point *p, E_Int fid) const return point_in_tri(p, fid); } -void DynMesh::smooth_skin_ref_data(SkinGraph *skin_graph, E_Int *fdat) +void DynMesh::init_adaptation_data(E_Int *tagged_faces, E_Int count) +{ + flevel.resize(nf, 0); + + for (E_Int i = 0; i < count; i++) factive.insert(tagged_faces[i]); +} + +void DynMesh::init_adaptation_data() +{ + flevel.resize(nf, 0); + + for (E_Int i = 0; i < nf; i++) factive.insert(i); +} + +void DynMesh::prepare_for_refinement(ArrayI *ref_faces) +{ + ref_faces->count = 0; + for (E_Int fid : factive) { + ref_faces->count += (fref[fid] == 1); + } + ref_faces->ptr = (E_Int *)XMALLOC(ref_faces->count * sizeof(E_Int)); + E_Int *ptr = ref_faces->ptr; + for (E_Int fid = 0; fid < nf; fid++) { + if (fref[fid] > 0) { + assert(fref[fid] == 1); + *ptr++ = fid; + } + } + + // Refine the lower-level faces first + std::sort(ref_faces->ptr, ref_faces->ptr + ref_faces->count, + [&] (E_Int i, E_Int j) { return flevel[i] < flevel[j]; }); + + // Resize data structures + resize_point_data(ref_faces->count); + resize_face_data(ref_faces->count); +} + +void DynMesh::refine_faces(ArrayI *ref_faces) +{ + for (E_Int i = 0; i < ref_faces->count; i++) { + E_Int fid = ref_faces->ptr[i]; + if (face_is_tri(fid)) refine_tri(fid); + else refine_quad(fid); + } +} + +void DynMesh::resize_point_data(size_t nref_faces) +{ + size_t nnew_points = np + nref_faces * 5; + X.resize(nnew_points); + Y.resize(nnew_points); + Z.resize(nnew_points); +} + +void DynMesh::resize_face_data(size_t nref_faces) +{ + size_t nnew_faces = nf + nref_faces * 4; + F.resize(nnew_faces); + flevel.resize(nnew_faces, -1); + owner.resize(nnew_faces); + neigh.resize(nnew_faces); + ftag.resize(nnew_faces, 0); +} + +void DynMesh::refine_tri(E_Int tri) +{ + // Refine the edges + const auto &pn = F[tri]; + E_Int ec[3]; + + for (size_t i = 0; i < pn.size(); i++) { + E_Int p = pn[i]; + E_Int q = pn[(i+1)%pn.size()]; + uEdge edge(p, q); + + auto it = ecenter.find(edge); + + if (it == ecenter.end()) { + X[np] = 0.5 * (X[p] + X[q]); + Y[np] = 0.5 * (Y[p] + Y[q]); + Z[np] = 0.5 * (Z[p] + Z[q]); + ecenter[edge] = np; + ec[i] = np; + np++; + } else { + ec[i] = it->second; + } + } + + // New face points + E_Int nf0 = nf, nf1 = nf+1, nf2 = nf+2, nf3 = nf+3; + + F[nf0] = { pn[0], ec[0], ec[2] }; + F[nf1] = { ec[0], pn[1], ec[1] }; + F[nf2] = { ec[2], ec[1], pn[2] }; + F[nf3] = { ec[0], ec[1], ec[2] }; + + // Disable quad and enable its children + factive.erase(tri); + factive.insert(nf0); + factive.insert(nf1); + factive.insert(nf2); + factive.insert(nf3); + + // Set quad children pointers + fchildren[tri] = { nf0, nf1, nf2, nf3 }; + flevel[nf0] = flevel[nf1] = flevel[nf2] = flevel[nf3] = flevel[tri] + 1; + + ftag[nf0] = ftag[nf1] = ftag[nf2] = ftag[nf3] = ftag[tri]; + + neigh[nf0] = neigh[nf1] = neigh[nf2] = neigh[nf3] = neigh[tri]; + owner[nf0] = owner[nf1] = owner[nf2] = owner[nf3] = owner[tri]; + + nf += 4; +} + +void DynMesh::refine_quad(E_Int quad) +{ + // Refine the edges + const auto &pn = F[quad]; + E_Int ec[4]; + + for (size_t i = 0; i < pn.size(); i++) { + E_Int p = pn[i]; + E_Int q = pn[(i+1)%pn.size()]; + uEdge edge(p, q); + + auto it = ecenter.find(edge); + + if (it == ecenter.end()) { + X[np] = 0.5 * (X[p] + X[q]); + Y[np] = 0.5 * (Y[p] + Y[q]); + Z[np] = 0.5 * (Z[p] + Z[q]); + ecenter[edge] = np; + ec[i] = np; + np++; + } else { + ec[i] = it->second; + } + } + + // Face centroid + + X[np] = Y[np] = Z[np] = 0.0; + for (E_Int i = 0; i < 4; i++) { + E_Int p = pn[i]; + X[np] += X[p]; + Y[np] += Y[p]; + Z[np] += Z[p]; + } + X[np] *= 0.25; + Y[np] *= 0.25; + Z[np] *= 0.25; + + // New face points + E_Int nf0 = nf, nf1 = nf+1, nf2 = nf+2, nf3 = nf+3; + + F[nf0] = { pn[0], ec[0], np, ec[3] }; + F[nf1] = { ec[0], pn[1], ec[1], np }; + F[nf2] = { np , ec[1], pn[2], ec[2] }; + F[nf3] = { ec[3], np , ec[2], pn[3] }; + + // Disable quad and enable its children + factive.erase(quad); + factive.insert(nf0); + factive.insert(nf1); + factive.insert(nf2); + factive.insert(nf3); + + // Set quad children pointers + fchildren[quad] = { nf0, nf1, nf2, nf3 }; + flevel[nf0] = flevel[nf1] = flevel[nf2] = flevel[nf3] = flevel[quad] + 1; + + ftag[nf0] = ftag[nf1] = ftag[nf2] = ftag[nf3] = ftag[quad]; + + neigh[nf0] = neigh[nf1] = neigh[nf2] = neigh[nf3] = neigh[quad]; + owner[nf0] = owner[nf1] = owner[nf2] = owner[nf3] = owner[quad]; + + np += 1; + nf += 4; +} + +DynMesh DynMesh::extract_conformized() +{ + // Keep all the points + std::vector new_X(X), new_Y(Y), new_Z(Z); + + // Conformize the faces + + std::vector> new_F(factive.size()); + + E_Int new_nf = 0; + + std::map new_fids; + + for (E_Int face : factive) { + new_fids[face] = new_nf; + + const auto &pn = F[face]; + + auto &new_face = new_F[new_nf]; + + for (size_t j = 0; j < pn.size(); j++) { + E_Int p = pn[j]; + E_Int q = pn[(j+1)%pn.size()]; + + std::list epoints; + + extract_edge_points(p, q, epoints); + + epoints.pop_back(); + + for (auto it = epoints.begin(); it != epoints.end(); it++) + new_face.push_back(*it); + } + + new_nf++; + } + + // Update cell connectivity + + std::vector> new_C(C.size()); + + for (E_Int i = 0; i < nc; i++) { + const auto &pf = C[i]; + + auto &new_cell = new_C[i]; + + for (E_Int face : pf) { + + if (face_is_active(face)) { + new_cell.push_back(new_fids[face]); + } else { + std::vector fleaves; + get_fleaves(face, fleaves); + + for (E_Int fleaf : fleaves) + new_cell.push_back(new_fids[fleaf]); + } + } + } + + DynMesh new_M; + new_M.np = np; + new_M.X = X; + new_M.Y = Y; + new_M.Z = Z; + new_M.nf = new_nf; + new_M.F = new_F; + new_M.nc = nc; + new_M.C = new_C; + + for (E_Int face : factive) { + new_M.factive.insert(new_fids[face]); + } + + return new_M; +} + +PyObject *DynMesh::export_karray() +{ + E_Int sizeNGon = 0, sizeNFace = 0; + + for (const auto &pn : F) sizeNGon += (E_Int)pn.size(); + for (const auto &pf : C) sizeNFace += (E_Int)pf.size(); + + const char *varString = "CoordinateX,CoordinateY,CoordinateZ"; + + PyObject *array = K_ARRAY::buildArray3(3, varString, np, nc, nf, "NGON", + sizeNGon, sizeNFace, 3, false, 3); + + K_FLD::FldArrayF *f; + K_FLD::FldArrayI *cn; + K_ARRAY::getFromArray3(array, f, cn); + + E_Float *px = f->begin(1); + for (E_Int i = 0; i < np; i++) px[i] = X[i]; + E_Float *py = f->begin(2); + for (E_Int i = 0; i < np; i++) py[i] = Y[i]; + E_Float *pz = f->begin(3); + for (E_Int i = 0; i < np; i++) pz[i] = Z[i]; + + E_Int *indPG = cn->getIndPG(); + E_Int *ngon = cn->getNGon(); + E_Int *indPH = cn->getIndPH(); + E_Int *nface = cn->getNFace(); + + indPG[0] = indPH[0] = 0; + for (E_Int i = 0; i < nf; i++) indPG[i+1] = indPG[i] + (E_Int)F[i].size(); + for (E_Int i = 0; i < nc; i++) indPH[i+1] = indPH[i] + (E_Int)C[i].size(); + + assert(indPG[nf] == sizeNGon); + assert(indPH[nc] == sizeNFace); + + E_Int *ptr = ngon; + + for (E_Int i = 0; i < nf; i++) { + const auto &pn = F[i]; + for (E_Int p : pn) *ptr++ = p+1; + } + + ptr = nface; + + for (E_Int i = 0; i < nc; i++) { + const auto &pf = C[i]; + for (E_Int f : pf) *ptr++ = f+1; + } + + delete f; + delete cn; + + return array; +} + +void DynMesh::extract_edge_points(E_Int a, E_Int b, std::list &points) { - assert(0); + E_Int ref = 0; + + points.clear(); + points.push_back(a); + points.push_back(b); + + do { + ref = 0; + + assert(*std::prev(points.end()) == b); + + for (auto it = points.begin(); it != std::prev(points.end()); it++) { + E_Int a = *it; + E_Int b = *std::next(it); + + uEdge e(a, b); + + auto search = ecenter.find(e); + + if (search != ecenter.end()) { + points.insert(std::next(it), search->second); + ref = 1; + } + } + } while (ref); } + +void DynMesh::get_fleaves(E_Int face, std::vector &fleaves) +{ + if (face_is_active(face)) { + fleaves.push_back(face); + return; + } + + for (E_Int child : fchildren.at(face)) get_fleaves(child, fleaves); +} \ No newline at end of file diff --git a/Cassiopee/XCore/XCore/AdaptMesh/DynMesh.h b/Cassiopee/XCore/XCore/AdaptMesh/DynMesh.h index ad58e44d7..ab70713ad 100644 --- a/Cassiopee/XCore/XCore/AdaptMesh/DynMesh.h +++ b/Cassiopee/XCore/XCore/AdaptMesh/DynMesh.h @@ -3,6 +3,7 @@ #include #include #include +#include #include "xcore.h" #include "common/common.h" @@ -48,6 +49,14 @@ struct DynMesh { std::vector fref; + std::vector flevel; + + std::set factive; + + std::map> fchildren; + + std::map ecenter; + DynMesh(); DynMesh(Karray *karray); @@ -59,8 +68,6 @@ struct DynMesh { void make_face_centers(const E_Int NF, const E_Int *skin, Vec3f *fc); - void smooth_skin_ref_data(SkinGraph *skin_graph, E_Int *fdat); - bool point_in_tri(const Point *p, E_Int tid) const; bool point_in_quad(const Point *p, E_Int qid) const; @@ -75,39 +82,29 @@ struct DynMesh { void make_skin_neighbours(SkinGraph *skin_graph); + void init_adaptation_data(E_Int *tagged_faces, E_Int count); + + void init_adaptation_data(); + + void prepare_for_refinement(ArrayI *ref_faces); + + void refine_faces(ArrayI *ref_faces); inline bool face_is_quad(E_Int face) const { return F[face].size() == 4; } inline bool face_is_tri(E_Int face) const { return F[face].size() == 3; } + DynMesh extract_conformized(); + void write_ngon(const char *fname); void write_faces(const char *fname, const std::vector &faces) const; void write_face(const char *fname, E_Int fid) const; - - // Adaptation - void init_adaptation_data(); - - std::vector smooth_ref_data( - const std::map> &sensor); - - std::vector prepare_for_refinement( - const std::vector &ref_data); - - std::set factive; - std::map> fchildren; - std::vector flevel; - - std::map ecenter; - - size_t refine(const DynMesh &S); inline bool face_is_active(E_Int face) const { return factive.find(face) != factive.end(); } - void refine_faces(const std::vector &ref_faces); - void resize_point_data(size_t nref_faces); void resize_face_data(size_t nref_faces); @@ -116,20 +113,14 @@ struct DynMesh { void refine_tri(E_Int tri); - DynMesh extract_conformized(); - void get_fleaves(E_Int face, std::vector &fleaves); - PyObject *export_karray(E_Int remove_periodic = 0); - - PyObject *export_karray_orig(); + PyObject *export_karray(); - PyObject *export_karray_periodic(); + void extract_edge_points(E_Int a, E_Int b, std::list &points); /* TOPO */ - - void flag_and_get_external_faces(std::vector &fflags, std::vector &efaces); diff --git a/Cassiopee/XCore/XCore/AdaptMesh/Mesh.h b/Cassiopee/XCore/XCore/AdaptMesh/Mesh.h index df8ededdb..bb4dc3941 100644 --- a/Cassiopee/XCore/XCore/AdaptMesh/Mesh.h +++ b/Cassiopee/XCore/XCore/AdaptMesh/Mesh.h @@ -371,6 +371,11 @@ E_Int Mesh_load_balance(Mesh *M); /* Adaptation */ +void Mesh_smooth_skin_ref_data(Mesh *M, const SkinGraph *skin_graph, + E_Int *fdat); + +void Mesh_smooth_cell_refinement_data(Mesh *M); + E_Int Mesh_smooth_cref(Mesh *M); void Mesh_get_ref_entities(Mesh *M, std::vector &ref_cells, diff --git a/Cassiopee/XCore/XCore/AdaptMesh/MeshExtract.cpp b/Cassiopee/XCore/XCore/AdaptMesh/MeshExtract.cpp index b19541d1b..1ac055c52 100644 --- a/Cassiopee/XCore/XCore/AdaptMesh/MeshExtract.cpp +++ b/Cassiopee/XCore/XCore/AdaptMesh/MeshExtract.cpp @@ -61,7 +61,6 @@ void Mesh_extract_faces_from_ftag(const Mesh *M, FaceSort **mfaces, assert(*mcount == count); } -static void Mesh_extract_skin(const Mesh *M, E_Int *count, E_Int **skin) { *count = 0; @@ -79,7 +78,6 @@ void Mesh_extract_skin(const Mesh *M, E_Int *count, E_Int **skin) } } -static void Mesh_make_skin_connectivity(const Mesh *M, SkinGraph *skin_graph) { // Count diff --git a/Cassiopee/XCore/XCore/AdaptMesh/MeshSmooth.cpp b/Cassiopee/XCore/XCore/AdaptMesh/MeshSmooth.cpp index 1f1d7fb93..5b9d6bf19 100644 --- a/Cassiopee/XCore/XCore/AdaptMesh/MeshSmooth.cpp +++ b/Cassiopee/XCore/XCore/AdaptMesh/MeshSmooth.cpp @@ -136,3 +136,35 @@ E_Int Mesh_smooth_cref(Mesh *M) return 0; } + +// TODO(Imad): exactly the same as Mesh_smooth_cref... +void Mesh_smooth_cell_refinement_data(Mesh *M) +{ + E_Int nc = M->nc; + + std::stack stk; + + for (E_Int cid = 0; cid < nc; cid++) { + if (M->cref[cid] > 0) + stk.push(cid); + } + + while (!stk.empty()) { + E_Int cid = stk.top(); + stk.pop(); + + E_Int nn, neis[24]; + Mesh_get_cneis(M, cid, nn, neis); + + for (E_Int i = 0; i < nn; i++) { + E_Int nei = neis[i]; + E_Int incr_nei = M->cref[nei] + M->clevel[nei]; + E_Int incr_cid = M->cref[cid] + M->clevel[cid]; + E_Int diff = abs(incr_nei - incr_cid); + if (diff <= 1) continue; + E_Int idx_to_modify = incr_cid > incr_nei ? nei : cid; + M->cref[idx_to_modify] += diff-1; + stk.push(idx_to_modify); + } + } +} diff --git a/Cassiopee/XCore/XCore/AdaptMesh/Skin.cpp b/Cassiopee/XCore/XCore/AdaptMesh/Skin.cpp index e7f0c4d7e..d263f569f 100644 --- a/Cassiopee/XCore/XCore/AdaptMesh/Skin.cpp +++ b/Cassiopee/XCore/XCore/AdaptMesh/Skin.cpp @@ -1,5 +1,9 @@ #include "Skin.h" #include "common/mem.h" +#include "Mesh.h" +#include "DynMesh.h" + +#include void SkinGraph_free(SkinGraph *skin_graph) { @@ -73,8 +77,8 @@ void SkinGraph_make_skin_neighbours(SkinGraph *skin_graph) const E_Int *fpts = skin_graph->fpts; skin_graph->fnei = (E_Int *)XMALLOC(xadj[nf] * sizeof(E_Int)); - E_Int *fnei = skin_graph->fnei; - memset(fnei, -1, xadj[nf] * sizeof(E_Int)); + memset(skin_graph->fnei, -1, xadj[nf] * sizeof(E_Int)); + E_Int *fnei = skin_graph->fnei; EdgeNode **ht = (EdgeNode **)XMALLOC(nf * sizeof(EdgeNode *)); memset(ht, 0, nf * sizeof(EdgeNode *)); @@ -105,14 +109,88 @@ void SkinGraph_make_skin_neighbours(SkinGraph *skin_graph) EdgeNode *node = ht[i]; while (node) { E_Int pi = xadj[node->i] + node->posi; - assert(fnei[pi] == -1); + //assert(fnei[pi] == -1); fnei[pi] = node->j; E_Int pj = xadj[node->j] + node->posj; - assert(fnei[pj] == -1); + //assert(fnei[pj] == -1); fnei[pj] = node->i; node = node->next; } } +} + +void SkinGraph_smooth_ref_data(const SkinGraph *skin_graph, E_Int *fdat, + const Mesh *M) +{ + E_Int nf = skin_graph->nf; + + std::stack stk; + + for (E_Int i = 0; i < nf; i++) { + if (fdat[i] > 0) + stk.push(i); + } + + const E_Int *xadj = skin_graph->xadj; + const E_Int *fnei = skin_graph->fnei; + + while (!stk.empty()) { + + E_Int fid = stk.top(); + stk.pop(); + + E_Int start = xadj[fid]; + E_Int nneis = xadj[fid+1] - start; + const E_Int *neis = &fnei[start]; + + for (E_Int i = 0; i < nneis; i++) { + E_Int nei = neis[i]; + E_Int incr_nei = fdat[nei] + M->flevel[skin_graph->skin[nei]]; + E_Int incr_fid = fdat[fid] + M->flevel[skin_graph->skin[fid]]; + E_Int diff = abs(incr_nei - incr_fid); + if (diff <= 1) continue; + E_Int idx_to_modify = incr_fid > incr_nei ? nei : fid; + fdat[idx_to_modify] += diff-1; + stk.push(idx_to_modify); + } + } +} + +void SkinGraph_smooth_ref_data(const SkinGraph *skin_graph, E_Int *fdat, + const DynMesh *M) +{ + E_Int nf = skin_graph->nf; + + std::stack stk; + + for (E_Int i = 0; i < nf; i++) { + if (fdat[i] > 0) + stk.push(i); + } + + const E_Int *xadj = skin_graph->xadj; + const E_Int *fnei = skin_graph->fnei; + + while (!stk.empty()) { + + E_Int fid = stk.top(); + stk.pop(); + + E_Int start = xadj[fid]; + E_Int nneis = xadj[fid+1] - start; + const E_Int *neis = &fnei[start]; + + for (E_Int i = 0; i < nneis; i++) { + E_Int nei = neis[i]; + E_Int incr_nei = fdat[nei] + M->flevel[skin_graph->skin[nei]]; + E_Int incr_fid = fdat[fid] + M->flevel[skin_graph->skin[fid]]; + E_Int diff = abs(incr_nei - incr_fid); + if (diff <= 1) continue; + E_Int idx_to_modify = incr_fid > incr_nei ? nei : fid; + fdat[idx_to_modify] += diff-1; + stk.push(idx_to_modify); + } + } } \ No newline at end of file diff --git a/Cassiopee/XCore/XCore/AdaptMesh/Skin.h b/Cassiopee/XCore/XCore/AdaptMesh/Skin.h index 6f89d1d31..a6b6661ea 100644 --- a/Cassiopee/XCore/XCore/AdaptMesh/Skin.h +++ b/Cassiopee/XCore/XCore/AdaptMesh/Skin.h @@ -3,6 +3,9 @@ #include "xcore.h" #include "Vec.h" +struct Mesh; +struct DynMesh; + struct SkinGraph { E_Int nf; E_Int *skin; @@ -15,3 +18,9 @@ struct SkinGraph { void SkinGraph_free(SkinGraph *skin_graph); void SkinGraph_make_skin_neighbours(SkinGraph *skin_graph); + +void SkinGraph_smooth_ref_data(const SkinGraph *skin_graph, + E_Int *fdat, const Mesh *M); + +void SkinGraph_smooth_ref_data(const SkinGraph *skin_graph, + E_Int *fdat, const DynMesh *M); \ No newline at end of file diff --git a/Cassiopee/XCore/XCore/PyTree.py b/Cassiopee/XCore/XCore/PyTree.py index 4f0500b3f..fa1fec6a9 100644 --- a/Cassiopee/XCore/XCore/PyTree.py +++ b/Cassiopee/XCore/XCore/PyTree.py @@ -106,7 +106,13 @@ def AdaptMesh_AdaptGeom(AM, slave, tagged_faces): keep = I.getNodeFromName(zs, 'keep') - return xcore.AdaptMesh_AdaptGeom(AM, s, tagged_faces) + s = xcore.AdaptMesh_AdaptGeom(AM, s, tagged_faces) + + zso = I.createZoneNode("S_adapted", s) + + ts = C.newPyTree(["S_adapted", zso]) + + return ts ''' s, spatch = xcore.AdaptMesh_AdaptGeom(AM, s, tagged_faces) diff --git a/Cassiopee/XCore/XCore/intersectMesh/meshExport.cpp b/Cassiopee/XCore/XCore/intersectMesh/meshExport.cpp index 2fba147e7..0eb373a5f 100644 --- a/Cassiopee/XCore/XCore/intersectMesh/meshExport.cpp +++ b/Cassiopee/XCore/XCore/intersectMesh/meshExport.cpp @@ -47,7 +47,6 @@ PyObject *IMesh::export_karray_periodic() for (const auto &fdat : new_fids) { E_Int ofid = fdat.first; - E_Int nfid = fdat.second; const auto &pn = F[ofid]; diff --git a/Cassiopee/XCore/XCore/intersectMesh/smesh.cpp b/Cassiopee/XCore/XCore/intersectMesh/smesh.cpp index 85d7ea10d..71b2b88a2 100644 --- a/Cassiopee/XCore/XCore/intersectMesh/smesh.cpp +++ b/Cassiopee/XCore/XCore/intersectMesh/smesh.cpp @@ -80,8 +80,8 @@ Smesh::Smesh(const IMesh &M) nf++; } - assert(np == g2lp.size()); - assert(np == l2gp.size()); + assert((size_t)np == g2lp.size()); + assert((size_t)np == l2gp.size()); // Get the points //np = g2lp.size(); @@ -140,7 +140,7 @@ void Smesh::make_edges() } } - assert(ne == E.size()); + assert((size_t)ne == E.size()); // Make edge_to_face E2F.resize(ne, {-1,-1}); From 65f6a9a0f1c3631033f593bd8373ffc448db3f04 Mon Sep 17 00:00:00 2001 From: imadhammani Date: Thu, 26 Sep 2024 19:29:55 +0200 Subject: [PATCH 18/86] XCore AdaptMesh: updated test script --- Cassiopee/XCore/XCore/AdaptMesh/test.py | 22 ++++++++++++++-------- 1 file changed, 14 insertions(+), 8 deletions(-) diff --git a/Cassiopee/XCore/XCore/AdaptMesh/test.py b/Cassiopee/XCore/XCore/AdaptMesh/test.py index 0c65abca5..bd6ba7dcc 100644 --- a/Cassiopee/XCore/XCore/AdaptMesh/test.py +++ b/Cassiopee/XCore/XCore/AdaptMesh/test.py @@ -69,19 +69,25 @@ zp = I.getZones(sp)[0] zp1 = I.getZones(sp1)[0] sp = T.merge([zp, zp1]) -C.convertPyTree2File(sp, "sp.cgns") sfaces = X.extractFacesFromPointTag(sp, "tag") +print(len(sfaces)) +cont = I.createUniqueChild(I.getZones(sp)[0], 'ZoneBC', 'ZoneBC_t') +I.newBC(name='CONTACT', pointList=sfaces[:]+1, btype='BCWall', parent=cont) +C.convertPyTree2File(sp, "sp.cgns") + # AdaptGeom AM = X.AdaptMesh_Init(mm) -sfaces = X.AdaptMesh_AdaptGeom(AM, sp, sfaces) -cont = I.createUniqueChild(I.getZones(sp)[0], 'ZoneBC', 'ZoneBC_t') -I.newBC(name='CONTACT', pointList=sfaces, btype='BCWall', parent=cont) -C.convertPyTree2File(sp, "sp.cgns") +#sfaces = X.AdaptMesh_AdaptGeom(AM, sp, sfaces) +#cont = I.createUniqueChild(I.getZones(sp)[0], 'ZoneBC', 'ZoneBC_t') +#I.newBC(name='CONTACT', pointList=sfaces, btype='BCWall', parent=cont) +sa = X.AdaptMesh_AdaptGeom(AM, sp, sfaces) +C.convertPyTree2File(sa, "sa.cgns") -mp = X.AdaptMesh_ExtractMesh(AM) -C.convertPyTree2File(mp, "mp.cgns") +ma = X.AdaptMesh_ExtractMesh(AM) +C.convertPyTree2File(ma, "ma.cgns") -#C.convertPyTree2File(si, "si.cgns") +X.IntersectMesh_Exit(IM) +X.AdaptMesh_Exit(AM) From 415df951b8fc34ff651ca20107f4e07d04c2123e Mon Sep 17 00:00:00 2001 From: Imad Date: Sat, 28 Sep 2024 21:47:20 +0200 Subject: [PATCH 19/86] XCore AdaptMesh: one iteration of triangle skin refinement --- .../XCore/AdaptMesh/AdaptMesh_AdaptGeom.cpp | 62 +-- Cassiopee/XCore/XCore/AdaptMesh/DynMesh.cpp | 505 ++++++++++++------ Cassiopee/XCore/XCore/AdaptMesh/DynMesh.h | 28 +- .../XCore/XCore/AdaptMesh/DynMeshTopo.cpp | 6 +- .../XCore/XCore/AdaptMesh/MeshReorder.cpp | 7 + Cassiopee/XCore/XCore/AdaptMesh/Skin.cpp | 151 ++---- Cassiopee/XCore/XCore/AdaptMesh/Skin.h | 3 - Cassiopee/XCore/XCore/AdaptMesh/TriGraph.cpp | 10 + Cassiopee/XCore/XCore/AdaptMesh/TriGraph.h | 18 + Cassiopee/XCore/srcs.py | 1 + 10 files changed, 461 insertions(+), 330 deletions(-) create mode 100644 Cassiopee/XCore/XCore/AdaptMesh/MeshReorder.cpp create mode 100644 Cassiopee/XCore/XCore/AdaptMesh/TriGraph.cpp create mode 100644 Cassiopee/XCore/XCore/AdaptMesh/TriGraph.h diff --git a/Cassiopee/XCore/XCore/AdaptMesh/AdaptMesh_AdaptGeom.cpp b/Cassiopee/XCore/XCore/AdaptMesh/AdaptMesh_AdaptGeom.cpp index 54d39903b..fbf9d9596 100644 --- a/Cassiopee/XCore/XCore/AdaptMesh/AdaptMesh_AdaptGeom.cpp +++ b/Cassiopee/XCore/XCore/AdaptMesh/AdaptMesh_AdaptGeom.cpp @@ -499,8 +499,11 @@ PyObject *K_XCORE::AdaptMesh_AdaptGeom(PyObject *self, PyObject *args) for (E_Int i = 0; i < tag_size; i++) { S.ftag[tagged_faces[i]] = 1; } - //S.init_adaptation_data(tagged_faces, tag_size); - S.init_adaptation_data(); + + S.triangulate(tagged_faces, tag_size); + + //S = S.extract_conformized(); + //return S.export_karray(); // Refine M volumetric wrt to S tagged faces point cloud // Refine S surfacic wrt to M tagged faces point cloud @@ -788,17 +791,16 @@ PyObject *K_XCORE::AdaptMesh_AdaptGeom(PyObject *self, PyObject *args) */ // We need the skin connectivity graph - skin_graph = {0}; - S.make_skin_graph(&skin_graph); - printf("Skin: %d faces\n", skin_graph.nf); + S.make_tri_graph(); + printf("Skin: %lu faces\n", S.tri_graph.nf); // BVH the skin - skin_fc = (Vec3f *)XCALLOC(skin_graph.nf, sizeof(Vec3f)); - S.make_face_centers(skin_graph.nf, skin_graph.skin, skin_fc); - indices = (E_Int *)XMALLOC(skin_graph.nf * sizeof(E_Int)); - for (E_Int i = 0; i < skin_graph.nf; i++) indices[i] = i; - bvh = BVH_make(&S, skin_graph.skin, skin_fc, indices, 0, - skin_graph.nf, &huge); + skin_fc = (Vec3f *)XCALLOC(S.tri_graph.nf, sizeof(Vec3f)); + S.make_face_centers(S.tri_graph.nf, S.tri_graph.skin.data(), skin_fc); + indices = (E_Int *)XMALLOC(S.tri_graph.nf * sizeof(E_Int)); + for (size_t i = 0; i < S.tri_graph.nf; i++) indices[i] = i; + bvh = BVH_make(&S, S.tri_graph.skin.data(), skin_fc, indices, 0, + S.tri_graph.nf, &huge); puts("BVH constructed"); // Locate mpoints in skin @@ -807,7 +809,7 @@ PyObject *K_XCORE::AdaptMesh_AdaptGeom(PyObject *self, PyObject *args) locate_points_in_skin ( M, &mpoints, - &S, skin_graph.skin, indices, + &S, S.tri_graph.skin.data(), indices, bvh, mploc ); @@ -817,7 +819,7 @@ PyObject *K_XCORE::AdaptMesh_AdaptGeom(PyObject *self, PyObject *args) PointFaces_extract_by_threshold ( mploc, mpoints.count, - skin_graph.skin, skin_graph.nf, + S.tri_graph.skin.data(), S.tri_graph.nf, 1, // threshold &rfaces ); @@ -849,44 +851,33 @@ PyObject *K_XCORE::AdaptMesh_AdaptGeom(PyObject *self, PyObject *args) if (rfaces.count > 0) { // Smooth face refinement data - E_Int *fdat = (E_Int *)XMALLOC(skin_graph.nf * sizeof(E_Int)); - memset(fdat, 0, skin_graph.nf * sizeof(E_Int)); + S.tri_graph.fdat.clear(); + S.tri_graph.fdat.resize(S.tri_graph.nf, 0); for (E_Int i = 0; i < rfaces.count; i++) { E_Int idx_in_skin = indices[rfaces.ptr[i]]; - fdat[idx_in_skin] = 1; + S.tri_graph.fdat[idx_in_skin] = 1; } - SkinGraph_smooth_ref_data(&skin_graph, fdat, &S); - puts("Face refinement smoothed out"); - // Assign refinement data - S.fref.resize(S.nf, 0); - - E_Int smooth_nfref = 0; - for (E_Int i = 0; i < skin_graph.nf; i++) { - if (fdat[i] > 0) { - E_Int fid = skin_graph.skin[i]; - assert(S.face_is_active(fid)); - S.fref[fid] = 1; - smooth_nfref++; - } - } - printf("Smooth refinement face count: %d\n", smooth_nfref); - // Isolate refinement faces ArrayI ref_faces; S.prepare_for_refinement(&ref_faces); printf("Refinement faces: %d\n", ref_faces.count); - assert(ref_faces.count == smooth_nfref); // Refine S.refine_faces(&ref_faces); - XFREE(fdat); + // Make sure to copy ftag data + S = S.extract_conformized(); + + return S.export_karray(); + ArrayI_free(&ref_faces); } // FREE - + S.tri_graph.clear(); + S.fchildren.clear(); + S.ecenter.clear(); BVH_free(bvh); ArrayI_free(&rfaces); ArrayI_free(&mpoints); @@ -897,7 +888,6 @@ PyObject *K_XCORE::AdaptMesh_AdaptGeom(PyObject *self, PyObject *args) } while (iter < max_iter && (ref_count_M > 0 || ref_count_S > 0)); - S = S.extract_conformized(); PyObject *Sout = S.export_karray(); diff --git a/Cassiopee/XCore/XCore/AdaptMesh/DynMesh.cpp b/Cassiopee/XCore/XCore/AdaptMesh/DynMesh.cpp index d8c3c365d..978a5c898 100644 --- a/Cassiopee/XCore/XCore/AdaptMesh/DynMesh.cpp +++ b/Cassiopee/XCore/XCore/AdaptMesh/DynMesh.cpp @@ -63,7 +63,7 @@ void DynMesh::extract_points_from_ftag(ArrayI *pids) memset(ptag, 0, np * sizeof(E_Int)); pids->count = 0; - for (E_Int fid : factive) { + for (E_Int fid = 0; fid < nf; fid++) { if (ftag[fid] != 1) continue; const auto &pn = F[fid]; @@ -84,23 +84,6 @@ void DynMesh::extract_points_from_ftag(ArrayI *pids) XFREE(ptag); } -void DynMesh::extract_skin(E_Int *count, E_Int **skin) -{ - *count = 0; - - for (E_Int fid : factive) { - *count += (neigh[fid] == -1); - } - - *skin = (E_Int *)XMALLOC(*count * sizeof(E_Int)); - E_Int *ptr = *skin; - - for (E_Int fid : factive) { - if (neigh[fid] == -1) - *ptr++ = fid; - } -} - void DynMesh::make_skin_connectivity(SkinGraph *skin_graph) { // Count @@ -131,21 +114,14 @@ void DynMesh::make_skin_connectivity(SkinGraph *skin_graph) assert(ptr - skin_graph->fpts == xadj[skin_graph->nf]); } -void DynMesh::make_skin_graph(SkinGraph *skin_graph) -{ - extract_skin(&skin_graph->nf, &skin_graph->skin); - make_skin_connectivity(skin_graph); - SkinGraph_make_skin_neighbours(skin_graph); -} - void DynMesh::make_face_centers(const E_Int NF, const E_Int *skin, Vec3f *fc) { for (E_Int i = 0; i < NF; i++) { fc[i].x = fc[i].y = fc[i].z = 0.0; E_Int fid = skin[i]; - assert(face_is_active(fid)); const auto &pn = F[fid]; + assert(ftag[skin[i]] == 1); for (E_Int p : pn) { fc[i].x += X[p]; fc[i].y += Y[p]; @@ -216,39 +192,20 @@ bool DynMesh::point_in_face(const Point *p, E_Int fid) const return point_in_tri(p, fid); } -void DynMesh::init_adaptation_data(E_Int *tagged_faces, E_Int count) -{ - flevel.resize(nf, 0); - - for (E_Int i = 0; i < count; i++) factive.insert(tagged_faces[i]); -} - -void DynMesh::init_adaptation_data() -{ - flevel.resize(nf, 0); - - for (E_Int i = 0; i < nf; i++) factive.insert(i); -} - void DynMesh::prepare_for_refinement(ArrayI *ref_faces) { ref_faces->count = 0; - for (E_Int fid : factive) { - ref_faces->count += (fref[fid] == 1); + for (size_t i = 0; i < tri_graph.nf; i++) { + ref_faces->count += (tri_graph.fdat[i] == 1); } ref_faces->ptr = (E_Int *)XMALLOC(ref_faces->count * sizeof(E_Int)); E_Int *ptr = ref_faces->ptr; - for (E_Int fid = 0; fid < nf; fid++) { - if (fref[fid] > 0) { - assert(fref[fid] == 1); - *ptr++ = fid; + for (size_t i = 0; i < tri_graph.nf; i++) { + if (tri_graph.fdat[i] == 1) { + *ptr++ = i; } } - // Refine the lower-level faces first - std::sort(ref_faces->ptr, ref_faces->ptr + ref_faces->count, - [&] (E_Int i, E_Int j) { return flevel[i] < flevel[j]; }); - // Resize data structures resize_point_data(ref_faces->count); resize_face_data(ref_faces->count); @@ -256,16 +213,24 @@ void DynMesh::prepare_for_refinement(ArrayI *ref_faces) void DynMesh::refine_faces(ArrayI *ref_faces) { + tri_graph.T.resize(tri_graph.nf + ref_faces->count*4, {-1, -1, -1}); + tri_graph.E.resize(tri_graph.nf + ref_faces->count*4, {-1, -1, -1}); + tri_graph.skin.resize(tri_graph.nf + ref_faces->count*4, -1); + tri_graph.level.resize(tri_graph.nf + ref_faces->count*4, 0); + + printf("Faces before refinement: %d\n", nf); + for (E_Int i = 0; i < ref_faces->count; i++) { E_Int fid = ref_faces->ptr[i]; - if (face_is_tri(fid)) refine_tri(fid); - else refine_quad(fid); + assert(tri_graph.level[fid] == 0); + assert(face_is_tri(tri_graph.skin[fid])); + refine_tri(fid); } } void DynMesh::resize_point_data(size_t nref_faces) { - size_t nnew_points = np + nref_faces * 5; + size_t nnew_points = np + nref_faces * 3; X.resize(nnew_points); Y.resize(nnew_points); Z.resize(nnew_points); @@ -273,20 +238,35 @@ void DynMesh::resize_point_data(size_t nref_faces) void DynMesh::resize_face_data(size_t nref_faces) { - size_t nnew_faces = nf + nref_faces * 4; + size_t nnew_faces = nf + nref_faces * 4; // 3 new triangles + 1 potential neighbor triangle F.resize(nnew_faces); - flevel.resize(nnew_faces, -1); owner.resize(nnew_faces); neigh.resize(nnew_faces); ftag.resize(nnew_faces, 0); } -void DynMesh::refine_tri(E_Int tri) +E_Int DynMesh::get_edge_index(E_Int nei, E_Int tri) { + for (E_Int i = 0; i < 3; i++) { + if (tri_graph.E[nei][i] == tri) + return i; + } + return -1; +} + +void DynMesh::refine_tri(E_Int tri_idx) +{ + assert(tri_graph.level[tri_idx] == 0); + puts("refining"); + fflush(stdout); + E_Int tri = tri_graph.skin[tri_idx]; + // Refine the edges const auto &pn = F[tri]; E_Int ec[3]; + assert(pn.size() == 3); + for (size_t i = 0; i < pn.size(); i++) { E_Int p = pn[i]; E_Int q = pn[(i+1)%pn.size()]; @@ -305,98 +285,208 @@ void DynMesh::refine_tri(E_Int tri) ec[i] = it->second; } } + + E_Int vn[3] = {pn[0], pn[1], pn[2]}; - // New face points - E_Int nf0 = nf, nf1 = nf+1, nf2 = nf+2, nf3 = nf+3; + // Create new triangles + F[tri] = {vn[0], ec[0], ec[2]}; + F[nf] = {ec[0], vn[1], ec[1]}; + F[nf+1] = {ec[2], ec[1], vn[2]}; + F[nf+2] = {ec[0], ec[1], ec[2]}; - F[nf0] = { pn[0], ec[0], ec[2] }; - F[nf1] = { ec[0], pn[1], ec[1] }; - F[nf2] = { ec[2], ec[1], pn[2] }; - F[nf3] = { ec[0], ec[1], ec[2] }; + fchildren[tri] = {nf, nf+1, nf+2}; + ftag[nf] = ftag[nf+1] = ftag[nf+2] = ftag[tri]; - // Disable quad and enable its children - factive.erase(tri); - factive.insert(nf0); - factive.insert(nf1); - factive.insert(nf2); - factive.insert(nf3); + // Update owners and neighbours + neigh[nf] = neigh[nf+1] = neigh[nf+2] = neigh[tri]; + owner[nf] = owner[nf+1] = owner[nf+2] = owner[tri]; - // Set quad children pointers - fchildren[tri] = { nf0, nf1, nf2, nf3 }; - flevel[nf0] = flevel[nf1] = flevel[nf2] = flevel[nf3] = flevel[tri] + 1; + // Skin - ftag[nf0] = ftag[nf1] = ftag[nf2] = ftag[nf3] = ftag[tri]; + // Add the new triangles + size_t NF = tri_graph.nf; + + auto &T = tri_graph.T; + auto &E = tri_graph.E; + + T[tri_idx][0] = vn[0]; T[tri_idx][1] = ec[0]; T[tri_idx][2] = ec[2]; + assert(T[tri_idx][0] != T[tri_idx][1]); + assert(T[tri_idx][0] != T[tri_idx][2]); + assert(T[tri_idx][1] != T[tri_idx][2]); + + T[NF][0] = ec[0]; T[NF][1] = vn[1]; T[NF][2] = ec[1]; + T[NF+1][0] = ec[2]; T[NF+1][1] = ec[1]; T[NF+1][2] = vn[2]; + T[NF+2][0] = ec[0]; T[NF+2][1] = ec[1]; T[NF+2][2] = ec[2]; + + E_Int N0 = NF; + E_Int N1 = NF+1; + E_Int N2 = NF+2; - neigh[nf0] = neigh[nf1] = neigh[nf2] = neigh[nf3] = neigh[tri]; - owner[nf0] = owner[nf1] = owner[nf2] = owner[nf3] = owner[tri]; + E_Int A = tri_graph.E[tri_idx][0]; + E_Int B = tri_graph.E[tri_idx][1]; + E_Int C = tri_graph.E[tri_idx][2]; + + E[tri_idx][0] = A; E[tri_idx][1] = N2; E[tri_idx][2] = C; + E[N0][0] = A; E[N0][1] = B; E[N0][2] = N2; + E[N1][0] = N2; E[N1][1] = B; E[N1][2] = C; + E[N2][0] = N0; E[N2][1] = N1; E[N2][2] = tri_idx; + + tri_graph.skin[NF] = nf; + tri_graph.skin[NF+1] = nf+1; + tri_graph.skin[NF+2] = nf+2; + + tri_graph.level[tri_idx]++; + assert(tri_graph.level[tri_idx] == 1); + tri_graph.level[NF] = tri_graph.level[NF+1] = tri_graph.level[NF+2] = 1; + + // Increment face count + nf += 3; + tri_graph.nf += 3; - nf += 4; -} + NF = tri_graph.nf; -void DynMesh::refine_quad(E_Int quad) -{ - // Refine the edges - const auto &pn = F[quad]; - E_Int ec[4]; + bool cut_A = (A != -1) && (tri_graph.level[A] == 0 && tri_graph.fdat[A] == 0); + + if (cut_A) { + E_Int edge_idx = get_edge_index(A, tri_idx); + assert(edge_idx != -1); + E_Int P = T[A][(edge_idx+2)%3]; - for (size_t i = 0; i < pn.size(); i++) { - E_Int p = pn[i]; - E_Int q = pn[(i+1)%pn.size()]; - uEdge edge(p, q); + E_Int D = E[A][(edge_idx+1)%3]; + E_Int e = E[A][(edge_idx+2)%3]; - auto it = ecenter.find(edge); + // A points and neighbours + T[A][0] = ec[0]; T[A][1] = vn[0]; T[A][2] = P; - if (it == ecenter.end()) { - X[np] = 0.5 * (X[p] + X[q]); - Y[np] = 0.5 * (Y[p] + Y[q]); - Z[np] = 0.5 * (Z[p] + Z[q]); - ecenter[edge] = np; - ec[i] = np; - np++; - } else { - ec[i] = it->second; + // NF points and neighbours + T[NF][0] = ec[0]; T[NF][1] = P; T[NF][2] = vn[1]; + + // e neighbours (if it exists) + if (e != -1) { + E_Int idx = get_edge_index(e, A); + E[e][idx] = NF; } + + E[A][0] = tri_idx; E[A][1] = D; E[A][2] = NF; + E[NF][0] = A; E[NF][1] = e; E[NF][2] = N0; + + // N0 neighbours + E[N0][0] = NF;// E[N1][0] = B; E[N1][1] = N2; + + tri_graph.skin[NF] = nf; + + assert(tri_graph.level[A] == 0); + assert(tri_graph.level[NF] == 0); + + NF += 1; + + // Global stuff + E_Int gA = tri_graph.skin[A]; + F[gA] = {ec[0], vn[0], P}; + fchildren[gA].push_back(nf); + + F[nf] = {ec[0], P, vn[1]}; + ftag[nf] = ftag[gA]; + owner[nf] = owner[gA]; + neigh[nf] = neigh[gA]; + + nf += 1; } - // Face centroid + bool cut_B = (B != -1) && (tri_graph.level[B] == 0 && tri_graph.fdat[B] == 0); + + if (cut_B) { + E_Int edge_idx = get_edge_index(B, tri_idx); + assert(edge_idx != -1); + E_Int P = T[B][(edge_idx+2)%3]; + + E_Int f = E[B][(edge_idx+1)%3]; + E_Int G = E[B][(edge_idx+2)%3]; - X[np] = Y[np] = Z[np] = 0.0; - for (E_Int i = 0; i < 4; i++) { - E_Int p = pn[i]; - X[np] += X[p]; - Y[np] += Y[p]; - Z[np] += Z[p]; + // B points and neighbours + T[B][0] = ec[1]; T[B][1] = vn[1]; T[B][2] = P; + + // NF points and neighbours + T[NF][0] = ec[1]; T[NF][1] = P; T[NF][2] = vn[2]; + + // G neighbours (if it exists) + if (G != -1) { + E_Int idx = get_edge_index(G, B); + E[G][idx] = NF; + } + + E[B][0] = N0; E[B][1] = f; E[B][2] = NF; + E[NF][0] = B; E[NF][1] = G; E[NF][2] = N1; + + // N1 neighbours + E[N1][1] = NF; + + assert(tri_graph.level[B] == 0); + assert(tri_graph.level[NF] == 0); + + tri_graph.skin[NF] = nf; + NF += 1; + + // Global stuff + E_Int gB = tri_graph.skin[B]; + F[gB] = {ec[1], vn[1], P}; + fchildren[gB].push_back(nf); + + F[nf] = {ec[1], P, vn[2]}; + ftag[nf] = ftag[gB]; + owner[nf] = owner[gB]; + neigh[nf] = neigh[gB]; + + nf += 1; } - X[np] *= 0.25; - Y[np] *= 0.25; - Z[np] *= 0.25; - // New face points - E_Int nf0 = nf, nf1 = nf+1, nf2 = nf+2, nf3 = nf+3; + bool cut_C = (C != -1) && (tri_graph.level[C] == 0 && tri_graph.fdat[C] == 0); + + if (cut_C) { + E_Int edge_idx = get_edge_index(C, tri_idx); + assert(edge_idx != -1); + E_Int P = T[C][(edge_idx+2)%3]; - F[nf0] = { pn[0], ec[0], np, ec[3] }; - F[nf1] = { ec[0], pn[1], ec[1], np }; - F[nf2] = { np , ec[1], pn[2], ec[2] }; - F[nf3] = { ec[3], np , ec[2], pn[3] }; + E_Int I = E[C][(edge_idx+1)%3]; + E_Int H = E[C][(edge_idx+2)%3]; + + // C points and neighbours + T[C][0] = ec[2]; T[C][1] = P; T[C][2] = vn[0]; - // Disable quad and enable its children - factive.erase(quad); - factive.insert(nf0); - factive.insert(nf1); - factive.insert(nf2); - factive.insert(nf3); + // NF points and neighbours + T[NF][0] = ec[2]; T[NF][1] = vn[2]; T[NF][2] = P; + + // I neighbours (if it exists) + if (I != -1) { + E_Int idx = get_edge_index(I, C); + E[I][idx] = NF; + } - // Set quad children pointers - fchildren[quad] = { nf0, nf1, nf2, nf3 }; - flevel[nf0] = flevel[nf1] = flevel[nf2] = flevel[nf3] = flevel[quad] + 1; + E[C][0] = NF; E[C][1] = H; E[C][2] = tri_idx; + E[NF][0] = N1; E[NF][1] = I; E[NF][2] = C; + - ftag[nf0] = ftag[nf1] = ftag[nf2] = ftag[nf3] = ftag[quad]; + // N1 adjacency + E[N1][2] = NF; + + assert(tri_graph.level[C] == 0); + assert(tri_graph.level[NF] == 0); + + tri_graph.skin[NF] = nf; + NF += 1; + + // Global stuff + E_Int gC = tri_graph.skin[C]; + F[gC] = {ec[2], vn[2], P}; + fchildren[gC].push_back(nf); - neigh[nf0] = neigh[nf1] = neigh[nf2] = neigh[nf3] = neigh[quad]; - owner[nf0] = owner[nf1] = owner[nf2] = owner[nf3] = owner[quad]; + F[nf] = {ec[2], P, vn[0]}; + ftag[nf] = ftag[gC]; + owner[nf] = owner[gC]; + neigh[nf] = neigh[gC]; - np += 1; - nf += 4; + nf += 1; + } } DynMesh DynMesh::extract_conformized() @@ -406,18 +496,13 @@ DynMesh DynMesh::extract_conformized() // Conformize the faces - std::vector> new_F(factive.size()); - - E_Int new_nf = 0; - - std::map new_fids; + std::vector> new_F(nf); - for (E_Int face : factive) { - new_fids[face] = new_nf; + for (E_Int fid = 0; fid < nf; fid++) { - const auto &pn = F[face]; + const auto &pn = F[fid]; - auto &new_face = new_F[new_nf]; + auto &new_face = new_F[fid]; for (size_t j = 0; j < pn.size(); j++) { E_Int p = pn[j]; @@ -432,8 +517,6 @@ DynMesh DynMesh::extract_conformized() for (auto it = epoints.begin(); it != epoints.end(); it++) new_face.push_back(*it); } - - new_nf++; } // Update cell connectivity @@ -445,16 +528,16 @@ DynMesh DynMesh::extract_conformized() auto &new_cell = new_C[i]; - for (E_Int face : pf) { + for (E_Int fid : pf) { + auto it = fchildren.find(fid); - if (face_is_active(face)) { - new_cell.push_back(new_fids[face]); + if (it == fchildren.end()) { + new_cell.push_back(fid); } else { std::vector fleaves; - get_fleaves(face, fleaves); - - for (E_Int fleaf : fleaves) - new_cell.push_back(new_fids[fleaf]); + get_fleaves(fid, fleaves); + for (E_Int leaf : fleaves) + new_cell.push_back(leaf); } } } @@ -464,18 +547,30 @@ DynMesh DynMesh::extract_conformized() new_M.X = X; new_M.Y = Y; new_M.Z = Z; - new_M.nf = new_nf; + new_M.nf = nf; new_M.F = new_F; new_M.nc = nc; new_M.C = new_C; + new_M.ftag = ftag; - for (E_Int face : factive) { - new_M.factive.insert(new_fids[face]); - } return new_M; } +void DynMesh::get_fleaves(E_Int face, std::vector &fleaves) +{ + fleaves.push_back(face); + + const auto it = fchildren.find(face); + + if (it == fchildren.end()) { + return; + } + + for (E_Int child : it->second) + get_fleaves(child, fleaves); +} + PyObject *DynMesh::export_karray() { E_Int sizeNGon = 0, sizeNFace = 0; @@ -560,12 +655,116 @@ void DynMesh::extract_edge_points(E_Int a, E_Int b, std::list &points) } while (ref); } -void DynMesh::get_fleaves(E_Int face, std::vector &fleaves) +struct EdgeNode { + E_Int p, q; + E_Int fi, posi; + mutable E_Int fj, posj; + EdgeNode(E_Int p_, E_Int q_) + { + p = std::min(p_, q_); + q = std::max(p_, q_); + fi = posi = fj = posj = -1; + } + bool operator<(const EdgeNode &e) const + { + return (p < e.p) || (p == e.p && q < e.q); + } +}; + +void DynMesh::make_tri_graph() { - if (face_is_active(face)) { - fleaves.push_back(face); - return; + tri_graph.nf = 0; + + // From tagged faces + for (E_Int i = 0; i < nf; i++) { + tri_graph.nf += (ftag[i] == 1); } + tri_graph.skin.clear(); + tri_graph.skin.resize(tri_graph.nf); + E_Int *skin = tri_graph.skin.data(); + E_Int *ptr = skin; + for (E_Int i = 0; i < nf; i++) { + if (ftag[i] == 1) + *ptr++ = i; + } + + tri_graph.T.clear(); + tri_graph.E.clear(); + tri_graph.level.clear(); + + tri_graph.T.resize(tri_graph.nf, {-1, -1, -1}); + tri_graph.E.resize(tri_graph.nf, {-1, -1, -1}); + tri_graph.level.resize(tri_graph.nf, 0); + + std::set edges; - for (E_Int child : fchildren.at(face)) get_fleaves(child, fleaves); -} \ No newline at end of file + for (size_t i = 0; i < tri_graph.nf; i++) { + E_Int fid = tri_graph.skin[i]; + const auto &pn = F[fid]; + assert(pn.size() == 3); + for (size_t j = 0; j < pn.size(); j++) { + E_Int p = pn[j]; + + tri_graph.T[i][j] = p; + + E_Int q = pn[(j+1)%3]; + + EdgeNode node(p, q); + auto it = edges.find(node); + if (it == edges.end()) { + node.fi = i; + node.posi = j; + edges.insert(node); + } else { + assert(it->fi != -1); + assert(it->posi != -1); + assert(it->fj == -1); + assert(it->posj == -1); + it->fj = i; + it->posj = j; + } + } + } + + for (const auto &e : edges) { + assert(e.fi != -1); + tri_graph.E[e.fi][e.posi] = e.fj; + if (e.fj != -1) + tri_graph.E[e.fj][e.posj] = e.fi; + else + assert(e.posj == -1); + } +} + + +void DynMesh::triangulate(const E_Int *faces, E_Int fcount) +{ + F.resize(nf + fcount); + owner.resize(nf + fcount, -1); + neigh.resize(nf + fcount, -1); + ftag.resize(nf + fcount, 0); + + for (E_Int i = 0; i < fcount; i++) { + E_Int fid = faces[i]; + + auto &pn = F[fid]; + auto &tri = F[nf]; + + tri = { pn[0], pn[2], pn[3] }; + pn = { pn[0], pn[1], pn[2] }; + + auto &pown = C[owner[fid]]; + pown.push_back(nf); + + if (neigh[fid] != -1) { + auto &pnei = C[neigh[fid]]; + pnei.push_back(nf); + } + + owner[nf] = owner[fid]; + neigh[nf] = neigh[fid]; + ftag[nf] = ftag[fid]; + + nf++; + } +} diff --git a/Cassiopee/XCore/XCore/AdaptMesh/DynMesh.h b/Cassiopee/XCore/XCore/AdaptMesh/DynMesh.h index ab70713ad..d54db8a85 100644 --- a/Cassiopee/XCore/XCore/AdaptMesh/DynMesh.h +++ b/Cassiopee/XCore/XCore/AdaptMesh/DynMesh.h @@ -7,6 +7,7 @@ #include "xcore.h" #include "common/common.h" +#include "TriGraph.h" struct Karray; struct ArrayI; @@ -43,27 +44,25 @@ struct DynMesh { std::vector owner, neigh; - std::vector skin; - std::vector ftag; - std::vector fref; - - std::vector flevel; - - std::set factive; - std::map> fchildren; std::map ecenter; + TriGraph tri_graph; + DynMesh(); DynMesh(Karray *karray); + void triangulate(const E_Int *faces, E_Int fcount); + + E_Int get_edge_index(E_Int nei, E_Int tri); + void extract_points_from_ftag(ArrayI *points); - void make_skin_graph(SkinGraph *skin_graph); + void make_tri_graph(); void make_face_centers(const E_Int NF, const E_Int *skin, Vec3f *fc); @@ -82,16 +81,10 @@ struct DynMesh { void make_skin_neighbours(SkinGraph *skin_graph); - void init_adaptation_data(E_Int *tagged_faces, E_Int count); - - void init_adaptation_data(); - void prepare_for_refinement(ArrayI *ref_faces); void refine_faces(ArrayI *ref_faces); - inline bool face_is_quad(E_Int face) const { return F[face].size() == 4; } - inline bool face_is_tri(E_Int face) const { return F[face].size() == 3; } DynMesh extract_conformized(); @@ -102,15 +95,10 @@ struct DynMesh { void write_face(const char *fname, E_Int fid) const; - inline bool face_is_active(E_Int face) const - { return factive.find(face) != factive.end(); } - void resize_point_data(size_t nref_faces); void resize_face_data(size_t nref_faces); - void refine_quad(E_Int quad); - void refine_tri(E_Int tri); void get_fleaves(E_Int face, std::vector &fleaves); diff --git a/Cassiopee/XCore/XCore/AdaptMesh/DynMeshTopo.cpp b/Cassiopee/XCore/XCore/AdaptMesh/DynMeshTopo.cpp index 2964e64df..5acbf0582 100644 --- a/Cassiopee/XCore/XCore/AdaptMesh/DynMeshTopo.cpp +++ b/Cassiopee/XCore/XCore/AdaptMesh/DynMeshTopo.cpp @@ -27,10 +27,6 @@ E_Int DynMesh::orient_skin(E_Int normal_direction) E_Int nefaces = (E_Int)efaces.size(); - if (skin.size()) { - assert(efaces.size() == skin.size()); - } - for (E_Int i = 0; i < nefaces; i++) xadj[i+1] += xadj[i]; // build skin neighbourhood @@ -329,4 +325,4 @@ void DynMesh::flag_all_external_cells(const std::vector &fflags, } } } -} \ No newline at end of file +} diff --git a/Cassiopee/XCore/XCore/AdaptMesh/MeshReorder.cpp b/Cassiopee/XCore/XCore/AdaptMesh/MeshReorder.cpp new file mode 100644 index 000000000..86f14f806 --- /dev/null +++ b/Cassiopee/XCore/XCore/AdaptMesh/MeshReorder.cpp @@ -0,0 +1,7 @@ +#include "Mesh.h" + +void Mesh_reorder_hexa(Mesh *M, E_Int hexa, E_Int base) +{ + + +} diff --git a/Cassiopee/XCore/XCore/AdaptMesh/Skin.cpp b/Cassiopee/XCore/XCore/AdaptMesh/Skin.cpp index d263f569f..673f3b239 100644 --- a/Cassiopee/XCore/XCore/AdaptMesh/Skin.cpp +++ b/Cassiopee/XCore/XCore/AdaptMesh/Skin.cpp @@ -4,6 +4,7 @@ #include "DynMesh.h" #include +#include void SkinGraph_free(SkinGraph *skin_graph) { @@ -15,60 +16,25 @@ void SkinGraph_free(SkinGraph *skin_graph) } struct EdgeNode { - E_Int p, q; - E_Int i, j; - E_Int posi, posj; - EdgeNode *next; -}; - -static -EdgeNode *make_edge_node(E_Int p, E_Int q, E_Int i, E_Int posi) -{ - EdgeNode *node = (EdgeNode *)XMALLOC(sizeof(EdgeNode)); - node->p = p < q ? p : q; - node->q = p < q ? q : p; - node->i = i; - node->posi = posi; - node->j = -1; - node->posj = -1; - node->next = NULL; - return node; -} - -static -EdgeNode *find_edge_node(EdgeNode **ht, E_Int hsize, E_Int p, E_Int q) -{ - E_Int p_ = p < q ? p : q; - E_Int q_ = p < q ? q : p; - E_Int bucket = p_ % hsize; - EdgeNode *current = ht[bucket]; - - while (current) { - E_Int P = current->p, Q = current->q; - if (P == p_ && Q == q_) { - return current; - } - current = current->next; + E_Int m_p, m_q; + E_Int m_i, m_posi; + mutable E_Int m_j, m_posj; + + EdgeNode(E_Int p, E_Int q) + { + m_p = std::min(p, q); + m_q = std::max(p, q); + m_i = -1; + m_posi = -1; + m_j = -1; + m_posj = -1; } - return NULL; -} - -static -void insert_edge_node(EdgeNode *node, const E_Int hsize, EdgeNode **ht) -{ - assert(node->p < node->q); - E_Int bucket = node->p % hsize; - EdgeNode *current = ht[bucket]; - - if (current) { - EdgeNode *tmp = current; - ht[bucket] = node; - node->next = tmp; - } else { - ht[bucket] = node; + bool operator<(const EdgeNode &e) const + { + return (m_p < e.m_p) || (m_p == e.m_p && m_q < e.m_q); } -} +}; void SkinGraph_make_skin_neighbours(SkinGraph *skin_graph) { @@ -80,8 +46,7 @@ void SkinGraph_make_skin_neighbours(SkinGraph *skin_graph) memset(skin_graph->fnei, -1, xadj[nf] * sizeof(E_Int)); E_Int *fnei = skin_graph->fnei; - EdgeNode **ht = (EdgeNode **)XMALLOC(nf * sizeof(EdgeNode *)); - memset(ht, 0, nf * sizeof(EdgeNode *)); + std::set edge_set; for (E_Int i = 0; i < nf; i++) { E_Int start = xadj[i]; @@ -90,34 +55,31 @@ void SkinGraph_make_skin_neighbours(SkinGraph *skin_graph) for (E_Int j = 0; j < np; j++) { E_Int p = pn[j]; E_Int q = pn[(j+1)%np]; - EdgeNode *node = find_edge_node(ht, nf, p, q); - if (node) { - assert(node->i != -1); - assert(node->posi != -1); - assert(node->j == -1); - assert(node->posj == -1); - node->j = i; - node->posj = j; + EdgeNode e(p, q); + auto it = edge_set.find(e); + if (it != edge_set.end()) { + assert(it->m_i != -1); + assert(it->m_posi != -1); + assert(it->m_j == -1); + assert(it->m_posj == -1); + it->m_j = i; + it->m_posj = j; } else { - node = make_edge_node(p, q, i, j); - insert_edge_node(node, nf, ht); + e.m_i = i; + e.m_posi = j; + edge_set.insert(e); } } } - for (E_Int i = 0; i < nf; i++) { - EdgeNode *node = ht[i]; - while (node) { - E_Int pi = xadj[node->i] + node->posi; - //assert(fnei[pi] == -1); - fnei[pi] = node->j; - - E_Int pj = xadj[node->j] + node->posj; - //assert(fnei[pj] == -1); - fnei[pj] = node->i; - - node = node->next; - } + for (const auto &e : edge_set) { + E_Int pi = xadj[e.m_i] + e.m_posi; + assert(fnei[pi] == -1); + fnei[pi] = e.m_j; + + E_Int pj = xadj[e.m_j] + e.m_posj; + assert(fnei[pj] == -1); + fnei[pj] = e.m_i; } } @@ -157,40 +119,3 @@ void SkinGraph_smooth_ref_data(const SkinGraph *skin_graph, E_Int *fdat, } } } - -void SkinGraph_smooth_ref_data(const SkinGraph *skin_graph, E_Int *fdat, - const DynMesh *M) -{ - E_Int nf = skin_graph->nf; - - std::stack stk; - - for (E_Int i = 0; i < nf; i++) { - if (fdat[i] > 0) - stk.push(i); - } - - const E_Int *xadj = skin_graph->xadj; - const E_Int *fnei = skin_graph->fnei; - - while (!stk.empty()) { - - E_Int fid = stk.top(); - stk.pop(); - - E_Int start = xadj[fid]; - E_Int nneis = xadj[fid+1] - start; - const E_Int *neis = &fnei[start]; - - for (E_Int i = 0; i < nneis; i++) { - E_Int nei = neis[i]; - E_Int incr_nei = fdat[nei] + M->flevel[skin_graph->skin[nei]]; - E_Int incr_fid = fdat[fid] + M->flevel[skin_graph->skin[fid]]; - E_Int diff = abs(incr_nei - incr_fid); - if (diff <= 1) continue; - E_Int idx_to_modify = incr_fid > incr_nei ? nei : fid; - fdat[idx_to_modify] += diff-1; - stk.push(idx_to_modify); - } - } -} \ No newline at end of file diff --git a/Cassiopee/XCore/XCore/AdaptMesh/Skin.h b/Cassiopee/XCore/XCore/AdaptMesh/Skin.h index a6b6661ea..fddeee803 100644 --- a/Cassiopee/XCore/XCore/AdaptMesh/Skin.h +++ b/Cassiopee/XCore/XCore/AdaptMesh/Skin.h @@ -21,6 +21,3 @@ void SkinGraph_make_skin_neighbours(SkinGraph *skin_graph); void SkinGraph_smooth_ref_data(const SkinGraph *skin_graph, E_Int *fdat, const Mesh *M); - -void SkinGraph_smooth_ref_data(const SkinGraph *skin_graph, - E_Int *fdat, const DynMesh *M); \ No newline at end of file diff --git a/Cassiopee/XCore/XCore/AdaptMesh/TriGraph.cpp b/Cassiopee/XCore/XCore/AdaptMesh/TriGraph.cpp new file mode 100644 index 000000000..40dc4d730 --- /dev/null +++ b/Cassiopee/XCore/XCore/AdaptMesh/TriGraph.cpp @@ -0,0 +1,10 @@ +#include "TriGraph.h" + +void TriGraph::clear() +{ + skin.clear(); + T.clear(); + E.clear(); + fdat.clear(); + level.clear(); +} diff --git a/Cassiopee/XCore/XCore/AdaptMesh/TriGraph.h b/Cassiopee/XCore/XCore/AdaptMesh/TriGraph.h new file mode 100644 index 000000000..5add888ea --- /dev/null +++ b/Cassiopee/XCore/XCore/AdaptMesh/TriGraph.h @@ -0,0 +1,18 @@ +#pragma once + +#include "common/mem.h" +#include +#include + +struct TriGraph { + size_t nf; + std::vector skin; + std::vector> T; + std::vector> E; + std::vector fdat; + std::vector level; + + void clear(); +}; + + diff --git a/Cassiopee/XCore/srcs.py b/Cassiopee/XCore/srcs.py index 84a5385ba..876daa19c 100644 --- a/Cassiopee/XCore/srcs.py +++ b/Cassiopee/XCore/srcs.py @@ -108,6 +108,7 @@ 'XCore/AdaptMesh/DynMesh.cpp', 'XCore/AdaptMesh/DynMeshTopo.cpp', + 'XCore/AdaptMesh/TriGraph.cpp', From b0c8de239fdec6a6a25d1cf9f43db5d208dc0fe9 Mon Sep 17 00:00:00 2001 From: imadhammani Date: Tue, 1 Oct 2024 11:37:01 +0200 Subject: [PATCH 20/86] XCore AdaptMesh: small update --- Cassiopee/XCore/XCore/AdaptMesh/MeshSmooth.cpp | 4 ++-- Cassiopee/XCore/XCore/AdaptMesh/Q9.cpp | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Cassiopee/XCore/XCore/AdaptMesh/MeshSmooth.cpp b/Cassiopee/XCore/XCore/AdaptMesh/MeshSmooth.cpp index 5b9d6bf19..865b753ff 100644 --- a/Cassiopee/XCore/XCore/AdaptMesh/MeshSmooth.cpp +++ b/Cassiopee/XCore/XCore/AdaptMesh/MeshSmooth.cpp @@ -70,8 +70,8 @@ E_Int Mesh_smooth_cref_local(Mesh *M) E_Int cell_to_mod = incr_cell > incr_nei ? nei : cid; - //M->cref[cell_to_mod] += diff-1; - M->cref[cell_to_mod] += 1; + M->cref[cell_to_mod] += diff-1; + //M->cref[cell_to_mod] += 1; stk.push(cell_to_mod); } diff --git a/Cassiopee/XCore/XCore/AdaptMesh/Q9.cpp b/Cassiopee/XCore/XCore/AdaptMesh/Q9.cpp index 64b4ab5e9..5098a74da 100644 --- a/Cassiopee/XCore/XCore/AdaptMesh/Q9.cpp +++ b/Cassiopee/XCore/XCore/AdaptMesh/Q9.cpp @@ -154,7 +154,7 @@ E_Int Q9_refine(E_Int quad, Mesh *M) M->ftag[M->nf+1] = M->ftag[quad]; M->ftag[M->nf+2] = M->ftag[quad]; - assert(M->fpattern[quad] == DIR_ISO); + //assert(M->fpattern[quad] == DIR_ISO); M->fpattern[M->nf] = M->fpattern[quad]; M->fpattern[M->nf+1] = M->fpattern[quad]; M->fpattern[M->nf+2] = M->fpattern[quad]; From 17bd471c6583e31177c982ffcbe6b4f87e49f78c Mon Sep 17 00:00:00 2001 From: imadhammani Date: Tue, 1 Oct 2024 11:37:54 +0200 Subject: [PATCH 21/86] XCore AdaptMesh: leaks --- Cassiopee/XCore/XCore/AdaptMesh/AdaptMesh_Exit.cpp | 2 ++ Cassiopee/XCore/XCore/AdaptMesh/MeshClean.cpp | 1 + 2 files changed, 3 insertions(+) diff --git a/Cassiopee/XCore/XCore/AdaptMesh/AdaptMesh_Exit.cpp b/Cassiopee/XCore/XCore/AdaptMesh/AdaptMesh_Exit.cpp index d6f804cfd..7ab96c3cf 100644 --- a/Cassiopee/XCore/XCore/AdaptMesh/AdaptMesh_Exit.cpp +++ b/Cassiopee/XCore/XCore/AdaptMesh/AdaptMesh_Exit.cpp @@ -45,6 +45,8 @@ PyObject *K_XCORE::AdaptMesh_Exit(PyObject *self, PyObject *args) Mesh_reset_parallel_data(M); + Mesh_reset_tags(M); + XFREE(M->reqs); delete M; diff --git a/Cassiopee/XCore/XCore/AdaptMesh/MeshClean.cpp b/Cassiopee/XCore/XCore/AdaptMesh/MeshClean.cpp index 2dd786d3d..336712bb5 100644 --- a/Cassiopee/XCore/XCore/AdaptMesh/MeshClean.cpp +++ b/Cassiopee/XCore/XCore/AdaptMesh/MeshClean.cpp @@ -128,5 +128,6 @@ void Mesh_free(Mesh *M) Mesh_reset_adaptation_data(M); Mesh_reset_comm_data(M); Mesh_reset_parallel_data(M); + Mesh_reset_tags(M); delete M; } From 80339173c86d2cf8dbbb0c4e3dc8f35b65651557 Mon Sep 17 00:00:00 2001 From: imadhammani Date: Tue, 1 Oct 2024 11:54:59 +0200 Subject: [PATCH 22/86] XCore AdaptMesh: small fix --- Cassiopee/XCore/XCore/AdaptMesh/AdaptMesh_Exit.cpp | 1 + Cassiopee/XCore/XCore/AdaptMesh/AdaptMesh_Init.cpp | 2 -- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/Cassiopee/XCore/XCore/AdaptMesh/AdaptMesh_Exit.cpp b/Cassiopee/XCore/XCore/AdaptMesh/AdaptMesh_Exit.cpp index 7ab96c3cf..92f826fa4 100644 --- a/Cassiopee/XCore/XCore/AdaptMesh/AdaptMesh_Exit.cpp +++ b/Cassiopee/XCore/XCore/AdaptMesh/AdaptMesh_Exit.cpp @@ -48,6 +48,7 @@ PyObject *K_XCORE::AdaptMesh_Exit(PyObject *self, PyObject *args) Mesh_reset_tags(M); XFREE(M->reqs); + delete [] M->mode_2D; delete M; diff --git a/Cassiopee/XCore/XCore/AdaptMesh/AdaptMesh_Init.cpp b/Cassiopee/XCore/XCore/AdaptMesh/AdaptMesh_Init.cpp index 8dc1094e4..c2fc23f1d 100644 --- a/Cassiopee/XCore/XCore/AdaptMesh/AdaptMesh_Init.cpp +++ b/Cassiopee/XCore/XCore/AdaptMesh/AdaptMesh_Init.cpp @@ -209,9 +209,7 @@ PyObject *K_XCORE::AdaptMesh_Init(PyObject *self, PyObject *args) Mesh_free(M); return NULL; } - } - if (M->mode_2D) { ret = Mesh_set_cells_for_2D(M); if (ret != 0) { RAISE("Failed to set cells for 2D."); From 10e791696121ed07d3395d57edb02f44f06c713c Mon Sep 17 00:00:00 2001 From: imadhammani Date: Sun, 6 Oct 2024 21:15:25 +0200 Subject: [PATCH 23/86] XCore intersectMesh: added propagate to triangulate --- Cassiopee/XCore/XCore/intersectMesh/mesh.cpp | 40 +++++++++++++++++++- Cassiopee/XCore/XCore/intersectMesh/mesh.h | 2 +- 2 files changed, 39 insertions(+), 3 deletions(-) diff --git a/Cassiopee/XCore/XCore/intersectMesh/mesh.cpp b/Cassiopee/XCore/XCore/intersectMesh/mesh.cpp index b12ae569d..b845261bb 100644 --- a/Cassiopee/XCore/XCore/intersectMesh/mesh.cpp +++ b/Cassiopee/XCore/XCore/intersectMesh/mesh.cpp @@ -33,8 +33,42 @@ #include "ray.h" #include "io.h" -void IMesh::triangulate_face_set() +void IMesh::triangulate_face_set(bool propagate) { + if (propagate) { + E_Float xmin, ymin, zmin, xmax, ymax, zmax; + xmin = ymin = zmin = EFLOATMAX; + xmax = ymax = zmax = EFLOATMIN; + + for (auto fid : faces_to_tri) { + const auto &pn = F[fid]; + for (auto p : pn) { + if (X[p] < xmin) xmin = X[p]; + if (Y[p] < ymin) ymin = Y[p]; + if (Z[p] < zmin) zmin = Z[p]; + if (X[p] > xmax) xmax = X[p]; + if (Y[p] > ymax) ymax = Y[p]; + if (Z[p] > zmax) zmax = Z[p]; + } + } + + make_skin(); + + faces_to_tri.clear(); + + for (auto fid : skin) { + const auto &pn = F[fid]; + for (auto p : pn) { + if (X[p] >= xmin && X[p] <= xmax && + Y[p] >= ymin && Y[p] <= ymax && + Z[p] >= zmin && Z[p] <= zmax) { + faces_to_tri.insert(fid); + break; + } + } + } + } + E_Int NF = nf; E_Int face_incr = (E_Int)faces_to_tri.size(); @@ -92,9 +126,11 @@ void IMesh::triangulate_face_set() faces_to_tri.clear(); + /* for (E_Int cid = 0; cid < nc; cid++) { assert(C[cid].size() == 6 || C[cid].size() == 7); } + */ } struct DEdge { @@ -891,4 +927,4 @@ void IMesh::get_fleaves(E_Int face, std::vector &fleaves) } for (E_Int child : fchildren.at(face)) get_fleaves(child, fleaves); -} \ No newline at end of file +} diff --git a/Cassiopee/XCore/XCore/intersectMesh/mesh.h b/Cassiopee/XCore/XCore/intersectMesh/mesh.h index 30a0bef25..d7bc8de40 100644 --- a/Cassiopee/XCore/XCore/intersectMesh/mesh.h +++ b/Cassiopee/XCore/XCore/intersectMesh/mesh.h @@ -95,7 +95,7 @@ struct IMesh { E_Int project_point(E_Float px, E_Float py, E_Float pz, E_Float dx, E_Float dy, E_Float dz, TriangleIntersection &TI, E_Int II); - void triangulate_face_set(); + void triangulate_face_set(bool propagate = true); void hash_patch(); From cb45aa0f4373b61963c5f7d5355b1fccacc532a8 Mon Sep 17 00:00:00 2001 From: imadhammani Date: Sun, 6 Oct 2024 21:15:50 +0200 Subject: [PATCH 24/86] XCore intersectMesh: fixed patch hashing --- Cassiopee/XCore/XCore/intersectMesh/DDA.cpp | 48 ++++++++++++--------- 1 file changed, 28 insertions(+), 20 deletions(-) diff --git a/Cassiopee/XCore/XCore/intersectMesh/DDA.cpp b/Cassiopee/XCore/XCore/intersectMesh/DDA.cpp index ff76c2258..78b933bc0 100644 --- a/Cassiopee/XCore/XCore/intersectMesh/DDA.cpp +++ b/Cassiopee/XCore/XCore/intersectMesh/DDA.cpp @@ -25,14 +25,6 @@ void IMesh::hash_skin() E_Int J = floor((y - ymin) / HY); E_Int K = floor((z - zmin) / HZ); - assert(I >= 0); - assert(J >= 0); - assert(K >= 0); - - assert(I < NX); - assert(J < NY); - assert(K < NZ); - if (I < Imin) Imin = I; if (J < Jmin) Jmin = J; if (K < Kmin) Kmin = K; @@ -63,19 +55,35 @@ void IMesh::hash_patch() const auto &pn = F[fid]; - AABB bbox = AABB_face(pn); + E_Int Imin, Jmin, Kmin; + E_Int Imax, Jmax, Kmax; + + Imin = Jmin = Kmin = NXYZ; + Imax = Jmax = Kmax = -1; + + for (E_Int p : pn) { + E_Float x = X[p]; + E_Float y = Y[p]; + E_Float z = Z[p]; + + E_Int I = floor((x - xmin) / HX); + E_Int J = floor((y - ymin) / HY); + E_Int K = floor((z - zmin) / HZ); - E_Int imin = floor((bbox.xmin - xmin) / HX); - E_Int imax = floor((bbox.xmax - xmin) / HX); - E_Int jmin = floor((bbox.ymin - ymin) / HY); - E_Int jmax = floor((bbox.ymax - ymin) / HY); - E_Int kmin = floor((bbox.zmin - zmin) / HZ); - E_Int kmax = floor((bbox.zmax - zmin) / HZ); + if (I < Imin) Imin = I; + if (J < Jmin) Jmin = J; + if (K < Kmin) Kmin = K; + if (I > Imax) Imax = I; + if (J > Jmax) Jmax = J; + if (K > Kmax) Kmax = K; + } - for (E_Int k = kmin; k < kmax+1; k++) { - for (E_Int j = jmin; j < jmax+1; j++) { - for (E_Int i = imin; i < imax+1; i++) { - E_Int voxel = i + NX*j + NXY*k; + for (E_Int I = Imin; I <= Imax; I++) { + for (E_Int J = Jmin; J <= Jmax; J++) { + for (E_Int K = Kmin; K <= Kmax; K++) { + E_Int voxel = get_voxel(I, J, K); + assert(voxel >= 0); + assert(voxel < NXYZ); fmap[voxel].push_back(fid); } } @@ -95,4 +103,4 @@ AABB IMesh::AABB_face(const std::vector &pn) const if (Z[p] < ret.zmin) ret.zmin = Z[p]; } return ret; -} \ No newline at end of file +} From fc19a8d0cecdbd2eb8f8590d400c0e60341e9549 Mon Sep 17 00:00:00 2001 From: imadhammani Date: Sun, 6 Oct 2024 21:16:45 +0200 Subject: [PATCH 25/86] XCore intersectMesh: added algo1 to removeIntersectingKPlanes --- .../removeIntersectingKPlanes.cpp | 175 +++++++++++++++++- 1 file changed, 173 insertions(+), 2 deletions(-) diff --git a/Cassiopee/XCore/XCore/intersectMesh/removeIntersectingKPlanes.cpp b/Cassiopee/XCore/XCore/intersectMesh/removeIntersectingKPlanes.cpp index c74d7d91f..363c1a544 100644 --- a/Cassiopee/XCore/XCore/intersectMesh/removeIntersectingKPlanes.cpp +++ b/Cassiopee/XCore/XCore/intersectMesh/removeIntersectingKPlanes.cpp @@ -368,6 +368,166 @@ PyObject *handle_slave(IMesh *M, Karray& sarray) return out; } +static +E_Int get_kmax(IMesh *M, Karray& sarray) +{ + E_Int ni = sarray.ni; + E_Int nj = sarray.nj; + E_Int nk = sarray.nk; + E_Int nij = ni * nj; + + E_Float *Xs = sarray.X; + E_Float *Ys = sarray.Y; + E_Float *Zs = sarray.Z; + + E_Int kmax = -1; + + for (E_Int k = 0; k < nk && kmax == -1; k++) { + for (E_Int j = 0; j < nj && kmax == -1; j++) { + for (E_Int i = 0; i < ni; i++) { + E_Int idx = i + ni*j + nij*k; + + E_Float px = Xs[idx]; + E_Float py = Ys[idx]; + E_Float pz = Zs[idx]; + + if (M->is_point_inside(px, py, pz)) { + kmax = k-1; + return kmax; + } + } + } + } + + assert(0); + return kmax; +} + +static +PyObject *handle_slave2(IMesh *M, Karray& sarray, E_Int kmax) +{ + E_Int ni = sarray.ni; + E_Int nj = sarray.nj; + E_Int nk = sarray.nk; + E_Int nij = ni * nj; + + E_Float *Xs = sarray.X; + E_Float *Ys = sarray.Y; + E_Float *Zs = sarray.Z; + + // Indices of points to be projected + std::vector proj_points; + + for (E_Int j = 0; j < nj; j++) { + for (E_Int i = 0; i < ni; i++) { + + E_Int idx = i + ni*j + nij*kmax; + + proj_points.push_back(idx); + } + } + + //point_write("proj_points", Xs, Ys, Zs, proj_points); + + //E_Int np = ni*nj*nk; + + // Project points onto marray surface + std::unordered_map point_hit_table; + + for (E_Int i = 0; i < nij; i++) { + E_Int p = proj_points[i]; + E_Int q = p + nij; + + E_Float px = Xs[p]; + E_Float py = Ys[p]; + E_Float pz = Zs[p]; + + E_Float dx = Xs[q] - Xs[p]; + E_Float dy = Ys[q] - Ys[p]; + E_Float dz = Zs[q] - Zs[p]; + + E_Float NORM = sqrt(dx*dx + dy*dy + dz*dz); + + dx /= NORM, dy /= NORM, dz /= NORM; + + TriangleIntersection TI; + + E_Int hit = M->project_point(px, py, pz, dx, dy, dz, TI, i); + + assert(hit); + + TI.pid = p; + + point_hit_table[p] = TI; + } + + for (const auto &ploc : point_hit_table) { + E_Int fid = ploc.second.face; + const auto &pn = M->F[fid]; + assert(pn.size() == 4); + M->faces_to_tri.insert(fid); + } + + // Make out cartesian mesh + PyObject *tpl; + nk = kmax + 2; + tpl = K_ARRAY::buildArray3(3, "x,y,z", ni, nj, nk, 3); + + K_FLD::FldArrayF *f; + K_FLD::FldArrayI *c; + char *varString, *eltType; + K_ARRAY::getFromArray3(tpl, varString, f, ni, nj, nk, c, eltType); + + E_Float* xt = f->begin(1); + E_Float* yt = f->begin(2); + E_Float* zt = f->begin(3); + + // Copy all the points up to kmax + for (E_Int k = 0; k < kmax+1; k++) { + for (E_Int j = 0; j < nj; j++) { + for (E_Int i = 0; i < ni; i++) { + E_Int ind = i + j*ni + k*nij; + xt[ind] = Xs[ind]; + yt[ind] = Ys[ind]; + zt[ind] = Zs[ind]; + } + } + } + + // Copy the projected points + E_Int ind = nij*(kmax+1); + for (E_Int i = 0; i < nij; i++) { + E_Int p = proj_points[i]; + auto EH = point_hit_table[p]; + E_Float x = EH.x; + E_Float y = EH.y; + E_Float z = EH.z; + xt[ind] = x; + yt[ind] = y; + zt[ind] = z; + ind++; + } + + // Tag the projected points + npy_intp dims[2]; + dims[1] = 1; + dims[0] = (npy_intp)ni*nj*nk; + PyArrayObject *tag = (PyArrayObject *)PyArray_SimpleNew(1, dims, NPY_DOUBLE); + E_Float *ptag = (E_Float *)PyArray_DATA(tag); + for (E_Int i = 0; i < nij*(kmax+1); i++) ptag[i] = 0.0; + for (E_Int i = nij*(kmax+1); i < nij*nk; i++) ptag[i] = 1.0; + + PyObject *out = PyList_New(0); + PyList_Append(out, tpl); + PyList_Append(out, (PyObject *)tag); + RELEASESHAREDS(tpl, f); + Py_DECREF(tpl); + Py_DECREF(tag); + + return out; +} + + PyObject *K_XCORE::removeIntersectingKPlanes(PyObject *self, PyObject *args) { PyObject *MASTER, *SLAVES; @@ -411,15 +571,26 @@ PyObject *K_XCORE::removeIntersectingKPlanes(PyObject *self, PyObject *args) return NULL; } + E_Int kmax = 10000000; + + for (E_Int i = 0; i < nslaves; i++) { + E_Int k = get_kmax(M, sarrays[i]); + printf("k: %d\n", k); + if (k < kmax) kmax = k; + } + + printf("kmax: %d\n", kmax); + PyObject *slaves_out = PyList_New(0); for (E_Int i = 0; i < nslaves; i++) { printf("Projecting %d / %d\n", i+1, nslaves); - PyObject *st = handle_slave(M, sarrays[i]); + PyObject *st = handle_slave2(M, sarrays[i], kmax); + //PyObject *st = handle_slave(M, sarrays[i]); PyList_Append(slaves_out, st); Py_DECREF(st); Karray_free_structured(sarrays[i]); } return slaves_out; -} \ No newline at end of file +} From e16f89d6bad44b765ec1f35d6a1b561c6e495e74 Mon Sep 17 00:00:00 2001 From: imadhammani Date: Sun, 6 Oct 2024 21:17:47 +0200 Subject: [PATCH 26/86] XCore intersectMesh: added merge function (WIP) --- Cassiopee/XCore/XCore/PyTree.py | 8 + .../intersectMesh/IntersectMesh_Merge.cpp | 419 ++++++++++++++++++ Cassiopee/XCore/XCore/xcore.cpp | 1 + Cassiopee/XCore/XCore/xcore.h | 1 + Cassiopee/XCore/srcs.py | 1 + 5 files changed, 430 insertions(+) create mode 100644 Cassiopee/XCore/XCore/intersectMesh/IntersectMesh_Merge.cpp diff --git a/Cassiopee/XCore/XCore/PyTree.py b/Cassiopee/XCore/XCore/PyTree.py index fa1fec6a9..03671263c 100644 --- a/Cassiopee/XCore/XCore/PyTree.py +++ b/Cassiopee/XCore/XCore/PyTree.py @@ -435,6 +435,14 @@ def intersectMesh(IM, slave): def IntersectMesh_ExtractFaceSet(AM): return xcore.IntersectMesh_ExtractFaceSet(AM) +def IntersectMesh_Merge(M, S): + zm = I.getZones(M)[0] + m = C.getFields(I.__GridCoordinates__, zm, api=3)[0] + zs = I.getZones(S)[0] + s = C.getFields(I.__GridCoordinates__, zs, api=3)[0] + + return xcore.IntersectMesh_Merge(m, s) + def extractCell(a, cid): z = I.getZones(a)[0] diff --git a/Cassiopee/XCore/XCore/intersectMesh/IntersectMesh_Merge.cpp b/Cassiopee/XCore/XCore/intersectMesh/IntersectMesh_Merge.cpp new file mode 100644 index 000000000..a3c43ed45 --- /dev/null +++ b/Cassiopee/XCore/XCore/intersectMesh/IntersectMesh_Merge.cpp @@ -0,0 +1,419 @@ +#include "xcore.h" +#include "karray.h" +#include +#include + +#define TOL 1e-12 + +struct Vtx { + E_Float x, y, z; + E_Int i0; + mutable E_Int i1; + E_Int id; + + Vtx(E_Float x_, E_Float y_, E_Float z_) + : x(x_), y(y_), z(z_), i0(-1), i1(-1), id(-1) + {} + + bool operator<(const Vtx &v) const + { + if (x < v.x) return true; + if (x == v.x && y < v.y) return true; + if (x == v.x && y == v.y && z < v.z) return true; + return false; + } +}; + +struct FACE { + std::vector F; + E_Int i0; + mutable E_Int i1; + E_Int id; + + FACE(E_Int *pn, E_Int np) + { + F.reserve(np); + for (E_Int i = 0; i < np; i++) { + F.push_back(pn[i]); + } + std::sort(F.begin(), F.end()); + i0 = i1 = id = -1; + } + + bool operator==(const FACE &face) const + { + if (F.size() == face.F.size()) { + for (size_t i = 0; i < F.size(); i++) { + if (F[i] != face.F[i]) { + return false; + } + } + + return true; + } + + return false; + } +}; + +struct FACEHASH { + uint64_t hash(uint64_t val, uint64_t seed) const + { + uint64_t HASH = seed; + HASH += val; + HASH += HASH << 10; + HASH ^= HASH >> 6; + return HASH; + } + + uint32_t operator()(const FACE &face) const + { + uint64_t res = 0; + for (size_t i = 0; i < face.F.size(); i++) + res = hash(face.F[i], res); + + res += res << 3; + res ^= res >> 11; + res += res << 15; + + return res; + } +}; + +PyObject *K_XCORE::IntersectMesh_Merge(PyObject *self, PyObject *args) +{ + PyObject *MASTER, *SLAVE; + if (!PYPARSETUPLE_(args, OO_, &MASTER, &SLAVE)) { + RAISE("Bad input."); + return NULL; + } + + Karray marray, sarray; + E_Int ret = Karray_parse_ngon(MASTER, marray); + if (ret != 0) { + RAISE("First input mesh is not an NGon."); + return NULL; + } + + ret = Karray_parse_ngon(SLAVE, sarray); + if (ret != 0) { + RAISE("Second input mesh is not an NGon."); + Karray_free_ngon(marray); + return NULL; + } + + // Points + std::set points; + + // Master points + E_Float *X = marray.X; + E_Float *Y = marray.Y; + E_Float *Z = marray.Z; + + printf("M points: %d\n", marray.npts); + printf("S points: %d\n", sarray.npts); + + E_Int NP = 0; + + for (E_Int i = 0; i < marray.npts; i++) { + Vtx xyz(X[i], Y[i], Z[i]); + auto it = points.find(xyz); + if (it != points.end()) abort(); + xyz.i0 = i; + xyz.id = NP; + points.insert(xyz); + NP++; + } + + assert((size_t)NP == points.size()); + + // Slave points + X = sarray.X; + Y = sarray.Y; + Z = sarray.Z; + + for (E_Int i = 0; i < sarray.npts; i++) { + Vtx xyz(X[i], Y[i], Z[i]); + auto it = points.find(xyz); + if (it == points.end()) { + xyz.i1 = i; + xyz.id = NP; + points.insert(xyz); + NP++; + } else { + assert(it->i0 != -1); + assert(it->id != -1); + it->i1 = i; + } + } + + printf("Duplicate points: %lu\n", (size_t)(marray.npts + sarray.npts) - points.size()); + + // Change the points ids within marray + + X = marray.X; + Y = marray.Y; + Z = marray.Z; + + for (E_Int fid = 0; fid < marray.nfaces(); fid++) { + E_Int np = -1; + E_Int *pn = marray.get_face(fid, np); + for (E_Int j = 0; j < np; j++) { + E_Int pid = pn[j] - 1; + Vtx xyz(X[pid], Y[pid], Z[pid]); + auto it = points.find(xyz); + if (it == points.end()) abort(); + pn[j] = it->id; + } + } + + // Change the points within sarray + + X = sarray.X; + Y = sarray.Y; + Z = sarray.Z; + + for (E_Int fid = 0; fid < sarray.nfaces(); fid++) { + E_Int np = -1; + E_Int *pn = sarray.get_face(fid, np); + for (E_Int j = 0; j < np; j++) { + E_Int pid = pn[j] - 1; + Vtx xyz(X[pid], Y[pid], Z[pid]); + auto it = points.find(xyz); + if (it == points.end()) abort(); + pn[j] = it->id; + } + } + + // Hash the faces + std::unordered_set faces; + + // Hash the M faces + + E_Int NF = 0; + + for (E_Int fid = 0; fid < marray.nfaces(); fid++) { + E_Int np = -1; + E_Int *pn = marray.get_face(fid, np); + FACE face(pn, np); + auto it = faces.find(face); + if (it != faces.end()) abort(); + face.i0 = fid; + face.id = NF; + faces.insert(face); + NF++; + } + + // Hash the S faces + + for (E_Int fid = 0; fid < sarray.nfaces(); fid++) { + E_Int np = -1; + E_Int *pn = sarray.get_face(fid, np); + FACE face(pn, np); + auto it = faces.find(face); + if (it == faces.end()) { + face.i1 = fid; + face.id = NF; + faces.insert(face); + NF++; + } else { + assert(it->i0 != -1); + assert(it->id != -1); + it->i1 = fid; + } + } + + printf("Duplicate faces: %lu\n", marray.nfaces() + sarray.nfaces() - faces.size()); + + // Replace face ids in marray + + for (E_Int cid = 0; cid < marray.ncells(); cid++) { + E_Int nf = -1; + E_Int *pf = marray.get_cell(cid, nf); + for (E_Int i = 0; i < nf; i++) { + E_Int fid = pf[i]-1; + E_Int np = -1; + E_Int *pn = marray.get_face(fid, np); + FACE face(pn, np); + auto it = faces.find(face); + if (it == faces.end()) abort(); + pf[i] = it->id; + } + } + + + // Replace face ids in sarray + + for (E_Int cid = 0; cid < sarray.ncells(); cid++) { + E_Int nf = -1; + E_Int *pf = sarray.get_cell(cid, nf); + for (E_Int i = 0; i < nf; i++) { + E_Int fid = pf[i]-1; + E_Int np = -1; + E_Int *pn = sarray.get_face(fid, np); + FACE face(pn, np); + auto it = faces.find(face); + if (it == faces.end()) abort(); + pf[i] = it->id; + } + } + + + E_Int sizeNGon = 0, sizeNFace = 0; + + for (E_Int cid = 0; cid < marray.ncells(); cid++) { + E_Int nf = -1; + marray.get_cell(cid, nf); + sizeNFace += nf; + } + + for (E_Int cid = 0; cid < sarray.ncells(); cid++) { + E_Int nf = -1; + sarray.get_cell(cid, nf); + sizeNFace += nf; + } + + printf("sizeNFace: %d\n", sizeNFace); + + for (E_Int fid = 0; fid < marray.nfaces(); fid++) { + E_Int np = -1; + E_Int *pn = marray.get_face(fid, np); + sizeNGon += np; + } + + for (E_Int fid = 0; fid < sarray.nfaces(); fid++) { + E_Int np = -1; + E_Int *pn = sarray.get_face(fid, np); + // Don't add it if it's a dup + FACE face(pn, np); + auto it = faces.find(face); + if (it->i0 == -1) + sizeNGon += np; + } + + printf("sizeNGon: %d\n", sizeNGon); + + const char *var_string = "CoordinateX,CoordinateY,CoordinateZ"; + + E_Int NC = marray.ncells() + sarray.ncells(); + + printf("NC: %d\n", NC); + printf("NF: %d\n", NF); + printf("NP: %d\n", NP); + + PyObject *array = K_ARRAY::buildArray3(3, var_string, NP, NC, NF, + "NGON", sizeNGon, sizeNFace, 3, false, 3); + + K_FLD::FldArrayF *f; + K_FLD::FldArrayI *cn; + K_ARRAY::getFromArray3(array, f, cn); + + E_Float *px = f->begin(1); + E_Float *py = f->begin(2); + E_Float *pz = f->begin(3); + + for (const auto &point : points) { + if (point.id >= NP) abort(); + if (point.id < 0) abort(); + px[point.id] = point.x; + py[point.id] = point.y; + pz[point.id] = point.z; + } + + E_Int *indPG = cn->getIndPG(); + E_Int *ngon = cn->getNGon(); + E_Int *indPH = cn->getIndPH(); + E_Int *nface = cn->getNFace(); + + + indPG[0] = indPH[0] = 0; + + for (E_Int fid = 0; fid < marray.nfaces(); fid++) { + E_Int np = -1; + E_Int *pn = marray.get_face(fid, np); + FACE face(pn, np); + auto it = faces.find(face); + indPG[it->id+1] = np; + } + + for (E_Int fid = 0; fid < sarray.nfaces(); fid++) { + E_Int np = -1; + E_Int *pn = sarray.get_face(fid, np); + FACE face(pn, np); + auto it = faces.find(face); + indPG[it->id+1] = np; + } + + for (E_Int i = 0; i < NF; i++) indPG[i+1] += indPG[i]; + + printf("indPG[NF]: %d\n", indPG[NF]); + fflush(stdout); + + if (indPG[NF] != sizeNGon) abort(); + + puts("ok indPG"); + fflush(stdout); + + for (E_Int cid = 0; cid < marray.ncells(); cid++) { + E_Int nf = -1; + marray.get_cell(cid, nf); + indPH[cid+1] = nf; + } + + for (E_Int cid = 0; cid < sarray.ncells(); cid++) { + E_Int nf = -1; + sarray.get_cell(cid, nf); + indPH[cid + marray.ncells() + 1] = nf; + } + + for (E_Int i = 0; i < NC; i++) indPH[i+1] += indPH[i]; + + printf("indPH[NC]: %d\n", indPH[NC]); + fflush(stdout); + + if (indPH[NC] != sizeNFace) abort(); + + puts("ok indPH"); + fflush(stdout); + + for (E_Int fid = 0; fid < marray.nfaces(); fid++) { + E_Int np = -1; + E_Int *pn = marray.get_face(fid, np); + FACE face(pn, np); + auto it = faces.find(face); + E_Int *ptr = &ngon[indPG[it->id]]; + for (E_Int i = 0; i < np; i++) + *ptr++ = pn[i] + 1; + } + + for (E_Int fid = 0; fid < sarray.nfaces(); fid++) { + E_Int np = -1; + E_Int *pn = sarray.get_face(fid, np); + FACE face(pn, np); + auto it = faces.find(face); + E_Int *ptr = &ngon[indPG[it->id]]; + for (E_Int i = 0; i < np; i++) + *ptr++ = pn[i] + 1; + } + + for (E_Int cid = 0; cid < marray.ncells(); cid++) { + E_Int nf = -1; + E_Int *pf = marray.get_cell(cid, nf); + E_Int *ptr = &nface[indPH[cid]]; + for (E_Int i = 0; i < nf; i++) + *ptr++ = pf[i] + 1; + } + + for (E_Int cid = 0; cid < sarray.ncells(); cid++) { + E_Int nf = -1; + E_Int *pf = sarray.get_cell(cid, nf); + E_Int *ptr = &nface[indPH[cid + marray.ncells()]]; + for (E_Int i = 0; i < nf; i++) + *ptr++ = pf[i] + 1; + } + + delete f; + delete cn; + + return array; +} diff --git a/Cassiopee/XCore/XCore/xcore.cpp b/Cassiopee/XCore/XCore/xcore.cpp index 9684e7ee4..c69b73b0d 100644 --- a/Cassiopee/XCore/XCore/xcore.cpp +++ b/Cassiopee/XCore/XCore/xcore.cpp @@ -58,6 +58,7 @@ static PyMethodDef Pyxcore [] = {"IntersectMesh_ExtractMesh", K_XCORE::IntersectMesh_ExtractMesh, METH_VARARGS}, {"IntersectMesh_Exit", K_XCORE::IntersectMesh_Exit, METH_VARARGS}, {"IntersectMesh_ExtractFaceSet", K_XCORE::IntersectMesh_ExtractFaceSet, METH_VARARGS}, + {"IntersectMesh_Merge", K_XCORE::IntersectMesh_Merge, METH_VARARGS}, {"extractCell", K_XCORE::extractCell, METH_VARARGS}, diff --git a/Cassiopee/XCore/XCore/xcore.h b/Cassiopee/XCore/XCore/xcore.h index 91512c42a..2c50ca6f0 100644 --- a/Cassiopee/XCore/XCore/xcore.h +++ b/Cassiopee/XCore/XCore/xcore.h @@ -70,6 +70,7 @@ namespace K_XCORE PyObject *IntersectMesh_TriangulateFaceSet(PyObject *self, PyObject *args); PyObject *IntersectMesh_Exit(PyObject *self, PyObject *args); PyObject *IntersectMesh_ExtractFaceSet(PyObject *self, PyObject *args); + PyObject *IntersectMesh_Merge(PyObject *self, PyObject *args); PyObject *extractCell(PyObject *self, PyObject *args); diff --git a/Cassiopee/XCore/srcs.py b/Cassiopee/XCore/srcs.py index 876daa19c..a939fd62f 100644 --- a/Cassiopee/XCore/srcs.py +++ b/Cassiopee/XCore/srcs.py @@ -30,6 +30,7 @@ 'XCore/intersectMesh/IntersectMesh_ExtractMesh.cpp', 'XCore/intersectMesh/IntersectMesh_Exit.cpp', 'XCore/intersectMesh/IntersectMesh_ExtractFaceSet.cpp', + 'XCore/intersectMesh/IntersectMesh_Merge.cpp', 'XCore/intersectMesh/intersectMesh.cpp', 'XCore/intersectMesh/removeIntersectingKPlanes.cpp', From 2f9dc38061c3c20e2d3d5af0ee0df60bc4552e14 Mon Sep 17 00:00:00 2001 From: imadhammani Date: Sun, 6 Oct 2024 21:18:58 +0200 Subject: [PATCH 27/86] Updated karray --- Cassiopee/XCore/XCore/intersectMesh/karray.h | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/Cassiopee/XCore/XCore/intersectMesh/karray.h b/Cassiopee/XCore/XCore/intersectMesh/karray.h index c504d363f..439bf2d4b 100644 --- a/Cassiopee/XCore/XCore/intersectMesh/karray.h +++ b/Cassiopee/XCore/XCore/intersectMesh/karray.h @@ -32,6 +32,22 @@ struct Karray { E_Float *X, *Y, *Z; E_Int npts; + + inline E_Int *indpg() const { return cn->getIndPG(); } + inline E_Int *indph() const { return cn->getIndPH(); } + + inline E_Int *ngon() const { return cn->getNGon(); } + inline E_Int *nface() const { return cn->getNFace(); } + + inline E_Int *get_face(E_Int face, E_Int &np) const + { return cn->getFace(face, np, ngon(), indpg()); } + + inline E_Int *get_cell(E_Int cell, E_Int &nf) const + { return cn->getElt(cell, nf, nface(), indph()); } + + inline E_Int npoints() const { return npts; } + inline E_Int nfaces() const { return cn->getNFaces(); } + inline E_Int ncells() const { return cn->getNElts(); } }; void Karray_free_ngon(Karray &karray); From 2a35f8e3aefd1d15d0d9d018d01470a4f8a09135 Mon Sep 17 00:00:00 2001 From: imadhammani Date: Sun, 6 Oct 2024 21:19:29 +0200 Subject: [PATCH 28/86] dcel to debug --- Cassiopee/XCore/XCore/intersectMesh/dcel.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Cassiopee/XCore/XCore/intersectMesh/dcel.cpp b/Cassiopee/XCore/XCore/intersectMesh/dcel.cpp index 01d94bcd0..6c8f0a317 100644 --- a/Cassiopee/XCore/XCore/intersectMesh/dcel.cpp +++ b/Cassiopee/XCore/XCore/intersectMesh/dcel.cpp @@ -932,7 +932,7 @@ void Dcel::trace_hedge(Hedge *sh, const Smesh &M, const Smesh &S, E_Int hid) E_Int found = 0; E_Int walk = 0; - E_Int max_walk = 10; + E_Int max_walk = 100; Face *current_face = F[start_face]; @@ -1124,7 +1124,7 @@ void Dcel::find_intersections_3D(const Smesh &M, const Smesh &S) for (size_t hid = 0; hid < s_hedges.size(); hid++) { Hedge *sh = s_hedges[hid]; - //printf("Tracing hedge %d / %zu\n", hid+1, s_hedges.size()); + printf("Tracing hedge %zu / %zu\n", hid+1, s_hedges.size()); trace_hedge(sh, M, S, hid); } From 0cf81b9d2c95e0568d6e9aae548581310c6be76b Mon Sep 17 00:00:00 2001 From: imadhammani Date: Sun, 6 Oct 2024 21:21:45 +0200 Subject: [PATCH 29/86] XCore intersectMesh: write Mf and Sf --- Cassiopee/XCore/XCore/intersectMesh/intersectMesh.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Cassiopee/XCore/XCore/intersectMesh/intersectMesh.cpp b/Cassiopee/XCore/XCore/intersectMesh/intersectMesh.cpp index 289ddc829..c374aec8e 100644 --- a/Cassiopee/XCore/XCore/intersectMesh/intersectMesh.cpp +++ b/Cassiopee/XCore/XCore/intersectMesh/intersectMesh.cpp @@ -343,8 +343,8 @@ PyObject *K_XCORE::intersectMesh(PyObject *self, PyObject *args) Smesh Mf(M); Smesh Sf(S); - //Mf.write_ngon("Mf"); - //Sf.write_ngon("Sf"); + Mf.write_ngon("Mf"); + Sf.write_ngon("Sf"); puts("Making point edges..."); Mf.make_point_edges(); From a5114a3a64bc28639747057b376df972f462ee5d Mon Sep 17 00:00:00 2001 From: imadhammani Date: Mon, 7 Oct 2024 18:47:43 +0200 Subject: [PATCH 30/86] XCore intersectMesh: fixed hedge pre-sorting criterion --- Cassiopee/XCore/XCore/intersectMesh/dcel.cpp | 45 ++++++++++++++------ 1 file changed, 31 insertions(+), 14 deletions(-) diff --git a/Cassiopee/XCore/XCore/intersectMesh/dcel.cpp b/Cassiopee/XCore/XCore/intersectMesh/dcel.cpp index 6c8f0a317..46db7599d 100644 --- a/Cassiopee/XCore/XCore/intersectMesh/dcel.cpp +++ b/Cassiopee/XCore/XCore/intersectMesh/dcel.cpp @@ -389,10 +389,10 @@ void Dcel::init_hedges_and_faces(Smesh &M, E_Int color) for (E_Int pid = 0; pid < M.np; pid++) { auto &hedges = list[pid]; - assert(!hedges.empty()); + assert(hedges.size() >= 2); const E_Float *N = &pnormals[3*pid]; - assert(Sign(K_MATH::norm(N, 3)-1) == 0); + //assert(Sign(K_MATH::norm(N, 3)-1) == 0); sort_leaving_hedges(hedges, N, M); @@ -635,7 +635,7 @@ void Dcel::set_cycles_inout(const Smesh &M, const Smesh &S) } E_Float NORM = K_MATH::norm(N, 3); - assert(Sign(NORM -1) == 0); + //assert(Sign(NORM -1) == 0); E_Float cmp = K_MATH::dot(N, cp, 3); @@ -985,16 +985,16 @@ void Dcel::trace_hedge(Hedge *sh, const Smesh &M, const Smesh &S, E_Int hid) E_Float dp = K_MATH::dot(fN, dir, 3); for (E_Int i = 0; i < 3; i++) proj[i] = dir[i] - dp * fN[i]; - E_Float dx = px + 2*proj[0]; - E_Float dy = py + 2*proj[1]; - E_Float dz = pz + 2*proj[2]; + E_Float dx = px + 10000*proj[0]; + E_Float dy = py + 10000*proj[1]; + E_Float dz = pz + 10000*proj[2]; Hedge *h = current_face->rep; E_Int reached = 0; E_Int hit = 0; E_Float ix, iy, iz; - ix = iy = iz = -10000; + ix = iy = iz = EFLOATMIN; while (!reached && !found) { @@ -1094,7 +1094,7 @@ void Dcel::trace_hedge(Hedge *sh, const Smesh &M, const Smesh &S, E_Int hid) void Dcel::find_intersections_3D(const Smesh &M, const Smesh &S) { - puts("Isolating s_hedges..."); + puts(" Isolating s_hedges..."); std::vector s_hedges; @@ -1103,23 +1103,40 @@ void Dcel::find_intersections_3D(const Smesh &M, const Smesh &S) assert(h->twin == H[i+1]); assert(h->color == Dcel::BLACK); Hedge *t = h->twin; + assert(h != NULL); + assert(t != NULL); Vertex *p = h->orig; Vertex *q = t->orig; - if (cmp_vtx(p, q) <= 0) { + assert(p != NULL); + assert(q != NULL); + E_Int cmp = cmp_vtx(p, q); + assert(cmp != 0); + if (cmp_vtx(p, q) < 0) { s_hedges.push_back(h); } else { s_hedges.push_back(t); } } - puts("Sorting s_hedges..."); + puts(" Sorting s_hedges..."); std::sort(s_hedges.begin(), s_hedges.end(), [&] (Hedge *h, Hedge *w) { - return cmp_vtx(h->orig, w->orig) <= 0; + assert(h->twin != w); + assert(w->twin != h); + + E_Int cmp = cmp_vtx(h->orig, w->orig); + if (cmp < 0) return true; + if (cmp > 0) return false; + + cmp = cmp_vtx(h->twin->orig, w->twin->orig); + assert(cmp != 0); + + if (cmp < 0) return true; + return false; }); - puts("Tracing edges..."); + puts(" Tracing edges..."); for (size_t hid = 0; hid < s_hedges.size(); hid++) { Hedge *sh = s_hedges[hid]; @@ -1153,7 +1170,7 @@ void Dcel::sort_leaving_hedges(std::vector &leaving, for (E_Int i = 0; i < 3; i++) ref_vec[i] /= NORM; - assert(Sign(K_MATH::norm(ref_vec, 3) - 1) == 0); + //assert(Sign(K_MATH::norm(ref_vec, 3) - 1) == 0); std::vector angles; @@ -1361,7 +1378,7 @@ void Dcel::resolve_hedges(const Smesh &M, const Smesh &S) } E_Float NORM = K_MATH::norm(N, 3); - assert(Sign(NORM -1) == 0); + //assert(Sign(NORM -1) == 0); sort_leaving_hedges(leaving, N, M); From 0cd895193e42b05e048c4b5ea153ecad46378ea8 Mon Sep 17 00:00:00 2001 From: imadhammani Date: Mon, 7 Oct 2024 18:49:08 +0200 Subject: [PATCH 31/86] XCore intersectMesh: Mesh project on triangles and quads --- Cassiopee/XCore/XCore/intersectMesh/mesh.cpp | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/Cassiopee/XCore/XCore/intersectMesh/mesh.cpp b/Cassiopee/XCore/XCore/intersectMesh/mesh.cpp index b845261bb..4f3edfd4a 100644 --- a/Cassiopee/XCore/XCore/intersectMesh/mesh.cpp +++ b/Cassiopee/XCore/XCore/intersectMesh/mesh.cpp @@ -87,6 +87,8 @@ void IMesh::triangulate_face_set(bool propagate) assert(skin.size() > 0); + patch.clear(); + for (E_Int fid : faces_to_tri) { auto &pn = F[fid]; @@ -117,20 +119,16 @@ void IMesh::triangulate_face_set(bool propagate) skin.push_back(NF); + // Update patch + patch.insert(fid); + patch.insert(NF); + NF++; } assert(NF == nf + face_incr); nf = NF; - - faces_to_tri.clear(); - - /* - for (E_Int cid = 0; cid < nc; cid++) { - assert(C[cid].size() == 6 || C[cid].size() == 7); - } - */ } struct DEdge { @@ -337,8 +335,8 @@ E_Int IMesh::RayFaceIntersect(E_Float px, E_Float py, E_Float pz, E_Float dx, { const auto &pn = F[fid]; - // TODO(Imad): hexa mesh for now - assert(pn.size() == 4); + // TODO(Imad): quads or tris for now + assert(pn.size() == 4 || pn.size() == 3); E_Int a = pn[0], b = pn[1], c = pn[2]; @@ -361,6 +359,8 @@ E_Int IMesh::RayFaceIntersect(E_Float px, E_Float py, E_Float pz, E_Float dx, return 1; } + if (pn.size() == 3) return 0; + E_Int d = pn[3]; TI.tri = 1; From e1b7f2ddc547a16c38e9fdaeb9b4039e31e36d7b Mon Sep 17 00:00:00 2001 From: imadhammani Date: Mon, 7 Oct 2024 18:49:46 +0200 Subject: [PATCH 32/86] XCore intersectMesh: added slave mesh refinement (WIP) --- Cassiopee/XCore/XCore/intersectMesh/mesh.h | 2 + .../XCore/XCore/intersectMesh/meshRefine.cpp | 255 +++++++++++++++++- 2 files changed, 252 insertions(+), 5 deletions(-) diff --git a/Cassiopee/XCore/XCore/intersectMesh/mesh.h b/Cassiopee/XCore/XCore/intersectMesh/mesh.h index d7bc8de40..c0a50578d 100644 --- a/Cassiopee/XCore/XCore/intersectMesh/mesh.h +++ b/Cassiopee/XCore/XCore/intersectMesh/mesh.h @@ -96,6 +96,8 @@ struct IMesh { E_Float dy, E_Float dz, TriangleIntersection &TI, E_Int II); void triangulate_face_set(bool propagate = true); + + size_t refine_slave(const IMesh &master); void hash_patch(); diff --git a/Cassiopee/XCore/XCore/intersectMesh/meshRefine.cpp b/Cassiopee/XCore/XCore/intersectMesh/meshRefine.cpp index e398b0708..4c3ad7290 100644 --- a/Cassiopee/XCore/XCore/intersectMesh/meshRefine.cpp +++ b/Cassiopee/XCore/XCore/intersectMesh/meshRefine.cpp @@ -23,6 +23,7 @@ #include "triangle.h" #include "io.h" +#include "primitives.h" E_Int meshes_mutual_refinement(IMesh &M, IMesh &S) { @@ -32,29 +33,273 @@ E_Int meshes_mutual_refinement(IMesh &M, IMesh &S) S.init_adaptation_data(); M.init_adaptation_data(); + E_Int S_np_before = S.np; + do { iter++; + // Refine M wrt S + S.make_point_faces(); M.make_bbox(); - M.hash_skin(); + M.hash_skin(); // TODO(Imad): hash_patch! refM = M.refine(S); printf("Refined mf: %zu\n", refM); - if (refM > 0) { + // Refine S wrt M + if (iter == 1 || (iter > 1 && refM > 0)) { M.make_point_faces(); S.make_bbox(); - S.hash_skin(); + S.hash_skin(); // TODO(Imad): hash_patch! - refS = S.refine(M); + refS = S.refine_slave(M); printf("Refined sf: %zu\n", refS); } - } while (refS > 0); + + } while (refM > 0 || refS > 0); + + S.make_point_faces(); + M.hash_skin(); + + // Project all the new points from S onto M faces + // TODO(Imad): shouldn't this step be done after conformizing? + + for (E_Int spid = S_np_before; spid < S.np; spid++) { + const auto &pf = S.P2F[spid]; + std::vector stids; + for (auto stid : pf) { + if (S.F[stid].size() == 3) stids.push_back(stid); + } + + // Compute the normal at spid := sum of the normals of stids + E_Float N[3] = {0}; + for (auto stid : stids) { + const auto &pn = S.F[stid]; + E_Int a = pn[0], b = pn[1], c = pn[2]; + E_Float v0[3] = {S.X[b]-S.X[a], S.Y[b]-S.Y[a], S.Z[b]-S.Z[a]}; + E_Float v1[3] = {S.X[c]-S.X[a], S.Y[c]-S.Y[a], S.Z[c]-S.Z[a]}; + E_Float fN[3]; + K_MATH::cross(v0, v1, fN); + N[0] += fN[0]; + N[1] += fN[1]; + N[2] += fN[2]; + } + + E_Float NORM = K_MATH::norm(N, 3); + assert(Sign(NORM) != 0); + N[0] /= NORM; + N[1] /= NORM; + N[2] /= NORM; + + TriangleIntersection TI; + E_Int hit = 0; + + if (M.is_point_inside(S.X[spid], S.Y[spid], S.Z[spid])) { + hit = M.project_point(S.X[spid], S.Y[spid], S.Z[spid], + -N[0], -N[1], -N[2], TI, spid - S_np_before); + } else { + hit = M.project_point(S.X[spid], S.Y[spid], S.Z[spid], + N[0], N[1], N[2], TI, spid - S_np_before); + } + + assert(hit); + assert(M.patch.find(TI.face) != M.patch.end()); + + printf("Spid: %f %f %f -> Proj: %f %f %f (t = %f)\n", + S.X[spid], S.Y[spid], S.Z[spid], TI.x, TI.y, TI.z, TI.t); + + // Replace the point by its projection + S.X[spid] = TI.x; + S.Y[spid] = TI.y; + S.Z[spid] = TI.z; + } return 0; } +struct Fidn { + E_Int fid; + E_Float N[3]; +}; + +size_t IMesh::refine_slave(const IMesh &master) +{ + const auto &mpatch = master.patch; + std::set mpids; + for (const auto mfid : mpatch) { + assert(master.face_is_active(mfid)); + const auto &pn = master.F[mfid]; + for (const auto p : pn) mpids.insert(p); + } + + std::vector spatch; + spatch.reserve(patch.size()); + for (const auto fid : patch) { + const auto &pn = F[fid]; + assert(face_is_tri(fid)); + E_Int a = pn[0], b = pn[1], c = pn[2]; + E_Float v0[3] = {X[b]-X[a], Y[b]-Y[a], Z[b]-Z[a]}; + E_Float v1[3] = {X[c]-X[a], Y[c]-Y[a], Z[c]-Z[a]}; + Fidn fidn; + fidn.fid = fid; + K_MATH::cross(v0, v1, fidn.N); + E_Float NORM = K_MATH::norm(fidn.N, 3); + assert(Sign(NORM) != 0); + fidn.N[0] /= NORM; + fidn.N[1] /= NORM; + fidn.N[2] /= NORM; + spatch.push_back(fidn); + } + + const auto &mX = master.X; + const auto &mY = master.Y; + const auto &mZ = master.Z; + + // Master points to Slave triangles + std::map> mpids_to_stids; + + // TODO(Imad): how to accelerate this? + for (const auto &fidn : spatch) { + const E_Int fid = fidn.fid; + const E_Float *N = fidn.N; + const auto &pn = F[fid]; + E_Int a = pn[0]; + E_Int b = pn[1]; + E_Int c = pn[2]; + + for (auto mpid : mpids) { + // Does the projection of mpid along N live in the triangle fid? + + E_Float V[3] = {mX[mpid]-X[a], mY[mpid]-Y[a], mZ[mpid]-Z[a]}; + E_Float dp = K_MATH::dot(V, N, 3); + + E_Float Proj[3]; + Proj[0] = mX[mpid] - dp * N[0]; + Proj[1] = mY[mpid] - dp * N[1]; + Proj[2] = mZ[mpid] - dp * N[2]; + + bool inside = Triangle::is_point_inside(Proj[0], Proj[1], Proj[2], + X[a], Y[a], Z[a], + X[b], Y[b], Z[b], + X[c], Y[c], Z[c]); + + if (inside) { + mpids_to_stids[mpid].push_back(fid); + } + } + } + + // Invert the map: S triangles to all the M points (projection) within them + std::map> stids_to_mpids; + + for (const auto &m2s : mpids_to_stids) { + E_Int mpid = m2s.first; + const auto &stids = m2s.second; + for (const auto tid : stids) { + stids_to_mpids[tid].push_back(mpid); + } + } + + // Keep the S triangles containing three of more M points + std::map> filtered_stids_map; + + for (const auto &s2m : stids_to_mpids) { + if (s2m.second.size() >= 3) { + filtered_stids_map.insert({s2m.first, s2m.second}); + } + } + + // Sensor + std::map> ref_stids_to_mtids; + + for (const auto &s2m : filtered_stids_map) { + auto stid = s2m.first; + const auto &mpids = s2m.second; + + // For every sface, how many points are contained within mface? + std::map mcontained; + + for (auto mpid : mpids) { + // M tris sharing mpid + const auto &mtris = master.P2F[mpid]; + + for (auto mtri : mtris) { + assert(master.face_is_active(mtri)); + + // M tri should belong to patch + if (master.patch.find(mtri) == master.patch.end()) continue; + + // S tri contains another point of M tri + mcontained[mtri]++; + } + } + + for (const auto &mfdat : mcontained) { + E_Int mtid = mfdat.first; + + // The number of points of mtid contained within stid... + size_t npts = mfdat.second; + + // ... should be at most equal to the stride of mtid! + assert(npts <= master.F[mtid].size()); + + // Discard mtid if it is not completely enclosed by stid + if (npts < master.F[mtid].size()) continue; + + // Discard sface if it is a duplicate of mface + if (faces_are_dups(stid, mtid, master)) continue; + + // Add mtid to the set of faces enclosed by stid + ref_stids_to_mtids[stid].push_back(mtid); + } + } + + //printf("Faces to refine: %zu\n", ref_mfaces_to_sfaces.size()); + + E_Int iter = 0; + size_t ret = 0; + + while (!ref_stids_to_mtids.empty()) { + iter++; + + auto ref_data = smooth_ref_data(ref_stids_to_mtids); + + auto ref_faces = prepare_for_refinement(ref_data); + + ret += ref_faces.size(); + + refine_faces(ref_faces); + + std::map> new_sensor; + + for (const auto &fdata : ref_stids_to_mtids) { + E_Int parent = fdata.first; + const auto &mtids = fdata.second; + + const auto &children = fchildren[parent]; + + for (E_Int child : children) { + for (E_Int mtid : mtids) { + if (face_contains_sface(child, mtid, master)) { + // TODO(Imad): I think we can safely discard this check + assert(!faces_are_dups(child, mtid, master)); + new_sensor[child].push_back(mtid); + } + } + } + + // Update mpatch + patch.erase(parent); + for (E_Int child : children) patch.insert(child); + } + + ref_stids_to_mtids = new_sensor; + } + + return ret; +} + size_t IMesh::refine(const IMesh &S) { // Hash mpatch From 34a19b447d4216ded34da0a3ee2a55a774b5921d Mon Sep 17 00:00:00 2001 From: imadhammani Date: Mon, 7 Oct 2024 18:50:50 +0200 Subject: [PATCH 33/86] XCore intersectMesh: do not clear mesh patch before intersect function --- Cassiopee/XCore/XCore/intersectMesh/intersectMesh.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Cassiopee/XCore/XCore/intersectMesh/intersectMesh.cpp b/Cassiopee/XCore/XCore/intersectMesh/intersectMesh.cpp index c374aec8e..032353fbe 100644 --- a/Cassiopee/XCore/XCore/intersectMesh/intersectMesh.cpp +++ b/Cassiopee/XCore/XCore/intersectMesh/intersectMesh.cpp @@ -320,8 +320,8 @@ PyObject *K_XCORE::intersectMesh(PyObject *self, PyObject *args) M.orient_skin(OUT); S.orient_skin(IN); - M.patch.clear(); - for (E_Int fid : M.skin) M.patch.insert(fid); + //M.patch.clear(); + //for (E_Int fid : M.skin) M.patch.insert(fid); printf("Master patch: %zu faces\n", M.patch.size()); From 5c501b49b63e1690084d11c62a8f5503c06006e6 Mon Sep 17 00:00:00 2001 From: imadhammani Date: Mon, 7 Oct 2024 18:52:14 +0200 Subject: [PATCH 34/86] XCore intersectMesh: update how slave mesh is refined + triangulate slave patch before refinement --- .../prepareMeshesForIntersection.cpp | 31 ++++++++++++++----- 1 file changed, 23 insertions(+), 8 deletions(-) diff --git a/Cassiopee/XCore/XCore/intersectMesh/prepareMeshesForIntersection.cpp b/Cassiopee/XCore/XCore/intersectMesh/prepareMeshesForIntersection.cpp index 37516a1d6..fe86753de 100644 --- a/Cassiopee/XCore/XCore/intersectMesh/prepareMeshesForIntersection.cpp +++ b/Cassiopee/XCore/XCore/intersectMesh/prepareMeshesForIntersection.cpp @@ -45,12 +45,12 @@ PyObject *K_XCORE::prepareMeshesForIntersection(PyObject *self, PyObject *args) IMesh &M = *(IMesh *)PyCapsule_GetPointer(MASTER, "IntersectMesh"); - M.make_skin(); - assert(M.patch.empty()); - for (E_Int fid : M.skin) { - assert(fid < M.nf); - M.patch.insert(fid); - } + //M.make_skin(); + //assert(M.patch.empty()); + //for (E_Int fid : M.skin) { + // assert(fid < M.nf); + // M.patch.insert(fid); + //} Karray sarray; @@ -81,11 +81,13 @@ PyObject *K_XCORE::prepareMeshesForIntersection(PyObject *self, PyObject *args) // Init master/slave meshes IMesh S(*sarray.cn, sarray.X, sarray.Y, sarray.Z, sarray.npts); S.make_skin(); + S.patch.clear(); + + assert(tag_size == S.np); for (E_Int fid : S.skin) { const auto &pn = S.F[fid]; size_t stride = pn.size(); - assert(stride == 3 || stride == 4); E_Int keep = 1; @@ -100,8 +102,18 @@ PyObject *K_XCORE::prepareMeshesForIntersection(PyObject *self, PyObject *args) if (keep) S.patch.insert(fid); } + printf("S.patch size before triangulation: %lu\n", S.patch.size()); + + S.faces_to_tri.clear(); + for (auto fid : S.patch) S.faces_to_tri.insert(fid); + S.triangulate_face_set(false); + + printf("S.patch size after triangulation: %lu\n", S.patch.size()); + puts("Adapting intersection zones..."); + printf("M.patch size before refinement: %lu\n", M.patch.size()); + ret = meshes_mutual_refinement(M, S); if (ret != 0) { Karray_free_ngon(sarray); @@ -109,11 +121,14 @@ PyObject *K_XCORE::prepareMeshesForIntersection(PyObject *self, PyObject *args) return NULL; } + printf("M.patch size after refinement: %lu\n", M.patch.size()); + printf("S.patch size after refinement: %lu\n", S.patch.size()); + puts("Extracting conformized meshes..."); S = S.extract_conformized(); M = M.extract_conformized(); - + // Export puts("Exporting to CGNS format..."); From 3abce90140f8344a2da8cb29cfeec2c37fd41f40 Mon Sep 17 00:00:00 2001 From: imadhammani Date: Wed, 9 Oct 2024 17:24:17 +0200 Subject: [PATCH 35/86] XCore intersectMesh: fix name change in keep field copying --- Cassiopee/XCore/XCore/PyTree.py | 48 ++++++++++++++++++++------------- 1 file changed, 30 insertions(+), 18 deletions(-) diff --git a/Cassiopee/XCore/XCore/PyTree.py b/Cassiopee/XCore/XCore/PyTree.py index 03671263c..1af7e1913 100644 --- a/Cassiopee/XCore/XCore/PyTree.py +++ b/Cassiopee/XCore/XCore/PyTree.py @@ -392,45 +392,57 @@ def prepareMeshesForIntersection(IM, slave): keep = I.getNodeFromName(zs, 'keep') - s, spatch = xcore.prepareMeshesForIntersection(IM, s, tag) + m, mpatch, s, spatch = xcore.prepareMeshesForIntersection(IM, s, tag) - zso = I.createZoneNode("S_adapted", s) + zmo = I.createZoneNode("M_adapted", m) + zbcs = I.createUniqueChild(zmo, 'ZoneBC', 'ZoneBC_t') + I.newBC(name="intersection_patch", pointList=mpatch, family='UserDefined', parent=zbcs) + ma = C.newPyTree(["M_adapted", zmo]) + zso = I.createZoneNode("S_adapted", s) zbcs = I.createUniqueChild(zso, 'ZoneBC', 'ZoneBC_t') - I.newBC(name="intersection_patch", pointList=spatch, family='UserDefined', parent=zbcs) + sa = C.newPyTree(["S_adapted", zso]) - ts = C.newPyTree(["S_adapted", zso]) + try: import Intersector.PyTree as XOR + except: raise ImportError("XCore.PyTree: requires Intersector.PyTree module.") + + ma = XOR.closeCells(ma) + sa = XOR.closeCells(sa) if keep is not None: - C._cpVars(slave, 'centers:keep', ts, 'centers:keep') + C._cpVars(slave, 'centers:keep', sa, 'centers:keep') - return ts + return ma, sa -def intersectMesh(IM, slave): - zs = I.getZones(slave)[0] +def intersectMesh(master, slave): + zm = I.getZones(master)[0] + marr = C.getFields(I.__GridCoordinates__, zm, api=3)[0] + mpatch = I.getNodeFromName(zm, "intersection_patch")[2][0][1] + zs = I.getZones(slave)[0] keep = I.getNodeFromName(zs, 'keep') - - s = C.getFields(I.__GridCoordinates__, zs, api=3)[0] - + sarr = C.getFields(I.__GridCoordinates__, zs, api=3)[0] spatch = I.getNodeFromName(zs, "intersection_patch")[2][0][1] - - sinter = xcore.intersectMesh(IM, s, spatch) - zso = I.createZoneNode("S_inter", sinter) + marr, sarr = xcore.intersectMesh(marr, mpatch, sarr, spatch) - ts = C.newPyTree(["S_inter", zso]) + zmo = I.createZoneNode("mi", marr) + zso = I.createZoneNode("si", sarr) + + mi = C.newPyTree(["mi", zmo]) + si = C.newPyTree(["si", zso]) try: import Intersector.PyTree as XOR except: raise ImportError("XCore.PyTree: requires Intersector.PyTree module.") - ts = XOR.closeCells(ts) + mi = XOR.closeCells(mi) + si = XOR.closeCells(si) if keep is not None: - C._cpVars(slave, 'centers:keep', ts, 'centers:keep') + C._cpVars(slave, 'centers:keep', si, 'centers:keep') - return ts + return mi, si def IntersectMesh_ExtractFaceSet(AM): return xcore.IntersectMesh_ExtractFaceSet(AM) From 5a8e2f139708d56808a1a2ffc74f89c514ab48cb Mon Sep 17 00:00:00 2001 From: imadhammani Date: Wed, 9 Oct 2024 17:25:33 +0200 Subject: [PATCH 36/86] XCore intersectMesh: add alternative way to trace edge paths --- Cassiopee/XCore/XCore/intersectMesh/dcel.cpp | 138 +++++-- Cassiopee/XCore/XCore/intersectMesh/dcel.h | 4 +- Cassiopee/XCore/XCore/intersectMesh/trace.cpp | 372 ++++++++++++++++++ Cassiopee/XCore/srcs.py | 1 + 4 files changed, 490 insertions(+), 25 deletions(-) create mode 100644 Cassiopee/XCore/XCore/intersectMesh/trace.cpp diff --git a/Cassiopee/XCore/XCore/intersectMesh/dcel.cpp b/Cassiopee/XCore/XCore/intersectMesh/dcel.cpp index 46db7599d..83a2d515c 100644 --- a/Cassiopee/XCore/XCore/intersectMesh/dcel.cpp +++ b/Cassiopee/XCore/XCore/intersectMesh/dcel.cpp @@ -240,7 +240,11 @@ void Dcel::set_face_labels(std::vector &F) f->oid[Dcel::BLACK] = B->left->oid[Dcel::BLACK]; } else { // Second case: the face is single color + // Only single color possible is RED, otherwise intersection problem + // is ill-posed Hedge *REP = (R != NULL) ? R : B; + assert(REP == R); + assert(REP->color == Dcel::RED); assert(REP->left); f->oid[REP->color] = REP->left->oid[REP->color]; } @@ -300,9 +304,12 @@ Dcel::Dcel(Smesh &M0, Smesh &M1) { init_vertices(M0, M1); Q.inorder(V); + size_t count = 0; for (size_t i = 0; i < V.size(); i++) { V[i]->id = i; + if (V[i]->oid[0] != -1 && V[i]->oid[1] != -1) count++; } + printf("Duplicate points: %lu\n", count); init_hedges_and_faces(M0, RED); @@ -696,7 +703,9 @@ void Dcel::locate_spoints(const Smesh &M, const Smesh &S) for (size_t mf = 0; mf < pf.size() && !found; mf++) { - const auto &pn = M.F[pf[mf]]; + E_Int fid = pf[mf]; + + const auto &pn = M.F[fid]; E_Float o[3] = {0, 0, 0}; @@ -722,8 +731,9 @@ void Dcel::locate_spoints(const Smesh &M, const Smesh &S) found = 1; - ploc.fid = pf[mf]; + ploc.fid = fid; + // TODO(Imad): this absolutely needs to be robust if (Sign(v) == 0) ploc.e_idx = i; else if (Sign(1-u) == 0) ploc.v_idx = (i+1)%pn.size(); else if (Sign(1-w) == 0) ploc.v_idx = i; @@ -818,7 +828,7 @@ void Dcel::handle_intersecting_endpoint(Vertex *v, const Smesh &M) } E_Int Dcel::get_next_face(const Smesh &M, E_Float px, E_Float py, E_Float pz, - const std::vector &pf, E_Float dir[3]) + const std::vector &pf, E_Float dir[3], E_Int hid) { E_Int next_face = -1; E_Float t_min = EFLOATMAX; @@ -841,21 +851,26 @@ E_Int Dcel::get_next_face(const Smesh &M, E_Float px, E_Float py, E_Float pz, while (1) { + if (hid == 4108) hedge_write("h", h); + Vertex *a = h->orig; Vertex *b = h->twin->orig; - E_Float dx = px + 10000 * proj[0]; - E_Float dy = py + 10000 * proj[1]; - E_Float dz = pz + 10000 * proj[2]; + E_Float dx = px + 1.0 * proj[0]; + E_Float dy = py + 1.0 * proj[1]; + E_Float dz = pz + 1.0 * proj[2]; - E_Float t; + E_Float t = -1.0, s = -1.0; hit = EdgeEdgeIntersect( px, py, pz, dx, dy, dz, a->x, a->y, a->z, b->x, b->y, b->z, - t); + t, s); + + if (hid == 555) + printf("hit: %d - t: %f - s: %f\n", hit, t, s); if (hit) { if (t < t_min) { @@ -887,6 +902,8 @@ E_Int Dcel::get_next_face(const Smesh &M, E_Float px, E_Float py, E_Float pz, return next_face; } +std::vector points; + void Dcel::trace_hedge(Hedge *sh, const Smesh &M, const Smesh &S, E_Int hid) { Vertex *p = sh->orig; @@ -920,19 +937,31 @@ void Dcel::trace_hedge(Hedge *sh, const Smesh &M, const Smesh &S, E_Int hid) // Handle potential intersection of starting point - handle_intersecting_endpoint(p, M); - handle_intersecting_endpoint(q, M); + //handle_intersecting_endpoint(p, M); + //handle_intersecting_endpoint(q, M); // Determine the starting face - E_Int start_face = get_next_face(M, p->x, p->y, p->z, test_faces, dir); - + E_Int start_face = test_faces[0]; + if (test_faces.size() > 1) + start_face = get_next_face(M, p->x, p->y, p->z, test_faces, dir, hid); + + if (start_face == -1) { + hedge_write("sh", sh); + point_write("orig", sh->orig); + std::vector faces; + for (auto fid : test_faces) { + faces.push_back(F[fid]); + } + printf("test_faces: %lu\n", test_faces.size()); + faces_write("test_faces", faces); + } assert(start_face != -1); // Trace E_Int found = 0; E_Int walk = 0; - E_Int max_walk = 100; + E_Int max_walk = 5; Face *current_face = F[start_face]; @@ -985,9 +1014,9 @@ void Dcel::trace_hedge(Hedge *sh, const Smesh &M, const Smesh &S, E_Int hid) E_Float dp = K_MATH::dot(fN, dir, 3); for (E_Int i = 0; i < 3; i++) proj[i] = dir[i] - dp * fN[i]; - E_Float dx = px + 10000*proj[0]; - E_Float dy = py + 10000*proj[1]; - E_Float dz = pz + 10000*proj[2]; + E_Float dx = px + 1.0 * proj[0]; + E_Float dy = py + 1.0 * proj[1]; + E_Float dz = pz + 1.0 * proj[2]; Hedge *h = current_face->rep; E_Int reached = 0; @@ -1022,6 +1051,7 @@ void Dcel::trace_hedge(Hedge *sh, const Smesh &M, const Smesh &S, E_Int hid) if (x != NULL) { + /* // Stop if reached destination if (x->oid[1] != -1) { assert(x == q); @@ -1033,7 +1063,7 @@ void Dcel::trace_hedge(Hedge *sh, const Smesh &M, const Smesh &S, E_Int hid) E_Int mpid = x->oid[0]; const auto &pf = M.P2F[mpid]; - E_Int next_fid = get_next_face(M, x->x, x->y, x->z, pf, dir); + E_Int next_fid = get_next_face(M, x->x, x->y, x->z, pf, dir, hid); assert(next_fid != -1); assert(next_fid != current_fid); current_face = F[next_fid]; @@ -1045,6 +1075,36 @@ void Dcel::trace_hedge(Hedge *sh, const Smesh &M, const Smesh &S, E_Int hid) current_face = h->twin->left; } + */ + + + bool is_mpoint = x->oid[0] != -1; + bool is_spoint = x->oid[1] != -1; + + // Stictly an M point, get the next face + + if (is_mpoint && !is_spoint) { + E_Int mpid = x->oid[0]; + const auto &pf = M.P2F[mpid]; + E_Int next_fid = get_next_face(M, x->x, x->y, x->z, pf, dir, hid); + assert(next_fid != -1); + assert(next_fid != current_fid); + current_face = F[next_fid]; + } + + + // S point, must be q since edges from S do not cross + else if (is_spoint) { + assert(x == q); + assert(cmp_vtx(x, q) == 0); + found = 1; + } + + else { + assert(0); + } + + } else { // Hit the inside of an edge @@ -1055,6 +1115,8 @@ void Dcel::trace_hedge(Hedge *sh, const Smesh &M, const Smesh &S, E_Int hid) assert(xit == NULL); x = new Vertex(ix, iy, iz); + assert(x->oid[0] == -1); + assert(x->oid[1] == -1); x->id = V.size(); V.push_back(x); x->xhedge = h; @@ -1065,10 +1127,12 @@ void Dcel::trace_hedge(Hedge *sh, const Smesh &M, const Smesh &S, E_Int hid) } - if (found) break; - assert(x); + points.push_back(Point(x->x, x->y, x->z)); + + if (found) break; + cut_hedge_at_vertex(current_hedge, x); current_hedge = current_hedge->next; @@ -1085,7 +1149,13 @@ void Dcel::trace_hedge(Hedge *sh, const Smesh &M, const Smesh &S, E_Int hid) } } - assert(reached == 0); + if (reached != 0) { + fprintf(stderr, " Reached start_hedge!\n"); + face_write("last_face", current_face); + assert(0); + abort(); + } + walk++; } @@ -1136,15 +1206,34 @@ void Dcel::find_intersections_3D(const Smesh &M, const Smesh &S) return false; }); + for (Vertex *v : V) { + if (v->oid[1] != -1 && v->oid[0] == -1) { + handle_intersecting_endpoint(v, M); + } + } + puts(" Tracing edges..."); for (size_t hid = 0; hid < s_hedges.size(); hid++) { Hedge *sh = s_hedges[hid]; - printf("Tracing hedge %zu / %zu\n", hid+1, s_hedges.size()); + //printf("Tracing hedge %zu / %zu\n", hid+1, s_hedges.size()); + + //trace_hedge(sh, M, S, hid); + trace_hedge_2(sh, M, S, hid); + } + + exit(0); + + //point_write("xpoints", points); - trace_hedge(sh, M, S, hid); + /* + std::vector all_points; + for (Vertex *v : V) { + all_points.push_back(Point(v->x, v->y, v->z)); } + point_write("all_points", all_points); + */ } void Dcel::sort_leaving_hedges(std::vector &leaving, @@ -1410,6 +1499,7 @@ void Dcel::reconstruct(const Smesh &M, const Smesh &S) check_faces(H, F); - //write_degen_faces("degen"); - //write_inner_faces("inner"); + write_degen_faces("degen"); + write_inner_faces("inner"); + write_outer_faces("outer"); } diff --git a/Cassiopee/XCore/XCore/intersectMesh/dcel.h b/Cassiopee/XCore/XCore/intersectMesh/dcel.h index 74a3d066a..c02600d93 100644 --- a/Cassiopee/XCore/XCore/intersectMesh/dcel.h +++ b/Cassiopee/XCore/XCore/intersectMesh/dcel.h @@ -102,11 +102,13 @@ struct Dcel { void reconstruct(const Smesh &M, const Smesh &S); E_Int get_next_face(const Smesh &M, E_Float px, E_Float py, E_Float pz, - const std::vector &pf, E_Float dir[3]); + const std::vector &pf, E_Float dir[3], E_Int hid); void handle_intersecting_endpoint(Vertex *v, const Smesh &M); void trace_hedge(Hedge *sh, const Smesh &M, const Smesh &S, E_Int hid); + + E_Int trace_hedge_2(Hedge *sh, const Smesh &M, const Smesh &S, E_Int hid); void sort_leaving_hedges(std::vector &leaving, const E_Float N[3], const Smesh &M) const; diff --git a/Cassiopee/XCore/XCore/intersectMesh/trace.cpp b/Cassiopee/XCore/XCore/intersectMesh/trace.cpp new file mode 100644 index 000000000..68f5ee203 --- /dev/null +++ b/Cassiopee/XCore/XCore/intersectMesh/trace.cpp @@ -0,0 +1,372 @@ +#include "dcel.h" +#include "smesh.h" +#include "primitives.h" +#include "hedge.h" +#include "io.h" + +static +bool ray_edge_intersect(E_Float ox, E_Float oy, E_Float oz, + E_Float dx, E_Float dy, E_Float dz, + E_Float px, E_Float py, E_Float pz, + E_Float qx, E_Float qy, E_Float qz, + E_Float &t, E_Float &u) +{ + E_Float v[3]= {px-ox, py-oy, pz-oz}; + + E_Float dl[3] = {qx-px, qy-py, qz-pz}; + + E_Float dr[3] = {dx, dy, dz}; + + /* + E_Float w[3]; + K_MATH::cross(v, dl, w); + E_Float det = K_MATH::dot(w, dr, 3); + + // ray and edge must be coplanar + if (Sign(det) != 0) return false; + */ + + // ray and edge must not be parallel + E_Float n[3]; + K_MATH::cross(dr, dl, n); + E_Float denom = K_MATH::dot(n, n, 3); + if (Sign(denom) == 0) return false; + + E_Float tmp[3]; + K_MATH::cross(v, dl, tmp); + + t = K_MATH::dot(tmp, n, 3) / denom; + + if (t < TOL) return false; + + K_MATH::cross(v, dr, tmp); + + u = K_MATH::dot(tmp, n, 3) / denom; + + if (u < -TOL || u > 1 + TOL) return false; + + return true; +} + +static +void get_unit_projected_direction(E_Int fid, const Smesh &M, const E_Float D[3], + E_Float proj[3]) +{ + assert(fid >= 0); + assert(fid < M.nf); + + // Unit normal + const E_Float *fN = &M.fnormals[3*fid]; + + E_Float dp = K_MATH::dot(D, fN, 3); + + proj[0] = D[0] - dp * fN[0]; + proj[1] = D[1] - dp * fN[1]; + proj[2] = D[2] - dp * fN[2]; + E_Float NORM = K_MATH::norm(proj, 3); + proj[0] /= NORM, proj[1] /= NORM, proj[2] /= NORM; +} + +static +E_Int deduce_face(const std::vector &pf, const Smesh &M, + E_Float ox, E_Float oy, E_Float oz, E_Float D[3], + E_Int last_vertex, E_Int last_edge) +{ + // Intersect the projection of D with all the faces in pf + // At least one intersection must exist + // Return the face with the earliest intersection + + // For debugging + E_Int faces_hit = 0; + + E_Float t_min = EFLOATMAX; + E_Int ret_face = -1; + + for (auto fid : pf) { + + // Compute the unit projection of D on this face + + E_Float proj[3]; + get_unit_projected_direction(fid, M, D, proj); + + const auto &pn = M.F[fid]; + const auto &pe = M.F2E[fid]; + assert(pn.size() == pe.size()); + + for (size_t i = 0; i < pn.size(); i++) { + + E_Int p = pn[i]; + E_Int q = pn[(i+1)%pn.size()]; + E_Int e = pe[i]; + + if (p == last_vertex || q == last_vertex || e == last_edge) + continue; + + E_Float t, s; + + bool hit = ray_edge_intersect(ox, oy, oz, + proj[0], proj[1], proj[2], + M.X[p], M.Y[p], M.Z[p], + M.X[q], M.Y[q], M.Z[q], + t, s + ); + + if (hit) { + faces_hit += 1; + + if (t < t_min) { + t_min = t; + ret_face = fid; + } + + // Hit an edge of the face, stop + break; + } + } + } + + // We must have hit a face + assert(faces_hit > 0); + + return ret_face; +} + +static +void get_shared_faces(const Vertex *v, const Smesh &M, std::vector &ret, + E_Int &pid, E_Int &eid) +{ + ret.clear(); + + const auto &loc = v->loc; + + E_Int fid = loc.fid; + assert(fid != -1); + + if (loc.e_idx != -1) { + assert(loc.v_idx == -1); + const auto &pe = M.F2E[fid]; + eid = pe[loc.e_idx]; + const auto &pf = M.E2F[eid]; + assert(pf[0] == fid || pf[1] == fid); + ret.push_back(pf[0]); + // O could be on a boundary edge + if (pf[1] != -1) ret.push_back(pf[1]); + } + else if (loc.v_idx != -1) { + assert(loc.e_idx == -1); + const auto &pn = M.F[fid]; + pid = pn[loc.v_idx]; + const auto &pf = M.P2F[pid]; + // For consistency + bool found_fid = false; + for (auto face : pf) { + ret.push_back(face); + if (face == fid) { + found_fid = true; + } + } + assert(found_fid == true); + } + else { + ret.push_back(fid); + } +} + +E_Int Dcel::trace_hedge_2(Hedge *sh, const Smesh &M, const Smesh &S, E_Int hid) +{ + Vertex *O = sh->orig; + Vertex *T = sh->twin->orig; + E_Float D[3] = {T->x-O->x, T->y-O->y, T->z-O->z}; + E_Float NORM = K_MATH::norm(D, 3); + D[0] /= NORM, D[1] /= NORM, D[2] /= NORM; + + // The origin could be inside a face, on an edge or on a vertex + // If it is inside a face, no problem + // If it is on an edge/vertex, which face is intersected first by sh? + + std::vector orig_faces, tail_faces; + E_Int last_vertex = -1, last_edge = -1; + E_Int dummy; + get_shared_faces(O, M, orig_faces, last_vertex, last_edge); + get_shared_faces(T, M, tail_faces, dummy, dummy); + + // If O is inside fid, we could skip this check + // We keep it for consistency + E_Int starting_face = deduce_face( + orig_faces, M, O->x, O->y, O->z, D, + last_vertex, last_edge + ); + assert(starting_face != -1); + + bool found_tail = false; + E_Int current_fid = starting_face; + E_Float current_pos[3] = {O->x, O->y, O->z}; + + E_Int walk = 0; + E_Int max_walks = 10; + + if (hid == 1663) hedge_write("sh", sh); + + while (!found_tail && walk < max_walks) { + + if (hid == 1663) face_write("current_face", F[current_fid]); + + // We are on current_face + + // If the current_face shares the tail, stop + for (auto fid : tail_faces) { + if (fid == current_fid) { + found_tail = true; + break; + } + } + + if (found_tail) break; + + // The tail is not within current_face, nor is it on one of its + // edges, nor is it one of its vertices + // So we must: + // 1 - project the traced hedge direction on the current face + // 2 - shoot a ray {current position, projected dir} and intersect xedge + // 3 - if intersection is on an xedge endpoint, deduce the next face + // else, travel to the neighbour face of current face wrt to xedge + + // Project D onto current face + E_Float proj[3]; + get_unit_projected_direction(current_fid, M, D, proj); + + E_Int next_fid = -1; + E_Float next_pos[3] = {EFLOATMAX, EFLOATMAX, EFLOATMAX}; + + // Ray-edge intersection + const auto &pn = M.F[current_fid]; + const auto &pe = M.F2E[current_fid]; + bool hit = false; + for (size_t i = 0; i < pn.size(); i++) { + E_Int p = pn[i]; + E_Int q = pn[(i+1)%pn.size()]; + E_Int e = pe[i]; + if (p == last_vertex || q == last_vertex || e == last_edge) + continue; + + E_Float t, s; + hit = ray_edge_intersect( + current_pos[0], current_pos[1], current_pos[2], + proj[0], proj[1], proj[2], + M.X[p], M.Y[p], M.Z[p], + M.X[q], M.Y[q], M.Z[q], + t, s + ); + + if (hit) { + + if (hid == 1663) point_write("hit", current_pos[0] + t * proj[0], current_pos[1] + t * proj[1], current_pos[2] + t * proj[2]); + + // Intersection within the edge + if (s > TOL && s < 1 - TOL) { + + // Simply move to the neighbour face + const auto &pe = M.F2E[current_fid]; + E_Int eid = pe[i]; + last_edge = eid; + last_vertex = -1; + const auto &e = M.E[eid]; + if (e.p == p) assert(e.q == q); + else { + assert(e.p == q); + assert(e.q == p); + } + assert(M.E2F[eid][0] == current_fid || + M.E2F[eid][1] == current_fid); + if (M.E2F[eid][0] == current_fid) + next_fid = M.E2F[eid][1]; + else + next_fid = M.E2F[eid][0]; + // We should be within M still + assert(next_fid != -1); + + // Compute the next_pos + next_pos[0] = current_pos[0] + t * proj[0]; + next_pos[1] = current_pos[1] + t * proj[1]; + next_pos[2] = current_pos[2] + t * proj[2]; + } + + // Intersection on an endpoint + else { + bool hit_p = (s <= TOL); + bool hit_q = (s >= 1 - TOL); + + last_edge = -1; + + if (hit_p) { + assert(hit_q == false); + + // Next_pos is p + next_pos[0] = M.X[p]; + next_pos[1] = M.Y[p]; + next_pos[2] = M.Z[p]; + + last_vertex = p; + + } else if (hit_q) { + + // Next_pos is q + next_pos[0] = M.X[q]; + next_pos[1] = M.Y[q]; + next_pos[2] = M.Z[q]; + + last_vertex = q; + } + + // Exclude current_fid + const auto &pf = M.P2F[last_vertex]; + + /* + std::vector pf(M.P2F[last_vertex]); + E_Int found_fid = false; + for (auto &fid : pf) { + if (fid == current_fid) { + found_fid = true; + fid = pf.back(); + break; + } + } + pf.resize(pf.size()-1); + */ + + next_fid = deduce_face(pf, M, + next_pos[0], next_pos[1], next_pos[2], D, + last_vertex, last_edge + ); + assert(next_fid != -1); + } + + break; + } + } + + if (!hit) { + hedge_write("sh", sh); + face_write("current_face", F[current_fid]); + assert(0); + } + + assert(next_fid != current_fid); + current_fid = next_fid; + current_pos[0] = next_pos[0]; + current_pos[1] = next_pos[1]; + current_pos[2] = next_pos[2]; + walk++; + } + + if (walk >= max_walks) { + fprintf(stderr, "Warning : Could not find the tail after %d max walks!", + max_walks); + assert(0); + return 1; + } + + assert(found_tail); + + return 0; +} diff --git a/Cassiopee/XCore/srcs.py b/Cassiopee/XCore/srcs.py index a939fd62f..3d7316196 100644 --- a/Cassiopee/XCore/srcs.py +++ b/Cassiopee/XCore/srcs.py @@ -37,6 +37,7 @@ 'XCore/intersectMesh/prepareMeshesForIntersection.cpp', 'XCore/intersectMesh/cycle.cpp', 'XCore/intersectMesh/dcel.cpp', + 'XCore/intersectMesh/trace.cpp', 'XCore/intersectMesh/event.cpp', 'XCore/intersectMesh/hedge.cpp', 'XCore/intersectMesh/face.cpp', From 00602dc49e423f05be437c7faddb78e50315a756 Mon Sep 17 00:00:00 2001 From: imadhammani Date: Wed, 9 Oct 2024 17:26:32 +0200 Subject: [PATCH 37/86] XCore intersectMesh: fixed smesh faces gridding --- Cassiopee/XCore/XCore/intersectMesh/smesh.cpp | 56 ++++++++++++++----- 1 file changed, 42 insertions(+), 14 deletions(-) diff --git a/Cassiopee/XCore/XCore/intersectMesh/smesh.cpp b/Cassiopee/XCore/XCore/intersectMesh/smesh.cpp index 71b2b88a2..624fe37b6 100644 --- a/Cassiopee/XCore/XCore/intersectMesh/smesh.cpp +++ b/Cassiopee/XCore/XCore/intersectMesh/smesh.cpp @@ -917,38 +917,66 @@ void Smesh::make_bbox() if (Y[i] > ymax) ymax = Y[i]; if (Z[i] > zmax) zmax = Z[i]; } + + E_Float dx = xmax - xmin; + E_Float dy = ymax - ymin; + E_Float dz = zmax - zmin; + + xmin = xmin - dx*0.01; + ymin = ymin - dy*0.01; + zmin = zmin - dz*0.01; + xmax = xmax + dx*0.01; + ymax = ymax + dy*0.01; + zmax = zmax + dz*0.01; } void Smesh::hash_faces() { - NX = 100; - NY = 100; - NZ = 10; + NX = 50; + NY = 50; + NZ = 50; HX = (xmax - xmin) / NX; HY = (ymax - ymin) / NY; HZ = (zmax - zmin) / NZ; NXY = NX * NY; + E_Int NXYZ = NX * NY * NZ; fmap.clear(); for (E_Int fid = 0; fid < nf; fid++) { const auto &pn = F[fid]; - AABB bbox = AABB_face(pn); + E_Int Imin, Jmin, Kmin; + E_Int Imax, Jmax, Kmax; + + Imin = Jmin = Kmin = NXYZ; + Imax = Jmax = Kmax = -1; - E_Int imin = floor((bbox.xmin - xmin) / HX); - E_Int imax = floor((bbox.xmax - xmin) / HX); - E_Int jmin = floor((bbox.ymin - ymin) / HY); - E_Int jmax = floor((bbox.ymax - ymin) / HY); - E_Int kmin = floor((bbox.zmin - zmin) / HZ); - E_Int kmax = floor((bbox.zmax - zmin) / HZ); + for (E_Int p : pn) { + E_Float x = X[p]; + E_Float y = Y[p]; + E_Float z = Z[p]; + + E_Int I = floor((x - xmin) / HX); + E_Int J = floor((y - ymin) / HY); + E_Int K = floor((z - zmin) / HZ); + + if (I < Imin) Imin = I; + if (J < Jmin) Jmin = J; + if (K < Kmin) Kmin = K; + if (I > Imax) Imax = I; + if (J > Jmax) Jmax = J; + if (K > Kmax) Kmax = K; + } - for (E_Int k = kmin; k < kmax+1; k++) { - for (E_Int j = jmin; j < jmax+1; j++) { - for (E_Int i = imin; i < imax+1; i++) { - E_Int voxel = i + NX*j + NXY*k; + for (E_Int I = Imin; I <= Imax; I++) { + for (E_Int J = Jmin; J <= Jmax; J++) { + for (E_Int K = Kmin; K <= Kmax; K++) { + E_Int voxel = I + J * NX + (NX * NY) * K; + assert(voxel >= 0); + assert(voxel < NXYZ); fmap[voxel].push_back(fid); } } From 958fd2881dcc0a8d2f246ba548dd026e9413bae4 Mon Sep 17 00:00:00 2001 From: imadhammani Date: Wed, 9 Oct 2024 17:27:47 +0200 Subject: [PATCH 38/86] XCore intersectMesh: added dcel face writing --- Cassiopee/XCore/XCore/intersectMesh/io.cpp | 36 ++++++++++++++++++++++ Cassiopee/XCore/XCore/intersectMesh/io.h | 2 ++ 2 files changed, 38 insertions(+) diff --git a/Cassiopee/XCore/XCore/intersectMesh/io.cpp b/Cassiopee/XCore/XCore/intersectMesh/io.cpp index 05626e6e6..660fe0542 100644 --- a/Cassiopee/XCore/XCore/intersectMesh/io.cpp +++ b/Cassiopee/XCore/XCore/intersectMesh/io.cpp @@ -37,6 +37,7 @@ void face_write(const char *fname, Face *f) fprintf(fh, "POINTS\n"); fprintf(fh, "%d\n", np); + h = f->rep; Vertex *v = h->orig; fprintf(fh, "%f %f %f\n", v->x, v->y, v->z); @@ -49,6 +50,41 @@ void face_write(const char *fname, Face *f) fclose(fh); } +void faces_write(const char *fname, const std::vector &faces, E_Float scale) +{ + FILE *fh = fopen(fname, "w"); + assert(fh); + + E_Int NP = 0; + for (const Face *f : faces) { + E_Int np = 1; + Hedge *h = f->rep; + Hedge *w = h->next; + while (w != h) { + np++; + w = w->next; + } + NP += np; + } + + fprintf(fh, "POINTS\n"); + fprintf(fh, "%d\n", NP); + + for (const Face *f : faces) { + Hedge *h = f->rep; + Vertex *v = h->orig; + fprintf(fh, "%f %f %f\n", scale*v->x, scale*v->y, scale*v->z); + Hedge *w = h->next; + while (w != h) { + v = w->orig; + fprintf(fh, "%f %f %f\n", scale*v->x, scale*v->y, scale*v->z); + w = w->next; + } + } + + fclose(fh); +} + void hedge_write(const char *fname, const Hedge *h) { FILE *fh = fopen(fname, "w"); diff --git a/Cassiopee/XCore/XCore/intersectMesh/io.h b/Cassiopee/XCore/XCore/intersectMesh/io.h index df4092807..4f22975ab 100644 --- a/Cassiopee/XCore/XCore/intersectMesh/io.h +++ b/Cassiopee/XCore/XCore/intersectMesh/io.h @@ -39,6 +39,8 @@ struct IO_Edge { void face_write(const char *fname, Face *face); +void faces_write(const char *fname, const std::vector &faces, E_Float scale = 1.0); + void point_write(const char *fname, E_Float x, E_Float y, E_Float z); void point_write(const char *fname, Vertex *v); From 93addd4a43ee2b09cc8252a198cc1d3b569b87bf Mon Sep 17 00:00:00 2001 From: imadhammani Date: Wed, 9 Oct 2024 17:28:48 +0200 Subject: [PATCH 39/86] XCore intersectMesh: take mesh arrays as input instead of IM capsule --- .../XCore/intersectMesh/intersectMesh.cpp | 70 ++++++++++++++----- .../prepareMeshesForIntersection.cpp | 35 +++++----- 2 files changed, 71 insertions(+), 34 deletions(-) diff --git a/Cassiopee/XCore/XCore/intersectMesh/intersectMesh.cpp b/Cassiopee/XCore/XCore/intersectMesh/intersectMesh.cpp index 032353fbe..a207ad31d 100644 --- a/Cassiopee/XCore/XCore/intersectMesh/intersectMesh.cpp +++ b/Cassiopee/XCore/XCore/intersectMesh/intersectMesh.cpp @@ -287,24 +287,25 @@ IMesh reconstruct_mesh(IMesh &M, Smesh &Mf, const Dcel &D, E_Int color) PyObject *K_XCORE::intersectMesh(PyObject *self, PyObject *args) { - PyObject *MASTER, *SLAVE, *SPATCH; + PyObject *MASTER, *SLAVE, *MPATCH, *SPATCH; - if (!PYPARSETUPLE_(args, OOO_, &MASTER, &SLAVE, &SPATCH)) { + if (!PYPARSETUPLE_(args, OOOO_, &MASTER, &MPATCH, &SLAVE, &SPATCH)) { RAISE("Bad input."); return NULL; } - if (!PyCapsule_IsValid(MASTER, "IntersectMesh")) { - RAISE("Bad mesh hook."); + Karray marray; + + E_Int ret; + + ret = Karray_parse_ngon(MASTER, marray); + + if (ret != 0) { return NULL; } - IMesh &M = *(IMesh *)PyCapsule_GetPointer(MASTER, "IntersectMesh"); - Karray sarray; - E_Int ret; - ret = Karray_parse_ngon(SLAVE, sarray); if (ret != 0) { @@ -312,6 +313,7 @@ PyObject *K_XCORE::intersectMesh(PyObject *self, PyObject *args) } // Init and orient master/slave meshes + IMesh M(*marray.cn, marray.X, marray.Y, marray.Z, marray.npts); IMesh S(*sarray.cn, sarray.X, sarray.Y, sarray.Z, sarray.npts); M.make_skin(); @@ -320,23 +322,31 @@ PyObject *K_XCORE::intersectMesh(PyObject *self, PyObject *args) M.orient_skin(OUT); S.orient_skin(IN); - //M.patch.clear(); - //for (E_Int fid : M.skin) M.patch.insert(fid); - - printf("Master patch: %zu faces\n", M.patch.size()); + // Check intersection patches (one-based) + E_Int *mpatch = NULL; + E_Int mpatch_size = -1; + ret = K_NUMPY::getFromNumpyArray(MPATCH, mpatch, mpatch_size, true); + if (ret != 1) { + Karray_free_ngon(marray); + RAISE("Bad master patch."); + return NULL; + } + printf("Master patch: " SF_D_ " faces\n", mpatch_size); - // Check slave intersection patch (zero-based) E_Int *spatch = NULL; E_Int spatch_size = -1; ret = K_NUMPY::getFromNumpyArray(SPATCH, spatch, spatch_size, true); if (ret != 1) { + Karray_free_ngon(marray); Karray_free_ngon(sarray); RAISE("Bad slave patch."); return NULL; } - printf("Slave patch: " SF_D_ " faces\n", spatch_size); + assert(M.patch.empty()); + assert(S.patch.empty()); + for (E_Int i = 0; i < mpatch_size; i++) M.patch.insert(mpatch[i]-1); for (E_Int i = 0; i < spatch_size; i++) S.patch.insert(spatch[i]-1); // Extract surface meshes @@ -366,6 +376,22 @@ PyObject *K_XCORE::intersectMesh(PyObject *self, PyObject *args) Dcel D(Mf, Sf); + /* + for (Vertex *v : D.V) { + if (v->oid[0] != -1) { + Mf.X[v->oid[0]] = v->x; + Mf.Y[v->oid[0]] = v->y; + Mf.Z[v->oid[0]] = v->z; + } + + if (v->oid[1] != -1) { + Sf.X[v->oid[1]] = v->x; + Sf.Y[v->oid[1]] = v->y; + Sf.Z[v->oid[1]] = v->z; + } + } + */ + puts("Locating points..."); D.locate_spoints(Mf, Sf); @@ -389,21 +415,29 @@ PyObject *K_XCORE::intersectMesh(PyObject *self, PyObject *args) oid = v->oid[1]; if (oid != -1) v->oid[1] = Sf.l2gp[oid]; } - - M = reconstruct_mesh(M, Mf, D, Dcel::RED); + IMesh M_inter = reconstruct_mesh(M, Mf, D, Dcel::RED); IMesh S_inter = reconstruct_mesh(S, Sf, D, Dcel::BLACK); // Export printf("Exporting... "); + PyObject *Mout = M_inter.export_karray(); PyObject *Sout = S_inter.export_karray(); printf("Done.\n"); + Karray_free_ngon(marray); Karray_free_ngon(sarray); - + + Py_DECREF(MPATCH); Py_DECREF(SPATCH); - return Sout; + PyObject *out = PyList_New(0); + PyList_Append(out, Mout); + PyList_Append(out, Sout); + Py_DECREF(Mout); + Py_DECREF(Sout); + + return out; } diff --git a/Cassiopee/XCore/XCore/intersectMesh/prepareMeshesForIntersection.cpp b/Cassiopee/XCore/XCore/intersectMesh/prepareMeshesForIntersection.cpp index fe86753de..7a3438af7 100644 --- a/Cassiopee/XCore/XCore/intersectMesh/prepareMeshesForIntersection.cpp +++ b/Cassiopee/XCore/XCore/intersectMesh/prepareMeshesForIntersection.cpp @@ -45,13 +45,6 @@ PyObject *K_XCORE::prepareMeshesForIntersection(PyObject *self, PyObject *args) IMesh &M = *(IMesh *)PyCapsule_GetPointer(MASTER, "IntersectMesh"); - //M.make_skin(); - //assert(M.patch.empty()); - //for (E_Int fid : M.skin) { - // assert(fid < M.nf); - // M.patch.insert(fid); - //} - Karray sarray; E_Int ret; @@ -132,30 +125,40 @@ PyObject *K_XCORE::prepareMeshesForIntersection(PyObject *self, PyObject *args) // Export puts("Exporting to CGNS format..."); + PyObject *Mout = M.export_karray(); PyObject *Sout = S.export_karray(); - PyObject *Out = PyList_New(0); - - PyList_Append(Out, Sout); - - Py_DECREF(Sout); - Karray_free_ngon(sarray); // Extract master and slave patches - puts("Saving slave intersection patch..."); + puts("Saving intersection patches..."); npy_intp dims[2]; dims[1] = 1; + dims[0] = (npy_intp)M.patch.size(); + PyArrayObject *MP = (PyArrayObject *)PyArray_SimpleNew(1, dims, E_NPY_INT); + E_Int *mptr = (E_Int *)PyArray_DATA(MP); + E_Int *ptr = mptr; + for (E_Int fid : M.patch) *ptr++ = fid + 1; + dims[0] = (npy_intp)S.patch.size(); PyArrayObject *SP = (PyArrayObject *)PyArray_SimpleNew(1, dims, E_NPY_INT); E_Int *sptr = (E_Int *)PyArray_DATA(SP); - E_Int *ptr = sptr; - for (E_Int face : S.patch) *ptr++ = face + 1; + ptr = sptr; + for (E_Int fid : S.patch) *ptr++ = fid + 1; + + PyObject *Out = PyList_New(0); + PyList_Append(Out, Mout); + PyList_Append(Out, (PyObject *)MP); + PyList_Append(Out, Sout); PyList_Append(Out, (PyObject *)SP); + Py_DECREF(Mout); + Py_DECREF(Sout); + Py_DECREF(MP); Py_DECREF(SP); + Py_DECREF(TAG); return Out; From e5f45de17d95e60d81f76ef3b5a9583ffca465fe Mon Sep 17 00:00:00 2001 From: imadhammani Date: Wed, 9 Oct 2024 17:30:16 +0200 Subject: [PATCH 40/86] XCore intersectMesh: update patch on-the-fly in triangulate function --- Cassiopee/XCore/XCore/intersectMesh/mesh.cpp | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/Cassiopee/XCore/XCore/intersectMesh/mesh.cpp b/Cassiopee/XCore/XCore/intersectMesh/mesh.cpp index 4f3edfd4a..76eff7a4e 100644 --- a/Cassiopee/XCore/XCore/intersectMesh/mesh.cpp +++ b/Cassiopee/XCore/XCore/intersectMesh/mesh.cpp @@ -93,6 +93,10 @@ void IMesh::triangulate_face_set(bool propagate) auto &pn = F[fid]; + patch.insert(fid); + + if (pn.size() == 3) continue; + assert(pn.size() == 4); std::vector tri0(3), tri1(3); @@ -120,15 +124,14 @@ void IMesh::triangulate_face_set(bool propagate) skin.push_back(NF); // Update patch - patch.insert(fid); + patch.insert(NF); NF++; } - assert(NF == nf + face_incr); - nf = NF; + F.resize(NF); } struct DEdge { From a99a39b7c338ff63771b4f6db5ea2b49700e8315 Mon Sep 17 00:00:00 2001 From: imadhammani Date: Wed, 9 Oct 2024 21:14:22 +0200 Subject: [PATCH 41/86] XCore intersectMesh: add max number of walks in trace_hedge_2 --- Cassiopee/XCore/XCore/intersectMesh/dcel.cpp | 54 ++++++++----------- .../XCore/XCore/intersectMesh/meshRefine.cpp | 6 ++- Cassiopee/XCore/XCore/intersectMesh/trace.cpp | 15 +++--- 3 files changed, 33 insertions(+), 42 deletions(-) diff --git a/Cassiopee/XCore/XCore/intersectMesh/dcel.cpp b/Cassiopee/XCore/XCore/intersectMesh/dcel.cpp index 83a2d515c..e3f68ffd5 100644 --- a/Cassiopee/XCore/XCore/intersectMesh/dcel.cpp +++ b/Cassiopee/XCore/XCore/intersectMesh/dcel.cpp @@ -831,6 +831,7 @@ E_Int Dcel::get_next_face(const Smesh &M, E_Float px, E_Float py, E_Float pz, const std::vector &pf, E_Float dir[3], E_Int hid) { E_Int next_face = -1; + /* E_Float t_min = EFLOATMAX; for (size_t i = 0; i < pf.size(); i++) { @@ -886,19 +887,7 @@ E_Int Dcel::get_next_face(const Smesh &M, E_Float px, E_Float py, E_Float pz, } } - /* - if (next_face == -1) { - - point_write("test_point", px, py, pz); - - for (E_Int fid : pf) { - char fname[128] = {}; - sprintf(fname, "test_face_%d", fid); - face_write(fname, F[fid]); - } - } */ - return next_face; } @@ -906,6 +895,8 @@ std::vector points; void Dcel::trace_hedge(Hedge *sh, const Smesh &M, const Smesh &S, E_Int hid) { +/* + Vertex *p = sh->orig; Vertex *q = sh->twin->orig; @@ -1051,31 +1042,29 @@ void Dcel::trace_hedge(Hedge *sh, const Smesh &M, const Smesh &S, E_Int hid) if (x != NULL) { - /* - // Stop if reached destination - if (x->oid[1] != -1) { - assert(x == q); - found = 1; - } + //// Stop if reached destination + //if (x->oid[1] != -1) { + // assert(x == q); + // found = 1; + //} - // M point, get the next face - else if (x->oid[0] != -1) { + //// M point, get the next face + //else if (x->oid[0] != -1) { - E_Int mpid = x->oid[0]; - const auto &pf = M.P2F[mpid]; - E_Int next_fid = get_next_face(M, x->x, x->y, x->z, pf, dir, hid); - assert(next_fid != -1); - assert(next_fid != current_fid); - current_face = F[next_fid]; + // E_Int mpid = x->oid[0]; + // const auto &pf = M.P2F[mpid]; + // E_Int next_fid = get_next_face(M, x->x, x->y, x->z, pf, dir, hid); + // assert(next_fid != -1); + // assert(next_fid != current_fid); + // current_face = F[next_fid]; - } else { - - // Intersection, move + //} else { + // + // // Intersection, move - current_face = h->twin->left; + // current_face = h->twin->left; - } - */ + //} bool is_mpoint = x->oid[0] != -1; @@ -1160,6 +1149,7 @@ void Dcel::trace_hedge(Hedge *sh, const Smesh &M, const Smesh &S, E_Int hid) } assert(walk < max_walk); + */ } void Dcel::find_intersections_3D(const Smesh &M, const Smesh &S) diff --git a/Cassiopee/XCore/XCore/intersectMesh/meshRefine.cpp b/Cassiopee/XCore/XCore/intersectMesh/meshRefine.cpp index 4c3ad7290..e0ceb70a0 100644 --- a/Cassiopee/XCore/XCore/intersectMesh/meshRefine.cpp +++ b/Cassiopee/XCore/XCore/intersectMesh/meshRefine.cpp @@ -48,6 +48,7 @@ E_Int meshes_mutual_refinement(IMesh &M, IMesh &S) printf("Refined mf: %zu\n", refM); // Refine S wrt M + /* if (iter == 1 || (iter > 1 && refM > 0)) { M.make_point_faces(); S.make_bbox(); @@ -56,11 +57,11 @@ E_Int meshes_mutual_refinement(IMesh &M, IMesh &S) refS = S.refine_slave(M); printf("Refined sf: %zu\n", refS); } + */ - } while (refM > 0 || refS > 0); + } while (refS > 0); S.make_point_faces(); - M.hash_skin(); // Project all the new points from S onto M faces // TODO(Imad): shouldn't this step be done after conformizing? @@ -138,6 +139,7 @@ size_t IMesh::refine_slave(const IMesh &master) for (const auto fid : patch) { const auto &pn = F[fid]; assert(face_is_tri(fid)); + assert(face_is_active(fid)); E_Int a = pn[0], b = pn[1], c = pn[2]; E_Float v0[3] = {X[b]-X[a], Y[b]-Y[a], Z[b]-Z[a]}; E_Float v1[3] = {X[c]-X[a], Y[c]-Y[a], Z[c]-Z[a]}; diff --git a/Cassiopee/XCore/XCore/intersectMesh/trace.cpp b/Cassiopee/XCore/XCore/intersectMesh/trace.cpp index 68f5ee203..9c86b311e 100644 --- a/Cassiopee/XCore/XCore/intersectMesh/trace.cpp +++ b/Cassiopee/XCore/XCore/intersectMesh/trace.cpp @@ -203,13 +203,13 @@ E_Int Dcel::trace_hedge_2(Hedge *sh, const Smesh &M, const Smesh &S, E_Int hid) E_Float current_pos[3] = {O->x, O->y, O->z}; E_Int walk = 0; - E_Int max_walks = 10; + E_Int max_walks = 20; - if (hid == 1663) hedge_write("sh", sh); + if (hid == 1953) hedge_write("sh", sh); - while (!found_tail && walk < max_walks) { + while (!found_tail && walk <= max_walks) { - if (hid == 1663) face_write("current_face", F[current_fid]); + if (hid == 1953) face_write("current_face", F[current_fid]); // We are on current_face @@ -260,7 +260,7 @@ E_Int Dcel::trace_hedge_2(Hedge *sh, const Smesh &M, const Smesh &S, E_Int hid) if (hit) { - if (hid == 1663) point_write("hit", current_pos[0] + t * proj[0], current_pos[1] + t * proj[1], current_pos[2] + t * proj[2]); + if (hid == 1953) point_write("hit", current_pos[0] + t * proj[0], current_pos[1] + t * proj[1], current_pos[2] + t * proj[2]); // Intersection within the edge if (s > TOL && s < 1 - TOL) { @@ -359,9 +359,8 @@ E_Int Dcel::trace_hedge_2(Hedge *sh, const Smesh &M, const Smesh &S, E_Int hid) walk++; } - if (walk >= max_walks) { - fprintf(stderr, "Warning : Could not find the tail after %d max walks!", - max_walks); + if (walk > max_walks) { + fprintf(stderr, "Warning : Could not reach the tail of edge %d after %d max walks!", hid, max_walks); assert(0); return 1; } From 35b5b6c804d2aeed3f6a3eec6081682db169def6 Mon Sep 17 00:00:00 2001 From: imadhammani Date: Wed, 9 Oct 2024 22:30:51 +0200 Subject: [PATCH 42/86] XCore intersectMesh: map hedges to intersections --- Cassiopee/XCore/XCore/intersectMesh/dcel.cpp | 21 +++---- Cassiopee/XCore/XCore/intersectMesh/dcel.h | 6 +- Cassiopee/XCore/XCore/intersectMesh/smesh.cpp | 8 +-- Cassiopee/XCore/XCore/intersectMesh/trace.cpp | 55 +++++++++++++------ 4 files changed, 58 insertions(+), 32 deletions(-) diff --git a/Cassiopee/XCore/XCore/intersectMesh/dcel.cpp b/Cassiopee/XCore/XCore/intersectMesh/dcel.cpp index e3f68ffd5..e4952eb2d 100644 --- a/Cassiopee/XCore/XCore/intersectMesh/dcel.cpp +++ b/Cassiopee/XCore/XCore/intersectMesh/dcel.cpp @@ -1204,26 +1204,27 @@ void Dcel::find_intersections_3D(const Smesh &M, const Smesh &S) puts(" Tracing edges..."); + std::map> hedge_intersections; + for (size_t hid = 0; hid < s_hedges.size(); hid++) { Hedge *sh = s_hedges[hid]; //printf("Tracing hedge %zu / %zu\n", hid+1, s_hedges.size()); //trace_hedge(sh, M, S, hid); - trace_hedge_2(sh, M, S, hid); + trace_hedge_2(sh, M, S, hid, hedge_intersections); } - exit(0); - - //point_write("xpoints", points); + printf("Duplicate intersections: %d\n", dup_x); + printf("Vertices crossed: %lu\n", vertices_crossed.size()); - /* - std::vector all_points; - for (Vertex *v : V) { - all_points.push_back(Point(v->x, v->y, v->z)); + std::vector v_crossed; + for (Vertex *v : vertices_crossed) { + v_crossed.push_back(Point(v->x, v->y, v->z)); } - point_write("all_points", all_points); - */ + point_write("vertices_crossed", v_crossed); + + exit(0); } void Dcel::sort_leaving_hedges(std::vector &leaving, diff --git a/Cassiopee/XCore/XCore/intersectMesh/dcel.h b/Cassiopee/XCore/XCore/intersectMesh/dcel.h index c02600d93..4d609a7c0 100644 --- a/Cassiopee/XCore/XCore/intersectMesh/dcel.h +++ b/Cassiopee/XCore/XCore/intersectMesh/dcel.h @@ -51,6 +51,9 @@ struct Dcel { std::map> Cp; std::map> Lp; + E_Int dup_x = 0; // Number of duplicate intersections + std::set vertices_crossed; // M vertices crossed by S hedges + Dcel(Smesh &M0, Smesh &M1); ~Dcel(); @@ -108,7 +111,8 @@ struct Dcel { void trace_hedge(Hedge *sh, const Smesh &M, const Smesh &S, E_Int hid); - E_Int trace_hedge_2(Hedge *sh, const Smesh &M, const Smesh &S, E_Int hid); + E_Int trace_hedge_2(Hedge *sh, const Smesh &M, const Smesh &S, E_Int hid, + std::map> &hedge_intersections); void sort_leaving_hedges(std::vector &leaving, const E_Float N[3], const Smesh &M) const; diff --git a/Cassiopee/XCore/XCore/intersectMesh/smesh.cpp b/Cassiopee/XCore/XCore/intersectMesh/smesh.cpp index 624fe37b6..11faca7bc 100644 --- a/Cassiopee/XCore/XCore/intersectMesh/smesh.cpp +++ b/Cassiopee/XCore/XCore/intersectMesh/smesh.cpp @@ -932,9 +932,9 @@ void Smesh::make_bbox() void Smesh::hash_faces() { - NX = 50; - NY = 50; - NZ = 50; + NX = 100; + NY = 100; + NZ = 100; HX = (xmax - xmin) / NX; HY = (ymax - ymin) / NY; @@ -982,4 +982,4 @@ void Smesh::hash_faces() } } } -} \ No newline at end of file +} diff --git a/Cassiopee/XCore/XCore/intersectMesh/trace.cpp b/Cassiopee/XCore/XCore/intersectMesh/trace.cpp index 9c86b311e..f15fe0143 100644 --- a/Cassiopee/XCore/XCore/intersectMesh/trace.cpp +++ b/Cassiopee/XCore/XCore/intersectMesh/trace.cpp @@ -3,6 +3,7 @@ #include "primitives.h" #include "hedge.h" #include "io.h" +#include "event.h" static bool ray_edge_intersect(E_Float ox, E_Float oy, E_Float oz, @@ -172,7 +173,8 @@ void get_shared_faces(const Vertex *v, const Smesh &M, std::vector &ret, } } -E_Int Dcel::trace_hedge_2(Hedge *sh, const Smesh &M, const Smesh &S, E_Int hid) +E_Int Dcel::trace_hedge_2(Hedge *sh, const Smesh &M, const Smesh &S, E_Int hid, + std::map> &hedge_intersections) { Vertex *O = sh->orig; Vertex *T = sh->twin->orig; @@ -289,13 +291,30 @@ E_Int Dcel::trace_hedge_2(Hedge *sh, const Smesh &M, const Smesh &S, E_Int hid) next_pos[0] = current_pos[0] + t * proj[0]; next_pos[1] = current_pos[1] + t * proj[1]; next_pos[2] = current_pos[2] + t * proj[2]; - } + + // Register intersection + Event *xit = Q.lookup(next_pos[0], next_pos[1], next_pos[2]); + Vertex *x = NULL; + if (xit == NULL) { + x = new Vertex(next_pos[0], next_pos[1], next_pos[2]); + x->id = V.size(); + V.push_back(x); + } else { + x = xit->key; + dup_x++; + } + + hedge_intersections[sh].push_back(x); + // TODO(Imad): H[eid] or its twin? + hedge_intersections[H[eid]].push_back(x); + } // Intersection on an endpoint else { bool hit_p = (s <= TOL); bool hit_q = (s >= 1 - TOL); + last_edge = -1; if (hit_p) { @@ -317,28 +336,30 @@ E_Int Dcel::trace_hedge_2(Hedge *sh, const Smesh &M, const Smesh &S, E_Int hid) last_vertex = q; } - - // Exclude current_fid + const auto &pf = M.P2F[last_vertex]; - /* - std::vector pf(M.P2F[last_vertex]); - E_Int found_fid = false; - for (auto &fid : pf) { - if (fid == current_fid) { - found_fid = true; - fid = pf.back(); - break; - } - } - pf.resize(pf.size()-1); - */ - next_fid = deduce_face(pf, M, next_pos[0], next_pos[1], next_pos[2], D, last_vertex, last_edge ); assert(next_fid != -1); + + // Register intersection + + Event *xit = Q.lookup(M.X[last_vertex], + M.Y[last_vertex], M.Z[last_vertex]); + assert(xit != NULL); + Vertex *x = xit->key; + + // Edges from S do not cross + assert(x->oid[1] == -1); + + assert(vertices_crossed.find(x) == vertices_crossed.end()); + vertices_crossed.insert(x); + + hedge_intersections[sh].push_back(x); + } break; From 1b9c74ed94c78d0b071e281f1c7ff2f858513d13 Mon Sep 17 00:00:00 2001 From: imadhammani Date: Wed, 9 Oct 2024 23:12:49 +0200 Subject: [PATCH 43/86] XCore intersectMesh: added cut_hedges function --- Cassiopee/XCore/XCore/intersectMesh/cut.cpp | 84 ++++++++++++++++++++ Cassiopee/XCore/XCore/intersectMesh/dcel.cpp | 2 + Cassiopee/XCore/XCore/intersectMesh/dcel.h | 2 + Cassiopee/XCore/XCore/intersectMesh/vertex.h | 2 + Cassiopee/XCore/srcs.py | 1 + 5 files changed, 91 insertions(+) create mode 100644 Cassiopee/XCore/XCore/intersectMesh/cut.cpp diff --git a/Cassiopee/XCore/XCore/intersectMesh/cut.cpp b/Cassiopee/XCore/XCore/intersectMesh/cut.cpp new file mode 100644 index 000000000..7479c0223 --- /dev/null +++ b/Cassiopee/XCore/XCore/intersectMesh/cut.cpp @@ -0,0 +1,84 @@ +#include "dcel.h" +#include "hedge.h" +#include "vertex.h" +#include "primitives.h" + +void Dcel::cut_hedges(std::map> &hmap) +{ + size_t hid = 0; + + for (auto &hdata : hmap) { + Hedge *h = hdata.first; + auto &xs = hdata.second; + + // Distances (squared) of intersections to sh origin + + Vertex *o = h->orig; + + E_Float D[3]; + + for (Vertex *x : xs) { + E_Float D[3] = {x->x-o->x, x->y-o->y, x->z-o->z}; + x->d = K_MATH::dot(D, D, 3); + } + + std::sort(xs.begin(), xs.end(), [&] (const Vertex *a, const Vertex *b) + { + assert(Sign(a->d - b->d) != 0); + return a->d < b->d; + }); + + Hedge *current_h = h; + Hedge *current_t = h->twin; + + // Cache the tail + Vertex *tail = current_t->orig; + + assert(current_h->color == current_t->color); + + for (Vertex *x : xs) { + // Create two new hedges with x as their origin + Hedge *e1 = new Hedge(x); + Hedge *e2 = new Hedge(x); + + // Add to hedges collection + H.push_back(e1); + H.push_back(e2); + + // Copy the color + e1->color = current_h->color; + e2->color = current_t->color; + + // Copy the face record + e1->left = current_h->left; + e2->left = current_t->left; + + // Pair-up the new half-edges + current_h->twin = e2; + e2->twin = current_h; + current_t->twin = e1; + e1->twin = current_t; + + // Set prev and next pointers at x + current_h->next = e1; + e1->prev = current_h; + current_t->next = e2; + e2->prev = current_t; + + // NOTE(Imad): is this part necessary? + // Set prev and next pointers at the endpoints + e1->next = current_h->next; + e2->next = current_t->next; + current_h->next->prev = e1; + current_t->next->prev = e2; + + // Keep going + current_h = e1; + } + + assert(current_h->twin->orig == tail); + + hid++; + } +} + diff --git a/Cassiopee/XCore/XCore/intersectMesh/dcel.cpp b/Cassiopee/XCore/XCore/intersectMesh/dcel.cpp index e4952eb2d..1aa31968b 100644 --- a/Cassiopee/XCore/XCore/intersectMesh/dcel.cpp +++ b/Cassiopee/XCore/XCore/intersectMesh/dcel.cpp @@ -1224,6 +1224,8 @@ void Dcel::find_intersections_3D(const Smesh &M, const Smesh &S) } point_write("vertices_crossed", v_crossed); + cut_hedges(hedge_intersections); + exit(0); } diff --git a/Cassiopee/XCore/XCore/intersectMesh/dcel.h b/Cassiopee/XCore/XCore/intersectMesh/dcel.h index 4d609a7c0..984c557ab 100644 --- a/Cassiopee/XCore/XCore/intersectMesh/dcel.h +++ b/Cassiopee/XCore/XCore/intersectMesh/dcel.h @@ -114,6 +114,8 @@ struct Dcel { E_Int trace_hedge_2(Hedge *sh, const Smesh &M, const Smesh &S, E_Int hid, std::map> &hedge_intersections); + void cut_hedges(std::map> &hmap); + void sort_leaving_hedges(std::vector &leaving, const E_Float N[3], const Smesh &M) const; }; diff --git a/Cassiopee/XCore/XCore/intersectMesh/vertex.h b/Cassiopee/XCore/XCore/intersectMesh/vertex.h index 8718a7439..bede5833f 100644 --- a/Cassiopee/XCore/XCore/intersectMesh/vertex.h +++ b/Cassiopee/XCore/XCore/intersectMesh/vertex.h @@ -42,6 +42,8 @@ struct Vertex { Hedge *xhedge = NULL; + E_Float d = 0; + Vertex(E_Float X, E_Float Y, E_Float Z, E_Int Oid, E_Int color); Vertex(E_Float X, E_Float Y, E_Float Z); diff --git a/Cassiopee/XCore/srcs.py b/Cassiopee/XCore/srcs.py index 3d7316196..7999f7a47 100644 --- a/Cassiopee/XCore/srcs.py +++ b/Cassiopee/XCore/srcs.py @@ -38,6 +38,7 @@ 'XCore/intersectMesh/cycle.cpp', 'XCore/intersectMesh/dcel.cpp', 'XCore/intersectMesh/trace.cpp', + 'XCore/intersectMesh/cut.cpp', 'XCore/intersectMesh/event.cpp', 'XCore/intersectMesh/hedge.cpp', 'XCore/intersectMesh/face.cpp', From 2fc3274050673162351efe9bd0281d124dcbd1b9 Mon Sep 17 00:00:00 2001 From: imadhammani Date: Sat, 12 Oct 2024 00:06:29 +0200 Subject: [PATCH 44/86] Started ICapsule + moved Karray to common --- .../XCore/AdaptMesh/AdaptMesh_AdaptGeom.cpp | 2 +- .../XCore/XCore/AdaptMesh/AdaptMesh_Init.cpp | 2 +- Cassiopee/XCore/XCore/AdaptMesh/DynMesh.cpp | 2 +- Cassiopee/XCore/XCore/AdaptMesh/MeshInit.cpp | 2 +- Cassiopee/XCore/XCore/PyTree.py | 54 ++++- .../XCore/{AdaptMesh => common}/Karray.cpp | 0 .../XCore/{AdaptMesh => common}/Karray.h | 0 .../XCore/XCore/extractFacesFromPointTag.cpp | 2 +- Cassiopee/XCore/XCore/intersectMesh/DDA.cpp | 4 + .../intersectMesh/IntersectMesh_Init.cpp | 4 +- .../intersectMesh/IntersectMesh_Merge.cpp | 28 +-- Cassiopee/XCore/XCore/intersectMesh/cut.cpp | 100 +++++++-- Cassiopee/XCore/XCore/intersectMesh/dcel.cpp | 198 +++++++++++------- Cassiopee/XCore/XCore/intersectMesh/dcel.h | 18 +- .../XCore/XCore/intersectMesh/extract.cpp | 4 +- Cassiopee/XCore/XCore/intersectMesh/file | 0 .../XCore/XCore/intersectMesh/icapsule.cpp | 191 +++++++++++++++++ .../XCore/XCore/intersectMesh/icapsule.h | 13 ++ .../XCore/intersectMesh/intersectMesh.cpp | 73 ++++++- .../XCore/XCore/intersectMesh/karray.cpp | 116 ---------- Cassiopee/XCore/XCore/intersectMesh/karray.h | 59 ------ .../XCore/XCore/intersectMesh/locate.cpp | 67 ++++++ Cassiopee/XCore/XCore/intersectMesh/mesh.cpp | 90 +++++--- Cassiopee/XCore/XCore/intersectMesh/mesh.h | 21 +- .../XCore/XCore/intersectMesh/meshExport.cpp | 3 +- .../XCore/XCore/intersectMesh/meshRefine.cpp | 6 +- Cassiopee/XCore/XCore/intersectMesh/point.h | 9 + .../prepareMeshesForIntersection.cpp | 6 +- .../XCore/XCore/intersectMesh/primitives.cpp | 6 +- .../XCore/XCore/intersectMesh/primitives.h | 2 +- .../XCore/XCore/intersectMesh/project.cpp | 20 ++ .../removeIntersectingKPlanes.cpp | 40 ++-- Cassiopee/XCore/XCore/intersectMesh/smesh.cpp | 11 +- Cassiopee/XCore/XCore/intersectMesh/trace.cpp | 34 ++- .../XCore/XCore/intersectMesh/triangle.cpp | 35 ++-- .../XCore/XCore/intersectMesh/triangulate.cpp | 54 +++++ Cassiopee/XCore/XCore/intersectMesh/vertex.h | 10 +- Cassiopee/XCore/XCore/xcore.cpp | 5 + Cassiopee/XCore/XCore/xcore.h | 5 + Cassiopee/XCore/srcs.py | 7 +- 40 files changed, 898 insertions(+), 405 deletions(-) rename Cassiopee/XCore/XCore/{AdaptMesh => common}/Karray.cpp (100%) rename Cassiopee/XCore/XCore/{AdaptMesh => common}/Karray.h (100%) create mode 100644 Cassiopee/XCore/XCore/intersectMesh/file create mode 100644 Cassiopee/XCore/XCore/intersectMesh/icapsule.cpp create mode 100644 Cassiopee/XCore/XCore/intersectMesh/icapsule.h delete mode 100644 Cassiopee/XCore/XCore/intersectMesh/karray.cpp delete mode 100644 Cassiopee/XCore/XCore/intersectMesh/karray.h create mode 100644 Cassiopee/XCore/XCore/intersectMesh/locate.cpp create mode 100644 Cassiopee/XCore/XCore/intersectMesh/project.cpp create mode 100644 Cassiopee/XCore/XCore/intersectMesh/triangulate.cpp diff --git a/Cassiopee/XCore/XCore/AdaptMesh/AdaptMesh_AdaptGeom.cpp b/Cassiopee/XCore/XCore/AdaptMesh/AdaptMesh_AdaptGeom.cpp index fbf9d9596..08eb133db 100644 --- a/Cassiopee/XCore/XCore/AdaptMesh/AdaptMesh_AdaptGeom.cpp +++ b/Cassiopee/XCore/XCore/AdaptMesh/AdaptMesh_AdaptGeom.cpp @@ -447,7 +447,7 @@ void Mesh_refine_dir(Mesh *M, ArrayI *ref_cells, ArrayI *ref_faces) } } -#include "Karray.h" +#include "common/Karray.h" PyObject *K_XCORE::AdaptMesh_AdaptGeom(PyObject *self, PyObject *args) { diff --git a/Cassiopee/XCore/XCore/AdaptMesh/AdaptMesh_Init.cpp b/Cassiopee/XCore/XCore/AdaptMesh/AdaptMesh_Init.cpp index c2fc23f1d..18bccda7e 100644 --- a/Cassiopee/XCore/XCore/AdaptMesh/AdaptMesh_Init.cpp +++ b/Cassiopee/XCore/XCore/AdaptMesh/AdaptMesh_Init.cpp @@ -17,7 +17,7 @@ along with Cassiopee. If not, see . */ #include "Mesh.h" -#include "Karray.h" +#include "common/Karray.h" #include "common/mem.h" PyObject *K_XCORE::AdaptMesh_Init(PyObject *self, PyObject *args) diff --git a/Cassiopee/XCore/XCore/AdaptMesh/DynMesh.cpp b/Cassiopee/XCore/XCore/AdaptMesh/DynMesh.cpp index 978a5c898..7c1a5dc44 100644 --- a/Cassiopee/XCore/XCore/AdaptMesh/DynMesh.cpp +++ b/Cassiopee/XCore/XCore/AdaptMesh/DynMesh.cpp @@ -1,5 +1,5 @@ #include "DynMesh.h" -#include "Karray.h" +#include "common/Karray.h" #include "Array.h" #include "Skin.h" #include "Vec.h" diff --git a/Cassiopee/XCore/XCore/AdaptMesh/MeshInit.cpp b/Cassiopee/XCore/XCore/AdaptMesh/MeshInit.cpp index 52cb714d9..504b40097 100644 --- a/Cassiopee/XCore/XCore/AdaptMesh/MeshInit.cpp +++ b/Cassiopee/XCore/XCore/AdaptMesh/MeshInit.cpp @@ -17,7 +17,7 @@ along with Cassiopee. If not, see . */ #include "Mesh.h" -#include "Karray.h" +#include "common/Karray.h" #include "common/mem.h" Mesh::Mesh() diff --git a/Cassiopee/XCore/XCore/PyTree.py b/Cassiopee/XCore/XCore/PyTree.py index 1af7e1913..2d00c662c 100644 --- a/Cassiopee/XCore/XCore/PyTree.py +++ b/Cassiopee/XCore/XCore/PyTree.py @@ -341,12 +341,14 @@ def IntersectMesh_ExtractMesh(IM, removePeriodic=0): t = XOR.closeCells(t) return t -def removeIntersectingKPlanes(IM, slave): - - slave_bases = I.getBases(slave) +def removeIntersectingKPlanes(IM, slave_struct): + slave_bases = I.getBases(slave_struct) iter = -1 + import Generator.PyTree as G + import Transform.PyTree as T + ts = I.newCGNSTree() for slave_base in slave_bases: @@ -367,13 +369,21 @@ def removeIntersectingKPlanes(IM, slave): new_base = I.newCGNSBase('slave'+str(iter), 3, 3, parent=ts) + zones = [] for i in range(len(new_slaves_and_tags)): new_slave, tag = new_slaves_and_tags[i] zname = zs[i][0] zo = I.createZoneNode(zname, new_slave) cont = I.createUniqueChild(zo, I.__FlowSolutionNodes__, 'FlowSolution_t') I.newDataArray("tag", value=tag, parent=cont) - I.addChild(new_base, zo) + C._convertArray2NGon(zo) + G._close(zo) + zones.append(zo) + + merged = T.merge(zones) + merged = G.close(merged) + I.addChild(new_base, merged) + return ts @@ -423,6 +433,7 @@ def intersectMesh(master, slave): zs = I.getZones(slave)[0] keep = I.getNodeFromName(zs, 'keep') sarr = C.getFields(I.__GridCoordinates__, zs, api=3)[0] + #spatch = I.getNodeFromName(zs, "intersection_patch")[2][1][1][0] spatch = I.getNodeFromName(zs, "intersection_patch")[2][0][1] marr, sarr = xcore.intersectMesh(marr, mpatch, sarr, spatch) @@ -470,3 +481,38 @@ def extractFacesFromPointTag(t, tag_name): if tag is None: raise ValueError(tag_name + 'not found') arr = C.getFields(I.__GridCoordinates__, z, api=3)[0] return xcore.extractFacesFromPointTag(arr, tag[1]) + +def icapsule_init(mp, sp): + zm = I.getZones(mp)[0] + marr = C.getFields(I.__GridCoordinates__, zm, api=3)[0] + + sarrs = [] + tags = [] + bases = I.getBases(sp) + + for base in bases: + zs = I.getZones(base)[0] + sarr = C.getFields(I.__GridCoordinates__, zs, api=3)[0] + sarrs.append(sarr) + tag = I.getNodeFromName(zs, 'tag')[1] + tags.append(tag) + + return xcore.icapsule_init(marr, sarrs, tags) + +def icapsule_extract_master(icap): + marr = xcore.icapsule_extract_master(icap) + zm = I.createZoneNode("master", marr) + return zm + +def icapsule_extract_slave(icap, index=0): + sarr = xcore.icapsule_extract_slave(icap, index) + zs = I.createZoneNode("slave", sarr) + return zs + +def triangulate_skin(m): + zm = I.getZones(m)[0] + marr = C.getFields(I.__GridCoordinates__, zm, api=3)[0] + mo = xcore.triangulate_skin(marr) + zo = I.createZoneNode("triangulated", mo) + return zo + diff --git a/Cassiopee/XCore/XCore/AdaptMesh/Karray.cpp b/Cassiopee/XCore/XCore/common/Karray.cpp similarity index 100% rename from Cassiopee/XCore/XCore/AdaptMesh/Karray.cpp rename to Cassiopee/XCore/XCore/common/Karray.cpp diff --git a/Cassiopee/XCore/XCore/AdaptMesh/Karray.h b/Cassiopee/XCore/XCore/common/Karray.h similarity index 100% rename from Cassiopee/XCore/XCore/AdaptMesh/Karray.h rename to Cassiopee/XCore/XCore/common/Karray.h diff --git a/Cassiopee/XCore/XCore/extractFacesFromPointTag.cpp b/Cassiopee/XCore/XCore/extractFacesFromPointTag.cpp index cf116f44e..b2ef47bd0 100644 --- a/Cassiopee/XCore/XCore/extractFacesFromPointTag.cpp +++ b/Cassiopee/XCore/XCore/extractFacesFromPointTag.cpp @@ -1,4 +1,4 @@ -#include "AdaptMesh/Karray.h" +#include "common/Karray.h" PyObject *K_XCORE::extractFacesFromPointTag(PyObject *self, PyObject *args) { diff --git a/Cassiopee/XCore/XCore/intersectMesh/DDA.cpp b/Cassiopee/XCore/XCore/intersectMesh/DDA.cpp index 78b933bc0..a4b513e73 100644 --- a/Cassiopee/XCore/XCore/intersectMesh/DDA.cpp +++ b/Cassiopee/XCore/XCore/intersectMesh/DDA.cpp @@ -3,6 +3,10 @@ void IMesh::hash_skin() { + HX = (xmax - xmin) / NX; + HY = (ymax - ymin) / NY; + HZ = (zmax - zmin) / NZ; + bin_faces.clear(); bin_faces.resize(NXYZ); diff --git a/Cassiopee/XCore/XCore/intersectMesh/IntersectMesh_Init.cpp b/Cassiopee/XCore/XCore/intersectMesh/IntersectMesh_Init.cpp index ca555d7cf..2f46a16d5 100644 --- a/Cassiopee/XCore/XCore/intersectMesh/IntersectMesh_Init.cpp +++ b/Cassiopee/XCore/XCore/intersectMesh/IntersectMesh_Init.cpp @@ -17,7 +17,7 @@ along with Cassiopee. If not, see . */ #include "mesh.h" -#include "karray.h" +#include "common/Karray.h" //#include "BVH.h" PyObject *K_XCORE::IntersectMesh_Init(PyObject *self, PyObject *args) @@ -39,7 +39,7 @@ PyObject *K_XCORE::IntersectMesh_Init(PyObject *self, PyObject *args) // Init mesh - IMesh *M = new IMesh(*karray.cn, karray.X, karray.Y, karray.Z, karray.npts); + IMesh *M = new IMesh(*karray.cn, karray.X(), karray.Y(), karray.Z(), karray.npts); /* M->make_skin(); puts("Making BVH"); diff --git a/Cassiopee/XCore/XCore/intersectMesh/IntersectMesh_Merge.cpp b/Cassiopee/XCore/XCore/intersectMesh/IntersectMesh_Merge.cpp index a3c43ed45..a8915a801 100644 --- a/Cassiopee/XCore/XCore/intersectMesh/IntersectMesh_Merge.cpp +++ b/Cassiopee/XCore/XCore/intersectMesh/IntersectMesh_Merge.cpp @@ -1,5 +1,5 @@ #include "xcore.h" -#include "karray.h" +#include "common/Karray.h" #include #include @@ -106,9 +106,9 @@ PyObject *K_XCORE::IntersectMesh_Merge(PyObject *self, PyObject *args) std::set points; // Master points - E_Float *X = marray.X; - E_Float *Y = marray.Y; - E_Float *Z = marray.Z; + E_Float *X = marray.X(); + E_Float *Y = marray.Y(); + E_Float *Z = marray.Z(); printf("M points: %d\n", marray.npts); printf("S points: %d\n", sarray.npts); @@ -128,9 +128,9 @@ PyObject *K_XCORE::IntersectMesh_Merge(PyObject *self, PyObject *args) assert((size_t)NP == points.size()); // Slave points - X = sarray.X; - Y = sarray.Y; - Z = sarray.Z; + X = sarray.X(); + Y = sarray.Y(); + Z = sarray.Z(); for (E_Int i = 0; i < sarray.npts; i++) { Vtx xyz(X[i], Y[i], Z[i]); @@ -151,9 +151,9 @@ PyObject *K_XCORE::IntersectMesh_Merge(PyObject *self, PyObject *args) // Change the points ids within marray - X = marray.X; - Y = marray.Y; - Z = marray.Z; + X = marray.X(); + Y = marray.Y(); + Z = marray.Z(); for (E_Int fid = 0; fid < marray.nfaces(); fid++) { E_Int np = -1; @@ -169,9 +169,9 @@ PyObject *K_XCORE::IntersectMesh_Merge(PyObject *self, PyObject *args) // Change the points within sarray - X = sarray.X; - Y = sarray.Y; - Z = sarray.Z; + X = sarray.X(); + Y = sarray.Y(); + Z = sarray.Z(); for (E_Int fid = 0; fid < sarray.nfaces(); fid++) { E_Int np = -1; @@ -277,7 +277,7 @@ PyObject *K_XCORE::IntersectMesh_Merge(PyObject *self, PyObject *args) for (E_Int fid = 0; fid < marray.nfaces(); fid++) { E_Int np = -1; - E_Int *pn = marray.get_face(fid, np); + marray.get_face(fid, np); sizeNGon += np; } diff --git a/Cassiopee/XCore/XCore/intersectMesh/cut.cpp b/Cassiopee/XCore/XCore/intersectMesh/cut.cpp index 7479c0223..a1ca591c2 100644 --- a/Cassiopee/XCore/XCore/intersectMesh/cut.cpp +++ b/Cassiopee/XCore/XCore/intersectMesh/cut.cpp @@ -2,12 +2,80 @@ #include "hedge.h" #include "vertex.h" #include "primitives.h" +#include "smesh.h" +#include "io.h" -void Dcel::cut_hedges(std::map> &hmap) +void Dcel::init_mh_sv_intersections(const Smesh &M) +{ + for (Vertex *v : V) { + + // Strictly S points + + if (v->oid[0] == -1 && v->oid[1] != -1) { + const auto &loc = v->loc; + if (loc.e_idx == -1) continue; + + // Set the reference edge for normal computation + E_Int fid = loc.fid; + const auto &pe = M.F2E[fid]; + E_Int e = pe[loc.e_idx]; + v->meid = e; + + // Add the vertex to hedge intersections + // TODO(Imad): do we need to take the correctly-oriented hedge? + Hedge *h = H[2*e]; + if (cmp_vtx(h->orig, h->twin->orig) > 0) + h = h->twin; + hedge_intersections[h].push_back(v); + } + } +} + +/* +void Dcel::cut_hedges_intersecting_with_endpoint(Vertex *v, const Smesh &M) +{ + const auto &vloc = v->loc; + + if (vloc.e_idx == -1) return; + + E_Int fid = vloc.fid; + + const auto &pe = M.F2E[fid]; + + E_Int me = pe[vloc.e_idx]; + + Hedge *start = H[2*me]; + + Face *face = F[fid]; + + if (start->left != face) start = start->twin; + + Hedge *h = start; + + E_Int done = 0; + + while (1) { + + if (hedge_contains_vertex(h, v)) { + done = 1; + v->xhedge = h; + cut_hedge_at_vertex(h, v); + break; + } + + h = h->next; + if (h == start) break; + } + + assert(done == 1); +} +*/ + +void Dcel::cut_hedges() { size_t hid = 0; - for (auto &hdata : hmap) { + for (auto &hdata : hedge_intersections) { Hedge *h = hdata.first; auto &xs = hdata.second; @@ -15,7 +83,9 @@ void Dcel::cut_hedges(std::map> &hmap) Vertex *o = h->orig; - E_Float D[3]; + for (size_t i = 0; i < xs.size()-1; i++) { + assert(cmp_vtx(xs[i], xs[i+1]) != 0); + } for (Vertex *x : xs) { E_Float D[3] = {x->x-o->x, x->y-o->y, x->z-o->z}; @@ -24,15 +94,22 @@ void Dcel::cut_hedges(std::map> &hmap) std::sort(xs.begin(), xs.end(), [&] (const Vertex *a, const Vertex *b) { - assert(Sign(a->d - b->d) != 0); + if (Sign(a->d - b->d) == 0) { + hedge_write("hedge", h); + point_write("a", a->x, a->y, a->z); + point_write("b", b->x, b->y, b->z); + assert(Sign(a->d - b->d) != 0); + } return a->d < b->d; }); Hedge *current_h = h; Hedge *current_t = h->twin; - // Cache the tail + // Cache original connectivity Vertex *tail = current_t->orig; + //Hedge *h_next = h->next; + //Hedge *h_prev = h->prev; assert(current_h->color == current_t->color); @@ -59,19 +136,18 @@ void Dcel::cut_hedges(std::map> &hmap) current_t->twin = e1; e1->twin = current_t; + // Set prev and next pointers at the endpoints + //e1->next = current_h->next; + //e2->next = current_t->next; + //current_h->next->prev = e1; + //current_t->next->prev = e2; + // Set prev and next pointers at x current_h->next = e1; e1->prev = current_h; current_t->next = e2; e2->prev = current_t; - // NOTE(Imad): is this part necessary? - // Set prev and next pointers at the endpoints - e1->next = current_h->next; - e2->next = current_t->next; - current_h->next->prev = e1; - current_t->next->prev = e2; - // Keep going current_h = e1; } diff --git a/Cassiopee/XCore/XCore/intersectMesh/dcel.cpp b/Cassiopee/XCore/XCore/intersectMesh/dcel.cpp index 1aa31968b..900ad51db 100644 --- a/Cassiopee/XCore/XCore/intersectMesh/dcel.cpp +++ b/Cassiopee/XCore/XCore/intersectMesh/dcel.cpp @@ -33,6 +33,48 @@ #include "cycle.h" #include "triangle.h" +Smesh Dcel::export_smesh() const +{ + Smesh smesh; + smesh.ne = 0; + + smesh.np = V.size(); + + smesh.X.resize(smesh.np); + smesh.Y.resize(smesh.np); + smesh.Z.resize(smesh.np); + + for (Vertex *v : V) { + smesh.X[v->id] = v->x; + smesh.Y[v->id] = v->y; + smesh.Z[v->id] = v->z; + } + + for (size_t i = 0; i < F.size(); i++) { + Face *f = F[i]; + Hedge *REP = f->rep; + Cycle *c = REP->cycle; + if (c->inout != Cycle::OUTER) continue; + Hedge *h = REP; + + std::vector pn; + + do { + Vertex *v = h->orig; + pn.push_back(v->id); + h = h->next; + } while (h != REP); + + smesh.F.push_back(pn); + } + + smesh.nf = (E_Int)smesh.F.size(); + + smesh.make_edges(); + + return smesh; +} + E_Int Dcel::RED = 0; E_Int Dcel::BLACK = 1; E_Int Dcel::NO_IDEA = 2; @@ -243,6 +285,9 @@ void Dcel::set_face_labels(std::vector &F) // Only single color possible is RED, otherwise intersection problem // is ill-posed Hedge *REP = (R != NULL) ? R : B; + if (REP != R) { + hedge_write("black", REP); + } assert(REP == R); assert(REP->color == Dcel::RED); assert(REP->left); @@ -300,6 +345,23 @@ void Dcel::init_vertices(const Smesh &M0, const Smesh &M1) } } +Dcel::Dcel(const Smesh &M, E_Int color) +{ + for (E_Int i = 0; i < M.np; i++) { + Q.insert(M.X[i], M.Y[i], M.Z[i], i, color); + } + Q.inorder(V); + for (size_t i = 0; i < V.size(); i++) { + V[i]->id = i; + } + assert(V.size() == (size_t)M.np); + init_hedges_and_faces(M, color); + assert(check_hedges(H)); + assert(check_faces(H, F)); + make_cycles(); + set_cycles_inout(M); +} + Dcel::Dcel(Smesh &M0, Smesh &M1) { init_vertices(M0, M1); @@ -343,7 +405,7 @@ void mat3_vec(E_Float A[3][3], E_Float x[3], E_Float b[3]) } } -void Dcel::init_hedges_and_faces(Smesh &M, E_Int color) +void Dcel::init_hedges_and_faces(const Smesh &M, E_Int color) { printf("Doing color %d\n", color); size_t nh = H.size(); @@ -512,7 +574,7 @@ Dcel::~Dcel() Q.drop(); } -void Dcel::set_cycles_inout(const Smesh &M, const Smesh &S) +void Dcel::set_cycles_inout(const Smesh &M)//, const Smesh &S) { E_Int inner = 0; E_Int outer = 0; @@ -620,14 +682,19 @@ void Dcel::set_cycles_inout(const Smesh &M, const Smesh &S) // Intersection else { - Hedge *h = v->xhedge; - assert(h); + //Hedge *h = v->xhedge; + //assert(h); + //Face *f1 = h->left; + //Face *f2 = h->twin->left; + //E_Int mf1 = f1->oid[0]; + //E_Int mf2 = f2->oid[0]; - Face *f1 = h->left; - Face *f2 = h->twin->left; + E_Int eid = v->meid; + const auto &pf = M.E2F[eid]; - E_Int mf1 = f1->oid[0]; - E_Int mf2 = f2->oid[0]; + E_Int mf1 = pf[0]; + E_Int mf2 = pf[1]; + assert(mf2 != -1); const E_Float *fN1 = &M.fnormals[3*mf1]; const E_Float *fN2 = &M.fnormals[3*mf2]; @@ -678,6 +745,14 @@ std::vector Dcel::get_face_vertices(Face *f) return ret; } +static +E_Int Sign_tol(E_Float x, E_Float tol) +{ + if (x > tol) return 1; + if (x < -tol) return -1; + return 0; +} + void Dcel::locate_spoints(const Smesh &M, const Smesh &S) { for (E_Int sp = 0; sp < S.np; sp++) { @@ -723,7 +798,8 @@ void Dcel::locate_spoints(const Smesh &M, const Smesh &S) E_Float u, v, w; if (Triangle::is_point_inside( - S.X[sp], S.Y[sp], S.Z[sp], + S.X[sp], S.Y[sp], S.Z[sp], + //V->x, V->y, V->z, M.X[p], M.Y[p], M.Z[p], M.X[q], M.Y[q], M.Z[q], o[0], o[1], o[2], @@ -732,11 +808,17 @@ void Dcel::locate_spoints(const Smesh &M, const Smesh &S) found = 1; ploc.fid = fid; + ploc.u = u; + ploc.v = v; + ploc.w = w; // TODO(Imad): this absolutely needs to be robust - if (Sign(v) == 0) ploc.e_idx = i; - else if (Sign(1-u) == 0) ploc.v_idx = (i+1)%pn.size(); - else if (Sign(1-w) == 0) ploc.v_idx = i; + if (Sign_tol(v, 1e-3) == 0) + ploc.e_idx = i; + else if (Sign_tol(1-u, 1e-3) == 0) + ploc.v_idx = (i+1)%pn.size(); + else if (Sign_tol(1-w, 1e-3) == 0) + ploc.v_idx = i; break; } @@ -787,46 +869,6 @@ void Dcel::cut_hedge_at_vertex(Hedge *e, Vertex *x) Cp[x].push_back(e2); } -void Dcel::handle_intersecting_endpoint(Vertex *v, const Smesh &M) -{ - if (!Cp[v].empty()) return; - - const auto &vloc = v->loc; - - if (vloc.e_idx == -1) return; - - E_Int fid = vloc.fid; - - const auto &pe = M.F2E[fid]; - - E_Int me = pe[vloc.e_idx]; - - Hedge *start = H[2*me]; - - Face *face = F[fid]; - - if (start->left != face) start = start->twin; - - Hedge *h = start; - - E_Int done = 0; - - while (1) { - - if (hedge_contains_vertex(h, v)) { - done = 1; - v->xhedge = h; - cut_hedge_at_vertex(h, v); - break; - } - - h = h->next; - if (h == start) break; - } - - assert(done == 1); -} - E_Int Dcel::get_next_face(const Smesh &M, E_Float px, E_Float py, E_Float pz, const std::vector &pf, E_Float dir[3], E_Int hid) { @@ -1196,15 +1238,13 @@ void Dcel::find_intersections_3D(const Smesh &M, const Smesh &S) return false; }); - for (Vertex *v : V) { - if (v->oid[1] != -1 && v->oid[0] == -1) { - handle_intersecting_endpoint(v, M); - } - } + puts(" Registering endpoint-edge intersections..."); + + init_mh_sv_intersections(M); puts(" Tracing edges..."); - std::map> hedge_intersections; + size_t before = V.size(); for (size_t hid = 0; hid < s_hedges.size(); hid++) { Hedge *sh = s_hedges[hid]; @@ -1212,21 +1252,22 @@ void Dcel::find_intersections_3D(const Smesh &M, const Smesh &S) //printf("Tracing hedge %zu / %zu\n", hid+1, s_hedges.size()); //trace_hedge(sh, M, S, hid); - trace_hedge_2(sh, M, S, hid, hedge_intersections); + trace_hedge_2(sh, M, S, hid); } + size_t after = V.size(); + printf("Duplicate intersections: %d\n", dup_x); printf("Vertices crossed: %lu\n", vertices_crossed.size()); - std::vector v_crossed; - for (Vertex *v : vertices_crossed) { - v_crossed.push_back(Point(v->x, v->y, v->z)); + std::vector xpoints; + for (size_t i = before; i < after; i++) { + Vertex *v = V[i]; + xpoints.push_back(Point(v->x, v->y, v->z)); } - point_write("vertices_crossed", v_crossed); - - cut_hedges(hedge_intersections); + point_write("xpoints", xpoints); - exit(0); + cut_hedges(); } void Dcel::sort_leaving_hedges(std::vector &leaving, @@ -1366,6 +1407,7 @@ void Dcel::resolve_hedges(const Smesh &M, const Smesh &S) leaving.push_back(h); } + /* E_Int do_sort = 0; for (size_t i = 1; i < leaving.size(); i++) { @@ -1376,9 +1418,12 @@ void Dcel::resolve_hedges(const Smesh &M, const Smesh &S) } if (!do_sort) continue; + */ + + - E_Float N[3]= { }; + E_Float N[3]= {0}; // M point if (v->oid[0] != -1) { @@ -1438,14 +1483,19 @@ void Dcel::resolve_hedges(const Smesh &M, const Smesh &S) // Intersection else { - Hedge *h = v->xhedge; - assert(h); + //Hedge *h = v->xhedge; + //assert(h); + //Face *f1 = h->left; + //Face *f2 = h->twin->left; + //E_Int mf1 = f1->oid[0]; + //E_Int mf2 = f2->oid[0]; - Face *f1 = h->left; - Face *f2 = h->twin->left; + E_Int eid = v->meid; + const auto &pf = M.E2F[eid]; - E_Int mf1 = f1->oid[0]; - E_Int mf2 = f2->oid[0]; + E_Int mf1 = pf[0]; + E_Int mf2 = pf[1]; + assert(mf2 != -1); const E_Float *fN1 = &M.fnormals[3*mf1]; const E_Float *fN2 = &M.fnormals[3*mf2]; @@ -1479,7 +1529,7 @@ void Dcel::reconstruct(const Smesh &M, const Smesh &S) make_cycles(); - set_cycles_inout(M, S); + set_cycles_inout(M); auto new_F = make_cycle_faces(C); diff --git a/Cassiopee/XCore/XCore/intersectMesh/dcel.h b/Cassiopee/XCore/XCore/intersectMesh/dcel.h index 984c557ab..249c8c94c 100644 --- a/Cassiopee/XCore/XCore/intersectMesh/dcel.h +++ b/Cassiopee/XCore/XCore/intersectMesh/dcel.h @@ -53,14 +53,21 @@ struct Dcel { E_Int dup_x = 0; // Number of duplicate intersections std::set vertices_crossed; // M vertices crossed by S hedges + std::map> hedge_intersections; + + std::map> grid; + + Dcel(const Smesh &M, E_Int color); Dcel(Smesh &M0, Smesh &M1); ~Dcel(); + + void init_mh_sv_intersections(const Smesh &M); void init_vertices(const Smesh &M0, const Smesh &M1); - void init_hedges_and_faces(Smesh &M, E_Int color); + void init_hedges_and_faces(const Smesh &M, E_Int color); static E_Int check_hedges(const std::vector &H); @@ -77,7 +84,7 @@ struct Dcel { void update_hedge_faces(const std::vector &F); - void set_cycles_inout(const Smesh &M, const Smesh &S); + void set_cycles_inout(const Smesh &M);//, const Smesh &S); std::vector extract_indices_of_type(E_Int inout); @@ -111,11 +118,12 @@ struct Dcel { void trace_hedge(Hedge *sh, const Smesh &M, const Smesh &S, E_Int hid); - E_Int trace_hedge_2(Hedge *sh, const Smesh &M, const Smesh &S, E_Int hid, - std::map> &hedge_intersections); + E_Int trace_hedge_2(Hedge *sh, const Smesh &M, const Smesh &S, E_Int hid); - void cut_hedges(std::map> &hmap); + void cut_hedges(); void sort_leaving_hedges(std::vector &leaving, const E_Float N[3], const Smesh &M) const; + + Smesh export_smesh() const; }; diff --git a/Cassiopee/XCore/XCore/intersectMesh/extract.cpp b/Cassiopee/XCore/XCore/intersectMesh/extract.cpp index ea70443d9..5d9edb524 100644 --- a/Cassiopee/XCore/XCore/intersectMesh/extract.cpp +++ b/Cassiopee/XCore/XCore/intersectMesh/extract.cpp @@ -1,5 +1,5 @@ #include "mesh.h" -#include "karray.h" +#include "common/Karray.h" PyObject *K_XCORE::extractCell(PyObject *self, PyObject *args) { @@ -19,7 +19,7 @@ PyObject *K_XCORE::extractCell(PyObject *self, PyObject *args) if (ret != 0) return NULL; - IMesh M(*marray.cn, marray.X, marray.Y, marray.Z, marray.npts); + IMesh M(*marray.cn, marray.X(), marray.Y(), marray.Z(), marray.npts); IMesh M_out; diff --git a/Cassiopee/XCore/XCore/intersectMesh/file b/Cassiopee/XCore/XCore/intersectMesh/file new file mode 100644 index 000000000..e69de29bb diff --git a/Cassiopee/XCore/XCore/intersectMesh/icapsule.cpp b/Cassiopee/XCore/XCore/intersectMesh/icapsule.cpp new file mode 100644 index 000000000..f49996350 --- /dev/null +++ b/Cassiopee/XCore/XCore/intersectMesh/icapsule.cpp @@ -0,0 +1,191 @@ +#include "icapsule.h" +#include "common/Karray.h" +#include "point.h" +#include "io.h" + +Smesh IMesh::make_patch(const E_Float *ptag) +{ + patch.clear(); + + for (E_Int fid : skin) { + const auto &pn = F[fid]; + bool is_patch = true; + for (E_Int pid : pn) { + if (ptag[pid] != 1) { + is_patch = false; + break; + } + } + if (is_patch) + patch.insert(fid); + } + + return Smesh(*this); +} + +Smesh IMesh::make_patch(const Smesh &spatch) +{ + //patch.clear(); + + return Smesh(); +} + +ICapsule::ICapsule(const Karray &marray, const std::vector &sarrays, + const std::vector &ptags) +{ + M = IMesh(marray); + M.make_skin(); + M.orient_skin(OUT); + M.triangulate_skin(); + M.make_bbox(); + M.hash_skin(); + + Ss.reserve(sarrays.size()); + spatches.reserve(sarrays.size()); + + std::vector> plocs; + plocs.reserve(sarrays.size()); + + for (size_t i = 0; i < sarrays.size(); i++) { + Ss.push_back(IMesh(sarrays[i])); + Ss[i].make_skin(); + Ss[i].orient_skin(IN); + Ss[i].triangulate_skin(); + spatches.push_back(Ss[i].make_patch(ptags[i])); + plocs.push_back(M.locate(spatches[i])); + } + + // Correct near-vertex/edge situations + std::vector points; + for (size_t i = 0; i < sarrays.size(); i++) { + const Smesh &Sf = spatches[i]; + const std::vector &locs = plocs[i]; + assert(locs.size() == (size_t)spatches[i].np); + E_Int on_vertex = 0, on_edge = 0; + for (size_t j = 0; j < locs.size(); j++) { + if (locs[j].v_idx != -1) on_vertex++; + else if (locs[j].e_idx != -1) { + on_edge++; + points.push_back(Point(Sf.X[j], Sf.Y[j], Sf.Z[j])); + } + } + printf("on vertex: %d - on edge: %d\n", on_vertex, on_edge); + } + + point_write("points", points); + + mpatches.reserve(sarrays.size()); +} + + +PyObject *K_XCORE::icapsule_extract_master(PyObject *self, PyObject *args) +{ + PyObject *ICAPSULE; + if (!PYPARSETUPLE_(args, O_, &ICAPSULE)) { + RAISE("Bad input."); + return NULL; + } + + if (!PyCapsule_IsValid(ICAPSULE, "ICapsule")) { + RAISE("Bad ICapsule hook."); + return NULL; + } + + ICapsule *icap = (ICapsule *)PyCapsule_GetPointer(ICAPSULE, "ICapsule"); + + auto Mout = icap->M.export_karray(); + + return Mout; +} + +PyObject *K_XCORE::icapsule_extract_slave(PyObject *self, PyObject *args) +{ + PyObject *ICAPSULE; + E_Int INDEX; + if (!PYPARSETUPLE_(args, O_ I_, &ICAPSULE, &INDEX)) { + RAISE("Bad input."); + return NULL; + } + + if (!PyCapsule_IsValid(ICAPSULE, "ICapsule")) { + RAISE("Bad ICapsule hook."); + return NULL; + } + + ICapsule *icap = (ICapsule *)PyCapsule_GetPointer(ICAPSULE, "ICapsule"); + + auto Sout = icap->Ss[INDEX].export_karray(); + + return Sout; +} + +PyObject *K_XCORE::icapsule_init(PyObject *self, PyObject *args) +{ + PyObject *MASTER, *SLAVES, *PTAGS; + if (!PYPARSETUPLE_(args, OOO_, &MASTER, &SLAVES, &PTAGS)) { + RAISE("Bad input."); + return NULL; + } + + Karray marray; + if (Karray_parse_ngon(MASTER, marray) != 0) { + RAISE("Master should be an NGon."); + return NULL; + } + + E_Int nslaves = PyList_Size(SLAVES); + std::vector sarrays(nslaves); + E_Int ok = 0; + + for (E_Int i = 0; i < nslaves; i++) { + PyObject *SLAVE = PyList_GetItem(SLAVES, i); + E_Int ret = Karray_parse_ngon(SLAVE, sarrays[i]); + Py_DECREF(SLAVE); + if (ret != 0) { + RAISE("Slaves should be NGons."); + break; + } + ok++; + } + + if (ok != nslaves) { + Karray_free_ngon(marray); + for (E_Int i = 0; i < ok; i++) + Karray_free_ngon(sarrays[i]); + return NULL; + } + + std::vector ptags(nslaves, NULL); + + if (PyList_Size(PTAGS) != nslaves) { + RAISE("Ptags should be the same size as slaves."); + Karray_free_ngon(marray); + for (E_Int i = 0; i < nslaves; i++) + Karray_free_ngon(sarrays[i]); + return NULL; + } + + for (E_Int i = 0; i < nslaves; i++) { + PyObject *PTAG = PyList_GetItem(PTAGS, i); + E_Int size = -1; + E_Int ret = K_NUMPY::getFromNumpyArray(PTAG, ptags[i], size, true); + Py_DECREF(PTAG); + if (ret != 1 || size != sarrays[i].npoints()) { + RAISE("Ptag[i] should have size sarrays[i].npoints."); + Karray_free_ngon(marray); + for (E_Int j = 0; j < nslaves; j++) + Karray_free_ngon(sarrays[j]); + return NULL; + } + } + + ICapsule *icap = new ICapsule(marray, sarrays, ptags); + + PyObject *out = PyCapsule_New((void *)icap, "ICapsule", NULL); + + Karray_free_ngon(marray); + for (E_Int i = 0; i < nslaves; i++) + Karray_free_ngon(sarrays[i]); + + return out; +} diff --git a/Cassiopee/XCore/XCore/intersectMesh/icapsule.h b/Cassiopee/XCore/XCore/intersectMesh/icapsule.h new file mode 100644 index 000000000..b5af1a3a2 --- /dev/null +++ b/Cassiopee/XCore/XCore/intersectMesh/icapsule.h @@ -0,0 +1,13 @@ +#pragma once + +#include "mesh.h" + +struct ICapsule { + IMesh M; + std::vector Ss; + std::vector mpatches; + std::vector spatches; + + ICapsule(const Karray &marray, const std::vector &sarray, + const std::vector &ptags); +}; diff --git a/Cassiopee/XCore/XCore/intersectMesh/intersectMesh.cpp b/Cassiopee/XCore/XCore/intersectMesh/intersectMesh.cpp index a207ad31d..e214274b3 100644 --- a/Cassiopee/XCore/XCore/intersectMesh/intersectMesh.cpp +++ b/Cassiopee/XCore/XCore/intersectMesh/intersectMesh.cpp @@ -17,7 +17,7 @@ along with Cassiopee. If not, see . */ #include "xcore.h" -#include "karray.h" +#include "common/Karray.h" #include "common/common.h" #include "mesh.h" #include "smesh.h" @@ -131,6 +131,33 @@ IMesh reconstruct_mesh(IMesh &M, Smesh &Mf, const Dcel &D, E_Int color) // All ofaces must be present in the map assert(ofid_to_ofids.size() == pfset.size()); + /* + { + if (color == 1) { + std::vector faces; + auto it = ofid_to_ofids.find(24406); + assert(it != ofid_to_ofids.end()); + const auto &pf = it->second; + printf("number of children: %lu\n", pf.size()); + for (auto i : pf) faces.push_back(D.F[i]); + faces_write("children1", faces); + } + + if (color == 1) { + std::vector faces; + auto it = ofid_to_ofids.find(40246); + assert(it != ofid_to_ofids.end()); + const auto &pf = it->second; + printf("number of children: %lu\n", pf.size()); + for (auto i : pf) { + char fname[64] = {0}; + sprintf(fname, "child%d", i); + face_write(fname, D.F[i]); + } + } + } + */ + // Write untouched points std::vector new_X(np, -1), new_Y(np, -1), new_Z(np, -1); for (const auto &pt : new_pids) { @@ -313,8 +340,8 @@ PyObject *K_XCORE::intersectMesh(PyObject *self, PyObject *args) } // Init and orient master/slave meshes - IMesh M(*marray.cn, marray.X, marray.Y, marray.Z, marray.npts); - IMesh S(*sarray.cn, sarray.X, sarray.Y, sarray.Z, sarray.npts); + IMesh M(*marray.cn, marray.X(), marray.Y(), marray.Z(), marray.npts); + IMesh S(*sarray.cn, sarray.X(), sarray.Y(), sarray.Z(), sarray.npts); M.make_skin(); S.make_skin(); @@ -349,6 +376,21 @@ PyObject *K_XCORE::intersectMesh(PyObject *self, PyObject *args) for (E_Int i = 0; i < mpatch_size; i++) M.patch.insert(mpatch[i]-1); for (E_Int i = 0; i < spatch_size; i++) S.patch.insert(spatch[i]-1); + + { + //E_Int weird[2]; + //E_Int count = 0; + //const auto &pf = S.C[7726]; + //for (auto fid : pf) { + // if (S.patch.find(fid) != S.patch.end()) { + // weird[count++] = fid; + // assert(count == 1 || count == 2); + // } + //} + //printf("weirds: %d - %d\n", weird[0], weird[1]); + } + + // Extract surface meshes Smesh Mf(M); Smesh Sf(S); @@ -374,8 +416,28 @@ PyObject *K_XCORE::intersectMesh(PyObject *self, PyObject *args) puts("Initaliazing..."); + /* + puts("Doing Mf to Dcel"); + Dcel Dm(Mf, Dcel::RED); + Dm.export_smesh(); + puts("Doing Sf to Dcel"); + Dcel Ds(Sf, Dcel::RED); + Ds.export_smesh(); + */ + Dcel D(Mf, Sf); + /* + { + Face *f1 = D.F[Mf.nf + Sf.g2lf[D.weird1]]; + Face *f2 = D.F[Mf.nf + Sf.g2lf[D.weird2]]; + face_write("f1", f1); + face_write("f2", f2); + } + */ + + + /* for (Vertex *v : D.V) { if (v->oid[0] != -1) { @@ -408,6 +470,11 @@ PyObject *K_XCORE::intersectMesh(PyObject *self, PyObject *args) D.reconstruct(Mf, Sf); + puts("Constructing surface mesh..."); + + //Smesh smesh = D.export_smesh(); + //smesh.write_ngon("smesh"); + for (Vertex *v : D.V) { E_Int oid = v->oid[0]; if (oid != -1) v->oid[0] = Mf.l2gp[oid]; diff --git a/Cassiopee/XCore/XCore/intersectMesh/karray.cpp b/Cassiopee/XCore/XCore/intersectMesh/karray.cpp deleted file mode 100644 index 19fed4c35..000000000 --- a/Cassiopee/XCore/XCore/intersectMesh/karray.cpp +++ /dev/null @@ -1,116 +0,0 @@ -/* - Copyright 2013-2024 Onera. - - This file is part of Cassiopee. - - Cassiopee is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - Cassiopee is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with Cassiopee. If not, see . -*/ -#include "karray.h" -#include "common/common.h" - -void Karray_free_ngon(Karray &karray) -{ - RELEASESHAREDU(karray.pyobject, karray.f, karray.cn); -} - -E_Int Karray_parse_ngon(PyObject *pyobject, Karray &karray) -{ - E_Int ret; - - char *varString; - char *eltType; - - ret = K_ARRAY::getFromArray3(pyobject, varString, karray.f, karray.ni, - karray.nj, karray.nk, karray.cn, eltType); - - if (ret <= 0) { - RAISE("Bad input array."); - return 1; - } - - if (ret == 1) { - RAISE("IMesh should be an NGon."); - Karray_free_structured(karray); - return 1; - } - - E_Int posx = K_ARRAY::isCoordinateXPresent(varString); - E_Int posy = K_ARRAY::isCoordinateYPresent(varString); - E_Int posz = K_ARRAY::isCoordinateZPresent(varString); - - if (posx == -1 || posy == -1 || posz == -1) { - Karray_free_ngon(karray); - RAISE("Coordinates not found."); - return 1; - } - - posx++; posy++; posz++; - - karray.X = karray.f->begin(posx); - karray.Y = karray.f->begin(posy); - karray.Z = karray.f->begin(posz); - karray.npts = karray.f->getSize(); - - karray.pyobject = pyobject; - - return 0; -} - -void Karray_free_structured(Karray &karray) -{ - RELEASESHAREDS(karray.pyobject, karray.f); -} - -E_Int Karray_parse_structured(PyObject *pyobject, Karray &karray) -{ - E_Int ret; - - char *varString; - char *eltType; - - ret = K_ARRAY::getFromArray3(pyobject, varString, karray.f, karray.ni, - karray.nj, karray.nk, karray.cn, eltType); - - if (ret <= 0) { - RAISE("Bad input array"); - return 1; - } - - if (ret != 1) { - RAISE("IMesh should be structured."); - RELEASESHAREDB(ret, pyobject, karray.f, karray.cn); - return 1; - } - - E_Int posx = K_ARRAY::isCoordinateXPresent(varString); - E_Int posy = K_ARRAY::isCoordinateYPresent(varString); - E_Int posz = K_ARRAY::isCoordinateZPresent(varString); - - if (posx == -1 || posy == -1 || posz == -1) { - RAISE("Coordinates not found"); - Karray_free_structured(karray); - return 1; - } - - posx++; posy++; posz++; - - karray.X = karray.f->begin(posx); - karray.Y = karray.f->begin(posy); - karray.Z = karray.f->begin(posz); - karray.npts = karray.f->getSize(); - - karray.pyobject = pyobject; - - return 0; -} \ No newline at end of file diff --git a/Cassiopee/XCore/XCore/intersectMesh/karray.h b/Cassiopee/XCore/XCore/intersectMesh/karray.h deleted file mode 100644 index 439bf2d4b..000000000 --- a/Cassiopee/XCore/XCore/intersectMesh/karray.h +++ /dev/null @@ -1,59 +0,0 @@ -/* - Copyright 2013-2024 Onera. - - This file is part of Cassiopee. - - Cassiopee is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - Cassiopee is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with Cassiopee. If not, see . -*/ -#pragma once - -#include "xcore.h" -#include "common/common.h" - -struct Karray { - // Reference to the python array - PyObject *pyobject; - - K_FLD::FldArrayF *f; - E_Int ni, nj, nk; - - K_FLD::FldArrayI *cn; - - E_Float *X, *Y, *Z; - E_Int npts; - - inline E_Int *indpg() const { return cn->getIndPG(); } - inline E_Int *indph() const { return cn->getIndPH(); } - - inline E_Int *ngon() const { return cn->getNGon(); } - inline E_Int *nface() const { return cn->getNFace(); } - - inline E_Int *get_face(E_Int face, E_Int &np) const - { return cn->getFace(face, np, ngon(), indpg()); } - - inline E_Int *get_cell(E_Int cell, E_Int &nf) const - { return cn->getElt(cell, nf, nface(), indph()); } - - inline E_Int npoints() const { return npts; } - inline E_Int nfaces() const { return cn->getNFaces(); } - inline E_Int ncells() const { return cn->getNElts(); } -}; - -void Karray_free_ngon(Karray &karray); - -E_Int Karray_parse_ngon(PyObject *pyobject, Karray &karray); - -void Karray_free_structured(Karray &karray); - -E_Int Karray_parse_structured(PyObject *pyobject, Karray &karray); \ No newline at end of file diff --git a/Cassiopee/XCore/XCore/intersectMesh/locate.cpp b/Cassiopee/XCore/XCore/intersectMesh/locate.cpp new file mode 100644 index 000000000..6c36fea41 --- /dev/null +++ b/Cassiopee/XCore/XCore/intersectMesh/locate.cpp @@ -0,0 +1,67 @@ +#include "mesh.h" +#include "triangle.h" +#include "primitives.h" + +std::vector IMesh::locate(const Smesh &Sf) +{ + std::vector ploc(Sf.np); + + for (E_Int pid = 0; pid < Sf.np; pid++) { + + E_Float x = Sf.X[pid]; + E_Float y = Sf.Y[pid]; + E_Float z = Sf.Z[pid]; + + E_Int I = floor((x - xmin) / HX); + E_Int J = floor((y - ymin) / HY); + E_Int K = floor((z - zmin) / HZ); + E_Int voxel = get_voxel(I, J, K); + + const auto &pf = bin_faces[voxel]; + + bool found = false; + + // w, u, v + auto &loc = ploc[pid]; + assert(loc.fid == -1); + assert(loc.v_idx == -1); + assert(loc.e_idx == -1); + assert(loc.u == -1); + assert(loc.v == -1); + assert(loc.w == -1); + + for (size_t i = 0; i < pf.size() && !found; i++) { + E_Int fid = pf[i]; + const auto &pn = F[fid]; + E_Int a = pn[0], b = pn[1], c = pn[2]; + E_Float u, v, w; + if (Triangle::is_point_inside( + x, y, z, + X[a], Y[a], Z[a], + X[b], Y[b], Z[b], + X[c], Y[c], Z[c], + u, v, w)) { + + found = true; + + loc.fid = fid; + loc.u = u; + loc.v = v; + loc.w = w; + + if (Sign(1-u, 1e-3) == 0) loc.v_idx = 0; + else if (Sign(1-v, 1e-3) == 0) loc.v_idx = 1; + else if (Sign(1-w, 1e-3) == 0) loc.v_idx = 2; + else if (Sign(w, 1e-3) == 0) loc.e_idx = 0; + else if (Sign(u, 1e-3) == 0) loc.e_idx = 1; + else if (Sign(v, 1e-3) == 0) loc.e_idx = 2; + + break; + } + } + + assert(found); + } + + return ploc; +} diff --git a/Cassiopee/XCore/XCore/intersectMesh/mesh.cpp b/Cassiopee/XCore/XCore/intersectMesh/mesh.cpp index 76eff7a4e..2cddc90d8 100644 --- a/Cassiopee/XCore/XCore/intersectMesh/mesh.cpp +++ b/Cassiopee/XCore/XCore/intersectMesh/mesh.cpp @@ -32,9 +32,12 @@ #include "primitives.h" #include "ray.h" #include "io.h" +#include "common/Karray.h" void IMesh::triangulate_face_set(bool propagate) { + make_skin(); + if (propagate) { E_Float xmin, ymin, zmin, xmax, ymax, zmax; xmin = ymin = zmin = EFLOATMAX; @@ -52,7 +55,6 @@ void IMesh::triangulate_face_set(bool propagate) } } - make_skin(); faces_to_tri.clear(); @@ -75,18 +77,6 @@ void IMesh::triangulate_face_set(bool propagate) F.resize(NF + face_incr); - std::vector owner(NF, -1), neigh(NF, -1); - - for (E_Int i = 0; i < nc; i++) { - const auto &pf = C[i]; - for (E_Int fid : pf) { - if (owner[fid] == -1) owner[fid] = i; - else neigh[fid] = i; - } - } - - assert(skin.size() > 0); - patch.clear(); for (E_Int fid : faces_to_tri) { @@ -224,6 +214,49 @@ bool IMesh::faces_are_dups(E_Int mface, E_Int sface, const IMesh &S) IMesh::IMesh() {} +IMesh::IMesh(const Karray &karray) +{ + np = karray.npoints(); + nf = karray.nfaces(); + nc = karray.ncells(); + + X.resize(np); + Y.resize(np); + Z.resize(np); + for (E_Int i = 0; i < np; i++) { + X[i] = karray.x[i]; + Y[i] = karray.y[i]; + Z[i] = karray.z[i]; + } + + F.reserve(nf); + for (E_Int fid = 0; fid < nf; fid++) { + E_Int np = -1; + E_Int *pn = karray.get_face(fid, np); + std::vector points(np); + for (E_Int j = 0; j < np; j++) + points[j] = pn[j] - 1; + F.push_back(points); + } + + C.reserve(nc); + for (E_Int cid = 0; cid < nc; cid++) { + E_Int nf = -1; + E_Int *pf = karray.get_cell(cid, nf); + std::vector faces(nf); + for (E_Int j = 0; j < nf; j++) + faces[j] = pf[j] - 1; + C.push_back(faces); + } + + // Grid + NX = 100; + NY = 100; + NZ = 100; + NXY = NX * NY; + NXYZ = NXY * NZ; +} + IMesh::IMesh(K_FLD::FldArrayI &cn, E_Float *x, E_Float *y, E_Float *z, E_Int npts) { NX = 100; @@ -306,30 +339,37 @@ void IMesh::make_bbox() if (Z[i] > zmax) zmax = Z[i]; } + xmin = xmin - (xmax - xmin) * 0.01; + ymin = ymin - (ymax - ymin) * 0.01; + zmin = zmin - (zmax - zmin) * 0.01; xmax = xmax + (xmax - xmin) * 0.01; ymax = ymax + (ymax - ymin) * 0.01; zmax = zmax + (zmax - zmin) * 0.01; - - HX = (xmax - xmin) / NX; - HY = (ymax - ymin) / NY; - HZ = (zmax - zmin) / NZ; } void IMesh::make_skin() { skin.clear(); + owner.clear(); + neigh.clear(); + + owner.resize(nf, -1); + neigh.resize(nf, -1); + std::vector count(nf, 0); - - for (const auto &cn : C) { - for (E_Int face : cn) - count[face]++; + + for (E_Int cid = 0; cid < nc; cid++) { + const auto &pf = C[cid]; + for (auto fid : pf) { + if (owner[fid] == -1) owner[fid] = cid; + else neigh[fid] = cid; + } } - for (E_Int i = 0; i < nf; i++) { - E_Int c = count[i]; - assert(c == 1 || c == 2); - if (c == 1) skin.push_back(i); + for (E_Int fid = 0; fid < nf; fid++) { + if (neigh[fid] == -1) + skin.push_back(fid); } } diff --git a/Cassiopee/XCore/XCore/intersectMesh/mesh.h b/Cassiopee/XCore/XCore/intersectMesh/mesh.h index c0a50578d..2fb1f0d28 100644 --- a/Cassiopee/XCore/XCore/intersectMesh/mesh.h +++ b/Cassiopee/XCore/XCore/intersectMesh/mesh.h @@ -29,12 +29,13 @@ #include "common/common.h" #include "triangleIntersection.h" #include "AABB.h" +#include "smesh.h" #define OUT 0 #define IN 1 struct Ray; -struct Smesh; +struct Karray; struct UEdge { E_Int p, q; @@ -51,6 +52,13 @@ struct UEdge { } }; +struct skin_graph { + const std::vector &skin; + + + +}; + struct IMesh { E_Int np, ne, nf, nc; @@ -65,6 +73,8 @@ struct IMesh { std::vector> C; std::vector skin; + std::vector owner; + std::vector neigh; E_Float xmin, ymin, zmin; E_Float xmax, ymax, zmax; @@ -82,6 +92,9 @@ struct IMesh { std::vector ctag; + Smesh make_patch(const E_Float *ptag); + Smesh make_patch(const Smesh &spatch); + inline E_Int get_voxel(E_Int I, E_Int J, E_Int K) const { return I + J * NX + (NX * NY) * K; @@ -97,12 +110,16 @@ struct IMesh { void triangulate_face_set(bool propagate = true); + void triangulate_skin(); + size_t refine_slave(const IMesh &master); void hash_patch(); IMesh(); + IMesh(const Karray &karray); + IMesh(K_FLD::FldArrayI &cn, E_Float *X, E_Float *Y, E_Float *Z, E_Int npts); void make_patch(E_Int *faces, E_Int nfaces); @@ -152,6 +169,8 @@ struct IMesh { size_t refine(const IMesh &S); + std::vector locate(const Smesh &Sf); + //std::vector locate(E_Int p, E_Float x, E_Float y, E_Float z, // const std::set &patch) const; diff --git a/Cassiopee/XCore/XCore/intersectMesh/meshExport.cpp b/Cassiopee/XCore/XCore/intersectMesh/meshExport.cpp index 0eb373a5f..ba3d7c72e 100644 --- a/Cassiopee/XCore/XCore/intersectMesh/meshExport.cpp +++ b/Cassiopee/XCore/XCore/intersectMesh/meshExport.cpp @@ -193,7 +193,6 @@ PyObject *IMesh::export_karray_orig() delete f; delete cn; - return array; } @@ -287,4 +286,4 @@ IMesh IMesh::extract_conformized() } return new_M; -} \ No newline at end of file +} diff --git a/Cassiopee/XCore/XCore/intersectMesh/meshRefine.cpp b/Cassiopee/XCore/XCore/intersectMesh/meshRefine.cpp index e0ceb70a0..e74e52b22 100644 --- a/Cassiopee/XCore/XCore/intersectMesh/meshRefine.cpp +++ b/Cassiopee/XCore/XCore/intersectMesh/meshRefine.cpp @@ -48,16 +48,14 @@ E_Int meshes_mutual_refinement(IMesh &M, IMesh &S) printf("Refined mf: %zu\n", refM); // Refine S wrt M - /* - if (iter == 1 || (iter > 1 && refM > 0)) { + /*if (iter == 1 || (iter > 1 && refM > 0)) { M.make_point_faces(); S.make_bbox(); S.hash_skin(); // TODO(Imad): hash_patch! refS = S.refine_slave(M); printf("Refined sf: %zu\n", refS); - } - */ + }*/ } while (refS > 0); diff --git a/Cassiopee/XCore/XCore/intersectMesh/point.h b/Cassiopee/XCore/XCore/intersectMesh/point.h index 3cde67d91..9ee0296e2 100644 --- a/Cassiopee/XCore/XCore/intersectMesh/point.h +++ b/Cassiopee/XCore/XCore/intersectMesh/point.h @@ -22,6 +22,15 @@ typedef Vec3 Point; +struct PointLoc { + E_Int fid = -1; + E_Int v_idx = -1; + E_Int e_idx = -1; + E_Float u = -1; + E_Float v = -1; + E_Float w = -1; +}; + struct pointFace { E_Int F; diff --git a/Cassiopee/XCore/XCore/intersectMesh/prepareMeshesForIntersection.cpp b/Cassiopee/XCore/XCore/intersectMesh/prepareMeshesForIntersection.cpp index 7a3438af7..8069bb338 100644 --- a/Cassiopee/XCore/XCore/intersectMesh/prepareMeshesForIntersection.cpp +++ b/Cassiopee/XCore/XCore/intersectMesh/prepareMeshesForIntersection.cpp @@ -17,7 +17,7 @@ along with Cassiopee. If not, see . */ #include "xcore.h" -#include "karray.h" +#include "common/Karray.h" #include "common/common.h" #include "mesh.h" #include "smesh.h" @@ -72,7 +72,7 @@ PyObject *K_XCORE::prepareMeshesForIntersection(PyObject *self, PyObject *args) // TODO(Imad): quasi-planar surfaces // Init master/slave meshes - IMesh S(*sarray.cn, sarray.X, sarray.Y, sarray.Z, sarray.npts); + IMesh S(*sarray.cn, sarray.X(), sarray.Y(), sarray.Z(), sarray.npts); S.make_skin(); S.patch.clear(); @@ -103,6 +103,8 @@ PyObject *K_XCORE::prepareMeshesForIntersection(PyObject *self, PyObject *args) printf("S.patch size after triangulation: %lu\n", S.patch.size()); + //M.project_patch(S); + puts("Adapting intersection zones..."); printf("M.patch size before refinement: %lu\n", M.patch.size()); diff --git a/Cassiopee/XCore/XCore/intersectMesh/primitives.cpp b/Cassiopee/XCore/XCore/intersectMesh/primitives.cpp index b1be4c1cc..0781bacc4 100644 --- a/Cassiopee/XCore/XCore/intersectMesh/primitives.cpp +++ b/Cassiopee/XCore/XCore/intersectMesh/primitives.cpp @@ -25,10 +25,10 @@ E_Float TOL = 1e-12; -E_Int Sign(E_Float x) +E_Int Sign(E_Float x, E_Float tol) { - if (x > TOL) return 1; - if (x < -TOL) return -1; + if (x > tol) return 1; + if (x < -tol) return -1; //assert(x == 0.0); return 0; } diff --git a/Cassiopee/XCore/XCore/intersectMesh/primitives.h b/Cassiopee/XCore/XCore/intersectMesh/primitives.h index bc359f707..ce3d26115 100644 --- a/Cassiopee/XCore/XCore/intersectMesh/primitives.h +++ b/Cassiopee/XCore/XCore/intersectMesh/primitives.h @@ -42,7 +42,7 @@ E_Float DifferenceOfProducts(E_Float a, E_Float b, E_Float c, E_Float d); E_Float TwoDiff(E_Float a, E_Float b); -E_Int Sign(E_Float x); +E_Int Sign(E_Float x, E_Float tol=TOL); E_Int orient3D(E_Float *A, E_Float *B, E_Float *C, E_Float *D); diff --git a/Cassiopee/XCore/XCore/intersectMesh/project.cpp b/Cassiopee/XCore/XCore/intersectMesh/project.cpp new file mode 100644 index 000000000..57e51bae2 --- /dev/null +++ b/Cassiopee/XCore/XCore/intersectMesh/project.cpp @@ -0,0 +1,20 @@ +#include "mesh.h" + +void IMesh::grid_patch() +{ + + + + + +} + +void IMesh::project_patch(const IMesh &S) +{ + + + + + + +} diff --git a/Cassiopee/XCore/XCore/intersectMesh/removeIntersectingKPlanes.cpp b/Cassiopee/XCore/XCore/intersectMesh/removeIntersectingKPlanes.cpp index 363c1a544..01bb91354 100644 --- a/Cassiopee/XCore/XCore/intersectMesh/removeIntersectingKPlanes.cpp +++ b/Cassiopee/XCore/XCore/intersectMesh/removeIntersectingKPlanes.cpp @@ -18,7 +18,7 @@ */ #include "xcore.h" #include "common/common.h" -#include "karray.h" +#include "common/Karray.h" #include "mesh.h" #include "ray.h" #include "io.h" @@ -63,9 +63,9 @@ PyObject *handle_slave(IMesh *M, Karray& sarray) E_Int nk = sarray.nk; E_Int nij = ni * nj; - E_Float *Xs = sarray.X; - E_Float *Ys = sarray.Y; - E_Float *Zs = sarray.Z; + E_Float *Xs = sarray.X(); + E_Float *Ys = sarray.Y(); + E_Float *Zs = sarray.Z(); // Last k-plane outside of M std::vector kmax(nij, -1); @@ -132,13 +132,6 @@ PyObject *handle_slave(IMesh *M, Karray& sarray) point_hit_table[p] = TI; } - for (const auto &ploc : point_hit_table) { - E_Int fid = ploc.second.face; - const auto &pn = M->F[fid]; - assert(pn.size() == 4); - M->faces_to_tri.insert(fid); - } - // Construct the new faces and cells std::vector> faces; @@ -376,9 +369,9 @@ E_Int get_kmax(IMesh *M, Karray& sarray) E_Int nk = sarray.nk; E_Int nij = ni * nj; - E_Float *Xs = sarray.X; - E_Float *Ys = sarray.Y; - E_Float *Zs = sarray.Z; + E_Float *Xs = sarray.X(); + E_Float *Ys = sarray.Y(); + E_Float *Zs = sarray.Z(); E_Int kmax = -1; @@ -411,9 +404,9 @@ PyObject *handle_slave2(IMesh *M, Karray& sarray, E_Int kmax) E_Int nk = sarray.nk; E_Int nij = ni * nj; - E_Float *Xs = sarray.X; - E_Float *Ys = sarray.Y; - E_Float *Zs = sarray.Z; + E_Float *Xs = sarray.X(); + E_Float *Ys = sarray.Y(); + E_Float *Zs = sarray.Z(); // Indices of points to be projected std::vector proj_points; @@ -461,13 +454,6 @@ PyObject *handle_slave2(IMesh *M, Karray& sarray, E_Int kmax) point_hit_table[p] = TI; } - for (const auto &ploc : point_hit_table) { - E_Int fid = ploc.second.face; - const auto &pn = M->F[fid]; - assert(pn.size() == 4); - M->faces_to_tri.insert(fid); - } - // Make out cartesian mesh PyObject *tpl; nk = kmax + 2; @@ -571,6 +557,7 @@ PyObject *K_XCORE::removeIntersectingKPlanes(PyObject *self, PyObject *args) return NULL; } + /* E_Int kmax = 10000000; for (E_Int i = 0; i < nslaves; i++) { @@ -580,13 +567,14 @@ PyObject *K_XCORE::removeIntersectingKPlanes(PyObject *self, PyObject *args) } printf("kmax: %d\n", kmax); + */ PyObject *slaves_out = PyList_New(0); for (E_Int i = 0; i < nslaves; i++) { printf("Projecting %d / %d\n", i+1, nslaves); - PyObject *st = handle_slave2(M, sarrays[i], kmax); - //PyObject *st = handle_slave(M, sarrays[i]); + //PyObject *st = handle_slave2(M, sarrays[i], kmax); + PyObject *st = handle_slave(M, sarrays[i]); PyList_Append(slaves_out, st); Py_DECREF(st); Karray_free_structured(sarrays[i]); diff --git a/Cassiopee/XCore/XCore/intersectMesh/smesh.cpp b/Cassiopee/XCore/XCore/intersectMesh/smesh.cpp index 11faca7bc..8d95ee4c4 100644 --- a/Cassiopee/XCore/XCore/intersectMesh/smesh.cpp +++ b/Cassiopee/XCore/XCore/intersectMesh/smesh.cpp @@ -52,7 +52,6 @@ bool Smesh::ccw_oriented(E_Int face) Smesh::Smesh(const IMesh &M) { F.resize(M.patch.size()); - //assert(M.patch.size() == M.skin.size()); nf = 0; np = 0; @@ -166,6 +165,14 @@ void Smesh::make_edges() // Check + + assert(np - ne + nf + 1 == 2); + + for (E_Int i = 0; i < ne; i++) { + assert(count[i] == 1 || count[i] == 2); + } + + for (E_Int i = 0; i < ne; i++) { E_Int fi = E2F[i][0]; E_Int fj = E2F[i][1]; @@ -860,7 +867,7 @@ void Smesh::make_fnormals() E_Float *N = &fnormals[3*fid]; K_MATH::cross(oa, ob, N); E_Float NORM = K_MATH::norm(N, 3); - assert(Sign(NORM) != 0); + //assert(Sign(NORM) != 0); for (E_Int i = 0; i < 3; i++) N[i] /= NORM; } } diff --git a/Cassiopee/XCore/XCore/intersectMesh/trace.cpp b/Cassiopee/XCore/XCore/intersectMesh/trace.cpp index f15fe0143..f925dd701 100644 --- a/Cassiopee/XCore/XCore/intersectMesh/trace.cpp +++ b/Cassiopee/XCore/XCore/intersectMesh/trace.cpp @@ -37,7 +37,7 @@ bool ray_edge_intersect(E_Float ox, E_Float oy, E_Float oz, K_MATH::cross(v, dl, tmp); t = K_MATH::dot(tmp, n, 3) / denom; - + if (t < TOL) return false; K_MATH::cross(v, dr, tmp); @@ -173,8 +173,7 @@ void get_shared_faces(const Vertex *v, const Smesh &M, std::vector &ret, } } -E_Int Dcel::trace_hedge_2(Hedge *sh, const Smesh &M, const Smesh &S, E_Int hid, - std::map> &hedge_intersections) +E_Int Dcel::trace_hedge_2(Hedge *sh, const Smesh &M, const Smesh &S, E_Int hid) { Vertex *O = sh->orig; Vertex *T = sh->twin->orig; @@ -207,11 +206,11 @@ E_Int Dcel::trace_hedge_2(Hedge *sh, const Smesh &M, const Smesh &S, E_Int hid, E_Int walk = 0; E_Int max_walks = 20; - if (hid == 1953) hedge_write("sh", sh); + //if (hid == hid) hedge_write("sh", sh); while (!found_tail && walk <= max_walks) { - if (hid == 1953) face_write("current_face", F[current_fid]); + //if (hid == hid) face_write("current_face", F[current_fid]); // We are on current_face @@ -262,7 +261,7 @@ E_Int Dcel::trace_hedge_2(Hedge *sh, const Smesh &M, const Smesh &S, E_Int hid, if (hit) { - if (hid == 1953) point_write("hit", current_pos[0] + t * proj[0], current_pos[1] + t * proj[1], current_pos[2] + t * proj[2]); + //if (hid == hid) point_write("hit", current_pos[0] + t * proj[0], current_pos[1] + t * proj[1], current_pos[2] + t * proj[2]); // Intersection within the edge if (s > TOL && s < 1 - TOL) { @@ -296,9 +295,11 @@ E_Int Dcel::trace_hedge_2(Hedge *sh, const Smesh &M, const Smesh &S, E_Int hid, Event *xit = Q.lookup(next_pos[0], next_pos[1], next_pos[2]); Vertex *x = NULL; if (xit == NULL) { - x = new Vertex(next_pos[0], next_pos[1], next_pos[2]); + xit = Q.insert(next_pos[0], next_pos[1], next_pos[2]); + x = xit->key; x->id = V.size(); V.push_back(x); + x->meid = last_edge; } else { x = xit->key; dup_x++; @@ -306,7 +307,10 @@ E_Int Dcel::trace_hedge_2(Hedge *sh, const Smesh &M, const Smesh &S, E_Int hid, hedge_intersections[sh].push_back(x); // TODO(Imad): H[eid] or its twin? - hedge_intersections[H[eid]].push_back(x); + Hedge *mh = H[2*eid]; + if (cmp_vtx(mh->orig, mh->twin->orig) > 0) + mh = mh->twin; + hedge_intersections[mh].push_back(x); } // Intersection on an endpoint @@ -320,22 +324,16 @@ E_Int Dcel::trace_hedge_2(Hedge *sh, const Smesh &M, const Smesh &S, E_Int hid, if (hit_p) { assert(hit_q == false); - // Next_pos is p - next_pos[0] = M.X[p]; - next_pos[1] = M.Y[p]; - next_pos[2] = M.Z[p]; - last_vertex = p; } else if (hit_q) { - // Next_pos is q - next_pos[0] = M.X[q]; - next_pos[1] = M.Y[q]; - next_pos[2] = M.Z[q]; - last_vertex = q; } + + next_pos[0] = M.X[last_vertex]; + next_pos[1] = M.Y[last_vertex]; + next_pos[2] = M.Z[last_vertex]; const auto &pf = M.P2F[last_vertex]; diff --git a/Cassiopee/XCore/XCore/intersectMesh/triangle.cpp b/Cassiopee/XCore/XCore/intersectMesh/triangle.cpp index 0929cfc3a..55bb35a0e 100644 --- a/Cassiopee/XCore/XCore/intersectMesh/triangle.cpp +++ b/Cassiopee/XCore/XCore/intersectMesh/triangle.cpp @@ -29,34 +29,37 @@ E_Int Triangle::is_point_inside(E_Float px, E_Float py, E_Float pz, E_Float &u, E_Float &v, E_Float &w) { // Normal vector to the plane - E_Float Y[3] = {bx-ax, by-ay, bz-az}; - E_Float Z[3] = {cx-ax, cy-ay, cz-az}; + E_Float v0[3] = {bx-ax, by-ay, bz-az}; + E_Float v1[3] = {cx-ax, cy-ay, cz-az}; + E_Float v2[3] = {px-ax, py-ay, pz-az}; + E_Float N[3]; - K_MATH::cross(Y, Z, N); + K_MATH::cross(v0, v1, N); - E_Float X[3] = {px-ax, py-ay, pz-az}; + // TODO(Imad): check degenerate triangle with |N| = 0 - E_Float dp = K_MATH::dot(N, X, 3); + E_Float dp = K_MATH::dot(N, v2, 3); // Is the point on the plane? if (dp < -TOL || dp > TOL) return 0; - E_Float x1 = K_MATH::dot(X, Y, 3); - E_Float y1 = K_MATH::dot(Y, Y, 3); - E_Float z1 = K_MATH::dot(Z, Y, 3); - E_Float x2 = K_MATH::dot(X, Z, 3); - E_Float y2 = K_MATH::dot(Y, Z, 3); - E_Float z2 = K_MATH::dot(Z, Z, 3); + E_Float d00 = K_MATH::dot(v0, v0, 3); + E_Float d01 = K_MATH::dot(v0, v1, 3); + E_Float d11 = K_MATH::dot(v1, v1, 3); + E_Float d20 = K_MATH::dot(v2, v0, 3); + E_Float d21 = K_MATH::dot(v2, v1, 3); - u = (x1*z2 - x2*z1) / (y1*z2 - y2*z1); - if (u < -TOL || u > 1 + TOL) return 0; + E_Float denom = d00 * d11 - d01 * d01; - v = (-x1*y2 + x2*y1) / (y1*z2 - y2*z1); + v = (d11*d20 - d01*d21) / denom; if (v < -TOL || v > 1 + TOL) return 0; - - w = 1 - u - v; + + w = (d00*d21 - d01*d20) / denom; if (w < -TOL || w > 1 + TOL) return 0; + u = 1 - v - w; + if (u < -TOL || u > 1 + TOL) return 0; + return 1; } diff --git a/Cassiopee/XCore/XCore/intersectMesh/triangulate.cpp b/Cassiopee/XCore/XCore/intersectMesh/triangulate.cpp new file mode 100644 index 000000000..5e6f8b8f6 --- /dev/null +++ b/Cassiopee/XCore/XCore/intersectMesh/triangulate.cpp @@ -0,0 +1,54 @@ +#include "mesh.h" +#include "common/Karray.h" + +PyObject *K_XCORE::triangulate_skin(PyObject *self, PyObject *args) +{ + PyObject *MESH; + if (!PYPARSETUPLE_(args, O_, &MESH)) { + RAISE("Bad input."); + return NULL; + } + + Karray array; + if (Karray_parse_ngon(MESH, array) != 0) { + RAISE("Mesh should be an NGon."); + return NULL; + } + + IMesh M(array); + + M.make_skin(); + + M.triangulate_skin(); + + return M.export_karray(); +} + +void IMesh::triangulate_skin() +{ + E_Int NF = nf; + + for (auto fid : skin) { + assert(neigh[fid] == -1); + + const auto &pn = F[fid]; + if (pn.size() == 3) continue; + + assert(pn.size() == 4); + + E_Int nodes[4] = {pn[0], pn[1], pn[2], pn[3]}; + + F.push_back({nodes[2], nodes[3], nodes[0]}); + F[fid] = {nodes[0], nodes[1], nodes[2]}; + assert(F[fid].size() == 3); + + E_Int own = owner[fid]; + auto &pf = C[own]; + pf.push_back(nf); + + nf++; + } + + for (E_Int i = NF; i < nf; i++) + skin.push_back(i); +} diff --git a/Cassiopee/XCore/XCore/intersectMesh/vertex.h b/Cassiopee/XCore/XCore/intersectMesh/vertex.h index bede5833f..40d4faf7c 100644 --- a/Cassiopee/XCore/XCore/intersectMesh/vertex.h +++ b/Cassiopee/XCore/XCore/intersectMesh/vertex.h @@ -22,12 +22,7 @@ #include "xcore.h" #include "common/common.h" - -struct PointLoc { - E_Int fid = -1; - E_Int v_idx = -1; - E_Int e_idx = -1; -}; +#include "point.h" struct Hedge; @@ -40,7 +35,8 @@ struct Vertex { PointLoc loc; - Hedge *xhedge = NULL; + //Hedge *xhedge = NULL; + E_Int meid = -1; E_Float d = 0; diff --git a/Cassiopee/XCore/XCore/xcore.cpp b/Cassiopee/XCore/XCore/xcore.cpp index c69b73b0d..a43c2eb23 100644 --- a/Cassiopee/XCore/XCore/xcore.cpp +++ b/Cassiopee/XCore/XCore/xcore.cpp @@ -59,6 +59,11 @@ static PyMethodDef Pyxcore [] = {"IntersectMesh_Exit", K_XCORE::IntersectMesh_Exit, METH_VARARGS}, {"IntersectMesh_ExtractFaceSet", K_XCORE::IntersectMesh_ExtractFaceSet, METH_VARARGS}, {"IntersectMesh_Merge", K_XCORE::IntersectMesh_Merge, METH_VARARGS}, + + {"icapsule_init", K_XCORE::icapsule_init, METH_VARARGS}, + {"icapsule_extract_master", K_XCORE::icapsule_extract_master, METH_VARARGS}, + {"icapsule_extract_slave", K_XCORE::icapsule_extract_slave, METH_VARARGS}, + {"triangulate_skin", K_XCORE::triangulate_skin, METH_VARARGS}, {"extractCell", K_XCORE::extractCell, METH_VARARGS}, diff --git a/Cassiopee/XCore/XCore/xcore.h b/Cassiopee/XCore/XCore/xcore.h index 2c50ca6f0..b44a83a88 100644 --- a/Cassiopee/XCore/XCore/xcore.h +++ b/Cassiopee/XCore/XCore/xcore.h @@ -71,6 +71,11 @@ namespace K_XCORE PyObject *IntersectMesh_Exit(PyObject *self, PyObject *args); PyObject *IntersectMesh_ExtractFaceSet(PyObject *self, PyObject *args); PyObject *IntersectMesh_Merge(PyObject *self, PyObject *args); + + PyObject *icapsule_init(PyObject *self, PyObject *args); + PyObject *icapsule_extract_master(PyObject *self, PyObject *args); + PyObject *icapsule_extract_slave(PyObject *self, PyObject *args); + PyObject *triangulate_skin(PyObject *self, PyObject *args); PyObject *extractCell(PyObject *self, PyObject *args); diff --git a/Cassiopee/XCore/srcs.py b/Cassiopee/XCore/srcs.py index 7999f7a47..fa92daa04 100644 --- a/Cassiopee/XCore/srcs.py +++ b/Cassiopee/XCore/srcs.py @@ -19,6 +19,11 @@ 'XCore/common/mem.cpp', 'XCore/common/common.cpp', + 'XCore/common/Karray.cpp', + + 'XCore/intersectMesh/icapsule.cpp', + 'XCore/intersectMesh/triangulate.cpp', + 'XCore/intersectMesh/locate.cpp', 'XCore/intersectMesh/BVH.cpp', 'XCore/intersectMesh/AABB.cpp', @@ -59,7 +64,6 @@ 'XCore/intersectMesh/triangle.cpp', 'XCore/intersectMesh/point.cpp', 'XCore/intersectMesh/ray.cpp', - 'XCore/intersectMesh/karray.cpp', 'XCore/intersectMesh/meshExport.cpp', 'XCore/intersectMesh/DDA.cpp', @@ -97,7 +101,6 @@ 'XCore/AdaptMesh/Q6.cpp', 'XCore/AdaptMesh/Tri.cpp', 'XCore/AdaptMesh/Edge.cpp', - 'XCore/AdaptMesh/Karray.cpp', 'XCore/AdaptMesh/BVH.cpp', 'XCore/AdaptMesh/Box.cpp', From 4975bec9ebac496ea7b9894a486d2f3de514531a Mon Sep 17 00:00:00 2001 From: imadhammani Date: Sat, 12 Oct 2024 14:24:41 +0200 Subject: [PATCH 45/86] XCore interectMesh: correct near-point/edge situations + make sgraph --- Cassiopee/XCore/XCore/intersectMesh/dcel.cpp | 6 +- .../XCore/XCore/intersectMesh/icapsule.cpp | 84 +++++++++++++----- .../XCore/XCore/intersectMesh/icapsule.h | 6 ++ .../XCore/XCore/intersectMesh/locate.cpp | 26 +++--- Cassiopee/XCore/XCore/intersectMesh/mesh.h | 21 +++-- Cassiopee/XCore/XCore/intersectMesh/point.h | 4 +- .../XCore/XCore/intersectMesh/primitives.h | 2 +- .../XCore/XCore/intersectMesh/sgraph.cpp | 87 +++++++++++++++++++ Cassiopee/XCore/XCore/intersectMesh/smesh.cpp | 29 +++++++ Cassiopee/XCore/XCore/intersectMesh/smesh.h | 4 + Cassiopee/XCore/srcs.py | 1 + 11 files changed, 221 insertions(+), 49 deletions(-) create mode 100644 Cassiopee/XCore/XCore/intersectMesh/sgraph.cpp diff --git a/Cassiopee/XCore/XCore/intersectMesh/dcel.cpp b/Cassiopee/XCore/XCore/intersectMesh/dcel.cpp index 900ad51db..db550758c 100644 --- a/Cassiopee/XCore/XCore/intersectMesh/dcel.cpp +++ b/Cassiopee/XCore/XCore/intersectMesh/dcel.cpp @@ -808,9 +808,9 @@ void Dcel::locate_spoints(const Smesh &M, const Smesh &S) found = 1; ploc.fid = fid; - ploc.u = u; - ploc.v = v; - ploc.w = w; + ploc.bcrd[0] = u; + ploc.bcrd[1] = v; + ploc.bcrd[2] = w; // TODO(Imad): this absolutely needs to be robust if (Sign_tol(v, 1e-3) == 0) diff --git a/Cassiopee/XCore/XCore/intersectMesh/icapsule.cpp b/Cassiopee/XCore/XCore/intersectMesh/icapsule.cpp index f49996350..d312354c1 100644 --- a/Cassiopee/XCore/XCore/intersectMesh/icapsule.cpp +++ b/Cassiopee/XCore/XCore/intersectMesh/icapsule.cpp @@ -2,6 +2,7 @@ #include "common/Karray.h" #include "point.h" #include "io.h" +#include "primitives.h" Smesh IMesh::make_patch(const E_Float *ptag) { @@ -23,7 +24,60 @@ Smesh IMesh::make_patch(const E_Float *ptag) return Smesh(*this); } -Smesh IMesh::make_patch(const Smesh &spatch) +std::vector epoints; +std::vector cpoints; + +void ICapsule::correct_near_points_and_edges(Smesh &Sf, + std::vector &plocs, const IMesh &M) +{ + E_Int on_vertex = 0, on_edge = 0; + for (size_t i = 0; i < plocs.size(); i++) { + auto &ploc = plocs[i]; + + E_Int fid = ploc.fid; + const auto &pn = M.F[fid]; + + if (ploc.v_idx != -1) { + on_vertex++; + E_Int p = pn[ploc.v_idx]; + E_Float dx = M.X[p]-Sf.X[i]; + E_Float dy = M.Y[p]-Sf.Y[i]; + E_Float dz = M.Z[p]-Sf.Z[i]; + E_Float dist = dx*dx + dy*dy + dz*dz; + if (dist >= Sf.min_pdist_squared) { + fprintf(stderr, "Tight near-vertex situation!\n"); + point_write("mpoint", M.X[p], M.Y[p], M.Z[p]); + point_write("spoint", Sf.X[i], Sf.Y[i], Sf.Z[i]); + assert(0); + } else { + Sf.X[i] = M.X[p]; + Sf.Y[i] = M.Y[p]; + Sf.Z[i] = M.Z[p]; + } + } else if (ploc.e_idx != -1) { + on_edge++; + E_Int zero_crd = (ploc.e_idx+2)%3; + E_Float U = ploc.bcrd[zero_crd]; + assert(Sign(U, NEAR_EDGE_TOL) == 0); + E_Int i1 = (zero_crd+1)%3; + E_Int i2 = (zero_crd+2)%3; + E_Float V = ploc.bcrd[i1]; + E_Float W = ploc.bcrd[i2]; + E_Int a = pn[i1]; + E_Int b = pn[i2]; + V += U; + assert(Sign(V+W-1) == 0); + //epoints.push_back(Point(Sf.X[i], Sf.Y[i], Sf.Z[i])); + Sf.X[i] = V*M.X[a] + W*M.X[b]; + Sf.Y[i] = V*M.Y[a] + W*M.Y[b]; + Sf.Z[i] = V*M.Z[a] + W*M.Z[b]; + //cpoints.push_back(Point(Sf.X[i], Sf.Y[i], Sf.Z[i])); + } + } + printf("on vertex: %d - on edge: %d\n", on_vertex, on_edge); +} + +Smesh IMesh::make_patch(const Smesh &spatch, const std::vector &plocs) { //patch.clear(); @@ -34,47 +88,37 @@ ICapsule::ICapsule(const Karray &marray, const std::vector &sarrays, const std::vector &ptags) { M = IMesh(marray); + M.set_tolerances(NEAR_VERTEX_TOL, NEAR_EDGE_TOL); M.make_skin(); M.orient_skin(OUT); M.triangulate_skin(); M.make_bbox(); M.hash_skin(); + M.make_skin_graph(); Ss.reserve(sarrays.size()); spatches.reserve(sarrays.size()); std::vector> plocs; plocs.reserve(sarrays.size()); + mpatches.reserve(sarrays.size()); for (size_t i = 0; i < sarrays.size(); i++) { Ss.push_back(IMesh(sarrays[i])); + Ss[i].set_tolerances(NEAR_VERTEX_TOL, NEAR_EDGE_TOL); Ss[i].make_skin(); Ss[i].orient_skin(IN); Ss[i].triangulate_skin(); spatches.push_back(Ss[i].make_patch(ptags[i])); + spatches[i].compute_min_distance_between_points(); plocs.push_back(M.locate(spatches[i])); + correct_near_points_and_edges(spatches[i], plocs[i], M); + mpatches.push_back(M.make_patch(spatches[i], plocs[i])); } - // Correct near-vertex/edge situations - std::vector points; - for (size_t i = 0; i < sarrays.size(); i++) { - const Smesh &Sf = spatches[i]; - const std::vector &locs = plocs[i]; - assert(locs.size() == (size_t)spatches[i].np); - E_Int on_vertex = 0, on_edge = 0; - for (size_t j = 0; j < locs.size(); j++) { - if (locs[j].v_idx != -1) on_vertex++; - else if (locs[j].e_idx != -1) { - on_edge++; - points.push_back(Point(Sf.X[j], Sf.Y[j], Sf.Z[j])); - } - } - printf("on vertex: %d - on edge: %d\n", on_vertex, on_edge); - } + //point_write("epoints", epoints); + //point_write("cpoints", cpoints); - point_write("points", points); - - mpatches.reserve(sarrays.size()); } diff --git a/Cassiopee/XCore/XCore/intersectMesh/icapsule.h b/Cassiopee/XCore/XCore/intersectMesh/icapsule.h index b5af1a3a2..0abdddb8f 100644 --- a/Cassiopee/XCore/XCore/intersectMesh/icapsule.h +++ b/Cassiopee/XCore/XCore/intersectMesh/icapsule.h @@ -8,6 +8,12 @@ struct ICapsule { std::vector mpatches; std::vector spatches; + E_Float NEAR_VERTEX_TOL = 1e-3; + E_Float NEAR_EDGE_TOL = 1e-3; + ICapsule(const Karray &marray, const std::vector &sarray, const std::vector &ptags); + + void correct_near_points_and_edges(Smesh &Sf, std::vector &plocs, + const IMesh &M); }; diff --git a/Cassiopee/XCore/XCore/intersectMesh/locate.cpp b/Cassiopee/XCore/XCore/intersectMesh/locate.cpp index 6c36fea41..3716e6601 100644 --- a/Cassiopee/XCore/XCore/intersectMesh/locate.cpp +++ b/Cassiopee/XCore/XCore/intersectMesh/locate.cpp @@ -23,12 +23,6 @@ std::vector IMesh::locate(const Smesh &Sf) // w, u, v auto &loc = ploc[pid]; - assert(loc.fid == -1); - assert(loc.v_idx == -1); - assert(loc.e_idx == -1); - assert(loc.u == -1); - assert(loc.v == -1); - assert(loc.w == -1); for (size_t i = 0; i < pf.size() && !found; i++) { E_Int fid = pf[i]; @@ -45,16 +39,16 @@ std::vector IMesh::locate(const Smesh &Sf) found = true; loc.fid = fid; - loc.u = u; - loc.v = v; - loc.w = w; - - if (Sign(1-u, 1e-3) == 0) loc.v_idx = 0; - else if (Sign(1-v, 1e-3) == 0) loc.v_idx = 1; - else if (Sign(1-w, 1e-3) == 0) loc.v_idx = 2; - else if (Sign(w, 1e-3) == 0) loc.e_idx = 0; - else if (Sign(u, 1e-3) == 0) loc.e_idx = 1; - else if (Sign(v, 1e-3) == 0) loc.e_idx = 2; + loc.bcrd[0] = u; + loc.bcrd[1] = v; + loc.bcrd[2] = w; + + if (Sign(1-u, NEAR_VERTEX_TOL) == 0) loc.v_idx = 0; + else if (Sign(1-v, NEAR_VERTEX_TOL) == 0) loc.v_idx = 1; + else if (Sign(1-w, NEAR_VERTEX_TOL) == 0) loc.v_idx = 2; + else if (Sign(w, NEAR_EDGE_TOL) == 0) loc.e_idx = 0; + else if (Sign(u, NEAR_EDGE_TOL) == 0) loc.e_idx = 1; + else if (Sign(v, NEAR_EDGE_TOL) == 0) loc.e_idx = 2; break; } diff --git a/Cassiopee/XCore/XCore/intersectMesh/mesh.h b/Cassiopee/XCore/XCore/intersectMesh/mesh.h index 2fb1f0d28..e1b446343 100644 --- a/Cassiopee/XCore/XCore/intersectMesh/mesh.h +++ b/Cassiopee/XCore/XCore/intersectMesh/mesh.h @@ -52,11 +52,10 @@ struct UEdge { } }; -struct skin_graph { - const std::vector &skin; - - - +struct Sgraph { + std::vector xadj; + std::vector fpts; + std::vector fadj; }; struct IMesh { @@ -75,6 +74,9 @@ struct IMesh { std::vector skin; std::vector owner; std::vector neigh; + Sgraph sgraph; + E_Float NEAR_VERTEX_TOL = 1e-3; + E_Float NEAR_EDGE_TOL = 1e-3; E_Float xmin, ymin, zmin; E_Float xmax, ymax, zmax; @@ -91,9 +93,16 @@ struct IMesh { std::vector entries; std::vector ctag; + + void set_tolerances(E_Float near_vertex_tol, E_Float near_edge_tol) + { + NEAR_VERTEX_TOL = near_vertex_tol; + NEAR_EDGE_TOL = near_edge_tol; + } Smesh make_patch(const E_Float *ptag); - Smesh make_patch(const Smesh &spatch); + Smesh make_patch(const Smesh &spatch, const std::vector &plocs); + void make_skin_graph(); inline E_Int get_voxel(E_Int I, E_Int J, E_Int K) const { diff --git a/Cassiopee/XCore/XCore/intersectMesh/point.h b/Cassiopee/XCore/XCore/intersectMesh/point.h index 9ee0296e2..0d93631e0 100644 --- a/Cassiopee/XCore/XCore/intersectMesh/point.h +++ b/Cassiopee/XCore/XCore/intersectMesh/point.h @@ -26,9 +26,7 @@ struct PointLoc { E_Int fid = -1; E_Int v_idx = -1; E_Int e_idx = -1; - E_Float u = -1; - E_Float v = -1; - E_Float w = -1; + E_Float bcrd[3] = {-1, -1, -1}; }; struct pointFace { diff --git a/Cassiopee/XCore/XCore/intersectMesh/primitives.h b/Cassiopee/XCore/XCore/intersectMesh/primitives.h index ce3d26115..2bdffcfef 100644 --- a/Cassiopee/XCore/XCore/intersectMesh/primitives.h +++ b/Cassiopee/XCore/XCore/intersectMesh/primitives.h @@ -42,7 +42,7 @@ E_Float DifferenceOfProducts(E_Float a, E_Float b, E_Float c, E_Float d); E_Float TwoDiff(E_Float a, E_Float b); -E_Int Sign(E_Float x, E_Float tol=TOL); +E_Int Sign(E_Float x, E_Float tol=1e-12); E_Int orient3D(E_Float *A, E_Float *B, E_Float *C, E_Float *D); diff --git a/Cassiopee/XCore/XCore/intersectMesh/sgraph.cpp b/Cassiopee/XCore/XCore/intersectMesh/sgraph.cpp new file mode 100644 index 000000000..d7d5008dc --- /dev/null +++ b/Cassiopee/XCore/XCore/intersectMesh/sgraph.cpp @@ -0,0 +1,87 @@ +#include "mesh.h" + +struct EdgeNode { + E_Int p, q; + E_Int i, posi; + mutable E_Int j, posj; + + EdgeNode(E_Int P, E_Int Q) + { + p = std::min(P, Q); + q = std::max(P, Q); + i = posi = j = posj = -1; + } + + bool operator<(const EdgeNode &e) const + { + return (p < e.p) || (p == e.p && q < e.q); + } +}; + +void IMesh::make_skin_graph() +{ + auto &xadj = sgraph.xadj; + auto &fpts = sgraph.fpts; + auto &fadj = sgraph.fadj; + + xadj.clear(); + fpts.clear(); + fadj.clear(); + + xadj.resize(skin.size()+1); + xadj[0] = 0; + + for (size_t i = 0; i < skin.size(); i++) { + E_Int fid = skin[i]; + xadj[i+1] = xadj[i] + F[fid].size(); + } + + fpts.resize(xadj[skin.size()]); + fadj.resize(xadj[skin.size()], -1); + + for (size_t i = 0; i < skin.size(); i++) { + E_Int fid = skin[i]; + const auto &pn = F[fid]; + E_Int start = xadj[i]; + E_Int end = xadj[i+1]; + for (size_t j = 0; j < end-start; j++) + fpts[start+j] = pn[j]; + } + + std::set edge_set; + + for (size_t i = 0; i < skin.size(); i++) { + E_Int start = xadj[i]; + E_Int np = xadj[i+1] - start; + const E_Int *pn = &fpts[start]; + for (E_Int j = 0; j < np; j++) { + E_Int p = pn[j]; + E_Int q = pn[(j+1)%np]; + EdgeNode e(p, q); + auto it = edge_set.find(e); + if (it == edge_set.end()) { + e.i = i; + e.posi = j; + edge_set.insert(e); + } else { + assert(it->i != -1); + assert(it->posi != -1); + assert(it->j == -1); + assert(it->posj == -1); + it->j = i; + it->posj = j; + } + } + } + + for (const auto &e : edge_set) { + E_Int pi = xadj[e.i] + e.posi; + assert(fadj[pi] == -1); + fadj[pi] = e.j; + + E_Int pj = xadj[e.j] + e.posj; + assert(fadj[pj] == -1); + fadj[pj] = e.i; + } +} + diff --git a/Cassiopee/XCore/XCore/intersectMesh/smesh.cpp b/Cassiopee/XCore/XCore/intersectMesh/smesh.cpp index 8d95ee4c4..4f38afd55 100644 --- a/Cassiopee/XCore/XCore/intersectMesh/smesh.cpp +++ b/Cassiopee/XCore/XCore/intersectMesh/smesh.cpp @@ -990,3 +990,32 @@ void Smesh::hash_faces() } } } + +void Smesh::compute_min_distance_between_points() +{ + min_pdist_squared = EFLOATMAX; + E_Int ndists = 0; + + for (E_Int i = 0; i < np; i++) { + E_Float xi = X[i]; + E_Float yi = Y[i]; + E_Float zi = Z[i]; + for (E_Int j = i+1; j < np; j++) { + E_Float xj = X[j]; + E_Float yj = Y[j]; + E_Float zj = Z[j]; + + E_Float dx = xj-xi; + E_Float dy = yj-yi; + E_Float dz = zj-zi; + + E_Float dist = dx*dx + dy*dy + dz*dz; + + if (dist < min_pdist_squared) min_pdist_squared = dist; + + ndists++; + } + } + + assert(ndists == np*(np-1)/2); +} diff --git a/Cassiopee/XCore/XCore/intersectMesh/smesh.h b/Cassiopee/XCore/XCore/intersectMesh/smesh.h index 8d4a7dbc2..454f98d06 100644 --- a/Cassiopee/XCore/XCore/intersectMesh/smesh.h +++ b/Cassiopee/XCore/XCore/intersectMesh/smesh.h @@ -72,12 +72,16 @@ struct Smesh { std::map> fmap; + E_Float min_pdist_squared = EFLOATMIN; + void make_fnormals(); void make_pnormals(); void make_bbox(); void hash_faces(); + void compute_min_distance_between_points(); + AABB AABB_face(const std::vector &pn) const; // Adaptation diff --git a/Cassiopee/XCore/srcs.py b/Cassiopee/XCore/srcs.py index fa92daa04..effdfead2 100644 --- a/Cassiopee/XCore/srcs.py +++ b/Cassiopee/XCore/srcs.py @@ -24,6 +24,7 @@ 'XCore/intersectMesh/icapsule.cpp', 'XCore/intersectMesh/triangulate.cpp', 'XCore/intersectMesh/locate.cpp', + 'XCore/intersectMesh/sgraph.cpp', 'XCore/intersectMesh/BVH.cpp', 'XCore/intersectMesh/AABB.cpp', From 3374da4bd2ac57569e1695887c3963dcfa96e233 Mon Sep 17 00:00:00 2001 From: imadhammani Date: Sat, 12 Oct 2024 15:00:46 +0200 Subject: [PATCH 46/86] XCore intersectMesh: added pchain construction --- .../XCore/XCore/intersectMesh/icapsule.cpp | 53 ++++++++++++++++++- 1 file changed, 51 insertions(+), 2 deletions(-) diff --git a/Cassiopee/XCore/XCore/intersectMesh/icapsule.cpp b/Cassiopee/XCore/XCore/intersectMesh/icapsule.cpp index d312354c1..c8496eb56 100644 --- a/Cassiopee/XCore/XCore/intersectMesh/icapsule.cpp +++ b/Cassiopee/XCore/XCore/intersectMesh/icapsule.cpp @@ -77,9 +77,57 @@ void ICapsule::correct_near_points_and_edges(Smesh &Sf, printf("on vertex: %d - on edge: %d\n", on_vertex, on_edge); } -Smesh IMesh::make_patch(const Smesh &spatch, const std::vector &plocs) +std::vector chain_points; + +Smesh IMesh::make_patch(const Smesh &Sf, const std::vector &plocs) { - //patch.clear(); + // Get boundary edges from spatch + std::set bedges; + for (size_t i = 0; i < Sf.E2F.size(); i++) { + const auto &pf = Sf.E2F[i]; + assert(pf[0] != -1); + if (pf[1] == -1) bedges.insert(i); + } + size_t nbedges = bedges.size(); + + // Make the boundary point chain + std::vector pchain; + + const auto &E = Sf.E; + + E_Int first_edge = *bedges.begin(); + + pchain.push_back(E[first_edge].p); + pchain.push_back(E[first_edge].q); + + bedges.erase(first_edge); + + E_Int current_point = pchain[1]; + + while (pchain.size() < nbedges) { + E_Int to_delete = -1; + for (auto e : bedges) { + if (E[e].p == current_point) { + pchain.push_back(E[e].q); + current_point = pchain.back(); + to_delete = e; + break; + } else if (E[e].q == current_point) { + pchain.push_back(E[e].p); + current_point = pchain.back(); + to_delete = e; + break; + } + } + bedges.erase(to_delete); + } + + assert(pchain.size() == nbedges); + + for (auto p : pchain) + chain_points.push_back(Point(Sf.X[p], Sf.Y[p], Sf.Z[p])); + + return Smesh(); } @@ -119,6 +167,7 @@ ICapsule::ICapsule(const Karray &marray, const std::vector &sarrays, //point_write("epoints", epoints); //point_write("cpoints", cpoints); + point_write("chain", chain_points); } From 2bd6d84f85b54e27fe5f4ef25703705abb3be7e1 Mon Sep 17 00:00:00 2001 From: imadhammani Date: Sat, 12 Oct 2024 16:46:36 +0200 Subject: [PATCH 47/86] XCore intersectMesh: started bounding Smesh extraction --- Cassiopee/XCore/XCore/intersectMesh/DDA.cpp | 10 +- Cassiopee/XCore/XCore/intersectMesh/dcel.cpp | 10 +- Cassiopee/XCore/XCore/intersectMesh/dcel.h | 2 +- .../XCore/XCore/intersectMesh/icapsule.cpp | 112 +++++++++--- .../XCore/XCore/intersectMesh/icapsule.h | 3 - .../XCore/XCore/intersectMesh/locate.cpp | 4 +- Cassiopee/XCore/XCore/intersectMesh/mesh.cpp | 18 +- Cassiopee/XCore/XCore/intersectMesh/mesh.h | 11 +- .../XCore/XCore/intersectMesh/meshRefine.cpp | 6 +- Cassiopee/XCore/XCore/intersectMesh/smesh.cpp | 161 +++--------------- Cassiopee/XCore/XCore/intersectMesh/smesh.h | 36 +++- Cassiopee/XCore/XCore/intersectMesh/trace.cpp | 51 +++--- 12 files changed, 187 insertions(+), 237 deletions(-) diff --git a/Cassiopee/XCore/XCore/intersectMesh/DDA.cpp b/Cassiopee/XCore/XCore/intersectMesh/DDA.cpp index a4b513e73..a347ef7ea 100644 --- a/Cassiopee/XCore/XCore/intersectMesh/DDA.cpp +++ b/Cassiopee/XCore/XCore/intersectMesh/DDA.cpp @@ -2,11 +2,7 @@ #include "primitives.h" void IMesh::hash_skin() -{ - HX = (xmax - xmin) / NX; - HY = (ymax - ymin) / NY; - HZ = (zmax - zmin) / NZ; - +{ bin_faces.clear(); bin_faces.resize(NXYZ); @@ -52,7 +48,7 @@ void IMesh::hash_skin() void IMesh::hash_patch() { - fmap.clear(); + bin_faces.clear(); for (E_Int fid : patch) { assert(face_is_active(fid)); @@ -88,7 +84,7 @@ void IMesh::hash_patch() E_Int voxel = get_voxel(I, J, K); assert(voxel >= 0); assert(voxel < NXYZ); - fmap[voxel].push_back(fid); + bin_faces[voxel].push_back(fid); } } } diff --git a/Cassiopee/XCore/XCore/intersectMesh/dcel.cpp b/Cassiopee/XCore/XCore/intersectMesh/dcel.cpp index db550758c..b00732774 100644 --- a/Cassiopee/XCore/XCore/intersectMesh/dcel.cpp +++ b/Cassiopee/XCore/XCore/intersectMesh/dcel.cpp @@ -33,7 +33,7 @@ #include "cycle.h" #include "triangle.h" -Smesh Dcel::export_smesh() const +Smesh Dcel::export_smesh(bool is_planar) const { Smesh smesh; smesh.ne = 0; @@ -70,7 +70,7 @@ Smesh Dcel::export_smesh() const smesh.nf = (E_Int)smesh.F.size(); - smesh.make_edges(); + smesh.make_edges(is_planar); return smesh; } @@ -770,11 +770,9 @@ void Dcel::locate_spoints(const Smesh &M, const Smesh &S) E_Int voxel_z = floor((S.Z[sp] - M.zmin) / M.HZ); E_Int sp_bin = voxel_x + M.NX * voxel_y + M.NXY * voxel_z; - auto it = M.fmap.find(sp_bin); + const auto &pf = M.bin_faces[sp_bin]; - assert(it != M.fmap.end()); - - const auto &pf = it->second; + assert(pf.size() > 0); for (size_t mf = 0; mf < pf.size() && !found; mf++) { diff --git a/Cassiopee/XCore/XCore/intersectMesh/dcel.h b/Cassiopee/XCore/XCore/intersectMesh/dcel.h index 249c8c94c..eb63b0230 100644 --- a/Cassiopee/XCore/XCore/intersectMesh/dcel.h +++ b/Cassiopee/XCore/XCore/intersectMesh/dcel.h @@ -125,5 +125,5 @@ struct Dcel { void sort_leaving_hedges(std::vector &leaving, const E_Float N[3], const Smesh &M) const; - Smesh export_smesh() const; + Smesh export_smesh(bool is_planar=true) const; }; diff --git a/Cassiopee/XCore/XCore/intersectMesh/icapsule.cpp b/Cassiopee/XCore/XCore/intersectMesh/icapsule.cpp index c8496eb56..6cf5024e4 100644 --- a/Cassiopee/XCore/XCore/intersectMesh/icapsule.cpp +++ b/Cassiopee/XCore/XCore/intersectMesh/icapsule.cpp @@ -4,7 +4,7 @@ #include "io.h" #include "primitives.h" -Smesh IMesh::make_patch(const E_Float *ptag) +Smesh IMesh::make_smesh(const E_Float *ptag) { patch.clear(); @@ -24,35 +24,47 @@ Smesh IMesh::make_patch(const E_Float *ptag) return Smesh(*this); } +Smesh IMesh::make_smesh_from_skin(bool is_planar) +{ + patch.clear(); + + for (E_Int fid : skin) { + patch.insert(fid); + } + + return Smesh(*this, is_planar); +} + std::vector epoints; std::vector cpoints; -void ICapsule::correct_near_points_and_edges(Smesh &Sf, - std::vector &plocs, const IMesh &M) +void Smesh::correct_near_points_and_edges(Smesh &Sf, + std::vector &plocs) { E_Int on_vertex = 0, on_edge = 0; for (size_t i = 0; i < plocs.size(); i++) { auto &ploc = plocs[i]; E_Int fid = ploc.fid; - const auto &pn = M.F[fid]; + assert(fid < nf); + const auto &pn = F[fid]; if (ploc.v_idx != -1) { on_vertex++; E_Int p = pn[ploc.v_idx]; - E_Float dx = M.X[p]-Sf.X[i]; - E_Float dy = M.Y[p]-Sf.Y[i]; - E_Float dz = M.Z[p]-Sf.Z[i]; + E_Float dx = X[p]-Sf.X[i]; + E_Float dy = Y[p]-Sf.Y[i]; + E_Float dz = Z[p]-Sf.Z[i]; E_Float dist = dx*dx + dy*dy + dz*dz; if (dist >= Sf.min_pdist_squared) { fprintf(stderr, "Tight near-vertex situation!\n"); - point_write("mpoint", M.X[p], M.Y[p], M.Z[p]); + point_write("mpoint", X[p], Y[p], Z[p]); point_write("spoint", Sf.X[i], Sf.Y[i], Sf.Z[i]); assert(0); } else { - Sf.X[i] = M.X[p]; - Sf.Y[i] = M.Y[p]; - Sf.Z[i] = M.Z[p]; + Sf.X[i] = X[p]; + Sf.Y[i] = Y[p]; + Sf.Z[i] = Z[p]; } } else if (ploc.e_idx != -1) { on_edge++; @@ -67,11 +79,11 @@ void ICapsule::correct_near_points_and_edges(Smesh &Sf, E_Int b = pn[i2]; V += U; assert(Sign(V+W-1) == 0); - //epoints.push_back(Point(Sf.X[i], Sf.Y[i], Sf.Z[i])); - Sf.X[i] = V*M.X[a] + W*M.X[b]; - Sf.Y[i] = V*M.Y[a] + W*M.Y[b]; - Sf.Z[i] = V*M.Z[a] + W*M.Z[b]; - //cpoints.push_back(Point(Sf.X[i], Sf.Y[i], Sf.Z[i])); + epoints.push_back(Point(Sf.X[i], Sf.Y[i], Sf.Z[i])); + Sf.X[i] = V*X[a] + W*X[b]; + Sf.Y[i] = V*Y[a] + W*Y[b]; + Sf.Z[i] = V*Z[a] + W*Z[b]; + cpoints.push_back(Point(Sf.X[i], Sf.Y[i], Sf.Z[i])); } } printf("on vertex: %d - on edge: %d\n", on_vertex, on_edge); @@ -79,7 +91,8 @@ void ICapsule::correct_near_points_and_edges(Smesh &Sf, std::vector chain_points; -Smesh IMesh::make_patch(const Smesh &Sf, const std::vector &plocs) +Smesh Smesh::extract_bounding_smesh(const Smesh &Sf, + const std::vector &plocs) { // Get boundary edges from spatch std::set bedges; @@ -119,15 +132,60 @@ Smesh IMesh::make_patch(const Smesh &Sf, const std::vector &plocs) break; } } + assert(to_delete != -1); bedges.erase(to_delete); } assert(pchain.size() == nbedges); - for (auto p : pchain) + for (auto p : pchain) { chain_points.push_back(Point(Sf.X[p], Sf.Y[p], Sf.Z[p])); + } + + /* + std::set bfids; + + for (size_t i = 0; i < pchain.size(); i++) { + E_Int p = pchain[i]; + E_Int q = pchain[(i+1)%pchain.size()]; + E_Float px = Mf.X[p], py = Mf.Y[p], pz = Mf.Z[p]; + E_Float qx = Mf.X[q], qy = Mf.Y[q], qz = Mf.Z[q]; + E_Float D[3] = {qx-px, qy-py, qz-pz}; + E_Float NORM = K_MATH::norm(D, 3); + D[0] /= NORM, D[1] /= NORM, D[2] /= NORM; + + std::vector orig_faces; + std::vector tail_faces; + + E_Int last_vertex = -1, last_edge = -1, dummy; + + Mf.get_shared_faces(plocs[p], orig_faces, last_vertex, last_edge); + Mf.get_shared_faces(plocs[q], tail_faces, dummy, dummy); + + E_Int starting_face = Mf.deduce_face(orig_faces, px, py, pz, + D, last_vertex, last_edge); + assert(starting_face != -1); + + bool found_tail = false; + E_Int current_fid = starting_face; + E_Float current_pos[3] = {px, py, pz}; + + E_Int walk = 0; + E_Int max_walks = 20; + + while (!found_tail && walk <= max_walks) { + found_tail = true; + walk++; + } + + assert(found_tail); + assert(walk <= max_walks); + + + } + */ return Smesh(); } @@ -143,6 +201,10 @@ ICapsule::ICapsule(const Karray &marray, const std::vector &sarrays, M.make_bbox(); M.hash_skin(); M.make_skin_graph(); + Smesh Mf = M.make_smesh_from_skin(false); + Mf.make_bbox(); + Mf.hash_faces(); + Mf.make_fnormals(); Ss.reserve(sarrays.size()); spatches.reserve(sarrays.size()); @@ -157,15 +219,17 @@ ICapsule::ICapsule(const Karray &marray, const std::vector &sarrays, Ss[i].make_skin(); Ss[i].orient_skin(IN); Ss[i].triangulate_skin(); - spatches.push_back(Ss[i].make_patch(ptags[i])); + spatches.push_back(Ss[i].make_smesh(ptags[i])); + spatches[i].make_bbox(); + spatches[i].hash_faces(); spatches[i].compute_min_distance_between_points(); - plocs.push_back(M.locate(spatches[i])); - correct_near_points_and_edges(spatches[i], plocs[i], M); - mpatches.push_back(M.make_patch(spatches[i], plocs[i])); + plocs.push_back(Mf.locate(spatches[i])); + Mf.correct_near_points_and_edges(spatches[i], plocs[i]); + mpatches.push_back(Mf.extract_bounding_smesh(spatches[i], plocs[i])); } - //point_write("epoints", epoints); - //point_write("cpoints", cpoints); + point_write("epoints", epoints); + point_write("cpoints", cpoints); point_write("chain", chain_points); } diff --git a/Cassiopee/XCore/XCore/intersectMesh/icapsule.h b/Cassiopee/XCore/XCore/intersectMesh/icapsule.h index 0abdddb8f..73b8bf328 100644 --- a/Cassiopee/XCore/XCore/intersectMesh/icapsule.h +++ b/Cassiopee/XCore/XCore/intersectMesh/icapsule.h @@ -13,7 +13,4 @@ struct ICapsule { ICapsule(const Karray &marray, const std::vector &sarray, const std::vector &ptags); - - void correct_near_points_and_edges(Smesh &Sf, std::vector &plocs, - const IMesh &M); }; diff --git a/Cassiopee/XCore/XCore/intersectMesh/locate.cpp b/Cassiopee/XCore/XCore/intersectMesh/locate.cpp index 3716e6601..62d9320df 100644 --- a/Cassiopee/XCore/XCore/intersectMesh/locate.cpp +++ b/Cassiopee/XCore/XCore/intersectMesh/locate.cpp @@ -1,8 +1,8 @@ -#include "mesh.h" +#include "smesh.h" #include "triangle.h" #include "primitives.h" -std::vector IMesh::locate(const Smesh &Sf) +std::vector Smesh::locate(const Smesh &Sf) const { std::vector ploc(Sf.np); diff --git a/Cassiopee/XCore/XCore/intersectMesh/mesh.cpp b/Cassiopee/XCore/XCore/intersectMesh/mesh.cpp index 2cddc90d8..bca626da7 100644 --- a/Cassiopee/XCore/XCore/intersectMesh/mesh.cpp +++ b/Cassiopee/XCore/XCore/intersectMesh/mesh.cpp @@ -248,13 +248,6 @@ IMesh::IMesh(const Karray &karray) faces[j] = pf[j] - 1; C.push_back(faces); } - - // Grid - NX = 100; - NY = 100; - NZ = 100; - NXY = NX * NY; - NXYZ = NXY * NZ; } IMesh::IMesh(K_FLD::FldArrayI &cn, E_Float *x, E_Float *y, E_Float *z, E_Int npts) @@ -327,6 +320,13 @@ void IMesh::make_point_faces() void IMesh::make_bbox() { + // Grid + NX = 100; + NY = 100; + NZ = 100; + NXY = NX * NY; + NXYZ = NXY * NZ; + xmin = ymin = zmin = EFLOATMAX; xmax = ymax = zmax = EFLOATMIN; @@ -345,6 +345,10 @@ void IMesh::make_bbox() xmax = xmax + (xmax - xmin) * 0.01; ymax = ymax + (ymax - ymin) * 0.01; zmax = zmax + (zmax - zmin) * 0.01; + + HX = (xmax - xmin) / NX; + HY = (ymax - ymin) / NY; + HZ = (zmax - zmin) / NZ; } void IMesh::make_skin() diff --git a/Cassiopee/XCore/XCore/intersectMesh/mesh.h b/Cassiopee/XCore/XCore/intersectMesh/mesh.h index e1b446343..fa342f940 100644 --- a/Cassiopee/XCore/XCore/intersectMesh/mesh.h +++ b/Cassiopee/XCore/XCore/intersectMesh/mesh.h @@ -86,8 +86,6 @@ struct IMesh { std::vector> bin_faces; - std::map> fmap; - std::set patch; std::vector entries; @@ -100,8 +98,8 @@ struct IMesh { NEAR_EDGE_TOL = near_edge_tol; } - Smesh make_patch(const E_Float *ptag); - Smesh make_patch(const Smesh &spatch, const std::vector &plocs); + Smesh make_smesh(const E_Float *ptag); + Smesh make_smesh_from_skin(bool is_planar = true); void make_skin_graph(); inline E_Int get_voxel(E_Int I, E_Int J, E_Int K) const @@ -178,11 +176,6 @@ struct IMesh { size_t refine(const IMesh &S); - std::vector locate(const Smesh &Sf); - - //std::vector locate(E_Int p, E_Float x, E_Float y, E_Float z, - // const std::set &patch) const; - inline bool face_is_active(E_Int face) const { return factive.find(face) != factive.end(); } diff --git a/Cassiopee/XCore/XCore/intersectMesh/meshRefine.cpp b/Cassiopee/XCore/XCore/intersectMesh/meshRefine.cpp index e74e52b22..6c60de429 100644 --- a/Cassiopee/XCore/XCore/intersectMesh/meshRefine.cpp +++ b/Cassiopee/XCore/XCore/intersectMesh/meshRefine.cpp @@ -326,11 +326,9 @@ size_t IMesh::refine(const IMesh &S) E_Int voxel_z = floor((S.Z[spt] - zmin) / HZ); E_Int spt_bin = voxel_x + NX * voxel_y + NXY * voxel_z; - auto it = fmap.find(spt_bin); + const auto &pf = bin_faces[spt_bin]; - if (it == fmap.end()) continue; - - const auto &pf = it->second; + assert(pf.size() > 0); for (E_Int fid : pf) { diff --git a/Cassiopee/XCore/XCore/intersectMesh/smesh.cpp b/Cassiopee/XCore/XCore/intersectMesh/smesh.cpp index 4f38afd55..55f9a32b0 100644 --- a/Cassiopee/XCore/XCore/intersectMesh/smesh.cpp +++ b/Cassiopee/XCore/XCore/intersectMesh/smesh.cpp @@ -49,8 +49,11 @@ bool Smesh::ccw_oriented(E_Int face) return sign < 0; } -Smesh::Smesh(const IMesh &M) +Smesh::Smesh(const IMesh &M, bool is_planar) { + NEAR_VERTEX_TOL = M.NEAR_VERTEX_TOL; + NEAR_EDGE_TOL = M.NEAR_EDGE_TOL; + F.resize(M.patch.size()); nf = 0; @@ -83,7 +86,6 @@ Smesh::Smesh(const IMesh &M) assert((size_t)np == l2gp.size()); // Get the points - //np = g2lp.size(); X.resize(np); Y.resize(np); Z.resize(np); @@ -94,7 +96,7 @@ Smesh::Smesh(const IMesh &M) Z[pids.second] = M.Z[pids.first]; } - make_edges(); + make_edges(is_planar); } o_edge::o_edge(E_Int P, E_Int Q) @@ -113,7 +115,7 @@ struct o_edge_cmp { } }; -void Smesh::make_edges() +void Smesh::make_edges(bool is_planar) { // Make the edges F2E.resize(F.size()); @@ -164,9 +166,9 @@ void Smesh::make_edges() } - // Check - - assert(np - ne + nf + 1 == 2); + // Check Euler formula for planar graphs + if (is_planar) + assert(np - ne + nf + 1 == 2); for (E_Int i = 0; i < ne; i++) { assert(count[i] == 1 || count[i] == 2); @@ -288,72 +290,6 @@ void Smesh::make_edges() } } -#define TRI 5 -#define QUAD 9 - -Smesh::Smesh(const char *fname) -{ - FILE *fh = fopen(fname, "r"); - assert(fh); - - char buf[256]; - - fgets(buf, 256, fh); - fgets(buf, 256, fh); - char *next = strtok(buf, " "); - next = strtok(NULL, "\n"); - - char *bad_ptr = NULL; - nf = strtod(next, &bad_ptr); - assert(*bad_ptr == '\0'); - printf("Faces: " SF_D_ "\n", nf); - - F.resize(nf); - - E_Int ret, type, dummy; - - for (E_Int i = 0; i < nf; i++) { - auto &cn = F[i]; - ret = fscanf(fh, SF_D_ " ", &type); - if (ret != 1) abort(); - if (type == TRI) { - cn.resize(3); - ret = fscanf(fh, SF_D_ SF_D_ SF_D_ SF_D_ "\n", - &cn[0], &cn[1], &cn[2], &dummy); - if (ret != 4) abort(); - } else if (type == QUAD) { - cn.resize(4); - ret = fscanf(fh, SF_D_ SF_D_ SF_D_ SF_D_ SF_D_ "\n", - &cn[0], &cn[1], &cn[2], &cn[3], &dummy); - if (ret != 5) abort(); - } else { - assert(0); - } - } - - fgets(buf, 256, fh); - next = strtok(buf, " "); - next = strtok(NULL, "\n"); - - np = strtod(next, &bad_ptr); - assert(*bad_ptr == '\0'); - printf("points: " SF_D_ "\n", np); - - X.resize(np); - Y.resize(np); - - for (E_Int i = 0; i < np; i++) { - ret = fscanf(fh, "%lf %lf " SF_D_ "\n", &X[i], &Y[i], &dummy); - if (ret != 3) abort(); - } - - fclose(fh); - - make_edges(); - - init_adaptation_data(); -} - // Refine M0/M1 as long as one of its faces contains another face from M1/M0 #define NON_DEGEN 0 @@ -565,45 +501,6 @@ E_Int Smesh::face_contains_point(E_Int face, E_Float x, E_Float y, E_Float z) co return -1; } -/* -std::vector Smesh::locate(E_Float x, E_Float y, E_Float z) const -{ - E_Int a, b, c; - E_Int hit = 0; - std::vector HITS; - - for (E_Int face : factive) { - const auto &cn = F[face]; - if (cn.size() == 4) { - // First triangle - a = cn[0], b = cn[1], c = cn[2]; - hit = Triangle::is_point_inside(x, y, z, X[a], Y[a], Z[a], - X[b], Y[b], Z[b], X[c], Y[c], Z[c]); - if (hit) { - HITS.push_back(pointFace(face, 0)); - } else { - // Second triangle - a = cn[0], b = cn[2], c = cn[3]; - hit = Triangle::is_point_inside(x, y, z, X[a], Y[a], Z[a], - X[b], Y[b], Z[b], X[c], Y[c], Z[c]); - if (hit) { - HITS.push_back(pointFace(face, 1)); - } - } - } else { - a = cn[0], b = cn[1], c = cn[2]; - hit = Triangle::is_point_inside(x, y, z, X[a], Y[a], Z[a], - X[b], Y[b], Z[b], X[c], Y[c], Z[c]); - if (hit) { - HITS.push_back(pointFace(face, 0)); - } - } - } - - return HITS; -} -*/ - void Smesh::init_adaptation_data() { flevel.resize(nf, 0); @@ -897,22 +794,14 @@ void Smesh::make_pnormals() } } -AABB Smesh::AABB_face(const std::vector &pn) const -{ - AABB ret; - for (E_Int p : pn) { - if (X[p] > ret.xmax) ret.xmax = X[p]; - if (X[p] < ret.xmin) ret.xmin = X[p]; - if (Y[p] > ret.ymax) ret.ymax = Y[p]; - if (Y[p] < ret.ymin) ret.ymin = Y[p]; - if (Z[p] > ret.zmax) ret.zmax = Z[p]; - if (Z[p] < ret.zmin) ret.zmin = Z[p]; - } - return ret; -} - void Smesh::make_bbox() { + NX = 100; + NY = 100; + NZ = 100; + NXY = NX * NY; + NXYZ = NXY * NZ; + xmin = ymin = zmin = std::numeric_limits::max(); xmax = ymax = zmax = std::numeric_limits::min(); @@ -935,22 +824,16 @@ void Smesh::make_bbox() xmax = xmax + dx*0.01; ymax = ymax + dy*0.01; zmax = zmax + dz*0.01; -} - -void Smesh::hash_faces() -{ - NX = 100; - NY = 100; - NZ = 100; HX = (xmax - xmin) / NX; HY = (ymax - ymin) / NY; HZ = (zmax - zmin) / NZ; +} - NXY = NX * NY; - E_Int NXYZ = NX * NY * NZ; - - fmap.clear(); +void Smesh::hash_faces() +{ + bin_faces.clear(); + bin_faces.resize(NXYZ); for (E_Int fid = 0; fid < nf; fid++) { const auto &pn = F[fid]; @@ -981,10 +864,10 @@ void Smesh::hash_faces() for (E_Int I = Imin; I <= Imax; I++) { for (E_Int J = Jmin; J <= Jmax; J++) { for (E_Int K = Kmin; K <= Kmax; K++) { - E_Int voxel = I + J * NX + (NX * NY) * K; + E_Int voxel = get_voxel(I, J, K); assert(voxel >= 0); assert(voxel < NXYZ); - fmap[voxel].push_back(fid); + bin_faces[voxel].push_back(fid); } } } diff --git a/Cassiopee/XCore/XCore/intersectMesh/smesh.h b/Cassiopee/XCore/XCore/intersectMesh/smesh.h index 454f98d06..49a6694d9 100644 --- a/Cassiopee/XCore/XCore/intersectMesh/smesh.h +++ b/Cassiopee/XCore/XCore/intersectMesh/smesh.h @@ -66,14 +66,32 @@ struct Smesh { std::vector fnormals; std::vector pnormals; - E_Int NX, NY, NZ, NXY; + E_Int NX, NY, NZ, NXY, NXYZ; E_Float xmin, xmax, ymin, ymax, zmin, zmax; E_Float HX, HY, HZ; - std::map> fmap; + std::vector> bin_faces; E_Float min_pdist_squared = EFLOATMIN; + E_Float NEAR_VERTEX_TOL = 1e-3; + E_Float NEAR_EDGE_TOL = 1e-3; + + Smesh extract_bounding_smesh(const Smesh &Sf, + const std::vector &plocs); + + void correct_near_points_and_edges(Smesh &Sf, std::vector &plocs); + + E_Int deduce_face(const std::vector &pf, + E_Float ox, E_Float oy, E_Float oz, E_Float D[3], + E_Int last_vertex, E_Int last_edge) const; + + void get_unit_projected_direction(E_Int fid, const E_Float D[3], + E_Float proj[3]) const; + + void get_shared_faces(const PointLoc &loc, std::vector &ret, + E_Int &pid, E_Int &eid) const; + void make_fnormals(); void make_pnormals(); @@ -98,15 +116,13 @@ struct Smesh { Smesh() {}; - Smesh(const char *fname); - - Smesh(const IMesh &M); + Smesh(const IMesh &M, bool is_planar=true); Smesh(const IMesh &M, const std::vector &faces); bool ccw_oriented(E_Int face); - void make_edges(); + void make_edges(bool is_planar); void make_point_faces(); @@ -122,7 +138,7 @@ struct Smesh { //size_t refine(Smesh &M); - //std::vector locate(E_Float x, E_Float y, E_Float z) const; + std::vector locate(const Smesh &Sf) const; void write_faces(const char *fname, const std::vector &faces) const; @@ -173,4 +189,10 @@ struct Smesh { Smesh extract_conformized(); bool faces_are_dups(E_Int face, E_Int mface, const Smesh &M); + + inline E_Int get_voxel(E_Int i, E_Int j, E_Int k) const + { + return i + NX*j + NXY*k; + } }; + diff --git a/Cassiopee/XCore/XCore/intersectMesh/trace.cpp b/Cassiopee/XCore/XCore/intersectMesh/trace.cpp index f925dd701..57ce051ec 100644 --- a/Cassiopee/XCore/XCore/intersectMesh/trace.cpp +++ b/Cassiopee/XCore/XCore/intersectMesh/trace.cpp @@ -49,15 +49,14 @@ bool ray_edge_intersect(E_Float ox, E_Float oy, E_Float oz, return true; } -static -void get_unit_projected_direction(E_Int fid, const Smesh &M, const E_Float D[3], - E_Float proj[3]) +void Smesh::get_unit_projected_direction(E_Int fid, const E_Float D[3], + E_Float proj[3]) const { assert(fid >= 0); - assert(fid < M.nf); + assert(fid < nf); // Unit normal - const E_Float *fN = &M.fnormals[3*fid]; + const E_Float *fN = &fnormals[3*fid]; E_Float dp = K_MATH::dot(D, fN, 3); @@ -68,10 +67,9 @@ void get_unit_projected_direction(E_Int fid, const Smesh &M, const E_Float D[3], proj[0] /= NORM, proj[1] /= NORM, proj[2] /= NORM; } -static -E_Int deduce_face(const std::vector &pf, const Smesh &M, +E_Int Smesh::deduce_face(const std::vector &pf, E_Float ox, E_Float oy, E_Float oz, E_Float D[3], - E_Int last_vertex, E_Int last_edge) + E_Int last_vertex, E_Int last_edge) const { // Intersect the projection of D with all the faces in pf // At least one intersection must exist @@ -88,10 +86,10 @@ E_Int deduce_face(const std::vector &pf, const Smesh &M, // Compute the unit projection of D on this face E_Float proj[3]; - get_unit_projected_direction(fid, M, D, proj); + get_unit_projected_direction(fid, D, proj); - const auto &pn = M.F[fid]; - const auto &pe = M.F2E[fid]; + const auto &pn = F[fid]; + const auto &pe = F2E[fid]; assert(pn.size() == pe.size()); for (size_t i = 0; i < pn.size(); i++) { @@ -107,8 +105,8 @@ E_Int deduce_face(const std::vector &pf, const Smesh &M, bool hit = ray_edge_intersect(ox, oy, oz, proj[0], proj[1], proj[2], - M.X[p], M.Y[p], M.Z[p], - M.X[q], M.Y[q], M.Z[q], + X[p], Y[p], Z[p], + X[q], Y[q], Z[q], t, s ); @@ -132,22 +130,19 @@ E_Int deduce_face(const std::vector &pf, const Smesh &M, return ret_face; } -static -void get_shared_faces(const Vertex *v, const Smesh &M, std::vector &ret, - E_Int &pid, E_Int &eid) +void Smesh::get_shared_faces(const PointLoc &loc, std::vector &ret, + E_Int &pid, E_Int &eid) const { ret.clear(); - const auto &loc = v->loc; - E_Int fid = loc.fid; assert(fid != -1); if (loc.e_idx != -1) { assert(loc.v_idx == -1); - const auto &pe = M.F2E[fid]; + const auto &pe = F2E[fid]; eid = pe[loc.e_idx]; - const auto &pf = M.E2F[eid]; + const auto &pf = E2F[eid]; assert(pf[0] == fid || pf[1] == fid); ret.push_back(pf[0]); // O could be on a boundary edge @@ -155,9 +150,9 @@ void get_shared_faces(const Vertex *v, const Smesh &M, std::vector &ret, } else if (loc.v_idx != -1) { assert(loc.e_idx == -1); - const auto &pn = M.F[fid]; + const auto &pn = F[fid]; pid = pn[loc.v_idx]; - const auto &pf = M.P2F[pid]; + const auto &pf = P2F[pid]; // For consistency bool found_fid = false; for (auto face : pf) { @@ -188,13 +183,13 @@ E_Int Dcel::trace_hedge_2(Hedge *sh, const Smesh &M, const Smesh &S, E_Int hid) std::vector orig_faces, tail_faces; E_Int last_vertex = -1, last_edge = -1; E_Int dummy; - get_shared_faces(O, M, orig_faces, last_vertex, last_edge); - get_shared_faces(T, M, tail_faces, dummy, dummy); + M.get_shared_faces(O->loc, orig_faces, last_vertex, last_edge); + M.get_shared_faces(T->loc, tail_faces, dummy, dummy); // If O is inside fid, we could skip this check // We keep it for consistency - E_Int starting_face = deduce_face( - orig_faces, M, O->x, O->y, O->z, D, + E_Int starting_face = M.deduce_face( + orig_faces, O->x, O->y, O->z, D, last_vertex, last_edge ); assert(starting_face != -1); @@ -234,7 +229,7 @@ E_Int Dcel::trace_hedge_2(Hedge *sh, const Smesh &M, const Smesh &S, E_Int hid) // Project D onto current face E_Float proj[3]; - get_unit_projected_direction(current_fid, M, D, proj); + M.get_unit_projected_direction(current_fid, D, proj); E_Int next_fid = -1; E_Float next_pos[3] = {EFLOATMAX, EFLOATMAX, EFLOATMAX}; @@ -337,7 +332,7 @@ E_Int Dcel::trace_hedge_2(Hedge *sh, const Smesh &M, const Smesh &S, E_Int hid) const auto &pf = M.P2F[last_vertex]; - next_fid = deduce_face(pf, M, + next_fid = M.deduce_face(pf, next_pos[0], next_pos[1], next_pos[2], D, last_vertex, last_edge ); From dedf26ce79588c74ce193afbd374a1c7e261ff6f Mon Sep 17 00:00:00 2001 From: imadhammani Date: Sat, 12 Oct 2024 16:50:32 +0200 Subject: [PATCH 48/86] XCore intersectMesh: we correctly detect the starting face for bounding smesh extraction --- Cassiopee/XCore/XCore/intersectMesh/icapsule.cpp | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/Cassiopee/XCore/XCore/intersectMesh/icapsule.cpp b/Cassiopee/XCore/XCore/intersectMesh/icapsule.cpp index 6cf5024e4..d005925a1 100644 --- a/Cassiopee/XCore/XCore/intersectMesh/icapsule.cpp +++ b/Cassiopee/XCore/XCore/intersectMesh/icapsule.cpp @@ -142,15 +142,14 @@ Smesh Smesh::extract_bounding_smesh(const Smesh &Sf, chain_points.push_back(Point(Sf.X[p], Sf.Y[p], Sf.Z[p])); } - /* std::set bfids; for (size_t i = 0; i < pchain.size(); i++) { E_Int p = pchain[i]; E_Int q = pchain[(i+1)%pchain.size()]; - E_Float px = Mf.X[p], py = Mf.Y[p], pz = Mf.Z[p]; - E_Float qx = Mf.X[q], qy = Mf.Y[q], qz = Mf.Z[q]; + E_Float px = Sf.X[p], py = Sf.Y[p], pz = Sf.Z[p]; + E_Float qx = Sf.X[q], qy = Sf.Y[q], qz = Sf.Z[q]; E_Float D[3] = {qx-px, qy-py, qz-pz}; E_Float NORM = K_MATH::norm(D, 3); @@ -161,10 +160,10 @@ Smesh Smesh::extract_bounding_smesh(const Smesh &Sf, E_Int last_vertex = -1, last_edge = -1, dummy; - Mf.get_shared_faces(plocs[p], orig_faces, last_vertex, last_edge); - Mf.get_shared_faces(plocs[q], tail_faces, dummy, dummy); + get_shared_faces(plocs[p], orig_faces, last_vertex, last_edge); + get_shared_faces(plocs[q], tail_faces, dummy, dummy); - E_Int starting_face = Mf.deduce_face(orig_faces, px, py, pz, + E_Int starting_face = deduce_face(orig_faces, px, py, pz, D, last_vertex, last_edge); assert(starting_face != -1); @@ -185,7 +184,6 @@ Smesh Smesh::extract_bounding_smesh(const Smesh &Sf, } - */ return Smesh(); } From ac6203f19f0dce42f116a336bfb77d1214b6ef26 Mon Sep 17 00:00:00 2001 From: imadhammani Date: Sat, 12 Oct 2024 20:14:05 +0200 Subject: [PATCH 49/86] XCore intersectMesh: trace the exterior Sf edges + grab pwalls --- .../XCore/XCore/intersectMesh/icapsule.cpp | 160 +++++++++++++++++- .../XCore/intersectMesh/intersectMesh.cpp | 6 +- .../XCore/XCore/intersectMesh/primitives.cpp | 2 - .../XCore/XCore/intersectMesh/primitives.h | 13 +- Cassiopee/XCore/XCore/intersectMesh/ray.h | 1 + Cassiopee/XCore/XCore/intersectMesh/smesh.cpp | 53 +++++- Cassiopee/XCore/XCore/intersectMesh/smesh.h | 6 +- Cassiopee/XCore/XCore/intersectMesh/trace.cpp | 1 - 8 files changed, 224 insertions(+), 18 deletions(-) diff --git a/Cassiopee/XCore/XCore/intersectMesh/icapsule.cpp b/Cassiopee/XCore/XCore/intersectMesh/icapsule.cpp index d005925a1..fd6c12955 100644 --- a/Cassiopee/XCore/XCore/intersectMesh/icapsule.cpp +++ b/Cassiopee/XCore/XCore/intersectMesh/icapsule.cpp @@ -4,6 +4,19 @@ #include "io.h" #include "primitives.h" +E_Int ray_point_orient(const E_Float o[3], const E_Float d[3], + const E_Float fN[3], E_Float px, E_Float py, E_Float pz) +{ + E_Float w[3] = {px-o[0], py-o[1], pz-o[2]}; + E_Float c[3]; + K_MATH::cross(d, w, c); + E_Float dp = K_MATH::dot(c, fN, 3); + E_Int cmp = Sign(dp); + if (cmp > 0) return 1; + if (cmp < 0) return -1; + return 0; +} + Smesh IMesh::make_smesh(const E_Float *ptag) { patch.clear(); @@ -90,6 +103,8 @@ void Smesh::correct_near_points_and_edges(Smesh &Sf, } std::vector chain_points; +std::set walls; +std::set pwalls; Smesh Smesh::extract_bounding_smesh(const Smesh &Sf, const std::vector &plocs) @@ -117,6 +132,7 @@ Smesh Smesh::extract_bounding_smesh(const Smesh &Sf, E_Int current_point = pchain[1]; + while (pchain.size() < nbedges) { E_Int to_delete = -1; for (auto e : bedges) { @@ -142,7 +158,28 @@ Smesh Smesh::extract_bounding_smesh(const Smesh &Sf, chain_points.push_back(Point(Sf.X[p], Sf.Y[p], Sf.Z[p])); } - std::set bfids; + point_write("first", Sf.X[pchain[0]], Sf.Y[pchain[0]], Sf.Z[pchain[0]]); + point_write("second", Sf.X[pchain[1]], Sf.Y[pchain[1]], Sf.Z[pchain[1]]); + point_write("third", Sf.X[pchain[2]], Sf.Y[pchain[2]], Sf.Z[pchain[2]]); + + // Sort the pchain counterclockwise + E_Int a = pchain[0], b = pchain[1], c = pchain[2]; + E_Float ux = Sf.X[b] - Sf.X[a]; + E_Float uy = Sf.Y[b] - Sf.Y[a]; + E_Float uz = Sf.Z[b] - Sf.Z[a]; + E_Float vx = Sf.X[c] - Sf.X[b]; + E_Float vy = Sf.Y[c] - Sf.Y[b]; + E_Float vz = Sf.Z[c] - Sf.Z[b]; + E_Float cp[3] = {uy*vz - uz*vy, uz*vx - ux*vz, ux*vy - uy*vx}; + const E_Float *N_b = &fnormals[3*plocs[b].fid]; + E_Float dp = K_MATH::dot(cp, N_b, 3); + E_Int cmp = Sign(dp); + assert(cmp != 0); + if (cmp < 0) + std::reverse(pchain.begin(), pchain.end()); + + std::set bfids; // Boundary face ids + std::set weids; // Wall edge ids for (size_t i = 0; i < pchain.size(); i++) { E_Int p = pchain[i]; @@ -168,23 +205,122 @@ Smesh Smesh::extract_bounding_smesh(const Smesh &Sf, assert(starting_face != -1); bool found_tail = false; - E_Int current_fid = starting_face; - E_Float current_pos[3] = {px, py, pz}; + E_Int cur_fid = starting_face; + E_Float cur_pos[3] = {px, py, pz}; E_Int walk = 0; E_Int max_walks = 20; while (!found_tail && walk <= max_walks) { - found_tail = true; + + // Add current face to the set of boundary faces + bfids.insert(cur_fid); + + E_Float proj[3]; + get_unit_projected_direction(cur_fid, D, proj); + + const auto &pn = F[cur_fid]; + const auto &pe = F2E[cur_fid]; + + const E_Float *fN = &fnormals[3*cur_fid]; + + // First pass: define the wall points + for (size_t i = 0; i < pn.size(); i++) { + E_Int p = pn[i]; + //E_Int q = pn[(i+1)%pn.size()]; + //E_Int e = pe[i]; + E_Float px = X[p], py = Y[p], pz = Z[p]; + //E_Float qx = X[q], qy = Y[q], qz = Z[q]; + if (ray_point_orient(cur_pos, proj, fN, px, py, pz) <= 0) {// && + //ray_point_orient(cur_pos, proj, fN, qx, qy, qz) <= 0) { + //walls.insert(e); + //weids.insert(e); + pwalls.insert(p); + } + } + + for (auto fid : tail_faces) { + if (fid == cur_fid) { + found_tail = true; + break; + } + } + + if (found_tail) break; + + E_Int next_fid = -1; + E_Float next_pos[3] = {EFLOATMAX, EFLOATMAX, EFLOATMAX}; + + bool hit = false; + + for (size_t i = 0; i < pn.size(); i++) { + E_Int p = pn[i]; + E_Int q = pn[(i+1)%pn.size()]; + E_Int e = pe[i]; + + + if (p == last_vertex || q == last_vertex || e == last_edge) + continue; + + E_Float px = X[p], py = Y[p], pz = Z[p]; + E_Float qx = X[q], qy = Y[q], qz = Z[q]; + + E_Float t, s; + hit = ray_edge_intersect( + cur_pos[0], cur_pos[1], cur_pos[2], + proj[0], proj[1], proj[2], + px, py, pz, qx, qy, qz, + t, s + ); + + if (hit) { + if (s > TOL && s < 1 - TOL) { + const auto &pe = F2E[cur_fid]; + E_Int eid = pe[i]; + last_edge = eid; + last_vertex = -1; + if (E2F[eid][0] == cur_fid) next_fid = E2F[eid][1]; + else next_fid = E2F[eid][0]; + + next_pos[0] = cur_pos[0] + t * proj[0]; + next_pos[1] = cur_pos[1] + t * proj[1]; + next_pos[2] = cur_pos[2] + t * proj[2]; + } else { + bool hit_p = (s <= TOL); + bool hit_q = (s >= 1 - TOL); + assert(!(hit_p && hit_q)); + last_edge = -1; + if (hit_p) last_vertex = p; + else last_vertex = q; + next_pos[0] = X[last_vertex]; + next_pos[1] = Y[last_vertex]; + next_pos[2] = Z[last_vertex]; + const auto &pf = P2F[last_vertex]; + next_fid = deduce_face(pf, + next_pos[0], next_pos[1], next_pos[2], + D, last_vertex, last_edge + ); + assert(next_fid != -1); + } + break; + } + } + + assert(hit); + assert(next_fid != cur_fid); + cur_fid = next_fid; + cur_pos[0] = next_pos[0]; + cur_pos[1] = next_pos[1]; + cur_pos[2] = next_pos[2]; walk++; } assert(found_tail); assert(walk <= max_walks); - - } + //write_edges("wall", weids); + return Smesh(); } @@ -203,6 +339,8 @@ ICapsule::ICapsule(const Karray &marray, const std::vector &sarrays, Mf.make_bbox(); Mf.hash_faces(); Mf.make_fnormals(); + Mf.make_point_faces(); + Mf.make_pnormals(); Ss.reserve(sarrays.size()); spatches.reserve(sarrays.size()); @@ -220,6 +358,9 @@ ICapsule::ICapsule(const Karray &marray, const std::vector &sarrays, spatches.push_back(Ss[i].make_smesh(ptags[i])); spatches[i].make_bbox(); spatches[i].hash_faces(); + spatches[i].make_fnormals(); + spatches[i].make_point_faces(); + spatches[i].make_pnormals(); spatches[i].compute_min_distance_between_points(); plocs.push_back(Mf.locate(spatches[i])); Mf.correct_near_points_and_edges(spatches[i], plocs[i]); @@ -230,6 +371,8 @@ ICapsule::ICapsule(const Karray &marray, const std::vector &sarrays, point_write("cpoints", cpoints); point_write("chain", chain_points); + //Mf.write_edges("walls", walls); + Mf.write_points("pwalls", pwalls); } @@ -269,6 +412,11 @@ PyObject *K_XCORE::icapsule_extract_slave(PyObject *self, PyObject *args) ICapsule *icap = (ICapsule *)PyCapsule_GetPointer(ICAPSULE, "ICapsule"); + if (INDEX >= icap->Ss.size()) { + RAISE("Bad slave index."); + return NULL; + } + auto Sout = icap->Ss[INDEX].export_karray(); return Sout; diff --git a/Cassiopee/XCore/XCore/intersectMesh/intersectMesh.cpp b/Cassiopee/XCore/XCore/intersectMesh/intersectMesh.cpp index e214274b3..b14fd991f 100644 --- a/Cassiopee/XCore/XCore/intersectMesh/intersectMesh.cpp +++ b/Cassiopee/XCore/XCore/intersectMesh/intersectMesh.cpp @@ -398,13 +398,15 @@ PyObject *K_XCORE::intersectMesh(PyObject *self, PyObject *args) Mf.write_ngon("Mf"); Sf.write_ngon("Sf"); + /* puts("Making point edges..."); Mf.make_point_edges(); Sf.make_point_edges(); + */ puts("Making point faces..."); - Mf.make_point_faces_all(); - Sf.make_point_faces_all(); + Mf.make_point_faces(); + Sf.make_point_faces(); puts("Making point/face normals..."); Mf.make_pnormals(); diff --git a/Cassiopee/XCore/XCore/intersectMesh/primitives.cpp b/Cassiopee/XCore/XCore/intersectMesh/primitives.cpp index 0781bacc4..3972f3e24 100644 --- a/Cassiopee/XCore/XCore/intersectMesh/primitives.cpp +++ b/Cassiopee/XCore/XCore/intersectMesh/primitives.cpp @@ -23,8 +23,6 @@ #include "primitives.h" #include "event.h" -E_Float TOL = 1e-12; - E_Int Sign(E_Float x, E_Float tol) { if (x > tol) return 1; diff --git a/Cassiopee/XCore/XCore/intersectMesh/primitives.h b/Cassiopee/XCore/XCore/intersectMesh/primitives.h index 2bdffcfef..d0ff63210 100644 --- a/Cassiopee/XCore/XCore/intersectMesh/primitives.h +++ b/Cassiopee/XCore/XCore/intersectMesh/primitives.h @@ -24,7 +24,7 @@ #include "status.h" #include "common/common.h" -extern E_Float TOL; +constexpr E_Float TOL = 1e-12; void compute_intersection(Queue &Q, Snode *sit0, Snode *sit1, std::vector &I); @@ -42,7 +42,7 @@ E_Float DifferenceOfProducts(E_Float a, E_Float b, E_Float c, E_Float d); E_Float TwoDiff(E_Float a, E_Float b); -E_Int Sign(E_Float x, E_Float tol=1e-12); +E_Int Sign(E_Float x, E_Float tol=TOL); E_Int orient3D(E_Float *A, E_Float *B, E_Float *C, E_Float *D); @@ -61,3 +61,12 @@ E_Int EdgeEdgeIntersect(E_Float ax, E_Float ay, E_Float az, E_Float bx, E_Float E_Int EdgeEdgeIntersect(E_Float ax, E_Float ay, E_Float az, E_Float bx, E_Float by, E_Float bz, E_Float px, E_Float py, E_Float pz, E_Float qx, E_Float qy, E_Float qz, E_Float &t); + +bool ray_edge_intersect(E_Float ox, E_Float oy, E_Float oz, + E_Float dx, E_Float dy, E_Float dz, + E_Float px, E_Float py, E_Float pz, + E_Float qx, E_Float qy, E_Float qz, + E_Float &t, E_Float &u); + +E_Int ray_point_orient(const E_Float o[3], const E_Float d[3], + const E_Float fN[3], E_Float px, E_Float py, E_Float pz); diff --git a/Cassiopee/XCore/XCore/intersectMesh/ray.h b/Cassiopee/XCore/XCore/intersectMesh/ray.h index 291c3d30a..7e7bf1ff7 100644 --- a/Cassiopee/XCore/XCore/intersectMesh/ray.h +++ b/Cassiopee/XCore/XCore/intersectMesh/ray.h @@ -36,3 +36,4 @@ struct Ray { E_Int MollerTrumbore(E_Float px, E_Float py, E_Float pz, E_Float dx, E_Float dy, E_Float dz, E_Float ax, E_Float ay, E_Float az, E_Float bx, E_Float by, E_Float bz, E_Float cx, E_Float cy, E_Float cz, TriangleIntersection &TI); + diff --git a/Cassiopee/XCore/XCore/intersectMesh/smesh.cpp b/Cassiopee/XCore/XCore/intersectMesh/smesh.cpp index 55f9a32b0..3bf991f22 100644 --- a/Cassiopee/XCore/XCore/intersectMesh/smesh.cpp +++ b/Cassiopee/XCore/XCore/intersectMesh/smesh.cpp @@ -515,7 +515,7 @@ void Smesh::init_adaptation_data() } } -void Smesh::make_point_faces() +void Smesh::make_point_faces_active() { P2F.clear(); P2F.resize(np); @@ -527,9 +527,8 @@ void Smesh::make_point_faces() } } -void Smesh::make_point_faces_all() +void Smesh::make_point_faces() { - assert(P2F.empty()); P2F.clear(); P2F.resize(np); @@ -771,7 +770,15 @@ void Smesh::make_fnormals() void Smesh::make_pnormals() { - make_fnormals(); + if (fnormals.empty()) { + fprintf(stderr, "Trying to compute pnormals without fnormals!\n"); + assert(0); + } + + if (P2F.empty()) { + fprintf(stderr, "Trying to compute pnormals without P2F!\n"); + assert(0); + } pnormals.clear(); pnormals.resize(3*np, 0); @@ -902,3 +909,41 @@ void Smesh::compute_min_distance_between_points() assert(ndists == np*(np-1)/2); } + +void Smesh::write_edges(const char *fname, const std::set &eids) const +{ + FILE *fh = fopen(fname, "w"); + assert(fh); + + fprintf(fh, "POINTS\n"); + fprintf(fh, "%lu\n", eids.size()*2); + for (E_Int eid : eids) { + const auto &e = E[eid]; + E_Int p = e.p; + E_Int q = e.q; + fprintf(fh, "%f %f %f\n", X[p], Y[p], Z[p]); + fprintf(fh, "%f %f %f\n", X[q], Y[q], Z[q]); + } + fprintf(fh, "EDGES\n"); + fprintf(fh, "%lu\n", eids.size()); + for (size_t i = 0; i < 2*eids.size(); i++) { + fprintf(fh, "%lu ", i); + } + fprintf(fh, "\n"); + + fclose(fh); +} + +void Smesh::write_points(const char *fname, const std::set &pids) const +{ + FILE *fh= fopen(fname, "w"); + assert(fh); + + fprintf(fh, "POINTS\n"); + fprintf(fh, "%lu\n", pids.size()); + for (E_Int pid : pids){ + fprintf(fh, "%f %f %f\n", X[pid], Y[pid], Z[pid]); + } + + fclose(fh); +} diff --git a/Cassiopee/XCore/XCore/intersectMesh/smesh.h b/Cassiopee/XCore/XCore/intersectMesh/smesh.h index 49a6694d9..28d61fc27 100644 --- a/Cassiopee/XCore/XCore/intersectMesh/smesh.h +++ b/Cassiopee/XCore/XCore/intersectMesh/smesh.h @@ -126,7 +126,7 @@ struct Smesh { void make_point_faces(); - void make_point_faces_all(); + void make_point_faces_active(); void make_point_edges(); @@ -140,6 +140,10 @@ struct Smesh { std::vector locate(const Smesh &Sf) const; + void write_points(const char *fname, const std::set &pids) const; + + void write_edges(const char *fname, const std::set &eids) const; + void write_faces(const char *fname, const std::vector &faces) const; void write_ngon(const char *fname); diff --git a/Cassiopee/XCore/XCore/intersectMesh/trace.cpp b/Cassiopee/XCore/XCore/intersectMesh/trace.cpp index 57ce051ec..2b188835b 100644 --- a/Cassiopee/XCore/XCore/intersectMesh/trace.cpp +++ b/Cassiopee/XCore/XCore/intersectMesh/trace.cpp @@ -5,7 +5,6 @@ #include "io.h" #include "event.h" -static bool ray_edge_intersect(E_Float ox, E_Float oy, E_Float oz, E_Float dx, E_Float dy, E_Float dz, E_Float px, E_Float py, E_Float pz, From 09383b7a1c9e4f8a5c0f7b805af980a9d573922a Mon Sep 17 00:00:00 2001 From: imadhammani Date: Sun, 13 Oct 2024 02:39:08 +0200 Subject: [PATCH 50/86] XCore intersectMesh: extract wfids/weids for BFS (bounding smesh) + fixed weird bug with Sf.E instead of E --- Cassiopee/XCore/XCore/intersectMesh/dcel.cpp | 6 -- .../XCore/XCore/intersectMesh/icapsule.cpp | 84 ++++++++----------- .../XCore/XCore/intersectMesh/sgraph.cpp | 2 +- Cassiopee/XCore/XCore/intersectMesh/smesh.cpp | 9 ++ Cassiopee/XCore/XCore/intersectMesh/smesh.h | 2 +- 5 files changed, 47 insertions(+), 56 deletions(-) diff --git a/Cassiopee/XCore/XCore/intersectMesh/dcel.cpp b/Cassiopee/XCore/XCore/intersectMesh/dcel.cpp index b00732774..a3cf01935 100644 --- a/Cassiopee/XCore/XCore/intersectMesh/dcel.cpp +++ b/Cassiopee/XCore/XCore/intersectMesh/dcel.cpp @@ -708,9 +708,6 @@ void Dcel::set_cycles_inout(const Smesh &M)//, const Smesh &S) for (E_Int i = 0; i < 3; i++) N[i] /= NORM; } - E_Float NORM = K_MATH::norm(N, 3); - //assert(Sign(NORM -1) == 0); - E_Float cmp = K_MATH::dot(N, cp, 3); if (cmp < 0) { @@ -1507,9 +1504,6 @@ void Dcel::resolve_hedges(const Smesh &M, const Smesh &S) for (E_Int i = 0; i < 3; i++) N[i] /= NORM; } - E_Float NORM = K_MATH::norm(N, 3); - //assert(Sign(NORM -1) == 0); - sort_leaving_hedges(leaving, N, M); for (size_t i = 0; i < leaving.size(); i++) { diff --git a/Cassiopee/XCore/XCore/intersectMesh/icapsule.cpp b/Cassiopee/XCore/XCore/intersectMesh/icapsule.cpp index fd6c12955..bcfb36b58 100644 --- a/Cassiopee/XCore/XCore/intersectMesh/icapsule.cpp +++ b/Cassiopee/XCore/XCore/intersectMesh/icapsule.cpp @@ -48,9 +48,6 @@ Smesh IMesh::make_smesh_from_skin(bool is_planar) return Smesh(*this, is_planar); } -std::vector epoints; -std::vector cpoints; - void Smesh::correct_near_points_and_edges(Smesh &Sf, std::vector &plocs) { @@ -92,22 +89,19 @@ void Smesh::correct_near_points_and_edges(Smesh &Sf, E_Int b = pn[i2]; V += U; assert(Sign(V+W-1) == 0); - epoints.push_back(Point(Sf.X[i], Sf.Y[i], Sf.Z[i])); Sf.X[i] = V*X[a] + W*X[b]; Sf.Y[i] = V*Y[a] + W*Y[b]; Sf.Z[i] = V*Z[a] + W*Z[b]; - cpoints.push_back(Point(Sf.X[i], Sf.Y[i], Sf.Z[i])); } } printf("on vertex: %d - on edge: %d\n", on_vertex, on_edge); } -std::vector chain_points; -std::set walls; +std::set ewalls; std::set pwalls; Smesh Smesh::extract_bounding_smesh(const Smesh &Sf, - const std::vector &plocs) + const std::vector &plocs) const { // Get boundary edges from spatch std::set bedges; @@ -121,28 +115,25 @@ Smesh Smesh::extract_bounding_smesh(const Smesh &Sf, // Make the boundary point chain std::vector pchain; - const auto &E = Sf.E; - E_Int first_edge = *bedges.begin(); - pchain.push_back(E[first_edge].p); - pchain.push_back(E[first_edge].q); + pchain.push_back(Sf.E[first_edge].p); + pchain.push_back(Sf.E[first_edge].q); bedges.erase(first_edge); E_Int current_point = pchain[1]; - while (pchain.size() < nbedges) { E_Int to_delete = -1; for (auto e : bedges) { - if (E[e].p == current_point) { - pchain.push_back(E[e].q); + if (Sf.E[e].p == current_point) { + pchain.push_back(Sf.E[e].q); current_point = pchain.back(); to_delete = e; break; - } else if (E[e].q == current_point) { - pchain.push_back(E[e].p); + } else if (Sf.E[e].q == current_point) { + pchain.push_back(Sf.E[e].p); current_point = pchain.back(); to_delete = e; break; @@ -154,14 +145,6 @@ Smesh Smesh::extract_bounding_smesh(const Smesh &Sf, assert(pchain.size() == nbedges); - for (auto p : pchain) { - chain_points.push_back(Point(Sf.X[p], Sf.Y[p], Sf.Z[p])); - } - - point_write("first", Sf.X[pchain[0]], Sf.Y[pchain[0]], Sf.Z[pchain[0]]); - point_write("second", Sf.X[pchain[1]], Sf.Y[pchain[1]], Sf.Z[pchain[1]]); - point_write("third", Sf.X[pchain[2]], Sf.Y[pchain[2]], Sf.Z[pchain[2]]); - // Sort the pchain counterclockwise E_Int a = pchain[0], b = pchain[1], c = pchain[2]; E_Float ux = Sf.X[b] - Sf.X[a]; @@ -178,9 +161,9 @@ Smesh Smesh::extract_bounding_smesh(const Smesh &Sf, if (cmp < 0) std::reverse(pchain.begin(), pchain.end()); - std::set bfids; // Boundary face ids - std::set weids; // Wall edge ids - + std::set wfids; + std::set weids; + for (size_t i = 0; i < pchain.size(); i++) { E_Int p = pchain[i]; E_Int q = pchain[(i+1)%pchain.size()]; @@ -212,30 +195,25 @@ Smesh Smesh::extract_bounding_smesh(const Smesh &Sf, E_Int max_walks = 20; while (!found_tail && walk <= max_walks) { - - // Add current face to the set of boundary faces - bfids.insert(cur_fid); + wfids.insert(cur_fid); + E_Float proj[3]; get_unit_projected_direction(cur_fid, D, proj); const auto &pn = F[cur_fid]; const auto &pe = F2E[cur_fid]; - const E_Float *fN = &fnormals[3*cur_fid]; // First pass: define the wall points for (size_t i = 0; i < pn.size(); i++) { E_Int p = pn[i]; - //E_Int q = pn[(i+1)%pn.size()]; - //E_Int e = pe[i]; + E_Int q = pn[(i+1)%pn.size()]; + E_Int e = pe[i]; E_Float px = X[p], py = Y[p], pz = Z[p]; - //E_Float qx = X[q], qy = Y[q], qz = Z[q]; - if (ray_point_orient(cur_pos, proj, fN, px, py, pz) <= 0) {// && - //ray_point_orient(cur_pos, proj, fN, qx, qy, qz) <= 0) { - //walls.insert(e); - //weids.insert(e); - pwalls.insert(p); + if (ray_point_orient(cur_pos, proj, fN, px, py, pz) <= 0 || + ray_point_orient(cur_pos, proj, fN, qx, qy, qz) <= 0) { + weids.insert(e); } } @@ -318,9 +296,15 @@ Smesh Smesh::extract_bounding_smesh(const Smesh &Sf, assert(found_tail); assert(walk <= max_walks); } + + for (E_Int eid : weids) ewalls.insert(eid); + + // TODO(Imad): project wpids on best-fit plane and jarvis march + - //write_edges("wall", weids); + // BFS to get the smesh mpids + return Smesh(); } @@ -341,6 +325,15 @@ ICapsule::ICapsule(const Karray &marray, const std::vector &sarrays, Mf.make_fnormals(); Mf.make_point_faces(); Mf.make_pnormals(); + Mf.make_point_edges(); + + for (E_Int pid = 0; pid < Mf.np; pid++) { + const auto &pe = Mf.P2E[pid]; + for (E_Int eid : pe) { + const auto &e = Mf.E[eid]; + assert(e.p == pid || e.q == pid); + } + } Ss.reserve(sarrays.size()); spatches.reserve(sarrays.size()); @@ -367,12 +360,7 @@ ICapsule::ICapsule(const Karray &marray, const std::vector &sarrays, mpatches.push_back(Mf.extract_bounding_smesh(spatches[i], plocs[i])); } - point_write("epoints", epoints); - point_write("cpoints", cpoints); - - point_write("chain", chain_points); - //Mf.write_edges("walls", walls); - Mf.write_points("pwalls", pwalls); + Mf.write_edges("ewalls", ewalls); } @@ -412,7 +400,7 @@ PyObject *K_XCORE::icapsule_extract_slave(PyObject *self, PyObject *args) ICapsule *icap = (ICapsule *)PyCapsule_GetPointer(ICAPSULE, "ICapsule"); - if (INDEX >= icap->Ss.size()) { + if (INDEX >= (E_Int)icap->Ss.size()) { RAISE("Bad slave index."); return NULL; } diff --git a/Cassiopee/XCore/XCore/intersectMesh/sgraph.cpp b/Cassiopee/XCore/XCore/intersectMesh/sgraph.cpp index d7d5008dc..fa53cc4a7 100644 --- a/Cassiopee/XCore/XCore/intersectMesh/sgraph.cpp +++ b/Cassiopee/XCore/XCore/intersectMesh/sgraph.cpp @@ -44,7 +44,7 @@ void IMesh::make_skin_graph() const auto &pn = F[fid]; E_Int start = xadj[i]; E_Int end = xadj[i+1]; - for (size_t j = 0; j < end-start; j++) + for (E_Int j = 0; j < end-start; j++) fpts[start+j] = pn[j]; } diff --git a/Cassiopee/XCore/XCore/intersectMesh/smesh.cpp b/Cassiopee/XCore/XCore/intersectMesh/smesh.cpp index 3bf991f22..2d5c79a95 100644 --- a/Cassiopee/XCore/XCore/intersectMesh/smesh.cpp +++ b/Cassiopee/XCore/XCore/intersectMesh/smesh.cpp @@ -548,6 +548,15 @@ void Smesh::make_point_edges() P2E[E[eid].p].push_back(eid); P2E[E[eid].q].push_back(eid); } + + for (E_Int pid = 0; pid < np; pid++) { + const auto &pe = P2E[pid]; + for (auto eid : pe) { + const auto &e = E[eid]; + assert(e.p == pid || e.q == pid); + } + } + } Smesh Smesh::extract_conformized() diff --git a/Cassiopee/XCore/XCore/intersectMesh/smesh.h b/Cassiopee/XCore/XCore/intersectMesh/smesh.h index 28d61fc27..b92c9b153 100644 --- a/Cassiopee/XCore/XCore/intersectMesh/smesh.h +++ b/Cassiopee/XCore/XCore/intersectMesh/smesh.h @@ -78,7 +78,7 @@ struct Smesh { E_Float NEAR_EDGE_TOL = 1e-3; Smesh extract_bounding_smesh(const Smesh &Sf, - const std::vector &plocs); + const std::vector &plocs) const; void correct_near_points_and_edges(Smesh &Sf, std::vector &plocs); From 9fbe21075d7ba27504a4581ce509f4feff5544c4 Mon Sep 17 00:00:00 2001 From: imadhammani Date: Sun, 13 Oct 2024 13:31:31 +0200 Subject: [PATCH 51/86] XCore intersectMesh: write ngon from smesh facelist --- Cassiopee/XCore/XCore/intersectMesh/smesh.cpp | 107 +++++++++++++++--- Cassiopee/XCore/XCore/intersectMesh/smesh.h | 4 +- 2 files changed, 93 insertions(+), 18 deletions(-) diff --git a/Cassiopee/XCore/XCore/intersectMesh/smesh.cpp b/Cassiopee/XCore/XCore/intersectMesh/smesh.cpp index 2d5c79a95..c6f9cb6fb 100644 --- a/Cassiopee/XCore/XCore/intersectMesh/smesh.cpp +++ b/Cassiopee/XCore/XCore/intersectMesh/smesh.cpp @@ -666,35 +666,108 @@ Smesh Smesh::extract_conformized() return ret; } -void Smesh::write_faces(const char *fname, const std::vector &faces) const +void Smesh::write_ngon(const char *fname, const std::set &fset) const { - std::map pmap; + std::vector flist; + flist.reserve(fset.size()); + for (E_Int fid : fset) flist.push_back(fid); + write_ngon(fname, flist); +} - E_Int np = 0; +void Smesh::write_ngon(const char *fname, const std::vector &faces) const +{ + std::vector INDPH(faces.size() + 1); + INDPH[0] = 0; - for (size_t i = 0; i < faces.size(); i++) { - E_Int f = faces[i]; - const auto &cn = F[f]; - for (auto p : cn) { - if (pmap.find(p) == pmap.end()) { - pmap[p] = np++; + std::map new_pids; + std::map new_eids; + E_Int idx = 0; + E_Int NP = 0; + E_Int NE = 0; + E_Int NF = (E_Int)faces.size(); + + for (E_Int fid : faces) { + const auto &pn = F[fid]; + const auto &pe = F2E[fid]; + + INDPH[idx+1] = INDPH[idx] + (E_Int)pn.size(); + idx++; + + for (E_Int pid : pn) { + if (new_pids.find(pid) == new_pids.end()) { + new_pids[pid] = NP; + NP++; } } - } - std::vector ipmap(pmap.size()); - for (auto &pdata : pmap) ipmap[pdata.second] = pdata.first; + for (E_Int eid : pe) { + if (new_eids.find(eid) == new_eids.end()) { + new_eids[eid] = NE; + NE++; + } + } + } FILE *fh = fopen(fname, "w"); assert(fh); - fprintf(fh, "POINTS\n"); - fprintf(fh, "%d\n", np); - for (size_t i = 0; i < ipmap.size(); i++) { - E_Int op = ipmap[i]; - fprintf(fh, "%f %f %f\n", X[op], Y[op], Z[op]); + fprintf(fh, "%lu\n", new_pids.size()); + + std::vector nX(NP), nY(NP), nZ(NP); + for (const auto &pids : new_pids) { + E_Int opid = pids.first; + E_Int npid = pids.second; + nX[npid] = X[opid]; + nY[npid] = Y[opid]; + nZ[npid] = Z[opid]; } + for (size_t pid = 0; pid < NP; pid++) { + fprintf(fh, "%f %f %f\n", nX[pid], nY[pid], nZ[pid]); + } + + fprintf(fh, "INDPG\n"); + fprintf(fh, "%lu\n", new_eids.size()+1); + E_Int sizeNGon = -2; + for (size_t i = 0; i < new_eids.size() + 1; i++) { + sizeNGon += 2; + fprintf(fh, "%d ", sizeNGon); + } + fprintf(fh, "\n"); + assert(sizeNGon == 2*NE); + + std::vector nE(new_eids.size(), {-1, -1}); + for (const auto &eids : new_eids) { + E_Int oeid = eids.first; + E_Int neid = eids.second; + nE[neid].p = new_pids[E[oeid].p]; + nE[neid].q = new_pids[E[oeid].q]; + } + + fprintf(fh, "NGON\n"); + fprintf(fh, "%d\n", 2*NE); + for (const auto &e : nE) { + fprintf(fh, "%d %d ", e.p, e.q); + } + fprintf(fh, "\n"); + + fprintf(fh, "INDPH\n"); + fprintf(fh, "%d\n", NF+1); + for (E_Int i = 0; i < NF+1; i++) + fprintf(fh, "%d ", INDPH[i]); + fprintf(fh, "\n"); + + fprintf(fh, "NFACE\n"); + fprintf(fh, "%d\n", INDPH[NF]); + for (size_t i = 0; i < faces.size(); i++) { + const auto &pe = F2E[faces[i]]; + for (E_Int eid : pe) { + fprintf(fh, "%d ", new_eids[eid]); + } + } + fprintf(fh, "\n"); + + fclose(fh); } diff --git a/Cassiopee/XCore/XCore/intersectMesh/smesh.h b/Cassiopee/XCore/XCore/intersectMesh/smesh.h index b92c9b153..cf844423d 100644 --- a/Cassiopee/XCore/XCore/intersectMesh/smesh.h +++ b/Cassiopee/XCore/XCore/intersectMesh/smesh.h @@ -144,7 +144,9 @@ struct Smesh { void write_edges(const char *fname, const std::set &eids) const; - void write_faces(const char *fname, const std::vector &faces) const; + void write_ngon(const char *fname, const std::set &fset) const; + + void write_ngon(const char *fname, const std::vector &faces) const; void write_ngon(const char *fname); From 52ff672600a982f25c81f1e397c34de4e74782f8 Mon Sep 17 00:00:00 2001 From: imadhammani Date: Sun, 13 Oct 2024 14:08:37 +0200 Subject: [PATCH 52/86] XCore intersectMesh: smesh io --- Cassiopee/XCore/XCore/intersectMesh/smesh.cpp | 14 ++++++++++++++ Cassiopee/XCore/XCore/intersectMesh/smesh.h | 4 +++- 2 files changed, 17 insertions(+), 1 deletion(-) diff --git a/Cassiopee/XCore/XCore/intersectMesh/smesh.cpp b/Cassiopee/XCore/XCore/intersectMesh/smesh.cpp index c6f9cb6fb..8c7f56115 100644 --- a/Cassiopee/XCore/XCore/intersectMesh/smesh.cpp +++ b/Cassiopee/XCore/XCore/intersectMesh/smesh.cpp @@ -1016,6 +1016,20 @@ void Smesh::write_edges(const char *fname, const std::set &eids) const fclose(fh); } +void Smesh::write_points(const char *fname, const std::vector &pids) const +{ + FILE *fh= fopen(fname, "w"); + assert(fh); + + fprintf(fh, "POINTS\n"); + fprintf(fh, "%lu\n", pids.size()); + for (E_Int pid : pids){ + fprintf(fh, "%f %f %f\n", X[pid], Y[pid], Z[pid]); + } + + fclose(fh); +} + void Smesh::write_points(const char *fname, const std::set &pids) const { FILE *fh= fopen(fname, "w"); diff --git a/Cassiopee/XCore/XCore/intersectMesh/smesh.h b/Cassiopee/XCore/XCore/intersectMesh/smesh.h index cf844423d..3fd280964 100644 --- a/Cassiopee/XCore/XCore/intersectMesh/smesh.h +++ b/Cassiopee/XCore/XCore/intersectMesh/smesh.h @@ -140,7 +140,9 @@ struct Smesh { std::vector locate(const Smesh &Sf) const; - void write_points(const char *fname, const std::set &pids) const; + void write_points(const char *fname, const std::set &pset) const; + + void write_points(const char *fname, const std::vector &pids) const; void write_edges(const char *fname, const std::set &eids) const; From 580b0f5eb5af8eac6b967fa68cd472d1913ae6e3 Mon Sep 17 00:00:00 2001 From: imadhammani Date: Sun, 13 Oct 2024 14:09:14 +0200 Subject: [PATCH 53/86] XCore intersectMesh: wfids extraction seems to work properly --- .../XCore/XCore/intersectMesh/icapsule.cpp | 48 +++++++++++++++++-- 1 file changed, 43 insertions(+), 5 deletions(-) diff --git a/Cassiopee/XCore/XCore/intersectMesh/icapsule.cpp b/Cassiopee/XCore/XCore/intersectMesh/icapsule.cpp index bcfb36b58..299a29038 100644 --- a/Cassiopee/XCore/XCore/intersectMesh/icapsule.cpp +++ b/Cassiopee/XCore/XCore/intersectMesh/icapsule.cpp @@ -3,6 +3,7 @@ #include "point.h" #include "io.h" #include "primitives.h" +#include E_Int ray_point_orient(const E_Float o[3], const E_Float d[3], const E_Float fN[3], E_Float px, E_Float py, E_Float pz) @@ -11,6 +12,7 @@ E_Int ray_point_orient(const E_Float o[3], const E_Float d[3], E_Float c[3]; K_MATH::cross(d, w, c); E_Float dp = K_MATH::dot(c, fN, 3); + // TODO(Imad): needs FEA + float128 E_Int cmp = Sign(dp); if (cmp > 0) return 1; if (cmp < 0) return -1; @@ -94,11 +96,12 @@ void Smesh::correct_near_points_and_edges(Smesh &Sf, Sf.Z[i] = V*Z[a] + W*Z[b]; } } - printf("on vertex: %d - on edge: %d\n", on_vertex, on_edge); + //printf("on vertex: %d - on edge: %d\n", on_vertex, on_edge); } std::set ewalls; -std::set pwalls; +std::set fwalls; +std::vector pchains; Smesh Smesh::extract_bounding_smesh(const Smesh &Sf, const std::vector &plocs) const @@ -161,6 +164,9 @@ Smesh Smesh::extract_bounding_smesh(const Smesh &Sf, if (cmp < 0) std::reverse(pchain.begin(), pchain.end()); + Sf.write_points("pchain", pchain); + for (E_Int p : pchain) pchains.push_back({Sf.X[p], Sf.Y[p], Sf.Z[p]}); + std::set wfids; std::set weids; @@ -205,12 +211,13 @@ Smesh Smesh::extract_bounding_smesh(const Smesh &Sf, const auto &pe = F2E[cur_fid]; const E_Float *fN = &fnormals[3*cur_fid]; - // First pass: define the wall points + // First pass: define the wall data for (size_t i = 0; i < pn.size(); i++) { E_Int p = pn[i]; E_Int q = pn[(i+1)%pn.size()]; E_Int e = pe[i]; E_Float px = X[p], py = Y[p], pz = Z[p]; + E_Float qx = X[q], qy = Y[q], qz = Z[q]; if (ray_point_orient(cur_pos, proj, fN, px, py, pz) <= 0 || ray_point_orient(cur_pos, proj, fN, qx, qy, qz) <= 0) { weids.insert(e); @@ -296,14 +303,42 @@ Smesh Smesh::extract_bounding_smesh(const Smesh &Sf, assert(found_tail); assert(walk <= max_walks); } + + write_edges("weids", weids); - for (E_Int eid : weids) ewalls.insert(eid); // TODO(Imad): project wpids on best-fit plane and jarvis march - // BFS to get the smesh mpids + std::queue Q; + for (E_Int fid : wfids) Q.push(fid); + + printf("wfids before: %lu", wfids.size()); + + while (!Q.empty()) { + E_Int fid = Q.front(); + Q.pop(); + + const auto &neis = F2F[fid]; + const auto &pe = F2E[fid]; + for (size_t i = 0; i < pe.size(); i++) { + E_Int eid = pe[i]; + if (weids.find(eid) != weids.end()) continue; + E_Int nei = neis[i]; + if (wfids.find(nei) == wfids.end()) { + wfids.insert(nei); + Q.push(nei); + } + } + } + + write_ngon("wfids", wfids); + + printf(" - after: %lu\n", wfids.size()); + + for (E_Int eid : weids) ewalls.insert(eid); + for (E_Int fid : wfids) fwalls.insert(fid); return Smesh(); } @@ -357,10 +392,13 @@ ICapsule::ICapsule(const Karray &marray, const std::vector &sarrays, spatches[i].compute_min_distance_between_points(); plocs.push_back(Mf.locate(spatches[i])); Mf.correct_near_points_and_edges(spatches[i], plocs[i]); + printf("slave %d\n", i); mpatches.push_back(Mf.extract_bounding_smesh(spatches[i], plocs[i])); } Mf.write_edges("ewalls", ewalls); + Mf.write_ngon("fwalls", fwalls); + point_write("pchains", pchains); } From f4f2bb8e982719910de29c2e416415fdddbf0b80 Mon Sep 17 00:00:00 2001 From: imadhammani Date: Sun, 13 Oct 2024 16:54:28 +0200 Subject: [PATCH 54/86] XCore intersectMesh: visualize mfaces shared between spatches --- .../XCore/XCore/intersectMesh/icapsule.cpp | 32 +++++++++++++------ Cassiopee/XCore/XCore/intersectMesh/smesh.cpp | 5 +++ Cassiopee/XCore/XCore/intersectMesh/smesh.h | 4 ++- 3 files changed, 31 insertions(+), 10 deletions(-) diff --git a/Cassiopee/XCore/XCore/intersectMesh/icapsule.cpp b/Cassiopee/XCore/XCore/intersectMesh/icapsule.cpp index 299a29038..f64336924 100644 --- a/Cassiopee/XCore/XCore/intersectMesh/icapsule.cpp +++ b/Cassiopee/XCore/XCore/intersectMesh/icapsule.cpp @@ -103,7 +103,7 @@ std::set ewalls; std::set fwalls; std::vector pchains; -Smesh Smesh::extract_bounding_smesh(const Smesh &Sf, +std::set Smesh::extract_bounding_faces(const Smesh &Sf, const std::vector &plocs) const { // Get boundary edges from spatch @@ -313,8 +313,6 @@ Smesh Smesh::extract_bounding_smesh(const Smesh &Sf, std::queue Q; for (E_Int fid : wfids) Q.push(fid); - printf("wfids before: %lu", wfids.size()); - while (!Q.empty()) { E_Int fid = Q.front(); Q.pop(); @@ -335,12 +333,10 @@ Smesh Smesh::extract_bounding_smesh(const Smesh &Sf, write_ngon("wfids", wfids); - printf(" - after: %lu\n", wfids.size()); - for (E_Int eid : weids) ewalls.insert(eid); for (E_Int fid : wfids) fwalls.insert(fid); - return Smesh(); + return wfids; } ICapsule::ICapsule(const Karray &marray, const std::vector &sarrays, @@ -375,7 +371,8 @@ ICapsule::ICapsule(const Karray &marray, const std::vector &sarrays, std::vector> plocs; plocs.reserve(sarrays.size()); - mpatches.reserve(sarrays.size()); + std::vector> bfaces_list; + bfaces_list.reserve(sarrays.size()); for (size_t i = 0; i < sarrays.size(); i++) { Ss.push_back(IMesh(sarrays[i])); @@ -392,13 +389,30 @@ ICapsule::ICapsule(const Karray &marray, const std::vector &sarrays, spatches[i].compute_min_distance_between_points(); plocs.push_back(Mf.locate(spatches[i])); Mf.correct_near_points_and_edges(spatches[i], plocs[i]); - printf("slave %d\n", i); - mpatches.push_back(Mf.extract_bounding_smesh(spatches[i], plocs[i])); + bfaces_list.push_back(Mf.extract_bounding_faces(spatches[i], plocs[i])); } Mf.write_edges("ewalls", ewalls); Mf.write_ngon("fwalls", fwalls); point_write("pchains", pchains); + + // Isolate the mfaces that contain spoints from different spatches + std::map> wfid_to_spatch; + + for (size_t i = 0; i < bfaces_list.size(); i++) { + const auto &bfaces = bfaces_list[i]; + for (E_Int fid : bfaces) { + wfid_to_spatch[fid].insert(i); + } + } + + std::set ref_faces; + for (const auto &fdata : wfid_to_spatch) { + if (fdata.second.size() > 1) + ref_faces.insert(fdata.first); + } + + Mf.write_ngon("ref_faces", ref_faces); } diff --git a/Cassiopee/XCore/XCore/intersectMesh/smesh.cpp b/Cassiopee/XCore/XCore/intersectMesh/smesh.cpp index 8c7f56115..56bea0d78 100644 --- a/Cassiopee/XCore/XCore/intersectMesh/smesh.cpp +++ b/Cassiopee/XCore/XCore/intersectMesh/smesh.cpp @@ -1043,3 +1043,8 @@ void Smesh::write_points(const char *fname, const std::set &pids) const fclose(fh); } + +Smesh Smesh::extract_smesh(const std::set &fids, bool is_planar) +{ + return Smesh(); +} diff --git a/Cassiopee/XCore/XCore/intersectMesh/smesh.h b/Cassiopee/XCore/XCore/intersectMesh/smesh.h index 3fd280964..b5ddc43ce 100644 --- a/Cassiopee/XCore/XCore/intersectMesh/smesh.h +++ b/Cassiopee/XCore/XCore/intersectMesh/smesh.h @@ -77,7 +77,7 @@ struct Smesh { E_Float NEAR_VERTEX_TOL = 1e-3; E_Float NEAR_EDGE_TOL = 1e-3; - Smesh extract_bounding_smesh(const Smesh &Sf, + std::set extract_bounding_faces(const Smesh &Sf, const std::vector &plocs) const; void correct_near_points_and_edges(Smesh &Sf, std::vector &plocs); @@ -116,6 +116,8 @@ struct Smesh { Smesh() {}; + Smesh extract_smesh(const std::set &fids, bool is_planar=true); + Smesh(const IMesh &M, bool is_planar=true); Smesh(const IMesh &M, const std::vector &faces); From 6c84c62a5cdcf47867c2674ea0e00e75e4a6ba76 Mon Sep 17 00:00:00 2001 From: imadhammani Date: Sun, 13 Oct 2024 18:19:50 +0200 Subject: [PATCH 55/86] XCore intersectMesh: prepare mfaces refinement sensor --- .../XCore/XCore/intersectMesh/icapsule.cpp | 56 +++++++++++++------ Cassiopee/XCore/XCore/intersectMesh/point.h | 7 +++ 2 files changed, 46 insertions(+), 17 deletions(-) diff --git a/Cassiopee/XCore/XCore/intersectMesh/icapsule.cpp b/Cassiopee/XCore/XCore/intersectMesh/icapsule.cpp index f64336924..b588fc32a 100644 --- a/Cassiopee/XCore/XCore/intersectMesh/icapsule.cpp +++ b/Cassiopee/XCore/XCore/intersectMesh/icapsule.cpp @@ -369,8 +369,8 @@ ICapsule::ICapsule(const Karray &marray, const std::vector &sarrays, Ss.reserve(sarrays.size()); spatches.reserve(sarrays.size()); - std::vector> plocs; - plocs.reserve(sarrays.size()); + std::vector> plocs_list; + plocs_list.reserve(sarrays.size()); std::vector> bfaces_list; bfaces_list.reserve(sarrays.size()); @@ -387,32 +387,54 @@ ICapsule::ICapsule(const Karray &marray, const std::vector &sarrays, spatches[i].make_point_faces(); spatches[i].make_pnormals(); spatches[i].compute_min_distance_between_points(); - plocs.push_back(Mf.locate(spatches[i])); - Mf.correct_near_points_and_edges(spatches[i], plocs[i]); - bfaces_list.push_back(Mf.extract_bounding_faces(spatches[i], plocs[i])); + plocs_list.push_back(Mf.locate(spatches[i])); + Mf.correct_near_points_and_edges(spatches[i], plocs_list[i]); + bfaces_list.push_back( + Mf.extract_bounding_faces(spatches[i], plocs_list[i])); } Mf.write_edges("ewalls", ewalls); Mf.write_ngon("fwalls", fwalls); point_write("pchains", pchains); - // Isolate the mfaces that contain spoints from different spatches - std::map> wfid_to_spatch; - - for (size_t i = 0; i < bfaces_list.size(); i++) { - const auto &bfaces = bfaces_list[i]; - for (E_Int fid : bfaces) { - wfid_to_spatch[fid].insert(i); + // mfaces to spoints + std::map> mfid_to_spids; + + for (size_t i = 0; i < plocs_list.size(); i++) { + const auto &plocs = plocs_list[i]; + for (size_t j = 0; j < plocs.size(); j++) { + const auto &ploc = plocs[j]; + PointData point_data; + point_data.pid = j; + point_data.fid = ploc.fid; + point_data.sid = i; + point_data.x = spatches[i].X[j]; + point_data.y = spatches[i].Y[j]; + point_data.z = spatches[i].Z[j]; + + mfid_to_spids[ploc.fid].push_back(point_data); } } - - std::set ref_faces; - for (const auto &fdata : wfid_to_spatch) { - if (fdata.second.size() > 1) - ref_faces.insert(fdata.first); + + std::vector fids_to_erase; + for (const auto &mfdata : mfid_to_spids) { + std::set sids; + for (const auto &spdata : mfdata.second) + sids.insert(spdata.sid); + if (sids.size() == 1) + fids_to_erase.push_back(mfdata.first); } + for (E_Int fid : fids_to_erase) + mfid_to_spids.erase(fid); + + std::vector ref_faces; + for (const auto &mfdata : mfid_to_spids) + ref_faces.push_back(mfdata.first); + Mf.write_ngon("ref_faces", ref_faces); + + Mf.refine(mfid_to_spids); } diff --git a/Cassiopee/XCore/XCore/intersectMesh/point.h b/Cassiopee/XCore/XCore/intersectMesh/point.h index 0d93631e0..b921e73ac 100644 --- a/Cassiopee/XCore/XCore/intersectMesh/point.h +++ b/Cassiopee/XCore/XCore/intersectMesh/point.h @@ -29,6 +29,13 @@ struct PointLoc { E_Float bcrd[3] = {-1, -1, -1}; }; +struct PointData { + E_Int pid; // my id in spatch + E_Int fid; // id of the mface I am on + E_Int sid; // if of the smesh I belong to + E_Float x, y, z; +}; + struct pointFace { E_Int F; From 00f556f3d0edf9c47af43ca4f8a51f1be8f8e193 Mon Sep 17 00:00:00 2001 From: imadhammani Date: Sun, 13 Oct 2024 18:20:26 +0200 Subject: [PATCH 56/86] XCore intersectMesh: clean-up smesh files --- Cassiopee/XCore/XCore/intersectMesh/smesh.cpp | 371 +----------------- Cassiopee/XCore/XCore/intersectMesh/smesh.h | 96 ++--- .../XCore/XCore/intersectMesh/smeshRefine.cpp | 301 ++------------ 3 files changed, 73 insertions(+), 695 deletions(-) diff --git a/Cassiopee/XCore/XCore/intersectMesh/smesh.cpp b/Cassiopee/XCore/XCore/intersectMesh/smesh.cpp index 56bea0d78..14ebb8da7 100644 --- a/Cassiopee/XCore/XCore/intersectMesh/smesh.cpp +++ b/Cassiopee/XCore/XCore/intersectMesh/smesh.cpp @@ -21,6 +21,7 @@ #include "triangle.h" #include "mesh.h" #include "io.h" +#include "point.h" #include #include @@ -31,23 +32,9 @@ #include #include -bool Smesh::ccw_oriented(E_Int face) -{ - E_Float sum = 0; - - const auto &pn = F[face]; - - for (size_t i = 0; i < pn.size(); i++) { - E_Int p = pn[i]; - E_Int q = pn[(i+1)%pn.size()]; - sum += (X[q]-X[p])*(Y[q]+Y[p]); - } - - E_Int sign = Sign(sum); - assert(sign != 0); +Smesh::Smesh() +{} - return sign < 0; -} Smesh::Smesh(const IMesh &M, bool is_planar) { @@ -290,243 +277,6 @@ void Smesh::make_edges(bool is_planar) } } -// Refine M0/M1 as long as one of its faces contains another face from M1/M0 - -#define NON_DEGEN 0 -#define ON_VERTEX 1 -#define ON_EDGE 2 - -bool Smesh::faces_are_dups(E_Int face, E_Int mface, const Smesh &M) -{ - const auto &pn = F[face]; - const auto &pnm = M.F[mface]; - - assert(face_is_quad(face) || face_is_tri(face)); - assert(M.face_is_quad(mface) || M.face_is_tri(mface)); - - if (pn.size() != pnm.size()) return false; - - E_Int mfound[4] = { 0, 0, 0, 0 }; - - for (size_t i = 0; i < pn.size(); i++) { - E_Int p = pn[i]; - for (size_t j = 0; j < pnm.size(); j++) { - E_Int pm = pnm[j]; - if (cmp_points(X[p], Y[p], Z[p], M.X[pm], M.Y[pm], M.Z[pm]) == 0) { - assert(mfound[i] == 0); - mfound[i] = 1; - break; - } - } - - if (mfound[i] == 0) return false; - } - - return true; -} - -std::vector Smesh::prepare_for_refinement(const std::vector &ref_data) -{ - std::vector ref_faces; - - for (size_t i = 0; i < ref_data.size(); i++) { - if (ref_data[i] > 0) ref_faces.push_back(i); - } - - // Refine the lower-level faces first - std::sort(ref_faces.begin(), ref_faces.end(), - [&] (E_Int i, E_Int j) { return flevel[i] < flevel[j]; }); - - // Resize data structures - resize_point_data(ref_faces.size()); - resize_edge_data(ref_faces.size()); - resize_face_data(ref_faces.size()); - - return ref_faces; -} - -void Smesh::resize_point_data(size_t nref_faces) -{ - size_t nnew_points = np + nref_faces * 5; - X.resize(nnew_points); - Y.resize(nnew_points); -} - -void Smesh::resize_edge_data(size_t nref_faces) -{ - size_t nnew_edges = ne + nref_faces * 12; - E.resize(nnew_edges, {-1, -1}); - E2F.resize(nnew_edges, {-1, -1}); - elevel.resize(nnew_edges, -1); -} - -void Smesh::resize_face_data(size_t nref_faces) -{ - size_t nnew_faces = nf + nref_faces * 4; - F.resize(nnew_faces); - F2E.resize(nnew_faces); - flevel.resize(nnew_faces, -1); -} - -void Smesh::refine_faces(const std::vector &ref_faces) -{ - for (E_Int ref_face : ref_faces) { - - if (face_is_tri(ref_face)) refine_tri(ref_face); - else refine_quad(ref_face); - } -} - -std::vector Smesh::smooth_ref_data(std::map> &sensor) -{ - std::vector ref_data(nf, 0); - std::stack stk; - - for (const auto &fdata : sensor) { - assert(face_is_active(fdata.first)); - ref_data[fdata.first] = 1; - stk.push(fdata.first); - } - - while (!stk.empty()) { - E_Int face = stk.top(); - stk.pop(); - - E_Int face_incr = ref_data[face] + flevel[face]; - - auto neis = get_active_neighbours(face); - - for (auto nei : neis) { - assert(nei != -1); - - E_Int nei_incr = ref_data[nei] + flevel[nei]; - - E_Int diff = abs(face_incr - nei_incr); - - if (diff <= 1) continue; - - E_Int fid = face_incr > nei_incr ? nei : face; - - ref_data[fid] += 1; - - stk.push(fid); - } - } - - return ref_data; -} - -std::vector Smesh::get_active_neighbours(E_Int face) -{ - std::vector neis; - - for (E_Int edge : F2E[face]) { - assert(face == E2F[edge][0] || face == E2F[edge][1]); - - // For now, an edge is enabled if it has no children. - // This is not necessarily true if unrefinement is considered. - auto it = echildren.find(edge); - - if (it == echildren.end()) { - assert(edge_is_active(edge)); - - E_Int nei = get_neighbour(face, edge); - - if (nei != -1) neis.push_back(nei); - } else { - // Edge was refined, get the neighbours of its children - assert(!edge_is_active(edge)); - - const auto &children = it->second; - - for (E_Int child : children) { - E_Int nei = get_neighbour(face, child); - - if (nei != -1) neis.push_back(nei); - } - } - } - - return neis; -} - -bool Smesh::face_contains_Mface(E_Int face, E_Int mface, const Smesh &M) const -{ - // face containes mface iff it contains all its points - assert(M.face_is_active(mface)); - const auto &cn = M.F[mface]; - for (E_Int p : cn) { - if (face_contains_point(face, M.X[p], M.Y[p], M.Z[p]) == -1) - return false; - } - return true; -} - -E_Int Smesh::face_contains_point(E_Int face, E_Float x, E_Float y, E_Float z) const -{ - const auto &cn = F[face]; - - E_Int hit, a, b, c; - - if (face_is_quad(face)) { - - // First triangle - - a = cn[0], b = cn[1], c = cn[2]; - - hit = Triangle::is_point_inside(x, y, z, X[a], Y[a], Z[a], - X[b], Y[b], Z[b], X[c], Y[c], Z[c]); - - if (hit) return 0; - - // Second triangle - a = cn[0], b = cn[2], c = cn[3]; - - hit = Triangle::is_point_inside(x, y, z, X[a], Y[a], Z[a], - X[b], Y[b], Z[b], X[c], Y[c], Z[c]); - - if (hit) return 1; - } else { - - assert(face_is_tri(face)); - - a = cn[0], b = cn[1], c = cn[2]; - - hit = Triangle::is_point_inside(x, y, z, X[a], Y[a], Z[a], - X[b], Y[b], Z[b], X[c], Y[c], Z[c]); - - if (hit) return 0; - } - - return -1; -} - -void Smesh::init_adaptation_data() -{ - flevel.resize(nf, 0); - elevel.resize(ne, 0); - - for (E_Int i = 0; i < nf; i++) { - factive.insert(i); - } - - for (E_Int i = 0; i < ne; i++) { - eactive.insert(i); - } -} - -void Smesh::make_point_faces_active() -{ - P2F.clear(); - P2F.resize(np); - - for (E_Int face : factive) { - const auto &cn = F[face]; - for (auto p : cn) - P2F[p].push_back(face); - } -} - void Smesh::make_point_faces() { P2F.clear(); @@ -561,109 +311,8 @@ void Smesh::make_point_edges() Smesh Smesh::extract_conformized() { - // Keep all the points - std::vector new_X(np), new_Y(np); - for (E_Int i = 0; i < np; i++) { - new_X[i] = X[i]; - new_Y[i] = Y[i]; - } - - // Keep the active edges and faces - std::map new_eids; - std::map new_fids; - - E_Int new_ne = 0, new_nf = 0; - - for (E_Int edge : eactive) new_eids[edge] = new_ne++; - for (E_Int face : factive) new_fids[face] = new_nf++; - - // E - std::vector new_E(new_ne, {-1, -1}); - - for (E_Int edge : eactive) { - E_Int new_eid = new_eids[edge]; - - // TODO: (p,q) -> new_pids(p,q) - new_E[new_eid].p = E[edge].p; - new_E[new_eid].q = E[edge].q; - } - - // E2F - std::vector> new_E2F(new_ne, {-1, -1}); - - for (E_Int edge : eactive) { - E_Int new_eid = new_eids[edge]; - - E_Int left = E2F[edge][0]; - E_Int right = E2F[edge][1]; - - new_E2F[new_eid][0] = new_fids[left]; - if (right != -1) new_E2F[new_eid][1] = new_fids[right]; - } - - // F2E - std::vector> new_F2E(new_nf); - - for (E_Int face : factive) { - E_Int new_fid = new_fids[face]; - - const auto &old_pe = F2E[face]; - - auto &new_pe = new_F2E[new_fid]; - - for (E_Int e : old_pe) { - if (edge_is_active(e)) { - new_pe.push_back(new_eids[e]); - } else { - const auto &children = echildren[e]; - assert(children.size() == 2); - - for (E_Int child : children) new_pe.push_back(new_eids[child]); - } - } - } - - // Check consistent E2F and F2E - /* - for (E_Int i = 0; i < new_nf; i++) { - const auto &pe = new_F2E[i]; - - for (E_Int e : pe) { - assert(i == new_E2F[e][0] || i == new_E2F[e][1]); - } - } - */ - - // F - std::vector> new_F(new_nf); - - for (E_Int face = 0; face < new_nf; face++) { - const auto &pe = new_F2E[face]; - - auto &pn = new_F[face]; - - for (E_Int e : pe) { - assert(face == new_E2F[e][0] || face == new_E2F[e][1]); - if (new_E2F[e][0] == face) pn.push_back(new_E[e].p); - else pn.push_back(new_E[e].q); - } - } - - // Build and return - Smesh ret; - ret.X = new_X; - ret.Y = new_Y; - ret.E = new_E; - ret.E2F = new_E2F; - ret.F = new_F; - ret.F2E = new_F2E; - ret.np = np; - ret.ne = new_ne; - ret.nf = new_nf; - //ret.l2gp = l2gp; - //ret.factive = factive; - - return ret; + assert(0); + return Smesh(); } void Smesh::write_ngon(const char *fname, const std::set &fset) const @@ -1048,3 +697,13 @@ Smesh Smesh::extract_smesh(const std::set &fids, bool is_planar) { return Smesh(); } + +void Smesh::refine(const std::map> &sensor) +{ + size_t nref = sensor.size(); + + while (nref > 0) { + resize_for_refinement(nref); + nref = 0; + } +} diff --git a/Cassiopee/XCore/XCore/intersectMesh/smesh.h b/Cassiopee/XCore/XCore/intersectMesh/smesh.h index b5ddc43ce..331039a39 100644 --- a/Cassiopee/XCore/XCore/intersectMesh/smesh.h +++ b/Cassiopee/XCore/XCore/intersectMesh/smesh.h @@ -36,6 +36,19 @@ struct o_edge { o_edge(E_Int P, E_Int Q); }; +struct u_edge { + E_Int p, q; + + u_edge(E_Int P, E_Int Q) + : p(std::min(P, Q)), q(std::max(P, Q)) + {} + + bool operator<(const u_edge& e) const + { + return (p < e.p) || (p == e.p && q < e.q); + } +}; + struct Smesh { E_Int np, ne, nf; @@ -50,19 +63,12 @@ struct Smesh { std::vector> F2E; std::vector> F2F; - E_Int M_np; - E_Int M_ne; - E_Int M_nf; - std::map g2lp; std::map l2gp; std::map g2lf; std::map l2gf; - std::map g2le; - std::map l2ge; - std::vector fnormals; std::vector pnormals; @@ -77,6 +83,14 @@ struct Smesh { E_Float NEAR_VERTEX_TOL = 1e-3; E_Float NEAR_EDGE_TOL = 1e-3; + std::map ecenter; + + Smesh(); + + void resize_for_refinement(size_t nref_faces); + + void refine(const std::map> &sensor); + std::set extract_bounding_faces(const Smesh &Sf, const std::vector &plocs) const; @@ -100,21 +114,9 @@ struct Smesh { void compute_min_distance_between_points(); - AABB AABB_face(const std::vector &pn) const; - - // Adaptation void get_leaves(E_Int face, std::vector &leaves) const; - - std::map> fchildren; - std::set factive; - std::vector flevel; - - std::map> echildren; - std::set eactive; - std::vector elevel; - - Smesh() {}; + std::map>> fchildren; Smesh extract_smesh(const std::set &fids, bool is_planar=true); @@ -122,24 +124,12 @@ struct Smesh { Smesh(const IMesh &M, const std::vector &faces); - bool ccw_oriented(E_Int face); - void make_edges(bool is_planar); void make_point_faces(); - void make_point_faces_active(); - void make_point_edges(); - inline bool edge_is_active(E_Int edge) const - { return eactive.find(edge) != eactive.end(); } - - inline bool face_is_active(E_Int face) const - { return factive.find(face) != factive.end(); } - - //size_t refine(Smesh &M); - std::vector locate(const Smesh &Sf) const; void write_points(const char *fname, const std::set &pset) const; @@ -154,52 +144,14 @@ struct Smesh { void write_ngon(const char *fname); - inline bool face_is_tri(E_Int fid) const { return F[fid].size() == 3; } - - inline bool face_is_quad(E_Int fid) const { return F[fid].size() == 4; } - - bool face_contains_Mface(E_Int face, E_Int mface, const Smesh &M) const; - - E_Int face_contains_point(E_Int face, E_Float x, E_Float y, E_Float z) const; - - std::vector smooth_ref_data(std::map> &sensor); - - std::vector prepare_for_refinement(const std::vector &ref_data); - void refine_faces(const std::vector &ref_faces); - std::vector get_active_neighbours(E_Int face); - - inline E_Int get_neighbour(E_Int face, E_Int edge) const - { - assert(E2F[edge][0] == face || E2F[edge][1] == face); - return (E2F[edge][0] == face) ? E2F[edge][1] : E2F[edge][0]; - } - - void resize_point_data(size_t nref_faces); - - void resize_edge_data(size_t nref_faces); - - void resize_face_data(size_t nref_faces); - - void refine_tri(E_Int tri); - - void refine_quad(E_Int quad); + void refine_tri(E_Int fid); - void refine_edge(E_Int edge); + void refine_edge(const u_edge &e); - inline E_Int get_edge_center(E_Int edge) - { - assert(echildren.find(edge) != echildren.end()); - return E[echildren[edge][0]].q; - } - - void init_adaptation_data(); - Smesh extract_conformized(); - bool faces_are_dups(E_Int face, E_Int mface, const Smesh &M); - inline E_Int get_voxel(E_Int i, E_Int j, E_Int k) const { return i + NX*j + NXY*k; diff --git a/Cassiopee/XCore/XCore/intersectMesh/smeshRefine.cpp b/Cassiopee/XCore/XCore/intersectMesh/smeshRefine.cpp index dc1041482..e1f1304c7 100644 --- a/Cassiopee/XCore/XCore/intersectMesh/smeshRefine.cpp +++ b/Cassiopee/XCore/XCore/intersectMesh/smeshRefine.cpp @@ -20,289 +20,56 @@ #include "smesh.h" -// Refine wrt M's point cloud -/* -size_t Smesh::refine(Smesh &M) +void Smesh::refine_edge(const u_edge &e) { - // Locate M points within my faces - std::vector> pfs; - pfs.reserve(M.np); + E_Int p = e.p; + E_Int q = e.q; - for (E_Int i = 0; i < M.np; i++) { - auto pf = locate(M.X[i], M.Y[i], M.Z[i]); - pfs.push_back(pf); - } - - // Face to mpoints located within it - std::map> fpoints; - - for (size_t i = 0; i < pfs.size(); i++) { - for (const auto &faces : pfs[i]) { - E_Int F = faces.F; - fpoints[F].push_back(i); - } - } - - // Keep the faces which contain 3 points or more - std::map> filtered_faces_map; - std::vector filtered_faces; - - for (auto &fpts : fpoints) { - if (fpts.second.size() >= 3) { - filtered_faces_map.insert({fpts.first, fpts.second}); - filtered_faces.push_back(fpts.first); - } - } - - // Make point-to-face connectivity for M - M.make_point_faces(); - - std::map> ref_faces_to_Mfaces; - - for (const auto &fdata : filtered_faces_map) { - E_Int face = fdata.first; - const auto &points = fdata.second; - - // For every mface, how many points are contained within face? - std::map mcontained; - - for (E_Int p : points) { - for (E_Int mface : M.P2F[p]) { - assert(M.face_is_active(mface)); - mcontained[mface]++; - } - } - - for (const auto &mfdat : mcontained) { - E_Int mface = mfdat.first; - size_t npts = mfdat.second; - - assert(npts <= M.F[mface].size()); - - // Do not keep mface if it is not completely enclosed by face - if (npts < M.F[mface].size()) continue; - - // Do not keep mface if it is a duplicate of face - if (faces_are_dups(face, mface, M)) continue; - - ref_faces_to_Mfaces[face].push_back(mface); - } - } - - printf("Faces to refine: %zu\n", ref_faces_to_Mfaces.size()); - - filtered_faces.clear(); - - for (auto &fdata : ref_faces_to_Mfaces) { - filtered_faces.push_back(fdata.first); - } - - E_Int iter = 0; - size_t ret = 0; - - while (!ref_faces_to_Mfaces.empty()) { - iter++; - - auto ref_data = smooth_ref_data(ref_faces_to_Mfaces); - - auto ref_faces = prepare_for_refinement(ref_data); - - ret += ref_faces.size(); - - refine_faces(ref_faces); - - std::map> new_ref_faces_to_Mfaces; - - for (const auto &fdata : ref_faces_to_Mfaces) { - E_Int parent = fdata.first; - const auto &Mfaces = fdata.second; - - const auto &children = fchildren[parent]; - - for (auto child : children) { - for (E_Int mface : Mfaces) { - if (face_contains_Mface(child, mface, M)) { - assert(!faces_are_dups(child, mface, M)); - new_ref_faces_to_Mfaces[child].push_back(mface); - } - } - } - } - - ref_faces_to_Mfaces = new_ref_faces_to_Mfaces; - } - - return ret; -} -*/ - -void Smesh::refine_edge(E_Int edge) -{ - E_Int p = E[edge].p; - E_Int q = E[edge].q; - - // Rounding errors! X[np] = 0.5 * (X[p] + X[q]); Y[np] = 0.5 * (Y[p] + Y[q]); + Z[np] = 0.5 * (Z[p] + Z[q]); - E_Int ne1 = ne + 1; - - E[ne].p = p; - E[ne].q = np; - E[ne1].p = np; - E[ne1].q = q; - - E2F[ne][0] = E2F[ne1][0] = E2F[edge][0]; - E2F[ne][1] = E2F[ne1][1] = E2F[edge][1]; - - eactive.erase(edge); - eactive.insert(ne); - eactive.insert(ne1); - - echildren[edge] = {ne, ne1}; - - elevel[ne] = elevel[ne+1] = elevel[edge] + 1; - - l2gp[np] = M_np++; - - l2ge[ne] = M_ne++; - l2ge[ne+1] = M_ne++; - - np += 1; - ne += 2; + ecenter[e] = np; + np++; } -void Smesh::refine_quad(E_Int quad) +void Smesh::refine_tri(E_Int fid) { - // Refine the edges - const auto &pe = F2E[quad]; - assert(pe.size() == 4); - for (E_Int edge : pe) { - if (echildren.find(edge) == echildren.end()) { - refine_edge(edge); - } - } - - // Edge centers - E_Int ec[4]; - for (E_Int i = 0; i < 4; i++) { - ec[i] = get_edge_center(pe[i]); - } - - // Face centroid - const auto &pn = F[quad]; - - X[np] = Y[np] = 0.0; - for (E_Int i = 0; i < 4; i++) { - E_Int p = pn[i]; - X[np] += X[p]; - Y[np] += Y[p]; - } - X[np] *= 0.25; - Y[np] *= 0.25; - - // New face points - E_Int nf0 = nf, nf1 = nf+1, nf2 = nf+2, nf3 = nf+3; - - F[nf0] = { pn[0], ec[0], np, ec[3] }; - F[nf1] = { ec[0], pn[1], ec[1], np }; - F[nf2] = { np , ec[1], pn[2], ec[2] }; - F[nf3] = { ec[3], np , ec[2], pn[3] }; - - // Internal edge points - E_Int ne0 = ne, ne1 = ne+1, ne2 = ne+2, ne3 = ne+3; - - E[ne0].p = ec[0]; E[ne0].q = np; - E[ne1].p = ec[1]; E[ne1].q = np; - E[ne2].p = ec[2]; E[ne2].q = np; - E[ne3].p = ec[3]; E[ne3].q = np; - - // New face edges - const auto &pe0 = echildren[pe[0]]; - const auto &pe1 = echildren[pe[1]]; - const auto &pe2 = echildren[pe[2]]; - const auto &pe3 = echildren[pe[3]]; - - E_Int eid[8]; - eid[0] = pe0[0]; eid[1] = pe0[1]; - eid[2] = pe1[0]; eid[3] = pe1[1]; - eid[4] = pe2[0]; eid[5] = pe2[1]; - eid[6] = pe3[0]; eid[7] = pe3[1]; - - if (E2F[pe[0]][0] != quad) std::swap(eid[0], eid[1]); - if (E2F[pe[1]][0] != quad) std::swap(eid[2], eid[3]); - if (E2F[pe[2]][0] != quad) std::swap(eid[4], eid[5]); - if (E2F[pe[3]][0] != quad) std::swap(eid[6], eid[7]); - - F2E[nf0] = { eid[0], ne0 , ne3 , eid[7] }; - F2E[nf1] = { eid[1], eid[2], ne1 , ne0 }; - F2E[nf2] = { ne1 , eid[3], eid[4], ne2 }; - F2E[nf3] = { ne3 , ne2 , eid[5], eid[6] }; - - // External E2F - for (E_Int i = 0; i < 4; i++) { - E_Int fchild = nf + i; - const auto &pe = F2E[fchild]; - for (E_Int j = 0; j < 4; j++) { - E_Int edge = pe[j]; - if (E2F[edge][0] == quad) E2F[edge][0] = fchild; - else if (E2F[edge][1] == quad) E2F[edge][1] = fchild; + std::vector nodes(F[fid]); + + E_Int ec[3]; + + for (size_t i = 0; i < nodes.size(); i++) { + E_Int p = nodes[i]; + E_Int q = nodes[(i+1)%nodes.size()]; + u_edge e(p, q); + auto it = ecenter.find(e); + if (it == ecenter.end()) { + refine_edge(e); + ec[i] = ecenter[e]; + } else { + ec[i] = it->second; } } - // E_Internal E2F - E2F[ne0][0] = nf0; E2F[ne0][1] = nf1; - E2F[ne1][0] = nf1; E2F[ne1][1] = nf2; - E2F[ne2][0] = nf2; E2F[ne2][1] = nf3; - E2F[ne3][0] = nf3; E2F[ne3][1] = nf0; - - // Disable quad and enable its children - factive.erase(quad); - factive.insert(nf0); - factive.insert(nf1); - factive.insert(nf2); - factive.insert(nf3); - - // Set quad children pointers - fchildren[quad] = { nf0, nf1, nf2, nf3 }; - flevel[nf0] = flevel[nf1] = flevel[nf2] = flevel[nf3] = flevel[quad] + 1; - - // Enable internal edges - eactive.insert(ne0); - eactive.insert(ne1); - eactive.insert(ne2); - eactive.insert(ne3); - elevel[ne0] = elevel[ne1] = elevel[ne2] = elevel[ne3] = flevel[quad] + 1; + fchildren[fid].push_back({nf, nf+1, nf+2}); - l2gp[np] = M_np++; - - l2ge[ne0] = M_ne++; - l2ge[ne1] = M_ne++; - l2ge[ne2] = M_ne++; - l2ge[ne3] = M_ne++; - - l2gf[nf0] = M_nf++; - l2gf[nf1] = M_nf++; - l2gf[nf2] = M_nf++; - l2gf[nf3] = M_nf++; - - np += 1; - ne += 4; - nf += 4; + F[fid] = {nodes[0], ec[0], ec[2]}; + F[nf] = {ec[0], nodes[1], ec[1]}; + F[nf+1] = {ec[2], ec[1], nodes[2]}; + F[nf+2] = {ec[0], ec[1], ec[2]}; } -void Smesh::refine_tri(E_Int tri) +void Smesh::resize_for_refinement(size_t nref_faces) { - printf(SF_D_ "\n", tri); - assert(0); + E_Int fincr = nref_faces * 3; + E_Int pincr = nref_faces * 3; + F.resize(nf + fincr); + X.resize(np + pincr); + Y.resize(np + pincr); + Z.resize(np + pincr); } -void Smesh::get_leaves(E_Int face, std::vector &leaves) const +void Smesh::get_leaves(E_Int fid, std::vector &leaves) const { - if (face_is_active(face)) { - leaves.push_back(face); - return; - } - - for (E_Int child : fchildren.at(face)) get_leaves(child, leaves); } From 799d96100be7811fef80e32fe89703920104f830 Mon Sep 17 00:00:00 2001 From: imadhammani Date: Sun, 13 Oct 2024 18:52:02 +0200 Subject: [PATCH 57/86] XCore intersectMesh: more smesh files cleaning --- Cassiopee/XCore/XCore/intersectMesh/smesh.cpp | 259 +----------------- Cassiopee/XCore/XCore/intersectMesh/smesh.h | 113 ++++---- .../XCore/intersectMesh/smesh_extract.cpp | 14 + .../XCore/XCore/intersectMesh/smesh_io.cpp | 208 ++++++++++++++ .../{smeshRefine.cpp => smesh_refine.cpp} | 12 +- Cassiopee/XCore/srcs.py | 7 +- 6 files changed, 287 insertions(+), 326 deletions(-) create mode 100644 Cassiopee/XCore/XCore/intersectMesh/smesh_extract.cpp create mode 100644 Cassiopee/XCore/XCore/intersectMesh/smesh_io.cpp rename Cassiopee/XCore/XCore/intersectMesh/{smeshRefine.cpp => smesh_refine.cpp} (90%) diff --git a/Cassiopee/XCore/XCore/intersectMesh/smesh.cpp b/Cassiopee/XCore/XCore/intersectMesh/smesh.cpp index 14ebb8da7..aa3511875 100644 --- a/Cassiopee/XCore/XCore/intersectMesh/smesh.cpp +++ b/Cassiopee/XCore/XCore/intersectMesh/smesh.cpp @@ -24,7 +24,6 @@ #include "point.h" #include -#include #include #include #include @@ -35,7 +34,6 @@ Smesh::Smesh() {} - Smesh::Smesh(const IMesh &M, bool is_planar) { NEAR_VERTEX_TOL = M.NEAR_VERTEX_TOL; @@ -309,166 +307,6 @@ void Smesh::make_point_edges() } -Smesh Smesh::extract_conformized() -{ - assert(0); - return Smesh(); -} - -void Smesh::write_ngon(const char *fname, const std::set &fset) const -{ - std::vector flist; - flist.reserve(fset.size()); - for (E_Int fid : fset) flist.push_back(fid); - write_ngon(fname, flist); -} - -void Smesh::write_ngon(const char *fname, const std::vector &faces) const -{ - std::vector INDPH(faces.size() + 1); - INDPH[0] = 0; - - std::map new_pids; - std::map new_eids; - E_Int idx = 0; - E_Int NP = 0; - E_Int NE = 0; - E_Int NF = (E_Int)faces.size(); - - for (E_Int fid : faces) { - const auto &pn = F[fid]; - const auto &pe = F2E[fid]; - - INDPH[idx+1] = INDPH[idx] + (E_Int)pn.size(); - idx++; - - for (E_Int pid : pn) { - if (new_pids.find(pid) == new_pids.end()) { - new_pids[pid] = NP; - NP++; - } - } - - for (E_Int eid : pe) { - if (new_eids.find(eid) == new_eids.end()) { - new_eids[eid] = NE; - NE++; - } - } - } - - FILE *fh = fopen(fname, "w"); - assert(fh); - fprintf(fh, "POINTS\n"); - fprintf(fh, "%lu\n", new_pids.size()); - - std::vector nX(NP), nY(NP), nZ(NP); - for (const auto &pids : new_pids) { - E_Int opid = pids.first; - E_Int npid = pids.second; - nX[npid] = X[opid]; - nY[npid] = Y[opid]; - nZ[npid] = Z[opid]; - } - - for (size_t pid = 0; pid < NP; pid++) { - fprintf(fh, "%f %f %f\n", nX[pid], nY[pid], nZ[pid]); - } - - fprintf(fh, "INDPG\n"); - fprintf(fh, "%lu\n", new_eids.size()+1); - E_Int sizeNGon = -2; - for (size_t i = 0; i < new_eids.size() + 1; i++) { - sizeNGon += 2; - fprintf(fh, "%d ", sizeNGon); - } - fprintf(fh, "\n"); - assert(sizeNGon == 2*NE); - - std::vector nE(new_eids.size(), {-1, -1}); - for (const auto &eids : new_eids) { - E_Int oeid = eids.first; - E_Int neid = eids.second; - nE[neid].p = new_pids[E[oeid].p]; - nE[neid].q = new_pids[E[oeid].q]; - } - - fprintf(fh, "NGON\n"); - fprintf(fh, "%d\n", 2*NE); - for (const auto &e : nE) { - fprintf(fh, "%d %d ", e.p, e.q); - } - fprintf(fh, "\n"); - - fprintf(fh, "INDPH\n"); - fprintf(fh, "%d\n", NF+1); - for (E_Int i = 0; i < NF+1; i++) - fprintf(fh, "%d ", INDPH[i]); - fprintf(fh, "\n"); - - fprintf(fh, "NFACE\n"); - fprintf(fh, "%d\n", INDPH[NF]); - for (size_t i = 0; i < faces.size(); i++) { - const auto &pe = F2E[faces[i]]; - for (E_Int eid : pe) { - fprintf(fh, "%d ", new_eids[eid]); - } - } - fprintf(fh, "\n"); - - - fclose(fh); -} - - -void Smesh::write_ngon(const char *fname) -{ - FILE *fh = fopen(fname, "w"); - assert(fh); - - fprintf(fh, "POINTS\n"); - fprintf(fh, SF_D_ "\n", np); - for (E_Int i = 0; i < np; i++) { - fprintf(fh, "%f %f %f\n", X[i], Y[i], Z[i]); - } - - fprintf(fh, "INDPG\n"); - fprintf(fh, SF_D_ "\n", ne+1); - size_t sizeNGon = 0; - fprintf(fh, "0 "); - for (E_Int i = 0; i < ne; i++) { - sizeNGon += 2; - fprintf(fh, "%zu ", sizeNGon); - } - fprintf(fh, "\n"); - - fprintf(fh, "NGON\n"); - fprintf(fh, "%zu\n", sizeNGon); - for (E_Int i = 0; i < ne; i++) { - fprintf(fh, SF_D_ " " SF_D_ " ", E[i].p, E[i].q); - } - fprintf(fh, "\n"); - - fprintf(fh, "INDPH\n"); - fprintf(fh, SF_D_ "\n", nf+1); - size_t sizeNFace = 0; - fprintf(fh, "0 "); - for (E_Int i = 0; i < nf; i++) { - sizeNFace += F2E[i].size(); - fprintf(fh, "%zu ", sizeNFace); - } - fprintf(fh, "\n"); - - fprintf(fh, "NFACE\n"); - fprintf(fh, "%zu\n", sizeNFace); - for (E_Int i = 0; i < nf; i++) { - for (E_Int e : F2E[i]) fprintf(fh, SF_D_ " ", e); - } - fprintf(fh, "\n"); - - fclose(fh); -} - void Smesh::make_fnormals() { fnormals.clear(); @@ -476,41 +314,18 @@ void Smesh::make_fnormals() for (E_Int fid = 0; fid < nf; fid++) { const auto &pn = F[fid]; - - E_Float o[3] = {0, 0, 0}; - for (E_Int p : pn) { - o[0] += X[p]; - o[1] += Y[p]; - o[2] += Z[p]; - } - for (int i = 0; i < 3; i++) o[i] /= pn.size(); - - E_Int a = pn[0]; - E_Int b = pn[1]; - - E_Float oa[3] = {X[a]-o[0], Y[a]-o[1], Z[a]-o[2]}; - E_Float ob[3] = {X[b]-o[0], Y[b]-o[1], Z[b]-o[2]}; - + E_Int a = pn[0], b = pn[1], c = pn[2]; + E_Float v0[3] = {X[b]-X[a], Y[b]-Y[a], Z[b]-Z[a]}; + E_Float v1[3] = {X[c]-X[a], Y[c]-Y[a], Z[c]-Z[a]}; E_Float *N = &fnormals[3*fid]; - K_MATH::cross(oa, ob, N); + K_MATH::cross(v0, v1, N); E_Float NORM = K_MATH::norm(N, 3); - //assert(Sign(NORM) != 0); for (E_Int i = 0; i < 3; i++) N[i] /= NORM; } } void Smesh::make_pnormals() { - if (fnormals.empty()) { - fprintf(stderr, "Trying to compute pnormals without fnormals!\n"); - assert(0); - } - - if (P2F.empty()) { - fprintf(stderr, "Trying to compute pnormals without P2F!\n"); - assert(0); - } - pnormals.clear(); pnormals.resize(3*np, 0); @@ -641,69 +456,3 @@ void Smesh::compute_min_distance_between_points() assert(ndists == np*(np-1)/2); } -void Smesh::write_edges(const char *fname, const std::set &eids) const -{ - FILE *fh = fopen(fname, "w"); - assert(fh); - - fprintf(fh, "POINTS\n"); - fprintf(fh, "%lu\n", eids.size()*2); - for (E_Int eid : eids) { - const auto &e = E[eid]; - E_Int p = e.p; - E_Int q = e.q; - fprintf(fh, "%f %f %f\n", X[p], Y[p], Z[p]); - fprintf(fh, "%f %f %f\n", X[q], Y[q], Z[q]); - } - fprintf(fh, "EDGES\n"); - fprintf(fh, "%lu\n", eids.size()); - for (size_t i = 0; i < 2*eids.size(); i++) { - fprintf(fh, "%lu ", i); - } - fprintf(fh, "\n"); - - fclose(fh); -} - -void Smesh::write_points(const char *fname, const std::vector &pids) const -{ - FILE *fh= fopen(fname, "w"); - assert(fh); - - fprintf(fh, "POINTS\n"); - fprintf(fh, "%lu\n", pids.size()); - for (E_Int pid : pids){ - fprintf(fh, "%f %f %f\n", X[pid], Y[pid], Z[pid]); - } - - fclose(fh); -} - -void Smesh::write_points(const char *fname, const std::set &pids) const -{ - FILE *fh= fopen(fname, "w"); - assert(fh); - - fprintf(fh, "POINTS\n"); - fprintf(fh, "%lu\n", pids.size()); - for (E_Int pid : pids){ - fprintf(fh, "%f %f %f\n", X[pid], Y[pid], Z[pid]); - } - - fclose(fh); -} - -Smesh Smesh::extract_smesh(const std::set &fids, bool is_planar) -{ - return Smesh(); -} - -void Smesh::refine(const std::map> &sensor) -{ - size_t nref = sensor.size(); - - while (nref > 0) { - resize_for_refinement(nref); - nref = 0; - } -} diff --git a/Cassiopee/XCore/XCore/intersectMesh/smesh.h b/Cassiopee/XCore/XCore/intersectMesh/smesh.h index 331039a39..b7fc7004b 100644 --- a/Cassiopee/XCore/XCore/intersectMesh/smesh.h +++ b/Cassiopee/XCore/XCore/intersectMesh/smesh.h @@ -22,11 +22,9 @@ #include #include #include -#include -#include "point.h" #include "xcore.h" -#include "AABB.h" +#include "point.h" struct IMesh; @@ -50,111 +48,92 @@ struct u_edge { }; struct Smesh { - E_Int np, ne, nf; + // Connectivity + + E_Int np, ne, nf; std::vector X, Y, Z; std::vector> P2F; std::vector> P2E; - std::vector E; std::vector> E2F; - std::vector> F; std::vector> F2E; std::vector> F2F; - std::map g2lp; std::map l2gp; - std::map g2lf; std::map l2gf; + // Constructors + + Smesh(); + Smesh(const IMesh &M, bool is_planar=true); + Smesh(const IMesh &M, const std::vector &faces); + void make_edges(bool is_planar); + + // Geometry + std::vector fnormals; std::vector pnormals; + E_Float min_pdist_squared = EFLOATMIN; + E_Float NEAR_VERTEX_TOL = 1e-3; + E_Float NEAR_EDGE_TOL = 1e-3; + + void make_fnormals(); + void make_pnormals(); + void make_point_faces(); + void make_point_edges(); + std::vector locate(const Smesh &Sf) const; + void correct_near_points_and_edges(Smesh &Sf, std::vector &plocs); + void get_unit_projected_direction(E_Int fid, const E_Float D[3], + E_Float proj[3]) const; + void compute_min_distance_between_points(); + + // Hash E_Int NX, NY, NZ, NXY, NXYZ; E_Float xmin, xmax, ymin, ymax, zmin, zmax; E_Float HX, HY, HZ; - std::vector> bin_faces; + + void make_bbox(); + void hash_faces(); + inline E_Int get_voxel(E_Int i, E_Int j, E_Int k) const + { + return i + NX*j + NXY*k; + } - E_Float min_pdist_squared = EFLOATMIN; - - E_Float NEAR_VERTEX_TOL = 1e-3; - E_Float NEAR_EDGE_TOL = 1e-3; + // Adaptation std::map ecenter; - - Smesh(); - + std::map>> fchildren; + void resize_for_refinement(size_t nref_faces); - void refine(const std::map> &sensor); + void get_leaves(E_Int face, std::vector &leaves) const; + void refine_tri(E_Int fid); + void refine_edge(const u_edge &e); + + // Topology std::set extract_bounding_faces(const Smesh &Sf, const std::vector &plocs) const; - - void correct_near_points_and_edges(Smesh &Sf, std::vector &plocs); - E_Int deduce_face(const std::vector &pf, E_Float ox, E_Float oy, E_Float oz, E_Float D[3], E_Int last_vertex, E_Int last_edge) const; - - void get_unit_projected_direction(E_Int fid, const E_Float D[3], - E_Float proj[3]) const; - void get_shared_faces(const PointLoc &loc, std::vector &ret, E_Int &pid, E_Int &eid) const; - - void make_fnormals(); - void make_pnormals(); - - void make_bbox(); - void hash_faces(); - - void compute_min_distance_between_points(); - - void get_leaves(E_Int face, std::vector &leaves) const; - - std::map>> fchildren; - Smesh extract_smesh(const std::set &fids, bool is_planar=true); + Smesh extract_conformized(); - Smesh(const IMesh &M, bool is_planar=true); - - Smesh(const IMesh &M, const std::vector &faces); - - void make_edges(bool is_planar); - - void make_point_faces(); - - void make_point_edges(); - - std::vector locate(const Smesh &Sf) const; + // IO void write_points(const char *fname, const std::set &pset) const; - void write_points(const char *fname, const std::vector &pids) const; - void write_edges(const char *fname, const std::set &eids) const; - void write_ngon(const char *fname, const std::set &fset) const; - void write_ngon(const char *fname, const std::vector &faces) const; - - void write_ngon(const char *fname); - - void refine_faces(const std::vector &ref_faces); - - void refine_tri(E_Int fid); - - void refine_edge(const u_edge &e); - - Smesh extract_conformized(); - - inline E_Int get_voxel(E_Int i, E_Int j, E_Int k) const - { - return i + NX*j + NXY*k; - } + void write_ngon(const char *fname) const; }; diff --git a/Cassiopee/XCore/XCore/intersectMesh/smesh_extract.cpp b/Cassiopee/XCore/XCore/intersectMesh/smesh_extract.cpp new file mode 100644 index 000000000..dceb1a61c --- /dev/null +++ b/Cassiopee/XCore/XCore/intersectMesh/smesh_extract.cpp @@ -0,0 +1,14 @@ +#include "smesh.h" + +Smesh Smesh::extract_smesh(const std::set &fids, bool is_planar) +{ + assert(0); + return Smesh(); +} + +Smesh Smesh::extract_conformized() +{ + assert(0); + return Smesh(); +} + diff --git a/Cassiopee/XCore/XCore/intersectMesh/smesh_io.cpp b/Cassiopee/XCore/XCore/intersectMesh/smesh_io.cpp new file mode 100644 index 000000000..ccd7a9239 --- /dev/null +++ b/Cassiopee/XCore/XCore/intersectMesh/smesh_io.cpp @@ -0,0 +1,208 @@ +#include "smesh.h" + +void Smesh::write_edges(const char *fname, const std::set &eids) const +{ + FILE *fh = fopen(fname, "w"); + assert(fh); + + fprintf(fh, "POINTS\n"); + fprintf(fh, "%lu\n", eids.size()*2); + for (E_Int eid : eids) { + const auto &e = E[eid]; + E_Int p = e.p; + E_Int q = e.q; + fprintf(fh, "%f %f %f\n", X[p], Y[p], Z[p]); + fprintf(fh, "%f %f %f\n", X[q], Y[q], Z[q]); + } + fprintf(fh, "EDGES\n"); + fprintf(fh, "%lu\n", eids.size()); + for (size_t i = 0; i < 2*eids.size(); i++) { + fprintf(fh, "%lu ", i); + } + fprintf(fh, "\n"); + + fclose(fh); +} + +void Smesh::write_points(const char *fname, const std::vector &pids) const +{ + FILE *fh= fopen(fname, "w"); + assert(fh); + + fprintf(fh, "POINTS\n"); + fprintf(fh, "%lu\n", pids.size()); + for (E_Int pid : pids){ + fprintf(fh, "%f %f %f\n", X[pid], Y[pid], Z[pid]); + } + + fclose(fh); +} + +void Smesh::write_points(const char *fname, const std::set &pids) const +{ + FILE *fh= fopen(fname, "w"); + assert(fh); + + fprintf(fh, "POINTS\n"); + fprintf(fh, "%lu\n", pids.size()); + for (E_Int pid : pids){ + fprintf(fh, "%f %f %f\n", X[pid], Y[pid], Z[pid]); + } + + fclose(fh); +} + +void Smesh::write_ngon(const char *fname, const std::set &fset) const +{ + std::vector flist; + flist.reserve(fset.size()); + for (E_Int fid : fset) flist.push_back(fid); + write_ngon(fname, flist); +} + +void Smesh::write_ngon(const char *fname, const std::vector &faces) const +{ + std::vector INDPH(faces.size() + 1); + INDPH[0] = 0; + + std::map new_pids; + std::map new_eids; + E_Int idx = 0; + E_Int NP = 0; + E_Int NE = 0; + E_Int NF = (E_Int)faces.size(); + + for (E_Int fid : faces) { + const auto &pn = F[fid]; + const auto &pe = F2E[fid]; + + INDPH[idx+1] = INDPH[idx] + (E_Int)pn.size(); + idx++; + + for (E_Int pid : pn) { + if (new_pids.find(pid) == new_pids.end()) { + new_pids[pid] = NP; + NP++; + } + } + + for (E_Int eid : pe) { + if (new_eids.find(eid) == new_eids.end()) { + new_eids[eid] = NE; + NE++; + } + } + } + + FILE *fh = fopen(fname, "w"); + assert(fh); + fprintf(fh, "POINTS\n"); + fprintf(fh, "%lu\n", new_pids.size()); + + std::vector nX(NP), nY(NP), nZ(NP); + for (const auto &pids : new_pids) { + E_Int opid = pids.first; + E_Int npid = pids.second; + nX[npid] = X[opid]; + nY[npid] = Y[opid]; + nZ[npid] = Z[opid]; + } + + for (size_t pid = 0; pid < NP; pid++) { + fprintf(fh, "%f %f %f\n", nX[pid], nY[pid], nZ[pid]); + } + + fprintf(fh, "INDPG\n"); + fprintf(fh, "%lu\n", new_eids.size()+1); + E_Int sizeNGon = -2; + for (size_t i = 0; i < new_eids.size() + 1; i++) { + sizeNGon += 2; + fprintf(fh, "%d ", sizeNGon); + } + fprintf(fh, "\n"); + assert(sizeNGon == 2*NE); + + std::vector nE(new_eids.size(), {-1, -1}); + for (const auto &eids : new_eids) { + E_Int oeid = eids.first; + E_Int neid = eids.second; + nE[neid].p = new_pids[E[oeid].p]; + nE[neid].q = new_pids[E[oeid].q]; + } + + fprintf(fh, "NGON\n"); + fprintf(fh, "%d\n", 2*NE); + for (const auto &e : nE) { + fprintf(fh, "%d %d ", e.p, e.q); + } + fprintf(fh, "\n"); + + fprintf(fh, "INDPH\n"); + fprintf(fh, "%d\n", NF+1); + for (E_Int i = 0; i < NF+1; i++) + fprintf(fh, "%d ", INDPH[i]); + fprintf(fh, "\n"); + + fprintf(fh, "NFACE\n"); + fprintf(fh, "%d\n", INDPH[NF]); + for (size_t i = 0; i < faces.size(); i++) { + const auto &pe = F2E[faces[i]]; + for (E_Int eid : pe) { + fprintf(fh, "%d ", new_eids[eid]); + } + } + fprintf(fh, "\n"); + + fclose(fh); +} + +void Smesh::write_ngon(const char *fname) const +{ + FILE *fh = fopen(fname, "w"); + assert(fh); + + fprintf(fh, "POINTS\n"); + fprintf(fh, SF_D_ "\n", np); + for (E_Int i = 0; i < np; i++) { + fprintf(fh, "%f %f %f\n", X[i], Y[i], Z[i]); + } + + fprintf(fh, "INDPG\n"); + fprintf(fh, SF_D_ "\n", ne+1); + size_t sizeNGon = 0; + fprintf(fh, "0 "); + for (E_Int i = 0; i < ne; i++) { + sizeNGon += 2; + fprintf(fh, "%zu ", sizeNGon); + } + fprintf(fh, "\n"); + + fprintf(fh, "NGON\n"); + fprintf(fh, "%zu\n", sizeNGon); + for (E_Int i = 0; i < ne; i++) { + fprintf(fh, SF_D_ " " SF_D_ " ", E[i].p, E[i].q); + } + fprintf(fh, "\n"); + + fprintf(fh, "INDPH\n"); + fprintf(fh, SF_D_ "\n", nf+1); + size_t sizeNFace = 0; + fprintf(fh, "0 "); + for (E_Int i = 0; i < nf; i++) { + sizeNFace += F2E[i].size(); + fprintf(fh, "%zu ", sizeNFace); + } + fprintf(fh, "\n"); + + fprintf(fh, "NFACE\n"); + fprintf(fh, "%zu\n", sizeNFace); + for (E_Int i = 0; i < nf; i++) { + for (E_Int e : F2E[i]) fprintf(fh, SF_D_ " ", e); + } + fprintf(fh, "\n"); + + fclose(fh); +} + + + diff --git a/Cassiopee/XCore/XCore/intersectMesh/smeshRefine.cpp b/Cassiopee/XCore/XCore/intersectMesh/smesh_refine.cpp similarity index 90% rename from Cassiopee/XCore/XCore/intersectMesh/smeshRefine.cpp rename to Cassiopee/XCore/XCore/intersectMesh/smesh_refine.cpp index e1f1304c7..77df08246 100644 --- a/Cassiopee/XCore/XCore/intersectMesh/smeshRefine.cpp +++ b/Cassiopee/XCore/XCore/intersectMesh/smesh_refine.cpp @@ -16,8 +16,6 @@ You should have received a copy of the GNU General Public License along with Cassiopee. If not, see . */ -#include - #include "smesh.h" void Smesh::refine_edge(const u_edge &e) @@ -70,6 +68,16 @@ void Smesh::resize_for_refinement(size_t nref_faces) Z.resize(np + pincr); } +void Smesh::refine(const std::map> &sensor) +{ + size_t nref = sensor.size(); + + while (nref > 0) { + resize_for_refinement(nref); + nref = 0; + } +} + void Smesh::get_leaves(E_Int fid, std::vector &leaves) const { } diff --git a/Cassiopee/XCore/srcs.py b/Cassiopee/XCore/srcs.py index effdfead2..c4c0dac0a 100644 --- a/Cassiopee/XCore/srcs.py +++ b/Cassiopee/XCore/srcs.py @@ -25,6 +25,11 @@ 'XCore/intersectMesh/triangulate.cpp', 'XCore/intersectMesh/locate.cpp', 'XCore/intersectMesh/sgraph.cpp', + + 'XCore/intersectMesh/smesh.cpp', + 'XCore/intersectMesh/smesh_io.cpp', + 'XCore/intersectMesh/smesh_refine.cpp', + 'XCore/intersectMesh/smesh_extract.cpp', 'XCore/intersectMesh/BVH.cpp', 'XCore/intersectMesh/AABB.cpp', @@ -57,8 +62,6 @@ 'XCore/intersectMesh/mesh.cpp', 'XCore/intersectMesh/meshRefine.cpp', 'XCore/intersectMesh/meshTopo.cpp', - 'XCore/intersectMesh/smesh.cpp', - 'XCore/intersectMesh/smeshRefine.cpp', 'XCore/intersectMesh/io.cpp', 'XCore/intersectMesh/primitives.cpp', 'XCore/intersectMesh/vec3.cpp', From 9bcd1137cf2982653187fc709406ac5e4b686953 Mon Sep 17 00:00:00 2001 From: imadhammani Date: Sun, 13 Oct 2024 19:00:10 +0200 Subject: [PATCH 58/86] XCore intersectMesh: deleted mistake file --- Cassiopee/XCore/XCore/intersectMesh/file | 0 1 file changed, 0 insertions(+), 0 deletions(-) delete mode 100644 Cassiopee/XCore/XCore/intersectMesh/file diff --git a/Cassiopee/XCore/XCore/intersectMesh/file b/Cassiopee/XCore/XCore/intersectMesh/file deleted file mode 100644 index e69de29bb..000000000 From abda82d4d9354e9c660e7fd9f7f6dbc5d7e19f81 Mon Sep 17 00:00:00 2001 From: imadhammani Date: Mon, 14 Oct 2024 13:31:42 +0200 Subject: [PATCH 59/86] XCore intersectMesh: project fwall points onto spatches --- Cassiopee/XCore/XCore/intersectMesh/AABB.cpp | 34 +---- Cassiopee/XCore/XCore/intersectMesh/AABB.h | 9 +- Cassiopee/XCore/XCore/intersectMesh/BVH.cpp | 107 --------------- Cassiopee/XCore/XCore/intersectMesh/BVH.h | 31 +---- .../XCore/XCore/intersectMesh/icapsule.cpp | 10 +- .../XCore/XCore/intersectMesh/icapsule.h | 3 + .../XCore/intersectMesh/icapsule_refine.cpp | 102 ++++++++++++++ Cassiopee/XCore/XCore/intersectMesh/point.h | 6 +- Cassiopee/XCore/XCore/intersectMesh/ray.cpp | 125 ++++++++++++++++++ Cassiopee/XCore/XCore/intersectMesh/ray.h | 14 ++ Cassiopee/XCore/XCore/intersectMesh/smesh.cpp | 16 +++ Cassiopee/XCore/XCore/intersectMesh/smesh.h | 17 +++ .../XCore/XCore/intersectMesh/smesh_bvh.cpp | 89 +++++++++++++ Cassiopee/XCore/srcs.py | 4 +- 14 files changed, 397 insertions(+), 170 deletions(-) delete mode 100644 Cassiopee/XCore/XCore/intersectMesh/BVH.cpp create mode 100644 Cassiopee/XCore/XCore/intersectMesh/icapsule_refine.cpp create mode 100644 Cassiopee/XCore/XCore/intersectMesh/smesh_bvh.cpp diff --git a/Cassiopee/XCore/XCore/intersectMesh/AABB.cpp b/Cassiopee/XCore/XCore/intersectMesh/AABB.cpp index 89bc83981..c6398e50a 100644 --- a/Cassiopee/XCore/XCore/intersectMesh/AABB.cpp +++ b/Cassiopee/XCore/XCore/intersectMesh/AABB.cpp @@ -1,31 +1,11 @@ #include "AABB.h" -#include "mesh.h" -AABB::AABB() -: xmin(EFLOATMAX), ymin(EFLOATMAX), zmin(EFLOATMAX), - xmax(EFLOATMIN), ymax(EFLOATMIN), zmax(EFLOATMIN) -{} - -AABB::AABB(const IMesh &M, E_Int *ids, E_Int count) +void AABB_clamp(AABB &box, const AABB &parent) { - xmin = ymin = zmin = EFLOATMAX; - xmax = ymax = zmax = EFLOATMIN; - - for (E_Int i = 0; i < count; i++) { - E_Int fid = ids[i]; - - const auto &pn = M.F[fid]; - - for (E_Int p : pn) { - E_Float x = M.X[p]; - E_Float y = M.Y[p]; - E_Float z = M.Z[p]; - if (x < xmin) xmin = x; - if (y < ymin) ymin = y; - if (z < zmin) zmin = z; - if (x > xmax) xmax = x; - if (y > ymax) ymax = y; - if (z > zmax) zmax = z; - } - } + box.xmin = std::max(parent.xmin, box.xmin); + box.ymin = std::max(parent.ymin, box.ymin); + box.zmin = std::max(parent.zmin, box.zmin); + box.xmax = std::min(parent.xmax, box.xmax); + box.ymax = std::min(parent.ymax, box.ymax); + box.zmax = std::min(parent.zmax, box.zmax); } \ No newline at end of file diff --git a/Cassiopee/XCore/XCore/intersectMesh/AABB.h b/Cassiopee/XCore/XCore/intersectMesh/AABB.h index a07c133d0..b34155205 100644 --- a/Cassiopee/XCore/XCore/intersectMesh/AABB.h +++ b/Cassiopee/XCore/XCore/intersectMesh/AABB.h @@ -2,8 +2,6 @@ #include "xcore.h" -struct IMesh; - struct AABB { E_Float xmin; E_Float ymin; @@ -11,8 +9,9 @@ struct AABB { E_Float xmax; E_Float ymax; E_Float zmax; +}; - AABB(); +const AABB AABB_HUGE = {EFLOATMIN, EFLOATMIN, EFLOATMIN, + EFLOATMAX, EFLOATMAX, EFLOATMAX}; - AABB(const IMesh &M, E_Int *ids, E_Int count); -}; \ No newline at end of file +void AABB_clamp(AABB &box, const AABB &parent); \ No newline at end of file diff --git a/Cassiopee/XCore/XCore/intersectMesh/BVH.cpp b/Cassiopee/XCore/XCore/intersectMesh/BVH.cpp deleted file mode 100644 index 56dd3b545..000000000 --- a/Cassiopee/XCore/XCore/intersectMesh/BVH.cpp +++ /dev/null @@ -1,107 +0,0 @@ -#include "BVH.h" -#include "mesh.h" - -// Creates the tree - -static size_t leaf_count = 0; - -BVH_node *BVH_create_node(AABB aabb, BVH_node *left_child, BVH_node *right_child, - E_Int *ids, E_Int count, Mem_arena &arena) -{ - BVH_node *node = (BVH_node *)ARENA_ALLOC(sizeof(BVH_node)); - - node->bbox = aabb; - node->left = left_child; - node->right = right_child; - node->elements = (E_Int *)ARENA_ALLOC(count * sizeof(E_Int)); - assert(count > 0); - memcpy(node->elements, ids, count * sizeof(E_Int)); - - leaf_count++; - - return node; -} - - -BVH_node *BVH_create_node(AABB aabb, BVH_node *left_child, - BVH_node *right_child, Mem_arena &arena) -{ - BVH_node *node = (BVH_node *)ARENA_ALLOC(sizeof(BVH_node)); - - node->bbox = aabb; - node->left = left_child; - node->right = right_child; - node->elements = NULL; - - return node; -} - -BVH_node *BVH_create_node(E_Int *ids, E_Int count, const IMesh &M, - Mem_arena &arena) -{ - AABB aabb(M, ids, count); - - if (count <= MAX_FACES_PER_LEAF) { - return BVH_create_node(aabb, NULL, NULL, ids, count, arena); - } - - E_Float dx = aabb.xmax - aabb.xmin; - E_Float dy = aabb.ymax - aabb.ymin; - E_Float dz = aabb.zmax - aabb.zmin; - - E_Float *pCoor; - - if (dx >= dy && dx >= dz) { - pCoor = (E_Float *)M.X.data(); - } else if (dy >= dz) { - assert(dy >= dx); - pCoor = (E_Float *)M.Y.data(); - } else { - assert(dz >= dx && dz >= dy); - pCoor = (E_Float *)M.Z.data(); - } - - std::sort(ids, ids + count, [&] (E_Int i, E_Int j) - { - E_Float cci = 0.0, ccj = 0.0; - - const auto &pni = M.F[i]; - for (const E_Int p : pni) cci += pCoor[p]; - cci /= pni.size(); - - const auto &pnj = M.F[j]; - for (const E_Int p : pnj) ccj += pCoor[p]; - ccj /= pnj.size(); - - return cci < ccj; - }); - - BVH_node *left = BVH_create_node(ids, count/2, M, arena); - BVH_node *right = BVH_create_node(ids + count/2, count - count/2, M, arena); - - return BVH_create_node(aabb, left, right, arena); -} - -BVH::BVH(const IMesh &M) -{ - if (M.skin.empty()) { - puts("empty skin!"); - exit(1); - } - - size_t NF = M.skin.size(); - - printf("Number of faces: %zu\n", NF); - - arena.reserve(10 * NF * sizeof(E_Int)); - - E_Int *ids = (E_Int *)ARENA_ALLOC(NF * sizeof(E_Int)); - - for (size_t i = 0; i < NF; i++) ids[i] = M.skin[i]; - - root = BVH_create_node(ids, NF, M, arena); - - printf("Leaves: %zu\n", leaf_count); - - arena.print_stats(); -} \ No newline at end of file diff --git a/Cassiopee/XCore/XCore/intersectMesh/BVH.h b/Cassiopee/XCore/XCore/intersectMesh/BVH.h index ddcd60023..458bea6d7 100644 --- a/Cassiopee/XCore/XCore/intersectMesh/BVH.h +++ b/Cassiopee/XCore/XCore/intersectMesh/BVH.h @@ -1,32 +1,11 @@ #pragma once #include "AABB.h" -#include "common/mem.h" - -#define MAX_FACES_PER_LEAF 10 - -struct IMesh; struct BVH_node { - AABB bbox; - BVH_node *left; - BVH_node *right; - E_Int *elements; -}; - -BVH_node *BVH_create_node(AABB aabb, BVH_node *left_child, - BVH_node *right_child, Mem_arena &arena); - -BVH_node *BVH_create_node(AABB aabb, BVH_node *left_child, BVH_node *right_child, - E_Int *ids, E_Int count, Mem_arena &arena); - -BVH_node *BVH_create_node(E_Int *ids, E_Int count, const IMesh &M, - Mem_arena &arena); - -struct BVH { - BVH_node *root; - - Mem_arena arena; - - BVH(const IMesh &M); + AABB box = AABB_HUGE; + E_Int start = -1; + E_Int end = -1; + BVH_node *left = NULL; + BVH_node *right = NULL; }; \ No newline at end of file diff --git a/Cassiopee/XCore/XCore/intersectMesh/icapsule.cpp b/Cassiopee/XCore/XCore/intersectMesh/icapsule.cpp index b588fc32a..ecb389234 100644 --- a/Cassiopee/XCore/XCore/intersectMesh/icapsule.cpp +++ b/Cassiopee/XCore/XCore/intersectMesh/icapsule.cpp @@ -381,16 +381,20 @@ ICapsule::ICapsule(const Karray &marray, const std::vector &sarrays, Ss[i].orient_skin(IN); Ss[i].triangulate_skin(); spatches.push_back(Ss[i].make_smesh(ptags[i])); - spatches[i].make_bbox(); - spatches[i].hash_faces(); + spatches[i].make_fcenters(); spatches[i].make_fnormals(); spatches[i].make_point_faces(); spatches[i].make_pnormals(); spatches[i].compute_min_distance_between_points(); plocs_list.push_back(Mf.locate(spatches[i])); Mf.correct_near_points_and_edges(spatches[i], plocs_list[i]); + bfaces_list.push_back( Mf.extract_bounding_faces(spatches[i], plocs_list[i])); + + spatches[i].make_bbox(); + spatches[i].hash_faces(); + refine(Mf, bfaces_list[i], spatches[i], plocs_list[i]); } Mf.write_edges("ewalls", ewalls); @@ -434,7 +438,7 @@ ICapsule::ICapsule(const Karray &marray, const std::vector &sarrays, Mf.write_ngon("ref_faces", ref_faces); - Mf.refine(mfid_to_spids); + //Mf.refine(mfid_to_spids); } diff --git a/Cassiopee/XCore/XCore/intersectMesh/icapsule.h b/Cassiopee/XCore/XCore/intersectMesh/icapsule.h index 73b8bf328..1d4bc369c 100644 --- a/Cassiopee/XCore/XCore/intersectMesh/icapsule.h +++ b/Cassiopee/XCore/XCore/intersectMesh/icapsule.h @@ -13,4 +13,7 @@ struct ICapsule { ICapsule(const Karray &marray, const std::vector &sarray, const std::vector &ptags); + + void refine(Smesh &Mf, const std::set &mfids, Smesh &Sf, + std::vector &plocs_s); }; diff --git a/Cassiopee/XCore/XCore/intersectMesh/icapsule_refine.cpp b/Cassiopee/XCore/XCore/intersectMesh/icapsule_refine.cpp new file mode 100644 index 000000000..9a9f41f59 --- /dev/null +++ b/Cassiopee/XCore/XCore/intersectMesh/icapsule_refine.cpp @@ -0,0 +1,102 @@ +#include "icapsule.h" +#include "ray.h" +#include "BVH.h" +#include "io.h" + +// Returns a list of all the intersections, forwards and backwards +// Up to the caller to parse the data +void Smesh::ray_BVH_intersect(E_Float ox, E_Float oy, E_Float oz, + E_Float dx, E_Float dy, E_Float dz, BVH_node *node, + std::vector &plocs) +{ + bool hit = ray_AABB_intersect(ox, oy, oz, dx, dy, dz, node->box); + if (!hit) return; + + if (!node->left && !node->right) { + for (E_Int i = node->start; i < node->end; i++) { + E_Int fid = bvh_indices[i]; + const auto &pn = F[fid]; + E_Int a = pn[0], b = pn[1], c = pn[2]; + E_Float u, v, w, t, x, y, z; + bool hit = MollerTrumboreAnyDir(ox, oy, oz, dx, dy, dz, + X[a], Y[a], Z[a], X[b], Y[b], Z[b], X[c], Y[c], Z[c], + u, v, w, t, x, y, z); + if (hit) { + PointLoc ploc; + ploc.fid = fid; + ploc.bcrd[0] = u; + ploc.bcrd[1] = v; + ploc.bcrd[2] = w; + ploc.t = t; + ploc.x = x; + ploc.y = y; + ploc.z = z; + plocs.push_back(ploc); + } + } + return; + } + + ray_BVH_intersect(ox, oy, oz, dx, dy, dz, node->left, plocs); + ray_BVH_intersect(ox, oy, oz, dx, dy, dz, node->right, plocs); +} + +std::vector projections; + +void Smesh::project(const Smesh &Mf, const std::vector &mpids, + std::vector &plocs) +{ + for (size_t i = 0; i < mpids.size(); i++) { + E_Int mpid = mpids[i]; + const E_Float *N = &Mf.pnormals[3*mpid]; + E_Float mx = Mf.X[mpid]; + E_Float my = Mf.Y[mpid]; + E_Float mz = Mf.Z[mpid]; + std::vector mlocs; // to parse + ray_BVH_intersect(mx, my, mz, N[0], N[1], N[2], bvh_root, mlocs); + auto &ploc = plocs[i]; + E_Float min_abs_t = EFLOATMAX; + for (const auto &mloc : mlocs) { + if (fabs(mloc.t) < EFLOATMAX) { + min_abs_t = mloc.t; + ploc.fid = mloc.fid; + ploc.t = mloc.t; + ploc.x = mloc.x; + ploc.y = mloc.y; + ploc.z = mloc.z; + } + } + if (ploc.fid != -1) { + projections.push_back({ploc.x, ploc.y, ploc.z}); + } + } +} + +void ICapsule::refine(Smesh &Mf, const std::set &mfids, Smesh &Sf, + std::vector &plocs_s) +{ + E_Int ref_M, ref_S; + do { + // Construct the BVH of Sf + Sf.make_BVH(); + + // Isolate the points to project + std::set mpids_set; + for (E_Int fid : mfids) { + const auto &pn = Mf.F[fid]; + for (E_Int p : pn) mpids_set.insert(p); + } + std::vector mpids; + for (E_Int p : mpids_set) mpids.push_back(p); + std::vector plocs_m(mpids.size()); + + // Project mpids on Sf + Sf.project(Mf, mpids, plocs_m); + + ref_M = 0; + ref_S = 0; + + } while (ref_M > 0 || ref_S > 0); + + point_write("projections", projections); +} \ No newline at end of file diff --git a/Cassiopee/XCore/XCore/intersectMesh/point.h b/Cassiopee/XCore/XCore/intersectMesh/point.h index b921e73ac..06fbb6479 100644 --- a/Cassiopee/XCore/XCore/intersectMesh/point.h +++ b/Cassiopee/XCore/XCore/intersectMesh/point.h @@ -26,7 +26,11 @@ struct PointLoc { E_Int fid = -1; E_Int v_idx = -1; E_Int e_idx = -1; - E_Float bcrd[3] = {-1, -1, -1}; + E_Float bcrd[3] = {EFLOATMAX, EFLOATMAX, EFLOATMAX}; + E_Float t = EFLOATMAX; + E_Float x = EFLOATMAX; + E_Float y = EFLOATMAX; + E_Float z = EFLOATMAX; }; struct PointData { diff --git a/Cassiopee/XCore/XCore/intersectMesh/ray.cpp b/Cassiopee/XCore/XCore/intersectMesh/ray.cpp index 29966d557..a48a72191 100644 --- a/Cassiopee/XCore/XCore/intersectMesh/ray.cpp +++ b/Cassiopee/XCore/XCore/intersectMesh/ray.cpp @@ -18,6 +18,131 @@ */ #include "ray.h" #include "primitives.h" +#include "AABB.h" + +bool ray_AABB_intersect(E_Float ox, E_Float oy, E_Float oz, + E_Float dx, E_Float dy, E_Float dz, + const AABB &box) +{ + E_Float inv_dx = (dx != 0.0) ? 1.0/dx : EFLOATMAX; + E_Float inv_dy = (dy != 0.0) ? 1.0/dy : EFLOATMAX; + E_Float inv_dz = (dz != 0.0) ? 1.0/dz : EFLOATMAX; + + E_Float t_min = EFLOATMIN; + E_Float t_max = EFLOATMAX; + + // X + if (dx == 0.0) { + if (ox < box.xmin || ox > box.xmax) { + return false; + } + } else { + E_Float t1 = (box.xmin - ox) * inv_dx; + E_Float t2 = (box.xmax - ox) * inv_dx; + + if (t1 > t2) std::swap(t1, t2); + + t_min = std::max(t_min, t1); + t_max = std::max(t_max, t2); + + if (t_min > t_max) + return false; + } + + // Y + if (dy == 0.0) { + if (oy < box.ymin || oy > box.ymax) { + return false; + } + } else { + E_Float t1 = (box.ymin - oy) * inv_dy; + E_Float t2 = (box.ymax - oy) * inv_dy; + + if (t1 > t2) std::swap(t1, t2); + + t_min = std::max(t_min, t1); + t_max = std::max(t_max, t2); + + if (t_min > t_max) + return false; + } + + // Z + if (dz == 0.0) { + if (oz < box.zmin || oz > box.zmax) { + return false; + } + } else { + E_Float t1 = (box.zmin - oz) * inv_dz; + E_Float t2 = (box.zmax - oz) * inv_dz; + + if (t1 > t2) std::swap(t1, t2); + + t_min = std::max(t_min, t1); + t_max = std::max(t_max, t2); + + if (t_min > t_max) + return false; + } + + return true; +} + +bool MollerTrumboreAnyDir( + E_Float px, E_Float py, E_Float pz, + E_Float dx, E_Float dy, E_Float dz, + E_Float ax, E_Float ay, E_Float az, + E_Float bx, E_Float by, E_Float bz, + E_Float cx, E_Float cy, E_Float cz, + E_Float &u, E_Float &v, E_Float &w, E_Float &t, + E_Float &x, E_Float &y, E_Float &z) +{ + E_Float e1x = bx - ax; + E_Float e1y = by - ay; + E_Float e1z = bz - az; + + E_Float e2x = cx - ax; + E_Float e2y = cy - ay; + E_Float e2z = cz - az; + + E_Float pvecx = dy * e2z - dz * e2y; + E_Float pvecy = dz * e2x - dx * e2z; + E_Float pvecz = dx * e2y - dy * e2x; + + E_Float det = e1x * pvecx + e1y * pvecy + e1z * pvecz; + + if (det > -TOL && det < TOL) return false; + + E_Float inv_det = 1.0 / det; + + E_Float tvecx = px - ax; + E_Float tvecy = py - ay; + E_Float tvecz = pz - az; + + u = inv_det * (tvecx * pvecx + tvecy * pvecy + tvecz * pvecz); + + if (u < -TOL || u > 1+TOL) return false; + + E_Float qvecx = tvecy * e1z - tvecz * e1y; + E_Float qvecy = tvecz * e1x - tvecx * e1z; + E_Float qvecz = tvecx * e1y - tvecy * e1x; + + v = inv_det * (dx * qvecx + dy * qvecy + dz * qvecz); + + if (v < -TOL || v > 1+TOL) return false; + + w = 1 - u - v; + + if (w < -TOL || w > 1+TOL) return false; + + t = inv_det * (e2x * qvecx + e2y * qvecy + e2z * qvecz); + + x = px + t * dx; + y = py + t * dy; + z = pz + t * dz; + + return true; +} E_Int MollerTrumbore(E_Float px, E_Float py, E_Float pz, E_Float dx, E_Float dy, E_Float dz, E_Float ax, E_Float ay, E_Float az, E_Float bx, E_Float by, E_Float bz, diff --git a/Cassiopee/XCore/XCore/intersectMesh/ray.h b/Cassiopee/XCore/XCore/intersectMesh/ray.h index 7e7bf1ff7..59df8c2e9 100644 --- a/Cassiopee/XCore/XCore/intersectMesh/ray.h +++ b/Cassiopee/XCore/XCore/intersectMesh/ray.h @@ -21,6 +21,8 @@ #include "triangleIntersection.h" #include "point.h" +struct AABB; + struct Ray { Point org; Vec3 dir; @@ -33,7 +35,19 @@ struct Ray { TriangleIntersection &TI); }; +bool ray_AABB_intersect(E_Float ox, E_Float oy, E_Float oz, + E_Float dx, E_Float dy, E_Float dz, + const AABB &box); + E_Int MollerTrumbore(E_Float px, E_Float py, E_Float pz, E_Float dx, E_Float dy, E_Float dz, E_Float ax, E_Float ay, E_Float az, E_Float bx, E_Float by, E_Float bz, E_Float cx, E_Float cy, E_Float cz, TriangleIntersection &TI); +bool MollerTrumboreAnyDir( + E_Float px, E_Float py, E_Float pz, + E_Float dx, E_Float dy, E_Float dz, + E_Float ax, E_Float ay, E_Float az, + E_Float bx, E_Float by, E_Float bz, + E_Float cx, E_Float cy, E_Float cz, + E_Float &u, E_Float &v, E_Float &w, E_Float &t, + E_Float &x, E_Float &y, E_Float &z); diff --git a/Cassiopee/XCore/XCore/intersectMesh/smesh.cpp b/Cassiopee/XCore/XCore/intersectMesh/smesh.cpp index aa3511875..66e53028f 100644 --- a/Cassiopee/XCore/XCore/intersectMesh/smesh.cpp +++ b/Cassiopee/XCore/XCore/intersectMesh/smesh.cpp @@ -275,6 +275,22 @@ void Smesh::make_edges(bool is_planar) } } +void Smesh::make_fcenters() +{ + fcenters.clear(); + fcenters.resize(3*nf, 0); + for (E_Int fid = 0; fid < nf; fid++) { + E_Float *fc = &fcenters[3*fid]; + const auto &pn = F[fid]; + for (E_Int p : pn) { + fc[0] += X[p]; + fc[1] += Y[p]; + fc[2] += Z[p]; + } + for (E_Int i = 0; i < 3; i++) fc[i] /= pn.size(); + } +} + void Smesh::make_point_faces() { P2F.clear(); diff --git a/Cassiopee/XCore/XCore/intersectMesh/smesh.h b/Cassiopee/XCore/XCore/intersectMesh/smesh.h index b7fc7004b..bda9bbba4 100644 --- a/Cassiopee/XCore/XCore/intersectMesh/smesh.h +++ b/Cassiopee/XCore/XCore/intersectMesh/smesh.h @@ -27,6 +27,8 @@ #include "point.h" struct IMesh; +struct AABB; +struct BVH_node; struct o_edge { E_Int p, q; @@ -74,12 +76,14 @@ struct Smesh { // Geometry + std::vector fcenters; std::vector fnormals; std::vector pnormals; E_Float min_pdist_squared = EFLOATMIN; E_Float NEAR_VERTEX_TOL = 1e-3; E_Float NEAR_EDGE_TOL = 1e-3; + void make_fcenters(); void make_fnormals(); void make_pnormals(); void make_point_faces(); @@ -89,6 +93,11 @@ struct Smesh { void get_unit_projected_direction(E_Int fid, const E_Float D[3], E_Float proj[3]) const; void compute_min_distance_between_points(); + void project(const Smesh &Mf, const std::vector &mpids, + std::vector &plocs); + void ray_BVH_intersect(E_Float ox, E_Float oy, E_Float oz, + E_Float dx, E_Float dy, E_Float dz, BVH_node *node, + std::vector &plocs); // Hash @@ -96,6 +105,9 @@ struct Smesh { E_Float xmin, xmax, ymin, ymax, zmin, zmax; E_Float HX, HY, HZ; std::vector> bin_faces; + std::vector bvh_indices; + static const E_Int MAX_FACES_PER_BVH_LEAF = 8; + BVH_node *bvh_root = NULL; void make_bbox(); void hash_faces(); @@ -103,6 +115,11 @@ struct Smesh { { return i + NX*j + NXY*k; } + void make_BVH(); + AABB make_AABB(E_Int start, E_Int end); + BVH_node *make_BVH_node(const AABB &box, E_Int start, E_Int end, + BVH_node *left, BVH_node *right); + BVH_node *make_BVH_subtree(E_Int start, E_Int end, const AABB &parent); // Adaptation diff --git a/Cassiopee/XCore/XCore/intersectMesh/smesh_bvh.cpp b/Cassiopee/XCore/XCore/intersectMesh/smesh_bvh.cpp new file mode 100644 index 000000000..522f4c147 --- /dev/null +++ b/Cassiopee/XCore/XCore/intersectMesh/smesh_bvh.cpp @@ -0,0 +1,89 @@ +#include "smesh.h" +#include "AABB.h" +#include "BVH.h" + +AABB Smesh::make_AABB(E_Int start, E_Int end) +{ + E_Float xmin, ymin, zmin, xmax, ymax, zmax; + xmin = ymin = zmin = EFLOATMAX; + xmax = ymax = zmax = EFLOATMIN; + + for (E_Int i = start; i < end; i++) { + E_Int fid = bvh_indices[i]; + const auto &pn = F[fid]; + for (E_Int p : pn) { + if (X[p] < xmin) xmin = X[p]; + if (Y[p] < ymin) ymin = Y[p]; + if (Z[p] < zmin) zmin = Z[p]; + if (X[p] > xmax) xmax = X[p]; + if (Y[p] > ymax) ymax = Y[p]; + if (Z[p] > zmax) zmax = Z[p]; + } + } + + E_Float dx = (xmax - xmin) * 0.01; + E_Float dy = (ymax - ymin) * 0.01; + E_Float dz = (zmax - zmin) * 0.01; + + return {xmin, ymin, zmin, xmax, ymax, zmax}; +} + +BVH_node *Smesh::make_BVH_node(const AABB &box, E_Int start, E_Int end, + BVH_node *left, BVH_node *right) +{ + BVH_node *node = new BVH_node; + node->box = box; + node->start = start; + node->end = end; + node->left = left; + node->right = right; + return node; +} + +BVH_node *Smesh::make_BVH_subtree(E_Int start, E_Int end, const AABB &parent) +{ + AABB box = make_AABB(start, end); + AABB_clamp(box, parent); + + E_Int count = end - start; + if (count <= Smesh::MAX_FACES_PER_BVH_LEAF) { + return make_BVH_node(box, start, end, NULL, NULL); + } + + E_Float dx = box.xmax - box.xmin; + E_Float dy = box.ymax - box.ymin; + E_Float dz = box.zmax - box.zmin; + + E_Int dim = -1; + if (dx >= dy && dx >= dz) { + dim = 0; + } else if (dy >= dz) { + dim = 1; + } else { + dim = 2; + } + + std::sort(bvh_indices.begin() + start, bvh_indices.begin() + end, + [&] (E_Int i, E_Int j) { + E_Float *fci = &fcenters[3*i]; + E_Float *fcj = &fcenters[3*j]; + return fci[dim] < fcj[dim]; + } + ); + + E_Int mid = start + count/2; + + BVH_node *left = make_BVH_subtree(start, mid, box); + BVH_node *right = make_BVH_subtree(mid, end, box); + + return make_BVH_node(box, start, end, left, right); +} + +void Smesh::make_BVH() +{ + bvh_indices.clear(); + bvh_indices.reserve(nf); + for (E_Int i = 0; i < nf; i++) bvh_indices.push_back(i); + + bvh_root = make_BVH_subtree(0, nf, AABB_HUGE); +} \ No newline at end of file diff --git a/Cassiopee/XCore/srcs.py b/Cassiopee/XCore/srcs.py index c4c0dac0a..ea31b7739 100644 --- a/Cassiopee/XCore/srcs.py +++ b/Cassiopee/XCore/srcs.py @@ -22,6 +22,8 @@ 'XCore/common/Karray.cpp', 'XCore/intersectMesh/icapsule.cpp', + 'XCore/intersectMesh/icapsule_refine.cpp', + 'XCore/intersectMesh/triangulate.cpp', 'XCore/intersectMesh/locate.cpp', 'XCore/intersectMesh/sgraph.cpp', @@ -30,8 +32,8 @@ 'XCore/intersectMesh/smesh_io.cpp', 'XCore/intersectMesh/smesh_refine.cpp', 'XCore/intersectMesh/smesh_extract.cpp', + 'XCore/intersectMesh/smesh_bvh.cpp', - 'XCore/intersectMesh/BVH.cpp', 'XCore/intersectMesh/AABB.cpp', 'XCore/intersectMesh/extract.cpp', From 58cfc198549c26f6dabb34911e6b5960de1c8e10 Mon Sep 17 00:00:00 2001 From: imadhammani Date: Tue, 15 Oct 2024 17:08:54 +0200 Subject: [PATCH 60/86] XCore intersectMesh: correctly refined Mf (sequential) --- Cassiopee/XCore/XCore/intersectMesh/cut.cpp | 40 --- Cassiopee/XCore/XCore/intersectMesh/dcel.cpp | 268 +-------------- .../XCore/XCore/intersectMesh/icapsule.cpp | 202 +++++------- .../XCore/XCore/intersectMesh/icapsule.h | 2 +- .../XCore/intersectMesh/icapsule_refine.cpp | 117 ++++++- .../XCore/intersectMesh/intersectMesh.cpp | 4 +- .../XCore/XCore/intersectMesh/locate.cpp | 61 ---- Cassiopee/XCore/XCore/intersectMesh/mesh.h | 2 - Cassiopee/XCore/XCore/intersectMesh/point.h | 1 + .../removeIntersectingKPlanes.cpp | 3 - Cassiopee/XCore/XCore/intersectMesh/smesh.cpp | 304 ++++++++++-------- Cassiopee/XCore/XCore/intersectMesh/smesh.h | 44 ++- .../XCore/XCore/intersectMesh/smesh_bvh.cpp | 23 +- .../XCore/XCore/intersectMesh/smesh_io.cpp | 45 ++- .../XCore/intersectMesh/smesh_locate.cpp | 170 ++++++++++ .../XCore/intersectMesh/smesh_refine.cpp | 57 +++- Cassiopee/XCore/XCore/intersectMesh/trace.cpp | 6 +- Cassiopee/XCore/srcs.py | 2 +- 18 files changed, 689 insertions(+), 662 deletions(-) delete mode 100644 Cassiopee/XCore/XCore/intersectMesh/locate.cpp create mode 100644 Cassiopee/XCore/XCore/intersectMesh/smesh_locate.cpp diff --git a/Cassiopee/XCore/XCore/intersectMesh/cut.cpp b/Cassiopee/XCore/XCore/intersectMesh/cut.cpp index a1ca591c2..ec3a730fc 100644 --- a/Cassiopee/XCore/XCore/intersectMesh/cut.cpp +++ b/Cassiopee/XCore/XCore/intersectMesh/cut.cpp @@ -31,46 +31,6 @@ void Dcel::init_mh_sv_intersections(const Smesh &M) } } -/* -void Dcel::cut_hedges_intersecting_with_endpoint(Vertex *v, const Smesh &M) -{ - const auto &vloc = v->loc; - - if (vloc.e_idx == -1) return; - - E_Int fid = vloc.fid; - - const auto &pe = M.F2E[fid]; - - E_Int me = pe[vloc.e_idx]; - - Hedge *start = H[2*me]; - - Face *face = F[fid]; - - if (start->left != face) start = start->twin; - - Hedge *h = start; - - E_Int done = 0; - - while (1) { - - if (hedge_contains_vertex(h, v)) { - done = 1; - v->xhedge = h; - cut_hedge_at_vertex(h, v); - break; - } - - h = h->next; - if (h == start) break; - } - - assert(done == 1); -} -*/ - void Dcel::cut_hedges() { size_t hid = 0; diff --git a/Cassiopee/XCore/XCore/intersectMesh/dcel.cpp b/Cassiopee/XCore/XCore/intersectMesh/dcel.cpp index a3cf01935..b85e449c4 100644 --- a/Cassiopee/XCore/XCore/intersectMesh/dcel.cpp +++ b/Cassiopee/XCore/XCore/intersectMesh/dcel.cpp @@ -36,10 +36,9 @@ Smesh Dcel::export_smesh(bool is_planar) const { Smesh smesh; - smesh.ne = 0; + smesh.is_planar = is_planar; smesh.np = V.size(); - smesh.X.resize(smesh.np); smesh.Y.resize(smesh.np); smesh.Z.resize(smesh.np); @@ -70,7 +69,9 @@ Smesh Dcel::export_smesh(bool is_planar) const smesh.nf = (E_Int)smesh.F.size(); - smesh.make_edges(is_planar); + smesh.Fc = smesh.F; + + smesh.make_edges(); return smesh; } @@ -767,7 +768,7 @@ void Dcel::locate_spoints(const Smesh &M, const Smesh &S) E_Int voxel_z = floor((S.Z[sp] - M.zmin) / M.HZ); E_Int sp_bin = voxel_x + M.NX * voxel_y + M.NXY * voxel_z; - const auto &pf = M.bin_faces[sp_bin]; + const auto &pf = M.bin_faces.at(sp_bin); assert(pf.size() > 0); @@ -930,265 +931,6 @@ E_Int Dcel::get_next_face(const Smesh &M, E_Float px, E_Float py, E_Float pz, std::vector points; -void Dcel::trace_hedge(Hedge *sh, const Smesh &M, const Smesh &S, E_Int hid) -{ -/* - - Vertex *p = sh->orig; - Vertex *q = sh->twin->orig; - - E_Float dir[3] = {q->x-p->x, q->y-p->y, q->z-p->z}; - - const auto &ploc = p->loc; - - std::vector test_faces; - - E_Int mfid = ploc.fid; - - // Get the potential starting faces - - if (ploc.e_idx != -1) { - assert(ploc.v_idx == -1); - const auto &pe = M.F2E[mfid]; - E_Int eid = pe[ploc.e_idx]; - const auto &pf = M.E2F[eid]; - for (E_Int fid : pf) test_faces.push_back(fid); - } else if (ploc.v_idx != -1) { - assert(ploc.e_idx == -1); - const auto &pn = M.F[mfid]; - E_Int pid = pn[ploc.v_idx]; - const auto &pf = M.P2F[pid]; - for (E_Int fid : pf) test_faces.push_back(fid); - } else { - test_faces.push_back(mfid); - } - - // Handle potential intersection of starting point - - //handle_intersecting_endpoint(p, M); - //handle_intersecting_endpoint(q, M); - - // Determine the starting face - E_Int start_face = test_faces[0]; - if (test_faces.size() > 1) - start_face = get_next_face(M, p->x, p->y, p->z, test_faces, dir, hid); - - if (start_face == -1) { - hedge_write("sh", sh); - point_write("orig", sh->orig); - std::vector faces; - for (auto fid : test_faces) { - faces.push_back(F[fid]); - } - printf("test_faces: %lu\n", test_faces.size()); - faces_write("test_faces", faces); - } - assert(start_face != -1); - - // Trace - - E_Int found = 0; - E_Int walk = 0; - E_Int max_walk = 5; - - Face *current_face = F[start_face]; - - E_Float px = p->x, py = p->y, pz = p->z; - - Hedge *start_hedge = current_face->rep; - - Hedge *current_hedge = sh; - - // Pinpoint the endpoint - std::vector end_faces; - const auto &qloc = q->loc; - E_Int qfid = qloc.fid; - - if (qloc.e_idx != -1) { - assert(qloc.v_idx == -1); - const auto &pe = M.F2E[qfid]; - E_Int eid = pe[qloc.e_idx]; - const auto &pf = M.E2F[eid]; - for (E_Int fid : pf) end_faces.push_back(fid); - } else if (qloc.v_idx != -1) { - assert(qloc.e_idx == -1); - const auto &pn = M.F[qfid]; - E_Int pid = pn[qloc.v_idx]; - const auto &pf = M.P2F[pid]; - for (E_Int fid : pf) end_faces.push_back(fid); - } else { - end_faces.push_back(qfid); - } - - - while (!found && walk < max_walk) { - - // Check if we reached q - - for (E_Int fid : end_faces) { - if (F[fid] == current_face) { - found = 1; - break; - } - } - - if (found) break; - - E_Int current_fid = current_face->oid[0]; - - const E_Float *fN = &M.fnormals[3*current_fid]; - - E_Float proj[3] = { }; - E_Float dp = K_MATH::dot(fN, dir, 3); - for (E_Int i = 0; i < 3; i++) proj[i] = dir[i] - dp * fN[i]; - - E_Float dx = px + 1.0 * proj[0]; - E_Float dy = py + 1.0 * proj[1]; - E_Float dz = pz + 1.0 * proj[2]; - - Hedge *h = current_face->rep; - E_Int reached = 0; - E_Int hit = 0; - - E_Float ix, iy, iz; - ix = iy = iz = EFLOATMIN; - - while (!reached && !found) { - - Vertex *a = h->orig; - Vertex *b = h->twin->orig; - - hit = EdgeEdgeIntersect( - px, py, pz, - dx, dy, dz, - a->x, a->y, a->z, - b->x, b->y, b->z, - ix, iy, iz); - - if (hit) { - - Vertex *x = NULL; - - E_Int hit_a = cmp_points(ix, iy, iz, a->x, a->y, a->z) == 0; - E_Int hit_b = cmp_points(ix, iy, iz, b->x, b->y, b->z) == 0; - - // Hit a vertex: original m vertex, or intersection - - if (hit_a) x = a; - else if (hit_b) x = b; - - if (x != NULL) { - - //// Stop if reached destination - //if (x->oid[1] != -1) { - // assert(x == q); - // found = 1; - //} - - //// M point, get the next face - //else if (x->oid[0] != -1) { - - // E_Int mpid = x->oid[0]; - // const auto &pf = M.P2F[mpid]; - // E_Int next_fid = get_next_face(M, x->x, x->y, x->z, pf, dir, hid); - // assert(next_fid != -1); - // assert(next_fid != current_fid); - // current_face = F[next_fid]; - - //} else { - // - // // Intersection, move - - // current_face = h->twin->left; - - //} - - - bool is_mpoint = x->oid[0] != -1; - bool is_spoint = x->oid[1] != -1; - - // Stictly an M point, get the next face - - if (is_mpoint && !is_spoint) { - E_Int mpid = x->oid[0]; - const auto &pf = M.P2F[mpid]; - E_Int next_fid = get_next_face(M, x->x, x->y, x->z, pf, dir, hid); - assert(next_fid != -1); - assert(next_fid != current_fid); - current_face = F[next_fid]; - } - - - // S point, must be q since edges from S do not cross - else if (is_spoint) { - assert(x == q); - assert(cmp_vtx(x, q) == 0); - found = 1; - } - - else { - assert(0); - } - - - } else { - - // Hit the inside of an edge - - // Must be a new intersection - Event *xit = Q.lookup(ix, iy, iz); - - assert(xit == NULL); - - x = new Vertex(ix, iy, iz); - assert(x->oid[0] == -1); - assert(x->oid[1] == -1); - x->id = V.size(); - V.push_back(x); - x->xhedge = h; - - cut_hedge_at_vertex(h, x); - - current_face = h->twin->left; - - } - - assert(x); - - points.push_back(Point(x->x, x->y, x->z)); - - if (found) break; - - cut_hedge_at_vertex(current_hedge, x); - current_hedge = current_hedge->next; - - px = ix; - py = iy; - pz = iz; - - break; - } - - h = h->next; - if (h == start_hedge) { - reached = 1; - } - } - - if (reached != 0) { - fprintf(stderr, " Reached start_hedge!\n"); - face_write("last_face", current_face); - assert(0); - abort(); - } - - walk++; - } - - assert(walk < max_walk); - */ -} - void Dcel::find_intersections_3D(const Smesh &M, const Smesh &S) { puts(" Isolating s_hedges..."); diff --git a/Cassiopee/XCore/XCore/intersectMesh/icapsule.cpp b/Cassiopee/XCore/XCore/intersectMesh/icapsule.cpp index ecb389234..1687c2164 100644 --- a/Cassiopee/XCore/XCore/intersectMesh/icapsule.cpp +++ b/Cassiopee/XCore/XCore/intersectMesh/icapsule.cpp @@ -19,37 +19,6 @@ E_Int ray_point_orient(const E_Float o[3], const E_Float d[3], return 0; } -Smesh IMesh::make_smesh(const E_Float *ptag) -{ - patch.clear(); - - for (E_Int fid : skin) { - const auto &pn = F[fid]; - bool is_patch = true; - for (E_Int pid : pn) { - if (ptag[pid] != 1) { - is_patch = false; - break; - } - } - if (is_patch) - patch.insert(fid); - } - - return Smesh(*this); -} - -Smesh IMesh::make_smesh_from_skin(bool is_planar) -{ - patch.clear(); - - for (E_Int fid : skin) { - patch.insert(fid); - } - - return Smesh(*this, is_planar); -} - void Smesh::correct_near_points_and_edges(Smesh &Sf, std::vector &plocs) { @@ -59,7 +28,7 @@ void Smesh::correct_near_points_and_edges(Smesh &Sf, E_Int fid = ploc.fid; assert(fid < nf); - const auto &pn = F[fid]; + const auto &pn = Fc[fid]; if (ploc.v_idx != -1) { on_vertex++; @@ -80,23 +49,20 @@ void Smesh::correct_near_points_and_edges(Smesh &Sf, } } else if (ploc.e_idx != -1) { on_edge++; - E_Int zero_crd = (ploc.e_idx+2)%3; - E_Float U = ploc.bcrd[zero_crd]; - assert(Sign(U, NEAR_EDGE_TOL) == 0); - E_Int i1 = (zero_crd+1)%3; - E_Int i2 = (zero_crd+2)%3; - E_Float V = ploc.bcrd[i1]; - E_Float W = ploc.bcrd[i2]; - E_Int a = pn[i1]; - E_Int b = pn[i2]; - V += U; - assert(Sign(V+W-1) == 0); - Sf.X[i] = V*X[a] + W*X[b]; - Sf.Y[i] = V*Y[a] + W*Y[b]; - Sf.Z[i] = V*Z[a] + W*Z[b]; + E_Float u = ploc.bcrd[0]; + E_Float v = ploc.bcrd[1]; + E_Float w = ploc.bcrd[2]; + assert(Sign(w, NEAR_EDGE_TOL) == 0); + u += w; + assert(Sign(u+v-1) == 0); + E_Int p = pn[ploc.e_idx]; + E_Int q = pn[(ploc.e_idx+1)%pn.size()]; + Sf.X[i] = u*X[p] + v*X[q]; + Sf.Y[i] = u*Y[p] + v*Y[q]; + Sf.Z[i] = u*Z[p] + v*Z[q]; } } - //printf("on vertex: %d - on edge: %d\n", on_vertex, on_edge); + printf("on vertex: %d - on edge: %d\n", on_vertex, on_edge); } std::set ewalls; @@ -157,14 +123,15 @@ std::set Smesh::extract_bounding_faces(const Smesh &Sf, E_Float vy = Sf.Y[c] - Sf.Y[b]; E_Float vz = Sf.Z[c] - Sf.Z[b]; E_Float cp[3] = {uy*vz - uz*vy, uz*vx - ux*vz, ux*vy - uy*vx}; + // TODO(Imad): inherit fnormals const E_Float *N_b = &fnormals[3*plocs[b].fid]; E_Float dp = K_MATH::dot(cp, N_b, 3); E_Int cmp = Sign(dp); assert(cmp != 0); - if (cmp < 0) - std::reverse(pchain.begin(), pchain.end()); + if (cmp < 0) std::reverse(pchain.begin(), pchain.end()); Sf.write_points("pchain", pchain); + for (E_Int p : pchain) pchains.push_back({Sf.X[p], Sf.Y[p], Sf.Z[p]}); std::set wfids; @@ -177,6 +144,9 @@ std::set Smesh::extract_bounding_faces(const Smesh &Sf, E_Float px = Sf.X[p], py = Sf.Y[p], pz = Sf.Z[p]; E_Float qx = Sf.X[q], qy = Sf.Y[q], qz = Sf.Z[q]; + //point_write("p", px, py, pz); + //point_write("q", qx, qy, qz); + E_Float D[3] = {qx-px, qy-py, qz-pz}; E_Float NORM = K_MATH::norm(D, 3); D[0] /= NORM, D[1] /= NORM, D[2] /= NORM; @@ -187,7 +157,7 @@ std::set Smesh::extract_bounding_faces(const Smesh &Sf, E_Int last_vertex = -1, last_edge = -1, dummy; get_shared_faces(plocs[p], orig_faces, last_vertex, last_edge); - get_shared_faces(plocs[q], tail_faces, dummy, dummy); + get_shared_faces(plocs[q], tail_faces, dummy, dummy); E_Int starting_face = deduce_face(orig_faces, px, py, pz, D, last_vertex, last_edge); @@ -204,11 +174,14 @@ std::set Smesh::extract_bounding_faces(const Smesh &Sf, wfids.insert(cur_fid); + //write_face("cur_fid", cur_fid); + E_Float proj[3]; get_unit_projected_direction(cur_fid, D, proj); - const auto &pn = F[cur_fid]; + const auto &pn = Fc[cur_fid]; const auto &pe = F2E[cur_fid]; + assert(pe.size() == pn.size()); const E_Float *fN = &fnormals[3*cur_fid]; // First pass: define the wall data @@ -224,6 +197,8 @@ std::set Smesh::extract_bounding_faces(const Smesh &Sf, } } + //write_edges("wall", weids); + for (auto fid : tail_faces) { if (fid == cur_fid) { found_tail = true; @@ -264,6 +239,7 @@ std::set Smesh::extract_bounding_faces(const Smesh &Sf, E_Int eid = pe[i]; last_edge = eid; last_vertex = -1; + assert(E2F[eid][0] == cur_fid || E2F[eid][1] == cur_fid); if (E2F[eid][0] == cur_fid) next_fid = E2F[eid][1]; else next_fid = E2F[eid][0]; @@ -304,15 +280,14 @@ std::set Smesh::extract_bounding_faces(const Smesh &Sf, assert(walk <= max_walks); } - write_edges("weids", weids); - - // TODO(Imad): project wpids on best-fit plane and jarvis march // BFS to get the smesh mpids std::queue Q; for (E_Int fid : wfids) Q.push(fid); + //write_ngon("fwall_before_BFS", wfids); + while (!Q.empty()) { E_Int fid = Q.front(); Q.pop(); @@ -331,7 +306,10 @@ std::set Smesh::extract_bounding_faces(const Smesh &Sf, } } - write_ngon("wfids", wfids); + //write_ngon("fwall_after_BFS", wfids); + + //write_ngon("fwall", wfids); + //write_edges("ewall", weids); for (E_Int eid : weids) ewalls.insert(eid); for (E_Int fid : wfids) fwalls.insert(fid); @@ -349,22 +327,13 @@ ICapsule::ICapsule(const Karray &marray, const std::vector &sarrays, M.triangulate_skin(); M.make_bbox(); M.hash_skin(); - M.make_skin_graph(); - Smesh Mf = M.make_smesh_from_skin(false); + //M.make_skin_graph(); + Smesh Mf(M, M.skin, false); Mf.make_bbox(); Mf.hash_faces(); + Mf.make_fcenters(); Mf.make_fnormals(); - Mf.make_point_faces(); Mf.make_pnormals(); - Mf.make_point_edges(); - - for (E_Int pid = 0; pid < Mf.np; pid++) { - const auto &pe = Mf.P2E[pid]; - for (E_Int eid : pe) { - const auto &e = Mf.E[eid]; - assert(e.p == pid || e.q == pid); - } - } Ss.reserve(sarrays.size()); spatches.reserve(sarrays.size()); @@ -375,70 +344,43 @@ ICapsule::ICapsule(const Karray &marray, const std::vector &sarrays, bfaces_list.reserve(sarrays.size()); for (size_t i = 0; i < sarrays.size(); i++) { - Ss.push_back(IMesh(sarrays[i])); - Ss[i].set_tolerances(NEAR_VERTEX_TOL, NEAR_EDGE_TOL); - Ss[i].make_skin(); - Ss[i].orient_skin(IN); - Ss[i].triangulate_skin(); - spatches.push_back(Ss[i].make_smesh(ptags[i])); - spatches[i].make_fcenters(); - spatches[i].make_fnormals(); - spatches[i].make_point_faces(); - spatches[i].make_pnormals(); - spatches[i].compute_min_distance_between_points(); - plocs_list.push_back(Mf.locate(spatches[i])); - Mf.correct_near_points_and_edges(spatches[i], plocs_list[i]); - - bfaces_list.push_back( - Mf.extract_bounding_faces(spatches[i], plocs_list[i])); - - spatches[i].make_bbox(); - spatches[i].hash_faces(); - refine(Mf, bfaces_list[i], spatches[i], plocs_list[i]); + // Create IMesh S + IMesh S(sarrays[i]); + S.set_tolerances(NEAR_VERTEX_TOL, NEAR_EDGE_TOL); + S.make_skin(); + S.orient_skin(IN); + S.triangulate_skin(); + Ss.push_back(S); + + // Create SMesh Sf + Smesh Sf = Smesh::Smesh_from_point_tags(S, ptags[i]); + Sf.make_fcenters(); + Sf.make_fnormals(); + Sf.make_pnormals(); + Sf.compute_min_distance_between_points(); + + // Locate Sf points on Mf faces + auto plocs = Mf.locate(Sf); + Mf.correct_near_points_and_edges(Sf, plocs); + + // Correct AABB and Sf faces hash + Sf.make_bbox(); + Sf.hash_faces(); + + // Extract the initial Mf faces that bound Sf + auto bfaces = Mf.extract_bounding_faces(Sf, plocs); + + // Refinement loop + refine(Mf, bfaces, Sf, plocs); + + // Add Sf + spatches.push_back(Sf); + + // Add plocs + plocs_list.push_back(plocs); } - Mf.write_edges("ewalls", ewalls); - Mf.write_ngon("fwalls", fwalls); - point_write("pchains", pchains); - - // mfaces to spoints - std::map> mfid_to_spids; - - for (size_t i = 0; i < plocs_list.size(); i++) { - const auto &plocs = plocs_list[i]; - for (size_t j = 0; j < plocs.size(); j++) { - const auto &ploc = plocs[j]; - PointData point_data; - point_data.pid = j; - point_data.fid = ploc.fid; - point_data.sid = i; - point_data.x = spatches[i].X[j]; - point_data.y = spatches[i].Y[j]; - point_data.z = spatches[i].Z[j]; - - mfid_to_spids[ploc.fid].push_back(point_data); - } - } - - std::vector fids_to_erase; - for (const auto &mfdata : mfid_to_spids) { - std::set sids; - for (const auto &spdata : mfdata.second) - sids.insert(spdata.sid); - if (sids.size() == 1) - fids_to_erase.push_back(mfdata.first); - } - - for (E_Int fid : fids_to_erase) - mfid_to_spids.erase(fid); - - std::vector ref_faces; - for (const auto &mfdata : mfid_to_spids) - ref_faces.push_back(mfdata.first); - - Mf.write_ngon("ref_faces", ref_faces); - - //Mf.refine(mfid_to_spids); + Mf.write_ngon("refined_Mf"); } @@ -538,7 +480,7 @@ PyObject *K_XCORE::icapsule_init(PyObject *self, PyObject *args) PyObject *PTAG = PyList_GetItem(PTAGS, i); E_Int size = -1; E_Int ret = K_NUMPY::getFromNumpyArray(PTAG, ptags[i], size, true); - Py_DECREF(PTAG); + //Py_DECREF(PTAG); if (ret != 1 || size != sarrays[i].npoints()) { RAISE("Ptag[i] should have size sarrays[i].npoints."); Karray_free_ngon(marray); diff --git a/Cassiopee/XCore/XCore/intersectMesh/icapsule.h b/Cassiopee/XCore/XCore/intersectMesh/icapsule.h index 1d4bc369c..e92485506 100644 --- a/Cassiopee/XCore/XCore/intersectMesh/icapsule.h +++ b/Cassiopee/XCore/XCore/intersectMesh/icapsule.h @@ -14,6 +14,6 @@ struct ICapsule { ICapsule(const Karray &marray, const std::vector &sarray, const std::vector &ptags); - void refine(Smesh &Mf, const std::set &mfids, Smesh &Sf, + void refine(Smesh &Mf, std::set &mfids, Smesh &Sf, std::vector &plocs_s); }; diff --git a/Cassiopee/XCore/XCore/intersectMesh/icapsule_refine.cpp b/Cassiopee/XCore/XCore/intersectMesh/icapsule_refine.cpp index 9a9f41f59..e31c24a4a 100644 --- a/Cassiopee/XCore/XCore/intersectMesh/icapsule_refine.cpp +++ b/Cassiopee/XCore/XCore/intersectMesh/icapsule_refine.cpp @@ -48,6 +48,9 @@ void Smesh::project(const Smesh &Mf, const std::vector &mpids, { for (size_t i = 0; i < mpids.size(); i++) { E_Int mpid = mpids[i]; + assert(mpid >= 0); + assert(mpid < Mf.np); + assert(Mf.pnormals.size() == (size_t)(3*Mf.np)); const E_Float *N = &Mf.pnormals[3*mpid]; E_Float mx = Mf.X[mpid]; E_Float my = Mf.Y[mpid]; @@ -57,8 +60,8 @@ void Smesh::project(const Smesh &Mf, const std::vector &mpids, auto &ploc = plocs[i]; E_Float min_abs_t = EFLOATMAX; for (const auto &mloc : mlocs) { - if (fabs(mloc.t) < EFLOATMAX) { - min_abs_t = mloc.t; + if (fabs(mloc.t) < min_abs_t) { + min_abs_t = fabs(mloc.t); ploc.fid = mloc.fid; ploc.t = mloc.t; ploc.x = mloc.x; @@ -72,11 +75,67 @@ void Smesh::project(const Smesh &Mf, const std::vector &mpids, } } -void ICapsule::refine(Smesh &Mf, const std::set &mfids, Smesh &Sf, +static +std::vector deduce_ref_faces(const std::vector &mpids, + const std::vector &plocs_m, const Smesh &Mf, + std::vector &ref_faces) +{ + // Sfids to enclosed mpids + std::map> smap; + for (size_t i = 0; i < mpids.size(); i++) { + const auto &ploc_m = plocs_m[i]; + if (ploc_m.fid == -1) continue; + smap[ploc_m.fid].push_back(mpids[i]); + } + + std::map> sfid_to_mfids; + + for (const auto &spdata : smap) { + E_Int sfid = spdata.first; + + // Partly enclosed mfids to point count + std::map mfid_pcount; + + const auto &mpids = spdata.second; + for (E_Int mpid : mpids) { + const auto &pf = Mf.P2F[mpid]; + for (E_Int mfid : pf) mfid_pcount[mfid] += 1; + } + + // Deduce the mfids that are completely enclosed + for (const auto &mpdata : mfid_pcount) { + E_Int mfid = mpdata.first; + size_t count = mpdata.second; + assert(count <= Mf.Fc[mfid].size()); + if (count == Mf.Fc[mfid].size()) { + sfid_to_mfids[sfid].push_back(mfid); + } + } + } + + ref_faces.clear(); + ref_faces.reserve(sfid_to_mfids.size()); + for (auto it = sfid_to_mfids.begin(); it != sfid_to_mfids.end(); it++) + ref_faces.push_back(it->first); + + return ref_faces; +} + +void ICapsule::refine(Smesh &Mf, std::set &mfids, Smesh &Sf, std::vector &plocs_s) { - E_Int ref_M, ref_S; + size_t ref_M, ref_S; + + E_Int iter = 0; + do { + iter++; + + std::vector fat_sfids; + std::vector fat_mfids; + + /*********************** Sf refinement ***********************/ + // Construct the BVH of Sf Sf.make_BVH(); @@ -88,14 +147,58 @@ void ICapsule::refine(Smesh &Mf, const std::set &mfids, Smesh &Sf, } std::vector mpids; for (E_Int p : mpids_set) mpids.push_back(p); - std::vector plocs_m(mpids.size()); // Project mpids on Sf + std::vector plocs_m(mpids.size()); Sf.project(Mf, mpids, plocs_m); + Sf.destroy_BVH(Sf.bvh_root); + + // Deduce sfids to refine + std::vector sref_faces; + deduce_ref_faces(mpids, plocs_m, Mf, sref_faces); + + for (const E_Int sfid : sref_faces) { + fat_sfids.push_back(sfid); + } + printf("Fat sfids: %lu\n", fat_sfids.size()); - ref_M = 0; - ref_S = 0; + ref_S = sref_faces.size(); + if (ref_S > 0) { + Sf.refine(sref_faces); + Sf.conformize(); + Sf.hash_faces(); + Sf.make_pnormals(); + } + + /*********************** Mf refinement ***********************/ + + // Test all the Sf points + std::vector spids; + spids.reserve(Sf.np); + for (E_Int i = 0; i < Sf.np; i++) spids.push_back(i); + + // Deduce mfids to refine + std::vector mref_faces; + deduce_ref_faces(spids, plocs_s, Sf, mref_faces); + for (const E_Int mfid : mref_faces) { + fat_mfids.push_back(mfid); + } + printf("Fat mfids: %lu\n", fat_mfids.size()); + + ref_M = mref_faces.size(); + if (ref_M > 0) { + Mf.refine(mref_faces); + Mf.conformize(); + Mf.hash_faces(); + Mf.make_pnormals(); + // update mfids + for (E_Int fparent : mref_faces) { + const auto &children = Mf.fchildren[fparent].back(); + for (E_Int child : children) mfids.insert(child); + } + plocs_s = Mf.locate(Sf); + } } while (ref_M > 0 || ref_S > 0); point_write("projections", projections); diff --git a/Cassiopee/XCore/XCore/intersectMesh/intersectMesh.cpp b/Cassiopee/XCore/XCore/intersectMesh/intersectMesh.cpp index b14fd991f..ac33f2928 100644 --- a/Cassiopee/XCore/XCore/intersectMesh/intersectMesh.cpp +++ b/Cassiopee/XCore/XCore/intersectMesh/intersectMesh.cpp @@ -392,8 +392,8 @@ PyObject *K_XCORE::intersectMesh(PyObject *self, PyObject *args) // Extract surface meshes - Smesh Mf(M); - Smesh Sf(S); + Smesh Mf = Smesh::Smesh_from_mesh_patch(M); + Smesh Sf = Smesh::Smesh_from_mesh_patch(S); Mf.write_ngon("Mf"); Sf.write_ngon("Sf"); diff --git a/Cassiopee/XCore/XCore/intersectMesh/locate.cpp b/Cassiopee/XCore/XCore/intersectMesh/locate.cpp deleted file mode 100644 index 62d9320df..000000000 --- a/Cassiopee/XCore/XCore/intersectMesh/locate.cpp +++ /dev/null @@ -1,61 +0,0 @@ -#include "smesh.h" -#include "triangle.h" -#include "primitives.h" - -std::vector Smesh::locate(const Smesh &Sf) const -{ - std::vector ploc(Sf.np); - - for (E_Int pid = 0; pid < Sf.np; pid++) { - - E_Float x = Sf.X[pid]; - E_Float y = Sf.Y[pid]; - E_Float z = Sf.Z[pid]; - - E_Int I = floor((x - xmin) / HX); - E_Int J = floor((y - ymin) / HY); - E_Int K = floor((z - zmin) / HZ); - E_Int voxel = get_voxel(I, J, K); - - const auto &pf = bin_faces[voxel]; - - bool found = false; - - // w, u, v - auto &loc = ploc[pid]; - - for (size_t i = 0; i < pf.size() && !found; i++) { - E_Int fid = pf[i]; - const auto &pn = F[fid]; - E_Int a = pn[0], b = pn[1], c = pn[2]; - E_Float u, v, w; - if (Triangle::is_point_inside( - x, y, z, - X[a], Y[a], Z[a], - X[b], Y[b], Z[b], - X[c], Y[c], Z[c], - u, v, w)) { - - found = true; - - loc.fid = fid; - loc.bcrd[0] = u; - loc.bcrd[1] = v; - loc.bcrd[2] = w; - - if (Sign(1-u, NEAR_VERTEX_TOL) == 0) loc.v_idx = 0; - else if (Sign(1-v, NEAR_VERTEX_TOL) == 0) loc.v_idx = 1; - else if (Sign(1-w, NEAR_VERTEX_TOL) == 0) loc.v_idx = 2; - else if (Sign(w, NEAR_EDGE_TOL) == 0) loc.e_idx = 0; - else if (Sign(u, NEAR_EDGE_TOL) == 0) loc.e_idx = 1; - else if (Sign(v, NEAR_EDGE_TOL) == 0) loc.e_idx = 2; - - break; - } - } - - assert(found); - } - - return ploc; -} diff --git a/Cassiopee/XCore/XCore/intersectMesh/mesh.h b/Cassiopee/XCore/XCore/intersectMesh/mesh.h index fa342f940..bd4b67652 100644 --- a/Cassiopee/XCore/XCore/intersectMesh/mesh.h +++ b/Cassiopee/XCore/XCore/intersectMesh/mesh.h @@ -98,8 +98,6 @@ struct IMesh { NEAR_EDGE_TOL = near_edge_tol; } - Smesh make_smesh(const E_Float *ptag); - Smesh make_smesh_from_skin(bool is_planar = true); void make_skin_graph(); inline E_Int get_voxel(E_Int I, E_Int J, E_Int K) const diff --git a/Cassiopee/XCore/XCore/intersectMesh/point.h b/Cassiopee/XCore/XCore/intersectMesh/point.h index 06fbb6479..b5de436b3 100644 --- a/Cassiopee/XCore/XCore/intersectMesh/point.h +++ b/Cassiopee/XCore/XCore/intersectMesh/point.h @@ -31,6 +31,7 @@ struct PointLoc { E_Float x = EFLOATMAX; E_Float y = EFLOATMAX; E_Float z = EFLOATMAX; + E_Int sub = -1; }; struct PointData { diff --git a/Cassiopee/XCore/XCore/intersectMesh/removeIntersectingKPlanes.cpp b/Cassiopee/XCore/XCore/intersectMesh/removeIntersectingKPlanes.cpp index 01bb91354..b502b3b1c 100644 --- a/Cassiopee/XCore/XCore/intersectMesh/removeIntersectingKPlanes.cpp +++ b/Cassiopee/XCore/XCore/intersectMesh/removeIntersectingKPlanes.cpp @@ -55,7 +55,6 @@ void construct_faces(std::vector> &faces, NF++; } -static PyObject *handle_slave(IMesh *M, Karray& sarray) { E_Int ni = sarray.ni; @@ -361,7 +360,6 @@ PyObject *handle_slave(IMesh *M, Karray& sarray) return out; } -static E_Int get_kmax(IMesh *M, Karray& sarray) { E_Int ni = sarray.ni; @@ -396,7 +394,6 @@ E_Int get_kmax(IMesh *M, Karray& sarray) return kmax; } -static PyObject *handle_slave2(IMesh *M, Karray& sarray, E_Int kmax) { E_Int ni = sarray.ni; diff --git a/Cassiopee/XCore/XCore/intersectMesh/smesh.cpp b/Cassiopee/XCore/XCore/intersectMesh/smesh.cpp index 66e53028f..373d5136c 100644 --- a/Cassiopee/XCore/XCore/intersectMesh/smesh.cpp +++ b/Cassiopee/XCore/XCore/intersectMesh/smesh.cpp @@ -31,25 +31,128 @@ #include #include +#define LEFT 0 +#define RIGHT 1 + +void Smesh::get_edge_centers(E_Int p, E_Int q, std::list &edge_centers, + E_Int left_right) +{ + u_edge e(p, q); + auto it = ecenter.find(e); + if (it == ecenter.end()) return; + + E_Int ec = it->second; + if (left_right == LEFT) edge_centers.push_front(ec); + else edge_centers.push_back(ec); + + get_edge_centers(p, ec, edge_centers, LEFT); + get_edge_centers(ec, q, edge_centers, RIGHT); +} + +void Smesh::clear_conformal_data() +{ + //Fc.clear(); + F2E.clear(); + F2F.clear(); + + P2F.clear(); + P2E.clear(); + + ne = 0; + E.clear(); + E2F.clear(); +} + +void Smesh::conformize() +{ + clear_conformal_data(); + + std::vector> new_Fc(nf); + + for (E_Int fid = 0; fid < nf; fid++) { + const auto &pn = Fc[fid]; + + std::vector new_pn; + + for (size_t i = 0; i < pn.size(); i++) { + E_Int p = pn[i]; + E_Int q = pn[(i+1)%pn.size()]; + + new_pn.push_back(p); + + std::list edge_points; + get_edge_centers(p, q, edge_points, LEFT); + for (E_Int ep : edge_points) new_pn.push_back(ep); + } + + new_Fc[fid] = new_pn; + } + + Fc = new_Fc; + + make_edges(); + make_point_faces(); + make_point_edges(); +} + Smesh::Smesh() {} -Smesh::Smesh(const IMesh &M, bool is_planar) +Smesh Smesh::Smesh_from_mesh_skin(const IMesh &M, + const std::vector &skin, bool is_planar) +{ + return Smesh(M, skin, is_planar); +} + +Smesh Smesh::Smesh_from_point_tags(const IMesh &M, const E_Float *ptag, + bool is_planar) +{ + std::vector fids; + + for (E_Int fid : M.skin) { + const auto &pn = M.F[fid]; + bool keep = true; + for (E_Int pid : pn) { + if (ptag[pid] != 1) { + keep = false; + break; + } + } + if (keep) fids.push_back(fid); + } + + return Smesh(M, fids, is_planar); +} + +Smesh Smesh::Smesh_from_mesh_patch(const IMesh &M, bool is_planar) +{ + std::vector fids; + + for (E_Int fid : M.patch) { + fids.push_back(fid); + } + + return Smesh(M, fids, is_planar); +} + +Smesh::Smesh(const IMesh &M, const std::vector &fids, bool is_planar_) { NEAR_VERTEX_TOL = M.NEAR_VERTEX_TOL; NEAR_EDGE_TOL = M.NEAR_EDGE_TOL; - F.resize(M.patch.size()); + is_planar = is_planar_; + + F.resize(fids.size()); nf = 0; np = 0; // Get the faces - for (E_Int gf : M.patch) { + for (E_Int gf : fids) { g2lf[gf] = nf; l2gf[nf] = gf; - auto &face = F[nf]; + auto &pn = F[nf]; for (E_Int gp : M.F[gf]) { auto it = g2lp.find(gp); @@ -57,10 +160,10 @@ Smesh::Smesh(const IMesh &M, bool is_planar) if (it == g2lp.end()) { g2lp[gp] = np; l2gp[np] = gp; - face.push_back(np); + pn.push_back(np); np++; } else { - face.push_back(it->second); + pn.push_back(it->second); } } @@ -81,7 +184,10 @@ Smesh::Smesh(const IMesh &M, bool is_planar) Z[pids.second] = M.Z[pids.first]; } - make_edges(is_planar); + Fc = F; + make_edges(); + make_point_faces(); + make_point_edges(); } o_edge::o_edge(E_Int P, E_Int Q) @@ -100,16 +206,17 @@ struct o_edge_cmp { } }; -void Smesh::make_edges(bool is_planar) +void Smesh::make_edges() { // Make the edges - F2E.resize(F.size()); + F2E.resize(Fc.size()); std::map edges; + assert(E.empty()); ne = 0; for (E_Int i = 0; i < nf; i++) { - auto &face = F[i]; + auto &face = Fc[i]; for (size_t j = 0; j < face.size(); j++) { E_Int p = face[j]; E_Int q = face[(j+1)%face.size()]; @@ -129,17 +236,18 @@ void Smesh::make_edges(bool is_planar) assert((size_t)ne == E.size()); // Make edge_to_face + assert(E2F.empty()); E2F.resize(ne, {-1,-1}); std::vector count(ne, 0); for (E_Int i = 0; i < nf; i++) { - const auto &face = F2E[i]; - const auto &pn = F[i]; - assert(face.size() == pn.size()); + const auto &pe = F2E[i]; + const auto &pn = Fc[i]; + assert(pe.size() == pn.size()); - for (size_t j = 0; j < face.size(); j++) { - E_Int e = face[j]; + for (size_t j = 0; j < pe.size(); j++) { + E_Int e = pe[j]; count[e]++; if (E2F[e][0] == -1) E2F[e][0] = i; @@ -155,19 +263,20 @@ void Smesh::make_edges(bool is_planar) if (is_planar) assert(np - ne + nf + 1 == 2); + // Check that each edge's count is 1 or 2 for (E_Int i = 0; i < ne; i++) { assert(count[i] == 1 || count[i] == 2); } - + // Check consistency between E2F and F2E for (E_Int i = 0; i < ne; i++) { E_Int fi = E2F[i][0]; E_Int fj = E2F[i][1]; - const auto &face_i = F2E[fi]; + const auto &pe_i = F2E[fi]; E_Int found = false; - for (size_t j = 0; j < face_i.size(); j++) { - if (face_i[j] == (E_Int)i) { + for (size_t j = 0; j < pe_i.size(); j++) { + if (pe_i[j] == i) { found = true; break; } @@ -177,10 +286,10 @@ void Smesh::make_edges(bool is_planar) if (fj == -1) continue; - const auto &face_j = F2E[fj]; + const auto &pe_j = F2E[fj]; found = false; - for (size_t j = 0; j < face_j.size(); j++) { - if (face_j[j] == (E_Int)i) { + for (size_t j = 0; j < pe_j.size(); j++) { + if (pe_j[j] == i) { found = true; break; } @@ -190,16 +299,18 @@ void Smesh::make_edges(bool is_planar) } // Make faces neighbourhood + assert(F2F.empty()); F2F.resize(nf); - for (size_t i = 0; i < F2E.size(); i++) { - auto &face = F2E[i]; + for (E_Int i = 0; i < nf; i++) { + const auto &pe = F2E[i]; auto &neis = F2F[i]; - for (size_t j = 0; j < face.size(); j++) { - E_Int e = face[j]; - if (E2F[e][0] == (E_Int)i) neis.push_back(E2F[e][1]); - else if (E2F[e][1] == (E_Int)i) neis.push_back(E2F[e][0]); - else assert(0); + for (size_t j = 0; j < pe.size(); j++) { + E_Int e = pe[j]; + assert(E2F[e][0] == i || E2F[e][1] == i); + if (E2F[e][0] == i) neis.push_back(E2F[e][1]); + else neis.push_back(E2F[e][0]); } + assert(neis.size() == pe.size()); } // Traverse the face list breadth-first and adjust edges accordingly @@ -217,16 +328,16 @@ void Smesh::make_edges(bool is_planar) visited[f] = 1; auto &neis = F2F[f]; - auto &edgs = F2E[f]; - auto &face = F[f]; + auto &pe = F2E[f]; + auto &pn = Fc[f]; - for (size_t j = 0; j < face.size(); j++) { + for (size_t j = 0; j < pn.size(); j++) { E_Int nei = neis[j]; - E_Int p = face[j]; - E_Int q = face[(j+1)%face.size()]; + E_Int p = pn[j]; + E_Int q = pn[(j+1)%pn.size()]; - E_Int e = edgs[j]; + E_Int e = pe[j]; if (nei == -1) { assert(E[e].p == p); @@ -256,18 +367,18 @@ void Smesh::make_edges(bool is_planar) // Check for (E_Int i = 0; i < nf; i++) { - auto &face = F[i]; - for (size_t j = 0; j < face.size(); j++) { + const auto &pn = Fc[i]; + for (size_t j = 0; j < pn.size(); j++) { E_Int e = F2E[i][j]; - E_Int p = face[j]; - E_Int q = face[(j+1)%face.size()]; + E_Int p = pn[j]; + E_Int q = pn[(j+1)%pn.size()]; if (E[e].p == p) { assert(E[e].q == q); - assert(E2F[e][0] == (E_Int)i); + assert(E2F[e][0] == i); } else if (E[e].q == p) { assert(E[e].p == q); - assert(E2F[e][1] == (E_Int)i); + assert(E2F[e][1] == i); } else { assert(0); } @@ -296,10 +407,9 @@ void Smesh::make_point_faces() P2F.clear(); P2F.resize(np); - for (E_Int face = 0; face < nf; face++) { - const auto &cn = F[face]; - for (auto p : cn) - P2F[p].push_back(face); + for (E_Int fid = 0; fid < nf; fid++) { + const auto &pn = Fc[fid]; + for (auto p : pn) P2F[p].push_back(fid); } } @@ -347,12 +457,14 @@ void Smesh::make_pnormals() // Point normals: aggregate of shared faces normals + assert(fnormals.size() == (size_t)(3*nf)); + for (E_Int pid = 0; pid < np; pid++) { - const auto &faces = P2F[pid]; + const auto &pf = P2F[pid]; E_Float *N = &pnormals[3*pid]; - for (E_Int fid : faces) { + for (E_Int fid : pf) { E_Float *fN = &fnormals[3*fid]; for (E_Int i = 0; i < 3; i++) N[i] += fN[i]; } @@ -363,86 +475,6 @@ void Smesh::make_pnormals() } } -void Smesh::make_bbox() -{ - NX = 100; - NY = 100; - NZ = 100; - NXY = NX * NY; - NXYZ = NXY * NZ; - - xmin = ymin = zmin = std::numeric_limits::max(); - xmax = ymax = zmax = std::numeric_limits::min(); - - for (E_Int i = 0; i < np; i++) { - if (X[i] < xmin) xmin = X[i]; - if (Y[i] < ymin) ymin = Y[i]; - if (Z[i] < zmin) zmin = Z[i]; - if (X[i] > xmax) xmax = X[i]; - if (Y[i] > ymax) ymax = Y[i]; - if (Z[i] > zmax) zmax = Z[i]; - } - - E_Float dx = xmax - xmin; - E_Float dy = ymax - ymin; - E_Float dz = zmax - zmin; - - xmin = xmin - dx*0.01; - ymin = ymin - dy*0.01; - zmin = zmin - dz*0.01; - xmax = xmax + dx*0.01; - ymax = ymax + dy*0.01; - zmax = zmax + dz*0.01; - - HX = (xmax - xmin) / NX; - HY = (ymax - ymin) / NY; - HZ = (zmax - zmin) / NZ; -} - -void Smesh::hash_faces() -{ - bin_faces.clear(); - bin_faces.resize(NXYZ); - - for (E_Int fid = 0; fid < nf; fid++) { - const auto &pn = F[fid]; - - E_Int Imin, Jmin, Kmin; - E_Int Imax, Jmax, Kmax; - - Imin = Jmin = Kmin = NXYZ; - Imax = Jmax = Kmax = -1; - - for (E_Int p : pn) { - E_Float x = X[p]; - E_Float y = Y[p]; - E_Float z = Z[p]; - - E_Int I = floor((x - xmin) / HX); - E_Int J = floor((y - ymin) / HY); - E_Int K = floor((z - zmin) / HZ); - - if (I < Imin) Imin = I; - if (J < Jmin) Jmin = J; - if (K < Kmin) Kmin = K; - if (I > Imax) Imax = I; - if (J > Jmax) Jmax = J; - if (K > Kmax) Kmax = K; - } - - for (E_Int I = Imin; I <= Imax; I++) { - for (E_Int J = Jmin; J <= Jmax; J++) { - for (E_Int K = Kmin; K <= Kmax; K++) { - E_Int voxel = get_voxel(I, J, K); - assert(voxel >= 0); - assert(voxel < NXYZ); - bin_faces[voxel].push_back(fid); - } - } - } - } -} - void Smesh::compute_min_distance_between_points() { min_pdist_squared = EFLOATMAX; @@ -472,3 +504,21 @@ void Smesh::compute_min_distance_between_points() assert(ndists == np*(np-1)/2); } +void Smesh::clear() +{ + np = ne = nf = 0; + X.clear(); + Y.clear(); + Z.clear(); + P2F.clear(); + P2E.clear(); + E.clear(); + E2F.clear(); + F.clear(); + F2E.clear(); + F2F.clear(); + g2lp.clear(); + l2gp.clear(); + g2lf.clear(); + l2gf.clear(); +} \ No newline at end of file diff --git a/Cassiopee/XCore/XCore/intersectMesh/smesh.h b/Cassiopee/XCore/XCore/intersectMesh/smesh.h index bda9bbba4..ec9fcdae1 100644 --- a/Cassiopee/XCore/XCore/intersectMesh/smesh.h +++ b/Cassiopee/XCore/XCore/intersectMesh/smesh.h @@ -51,17 +51,26 @@ struct u_edge { struct Smesh { - // Connectivity + // Universal data - E_Int np, ne, nf; + E_Int np, nf; std::vector X, Y, Z; + std::vector> F; + + // Conformal data + E_Int ne; + std::vector> Fc; std::vector> P2F; std::vector> P2E; std::vector E; std::vector> E2F; - std::vector> F; std::vector> F2E; std::vector> F2F; + + void clear_conformal_data(); + + // Link to parent mesh + std::map g2lp; std::map l2gp; std::map g2lf; @@ -70,9 +79,16 @@ struct Smesh { // Constructors Smesh(); - Smesh(const IMesh &M, bool is_planar=true); - Smesh(const IMesh &M, const std::vector &faces); - void make_edges(bool is_planar); + Smesh(const IMesh &M, const std::vector &fids, bool is_planar=true); + static Smesh Smesh_from_point_tags(const IMesh &M, const E_Float *ptag, + bool is_planar=true); + static Smesh Smesh_from_mesh_skin(const IMesh &M, + const std::vector &skin, bool is_planar=true); + static Smesh Smesh_from_mesh_patch(const IMesh &M, + bool is_planar=true); + //Smesh(const IMesh &M, const std::vector &faces); + void make_edges(); + void clear(); // Geometry @@ -98,18 +114,20 @@ struct Smesh { void ray_BVH_intersect(E_Float ox, E_Float oy, E_Float oz, E_Float dx, E_Float dy, E_Float dz, BVH_node *node, std::vector &plocs); + inline void compute_face_center(E_Int fid); // Hash E_Int NX, NY, NZ, NXY, NXYZ; E_Float xmin, xmax, ymin, ymax, zmin, zmax; E_Float HX, HY, HZ; - std::vector> bin_faces; + std::map> bin_faces; std::vector bvh_indices; static const E_Int MAX_FACES_PER_BVH_LEAF = 8; BVH_node *bvh_root = NULL; void make_bbox(); + inline void bin_face(E_Int fid); void hash_faces(); inline E_Int get_voxel(E_Int i, E_Int j, E_Int k) const { @@ -120,6 +138,7 @@ struct Smesh { BVH_node *make_BVH_node(const AABB &box, E_Int start, E_Int end, BVH_node *left, BVH_node *right); BVH_node *make_BVH_subtree(E_Int start, E_Int end, const AABB &parent); + void destroy_BVH(BVH_node *root); // Adaptation @@ -127,13 +146,21 @@ struct Smesh { std::map>> fchildren; void resize_for_refinement(size_t nref_faces); - void refine(const std::map> &sensor); + void refine(const std::vector &ref_faces); void get_leaves(E_Int face, std::vector &leaves) const; void refine_tri(E_Int fid); void refine_edge(const u_edge &e); + void update_plocs(const std::vector &parents, + std::vector &plocs); + void conformize(); + void get_edge_centers(E_Int p, E_Int q, std::list &edge_centers, + E_Int left_right); + // Topology + bool is_planar = true; + std::set extract_bounding_faces(const Smesh &Sf, const std::vector &plocs) const; E_Int deduce_face(const std::vector &pf, @@ -152,5 +179,6 @@ struct Smesh { void write_ngon(const char *fname, const std::set &fset) const; void write_ngon(const char *fname, const std::vector &faces) const; void write_ngon(const char *fname) const; + void write_face(const char *fname, E_Int fid) const; }; diff --git a/Cassiopee/XCore/XCore/intersectMesh/smesh_bvh.cpp b/Cassiopee/XCore/XCore/intersectMesh/smesh_bvh.cpp index 522f4c147..4ca77b4a1 100644 --- a/Cassiopee/XCore/XCore/intersectMesh/smesh_bvh.cpp +++ b/Cassiopee/XCore/XCore/intersectMesh/smesh_bvh.cpp @@ -21,9 +21,16 @@ AABB Smesh::make_AABB(E_Int start, E_Int end) } } - E_Float dx = (xmax - xmin) * 0.01; - E_Float dy = (ymax - ymin) * 0.01; - E_Float dz = (zmax - zmin) * 0.01; + E_Float dx = xmax - xmin; + E_Float dy = ymax - ymin; + E_Float dz = zmax - zmin; + + xmin -= dx * 0.01; + ymin -= dy * 0.01; + zmin -= dz * 0.01; + xmax += dx * 0.01; + ymax += dy * 0.01; + zmax += dz * 0.01; return {xmin, ymin, zmin, xmax, ymax, zmax}; } @@ -86,4 +93,14 @@ void Smesh::make_BVH() for (E_Int i = 0; i < nf; i++) bvh_indices.push_back(i); bvh_root = make_BVH_subtree(0, nf, AABB_HUGE); +} + +void Smesh::destroy_BVH(BVH_node *root) +{ + if (root == NULL) return; + + destroy_BVH(root->left); + destroy_BVH(root->right); + + delete root; } \ No newline at end of file diff --git a/Cassiopee/XCore/XCore/intersectMesh/smesh_io.cpp b/Cassiopee/XCore/XCore/intersectMesh/smesh_io.cpp index ccd7a9239..737b35e24 100644 --- a/Cassiopee/XCore/XCore/intersectMesh/smesh_io.cpp +++ b/Cassiopee/XCore/XCore/intersectMesh/smesh_io.cpp @@ -73,7 +73,7 @@ void Smesh::write_ngon(const char *fname, const std::vector &faces) const E_Int NF = (E_Int)faces.size(); for (E_Int fid : faces) { - const auto &pn = F[fid]; + const auto &pn = Fc[fid]; const auto &pe = F2E[fid]; INDPH[idx+1] = INDPH[idx] + (E_Int)pn.size(); @@ -108,7 +108,7 @@ void Smesh::write_ngon(const char *fname, const std::vector &faces) const nZ[npid] = Z[opid]; } - for (size_t pid = 0; pid < NP; pid++) { + for (E_Int pid = 0; pid < NP; pid++) { fprintf(fh, "%f %f %f\n", nX[pid], nY[pid], nZ[pid]); } @@ -156,6 +156,47 @@ void Smesh::write_ngon(const char *fname, const std::vector &faces) const fclose(fh); } +void Smesh::write_face(const char *fname, E_Int fid) const +{ + FILE *fh = fopen(fname, "w"); + assert(fh); + + const auto &pn = Fc[fid]; + E_Int np = (size_t)pn.size(); + + fprintf(fh, "POINTS\n"); + fprintf(fh, "%d\n", np); + for (E_Int p : pn) { + fprintf(fh, "%f %f %f\n", X[p], Y[p], Z[p]); + } + + fprintf(fh, "INDPG\n"); + fprintf(fh, "%d\n", np + 1); + E_Int sizeNGon = -2; + for (E_Int i = 0; i < np+1; i++) { + sizeNGon += 2; + fprintf(fh, "%d ", sizeNGon); + } + fprintf(fh, "\n"); + + fprintf(fh, "NGON\n"); + fprintf(fh, "%d\n", 2*np); + for (E_Int i = 0; i < np; i++) { + fprintf(fh, "%d %d ", i, (i+1)%np); + } + fprintf(fh, "\n"); + + fprintf(fh, "INDPH\n"); + fprintf(fh, "%d\n", 2); + fprintf(fh, "0 %d\n", np); + + fprintf(fh, "NFACE\n"); + fprintf(fh, "%d\n", np); + for (E_Int i = 0; i < np; i++) fprintf(fh, "%d ", i); + + fclose(fh); +} + void Smesh::write_ngon(const char *fname) const { FILE *fh = fopen(fname, "w"); diff --git a/Cassiopee/XCore/XCore/intersectMesh/smesh_locate.cpp b/Cassiopee/XCore/XCore/intersectMesh/smesh_locate.cpp new file mode 100644 index 000000000..1ed85c9ea --- /dev/null +++ b/Cassiopee/XCore/XCore/intersectMesh/smesh_locate.cpp @@ -0,0 +1,170 @@ +#include "smesh.h" +#include "triangle.h" +#include "primitives.h" +#include "io.h" + +void Smesh::make_bbox() +{ + NX = 100; + NY = 100; + NZ = 100; + NXY = NX * NY; + NXYZ = NXY * NZ; + + xmin = ymin = zmin = std::numeric_limits::max(); + xmax = ymax = zmax = std::numeric_limits::min(); + + for (E_Int i = 0; i < np; i++) { + if (X[i] < xmin) xmin = X[i]; + if (Y[i] < ymin) ymin = Y[i]; + if (Z[i] < zmin) zmin = Z[i]; + if (X[i] > xmax) xmax = X[i]; + if (Y[i] > ymax) ymax = Y[i]; + if (Z[i] > zmax) zmax = Z[i]; + } + + E_Float dx = xmax - xmin; + E_Float dy = ymax - ymin; + E_Float dz = zmax - zmin; + + xmin = xmin - dx*0.01; + ymin = ymin - dy*0.01; + zmin = zmin - dz*0.01; + xmax = xmax + dx*0.01; + ymax = ymax + dy*0.01; + zmax = zmax + dz*0.01; + + HX = (xmax - xmin) / NX; + HY = (ymax - ymin) / NY; + HZ = (zmax - zmin) / NZ; +} + +inline +void Smesh::bin_face(E_Int fid) +{ + const auto &pn = Fc[fid]; + + E_Int Imin, Jmin, Kmin; + E_Int Imax, Jmax, Kmax; + + Imin = Jmin = Kmin = NXYZ; + Imax = Jmax = Kmax = -1; + + for (E_Int p : pn) { + E_Float x = X[p]; + E_Float y = Y[p]; + E_Float z = Z[p]; + + E_Int I = floor((x - xmin) / HX); + E_Int J = floor((y - ymin) / HY); + E_Int K = floor((z - zmin) / HZ); + + if (I < Imin) Imin = I; + if (J < Jmin) Jmin = J; + if (K < Kmin) Kmin = K; + if (I > Imax) Imax = I; + if (J > Jmax) Jmax = J; + if (K > Kmax) Kmax = K; + } + + for (E_Int I = Imin; I <= Imax; I++) { + for (E_Int J = Jmin; J <= Jmax; J++) { + for (E_Int K = Kmin; K <= Kmax; K++) { + E_Int voxel = get_voxel(I, J, K); + assert(voxel >= 0); + assert(voxel < NXYZ); + bin_faces[voxel].push_back(fid); + } + } + } +} + +void Smesh::hash_faces() +{ + bin_faces.clear(); + + for (E_Int fid = 0; fid < nf; fid++) { + bin_face(fid); + } +} + +std::vector Smesh::locate(const Smesh &Sf) const +{ + std::vector ploc(Sf.np); + + for (E_Int pid = 0; pid < Sf.np; pid++) { + + E_Float x = Sf.X[pid]; + E_Float y = Sf.Y[pid]; + E_Float z = Sf.Z[pid]; + + E_Int I = floor((x - xmin) / HX); + E_Int J = floor((y - ymin) / HY); + E_Int K = floor((z - zmin) / HZ); + E_Int voxel = get_voxel(I, J, K); + + const auto &pf = bin_faces.at(voxel); + + bool found = false; + + // w, u, v + auto &loc = ploc[pid]; + + for (size_t i = 0; i < pf.size() && !found; i++) { + E_Int fid = pf[i]; + const auto &pn = Fc[fid]; + const E_Float *fc = &fcenters[3*fid]; + + //point_write("o", fc[0], fc[1], fc[2]); + //std::vector dummy; + //dummy.push_back(fid); + //write_ngon("fid", dummy); + + for (size_t j = 0; j < pn.size(); j++) { + E_Int p = pn[j]; + E_Int q = pn[(j+1)%pn.size()]; + + //point_write("p", X[p], Y[p], Z[p]); + //point_write("q", X[q], Y[q], Z[q]); + + E_Float u, v, w; + + found = Triangle::is_point_inside(x, y, z, + X[p], Y[p], Z[p], + X[q], Y[q], Z[q], + fc[0], fc[1], fc[2], + u, v, w + ); + + if (found) { + loc.fid = fid; + loc.sub = j; + loc.bcrd[0] = u; + loc.bcrd[1] = v; + loc.bcrd[2] = w; + + // on p + if (Sign(1-u, NEAR_VERTEX_TOL) == 0) + loc.v_idx = j; + // on q + else if (Sign(1-v, NEAR_VERTEX_TOL) == 0) + loc.v_idx = (j+1)%pn.size(); + // on edge {p, q} + else if (Sign(w, NEAR_EDGE_TOL) == 0) + loc.e_idx = j; + + break; + } + } + } + + if (!found) { + write_ngon("bin", pf); + point_write("lost", x, y, z); + } + + assert(found); + } + + return ploc; +} diff --git a/Cassiopee/XCore/XCore/intersectMesh/smesh_refine.cpp b/Cassiopee/XCore/XCore/intersectMesh/smesh_refine.cpp index 77df08246..2bff6930a 100644 --- a/Cassiopee/XCore/XCore/intersectMesh/smesh_refine.cpp +++ b/Cassiopee/XCore/XCore/intersectMesh/smesh_refine.cpp @@ -18,6 +18,13 @@ */ #include "smesh.h" +void Smesh::update_plocs(const std::vector &fparents, + std::vector &plocs) +{ + // Children to update: fchildren[fparent].back(); + assert(0); +} + void Smesh::refine_edge(const u_edge &e) { E_Int p = e.p; @@ -31,6 +38,20 @@ void Smesh::refine_edge(const u_edge &e) np++; } +inline +void Smesh::compute_face_center(E_Int fid) +{ + E_Float *fc = &fcenters[3*fid]; + fc[0] = fc[1] = fc[2] = 0; + const auto &pn = F[fid]; + for (E_Int p : pn) { + fc[0] += X[p]; + fc[1] += Y[p]; + fc[2] += Z[p]; + } + for (E_Int i = 0; i < 3; i++) fc[i] /= pn.size(); +} + void Smesh::refine_tri(E_Int fid) { std::vector nodes(F[fid]); @@ -56,6 +77,22 @@ void Smesh::refine_tri(E_Int fid) F[nf] = {ec[0], nodes[1], ec[1]}; F[nf+1] = {ec[2], ec[1], nodes[2]}; F[nf+2] = {ec[0], ec[1], ec[2]}; + + Fc[fid] = F[fid]; + Fc[nf] = F[nf]; + Fc[nf+1] = F[nf+1]; + Fc[nf+2] = F[nf+2]; + + const E_Float *N = &fnormals[3*fid]; + for (E_Int i = 0; i < 3; i++) { + E_Float *fN = &fnormals[3*(nf+i)]; + for (E_Int j = 0; j < 3; j++) fN[j] = N[j]; + } + + compute_face_center(fid); + for (E_Int i = 0; i < 3; i++) compute_face_center(nf+i); + + nf += 3; } void Smesh::resize_for_refinement(size_t nref_faces) @@ -63,19 +100,19 @@ void Smesh::resize_for_refinement(size_t nref_faces) E_Int fincr = nref_faces * 3; E_Int pincr = nref_faces * 3; F.resize(nf + fincr); - X.resize(np + pincr); - Y.resize(np + pincr); - Z.resize(np + pincr); + Fc.resize(nf + fincr); + X.resize(np + pincr, EFLOATMAX); + Y.resize(np + pincr, EFLOATMAX); + Z.resize(np + pincr, EFLOATMAX); + fnormals.resize(3*(nf + fincr), EFLOATMAX); + fcenters.resize(3*(nf + fincr), EFLOATMAX); } -void Smesh::refine(const std::map> &sensor) +void Smesh::refine(const std::vector &ref_faces) { - size_t nref = sensor.size(); - - while (nref > 0) { - resize_for_refinement(nref); - nref = 0; - } + resize_for_refinement(ref_faces.size()); + for (E_Int fid : ref_faces) + refine_tri(fid); } void Smesh::get_leaves(E_Int fid, std::vector &leaves) const diff --git a/Cassiopee/XCore/XCore/intersectMesh/trace.cpp b/Cassiopee/XCore/XCore/intersectMesh/trace.cpp index 2b188835b..ffd8840c1 100644 --- a/Cassiopee/XCore/XCore/intersectMesh/trace.cpp +++ b/Cassiopee/XCore/XCore/intersectMesh/trace.cpp @@ -87,7 +87,7 @@ E_Int Smesh::deduce_face(const std::vector &pf, E_Float proj[3]; get_unit_projected_direction(fid, D, proj); - const auto &pn = F[fid]; + const auto &pn = Fc[fid]; const auto &pe = F2E[fid]; assert(pn.size() == pe.size()); @@ -137,6 +137,8 @@ void Smesh::get_shared_faces(const PointLoc &loc, std::vector &ret, E_Int fid = loc.fid; assert(fid != -1); + // TODO(Imad): e_idx is no good!!!! + if (loc.e_idx != -1) { assert(loc.v_idx == -1); const auto &pe = F2E[fid]; @@ -149,7 +151,7 @@ void Smesh::get_shared_faces(const PointLoc &loc, std::vector &ret, } else if (loc.v_idx != -1) { assert(loc.e_idx == -1); - const auto &pn = F[fid]; + const auto &pn = Fc[fid]; pid = pn[loc.v_idx]; const auto &pf = P2F[pid]; // For consistency diff --git a/Cassiopee/XCore/srcs.py b/Cassiopee/XCore/srcs.py index ea31b7739..2b2bb64ac 100644 --- a/Cassiopee/XCore/srcs.py +++ b/Cassiopee/XCore/srcs.py @@ -25,10 +25,10 @@ 'XCore/intersectMesh/icapsule_refine.cpp', 'XCore/intersectMesh/triangulate.cpp', - 'XCore/intersectMesh/locate.cpp', 'XCore/intersectMesh/sgraph.cpp', 'XCore/intersectMesh/smesh.cpp', + 'XCore/intersectMesh/smesh_locate.cpp', 'XCore/intersectMesh/smesh_io.cpp', 'XCore/intersectMesh/smesh_refine.cpp', 'XCore/intersectMesh/smesh_extract.cpp', From d46a5324fc3ce2a503c2f40bc8e4ded3ddbd6de3 Mon Sep 17 00:00:00 2001 From: imadhammani Date: Wed, 16 Oct 2024 18:28:25 +0200 Subject: [PATCH 61/86] XCore intersectMesh: improved refinement loop --- .../XCore/XCore/intersectMesh/icapsule.cpp | 13 +- .../XCore/intersectMesh/icapsule_refine.cpp | 128 +++++++++++++----- Cassiopee/XCore/XCore/intersectMesh/ray.cpp | 50 +++---- Cassiopee/XCore/XCore/intersectMesh/smesh.h | 9 +- .../XCore/intersectMesh/smesh_locate.cpp | 28 ++-- 5 files changed, 146 insertions(+), 82 deletions(-) diff --git a/Cassiopee/XCore/XCore/intersectMesh/icapsule.cpp b/Cassiopee/XCore/XCore/intersectMesh/icapsule.cpp index 1687c2164..94d188363 100644 --- a/Cassiopee/XCore/XCore/intersectMesh/icapsule.cpp +++ b/Cassiopee/XCore/XCore/intersectMesh/icapsule.cpp @@ -344,6 +344,9 @@ ICapsule::ICapsule(const Karray &marray, const std::vector &sarrays, bfaces_list.reserve(sarrays.size()); for (size_t i = 0; i < sarrays.size(); i++) { + + printf("S%lu\n", i); + // Create IMesh S IMesh S(sarrays[i]); S.set_tolerances(NEAR_VERTEX_TOL, NEAR_EDGE_TOL); @@ -361,7 +364,7 @@ ICapsule::ICapsule(const Karray &marray, const std::vector &sarrays, // Locate Sf points on Mf faces auto plocs = Mf.locate(Sf); - Mf.correct_near_points_and_edges(Sf, plocs); + //Mf.correct_near_points_and_edges(Sf, plocs); // Correct AABB and Sf faces hash Sf.make_bbox(); @@ -369,15 +372,23 @@ ICapsule::ICapsule(const Karray &marray, const std::vector &sarrays, // Extract the initial Mf faces that bound Sf auto bfaces = Mf.extract_bounding_faces(Sf, plocs); + //Mf.write_ngon("bounding_before", bfaces); + + //Sf.write_ngon("Sf"); // Refinement loop refine(Mf, bfaces, Sf, plocs); + //bfaces = Mf.extract_bounding_faces(Sf, plocs); + //Mf.write_ngon("bounding_after", bfaces); + // Add Sf spatches.push_back(Sf); // Add plocs plocs_list.push_back(plocs); + + puts(""); } Mf.write_ngon("refined_Mf"); diff --git a/Cassiopee/XCore/XCore/intersectMesh/icapsule_refine.cpp b/Cassiopee/XCore/XCore/intersectMesh/icapsule_refine.cpp index e31c24a4a..782817b3a 100644 --- a/Cassiopee/XCore/XCore/intersectMesh/icapsule_refine.cpp +++ b/Cassiopee/XCore/XCore/intersectMesh/icapsule_refine.cpp @@ -2,12 +2,13 @@ #include "ray.h" #include "BVH.h" #include "io.h" +#include "primitives.h" // Returns a list of all the intersections, forwards and backwards // Up to the caller to parse the data void Smesh::ray_BVH_intersect(E_Float ox, E_Float oy, E_Float oz, E_Float dx, E_Float dy, E_Float dz, BVH_node *node, - std::vector &plocs) + std::vector &plocs) const { bool hit = ray_AABB_intersect(ox, oy, oz, dx, dy, dz, node->box); if (!hit) return; @@ -15,23 +16,49 @@ void Smesh::ray_BVH_intersect(E_Float ox, E_Float oy, E_Float oz, if (!node->left && !node->right) { for (E_Int i = node->start; i < node->end; i++) { E_Int fid = bvh_indices[i]; - const auto &pn = F[fid]; - E_Int a = pn[0], b = pn[1], c = pn[2]; - E_Float u, v, w, t, x, y, z; - bool hit = MollerTrumboreAnyDir(ox, oy, oz, dx, dy, dz, - X[a], Y[a], Z[a], X[b], Y[b], Z[b], X[c], Y[c], Z[c], - u, v, w, t, x, y, z); - if (hit) { - PointLoc ploc; - ploc.fid = fid; - ploc.bcrd[0] = u; - ploc.bcrd[1] = v; - ploc.bcrd[2] = w; - ploc.t = t; - ploc.x = x; - ploc.y = y; - ploc.z = z; - plocs.push_back(ploc); + const auto &pn = Fc[fid]; + const E_Float *fc = &fcenters[3*fid]; + + for (size_t j = 0; j < pn.size(); j++) { + E_Int p = pn[j]; + E_Int q = pn[(j+1)%pn.size()]; + + E_Float u, v, w, t, x, y, z; + + bool hit = MollerTrumboreAnyDir( + ox, oy, oz, dx, dy, dz, + X[p], Y[p], Z[p], + X[q], Y[q], Z[q], + fc[0], fc[1], fc[2], + u, v, w, t, x, y, z + ); + + if (hit) { + PointLoc ploc; + ploc.fid = fid; + ploc.sub = j; + ploc.bcrd[0] = u; + ploc.bcrd[1] = v; + ploc.bcrd[2] = w; + ploc.t = t; + ploc.x = x; + ploc.y = y; + ploc.z = z; + + // on p + if (Sign(1-u, NEAR_VERTEX_TOL) == 0) + ploc.v_idx = j; + // on q + else if (Sign(1-v, NEAR_VERTEX_TOL) == 0) + ploc.v_idx = (j+1)%pn.size(); + // on edge {p, q} + else if (Sign(w, NEAR_EDGE_TOL) == 0) + ploc.e_idx = j; + + plocs.push_back(ploc); + + break; + } } } return; @@ -44,7 +71,7 @@ void Smesh::ray_BVH_intersect(E_Float ox, E_Float oy, E_Float oz, std::vector projections; void Smesh::project(const Smesh &Mf, const std::vector &mpids, - std::vector &plocs) + std::vector &plocs) const { for (size_t i = 0; i < mpids.size(); i++) { E_Int mpid = mpids[i]; @@ -62,11 +89,7 @@ void Smesh::project(const Smesh &Mf, const std::vector &mpids, for (const auto &mloc : mlocs) { if (fabs(mloc.t) < min_abs_t) { min_abs_t = fabs(mloc.t); - ploc.fid = mloc.fid; - ploc.t = mloc.t; - ploc.x = mloc.x; - ploc.y = mloc.y; - ploc.z = mloc.z; + ploc = mloc; } } if (ploc.fid != -1) { @@ -75,8 +98,27 @@ void Smesh::project(const Smesh &Mf, const std::vector &mpids, } } -static -std::vector deduce_ref_faces(const std::vector &mpids, +void Smesh::project_and_replace(Smesh &Mf, E_Int start) const +{ + E_Int NP = Mf.np - start; + std::vector pids(NP); + for (E_Int i = 0; i < NP; i++) pids[i] = start+i; + + std::vector plocs(NP); + + project(Mf, pids, plocs); + + // Replace + for (E_Int i = 0; i < NP; i++) { + assert(plocs[i].fid != -1); + E_Int pid = pids[i]; + Mf.X[pid] = plocs[i].x; + Mf.Y[pid] = plocs[i].y; + Mf.Z[pid] = plocs[i].z; + } +} + +std::vector Smesh::deduce_ref_faces(const std::vector &mpids, const std::vector &plocs_m, const Smesh &Mf, std::vector &ref_faces) { @@ -85,7 +127,13 @@ std::vector deduce_ref_faces(const std::vector &mpids, for (size_t i = 0; i < mpids.size(); i++) { const auto &ploc_m = plocs_m[i]; if (ploc_m.fid == -1) continue; - smap[ploc_m.fid].push_back(mpids[i]); + + std::vector sfids; + E_Int dummy; + get_shared_faces(ploc_m, sfids, dummy, dummy); + + for (E_Int sfid : sfids) + smap[sfid].push_back(mpids[i]); } std::map> sfid_to_mfids; @@ -133,12 +181,12 @@ void ICapsule::refine(Smesh &Mf, std::set &mfids, Smesh &Sf, std::vector fat_sfids; std::vector fat_mfids; + + Sf.make_BVH(); + Mf.make_BVH(); /*********************** Sf refinement ***********************/ - // Construct the BVH of Sf - Sf.make_BVH(); - // Isolate the points to project std::set mpids_set; for (E_Int fid : mfids) { @@ -151,11 +199,10 @@ void ICapsule::refine(Smesh &Mf, std::set &mfids, Smesh &Sf, // Project mpids on Sf std::vector plocs_m(mpids.size()); Sf.project(Mf, mpids, plocs_m); - Sf.destroy_BVH(Sf.bvh_root); // Deduce sfids to refine std::vector sref_faces; - deduce_ref_faces(mpids, plocs_m, Mf, sref_faces); + Sf.deduce_ref_faces(mpids, plocs_m, Mf, sref_faces); for (const E_Int sfid : sref_faces) { fat_sfids.push_back(sfid); @@ -164,11 +211,18 @@ void ICapsule::refine(Smesh &Mf, std::set &mfids, Smesh &Sf, ref_S = sref_faces.size(); if (ref_S > 0) { + // Cache the number of points before refinement + E_Int NP = Sf.np; Sf.refine(sref_faces); Sf.conformize(); Sf.hash_faces(); Sf.make_pnormals(); + Mf.project_and_replace(Sf, NP); + //Sf.write_ngon("refined_Sf"); } + + plocs_s = Mf.locate(Sf); + /*********************** Mf refinement ***********************/ @@ -179,7 +233,7 @@ void ICapsule::refine(Smesh &Mf, std::set &mfids, Smesh &Sf, // Deduce mfids to refine std::vector mref_faces; - deduce_ref_faces(spids, plocs_s, Sf, mref_faces); + Mf.deduce_ref_faces(spids, plocs_s, Sf, mref_faces); for (const E_Int mfid : mref_faces) { fat_mfids.push_back(mfid); @@ -197,9 +251,11 @@ void ICapsule::refine(Smesh &Mf, std::set &mfids, Smesh &Sf, const auto &children = Mf.fchildren[fparent].back(); for (E_Int child : children) mfids.insert(child); } - plocs_s = Mf.locate(Sf); } + + Mf.destroy_BVH(Mf.bvh_root); + Sf.destroy_BVH(Sf.bvh_root); } while (ref_M > 0 || ref_S > 0); - point_write("projections", projections); -} \ No newline at end of file + //point_write("projections", projections); +} diff --git a/Cassiopee/XCore/XCore/intersectMesh/ray.cpp b/Cassiopee/XCore/XCore/intersectMesh/ray.cpp index a48a72191..8b8cdbff2 100644 --- a/Cassiopee/XCore/XCore/intersectMesh/ray.cpp +++ b/Cassiopee/XCore/XCore/intersectMesh/ray.cpp @@ -89,7 +89,7 @@ bool ray_AABB_intersect(E_Float ox, E_Float oy, E_Float oz, } bool MollerTrumboreAnyDir( - E_Float px, E_Float py, E_Float pz, + E_Float ox, E_Float oy, E_Float oz, E_Float dx, E_Float dy, E_Float dz, E_Float ax, E_Float ay, E_Float az, E_Float bx, E_Float by, E_Float bz, @@ -97,49 +97,33 @@ bool MollerTrumboreAnyDir( E_Float &u, E_Float &v, E_Float &w, E_Float &t, E_Float &x, E_Float &y, E_Float &z) { - E_Float e1x = bx - ax; - E_Float e1y = by - ay; - E_Float e1z = bz - az; - - E_Float e2x = cx - ax; - E_Float e2y = cy - ay; - E_Float e2z = cz - az; - - E_Float pvecx = dy * e2z - dz * e2y; - E_Float pvecy = dz * e2x - dx * e2z; - E_Float pvecz = dx * e2y - dy * e2x; - - E_Float det = e1x * pvecx + e1y * pvecy + e1z * pvecz; + E_Float v1[3] = {bx-ax, by-ay, bz-az}; + E_Float v2[3] = {cx-ax, cy-ay, cz-az}; - if (det > -TOL && det < TOL) return false; + E_Float d[3] = {dx, dy, dz}; + E_Float h[3]; + K_MATH::cross(d, v2, h); + E_Float det = K_MATH::dot(v1, h, 3); + if (Sign(det) == 0) return false; E_Float inv_det = 1.0 / det; - E_Float tvecx = px - ax; - E_Float tvecy = py - ay; - E_Float tvecz = pz - az; - - u = inv_det * (tvecx * pvecx + tvecy * pvecy + tvecz * pvecz); - + E_Float s[3] = {ox-ax, oy-ay, oz-az}; + u = K_MATH::dot(s, h, 3) * inv_det; if (u < -TOL || u > 1+TOL) return false; - E_Float qvecx = tvecy * e1z - tvecz * e1y; - E_Float qvecy = tvecz * e1x - tvecx * e1z; - E_Float qvecz = tvecx * e1y - tvecy * e1x; - - v = inv_det * (dx * qvecx + dy * qvecy + dz * qvecz); - + E_Float q[3]; + K_MATH::cross(s, v1, q); + v = K_MATH::dot(d, q, 3) * inv_det; if (v < -TOL || v > 1+TOL) return false; w = 1 - u - v; - if (w < -TOL || w > 1+TOL) return false; - t = inv_det * (e2x * qvecx + e2y * qvecy + e2z * qvecz); - - x = px + t * dx; - y = py + t * dy; - z = pz + t * dz; + t = K_MATH::dot(v2, q, 3) * inv_det; + x = ox + t * dx; + y = oy + t * dy; + z = oz + t * dz; return true; } diff --git a/Cassiopee/XCore/XCore/intersectMesh/smesh.h b/Cassiopee/XCore/XCore/intersectMesh/smesh.h index ec9fcdae1..e85a0eeac 100644 --- a/Cassiopee/XCore/XCore/intersectMesh/smesh.h +++ b/Cassiopee/XCore/XCore/intersectMesh/smesh.h @@ -110,10 +110,11 @@ struct Smesh { E_Float proj[3]) const; void compute_min_distance_between_points(); void project(const Smesh &Mf, const std::vector &mpids, - std::vector &plocs); + std::vector &plocs) const; + void project_and_replace(Smesh &Mf, E_Int start) const; void ray_BVH_intersect(E_Float ox, E_Float oy, E_Float oz, E_Float dx, E_Float dy, E_Float dz, BVH_node *node, - std::vector &plocs); + std::vector &plocs) const; inline void compute_face_center(E_Int fid); // Hash @@ -155,7 +156,9 @@ struct Smesh { void conformize(); void get_edge_centers(E_Int p, E_Int q, std::list &edge_centers, E_Int left_right); - + std::vector deduce_ref_faces(const std::vector &mpids, + const std::vector &plocs_m, const Smesh &Mf, + std::vector &ref_faces); // Topology diff --git a/Cassiopee/XCore/XCore/intersectMesh/smesh_locate.cpp b/Cassiopee/XCore/XCore/intersectMesh/smesh_locate.cpp index 1ed85c9ea..7a07ec362 100644 --- a/Cassiopee/XCore/XCore/intersectMesh/smesh_locate.cpp +++ b/Cassiopee/XCore/XCore/intersectMesh/smesh_locate.cpp @@ -107,25 +107,35 @@ std::vector Smesh::locate(const Smesh &Sf) const bool found = false; - // w, u, v auto &loc = ploc[pid]; + /* + if (pid == 371) + point_write("lost", x, y, z); + */ + for (size_t i = 0; i < pf.size() && !found; i++) { E_Int fid = pf[i]; const auto &pn = Fc[fid]; const E_Float *fc = &fcenters[3*fid]; - //point_write("o", fc[0], fc[1], fc[2]); - //std::vector dummy; - //dummy.push_back(fid); - //write_ngon("fid", dummy); - + /* + if (pid == 371) { + write_face("fid", fid); + point_write("fc", fc[0], fc[1], fc[2]); + } + */ + for (size_t j = 0; j < pn.size(); j++) { E_Int p = pn[j]; E_Int q = pn[(j+1)%pn.size()]; - //point_write("p", X[p], Y[p], Z[p]); - //point_write("q", X[q], Y[q], Z[q]); + /* + if (pid == 371) { + point_write("p", X[p], Y[p], Z[p]); + point_write("q", X[q], Y[q], Z[q]); + } + */ E_Float u, v, w; @@ -159,8 +169,8 @@ std::vector Smesh::locate(const Smesh &Sf) const } if (!found) { - write_ngon("bin", pf); point_write("lost", x, y, z); + write_ngon("bin", pf); } assert(found); From 03868a576f6e0209bd927ac7ebd2996fde2cb92d Mon Sep 17 00:00:00 2001 From: imadhammani Date: Thu, 17 Oct 2024 18:37:26 +0200 Subject: [PATCH 62/86] XCore intersectMesh: starting reworking Dcel --- Cassiopee/XCore/XCore/intersectMesh/cycle.cpp | 64 - Cassiopee/XCore/XCore/intersectMesh/cycle.h | 46 - Cassiopee/XCore/XCore/intersectMesh/dcel.cpp | 1122 +++++------------ Cassiopee/XCore/XCore/intersectMesh/dcel.h | 128 +- .../intersectMesh/{cut.cpp => dcel_cut.cpp} | 2 - .../XCore/intersectMesh/dcel_extract.cpp | 69 + .../XCore/XCore/intersectMesh/dcel_io.cpp | 221 ++++ .../{trace.cpp => dcel_trace.cpp} | 165 +-- Cassiopee/XCore/XCore/intersectMesh/event.cpp | 52 - Cassiopee/XCore/XCore/intersectMesh/event.h | 41 - Cassiopee/XCore/XCore/intersectMesh/face.cpp | 27 - Cassiopee/XCore/XCore/intersectMesh/face.h | 31 - Cassiopee/XCore/XCore/intersectMesh/hedge.cpp | 148 --- Cassiopee/XCore/XCore/intersectMesh/hedge.h | 58 - .../XCore/XCore/intersectMesh/icapsule.cpp | 343 +---- .../XCore/intersectMesh/intersectMesh.cpp | 77 +- Cassiopee/XCore/XCore/intersectMesh/io.cpp | 121 +- Cassiopee/XCore/XCore/intersectMesh/io.h | 26 +- Cassiopee/XCore/XCore/intersectMesh/mesh.h | 2 +- Cassiopee/XCore/XCore/intersectMesh/point.h | 6 +- .../prepareMeshesForIntersection.cpp | 7 +- .../XCore/XCore/intersectMesh/primitives.cpp | 324 +---- .../XCore/XCore/intersectMesh/primitives.h | 40 +- .../XCore/XCore/intersectMesh/project.cpp | 20 - Cassiopee/XCore/XCore/intersectMesh/queue.cpp | 181 --- Cassiopee/XCore/XCore/intersectMesh/queue.h | 65 - Cassiopee/XCore/XCore/intersectMesh/ray.cpp | 29 +- Cassiopee/XCore/XCore/intersectMesh/ray.h | 9 +- .../XCore/XCore/intersectMesh/segment.cpp | 120 -- Cassiopee/XCore/XCore/intersectMesh/segment.h | 49 - .../XCore/XCore/intersectMesh/sgraph.cpp | 87 -- Cassiopee/XCore/XCore/intersectMesh/smesh.cpp | 85 +- Cassiopee/XCore/XCore/intersectMesh/smesh.h | 13 +- .../XCore/intersectMesh/smesh_extract.cpp | 298 ++++- .../XCore/XCore/intersectMesh/smesh_geom.cpp | 83 ++ .../XCore/intersectMesh/smesh_locate.cpp | 46 + Cassiopee/XCore/XCore/intersectMesh/snode.cpp | 32 - Cassiopee/XCore/XCore/intersectMesh/snode.h | 40 - .../XCore/XCore/intersectMesh/status.cpp | 230 ---- Cassiopee/XCore/XCore/intersectMesh/status.h | 60 - .../XCore/XCore/intersectMesh/triangle.h | 16 +- .../intersectMesh/triangleIntersection.h | 33 - Cassiopee/XCore/XCore/intersectMesh/vec3.cpp | 67 - Cassiopee/XCore/XCore/intersectMesh/vec3.h | 42 - .../XCore/XCore/intersectMesh/vertex.cpp | 39 - Cassiopee/XCore/XCore/intersectMesh/vertex.h | 50 - Cassiopee/XCore/srcs.py | 25 +- 47 files changed, 1326 insertions(+), 3513 deletions(-) delete mode 100644 Cassiopee/XCore/XCore/intersectMesh/cycle.cpp delete mode 100644 Cassiopee/XCore/XCore/intersectMesh/cycle.h rename Cassiopee/XCore/XCore/intersectMesh/{cut.cpp => dcel_cut.cpp} (98%) create mode 100644 Cassiopee/XCore/XCore/intersectMesh/dcel_extract.cpp create mode 100644 Cassiopee/XCore/XCore/intersectMesh/dcel_io.cpp rename Cassiopee/XCore/XCore/intersectMesh/{trace.cpp => dcel_trace.cpp} (65%) delete mode 100644 Cassiopee/XCore/XCore/intersectMesh/event.cpp delete mode 100644 Cassiopee/XCore/XCore/intersectMesh/event.h delete mode 100644 Cassiopee/XCore/XCore/intersectMesh/face.cpp delete mode 100644 Cassiopee/XCore/XCore/intersectMesh/face.h delete mode 100644 Cassiopee/XCore/XCore/intersectMesh/hedge.cpp delete mode 100644 Cassiopee/XCore/XCore/intersectMesh/hedge.h delete mode 100644 Cassiopee/XCore/XCore/intersectMesh/project.cpp delete mode 100644 Cassiopee/XCore/XCore/intersectMesh/queue.cpp delete mode 100644 Cassiopee/XCore/XCore/intersectMesh/queue.h delete mode 100644 Cassiopee/XCore/XCore/intersectMesh/segment.cpp delete mode 100644 Cassiopee/XCore/XCore/intersectMesh/segment.h delete mode 100644 Cassiopee/XCore/XCore/intersectMesh/sgraph.cpp create mode 100644 Cassiopee/XCore/XCore/intersectMesh/smesh_geom.cpp delete mode 100644 Cassiopee/XCore/XCore/intersectMesh/snode.cpp delete mode 100644 Cassiopee/XCore/XCore/intersectMesh/snode.h delete mode 100644 Cassiopee/XCore/XCore/intersectMesh/status.cpp delete mode 100644 Cassiopee/XCore/XCore/intersectMesh/status.h delete mode 100644 Cassiopee/XCore/XCore/intersectMesh/triangleIntersection.h delete mode 100644 Cassiopee/XCore/XCore/intersectMesh/vec3.cpp delete mode 100644 Cassiopee/XCore/XCore/intersectMesh/vec3.h delete mode 100644 Cassiopee/XCore/XCore/intersectMesh/vertex.cpp delete mode 100644 Cassiopee/XCore/XCore/intersectMesh/vertex.h diff --git a/Cassiopee/XCore/XCore/intersectMesh/cycle.cpp b/Cassiopee/XCore/XCore/intersectMesh/cycle.cpp deleted file mode 100644 index cb42b71da..000000000 --- a/Cassiopee/XCore/XCore/intersectMesh/cycle.cpp +++ /dev/null @@ -1,64 +0,0 @@ -/* - Copyright 2013-2024 Onera. - - This file is part of Cassiopee. - - Cassiopee is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - Cassiopee is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with Cassiopee. If not, see . -*/ -#include -#include -#include -#include - -#include "cycle.h" -#include "dcel.h" -#include "hedge.h" -#include "primitives.h" - -E_Int Cycle::INNER = 0; -E_Int Cycle::OUTER = 1; -E_Int Cycle::DEGEN = 2; - -Cycle::Cycle(Hedge *Rep) -: rep(Rep), inout(Dcel::NO_IDEA), left(NULL), prev(NULL), next(NULL) -{} - -void Cycle::write_vertices(const char *fname, const std::vector &C) -{ - FILE *fh = fopen(fname, "w"); - assert(fh); - - std::set V; - for (Cycle *c : C) { - Hedge *h = c->rep; - Vertex *v = h->orig; - if (V.find(v) == V.end()) V.insert(v); - - Hedge *w = h->next; - while (w != h) { - v = w->orig; - if (V.find(v) == V.end()) V.insert(v); - w = w->next; - } - } - - fprintf(fh, "POINTS\n"); - fprintf(fh, "%zu\n", V.size()); - for (const auto &v : V) { - fprintf(fh, "%f %f %f\n", v->x, v->y, v->z); - } - - - fclose(fh); -} diff --git a/Cassiopee/XCore/XCore/intersectMesh/cycle.h b/Cassiopee/XCore/XCore/intersectMesh/cycle.h deleted file mode 100644 index 3db2493d2..000000000 --- a/Cassiopee/XCore/XCore/intersectMesh/cycle.h +++ /dev/null @@ -1,46 +0,0 @@ -/* - Copyright 2013-2024 Onera. - - This file is part of Cassiopee. - - Cassiopee is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - Cassiopee is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with Cassiopee. If not, see . -*/ -#pragma once - -#include - -#include "xcore.h" -#include "common/common.h" - -struct Hedge; -struct Vertex; - -struct Cycle { - Hedge *rep; - E_Int inout; - Vertex *left; - Cycle *prev; - Cycle *next; - - static E_Int INNER; - static E_Int OUTER; - static E_Int DEGEN; - - Cycle(Hedge *Rep); - void print() const; - - static void set_inout(std::vector &C); - - static void write_vertices(const char *fname, const std::vector &C); -}; \ No newline at end of file diff --git a/Cassiopee/XCore/XCore/intersectMesh/dcel.cpp b/Cassiopee/XCore/XCore/intersectMesh/dcel.cpp index b85e449c4..7ad7d050f 100644 --- a/Cassiopee/XCore/XCore/intersectMesh/dcel.cpp +++ b/Cassiopee/XCore/XCore/intersectMesh/dcel.cpp @@ -22,449 +22,83 @@ #include #include "dcel.h" -#include "status.h" -#include "segment.h" #include "primitives.h" #include "io.h" -#include "hedge.h" #include "smesh.h" -#include "event.h" -#include "face.h" -#include "cycle.h" #include "triangle.h" -Smesh Dcel::export_smesh(bool is_planar) const +Dcel::Dcel(const Smesh &Mf, E_Int color) { - Smesh smesh; - smesh.is_planar = is_planar; - - smesh.np = V.size(); - smesh.X.resize(smesh.np); - smesh.Y.resize(smesh.np); - smesh.Z.resize(smesh.np); - - for (Vertex *v : V) { - smesh.X[v->id] = v->x; - smesh.Y[v->id] = v->y; - smesh.Z[v->id] = v->z; - } - - for (size_t i = 0; i < F.size(); i++) { - Face *f = F[i]; - Hedge *REP = f->rep; - Cycle *c = REP->cycle; - if (c->inout != Cycle::OUTER) continue; - Hedge *h = REP; - - std::vector pn; - - do { - Vertex *v = h->orig; - pn.push_back(v->id); - h = h->next; - } while (h != REP); - - smesh.F.push_back(pn); - } - - smesh.nf = (E_Int)smesh.F.size(); - - smesh.Fc = smesh.F; - - smesh.make_edges(); - - return smesh; -} - -E_Int Dcel::RED = 0; -E_Int Dcel::BLACK = 1; -E_Int Dcel::NO_IDEA = 2; - -void Dcel::write_degen_faces(const char *fname) -{ - auto degen_indices = extract_indices_of_type(Cycle::DEGEN); - auto degen_faces = extract_faces_of_indices(degen_indices); - write_ngon(fname, degen_faces); -} - -void Dcel::write_outer_faces(const char *fname) -{ - auto outer_indices = extract_indices_of_type(Cycle::OUTER); - auto outer_faces = extract_faces_of_indices(outer_indices); - write_ngon(fname, outer_faces); -} - -void Dcel::write_inner_faces(const char *fname) -{ - auto inner_indices = extract_indices_of_type(Cycle::INNER); - auto inner_faces = extract_faces_of_indices(inner_indices); - write_ngon(fname, inner_faces); -} - -void Dcel::write_ngon(const char *fname, const std::vector &faces) const -{ - FILE *fh = fopen(fname, "w"); - assert(fh); - - E_Int np = 0; - E_Int ne = 0; - E_Int nf = (E_Int)faces.size(); - - std::map vmap; - std::vector new_pids; - - for (Face *f : faces) { - Hedge *h = f->rep; - ne++; - Vertex *p = h->orig; - if (vmap.find(p) == vmap.end()) { - vmap[p] = np++; - new_pids.push_back(p); - } - Hedge *w = h->next; - while (w != h) { - p = w->orig; - if (vmap.find(p) == vmap.end()) { - vmap[p] = np++; - new_pids.push_back(p); - } - ne++; - w = w->next; - } - } - - fprintf(fh, "POINTS\n"); - fprintf(fh, SF_D_ "\n", np); - for (const auto &v : new_pids) { - fprintf(fh, "%f %f %f\n", v->x, v->y, v->z); - } - - fprintf(fh, "INDPG\n"); - fprintf(fh, SF_D_ "\n", ne+1); - E_Int sizeNGon = 0; - fprintf(fh, SF_D_ " ", sizeNGon); - for (E_Int i = 0; i < ne; i++) { - sizeNGon += 2; - fprintf(fh, SF_D_ " ", sizeNGon); - } - assert(sizeNGon == 2*ne); - fprintf(fh, "\n"); - - fprintf(fh, "NGON\n"); - fprintf(fh, SF_D_ "\n", sizeNGon); - for (Face *f : faces) { - Hedge *h = f->rep; - Vertex *p = h->orig; - Vertex *q = h->twin->orig; - fprintf(fh, SF_D_ " " SF_D_ " ", vmap[p], vmap[q]); - Hedge *w = h->next; - while (w != h) { - p = w->orig; - q = w->twin->orig; - fprintf(fh, SF_D_ " " SF_D_ " ", vmap[p], vmap[q]); - w = w->next; - } - } - fprintf(fh, "\n"); - - fprintf(fh, "INDPH\n"); - fprintf(fh, SF_D_ "\n", nf+1); - E_Int sizeNFace = 0; - fprintf(fh, SF_D_ " ", sizeNFace); - for (Face *f : faces) { - Hedge *h = f->rep; - sizeNFace += 1; - Hedge *w = h->next; - while (w != h) { - assert(w->left == f); - sizeNFace += 1; - w = w->next; - } - fprintf(fh, SF_D_ " ", sizeNFace); - } - fprintf(fh, "\n"); - - fprintf(fh, "NFACE\n"); - fprintf(fh, SF_D_ "\n", sizeNFace); - for (E_Int i = 0; i < sizeNFace; i++) - fprintf(fh, SF_D_ " ", i); - - fclose(fh); -} - -std::vector Dcel::extract_faces_of_indices( - const std::vector &indices) -{ - std::vector ret; - ret.reserve(indices.size()); - - for (E_Int index : indices) ret.push_back(F[index]); - - return ret; -} - -std::vector Dcel::extract_indices_of_type(E_Int type) -{ - std::vector ret; + const auto &X = Mf.X; + const auto &Y = Mf.Y; + const auto &Z = Mf.Z; - for (size_t i = 0; i < C.size(); i++) { - if (C[i]->inout == type) - ret.push_back(i); + V.reserve(Mf.np); + for (E_Int pid = 0; pid < Mf.np; pid++) { + Vertex *v = new Vertex(X[pid], Y[pid], Z[pid]); + v->oids[color] = pid; + V.push_back(v); } - return ret; -} + init_hedges_and_faces(Mf, color); -void Dcel::update_hedge_faces(const std::vector &F) -{ - for (Face *f : F) { - Hedge *h = f->rep; - h->left = f; - Hedge *w = h->next; - while (w != h) { - w->left = f; - w = w->next; - } + if (check_hedges(H) != 0) { + fprintf(stderr, "Dcel: Inconsistent half-edge records!\n"); + abort(); } -} -std::vector Dcel::make_cycle_faces(const std::vector &C) -{ - std::vector new_F; - - for (Cycle *c : C) { - - // Create a face record - Face *f = new Face; - - // Set its rep hedge to some edge of the cycle - Hedge *h = c->rep; - f->rep = h; - - new_F.push_back(f); + if (check_faces(H, F) != 0) { + fprintf(stderr, "Dcel: Inconsistent face records!\n"); + abort(); } - return new_F; -} - -void Dcel::set_face_labels(std::vector &F) -{ - // Label each face with the ids of the original faces containing it - - for (size_t i = 0; i < F.size(); i++) { - Face *f = F[i]; - - // Get the first RED and BLACK half-edges in the face cycle. - Hedge *h = f->rep; - - Hedge *R = NULL; - Hedge *B = NULL; - E_Int RB = 0; - - if (h->color == Dcel::RED) { - R = h; - B = get_hedge_of_color(f, Dcel::BLACK); - if (B) RB = 1; - } else if (h->color == Dcel::BLACK) { - B = h; - R = get_hedge_of_color(f, Dcel::RED); - if (R) RB = 1; - } else { - assert(0); - } - - if (RB) { - // First case: R and B both exist - assert(R->left); - assert(B->left); - assert(R->color == Dcel::RED); - assert(B->color == Dcel::BLACK); - f->oid[Dcel::RED] = R->left->oid[Dcel::RED]; - f->oid[Dcel::BLACK] = B->left->oid[Dcel::BLACK]; - } else { - // Second case: the face is single color - // Only single color possible is RED, otherwise intersection problem - // is ill-posed - Hedge *REP = (R != NULL) ? R : B; - if (REP != R) { - hedge_write("black", REP); - } - assert(REP == R); - assert(REP->color == Dcel::RED); - assert(REP->left); - f->oid[REP->color] = REP->left->oid[REP->color]; - } - } -} - -Hedge *Dcel::get_hedge_of_color(Face *f, E_Int color) -{ - Hedge *h = f->rep; - if (h->color == color) return h; - Hedge *w = h->next; - while (w != h) { - if (w->color == color) return w; - w = w->next; - } - return NULL; -} - -void Dcel::make_cycles() -{ - C.clear(); - - for (size_t i = 0; i < H.size(); i++) { - Hedge *h = H[i]; - - if (h->cycle) continue; - - Cycle *c = new Cycle(h); - C.push_back(c); - - h->cycle = c; - - Hedge *w = h->next; - while (w != h) { - w->cycle = c; - w = w->next; - } - } -} - -void Dcel::init_vertices(const Smesh &M0, const Smesh &M1) -{ - assert(Q.empty()); - - for (E_Int i = 0; i < M0.np; i++) { - //Q.insert(M0.X[i], M0.Y[i], M0.Z[i], M0.l2gp.at(i), Dcel::RED); - Q.insert(M0.X[i], M0.Y[i], M0.Z[i], i, Dcel::RED); - } - - for (E_Int i = 0; i < M1.np; i++) { - //Q.insert(M1.X[i], M1.Y[i], M1.Z[i], M1.l2gp.at(i), Dcel::BLACK); - Q.insert(M1.X[i], M1.Y[i], M1.Z[i], i, Dcel::BLACK); - } -} - -Dcel::Dcel(const Smesh &M, E_Int color) -{ - for (E_Int i = 0; i < M.np; i++) { - Q.insert(M.X[i], M.Y[i], M.Z[i], i, color); - } - Q.inorder(V); - for (size_t i = 0; i < V.size(); i++) { - V[i]->id = i; - } - assert(V.size() == (size_t)M.np); - init_hedges_and_faces(M, color); - assert(check_hedges(H)); - assert(check_faces(H, F)); make_cycles(); - set_cycles_inout(M); -} - -Dcel::Dcel(Smesh &M0, Smesh &M1) -{ - init_vertices(M0, M1); - Q.inorder(V); - size_t count = 0; - for (size_t i = 0; i < V.size(); i++) { - V[i]->id = i; - if (V[i]->oid[0] != -1 && V[i]->oid[1] != -1) count++; - } - printf("Duplicate points: %lu\n", count); - - init_hedges_and_faces(M0, RED); - - init_hedges_and_faces(M1, BLACK); - - assert(check_hedges(H)); - - assert(check_faces(H, F)); + set_cycles_inout(Mf, color); } -void mat3_mult(E_Float A[3][3], E_Float B[3][3], E_Float C[3][3]) +void Dcel::init_hedges_and_faces(const Smesh &Mf, E_Int color) { - for (E_Int i = 0; i < 3; i++) { - for (E_Int j = 0; j < 3; j++) { - C[i][j] = 0; - - for (E_Int k = 0; k < 3; k++) { - C[i][j] += A[i][k] * B[k][j]; - } - } - } -} + printf("Doing color %d\n", color); -void mat3_vec(E_Float A[3][3], E_Float x[3], E_Float b[3]) -{ - for (E_Int i = 0; i < 3; i++) { - b[i] = 0; - for (E_Int j = 0; j < 3; j++) { - b[i] += A[i][j] * x[j]; - } - } -} + H.reserve(Mf.ne*2); -void Dcel::init_hedges_and_faces(const Smesh &M, E_Int color) -{ - printf("Doing color %d\n", color); - size_t nh = H.size(); - size_t nhh = nh + 2 * M.E.size(); + std::vector> list(Mf.np); - H.reserve(nhh); + // Create hedge records - std::vector> list(M.np); + const auto &E = Mf.E; - for (E_Int i = 0; i < M.ne; i++) { - const auto &e = M.E[i]; + for (E_Int i = 0; i < Mf.ne; i++) { + const auto &e = E[i]; E_Int p = e.p; E_Int q = e.q; - Event *xit = Q.lookup(M.X[p], M.Y[p], M.Z[p]); - assert(xit); - - Vertex *P = xit->key; - - Hedge *h = new Hedge(P); - h->eid = i; - + Vertex *P = V[p]; + Hedge *h = new Hedge(P, color); list[p].push_back(h); - - xit = Q.lookup(M.X[q], M.Y[q], M.Z[q]); - assert(xit); - - Vertex *V = xit->key; - - Hedge *t = new Hedge(V); - t->eid = i; - + + Vertex *Q = V[q]; + Hedge *t = new Hedge(Q, color); list[q].push_back(t); h->twin = t; t->twin = h; - h->color = color; - t->color = color; - H.push_back(h); H.push_back(t); } // Pair-up hedges - const auto &pnormals = M.pnormals; + const auto &pnormals = Mf.pnormals; - for (E_Int pid = 0; pid < M.np; pid++) { + for (E_Int pid = 0; pid < Mf.np; pid++) { auto &hedges = list[pid]; - assert(hedges.size() >= 2); const E_Float *N = &pnormals[3*pid]; - //assert(Sign(K_MATH::norm(N, 3)-1) == 0); - - sort_leaving_hedges(hedges, N, M); + sort_leaving_hedges(hedges, N); for (size_t i = 0; i < hedges.size(); i++) { Hedge *h = hedges[i]; @@ -472,28 +106,30 @@ void Dcel::init_hedges_and_faces(const Smesh &M, E_Int color) h->twin->next = w; w->prev = h->twin; } - - Event *xit = Q.lookup(hedges[0]->orig); - - xit->key->rep = hedges[0]; } + // Create face records + const auto &F2E = Mf.F2E; + const auto &E2F = Mf.E2F; - for (E_Int i = 0; i < M.nf; i++) { - const auto &edges = M.F2E[i]; - E_Int first_edge = edges[0]; - E_Int where = nh + 2 * first_edge; + F.reserve(Mf.nf); + + for (E_Int fid = 0; fid < Mf.nf; fid++) { + const auto &pe = F2E[fid]; + E_Int first_edge = pe[0]; + E_Int where = 2*first_edge; Hedge *h = H[where]; Hedge *t = H[where + 1]; assert(h->twin == t); assert(t->twin == h); Face *f = new Face; - f->oid[color] = i; + f->oids[color] = fid; - assert(M.E2F[first_edge][0] == (E_Int)i || M.E2F[first_edge][1] == E_Int(i)); - Hedge *REP = (M.E2F[first_edge][0] == (E_Int)i) ? h : t; + // Face must lie to the left of hedge + assert(E2F[first_edge][0] == fid || E2F[first_edge][1] == fid); + Hedge *REP = (E2F[first_edge][0] == fid) ? h : t; assert(REP->left == NULL); @@ -504,97 +140,167 @@ void Dcel::init_hedges_and_faces(const Smesh &M, E_Int color) F.push_back(f); } +} - for (Face *f : F) { - Hedge *h = f->rep; - assert(h->left == f); - Hedge *w = h->next; - while (w != h) { - assert(w->left == f); - w = w->next; - } +void Dcel::sort_leaving_hedges(std::vector &leaving, + const E_Float N[3]) const +{ + // Choose a vector that is not parallel to N + + E_Float ref_vec[3] = {0, N[2], -N[1]}; + E_Float NORM = K_MATH::norm(ref_vec, 3); + if (Sign(NORM) == 0) { + ref_vec[0] = -N[2]; + ref_vec[1] = 0; + ref_vec[2] = N[0]; + NORM = K_MATH::norm(ref_vec, 3); + assert(Sign(NORM) != 0); } - - // Create the unbounded faces - f_unbounded[color] = new Face; - f_unbounded[color]->oid[color] = -1; - - // Set it as the left face for hedges without a left face - for (size_t i = nh; i < nhh; i++) { - if (H[i]->left == NULL) - H[i]->left = f_unbounded[color]; + + E_Float dp = K_MATH::dot(ref_vec, N, 3); + for (E_Int i = 0; i < 3; i++) ref_vec[i] = ref_vec[i] - dp * N[i]; + NORM = K_MATH::norm(ref_vec, 3); + for (E_Int i = 0; i < 3; i++) ref_vec[i] /= NORM; + + std::vector angles(leaving.size()); + + for (size_t i = 0; i < leaving.size(); i++) { + Hedge *h = leaving[i]; + Hedge *t = h->twin; + + Vertex *P = h->orig; + Vertex *Q = t->orig; + assert(P != Q); + + // Project the hedge onto the plane (pid, N) + E_Float PQ[3] = {Q->x-P->x, Q->y-P->y, Q->z-P->z}; + E_Float dp = K_MATH::dot(PQ, N, 3); + E_Float PQ_proj[3]; + for (E_Int j = 0; j < 3; j++) PQ_proj[j] = PQ[j] - dp * N[j]; + + E_Float costheta = K_MATH::dot(ref_vec, PQ_proj, 3) / K_MATH::norm(PQ_proj, 3); + costheta = std::min(costheta, 1.0); + costheta = std::max(costheta, -1.0); + E_Float angle = acos(costheta); + + // Determine the direction of the angle + E_Float C[3]; + K_MATH::cross(ref_vec, PQ_proj, C); + + if (K_MATH::dot(N, C, 3) > 0) angle = 2*K_MATH::PI - angle; + + angles[i] = angle; } + + std::vector indices(leaving.size()); + for (size_t i = 0; i < leaving.size(); i++) indices[i] = i; + + std::sort(indices.begin(), indices.end(), [&](E_Int i, E_Int j) + { + if (angles[i] < angles[j]) return true; + + if (angles[i] > angles[j]) return false; + + Hedge *h = leaving[i]; + Hedge *w = leaving[j]; + + assert(h->color != w->color); + + Vertex *P = h->orig; + Vertex *Q = h->twin->orig; + if (cmp_vtx(P, Q) < 0) return true; + + return false; + }); + + std::vector tmp(leaving); + for (size_t i = 0; i < leaving.size(); i++) leaving[i] = tmp[indices[i]]; } E_Int Dcel::check_hedges(const std::vector &H) { for (size_t i = 0; i < H.size(); i++) { Hedge *h = H[i]; - if (h->prev->next != h) { assert(0); return 0; } - if (h->next->prev != h) { assert(0); return 0; } - if (h->twin->twin != h) { assert(0); return 0; } - if (h->twin->next->orig != h->orig) { assert(0); return 0; } - if (h->prev->twin->orig != h->orig) { assert(0); return 0; } + if (h->prev->next != h) { assert(0); return 1; } + if (h->next->prev != h) { assert(0); return 1; } + if (h->twin->twin != h) { assert(0); return 1; } + if (h->twin->next->orig != h->orig) { assert(0); return 1; } + if (h->prev->twin->orig != h->orig) { assert(0); return 1; } } puts("CHECK: EDGES OK."); - return 1; + return 0; } - E_Int Dcel::check_faces(const std::vector &H, const std::vector &F) { for (size_t i = 0; i < H.size(); i++) { Hedge *h = H[i]; - if (h->prev->left != h->left) { assert(0); return 0; } - if (h->next->left != h->left) { assert(0); return 0; } + if (h->prev->left != h->left) { assert(0); return 1; } + if (h->next->left != h->left) { assert(0); return 1; } } for (size_t i = 0; i < F.size(); i++) { Face *f = F[i]; - if (f->rep->left != f) { assert(0); return 0; } + if (f->rep->left != f) { assert(0); return 1; } } puts("CHECK: FACES OK."); - return 1; + return 0; } -Dcel::~Dcel() +void Dcel::make_cycles() { - delete f_unbounded[0]; - delete f_unbounded[1]; + C.clear(); - for (size_t i = 0; i < V.size(); i++) delete V[i]; - for (size_t i = 0; i < H.size(); i++) delete H[i]; - for (size_t i = 0; i < F.size(); i++) delete F[i]; - for (size_t i = 0; i < C.size(); i++) delete C[i]; + for (size_t i = 0; i < H.size(); i++) { + Hedge *h = H[i]; + + if (h->cycle) continue; + + Cycle *c = new Cycle(h); + C.push_back(c); - Q.drop(); + h->cycle = c; + + Hedge *w = h->next; + while (w != h) { + w->cycle = c; + w = w->next; + } + } } -void Dcel::set_cycles_inout(const Smesh &M)//, const Smesh &S) +void Dcel::set_cycles_inout(const Smesh &Mf, E_Int color) { - E_Int inner = 0; - E_Int outer = 0; - E_Int degen = 0; + inner = 0; + outer = 0; + degen = 0; + hole = 0; for (Cycle *c : C) { - // Get the leftmost vertex in the cycle Hedge *h = c->rep; - Vertex *v = h->orig; + if (h->left == NULL) { + c->inout = Cycle::HOLE; + hole++; + continue; + } - Hedge *e2 = h; // Half-edge starting at v - Hedge *e1 = h->prev; // Half-edge ending at v + // Get the leftmost vertex in the cycle + Vertex *leftmost = h->orig; + + Hedge *e2 = h; // Half-edge starting at leftmost vertex + Hedge *e1 = h->prev; // Half-edge ending at leftmost vertex Hedge *w = h->next; while (w != h) { Vertex *p = w->orig; - E_Int cmp = cmp_vtx(p, v); + E_Int cmp = cmp_vtx(p, leftmost); if (cmp < 0) { - v = p; + leftmost = p; e2 = w; e1 = w->prev; } @@ -602,227 +308,195 @@ void Dcel::set_cycles_inout(const Smesh &M)//, const Smesh &S) w = w->next; } - assert(e2->orig == v); - assert(e1->twin->orig == v); - - c->left = v; + assert(e2->orig == leftmost); + assert(e1->twin->orig == leftmost); Vertex *a = e1->orig; Vertex *b = e2->twin->orig; - - // If the angle from e1 to e2 is less than 180°, c is an outer cycle. - // Else, c is an inner cycle. - E_Float px = v->x - a->x; - E_Float py = v->y - a->y; - E_Float pz = v->z - a->z; - E_Float nx = b->x - v->x; - E_Float ny = b->y - v->y; - E_Float nz = b->z - v->z; + E_Float px = leftmost->x - a->x; + E_Float py = leftmost->y - a->y; + E_Float pz = leftmost->z - a->z; + E_Float nx = b->x - leftmost->x; + E_Float ny = b->y - leftmost->y; + E_Float nz = b->z - leftmost->z; E_Float cp[3] = {py*nz - pz*ny, pz*nx - px*nz, px*ny - py*nx}; + E_Int pid = leftmost->oids[color]; - E_Float N[3]= { }; - - // M point - if (v->oid[0] != -1) { - - E_Int mpid = v->oid[0]; - - const E_Float *pN = &M.pnormals[3*mpid]; - for (E_Int i = 0; i < 3; i++) N[i] = pN[i]; - - } - - // S point - else if (v->oid[1] != -1) { - - const auto &loc = v->loc; - - E_Int mfid = loc.fid; - - if (loc.e_idx != -1) { - - const auto &pe = M.F2E[mfid]; - E_Int eid = pe[loc.e_idx]; - const auto &pf = M.E2F[eid]; - assert(mfid == pf[0] || mfid == pf[1]); - - E_Int mf1 = pf[0]; - E_Int mf2 = pf[1]; - - const E_Float *fN1 = &M.fnormals[3*mf1]; - const E_Float *fN2 = &M.fnormals[3*mf2]; - - for (E_Int i = 0; i < 3; i++) { - N[i] += fN1[i]; - N[i] += fN2[i]; - } - - E_Float NORM = K_MATH::norm(N, 3); - for (E_Int i = 0; i < 3; i++) N[i] /= NORM; - - } else if (loc.v_idx != -1) { - - const auto &pn = M.F[mfid]; - E_Int mpid = pn[loc.v_idx]; - const E_Float *pN = &M.pnormals[3*mpid]; - for (E_Int i = 0; i < 3; i++) N[i] = pN[i]; - - } else { - - const E_Float *fN = &M.fnormals[3*mfid]; - - for (E_Int i = 0; i < 3; i++) N[i] = fN[i]; - - } - - } - - // Intersection - else { - - //Hedge *h = v->xhedge; - //assert(h); - //Face *f1 = h->left; - //Face *f2 = h->twin->left; - //E_Int mf1 = f1->oid[0]; - //E_Int mf2 = f2->oid[0]; - - E_Int eid = v->meid; - const auto &pf = M.E2F[eid]; - - E_Int mf1 = pf[0]; - E_Int mf2 = pf[1]; - assert(mf2 != -1); - - const E_Float *fN1 = &M.fnormals[3*mf1]; - const E_Float *fN2 = &M.fnormals[3*mf2]; - - for (E_Int i = 0; i < 3; i++) { - N[i] += fN1[i]; - N[i] += fN2[i]; - } - - E_Float NORM = K_MATH::norm(N, 3); - for (E_Int i = 0; i < 3; i++) N[i] /= NORM; - } + const E_Float *N = &Mf.pnormals[3*pid]; E_Float cmp = K_MATH::dot(N, cp, 3); if (cmp < 0) { - c->inout = Cycle::INNER; - inner++; + c->inout = Cycle::OUTER; + outer++; } else if (cmp == 0) { c->inout = Cycle::DEGEN; degen++; } else { - c->inout = Cycle::OUTER; - outer++; + c->inout = Cycle::INNER; + inner++; } } printf("Inner cycles: " SF_D_ "\n", inner); printf("Outer cycles: " SF_D_ "\n", outer); printf("Degen cycles: " SF_D_ "\n", degen); - - printf("Total faces: " SF_D_ "\n", outer); + printf("Hole cycles: " SF_D_ "\n", hole); } -std::vector Dcel::get_face_vertices(Face *f) +Dcel::~Dcel() { - std::vector ret; - Hedge *h = f->rep; - ret.push_back(h->orig); - Hedge *w = h->next; - while (w != h) { - ret.push_back(w->orig); - w = w->next; - } - return ret; + for (Vertex *v : V) delete v; + for (Hedge *h : H) delete h; + for (Face *f : F) delete f; + for (Cycle *c : C) delete c; } -static -E_Int Sign_tol(E_Float x, E_Float tol) +/* + +void Dcel::init_vertices(const Smesh &M0, const Smesh &M1) { - if (x > tol) return 1; - if (x < -tol) return -1; - return 0; + assert(Q.empty()); + + for (E_Int i = 0; i < M0.np; i++) { + //Q.insert(M0.X[i], M0.Y[i], M0.Z[i], M0.l2gp.at(i), Dcel::RED); + Q.insert(M0.X[i], M0.Y[i], M0.Z[i], i, Dcel::RED); + } + + for (E_Int i = 0; i < M1.np; i++) { + //Q.insert(M1.X[i], M1.Y[i], M1.Z[i], M1.l2gp.at(i), Dcel::BLACK); + Q.insert(M1.X[i], M1.Y[i], M1.Z[i], i, Dcel::BLACK); + } } -void Dcel::locate_spoints(const Smesh &M, const Smesh &S) +void Dcel::update_hedge_faces(const std::vector &F) { - for (E_Int sp = 0; sp < S.np; sp++) { + for (Face *f : F) { + Hedge *h = f->rep; + h->left = f; + Hedge *w = h->next; + while (w != h) { + w->left = f; + w = w->next; + } + } +} - Event *xit = Q.lookup(S.X[sp], S.Y[sp], S.Z[sp]); - assert(xit); +std::vector Dcel::make_cycle_faces(const std::vector &C) +{ + std::vector new_F; - Vertex *V = xit->key; - auto &ploc = V->loc; + for (Cycle *c : C) { + + // Create a face record + Face *f = new Face; - E_Int found = 0; + // Set its rep hedge to some edge of the cycle + Hedge *h = c->rep; + f->rep = h; - E_Int voxel_x = floor((S.X[sp] - M.xmin) / M.HX); - E_Int voxel_y = floor((S.Y[sp] - M.ymin) / M.HY); - E_Int voxel_z = floor((S.Z[sp] - M.zmin) / M.HZ); - E_Int sp_bin = voxel_x + M.NX * voxel_y + M.NXY * voxel_z; + new_F.push_back(f); + } - const auto &pf = M.bin_faces.at(sp_bin); + return new_F; +} - assert(pf.size() > 0); +void Dcel::set_face_labels(std::vector &F) +{ + // Label each face with the ids of the original faces containing it - for (size_t mf = 0; mf < pf.size() && !found; mf++) { + for (size_t i = 0; i < F.size(); i++) { + Face *f = F[i]; - E_Int fid = pf[mf]; + // Get the first RED and BLACK half-edges in the face cycle. + Hedge *h = f->rep; - const auto &pn = M.F[fid]; + Hedge *R = NULL; + Hedge *B = NULL; + E_Int RB = 0; - E_Float o[3] = {0, 0, 0}; + if (h->color == Dcel::RED) { + R = h; + B = get_hedge_of_color(f, Dcel::BLACK); + if (B) RB = 1; + } else if (h->color == Dcel::BLACK) { + B = h; + R = get_hedge_of_color(f, Dcel::RED); + if (R) RB = 1; + } else { + assert(0); + } - for (E_Int p : pn) { - o[0] += M.X[p]; - o[1] += M.Y[p]; - o[2] += M.Z[p]; - } - for (E_Int i = 0; i < 3; i++) o[i] /= pn.size(); - - for (size_t i = 0; i < pn.size(); i++) { - E_Int p = pn[i]; - E_Int q = pn[(i+1)%pn.size()]; - - E_Float u, v, w; - - if (Triangle::is_point_inside( - S.X[sp], S.Y[sp], S.Z[sp], - //V->x, V->y, V->z, - M.X[p], M.Y[p], M.Z[p], - M.X[q], M.Y[q], M.Z[q], - o[0], o[1], o[2], - u, v, w)) { - - found = 1; - - ploc.fid = fid; - ploc.bcrd[0] = u; - ploc.bcrd[1] = v; - ploc.bcrd[2] = w; - - // TODO(Imad): this absolutely needs to be robust - if (Sign_tol(v, 1e-3) == 0) - ploc.e_idx = i; - else if (Sign_tol(1-u, 1e-3) == 0) - ploc.v_idx = (i+1)%pn.size(); - else if (Sign_tol(1-w, 1e-3) == 0) - ploc.v_idx = i; - - break; - } + if (RB) { + // First case: R and B both exist + assert(R->left); + assert(B->left); + assert(R->color == Dcel::RED); + assert(B->color == Dcel::BLACK); + f->oid[Dcel::RED] = R->left->oid[Dcel::RED]; + f->oid[Dcel::BLACK] = B->left->oid[Dcel::BLACK]; + } else { + // Second case: the face is single color + // Only single color possible is RED, otherwise intersection problem + // is ill-posed + Hedge *REP = (R != NULL) ? R : B; + if (REP != R) { + hedge_write("black", REP); } + assert(REP == R); + assert(REP->color == Dcel::RED); + assert(REP->left); + f->oid[REP->color] = REP->left->oid[REP->color]; } + } +} + +Hedge *Dcel::get_hedge_of_color(Face *f, E_Int color) +{ + Hedge *h = f->rep; + if (h->color == color) return h; + Hedge *w = h->next; + while (w != h) { + if (w->color == color) return w; + w = w->next; + } + return NULL; +} + +Dcel::Dcel(Smesh &M0, Smesh &M1) +{ + init_vertices(M0, M1); + Q.inorder(V); + size_t count = 0; + for (size_t i = 0; i < V.size(); i++) { + V[i]->id = i; + if (V[i]->oid[0] != -1 && V[i]->oid[1] != -1) count++; + } + printf("Duplicate points: %lu\n", count); - assert(found); + init_hedges_and_faces(M0, RED); + + init_hedges_and_faces(M1, BLACK); + + assert(check_hedges(H)); + + assert(check_faces(H, F)); +} + +std::vector Dcel::get_face_vertices(Face *f) +{ + std::vector ret; + Hedge *h = f->rep; + ret.push_back(h->orig); + Hedge *w = h->next; + while (w != h) { + ret.push_back(w->orig); + w = w->next; } + return ret; } void Dcel::cut_hedge_at_vertex(Hedge *e, Vertex *x) @@ -865,70 +539,6 @@ void Dcel::cut_hedge_at_vertex(Hedge *e, Vertex *x) Cp[x].push_back(e2); } -E_Int Dcel::get_next_face(const Smesh &M, E_Float px, E_Float py, E_Float pz, - const std::vector &pf, E_Float dir[3], E_Int hid) -{ - E_Int next_face = -1; - /* - E_Float t_min = EFLOATMAX; - - for (size_t i = 0; i < pf.size(); i++) { - - E_Int fid = pf[i]; - - Face *face = F[fid]; - - const E_Float *fN = &M.fnormals[3*fid]; - - E_Float proj[3] = { }; - E_Float dp = K_MATH::dot(fN, dir, 3); - for (E_Int j = 0; j < 3; j++) proj[j] = dir[j] - dp * fN[j]; - - Hedge *h = face->rep; - - E_Int hit = 0; - - while (1) { - - if (hid == 4108) hedge_write("h", h); - - Vertex *a = h->orig; - Vertex *b = h->twin->orig; - - E_Float dx = px + 1.0 * proj[0]; - E_Float dy = py + 1.0 * proj[1]; - E_Float dz = pz + 1.0 * proj[2]; - - E_Float t = -1.0, s = -1.0; - - hit = EdgeEdgeIntersect( - px, py, pz, - dx, dy, dz, - a->x, a->y, a->z, - b->x, b->y, b->z, - t, s); - - if (hid == 555) - printf("hit: %d - t: %f - s: %f\n", hit, t, s); - - if (hit) { - if (t < t_min) { - next_face = fid; - t_min = t; - } - - break; - } - - h = h->next; - if (h == face->rep) break; - } - } - - */ - return next_face; -} - std::vector points; void Dcel::find_intersections_3D(const Smesh &M, const Smesh &S) @@ -1007,105 +617,6 @@ void Dcel::find_intersections_3D(const Smesh &M, const Smesh &S) cut_hedges(); } -void Dcel::sort_leaving_hedges(std::vector &leaving, - const E_Float N[3], - const Smesh &M) const -{ - // Choose a vector that is not parallel to N - - E_Float ref_vec[3] = {0, N[2], -N[1]}; - - if (Sign(K_MATH::norm(ref_vec, 3)) == 0) { - ref_vec[0] = -N[2]; - ref_vec[1] = 0; - ref_vec[2] = N[0]; - assert(Sign(K_MATH::norm(ref_vec, 3)) != 0); - } - - E_Float dp = K_MATH::dot(ref_vec, N, 3); - - for (E_Int i = 0; i < 3; i++) ref_vec[i] = ref_vec[i] - dp * N[i]; - - E_Float NORM = K_MATH::norm(ref_vec, 3); - - for (E_Int i = 0; i < 3; i++) ref_vec[i] /= NORM; - - //assert(Sign(K_MATH::norm(ref_vec, 3) - 1) == 0); - - std::vector angles; - - for (size_t i = 0; i < leaving.size(); i++) { - Hedge *h = leaving[i]; - Hedge *t = h->twin; - - Vertex *P = h->orig; - Vertex *Q = t->orig; - assert(P != Q); - - // Project the hedge onto the plane (pid, N) - E_Float PQ[3] = {Q->x-P->x, Q->y-P->y, Q->z-P->z}; - - E_Float dp = K_MATH::dot(PQ, N, 3); - - E_Float PQ_proj[3]; - - for (E_Int j = 0; j < 3; j++) { - PQ_proj[j] = PQ[j] - dp * N[j]; - } - - E_Float costheta = K_MATH::dot(ref_vec, PQ_proj, 3) / K_MATH::norm(PQ_proj, 3); - - costheta = std::min(costheta, 1.0); - - costheta = std::max(costheta, -1.0); - - assert(costheta >= -1 && costheta <= 1); - - E_Float angle = acos(costheta); - - // Determine the direction of the angle - E_Float C[3] = {}; - - K_MATH::cross(ref_vec, PQ_proj, C); - - if (K_MATH::dot(N, C, 3) > 0) - angle = 2*K_MATH::PI - angle; - - //angle = angle * 180 / K_MATH::PI; - - angles.push_back(angle); - } - - std::vector indices(leaving.size()); - for (size_t i = 0; i < leaving.size(); i++) - indices[i] = i; - - std::sort(indices.begin(), indices.end(), [&](E_Int i, E_Int j) - { - if (angles[i] < angles[j]) return true; - - else if (angles[i] > angles[j]) return false; - - else { - Hedge *h = leaving[i]; - Hedge *w = leaving[j]; - - assert(h->color != w->color); - - Vertex *P = h->orig; - Vertex *Q = h->twin->orig; - if (cmp_vtx(P, Q) < 0) return true; - - return false; - } - }); - - std::vector tmp(leaving); - - for (size_t i = 0; i < leaving.size(); i++) - leaving[i] = tmp[indices[i]]; -} - void Dcel::resolve_hedges(const Smesh &M, const Smesh &S) { assert(Up.empty()); @@ -1144,23 +655,7 @@ void Dcel::resolve_hedges(const Smesh &M, const Smesh &S) leaving.push_back(h); } - /* - E_Int do_sort = 0; - - for (size_t i = 1; i < leaving.size(); i++) { - if (leaving[i]->color != leaving[0]->color) { - do_sort = 1; - break; - } - } - - if (!do_sort) continue; - */ - - - - - E_Float N[3]= {0}; + E_Float N[3] = {0}; // M point if (v->oid[0] != -1) { @@ -1262,8 +757,8 @@ void Dcel::reconstruct(const Smesh &M, const Smesh &S) check_hedges(H); make_cycles(); - - set_cycles_inout(M); + assert(0); + set_cycles_inout(M, 0); auto new_F = make_cycle_faces(C); @@ -1280,3 +775,4 @@ void Dcel::reconstruct(const Smesh &M, const Smesh &S) write_inner_faces("inner"); write_outer_faces("outer"); } +*/ diff --git a/Cassiopee/XCore/XCore/intersectMesh/dcel.h b/Cassiopee/XCore/XCore/intersectMesh/dcel.h index eb63b0230..16f35af21 100644 --- a/Cassiopee/XCore/XCore/intersectMesh/dcel.h +++ b/Cassiopee/XCore/XCore/intersectMesh/dcel.h @@ -23,33 +23,84 @@ #include #include "common/common.h" -#include "queue.h" #include "point.h" +#include "primitives.h" -struct Vertex; -struct Hedge; -struct Face; -struct Segment; struct Smesh; -struct Cycle; struct Dcel { + + static const int RED = 0; + static const int BLACK = 1; + static const int NO_IDEA = -1; + + struct Vertex { + E_Float x, y, z; + E_Int oids[2] = {-1, -1}; + E_Int id = -1; + + Vertex(E_Float x_, E_Float y_, E_Float z_) + { + x = x_; + y = y_; + z = z_; + oids[0] = -1; + oids[1] = -1; + } + }; + + int cmp_vtx(const Vertex *p, const Vertex *q) const + { + return cmp_points(p->x, p->y, p->z, q->x, q->y, q->z); + } + + struct Face; + struct Cycle; + + struct Hedge { + Vertex *orig = NULL; + Hedge *twin = NULL; + Hedge *next = NULL; + Hedge *prev = NULL; + Face *left = NULL; + int color = NO_IDEA; + Cycle *cycle = NULL; + + Hedge(Vertex *V, int color_) + { + orig = V; + color = color_; + } + }; + + struct Face { + Hedge *rep = NULL; + E_Int oids[2] = {-1, -1}; + }; + + struct Cycle { + Hedge *rep = NULL; + int inout = 0; + + static const int HOLE = -1; + static const int DEGEN = 0; + static const int INNER = 1; + static const int OUTER = 2; + + Cycle(Hedge *h) + : rep(h) + {} + }; + std::vector V; std::vector H; std::vector F; std::vector C; - Queue Q; // Filters out duplicate vertices - - Face *f_unbounded[2]; - - static E_Int RED; - static E_Int BLACK; - static E_Int NO_IDEA; - - std::map> Up; - std::map> Cp; - std::map> Lp; + E_Int inner = 0; + E_Int outer = 0; + E_Int degen = 0; + E_Int hole = 0; E_Int dup_x = 0; // Number of duplicate intersections std::set vertices_crossed; // M vertices crossed by S hedges @@ -84,20 +135,9 @@ struct Dcel { void update_hedge_faces(const std::vector &F); - void set_cycles_inout(const Smesh &M);//, const Smesh &S); + void set_cycles_inout(const Smesh &M, E_Int color); - std::vector extract_indices_of_type(E_Int inout); - std::vector extract_faces_of_indices( - const std::vector &indices); - - void write_ngon(const char *fname, const std::vector &faces) const; - - void write_degen_faces(const char *fname); - - void write_outer_faces(const char *fname); - - void write_inner_faces(const char *fname); static std::vector get_face_vertices(Face *f); @@ -113,17 +153,33 @@ struct Dcel { E_Int get_next_face(const Smesh &M, E_Float px, E_Float py, E_Float pz, const std::vector &pf, E_Float dir[3], E_Int hid); - - void handle_intersecting_endpoint(Vertex *v, const Smesh &M); - - void trace_hedge(Hedge *sh, const Smesh &M, const Smesh &S, E_Int hid); E_Int trace_hedge_2(Hedge *sh, const Smesh &M, const Smesh &S, E_Int hid); void cut_hedges(); - void sort_leaving_hedges(std::vector &leaving, const E_Float N[3], - const Smesh &M) const; + void sort_leaving_hedges(std::vector &leaving, const E_Float N[3]) const; - Smesh export_smesh(bool is_planar=true) const; + Smesh export_smesh(bool check_Euler=true) const; + + // Extract + + std::vector extract_indices_of_type(int inout) const; + std::vector extract_cycles_of_indices( + const std::vector &indices) const; + + // IO + + void write_face(const char *fname, const Face *face) const; + void write_faces(const char *fname, const std::vector &faces, + E_Float scale = 1.0) const; + void write_hedge(const char *fname, const Hedge *h) const; + void write_point(const char *fname, const Vertex *v) const; + void write_point(const char *fname, const std::vector &I) const; + void write_ngon(const char *fname, const std::vector &cycles) const; + void write_degen_cycles(const char *fname) const; + void write_inner_cycles(const char *fname) const; + void write_hole_cycles(const char *fname) const; + void write_outer_cycles(const char *fname) const; + void write_cycles_of_type(const char *fname, E_Int type) const; }; diff --git a/Cassiopee/XCore/XCore/intersectMesh/cut.cpp b/Cassiopee/XCore/XCore/intersectMesh/dcel_cut.cpp similarity index 98% rename from Cassiopee/XCore/XCore/intersectMesh/cut.cpp rename to Cassiopee/XCore/XCore/intersectMesh/dcel_cut.cpp index ec3a730fc..49e6324c1 100644 --- a/Cassiopee/XCore/XCore/intersectMesh/cut.cpp +++ b/Cassiopee/XCore/XCore/intersectMesh/dcel_cut.cpp @@ -1,6 +1,4 @@ #include "dcel.h" -#include "hedge.h" -#include "vertex.h" #include "primitives.h" #include "smesh.h" #include "io.h" diff --git a/Cassiopee/XCore/XCore/intersectMesh/dcel_extract.cpp b/Cassiopee/XCore/XCore/intersectMesh/dcel_extract.cpp new file mode 100644 index 000000000..9eb0fc2d1 --- /dev/null +++ b/Cassiopee/XCore/XCore/intersectMesh/dcel_extract.cpp @@ -0,0 +1,69 @@ +#include "dcel.h" +#include "smesh.h" + +Smesh Dcel::export_smesh(bool check_Euler) const +{ + Smesh smesh; + smesh.check_Euler = check_Euler; + + smesh.np = V.size(); + smesh.X.resize(smesh.np); + smesh.Y.resize(smesh.np); + smesh.Z.resize(smesh.np); + + for (Vertex *v : V) { + smesh.X[v->id] = v->x; + smesh.Y[v->id] = v->y; + smesh.Z[v->id] = v->z; + } + + for (size_t i = 0; i < F.size(); i++) { + Face *f = F[i]; + Hedge *REP = f->rep; + Cycle *c = REP->cycle; + if (c->inout != Cycle::OUTER) continue; + Hedge *h = REP; + + std::vector pn; + + do { + Vertex *v = h->orig; + pn.push_back(v->id); + h = h->next; + } while (h != REP); + + smesh.F.push_back(pn); + } + + smesh.nf = (E_Int)smesh.F.size(); + + smesh.Fc = smesh.F; + + smesh.make_edges(); + + return smesh; +} + +std::vector Dcel::extract_cycles_of_indices( + const std::vector &indices) const +{ + std::vector ret; + ret.reserve(indices.size()); + + for (E_Int index : indices) { + ret.push_back(C[index]); + } + + return ret; +} + +std::vector Dcel::extract_indices_of_type(int type) const +{ + std::vector ret; + + for (size_t i = 0; i < C.size(); i++) { + if (C[i]->inout == type) ret.push_back(i); + } + + return ret; +} \ No newline at end of file diff --git a/Cassiopee/XCore/XCore/intersectMesh/dcel_io.cpp b/Cassiopee/XCore/XCore/intersectMesh/dcel_io.cpp new file mode 100644 index 000000000..f15effc1a --- /dev/null +++ b/Cassiopee/XCore/XCore/intersectMesh/dcel_io.cpp @@ -0,0 +1,221 @@ +#include "dcel.h" + +void Dcel::write_face(const char *fname, const Face *f) const +{ + FILE *fh = fopen(fname, "w"); + assert(fh); + + E_Int np = 1; + Hedge *h = f->rep; + Hedge *w = h->next; + while (w != h) { + np++; + w = w->next; + } + + fprintf(fh, "POINTS\n"); + fprintf(fh, "%d\n", np); + + h = f->rep; + Vertex *v = h->orig; + fprintf(fh, "%f %f %f\n", v->x, v->y, v->z); + w = h->next; + while (w != h) { + v = w->orig; + fprintf(fh, "%f %f %f\n", v->x, v->y, v->z); + w = w->next; + } + fclose(fh); +} + +void Dcel::write_faces(const char *fname, const std::vector &faces, + E_Float scale) const +{ + FILE *fh = fopen(fname, "w"); + assert(fh); + + E_Int NP = 0; + for (const Face *f : faces) { + E_Int np = 1; + Hedge *h = f->rep; + Hedge *w = h->next; + while (w != h) { + np++; + w = w->next; + } + NP += np; + } + + fprintf(fh, "POINTS\n"); + fprintf(fh, "%d\n", NP); + + for (const Face *f : faces) { + Hedge *h = f->rep; + Vertex *v = h->orig; + fprintf(fh, "%f %f %f\n", scale*v->x, scale*v->y, scale*v->z); + Hedge *w = h->next; + while (w != h) { + v = w->orig; + fprintf(fh, "%f %f %f\n", scale*v->x, scale*v->y, scale*v->z); + w = w->next; + } + } + + fclose(fh); +} + +void Dcel::write_hedge(const char *fname, const Hedge *h) const +{ + FILE *fh = fopen(fname, "w"); + assert(fh); + fprintf(fh, "POINTS\n"); + fprintf(fh, "2\n"); + Vertex *p = h->orig; + Vertex *q = h->twin->orig; + fprintf(fh, "%f %f %f\n", p->x, p->y, p->z); + fprintf(fh, "%f %f %f\n", q->x, q->y, q->z); + fprintf(fh, "EDGES\n"); + fprintf(fh, "1\n"); + fprintf(fh, "0 1\n"); + fclose(fh); +} + +void Dcel::write_point(const char *fname, const Vertex *v) const +{ + FILE *fh = fopen(fname, "w"); + assert(fh); + fprintf(fh, "POINTS\n"); + fprintf(fh, "1\n"); + fprintf(fh, "%f %f %f\n", v->x, v->y, v->z); + fclose(fh); +} + +void Dcel::write_point(const char *fname, + const std::vector &I) const +{ + FILE *fh = fopen(fname, "w"); + assert(fh); + fprintf(fh, "POINTS\n"); + fprintf(fh, "%zu\n", I.size()); + for (auto &v : I) fprintf(fh, "%f %f %f\n", v->x, v->y, v->z); + fclose(fh); +} + +void Dcel::write_cycles_of_type(const char *fname, E_Int type) const +{ + auto indices = extract_indices_of_type(type); + auto cids = extract_cycles_of_indices(indices); + write_ngon(fname, cids); +} + +void Dcel::write_degen_cycles(const char *fname) const +{ + write_cycles_of_type(fname, Cycle::DEGEN); +} + +void Dcel::write_inner_cycles(const char *fname) const +{ + write_cycles_of_type(fname, Cycle::INNER); +} + +void Dcel::write_hole_cycles(const char *fname) const +{ + write_cycles_of_type(fname, Cycle::HOLE); +} + +void Dcel::write_outer_cycles(const char *fname) const +{ + write_cycles_of_type(fname, Cycle::OUTER); +} + + +void Dcel::write_ngon(const char *fname, const std::vector &cycles) const +{ + FILE *fh = fopen(fname, "w"); + assert(fh); + + E_Int np = 0; + E_Int ne = 0; + E_Int nf = (E_Int)cycles.size(); + + std::map vmap; + std::vector new_pids; + + for (size_t i = 0; i < cycles.size(); i++) { + Cycle *c = cycles[i]; + Hedge *h = c->rep; + ne++; + Vertex *p = h->orig; + if (vmap.find(p) == vmap.end()) { + vmap[p] = np++; + new_pids.push_back(p); + } + Hedge *w = h->next; + while (w != h) { + p = w->orig; + if (vmap.find(p) == vmap.end()) { + vmap[p] = np++; + new_pids.push_back(p); + } + ne++; + w = w->next; + } + } + + fprintf(fh, "POINTS\n"); + fprintf(fh, SF_D_ "\n", np); + for (const auto &v : new_pids) { + fprintf(fh, "%f %f %f\n", v->x, v->y, v->z); + } + + fprintf(fh, "INDPG\n"); + fprintf(fh, SF_D_ "\n", ne+1); + E_Int sizeNGon = 0; + fprintf(fh, SF_D_ " ", sizeNGon); + for (E_Int i = 0; i < ne; i++) { + sizeNGon += 2; + fprintf(fh, SF_D_ " ", sizeNGon); + } + assert(sizeNGon == 2*ne); + fprintf(fh, "\n"); + + fprintf(fh, "NGON\n"); + fprintf(fh, SF_D_ "\n", sizeNGon); + for (Cycle *c : cycles) { + Hedge *h = c->rep; + Vertex *p = h->orig; + Vertex *q = h->twin->orig; + fprintf(fh, SF_D_ " " SF_D_ " ", vmap[p], vmap[q]); + Hedge *w = h->next; + while (w != h) { + p = w->orig; + q = w->twin->orig; + fprintf(fh, SF_D_ " " SF_D_ " ", vmap[p], vmap[q]); + w = w->next; + } + } + fprintf(fh, "\n"); + + fprintf(fh, "INDPH\n"); + fprintf(fh, SF_D_ "\n", nf+1); + E_Int sizeNFace = 0; + fprintf(fh, SF_D_ " ", sizeNFace); + for (Cycle *c : cycles) { + Hedge *h = c->rep; + sizeNFace += 1; + Hedge *w = h->next; + while (w != h) { + sizeNFace += 1; + w = w->next; + } + fprintf(fh, SF_D_ " ", sizeNFace); + } + fprintf(fh, "\n"); + + fprintf(fh, "NFACE\n"); + fprintf(fh, SF_D_ "\n", sizeNFace); + for (E_Int i = 0; i < sizeNFace; i++) + fprintf(fh, SF_D_ " ", i); + + fclose(fh); +} \ No newline at end of file diff --git a/Cassiopee/XCore/XCore/intersectMesh/trace.cpp b/Cassiopee/XCore/XCore/intersectMesh/dcel_trace.cpp similarity index 65% rename from Cassiopee/XCore/XCore/intersectMesh/trace.cpp rename to Cassiopee/XCore/XCore/intersectMesh/dcel_trace.cpp index ffd8840c1..5a45a2385 100644 --- a/Cassiopee/XCore/XCore/intersectMesh/trace.cpp +++ b/Cassiopee/XCore/XCore/intersectMesh/dcel_trace.cpp @@ -1,176 +1,16 @@ #include "dcel.h" #include "smesh.h" #include "primitives.h" -#include "hedge.h" #include "io.h" -#include "event.h" -bool ray_edge_intersect(E_Float ox, E_Float oy, E_Float oz, - E_Float dx, E_Float dy, E_Float dz, - E_Float px, E_Float py, E_Float pz, - E_Float qx, E_Float qy, E_Float qz, - E_Float &t, E_Float &u) -{ - E_Float v[3]= {px-ox, py-oy, pz-oz}; - - E_Float dl[3] = {qx-px, qy-py, qz-pz}; - - E_Float dr[3] = {dx, dy, dz}; - - /* - E_Float w[3]; - K_MATH::cross(v, dl, w); - E_Float det = K_MATH::dot(w, dr, 3); - - // ray and edge must be coplanar - if (Sign(det) != 0) return false; - */ - - // ray and edge must not be parallel - E_Float n[3]; - K_MATH::cross(dr, dl, n); - E_Float denom = K_MATH::dot(n, n, 3); - if (Sign(denom) == 0) return false; - - E_Float tmp[3]; - K_MATH::cross(v, dl, tmp); - t = K_MATH::dot(tmp, n, 3) / denom; - - if (t < TOL) return false; - - K_MATH::cross(v, dr, tmp); - - u = K_MATH::dot(tmp, n, 3) / denom; - - if (u < -TOL || u > 1 + TOL) return false; - - return true; -} - -void Smesh::get_unit_projected_direction(E_Int fid, const E_Float D[3], - E_Float proj[3]) const -{ - assert(fid >= 0); - assert(fid < nf); - // Unit normal - const E_Float *fN = &fnormals[3*fid]; - E_Float dp = K_MATH::dot(D, fN, 3); - - proj[0] = D[0] - dp * fN[0]; - proj[1] = D[1] - dp * fN[1]; - proj[2] = D[2] - dp * fN[2]; - E_Float NORM = K_MATH::norm(proj, 3); - proj[0] /= NORM, proj[1] /= NORM, proj[2] /= NORM; -} - -E_Int Smesh::deduce_face(const std::vector &pf, - E_Float ox, E_Float oy, E_Float oz, E_Float D[3], - E_Int last_vertex, E_Int last_edge) const -{ - // Intersect the projection of D with all the faces in pf - // At least one intersection must exist - // Return the face with the earliest intersection - - // For debugging - E_Int faces_hit = 0; - - E_Float t_min = EFLOATMAX; - E_Int ret_face = -1; - - for (auto fid : pf) { - - // Compute the unit projection of D on this face - - E_Float proj[3]; - get_unit_projected_direction(fid, D, proj); - - const auto &pn = Fc[fid]; - const auto &pe = F2E[fid]; - assert(pn.size() == pe.size()); - - for (size_t i = 0; i < pn.size(); i++) { - - E_Int p = pn[i]; - E_Int q = pn[(i+1)%pn.size()]; - E_Int e = pe[i]; - - if (p == last_vertex || q == last_vertex || e == last_edge) - continue; - - E_Float t, s; - - bool hit = ray_edge_intersect(ox, oy, oz, - proj[0], proj[1], proj[2], - X[p], Y[p], Z[p], - X[q], Y[q], Z[q], - t, s - ); - - if (hit) { - faces_hit += 1; - - if (t < t_min) { - t_min = t; - ret_face = fid; - } - - // Hit an edge of the face, stop - break; - } - } - } - - // We must have hit a face - assert(faces_hit > 0); - - return ret_face; -} - -void Smesh::get_shared_faces(const PointLoc &loc, std::vector &ret, - E_Int &pid, E_Int &eid) const -{ - ret.clear(); - - E_Int fid = loc.fid; - assert(fid != -1); - - // TODO(Imad): e_idx is no good!!!! - - if (loc.e_idx != -1) { - assert(loc.v_idx == -1); - const auto &pe = F2E[fid]; - eid = pe[loc.e_idx]; - const auto &pf = E2F[eid]; - assert(pf[0] == fid || pf[1] == fid); - ret.push_back(pf[0]); - // O could be on a boundary edge - if (pf[1] != -1) ret.push_back(pf[1]); - } - else if (loc.v_idx != -1) { - assert(loc.e_idx == -1); - const auto &pn = Fc[fid]; - pid = pn[loc.v_idx]; - const auto &pf = P2F[pid]; - // For consistency - bool found_fid = false; - for (auto face : pf) { - ret.push_back(face); - if (face == fid) { - found_fid = true; - } - } - assert(found_fid == true); - } - else { - ret.push_back(fid); - } -} E_Int Dcel::trace_hedge_2(Hedge *sh, const Smesh &M, const Smesh &S, E_Int hid) { + assert(0); + /* Vertex *O = sh->orig; Vertex *T = sh->twin->orig; E_Float D[3] = {T->x-O->x, T->y-O->y, T->z-O->z}; @@ -381,6 +221,7 @@ E_Int Dcel::trace_hedge_2(Hedge *sh, const Smesh &M, const Smesh &S, E_Int hid) } assert(found_tail); + */ return 0; } diff --git a/Cassiopee/XCore/XCore/intersectMesh/event.cpp b/Cassiopee/XCore/XCore/intersectMesh/event.cpp deleted file mode 100644 index 30e818aad..000000000 --- a/Cassiopee/XCore/XCore/intersectMesh/event.cpp +++ /dev/null @@ -1,52 +0,0 @@ -/* - Copyright 2013-2024 Onera. - - This file is part of Cassiopee. - - Cassiopee is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - Cassiopee is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with Cassiopee. If not, see . -*/ -#include "event.h" -#include "vertex.h" - -Event::Event(E_Float x, E_Float y, E_Float z) -{ - key = new Vertex(x, y, z); - inf = NULL; - left = right = NULL; -} - -Event::Event(E_Float x, E_Float y, E_Float z, E_Int oid, E_Int color) -{ - key = new Vertex(x, y, z, oid, color); - inf = NULL; - left = right = NULL; -} - -void Event::inorder(std::vector &V) const -{ - if (left) left->inorder(V); - V.push_back(key); - if (right) right->inorder(V); -} - -void Event_drop(Event *event) -{ - if (event == NULL) return; - - Event_drop(event->left); - Event_drop(event->right); - - assert(event->inf == NULL); - delete event; -} \ No newline at end of file diff --git a/Cassiopee/XCore/XCore/intersectMesh/event.h b/Cassiopee/XCore/XCore/intersectMesh/event.h deleted file mode 100644 index e9bc7712c..000000000 --- a/Cassiopee/XCore/XCore/intersectMesh/event.h +++ /dev/null @@ -1,41 +0,0 @@ -/* - Copyright 2013-2024 Onera. - - This file is part of Cassiopee. - - Cassiopee is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - Cassiopee is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with Cassiopee. If not, see . -*/ -#pragma once - -#include - -#include "xcore.h" -#include "common/common.h" - -struct Vertex; -struct Segment; - -struct Event { - Vertex *key; - Segment *inf; - Event *left; - Event *right; - - Event(E_Float x, E_Float y, E_Float z, E_Int oid, E_Int color); - Event(E_Float x, E_Float y, E_Float z); - - void inorder(std::vector &V) const; -}; - -void Event_drop(Event *event); \ No newline at end of file diff --git a/Cassiopee/XCore/XCore/intersectMesh/face.cpp b/Cassiopee/XCore/XCore/intersectMesh/face.cpp deleted file mode 100644 index 8f1a27549..000000000 --- a/Cassiopee/XCore/XCore/intersectMesh/face.cpp +++ /dev/null @@ -1,27 +0,0 @@ -/* - Copyright 2013-2024 Onera. - - This file is part of Cassiopee. - - Cassiopee is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - Cassiopee is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with Cassiopee. If not, see . -*/ -#include - -#include "face.h" - -Face::Face() -: rep(NULL) -{ - oid[0] = oid[1] = -1; -} diff --git a/Cassiopee/XCore/XCore/intersectMesh/face.h b/Cassiopee/XCore/XCore/intersectMesh/face.h deleted file mode 100644 index 45779396f..000000000 --- a/Cassiopee/XCore/XCore/intersectMesh/face.h +++ /dev/null @@ -1,31 +0,0 @@ -/* - Copyright 2013-2024 Onera. - - This file is part of Cassiopee. - - Cassiopee is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - Cassiopee is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with Cassiopee. If not, see . -*/ -#pragma once - -#include "xcore.h" -#include "common/common.h" - -struct Hedge; - -struct Face { - Hedge *rep; - E_Int oid[2]; - - Face(); -}; diff --git a/Cassiopee/XCore/XCore/intersectMesh/hedge.cpp b/Cassiopee/XCore/XCore/intersectMesh/hedge.cpp deleted file mode 100644 index 1b2b03e53..000000000 --- a/Cassiopee/XCore/XCore/intersectMesh/hedge.cpp +++ /dev/null @@ -1,148 +0,0 @@ -/* - Copyright 2013-2024 Onera. - - This file is part of Cassiopee. - - Cassiopee is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - Cassiopee is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with Cassiopee. If not, see . -*/ -#include -#include - -#include "hedge.h" -#include "vertex.h" -#include "primitives.h" -#include "dcel.h" -#include "io.h" - -Hedge::Hedge(Vertex *v) -: orig(v), twin(NULL), prev(NULL), next(NULL), left(NULL), color(Dcel::NO_IDEA), - cycle(NULL) -{} - -static -E_Int _partition(std::vector &H, E_Int low, E_Int high) -{ - Hedge *pivot = H[high]; - E_Int i = low-1; - - for (E_Int j = low; j < high; j++) { - if (Hedge::cmp_cwise(H[j], pivot) <= 0) { - i++; - std::swap(H[i], H[j]); - } - } - - i++; - std::swap(H[i], H[high]); - return i; -} - -void Hedge::sort_cwise(std::vector &H, E_Int low, E_Int high) -{ - if (low >= high) - return; - - E_Int p = _partition(H, low, high); - - sort_cwise(H, low, p - 1); - sort_cwise(H, p + 1, high); -} - -void Hedge::sort_ccwise(std::vector &H, E_Int low, E_Int high) -{ - sort_cwise(H, low, high); - std::reverse(H.begin(), H.end()); -} - -E_Int Hedge::cmp_cwise(const Hedge *h, const Hedge *w) -{ - assert(h != w); - assert(h->orig == w->orig); - - E_Float ax = h->proj_tx; - E_Float ay = h->proj_ty; - E_Float bx = w->proj_tx; - E_Float by = w->proj_ty; - E_Float cx = h->proj_ox; - E_Float cy = h->proj_oy; - - assert(Sign(cx-w->proj_ox) == 0); - assert(Sign(cy-w->proj_oy) == 0); - - long double acx = (long double)ax - (long double)cx; - long double acy = (long double)ay - (long double)cy; - long double bcx = (long double)bx - (long double)cx; - long double bcy = (long double)by - (long double)cy; - - E_Int sign_acx = Sign(acx); - E_Int sign_acy = Sign(acy); - E_Int sign_bcx = Sign(bcx); - E_Int sign_bcy = Sign(bcy); - - if (sign_acx >= 0 && sign_bcx < 0) - return -1; - if (sign_acx < 0 && sign_bcx >= 0) - return 1; - if (sign_acx == 0 && sign_bcx == 0) { - if (sign_acy >= 0 || sign_bcy >= 0) { - long double diff = (long double)ay - (long double)by; - if (Sign(diff) > 0) return -1; - else return 1; - } - - long double diff = (long double)by - (long double)ay; - if (Sign(diff) > 0) return -1; - else return 1; - } - - E_Float det = acx * bcy - bcx * acy; - //E_Float det = DifferenceOfProducts(acx, bcy, bcx, acy); - E_Int cmp = Sign(det); - - if (cmp < 0) - return -1; - else if (cmp > 0) - return 1; - - // Overlapping segments - - if (h->color == w->color) { - hedge_write("h", h); - hedge_write("w", w); - } - - assert(h->color != w->color); - - // If right half, red before black - // Otherwise, black before red - - cmp = Sign(h->color - w->color); - - if (sign_acx >= 0) { - assert(sign_bcx >= 0); - return cmp; - } else { - return -cmp; - } -} - -E_Int hedge_contains_vertex(Hedge *h, Vertex *v) -{ - Vertex *a = h->orig; - Vertex *b = h->twin->orig; - return is_point_on_segment( - v->x, v->y, v->z, - a->x, a->y, a->z, - b->x, b->y, b->z); -} diff --git a/Cassiopee/XCore/XCore/intersectMesh/hedge.h b/Cassiopee/XCore/XCore/intersectMesh/hedge.h deleted file mode 100644 index 760827f24..000000000 --- a/Cassiopee/XCore/XCore/intersectMesh/hedge.h +++ /dev/null @@ -1,58 +0,0 @@ -/* - Copyright 2013-2024 Onera. - - This file is part of Cassiopee. - - Cassiopee is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - Cassiopee is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with Cassiopee. If not, see . -*/ -#pragma once - -#include - -#include "xcore.h" -#include "common/common.h" - -struct Vertex; -struct Face; -struct Cycle; - -struct Hedge { - Vertex *orig; - Hedge *twin; - Hedge *prev; - Hedge *next; - Face *left; - E_Int color; - Cycle *cycle; - - E_Int eid; - - // Projection of orig - E_Float proj_ox = -10000; - E_Float proj_oy = -10000; - E_Float proj_oz = -10000; - - // Projection of tail - E_Float proj_tx = -10000; - E_Float proj_ty = -10000; - E_Float proj_tz = -10000; - - Hedge(Vertex *Orig); - - static E_Int cmp_cwise(const Hedge *h, const Hedge *w); - static void sort_cwise(std::vector &H, E_Int start, E_Int end); - static void sort_ccwise(std::vector &H, E_Int start, E_Int end); -}; - -E_Int hedge_contains_vertex(Hedge *h, Vertex *v); diff --git a/Cassiopee/XCore/XCore/intersectMesh/icapsule.cpp b/Cassiopee/XCore/XCore/intersectMesh/icapsule.cpp index 94d188363..34e6b41ef 100644 --- a/Cassiopee/XCore/XCore/intersectMesh/icapsule.cpp +++ b/Cassiopee/XCore/XCore/intersectMesh/icapsule.cpp @@ -1,321 +1,11 @@ +#include + #include "icapsule.h" #include "common/Karray.h" #include "point.h" #include "io.h" #include "primitives.h" -#include - -E_Int ray_point_orient(const E_Float o[3], const E_Float d[3], - const E_Float fN[3], E_Float px, E_Float py, E_Float pz) -{ - E_Float w[3] = {px-o[0], py-o[1], pz-o[2]}; - E_Float c[3]; - K_MATH::cross(d, w, c); - E_Float dp = K_MATH::dot(c, fN, 3); - // TODO(Imad): needs FEA + float128 - E_Int cmp = Sign(dp); - if (cmp > 0) return 1; - if (cmp < 0) return -1; - return 0; -} - -void Smesh::correct_near_points_and_edges(Smesh &Sf, - std::vector &plocs) -{ - E_Int on_vertex = 0, on_edge = 0; - for (size_t i = 0; i < plocs.size(); i++) { - auto &ploc = plocs[i]; - - E_Int fid = ploc.fid; - assert(fid < nf); - const auto &pn = Fc[fid]; - - if (ploc.v_idx != -1) { - on_vertex++; - E_Int p = pn[ploc.v_idx]; - E_Float dx = X[p]-Sf.X[i]; - E_Float dy = Y[p]-Sf.Y[i]; - E_Float dz = Z[p]-Sf.Z[i]; - E_Float dist = dx*dx + dy*dy + dz*dz; - if (dist >= Sf.min_pdist_squared) { - fprintf(stderr, "Tight near-vertex situation!\n"); - point_write("mpoint", X[p], Y[p], Z[p]); - point_write("spoint", Sf.X[i], Sf.Y[i], Sf.Z[i]); - assert(0); - } else { - Sf.X[i] = X[p]; - Sf.Y[i] = Y[p]; - Sf.Z[i] = Z[p]; - } - } else if (ploc.e_idx != -1) { - on_edge++; - E_Float u = ploc.bcrd[0]; - E_Float v = ploc.bcrd[1]; - E_Float w = ploc.bcrd[2]; - assert(Sign(w, NEAR_EDGE_TOL) == 0); - u += w; - assert(Sign(u+v-1) == 0); - E_Int p = pn[ploc.e_idx]; - E_Int q = pn[(ploc.e_idx+1)%pn.size()]; - Sf.X[i] = u*X[p] + v*X[q]; - Sf.Y[i] = u*Y[p] + v*Y[q]; - Sf.Z[i] = u*Z[p] + v*Z[q]; - } - } - printf("on vertex: %d - on edge: %d\n", on_vertex, on_edge); -} - -std::set ewalls; -std::set fwalls; -std::vector pchains; - -std::set Smesh::extract_bounding_faces(const Smesh &Sf, - const std::vector &plocs) const -{ - // Get boundary edges from spatch - std::set bedges; - for (size_t i = 0; i < Sf.E2F.size(); i++) { - const auto &pf = Sf.E2F[i]; - assert(pf[0] != -1); - if (pf[1] == -1) bedges.insert(i); - } - size_t nbedges = bedges.size(); - - // Make the boundary point chain - std::vector pchain; - - E_Int first_edge = *bedges.begin(); - - pchain.push_back(Sf.E[first_edge].p); - pchain.push_back(Sf.E[first_edge].q); - - bedges.erase(first_edge); - - E_Int current_point = pchain[1]; - - while (pchain.size() < nbedges) { - E_Int to_delete = -1; - for (auto e : bedges) { - if (Sf.E[e].p == current_point) { - pchain.push_back(Sf.E[e].q); - current_point = pchain.back(); - to_delete = e; - break; - } else if (Sf.E[e].q == current_point) { - pchain.push_back(Sf.E[e].p); - current_point = pchain.back(); - to_delete = e; - break; - } - } - assert(to_delete != -1); - bedges.erase(to_delete); - } - - assert(pchain.size() == nbedges); - - // Sort the pchain counterclockwise - E_Int a = pchain[0], b = pchain[1], c = pchain[2]; - E_Float ux = Sf.X[b] - Sf.X[a]; - E_Float uy = Sf.Y[b] - Sf.Y[a]; - E_Float uz = Sf.Z[b] - Sf.Z[a]; - E_Float vx = Sf.X[c] - Sf.X[b]; - E_Float vy = Sf.Y[c] - Sf.Y[b]; - E_Float vz = Sf.Z[c] - Sf.Z[b]; - E_Float cp[3] = {uy*vz - uz*vy, uz*vx - ux*vz, ux*vy - uy*vx}; - // TODO(Imad): inherit fnormals - const E_Float *N_b = &fnormals[3*plocs[b].fid]; - E_Float dp = K_MATH::dot(cp, N_b, 3); - E_Int cmp = Sign(dp); - assert(cmp != 0); - if (cmp < 0) std::reverse(pchain.begin(), pchain.end()); - - Sf.write_points("pchain", pchain); - - for (E_Int p : pchain) pchains.push_back({Sf.X[p], Sf.Y[p], Sf.Z[p]}); - - std::set wfids; - std::set weids; - - for (size_t i = 0; i < pchain.size(); i++) { - E_Int p = pchain[i]; - E_Int q = pchain[(i+1)%pchain.size()]; - - E_Float px = Sf.X[p], py = Sf.Y[p], pz = Sf.Z[p]; - E_Float qx = Sf.X[q], qy = Sf.Y[q], qz = Sf.Z[q]; - - //point_write("p", px, py, pz); - //point_write("q", qx, qy, qz); - - E_Float D[3] = {qx-px, qy-py, qz-pz}; - E_Float NORM = K_MATH::norm(D, 3); - D[0] /= NORM, D[1] /= NORM, D[2] /= NORM; - - std::vector orig_faces; - std::vector tail_faces; - - E_Int last_vertex = -1, last_edge = -1, dummy; - - get_shared_faces(plocs[p], orig_faces, last_vertex, last_edge); - get_shared_faces(plocs[q], tail_faces, dummy, dummy); - - E_Int starting_face = deduce_face(orig_faces, px, py, pz, - D, last_vertex, last_edge); - assert(starting_face != -1); - - bool found_tail = false; - E_Int cur_fid = starting_face; - E_Float cur_pos[3] = {px, py, pz}; - - E_Int walk = 0; - E_Int max_walks = 20; - - while (!found_tail && walk <= max_walks) { - - wfids.insert(cur_fid); - - //write_face("cur_fid", cur_fid); - - E_Float proj[3]; - get_unit_projected_direction(cur_fid, D, proj); - - const auto &pn = Fc[cur_fid]; - const auto &pe = F2E[cur_fid]; - assert(pe.size() == pn.size()); - const E_Float *fN = &fnormals[3*cur_fid]; - - // First pass: define the wall data - for (size_t i = 0; i < pn.size(); i++) { - E_Int p = pn[i]; - E_Int q = pn[(i+1)%pn.size()]; - E_Int e = pe[i]; - E_Float px = X[p], py = Y[p], pz = Z[p]; - E_Float qx = X[q], qy = Y[q], qz = Z[q]; - if (ray_point_orient(cur_pos, proj, fN, px, py, pz) <= 0 || - ray_point_orient(cur_pos, proj, fN, qx, qy, qz) <= 0) { - weids.insert(e); - } - } - - //write_edges("wall", weids); - - for (auto fid : tail_faces) { - if (fid == cur_fid) { - found_tail = true; - break; - } - } - - if (found_tail) break; - - E_Int next_fid = -1; - E_Float next_pos[3] = {EFLOATMAX, EFLOATMAX, EFLOATMAX}; - - bool hit = false; - - for (size_t i = 0; i < pn.size(); i++) { - E_Int p = pn[i]; - E_Int q = pn[(i+1)%pn.size()]; - E_Int e = pe[i]; - - - if (p == last_vertex || q == last_vertex || e == last_edge) - continue; - - E_Float px = X[p], py = Y[p], pz = Z[p]; - E_Float qx = X[q], qy = Y[q], qz = Z[q]; - - E_Float t, s; - hit = ray_edge_intersect( - cur_pos[0], cur_pos[1], cur_pos[2], - proj[0], proj[1], proj[2], - px, py, pz, qx, qy, qz, - t, s - ); - - if (hit) { - if (s > TOL && s < 1 - TOL) { - const auto &pe = F2E[cur_fid]; - E_Int eid = pe[i]; - last_edge = eid; - last_vertex = -1; - assert(E2F[eid][0] == cur_fid || E2F[eid][1] == cur_fid); - if (E2F[eid][0] == cur_fid) next_fid = E2F[eid][1]; - else next_fid = E2F[eid][0]; - - next_pos[0] = cur_pos[0] + t * proj[0]; - next_pos[1] = cur_pos[1] + t * proj[1]; - next_pos[2] = cur_pos[2] + t * proj[2]; - } else { - bool hit_p = (s <= TOL); - bool hit_q = (s >= 1 - TOL); - assert(!(hit_p && hit_q)); - last_edge = -1; - if (hit_p) last_vertex = p; - else last_vertex = q; - next_pos[0] = X[last_vertex]; - next_pos[1] = Y[last_vertex]; - next_pos[2] = Z[last_vertex]; - const auto &pf = P2F[last_vertex]; - next_fid = deduce_face(pf, - next_pos[0], next_pos[1], next_pos[2], - D, last_vertex, last_edge - ); - assert(next_fid != -1); - } - break; - } - } - - assert(hit); - assert(next_fid != cur_fid); - cur_fid = next_fid; - cur_pos[0] = next_pos[0]; - cur_pos[1] = next_pos[1]; - cur_pos[2] = next_pos[2]; - walk++; - } - - assert(found_tail); - assert(walk <= max_walks); - } - - // TODO(Imad): project wpids on best-fit plane and jarvis march - - // BFS to get the smesh mpids - std::queue Q; - for (E_Int fid : wfids) Q.push(fid); - - //write_ngon("fwall_before_BFS", wfids); - - while (!Q.empty()) { - E_Int fid = Q.front(); - Q.pop(); - - const auto &neis = F2F[fid]; - const auto &pe = F2E[fid]; - - for (size_t i = 0; i < pe.size(); i++) { - E_Int eid = pe[i]; - if (weids.find(eid) != weids.end()) continue; - E_Int nei = neis[i]; - if (wfids.find(nei) == wfids.end()) { - wfids.insert(nei); - Q.push(nei); - } - } - } - - //write_ngon("fwall_after_BFS", wfids); - - //write_ngon("fwall", wfids); - //write_edges("ewall", weids); - - for (E_Int eid : weids) ewalls.insert(eid); - for (E_Int fid : wfids) fwalls.insert(fid); - - return wfids; -} +#include "dcel.h" ICapsule::ICapsule(const Karray &marray, const std::vector &sarrays, const std::vector &ptags) @@ -351,7 +41,7 @@ ICapsule::ICapsule(const Karray &marray, const std::vector &sarrays, IMesh S(sarrays[i]); S.set_tolerances(NEAR_VERTEX_TOL, NEAR_EDGE_TOL); S.make_skin(); - S.orient_skin(IN); + S.orient_skin(OUT); S.triangulate_skin(); Ss.push_back(S); @@ -379,8 +69,25 @@ ICapsule::ICapsule(const Karray &marray, const std::vector &sarrays, // Refinement loop refine(Mf, bfaces, Sf, plocs); - //bfaces = Mf.extract_bounding_faces(Sf, plocs); - //Mf.write_ngon("bounding_after", bfaces); + bfaces = Mf.extract_bounding_faces(Sf, plocs); + //Mf.write_ngon("bounding_after.im", bfaces); + + // Make a patch out of Mf bounding faces + Smesh Bf(Mf, bfaces, false); + Bf.make_fcenters(); + Bf.make_fnormals(); + Bf.make_pnormals(); + + // Make two DCELs out of Bf and Sf + Dcel Db(Bf, Dcel::RED); + Db.write_inner_cycles("Db.im"); + + Sf.write_ngon("refinement_Sf.im"); + + Dcel Ds(Sf, Dcel::BLACK); + Ds.write_inner_cycles("Ds_inner.im"); + Ds.write_outer_cycles("Ds_outer.im"); + Ds.write_hole_cycles("Ds_hole.im"); // Add Sf spatches.push_back(Sf); @@ -391,7 +98,9 @@ ICapsule::ICapsule(const Karray &marray, const std::vector &sarrays, puts(""); } - Mf.write_ngon("refined_Mf"); + Mf.write_ngon("refined_Mf.im"); + + } diff --git a/Cassiopee/XCore/XCore/intersectMesh/intersectMesh.cpp b/Cassiopee/XCore/XCore/intersectMesh/intersectMesh.cpp index ac33f2928..fa76a1073 100644 --- a/Cassiopee/XCore/XCore/intersectMesh/intersectMesh.cpp +++ b/Cassiopee/XCore/XCore/intersectMesh/intersectMesh.cpp @@ -22,17 +22,14 @@ #include "mesh.h" #include "smesh.h" #include "dcel.h" -#include "vertex.h" -#include "face.h" -#include "hedge.h" #include "io.h" -#include "cycle.h" #include "triangle.h" #include "primitives.h" -static IMesh reconstruct_mesh(IMesh &M, Smesh &Mf, const Dcel &D, E_Int color) { + assert(0); + /* // Isolate patch faces std::set pfset(M.patch); @@ -131,33 +128,6 @@ IMesh reconstruct_mesh(IMesh &M, Smesh &Mf, const Dcel &D, E_Int color) // All ofaces must be present in the map assert(ofid_to_ofids.size() == pfset.size()); - /* - { - if (color == 1) { - std::vector faces; - auto it = ofid_to_ofids.find(24406); - assert(it != ofid_to_ofids.end()); - const auto &pf = it->second; - printf("number of children: %lu\n", pf.size()); - for (auto i : pf) faces.push_back(D.F[i]); - faces_write("children1", faces); - } - - if (color == 1) { - std::vector faces; - auto it = ofid_to_ofids.find(40246); - assert(it != ofid_to_ofids.end()); - const auto &pf = it->second; - printf("number of children: %lu\n", pf.size()); - for (auto i : pf) { - char fname[64] = {0}; - sprintf(fname, "child%d", i); - face_write(fname, D.F[i]); - } - } - } - */ - // Write untouched points std::vector new_X(np, -1), new_Y(np, -1), new_Z(np, -1); for (const auto &pt : new_pids) { @@ -310,10 +280,13 @@ IMesh reconstruct_mesh(IMesh &M, Smesh &Mf, const Dcel &D, E_Int color) new_M.ctag = M.ctag; return new_M; + */ + return IMesh(); } PyObject *K_XCORE::intersectMesh(PyObject *self, PyObject *args) { + /* PyObject *MASTER, *SLAVE, *MPATCH, *SPATCH; if (!PYPARSETUPLE_(args, OOOO_, &MASTER, &MPATCH, &SLAVE, &SPATCH)) { @@ -398,11 +371,9 @@ PyObject *K_XCORE::intersectMesh(PyObject *self, PyObject *args) Mf.write_ngon("Mf"); Sf.write_ngon("Sf"); - /* puts("Making point edges..."); Mf.make_point_edges(); Sf.make_point_edges(); - */ puts("Making point faces..."); Mf.make_point_faces(); @@ -418,44 +389,8 @@ PyObject *K_XCORE::intersectMesh(PyObject *self, PyObject *args) puts("Initaliazing..."); - /* - puts("Doing Mf to Dcel"); - Dcel Dm(Mf, Dcel::RED); - Dm.export_smesh(); - puts("Doing Sf to Dcel"); - Dcel Ds(Sf, Dcel::RED); - Ds.export_smesh(); - */ - Dcel D(Mf, Sf); - /* - { - Face *f1 = D.F[Mf.nf + Sf.g2lf[D.weird1]]; - Face *f2 = D.F[Mf.nf + Sf.g2lf[D.weird2]]; - face_write("f1", f1); - face_write("f2", f2); - } - */ - - - - /* - for (Vertex *v : D.V) { - if (v->oid[0] != -1) { - Mf.X[v->oid[0]] = v->x; - Mf.Y[v->oid[0]] = v->y; - Mf.Z[v->oid[0]] = v->z; - } - - if (v->oid[1] != -1) { - Sf.X[v->oid[1]] = v->x; - Sf.Y[v->oid[1]] = v->y; - Sf.Z[v->oid[1]] = v->z; - } - } - */ - puts("Locating points..."); D.locate_spoints(Mf, Sf); @@ -509,4 +444,6 @@ PyObject *K_XCORE::intersectMesh(PyObject *self, PyObject *args) Py_DECREF(Sout); return out; + */ + return Py_None; } diff --git a/Cassiopee/XCore/XCore/intersectMesh/io.cpp b/Cassiopee/XCore/XCore/intersectMesh/io.cpp index 660fe0542..7257a5996 100644 --- a/Cassiopee/XCore/XCore/intersectMesh/io.cpp +++ b/Cassiopee/XCore/XCore/intersectMesh/io.cpp @@ -20,86 +20,6 @@ #include #include "io.h" -#include "face.h" - -void face_write(const char *fname, Face *f) -{ - FILE *fh = fopen(fname, "w"); - assert(fh); - - E_Int np = 1; - Hedge *h = f->rep; - Hedge *w = h->next; - while (w != h) { - np++; - w = w->next; - } - - fprintf(fh, "POINTS\n"); - fprintf(fh, "%d\n", np); - - h = f->rep; - Vertex *v = h->orig; - fprintf(fh, "%f %f %f\n", v->x, v->y, v->z); - w = h->next; - while (w != h) { - v = w->orig; - fprintf(fh, "%f %f %f\n", v->x, v->y, v->z); - w = w->next; - } - fclose(fh); -} - -void faces_write(const char *fname, const std::vector &faces, E_Float scale) -{ - FILE *fh = fopen(fname, "w"); - assert(fh); - - E_Int NP = 0; - for (const Face *f : faces) { - E_Int np = 1; - Hedge *h = f->rep; - Hedge *w = h->next; - while (w != h) { - np++; - w = w->next; - } - NP += np; - } - - fprintf(fh, "POINTS\n"); - fprintf(fh, "%d\n", NP); - - for (const Face *f : faces) { - Hedge *h = f->rep; - Vertex *v = h->orig; - fprintf(fh, "%f %f %f\n", scale*v->x, scale*v->y, scale*v->z); - Hedge *w = h->next; - while (w != h) { - v = w->orig; - fprintf(fh, "%f %f %f\n", scale*v->x, scale*v->y, scale*v->z); - w = w->next; - } - } - - fclose(fh); -} - -void hedge_write(const char *fname, const Hedge *h) -{ - FILE *fh = fopen(fname, "w"); - assert(fh); - fprintf(fh, "POINTS\n"); - fprintf(fh, "2\n"); - Vertex *p = h->orig; - Vertex *q = h->twin->orig; - fprintf(fh, "%f %f %f\n", p->x, p->y, p->z); - fprintf(fh, "%f %f %f\n", q->x, q->y, q->z); - fprintf(fh, "EDGES\n"); - fprintf(fh, "1\n"); - fprintf(fh, "0 1\n"); - fclose(fh); -} void point_write(const char *fname, E_Float x, E_Float y, E_Float z) { @@ -111,26 +31,6 @@ void point_write(const char *fname, E_Float x, E_Float y, E_Float z) fclose(fh); } -void point_write(const char *fname, Vertex *v) -{ - FILE *fh = fopen(fname, "w"); - assert(fh); - fprintf(fh, "POINTS\n"); - fprintf(fh, "1\n"); - fprintf(fh, "%f %f %f\n", v->x, v->y, v->z); - fclose(fh); -} - -void point_write(const char *fname, const std::vector &I) -{ - FILE *fh = fopen(fname, "w"); - assert(fh); - fprintf(fh, "POINTS\n"); - fprintf(fh, "%zu\n", I.size()); - for (auto &v : I) fprintf(fh, "%f %f %f\n", v->x, v->y, v->z); - fclose(fh); -} - void point_write(const char *fname, E_Float *Xs, E_Float *Ys, E_Float *Zs, const std::vector &P) { @@ -148,7 +48,7 @@ void point_write(const char *fname, const std::vector &P) assert(fh); fprintf(fh, "POINTS\n"); fprintf(fh, "%zu\n", P.size()); - for (auto p : P) fprintf(fh, "%f %f %f\n", p[0], p[1], p[2]); + for (auto p : P) fprintf(fh, "%f %f %f\n", p.x, p.y, p.z); fclose(fh); } @@ -188,22 +88,3 @@ void edge_write(const char *fname, E_Float px, E_Float py, E_Float pz, fprintf(fh, "0 1\n"); fclose(fh); } - -void edges_write(const char *fname, const std::vector &edges) -{ - FILE *fh = fopen(fname, "w"); - assert(fh); - fprintf(fh, "POINTS\n"); - fprintf(fh, "%zu\n", edges.size() * 2); - for (auto e : edges) { - fprintf(fh, "%f %f %f\n", e.px, e.py, e.pz); - fprintf(fh, "%f %f %f\n", e.qx, e.qy, e.qz); - } - fprintf(fh, "EDGES\n"); - fprintf(fh, "%zu\n", edges.size()); - for (size_t i = 0; i < 2*edges.size(); i++) { - fprintf(fh, "%zu ", i); - } - fprintf(fh, "\n"); - fclose(fh); -} diff --git a/Cassiopee/XCore/XCore/intersectMesh/io.h b/Cassiopee/XCore/XCore/intersectMesh/io.h index 4f22975ab..511a434cd 100644 --- a/Cassiopee/XCore/XCore/intersectMesh/io.h +++ b/Cassiopee/XCore/XCore/intersectMesh/io.h @@ -21,36 +21,14 @@ #include #include -#include "xcore.h" -#include "vertex.h" -#include "triangleIntersection.h" +#include "triangle.h" #include "common/common.h" #include "point.h" -#include "hedge.h" - -struct IO_Edge { - E_Float px, py, pz; - E_Float qx, qy, qz; - - IO_Edge(E_Float PX, E_Float PY, E_Float PZ, E_Float QX, E_Float QY, E_Float QZ) - : px(PX), py(PY), pz(PZ), qx(QX), qy(QY), qz(QZ) - {} -}; - -void face_write(const char *fname, Face *face); - -void faces_write(const char *fname, const std::vector &faces, E_Float scale = 1.0); void point_write(const char *fname, E_Float x, E_Float y, E_Float z); -void point_write(const char *fname, Vertex *v); - -void hedge_write(const char *fname, const Hedge *h); - void point_write(const char *fname, const std::vector &P); -void point_write(const char *fname, const std::vector &I); - void point_write(const char *fname, E_Float *Xs, E_Float *Ys, E_Float *Zs, const std::vector &proj_points); @@ -59,5 +37,3 @@ void edge_write(const char *fname, E_Float *X, E_Float *Y, E_Float *Z, void edge_write(const char *fname, E_Float px, E_Float py, E_Float pz, E_Float qx, E_Float qy, E_Float qz); - -void edges_write(const char *fname, const std::vector &edges); diff --git a/Cassiopee/XCore/XCore/intersectMesh/mesh.h b/Cassiopee/XCore/XCore/intersectMesh/mesh.h index bd4b67652..9316a419c 100644 --- a/Cassiopee/XCore/XCore/intersectMesh/mesh.h +++ b/Cassiopee/XCore/XCore/intersectMesh/mesh.h @@ -27,7 +27,7 @@ #include "point.h" #include "xcore.h" #include "common/common.h" -#include "triangleIntersection.h" +#include "triangle.h" #include "AABB.h" #include "smesh.h" diff --git a/Cassiopee/XCore/XCore/intersectMesh/point.h b/Cassiopee/XCore/XCore/intersectMesh/point.h index b5de436b3..a734d73c9 100644 --- a/Cassiopee/XCore/XCore/intersectMesh/point.h +++ b/Cassiopee/XCore/XCore/intersectMesh/point.h @@ -18,9 +18,11 @@ */ #pragma once -#include "vec3.h" +#include "xcore.h" -typedef Vec3 Point; +struct Point { + E_Float x, y, z; +}; struct PointLoc { E_Int fid = -1; diff --git a/Cassiopee/XCore/XCore/intersectMesh/prepareMeshesForIntersection.cpp b/Cassiopee/XCore/XCore/intersectMesh/prepareMeshesForIntersection.cpp index 8069bb338..aaeed0102 100644 --- a/Cassiopee/XCore/XCore/intersectMesh/prepareMeshesForIntersection.cpp +++ b/Cassiopee/XCore/XCore/intersectMesh/prepareMeshesForIntersection.cpp @@ -22,15 +22,12 @@ #include "mesh.h" #include "smesh.h" #include "dcel.h" -#include "vertex.h" -#include "face.h" -#include "hedge.h" #include "io.h" -#include "cycle.h" #include "triangle.h" PyObject *K_XCORE::prepareMeshesForIntersection(PyObject *self, PyObject *args) { + /* PyObject *MASTER, *SLAVE, *TAG; if (!PYPARSETUPLE_(args, OOO_, &MASTER, &SLAVE, &TAG)) { @@ -164,4 +161,6 @@ PyObject *K_XCORE::prepareMeshesForIntersection(PyObject *self, PyObject *args) Py_DECREF(TAG); return Out; + */ + return Py_None; } diff --git a/Cassiopee/XCore/XCore/intersectMesh/primitives.cpp b/Cassiopee/XCore/XCore/intersectMesh/primitives.cpp index 3972f3e24..acb4c846f 100644 --- a/Cassiopee/XCore/XCore/intersectMesh/primitives.cpp +++ b/Cassiopee/XCore/XCore/intersectMesh/primitives.cpp @@ -21,17 +21,16 @@ #include #include "primitives.h" -#include "event.h" E_Int Sign(E_Float x, E_Float tol) { if (x > tol) return 1; if (x < -tol) return -1; - //assert(x == 0.0); return 0; } -E_Int cmp_points(E_Float x1, E_Float y1, E_Float z1, E_Float x2, E_Float y2, E_Float z2) +E_Int cmp_points(E_Float x1, E_Float y1, E_Float z1, + E_Float x2, E_Float y2, E_Float z2) { E_Float t = x1 - x2; E_Int s = Sign(t); @@ -45,311 +44,46 @@ E_Int cmp_points(E_Float x1, E_Float y1, E_Float z1, E_Float x2, E_Float y2, E_F return Sign(t); } -/* -E_Int cmp_points(E_Float x1, E_Float y1, E_Float x2, E_Float y2) +bool ray_edge_intersect(E_Float ox, E_Float oy, E_Float oz, + E_Float dx, E_Float dy, E_Float dz, + E_Float px, E_Float py, E_Float pz, + E_Float qx, E_Float qy, E_Float qz, + E_Float &t, E_Float &u, + bool coplanar) { - E_Float t = x1 - x2; - E_Int s = Sign(t); - if (s) return s; - - t = y1 - y2; - return Sign(t); -} -*/ - -E_Int cmp_segments -( - E_Float px0, E_Float py0, - E_Float px1, E_Float py1, - E_Float qx1, E_Float qy1, - E_Float rx, E_Float ry, - E_Float dx0, E_Float dy0, - E_Float dx1, E_Float dy1 -) -{ - E_Float T1 = dy0 * dx1 - dy1 * dx0; - - E_Int sign1 = Sign(T1); + E_Float v[3]= {px-ox, py-oy, pz-oz}; - if (sign1 == 0) { + E_Float dl[3] = {qx-px, qy-py, qz-pz}; - E_Float mdx = qx1 - px0; - E_Float mdy = qy1 - py0; + E_Float dr[3] = {dx, dy, dz}; - E_Int sign2 = Sign(dy0 * mdx - mdy * dx0); - - if (sign2 == 0) { - E_Int sign3 = Sign(dy1 * mdx - mdy * dx1); + if (!coplanar) { + E_Float w[3]; + K_MATH::cross(v, dl, w); + E_Float det = K_MATH::dot(w, dr, 3); - assert(sign3 == 0); - - if (sign3 == 0) { - return 0; - } - } - } - - if (Sign(dx0) == 0) { - E_Float T2 = (py1 * dx1 - px1 * dy1) + (dy1 * rx - ry * dx1); - E_Int sign2 = Sign(T2); - return (sign2 <= 0) ? 1 : -1; + // Ray and edge must be coplanar + if (Sign(det) != 0) return false; } - if (Sign(dx1) == 0) { - E_Float T2 = (py0 * dx0 - px0 * dy0) + (dy0 * rx - ry * dx0); - E_Int sign2 = Sign(T2); - return (sign2 <= 0) ? -1 : 1; - } - - E_Float T2 = dx1 * (py0 * dx0 + dy0 * (rx - px0)) - dx0 - * (py1 * dx1 + dy1 * (rx - px1)); - - E_Int sign2 = Sign(T2); - if (sign2 != 0) return sign2; - - E_Float T3 = (py0 * dx0 - px0 * dy0) + (dy0 * rx - ry * dx0); - E_Int sign3 = Sign(T3); - return (sign3 <= 0) ? sign1 : -sign1; -} - -// We define the compare functions for Vertexs and Segments by first calling -// cmp_points and cmp_segments on the floating point filter coordinates of the -// corresponding points and segments. In the case that these calls do not -// return a reliable result (i.e. return NO_IDEA) we call them again with the -// exact routines. -E_Int compare(const Vertex &a, const Vertex &b) -{ - return cmp_points(a.x, a.y, a.z, b.x, b.y, b.z); -} - -E_Int compare(const Segment &s1, const Segment &s2, E_Float rx, E_Float ry) -{ - return cmp_segments(s1.p->x, s1.p->y, - s2.p->x, s2.p->y, - s2.q->x, s2.q->y, - rx, ry, - s1.dx, s1.dy, s2.dx, s2.dy); -} - -E_Int cmp_mySeg(const Segment &s1, const Segment &s2) -{ - E_Int cmp = cmp_points(s1.p->x, s1.p->y, s1.p->z, s2.p->x, s2.p->y, - s2.p->z); - if (cmp) return cmp; - - cmp = Sign(s1.color - s2.color); - if (cmp) return cmp; - - cmp = Sign(s1.id - s2.id); - - assert(cmp); - - return cmp; -} - -void compute_intersection(Queue &Q, Snode *sit0, Snode *sit1, - std::vector &I) -{ - Segment s0 = *sit0->key; - Segment s1 = *sit1->key; - - E_Float w = s0.dy * s1.dx - s1.dy * s0.dx; - E_Int i = Sign(w); - if (i == -1 || i == 0) return; - - E_Float c1 = s0.X2() * s0.Y1() - s0.X1() * s0.Y2(); - E_Float c2 = s1.X2() * s1.Y1() - s1.X1() * s1.Y2(); - - E_Float x = c2 * s0.dx - c1 * s1.dx; - E_Float d0 = x - s0.X2() * w; - if (Sign(d0) > 0) return; - if (Sign(x - s1.X2() * w) > 0) return; - - E_Float y = c2 * s0.dy - c1 * s1.dy; - if (Sign(d0) == 0 && - Sign(y - s0.Y2() * w) > 0) return; - - - x /= w; - y /= w; - - Event *xit = Q.lookup(x, y, 0); - - if (xit == NULL) { - xit = Q.insert(x, y, 0); - xit->key->id = I.size(); - I.push_back(xit->key); - } - - xit->inf = sit0->key; - sit0->inf = xit->key; -} - -E_Float DifferenceOfProducts(E_Float a, E_Float b, E_Float c, E_Float d) -{ - E_Float cd = c * d; - E_Float differenceOfProducts = std::fma(a, b, -cd); - E_Float err = std::fma(-c, d, cd); - return differenceOfProducts + err; -} - -E_Float dRand(E_Float dMin, E_Float dMax) -{ - E_Float d = (E_Float) rand() / RAND_MAX; - return dMin + d * (dMax - dMin); -} - -E_Int is_point_on_segment(E_Float px, E_Float py, E_Float pz, E_Float ax, E_Float ay, - E_Float az, E_Float bx, E_Float by, E_Float bz) -{ - E_Float Vab[3] = {bx-ax, by-ay, bz-az}; - E_Float Vap[3] = {px-ax, py-ay, pz-az}; - E_Float N[3]; - K_MATH::cross(Vab, Vap, N); - if (Sign(K_MATH::norm(N, 3)) != 0) return 0; - - E_Float Vbp[3] = {px-bx, py-by, pz-bz}; - - E_Float dp = K_MATH::dot(Vap, Vab, 3); - if (dp < -TOL) return 0; - - dp = K_MATH::dot(Vbp, Vab, 3); - if (dp > TOL) return 0; - - return 1; -} - -E_Int EdgeEdgeIntersect(E_Float ax, E_Float ay, E_Float az, E_Float bx, E_Float by, - E_Float bz, E_Float px, E_Float py, E_Float pz, E_Float qx, E_Float qy, E_Float qz, - E_Float &t) -{ - E_Float d1[3] = {bx-ax, by-ay, bz-az}; - E_Float d2[3] = {qx-px, qy-py, qz-pz}; - E_Float r[3] = {px-ax, py-ay, pz-az}; - - E_Float d1d2[3]; - K_MATH::cross(d1, d2, d1d2); - E_Float denom = K_MATH::dot(d1d2, d1d2, 3); - - if (Sign(denom) == 0) { - - return 0; - - /* - E_Float colli[3]; - K_MATH::cross(d1, r, colli); - E_Float NORM = K_MATH::norm(colli, 3); - if (Sign(NORM) == 0) { - assert("collinear!" && 0); - } else { - return 0; - } - */ - } + // ray and edge must not be parallel + E_Float n[3]; + K_MATH::cross(dr, dl, n); + E_Float denom = K_MATH::dot(n, n, 3); + if (Sign(denom) == 0) return false; E_Float tmp[3]; - K_MATH::cross(r, d2, tmp); - t = K_MATH::dot(tmp, d1d2, 3); - t /= denom; - if (t <= TOL) return 0; + K_MATH::cross(v, dl, tmp); - K_MATH::cross(r, d1, tmp); - E_Float u = K_MATH::dot(tmp, d1d2, 3); - u /= denom; - if (u < -TOL || u > 1 + TOL) return 0; + t = K_MATH::dot(tmp, n, 3) / denom; - //ix = px + u*(qx - px); - //iy = py + u*(qy - py); - //iz = pz + u*(qz - pz); + if (t < TOL) return false; - return 1; -} + K_MATH::cross(v, dr, tmp); -E_Int EdgeEdgeIntersect(E_Float ax, E_Float ay, E_Float az, E_Float bx, E_Float by, - E_Float bz, E_Float px, E_Float py, E_Float pz, E_Float qx, E_Float qy, E_Float qz, - E_Float &ix, E_Float &iy, E_Float &iz) -{ - E_Float d1[3] = {bx-ax, by-ay, bz-az}; - E_Float d2[3] = {qx-px, qy-py, qz-pz}; - E_Float r[3] = {px-ax, py-ay, pz-az}; - - E_Float d1d2[3]; - K_MATH::cross(d1, d2, d1d2); - E_Float denom = K_MATH::dot(d1d2, d1d2, 3); - - if (Sign(denom) == 0) { - - return 0; - - /* - E_Float colli[3]; - K_MATH::cross(d1, r, colli); - E_Float NORM = K_MATH::norm(colli, 3); - if (Sign(NORM) == 0) { - assert("collinear!" && 0); - } else { - return 0; - } - */ - } - - E_Float tmp[3]; - K_MATH::cross(r, d2, tmp); - E_Float t = K_MATH::dot(tmp, d1d2, 3); - t /= denom; - //if (t < -TOL) return 0; - if (t <= TOL) return 0; - - K_MATH::cross(r, d1, tmp); - E_Float u = K_MATH::dot(tmp, d1d2, 3); - u /= denom; - if (u < -TOL || u > 1 + TOL) return 0; - - ix = px + u*(qx - px); - iy = py + u*(qy - py); - iz = pz + u*(qz - pz); - - return 1; -} - -E_Int EdgeEdgeIntersect(E_Float ax, E_Float ay, E_Float az, E_Float bx, E_Float by, - E_Float bz, E_Float px, E_Float py, E_Float pz, E_Float qx, E_Float qy, E_Float qz) -{ - E_Float d1[3] = {bx-ax, by-ay, bz-az}; - E_Float d2[3] = {qx-px, qy-py, qz-pz}; - E_Float r[3] = {px-ax, py-ay, pz-az}; - - E_Float d1d2[3]; - K_MATH::cross(d1, d2, d1d2); - E_Float denom = K_MATH::dot(d1d2, d1d2, 3); - - if (Sign(denom) == 0) { - - return 0; - - /* - E_Float colli[3]; - K_MATH::cross(d1, r, colli); - E_Float NORM = K_MATH::norm(colli, 3); - if (Sign(NORM) == 0) { - assert("collinear!" && 0); - } else { - return 0; - } - */ - } - - E_Float tmp[3]; - K_MATH::cross(r, d2, tmp); - E_Float t = K_MATH::dot(tmp, d1d2, 3); - t /= denom; - //if (t < -TOL) return 0; - if (t <= TOL) return 0; + u = K_MATH::dot(tmp, n, 3) / denom; - K_MATH::cross(r, d1, tmp); - E_Float u = K_MATH::dot(tmp, d1d2, 3); - u /= denom; - if (u < -TOL || u > 1 + TOL) return 0; + if (u < -TOL || u > 1 + TOL) return false; - return 1; + return true; } diff --git a/Cassiopee/XCore/XCore/intersectMesh/primitives.h b/Cassiopee/XCore/XCore/intersectMesh/primitives.h index d0ff63210..bc4e453a7 100644 --- a/Cassiopee/XCore/XCore/intersectMesh/primitives.h +++ b/Cassiopee/XCore/XCore/intersectMesh/primitives.h @@ -20,53 +20,21 @@ #include -#include "queue.h" -#include "status.h" #include "common/common.h" constexpr E_Float TOL = 1e-12; -void compute_intersection(Queue &Q, Snode *sit0, Snode *sit1, - std::vector &I); - -E_Int compare(const Vertex &a, const Vertex &b); - -E_Int compare(const Segment &s0, const Segment &s1, E_Float rx, E_Float ry); - -E_Int cmp_mySeg(const Segment &s1, const Segment &s2); - -E_Int cmp_points(E_Float x1, E_Float y1, E_Float z1, E_Float x2, E_Float y2, E_Float z2); -//E_Int cmp_points(E_Float x1, E_Float y1, E_Float x2, E_Float y2); - -E_Float DifferenceOfProducts(E_Float a, E_Float b, E_Float c, E_Float d); - -E_Float TwoDiff(E_Float a, E_Float b); - E_Int Sign(E_Float x, E_Float tol=TOL); -E_Int orient3D(E_Float *A, E_Float *B, E_Float *C, E_Float *D); - -E_Float dRand(E_Float dMin, E_Float dMax); - -E_Int is_point_on_segment(E_Float px, E_Float py, E_Float pz, E_Float ax, E_Float ay, - E_Float az, E_Float bx, E_Float by, E_Float bz); - -E_Int EdgeEdgeIntersect(E_Float ax, E_Float ay, E_Float az, E_Float bx, E_Float by, - E_Float bz, E_Float px, E_Float py, E_Float pz, E_Float qx, E_Float qy, E_Float qz, - E_Float &ix, E_Float &iy, E_Float &iz); - -E_Int EdgeEdgeIntersect(E_Float ax, E_Float ay, E_Float az, E_Float bx, E_Float by, - E_Float bz, E_Float px, E_Float py, E_Float pz, E_Float qx, E_Float qy, E_Float qz); - -E_Int EdgeEdgeIntersect(E_Float ax, E_Float ay, E_Float az, E_Float bx, E_Float by, - E_Float bz, E_Float px, E_Float py, E_Float pz, E_Float qx, E_Float qy, E_Float qz, - E_Float &t); +E_Int cmp_points(E_Float x1, E_Float y1, E_Float z1, + E_Float x2, E_Float y2, E_Float z2); bool ray_edge_intersect(E_Float ox, E_Float oy, E_Float oz, E_Float dx, E_Float dy, E_Float dz, E_Float px, E_Float py, E_Float pz, E_Float qx, E_Float qy, E_Float qz, - E_Float &t, E_Float &u); + E_Float &t, E_Float &u, + bool coplanar = true); E_Int ray_point_orient(const E_Float o[3], const E_Float d[3], const E_Float fN[3], E_Float px, E_Float py, E_Float pz); diff --git a/Cassiopee/XCore/XCore/intersectMesh/project.cpp b/Cassiopee/XCore/XCore/intersectMesh/project.cpp deleted file mode 100644 index 57e51bae2..000000000 --- a/Cassiopee/XCore/XCore/intersectMesh/project.cpp +++ /dev/null @@ -1,20 +0,0 @@ -#include "mesh.h" - -void IMesh::grid_patch() -{ - - - - - -} - -void IMesh::project_patch(const IMesh &S) -{ - - - - - - -} diff --git a/Cassiopee/XCore/XCore/intersectMesh/queue.cpp b/Cassiopee/XCore/XCore/intersectMesh/queue.cpp deleted file mode 100644 index e52fc7bf7..000000000 --- a/Cassiopee/XCore/XCore/intersectMesh/queue.cpp +++ /dev/null @@ -1,181 +0,0 @@ -/* - Copyright 2013-2024 Onera. - - This file is part of Cassiopee. - - Cassiopee is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - Cassiopee is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with Cassiopee. If not, see . -*/ -#include -#include - -#include "queue.h" -#include "primitives.h" -#include "event.h" - -Queue::Queue() -: root(NULL), nelem(0) -{} - -// Insert an intersection -Event *Queue::insert(E_Float x, E_Float y, E_Float z) -{ - return insert_(root, x, y, z); -} - -Event *Queue::insert_(Event *&root, E_Float x, E_Float y, E_Float z) -{ - if (root == NULL) { - root = new Event(x, y, z); - return root; - } - - Vertex *key = root->key; - - E_Int cmp = cmp_points(key->x, key->y, key->z, x, y, z); - - if (cmp == 0) { - return root; - } else if (cmp < 0) { - return insert_(root->right, x, y, z); - } else { - return insert_(root->left, x, y, z); - } -} - -// Insert an input vertex -Event *Queue::insert(E_Float x, E_Float y, E_Float z, E_Int oid, E_Int color) -{ - return insert_(root, x, y, z, oid, color); -} - -Event *Queue::insert_(Event *&root, E_Float x, E_Float y, E_Float z, E_Int oid, E_Int color) -{ - if (root == NULL) { - root = new Event(x, y, z, oid, color); - return root; - } - - Vertex *key = root->key; - - E_Int cmp = cmp_points(key->x, key->y, key->z, x, y, z); - - if (cmp == 0) { - assert(key->oid[color] == -1); - assert(key->oid[(color+1)%2] != -1); - key->oid[color] = oid; - return root; - } else if (cmp < 0) { - return insert_(root->right, x, y, z, oid, color); - } else { - return insert_(root->left, x, y, z, oid, color); - } -} - -Event *Queue::lookup(E_Float x, E_Float y, E_Float z) -{ - return lookup_(root, x, y, z); -} - -Event *Queue::lookup(Vertex *key) -{ - return lookup_(root, key->x, key->y, key->z); -} - -Event *Queue::lookup_(Event *root, E_Float x, E_Float y, E_Float z) -{ - if (root == NULL) return NULL; - - Vertex *key = root->key; - E_Int cmp = cmp_points(key->x, key->y, key->z, x, y, z); - - if (cmp == 0) return root; - else if (cmp < 0) return lookup_(root->right, x, y, z); - else return lookup_(root->left, x, y, z); -} - -Event *Queue::min() -{ - if (root == NULL) return NULL; - - Event *curr = root; - - while (curr->left != NULL) curr = curr->left; - - return curr; -} - -void Queue::erase(Event *event) -{ - root = erase_(root, event->key); -} - -void Queue::erase(Vertex *p) -{ - root = erase_(root, p); -} - -Event *Queue::erase_(Event *root, Vertex *p) -{ - if (root == NULL) return NULL; - - E_Int cmp = compare(*root->key, *p); - - if (cmp < 0) { - root->right = erase_(root->right, p); - return root; - } else if (cmp > 0) { - root->left = erase_(root->left, p); - return root; - } - - assert(root->key == p); - - if (root->left == NULL) { - Event *tmp = root->right; - delete root; - return tmp; - } else if (root->right == NULL) { - Event *tmp = root->left; - delete root; - return tmp; - } else { - Event *succ_parent = root; - - Event *succ = root->right; - while (succ->left) { - succ_parent = succ; - succ = succ->left; - } - - if (succ_parent != root) succ_parent->left = succ->right; - else succ_parent->right = succ->left; - - root->key = succ->key; - root->inf = succ->inf; - - delete succ; - return root; - } -} - -void Queue::inorder(std::vector &V) const -{ - if (root == NULL) return; - root->inorder(V); -} - -void Queue::drop() -{ - Event_drop(root); -} \ No newline at end of file diff --git a/Cassiopee/XCore/XCore/intersectMesh/queue.h b/Cassiopee/XCore/XCore/intersectMesh/queue.h deleted file mode 100644 index c60c89c1b..000000000 --- a/Cassiopee/XCore/XCore/intersectMesh/queue.h +++ /dev/null @@ -1,65 +0,0 @@ -/* - Copyright 2013-2024 Onera. - - This file is part of Cassiopee. - - Cassiopee is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - Cassiopee is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with Cassiopee. If not, see . -*/ -#pragma once - -#include -#include - -#include "xcore.h" -#include "common/common.h" - -struct Vertex; -struct Segment; -struct Event; - -struct Queue { - Event *root; - - E_Int nelem; - - Queue(); - - Event *insert(E_Float X, E_Float Y, E_Float Z, E_Int oid, E_Int color); - - Event *insert(E_Float X, E_Float Y, E_Float Z); - - Event *lookup(Vertex *key); - - Event *lookup(E_Float x, E_Float y, E_Float z); - - inline bool empty() { return root == NULL; } - - Event *min(); - - void erase(Event *event); - - void erase(Vertex *p); - - void inorder(std::vector &V) const; - - Event *insert_(Event *&root, E_Float x, E_Float y, E_Float z, E_Int oid, E_Int color); - - Event *insert_(Event *&root, E_Float x, E_Float y, E_Float z); - - Event *lookup_(Event *root, E_Float x, E_Float y, E_Float z); - - Event *erase_(Event *root, Vertex *p); - - void drop(); -}; diff --git a/Cassiopee/XCore/XCore/intersectMesh/ray.cpp b/Cassiopee/XCore/XCore/intersectMesh/ray.cpp index 8b8cdbff2..671de6ebf 100644 --- a/Cassiopee/XCore/XCore/intersectMesh/ray.cpp +++ b/Cassiopee/XCore/XCore/intersectMesh/ray.cpp @@ -20,6 +20,20 @@ #include "primitives.h" #include "AABB.h" +E_Int ray_point_orient(const E_Float o[3], const E_Float d[3], + const E_Float fN[3], E_Float px, E_Float py, E_Float pz) +{ + E_Float w[3] = {px-o[0], py-o[1], pz-o[2]}; + E_Float c[3]; + K_MATH::cross(d, w, c); + E_Float dp = K_MATH::dot(c, fN, 3); + // TODO(Imad): needs FEA + float128 + E_Int cmp = Sign(dp); + if (cmp > 0) return 1; + if (cmp < 0) return -1; + return 0; +} + bool ray_AABB_intersect(E_Float ox, E_Float oy, E_Float oz, E_Float dx, E_Float dy, E_Float dz, const AABB &box) @@ -183,12 +197,18 @@ E_Int MollerTrumbore(E_Float px, E_Float py, E_Float pz, E_Float dx, E_Float dy, return 0; } -Ray::Ray(Point O, Vec3 D) +/* +Ray::Ray(Point O, E_Float D[3]) : org(O), dir(D) { - E_Float adx = fabs(dir[0]); - E_Float ady = fabs(dir[1]); - E_Float adz = fabs(dir[2]); + org.x = O.x; + org.y = O.y; + org.z = O.z; + + + E_Float adx = fabs(dir.x); + E_Float ady = fabs(dir.y); + E_Float adz = fabs(dir.z); if (adx > ady && adx > adz) kz = 0; else if (ady > adz) kz = 1; @@ -271,3 +291,4 @@ E_Int Ray::intersect_triangle(const Point &a, const Point &b, const Point &c, return 1; } +*/ diff --git a/Cassiopee/XCore/XCore/intersectMesh/ray.h b/Cassiopee/XCore/XCore/intersectMesh/ray.h index 59df8c2e9..a80170a31 100644 --- a/Cassiopee/XCore/XCore/intersectMesh/ray.h +++ b/Cassiopee/XCore/XCore/intersectMesh/ray.h @@ -18,11 +18,15 @@ */ #pragma once -#include "triangleIntersection.h" +#include "triangle.h" #include "point.h" struct AABB; +struct Vec3 { + E_Float x, y, z; +}; + struct Ray { Point org; Vec3 dir; @@ -35,6 +39,9 @@ struct Ray { TriangleIntersection &TI); }; +E_Int ray_point_orient(const E_Float o[3], const E_Float d[3], + const E_Float fN[3], E_Float px, E_Float py, E_Float pz); + bool ray_AABB_intersect(E_Float ox, E_Float oy, E_Float oz, E_Float dx, E_Float dy, E_Float dz, const AABB &box); diff --git a/Cassiopee/XCore/XCore/intersectMesh/segment.cpp b/Cassiopee/XCore/XCore/intersectMesh/segment.cpp deleted file mode 100644 index 72b4c4dee..000000000 --- a/Cassiopee/XCore/XCore/intersectMesh/segment.cpp +++ /dev/null @@ -1,120 +0,0 @@ -/* - Copyright 2013-2024 Onera. - - This file is part of Cassiopee. - - Cassiopee is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - Cassiopee is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with Cassiopee. If not, see . -*/ -#include -#include - -#include "segment.h" -#include "primitives.h" -#include "hedge.h" -#include "dcel.h" - -Segment::Segment(Vertex *P, Vertex *Q, E_Int Id) -{ - p = P; - q = Q; - dx = q->x - p->x; - dy = q->y - p->y; - rep = NULL; - id = Id; - color = Dcel::NO_IDEA; - assert(Sign(dx) >= 0); -} - -Segment::Segment(Vertex *P) -: p(P), q(P), dx(0.0), dy(0.0), rep(NULL), id(-1), color(Dcel::NO_IDEA) -{} - -Segment::Segment(Hedge *h, E_Int Id) -{ - p = h->orig; - Hedge *t = h->twin; - q = t->orig; - rep = h; - if (compare(*p, *q) > 0) { - std::swap(p, q); - rep = t; - } - dx = q->x - p->x; - dy = q->y - p->y; - id = Id; - color = rep->color; - assert(Sign(dx) >= 0); -} - -bool Segment::overlaps(const Segment &s) -{ - E_Float sdx = s.dx; - E_Float sdy = s.dy; - E_Float sqx = s.q->x; - E_Float sqy = s.q->y; - E_Float px = p->x; - E_Float py = p->y; - - E_Float T1 = dy * sdx - sdy * dx; - E_Int sign1 = Sign(T1); - - if (sign1 == 0) { - E_Float mdx = sqx - px; - E_Float mdy = sqy - py; - - E_Int sign2 = Sign(dy * mdx - mdy * dx); - - if (sign2 == 0) { - E_Int sign3 = Sign(sdy * mdx - mdy * sdx); - - assert(sign3 == 0); - - if (sign3 == 0) { - return true; - } - } - } - - return false; -} - -static -E_Int _partition(std::vector &S, E_Int low, E_Int high, - E_Int (*cmp)(const Segment &, const Segment &)) -{ - Segment *pivot = S[high]; - E_Int i = low-1; - - for (E_Int j = low; j < high; j++) { - if (cmp(*S[j], *pivot) <= 0) { - i++; - std::swap(S[i], S[j]); - } - } - - i++; - std::swap(S[i], S[high]); - return i; -} - -void Segment::sort(std::vector &S, E_Int start, E_Int end, - E_Int (*cmp)(const Segment &, const Segment &)) -{ - if (start >= end) return; - - E_Int p = _partition(S, start, end, cmp); - - sort(S, start, p - 1, cmp); - sort(S, p + 1, end, cmp); -} diff --git a/Cassiopee/XCore/XCore/intersectMesh/segment.h b/Cassiopee/XCore/XCore/intersectMesh/segment.h deleted file mode 100644 index 98275b5a8..000000000 --- a/Cassiopee/XCore/XCore/intersectMesh/segment.h +++ /dev/null @@ -1,49 +0,0 @@ -/* - Copyright 2013-2024 Onera. - - This file is part of Cassiopee. - - Cassiopee is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - Cassiopee is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with Cassiopee. If not, see . -*/ -#pragma once - -#include - -#include "vertex.h" - -struct Hedge; - -struct Segment { - Vertex *p; - Vertex *q; - E_Float dx; - E_Float dy; - Hedge *rep; - E_Int id; - E_Int color; - - inline E_Float X1() const { return p->x; } - inline E_Float Y1() const { return p->y; } - inline E_Float X2() const { return q->x; } - inline E_Float Y2() const { return q->y; } - - Segment(Vertex *p, Vertex *q, E_Int Id); - Segment(Hedge *h, E_Int Id); - Segment(Vertex *P); - - bool overlaps(const Segment &seg); - - static void sort(std::vector &S, E_Int start, E_Int end, - E_Int (*cmp)(const Segment &, const Segment &)); -}; diff --git a/Cassiopee/XCore/XCore/intersectMesh/sgraph.cpp b/Cassiopee/XCore/XCore/intersectMesh/sgraph.cpp deleted file mode 100644 index fa53cc4a7..000000000 --- a/Cassiopee/XCore/XCore/intersectMesh/sgraph.cpp +++ /dev/null @@ -1,87 +0,0 @@ -#include "mesh.h" - -struct EdgeNode { - E_Int p, q; - E_Int i, posi; - mutable E_Int j, posj; - - EdgeNode(E_Int P, E_Int Q) - { - p = std::min(P, Q); - q = std::max(P, Q); - i = posi = j = posj = -1; - } - - bool operator<(const EdgeNode &e) const - { - return (p < e.p) || (p == e.p && q < e.q); - } -}; - -void IMesh::make_skin_graph() -{ - auto &xadj = sgraph.xadj; - auto &fpts = sgraph.fpts; - auto &fadj = sgraph.fadj; - - xadj.clear(); - fpts.clear(); - fadj.clear(); - - xadj.resize(skin.size()+1); - xadj[0] = 0; - - for (size_t i = 0; i < skin.size(); i++) { - E_Int fid = skin[i]; - xadj[i+1] = xadj[i] + F[fid].size(); - } - - fpts.resize(xadj[skin.size()]); - fadj.resize(xadj[skin.size()], -1); - - for (size_t i = 0; i < skin.size(); i++) { - E_Int fid = skin[i]; - const auto &pn = F[fid]; - E_Int start = xadj[i]; - E_Int end = xadj[i+1]; - for (E_Int j = 0; j < end-start; j++) - fpts[start+j] = pn[j]; - } - - std::set edge_set; - - for (size_t i = 0; i < skin.size(); i++) { - E_Int start = xadj[i]; - E_Int np = xadj[i+1] - start; - const E_Int *pn = &fpts[start]; - for (E_Int j = 0; j < np; j++) { - E_Int p = pn[j]; - E_Int q = pn[(j+1)%np]; - EdgeNode e(p, q); - auto it = edge_set.find(e); - if (it == edge_set.end()) { - e.i = i; - e.posi = j; - edge_set.insert(e); - } else { - assert(it->i != -1); - assert(it->posi != -1); - assert(it->j == -1); - assert(it->posj == -1); - it->j = i; - it->posj = j; - } - } - } - - for (const auto &e : edge_set) { - E_Int pi = xadj[e.i] + e.posi; - assert(fadj[pi] == -1); - fadj[pi] = e.j; - - E_Int pj = xadj[e.j] + e.posj; - assert(fadj[pj] == -1); - fadj[pj] = e.i; - } -} - diff --git a/Cassiopee/XCore/XCore/intersectMesh/smesh.cpp b/Cassiopee/XCore/XCore/intersectMesh/smesh.cpp index 373d5136c..6feffd352 100644 --- a/Cassiopee/XCore/XCore/intersectMesh/smesh.cpp +++ b/Cassiopee/XCore/XCore/intersectMesh/smesh.cpp @@ -98,14 +98,69 @@ void Smesh::conformize() Smesh::Smesh() {} +Smesh::Smesh(const Smesh &Mf, const std::set &fids, bool check_Euler_) +{ + NEAR_VERTEX_TOL = Mf.NEAR_VERTEX_TOL; + NEAR_EDGE_TOL = Mf.NEAR_EDGE_TOL; + + check_Euler = check_Euler_; + + F.resize(fids.size()); + + nf = 0; + np = 0; + + // Get the faces + for (E_Int gf : fids) { + g2lf[gf] = nf; + l2gf[nf] = gf; + + auto &pn = F[nf]; + + for (E_Int gp : Mf.Fc[gf]) { + auto it = g2lp.find(gp); + + if (it == g2lp.end()) { + g2lp[gp] = np; + l2gp[np] = gp; + pn.push_back(np); + np++; + } else { + pn.push_back(it->second); + } + } + + nf++; + } + + assert((size_t)np == g2lp.size()); + assert((size_t)np == l2gp.size()); + + // Get the points + X.resize(np); + Y.resize(np); + Z.resize(np); + + for (const auto &pids : g2lp) { + X[pids.second] = Mf.X[pids.first]; + Y[pids.second] = Mf.Y[pids.first]; + Z[pids.second] = Mf.Z[pids.first]; + } + + Fc = F; + make_edges(); + make_point_faces(); + make_point_edges(); +} + Smesh Smesh::Smesh_from_mesh_skin(const IMesh &M, - const std::vector &skin, bool is_planar) + const std::vector &skin, bool check_Euler) { - return Smesh(M, skin, is_planar); + return Smesh(M, skin, check_Euler); } Smesh Smesh::Smesh_from_point_tags(const IMesh &M, const E_Float *ptag, - bool is_planar) + bool check_Euler) { std::vector fids; @@ -121,10 +176,10 @@ Smesh Smesh::Smesh_from_point_tags(const IMesh &M, const E_Float *ptag, if (keep) fids.push_back(fid); } - return Smesh(M, fids, is_planar); + return Smesh(M, fids, check_Euler); } -Smesh Smesh::Smesh_from_mesh_patch(const IMesh &M, bool is_planar) +Smesh Smesh::Smesh_from_mesh_patch(const IMesh &M, bool check_Euler) { std::vector fids; @@ -132,15 +187,15 @@ Smesh Smesh::Smesh_from_mesh_patch(const IMesh &M, bool is_planar) fids.push_back(fid); } - return Smesh(M, fids, is_planar); + return Smesh(M, fids, check_Euler); } -Smesh::Smesh(const IMesh &M, const std::vector &fids, bool is_planar_) +Smesh::Smesh(const IMesh &M, const std::vector &fids, bool check_Euler_) { NEAR_VERTEX_TOL = M.NEAR_VERTEX_TOL; NEAR_EDGE_TOL = M.NEAR_EDGE_TOL; - is_planar = is_planar_; + check_Euler = check_Euler_; F.resize(fids.size()); @@ -260,7 +315,7 @@ void Smesh::make_edges() // Check Euler formula for planar graphs - if (is_planar) + if (check_Euler) assert(np - ne + nf + 1 == 2); // Check that each edge's count is 1 or 2 @@ -310,9 +365,9 @@ void Smesh::make_edges() if (E2F[e][0] == i) neis.push_back(E2F[e][1]); else neis.push_back(E2F[e][0]); } - assert(neis.size() == pe.size()); } + /* // Traverse the face list breadth-first and adjust edges accordingly std::vector visited(nf, 0); std::queue Q; @@ -384,6 +439,7 @@ void Smesh::make_edges() } } } + */ } void Smesh::make_fcenters() @@ -440,9 +496,10 @@ void Smesh::make_fnormals() for (E_Int fid = 0; fid < nf; fid++) { const auto &pn = F[fid]; - E_Int a = pn[0], b = pn[1], c = pn[2]; - E_Float v0[3] = {X[b]-X[a], Y[b]-Y[a], Z[b]-Z[a]}; - E_Float v1[3] = {X[c]-X[a], Y[c]-Y[a], Z[c]-Z[a]}; + const E_Float *fc = &fcenters[3*fid]; + E_Int a = pn[0], b = pn[1]; + E_Float v0[3] = {X[a]-fc[0], Y[a]-fc[1], Z[a]-fc[2]}; + E_Float v1[3] = {X[b]-fc[0], Y[b]-fc[1], Z[b]-fc[2]}; E_Float *N = &fnormals[3*fid]; K_MATH::cross(v0, v1, N); E_Float NORM = K_MATH::norm(N, 3); @@ -521,4 +578,4 @@ void Smesh::clear() l2gp.clear(); g2lf.clear(); l2gf.clear(); -} \ No newline at end of file +} diff --git a/Cassiopee/XCore/XCore/intersectMesh/smesh.h b/Cassiopee/XCore/XCore/intersectMesh/smesh.h index e85a0eeac..581060e02 100644 --- a/Cassiopee/XCore/XCore/intersectMesh/smesh.h +++ b/Cassiopee/XCore/XCore/intersectMesh/smesh.h @@ -79,13 +79,14 @@ struct Smesh { // Constructors Smesh(); - Smesh(const IMesh &M, const std::vector &fids, bool is_planar=true); + Smesh(const Smesh &Mf, const std::set &fids, bool check_Euler=true); + Smesh(const IMesh &M, const std::vector &fids, bool check_Euler=true); static Smesh Smesh_from_point_tags(const IMesh &M, const E_Float *ptag, - bool is_planar=true); + bool check_Euler=true); static Smesh Smesh_from_mesh_skin(const IMesh &M, - const std::vector &skin, bool is_planar=true); + const std::vector &skin, bool check_Euler=true); static Smesh Smesh_from_mesh_patch(const IMesh &M, - bool is_planar=true); + bool check_Euler=true); //Smesh(const IMesh &M, const std::vector &faces); void make_edges(); void clear(); @@ -162,7 +163,7 @@ struct Smesh { // Topology - bool is_planar = true; + bool check_Euler = true; std::set extract_bounding_faces(const Smesh &Sf, const std::vector &plocs) const; @@ -171,7 +172,7 @@ struct Smesh { E_Int last_vertex, E_Int last_edge) const; void get_shared_faces(const PointLoc &loc, std::vector &ret, E_Int &pid, E_Int &eid) const; - Smesh extract_smesh(const std::set &fids, bool is_planar=true); + Smesh extract_smesh(const std::set &fids, bool check_Euler=true); Smesh extract_conformized(); // IO diff --git a/Cassiopee/XCore/XCore/intersectMesh/smesh_extract.cpp b/Cassiopee/XCore/XCore/intersectMesh/smesh_extract.cpp index dceb1a61c..5ee9e9c18 100644 --- a/Cassiopee/XCore/XCore/intersectMesh/smesh_extract.cpp +++ b/Cassiopee/XCore/XCore/intersectMesh/smesh_extract.cpp @@ -1,6 +1,302 @@ +#include + #include "smesh.h" +#include "primitives.h" +#include "ray.h" + +void Smesh::get_shared_faces(const PointLoc &loc, std::vector &ret, + E_Int &pid, E_Int &eid) const +{ + ret.clear(); + + E_Int fid = loc.fid; + assert(fid != -1); + + // TODO(Imad): e_idx is no good!!!! + + if (loc.e_idx != -1) { + assert(loc.v_idx == -1); + const auto &pe = F2E[fid]; + eid = pe[loc.e_idx]; + const auto &pf = E2F[eid]; + assert(pf[0] == fid || pf[1] == fid); + ret.push_back(pf[0]); + // O could be on a boundary edge + if (pf[1] != -1) ret.push_back(pf[1]); + } + else if (loc.v_idx != -1) { + assert(loc.e_idx == -1); + const auto &pn = Fc[fid]; + pid = pn[loc.v_idx]; + const auto &pf = P2F[pid]; + // For consistency + bool found_fid = false; + for (auto face : pf) { + ret.push_back(face); + if (face == fid) { + found_fid = true; + } + } + assert(found_fid == true); + } + else { + ret.push_back(fid); + } +} + +std::set ewalls; +std::set fwalls; +std::vector pchains; + +std::set Smesh::extract_bounding_faces(const Smesh &Sf, + const std::vector &plocs) const +{ + // Get boundary edges from spatch + std::set bedges; + for (size_t i = 0; i < Sf.E2F.size(); i++) { + const auto &pf = Sf.E2F[i]; + assert(pf[0] != -1); + if (pf[1] == -1) bedges.insert(i); + } + size_t nbedges = bedges.size(); + + // Make the boundary point chain + std::vector pchain; + + E_Int first_edge = *bedges.begin(); + + pchain.push_back(Sf.E[first_edge].p); + pchain.push_back(Sf.E[first_edge].q); + + bedges.erase(first_edge); + + E_Int current_point = pchain[1]; + + while (pchain.size() < nbedges) { + E_Int to_delete = -1; + for (auto e : bedges) { + if (Sf.E[e].p == current_point) { + pchain.push_back(Sf.E[e].q); + current_point = pchain.back(); + to_delete = e; + break; + } else if (Sf.E[e].q == current_point) { + pchain.push_back(Sf.E[e].p); + current_point = pchain.back(); + to_delete = e; + break; + } + } + assert(to_delete != -1); + bedges.erase(to_delete); + } + + assert(pchain.size() == nbedges); + + // Sort the pchain counterclockwise + E_Int a = pchain[0], b = pchain[1], c = pchain[2]; + E_Float ux = Sf.X[b] - Sf.X[a]; + E_Float uy = Sf.Y[b] - Sf.Y[a]; + E_Float uz = Sf.Z[b] - Sf.Z[a]; + E_Float vx = Sf.X[c] - Sf.X[b]; + E_Float vy = Sf.Y[c] - Sf.Y[b]; + E_Float vz = Sf.Z[c] - Sf.Z[b]; + E_Float cp[3] = {uy*vz - uz*vy, uz*vx - ux*vz, ux*vy - uy*vx}; + // TODO(Imad): inherit fnormals + const E_Float *N_b = &fnormals[3*plocs[b].fid]; + E_Float dp = K_MATH::dot(cp, N_b, 3); + E_Int cmp = Sign(dp); + assert(cmp != 0); + if (cmp < 0) std::reverse(pchain.begin(), pchain.end()); + + Sf.write_points("pchain.im", pchain); + + for (E_Int p : pchain) pchains.push_back({Sf.X[p], Sf.Y[p], Sf.Z[p]}); + + std::set wfids; + std::set weids; + + for (size_t i = 0; i < pchain.size(); i++) { + E_Int p = pchain[i]; + E_Int q = pchain[(i+1)%pchain.size()]; + + E_Float px = Sf.X[p], py = Sf.Y[p], pz = Sf.Z[p]; + E_Float qx = Sf.X[q], qy = Sf.Y[q], qz = Sf.Z[q]; + + //point_write("p", px, py, pz); + //point_write("q", qx, qy, qz); + + E_Float D[3] = {qx-px, qy-py, qz-pz}; + E_Float NORM = K_MATH::norm(D, 3); + D[0] /= NORM, D[1] /= NORM, D[2] /= NORM; + + std::vector orig_faces; + std::vector tail_faces; + + E_Int last_vertex = -1, last_edge = -1, dummy; + + get_shared_faces(plocs[p], orig_faces, last_vertex, last_edge); + get_shared_faces(plocs[q], tail_faces, dummy, dummy); + + E_Int starting_face = deduce_face(orig_faces, px, py, pz, + D, last_vertex, last_edge); + assert(starting_face != -1); + + bool found_tail = false; + E_Int cur_fid = starting_face; + E_Float cur_pos[3] = {px, py, pz}; + + E_Int walk = 0; + E_Int max_walks = 20; + + while (!found_tail && walk <= max_walks) { + + wfids.insert(cur_fid); + + //write_face("cur_fid", cur_fid); + + E_Float proj[3]; + get_unit_projected_direction(cur_fid, D, proj); + + const auto &pn = Fc[cur_fid]; + const auto &pe = F2E[cur_fid]; + assert(pe.size() == pn.size()); + const E_Float *fN = &fnormals[3*cur_fid]; + + // First pass: define the wall data + for (size_t i = 0; i < pn.size(); i++) { + E_Int p = pn[i]; + E_Int q = pn[(i+1)%pn.size()]; + E_Int e = pe[i]; + E_Float px = X[p], py = Y[p], pz = Z[p]; + E_Float qx = X[q], qy = Y[q], qz = Z[q]; + if (ray_point_orient(cur_pos, proj, fN, px, py, pz) <= 0 || + ray_point_orient(cur_pos, proj, fN, qx, qy, qz) <= 0) { + weids.insert(e); + } + } + + //write_edges("wall", weids); + + for (auto fid : tail_faces) { + if (fid == cur_fid) { + found_tail = true; + break; + } + } + + if (found_tail) break; + + E_Int next_fid = -1; + E_Float next_pos[3] = {EFLOATMAX, EFLOATMAX, EFLOATMAX}; + + bool hit = false; + + for (size_t i = 0; i < pn.size(); i++) { + E_Int p = pn[i]; + E_Int q = pn[(i+1)%pn.size()]; + E_Int e = pe[i]; + + + if (p == last_vertex || q == last_vertex || e == last_edge) + continue; + + E_Float px = X[p], py = Y[p], pz = Z[p]; + E_Float qx = X[q], qy = Y[q], qz = Z[q]; + + E_Float t, s; + hit = ray_edge_intersect( + cur_pos[0], cur_pos[1], cur_pos[2], + proj[0], proj[1], proj[2], + px, py, pz, qx, qy, qz, + t, s + ); + + if (hit) { + if (s > TOL && s < 1 - TOL) { + const auto &pe = F2E[cur_fid]; + E_Int eid = pe[i]; + last_edge = eid; + last_vertex = -1; + assert(E2F[eid][0] == cur_fid || E2F[eid][1] == cur_fid); + if (E2F[eid][0] == cur_fid) next_fid = E2F[eid][1]; + else next_fid = E2F[eid][0]; + + next_pos[0] = cur_pos[0] + t * proj[0]; + next_pos[1] = cur_pos[1] + t * proj[1]; + next_pos[2] = cur_pos[2] + t * proj[2]; + } else { + bool hit_p = (s <= TOL); + bool hit_q = (s >= 1 - TOL); + assert(!(hit_p && hit_q)); + last_edge = -1; + if (hit_p) last_vertex = p; + else last_vertex = q; + next_pos[0] = X[last_vertex]; + next_pos[1] = Y[last_vertex]; + next_pos[2] = Z[last_vertex]; + const auto &pf = P2F[last_vertex]; + next_fid = deduce_face(pf, + next_pos[0], next_pos[1], next_pos[2], + D, last_vertex, last_edge + ); + assert(next_fid != -1); + } + break; + } + } + + assert(hit); + assert(next_fid != cur_fid); + cur_fid = next_fid; + cur_pos[0] = next_pos[0]; + cur_pos[1] = next_pos[1]; + cur_pos[2] = next_pos[2]; + walk++; + } + + assert(found_tail); + assert(walk <= max_walks); + } + + // TODO(Imad): project wpids on best-fit plane and jarvis march + + // BFS to get the smesh mpids + std::queue Q; + for (E_Int fid : wfids) Q.push(fid); + + //write_ngon("fwall_before_BFS", wfids); + + while (!Q.empty()) { + E_Int fid = Q.front(); + Q.pop(); + + const auto &neis = F2F[fid]; + const auto &pe = F2E[fid]; + + for (size_t i = 0; i < pe.size(); i++) { + E_Int eid = pe[i]; + if (weids.find(eid) != weids.end()) continue; + E_Int nei = neis[i]; + if (wfids.find(nei) == wfids.end()) { + wfids.insert(nei); + Q.push(nei); + } + } + } + + //write_ngon("fwall_after_BFS", wfids); + + //write_ngon("fwall", wfids); + //write_edges("ewall", weids); + + for (E_Int eid : weids) ewalls.insert(eid); + for (E_Int fid : wfids) fwalls.insert(fid); + + return wfids; +} -Smesh Smesh::extract_smesh(const std::set &fids, bool is_planar) +Smesh Smesh::extract_smesh(const std::set &fids, bool check_Euler) { assert(0); return Smesh(); diff --git a/Cassiopee/XCore/XCore/intersectMesh/smesh_geom.cpp b/Cassiopee/XCore/XCore/intersectMesh/smesh_geom.cpp new file mode 100644 index 000000000..0d6c7372c --- /dev/null +++ b/Cassiopee/XCore/XCore/intersectMesh/smesh_geom.cpp @@ -0,0 +1,83 @@ +#include "smesh.h" +#include "primitives.h" + +void Smesh::get_unit_projected_direction(E_Int fid, const E_Float D[3], + E_Float proj[3]) const +{ + assert(fid >= 0); + assert(fid < nf); + + // Unit normal + const E_Float *fN = &fnormals[3*fid]; + + E_Float dp = K_MATH::dot(D, fN, 3); + + proj[0] = D[0] - dp * fN[0]; + proj[1] = D[1] - dp * fN[1]; + proj[2] = D[2] - dp * fN[2]; + E_Float NORM = K_MATH::norm(proj, 3); + proj[0] /= NORM, proj[1] /= NORM, proj[2] /= NORM; +} + +E_Int Smesh::deduce_face(const std::vector &pf, + E_Float ox, E_Float oy, E_Float oz, E_Float D[3], + E_Int last_vertex, E_Int last_edge) const +{ + // Intersect the projection of D with all the faces in pf + // At least one intersection must exist + // Return the face with the earliest intersection + + // For debugging + E_Int faces_hit = 0; + + E_Float t_min = EFLOATMAX; + E_Int ret_face = -1; + + for (auto fid : pf) { + + // Compute the unit projection of D on this face + + E_Float proj[3]; + get_unit_projected_direction(fid, D, proj); + + const auto &pn = Fc[fid]; + const auto &pe = F2E[fid]; + assert(pn.size() == pe.size()); + + for (size_t i = 0; i < pn.size(); i++) { + + E_Int p = pn[i]; + E_Int q = pn[(i+1)%pn.size()]; + E_Int e = pe[i]; + + if (p == last_vertex || q == last_vertex || e == last_edge) + continue; + + E_Float t, s; + + bool hit = ray_edge_intersect(ox, oy, oz, + proj[0], proj[1], proj[2], + X[p], Y[p], Z[p], + X[q], Y[q], Z[q], + t, s + ); + + if (hit) { + faces_hit += 1; + + if (t < t_min) { + t_min = t; + ret_face = fid; + } + + // Hit an edge of the face, stop + break; + } + } + } + + // We must have hit a face + assert(faces_hit > 0); + + return ret_face; +} \ No newline at end of file diff --git a/Cassiopee/XCore/XCore/intersectMesh/smesh_locate.cpp b/Cassiopee/XCore/XCore/intersectMesh/smesh_locate.cpp index 7a07ec362..339e02be6 100644 --- a/Cassiopee/XCore/XCore/intersectMesh/smesh_locate.cpp +++ b/Cassiopee/XCore/XCore/intersectMesh/smesh_locate.cpp @@ -3,6 +3,52 @@ #include "primitives.h" #include "io.h" +void Smesh::correct_near_points_and_edges(Smesh &Sf, + std::vector &plocs) +{ + E_Int on_vertex = 0, on_edge = 0; + for (size_t i = 0; i < plocs.size(); i++) { + auto &ploc = plocs[i]; + + E_Int fid = ploc.fid; + assert(fid < nf); + const auto &pn = Fc[fid]; + + if (ploc.v_idx != -1) { + on_vertex++; + E_Int p = pn[ploc.v_idx]; + E_Float dx = X[p]-Sf.X[i]; + E_Float dy = Y[p]-Sf.Y[i]; + E_Float dz = Z[p]-Sf.Z[i]; + E_Float dist = dx*dx + dy*dy + dz*dz; + if (dist >= Sf.min_pdist_squared) { + fprintf(stderr, "Tight near-vertex situation!\n"); + point_write("mpoint", X[p], Y[p], Z[p]); + point_write("spoint", Sf.X[i], Sf.Y[i], Sf.Z[i]); + assert(0); + } else { + Sf.X[i] = X[p]; + Sf.Y[i] = Y[p]; + Sf.Z[i] = Z[p]; + } + } else if (ploc.e_idx != -1) { + on_edge++; + E_Float u = ploc.bcrd[0]; + E_Float v = ploc.bcrd[1]; + E_Float w = ploc.bcrd[2]; + assert(Sign(w, NEAR_EDGE_TOL) == 0); + u += w; + assert(Sign(u+v-1) == 0); + E_Int p = pn[ploc.e_idx]; + E_Int q = pn[(ploc.e_idx+1)%pn.size()]; + Sf.X[i] = u*X[p] + v*X[q]; + Sf.Y[i] = u*Y[p] + v*Y[q]; + Sf.Z[i] = u*Z[p] + v*Z[q]; + } + } + printf("on vertex: %d - on edge: %d\n", on_vertex, on_edge); +} + void Smesh::make_bbox() { NX = 100; diff --git a/Cassiopee/XCore/XCore/intersectMesh/snode.cpp b/Cassiopee/XCore/XCore/intersectMesh/snode.cpp deleted file mode 100644 index 145d71925..000000000 --- a/Cassiopee/XCore/XCore/intersectMesh/snode.cpp +++ /dev/null @@ -1,32 +0,0 @@ -/* - Copyright 2013-2024 Onera. - - This file is part of Cassiopee. - - Cassiopee is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - Cassiopee is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with Cassiopee. If not, see . -*/ -#include "snode.h" - -Snode::Snode(Segment *Key, void *Inf) -: key(Key), inf(Inf), left(NULL), right(NULL) -{} - -void Snode::print_tree(Snode *root) -{ - if (root == NULL) return; - - print_tree(root->left); - root->print(); - print_tree(root->right); -} diff --git a/Cassiopee/XCore/XCore/intersectMesh/snode.h b/Cassiopee/XCore/XCore/intersectMesh/snode.h deleted file mode 100644 index 722caeaf5..000000000 --- a/Cassiopee/XCore/XCore/intersectMesh/snode.h +++ /dev/null @@ -1,40 +0,0 @@ -/* - Copyright 2013-2024 Onera. - - This file is part of Cassiopee. - - Cassiopee is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - Cassiopee is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with Cassiopee. If not, see . -*/ -#pragma once - -#include - -#include "segment.h" - -struct Snode { - Segment *key; - void *inf; - Snode *left; - Snode *right; - - Snode(Segment *Key, void *Inf); - - inline void print() - { - printf("S" SF_D_ "(P" SF_D_ ", P" SF_D_ ")\n", key->id, key->p->id, - key->q->id); - } - - static void print_tree(Snode *root); -}; diff --git a/Cassiopee/XCore/XCore/intersectMesh/status.cpp b/Cassiopee/XCore/XCore/intersectMesh/status.cpp deleted file mode 100644 index 7033a1faa..000000000 --- a/Cassiopee/XCore/XCore/intersectMesh/status.cpp +++ /dev/null @@ -1,230 +0,0 @@ -/* - Copyright 2013-2024 Onera. - - This file is part of Cassiopee. - - Cassiopee is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - Cassiopee is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with Cassiopee. If not, see . -*/ -#include -#include - -#include "status.h" -#include "primitives.h" - -Status::Status() -: root(NULL), rx(0.0), ry(0.0) -{} - -static -E_Int Segment_cmp(Segment *s0, Segment *s1, E_Float rx, E_Float ry) -{ - if (s0 == s1) return 0; - - E_Int cmp = compare(*s0, *s1, rx, ry); - - if (cmp == 0) { - cmp = cmp_mySeg(*s0, *s1); - } - - return cmp; -} - -Snode *Status::insert(Segment *key, void *inf) -{ - if (key == NULL) return NULL; - return insert_(root, key, inf); -} - -Snode *Status::insert_(Snode *&root, Segment *key, void *inf) -{ - if (root == NULL) { - root = new Snode(key, inf); - return root; - } - - E_Int cmp = Segment_cmp(root->key, key, rx, ry); - - if (cmp == 0) { - root->inf = inf; - return root; - } else if (cmp < 0) { - return insert_(root->right, key, inf); - } else { - return insert_(root->left, key, inf); - } -} - -Snode *Status::locate(Segment *seg) -{ - if (seg == NULL) return NULL; - return locate_(root, seg); -} - -Snode *Status::locate_(Snode *root, Segment *seg) -{ - if (root == NULL) return NULL; - - E_Int cmp = compare(*root->key, *seg, rx, ry); - - if (cmp == 0) return root; - else if (cmp < 0) return locate_(root->right, seg); - else return locate_(root->left, seg); -} - -Snode *Status::lookup(Segment *seg) -{ - if (seg == NULL) return NULL; - return lookup_(root, seg); -} - -Snode *Status::lookup_(Snode *root, Segment *seg) -{ - if (root == NULL) return NULL; - - E_Int cmp = Segment_cmp(root->key, seg, rx, ry); - - if (cmp == 0) return root; - else if (cmp < 0) return lookup_(root->right, seg); - else return lookup_(root->left, seg); -} - -Snode *Status::pred(Segment *seg) -{ - Snode *pre = NULL; - pred_(root, seg, pre); - return pre; -} - -Snode *Status::succ(Segment *seg) -{ - Snode *suc = NULL; - succ_(root, seg, suc); - return suc; -} - -Snode *Status::pred(Snode *sit) -{ - return pred(sit->key); -} - -Snode *Status::succ(Snode *sit) -{ - return succ(sit->key); -} - -void Status::pred_(Snode *root, Segment *seg, Snode *&pre) -{ - if (root == NULL) return; - - E_Int cmp = Segment_cmp(root->key, seg, rx, ry); - - if (cmp == 0) { - assert(root->key == seg); - - if (root->left != NULL) { - Snode *tmp = root->left; - while (tmp->right) tmp = tmp->right; - pre = tmp; - } - - return; - } - - if (cmp > 0) { - pred_(root->left, seg, pre); - } else { - pre = root; - pred_(root->right, seg, pre); - } -} - -void Status::succ_(Snode *root, Segment *seg, Snode *&suc) -{ - if (root == NULL) return; - - E_Int cmp = Segment_cmp(root->key, seg, rx, ry); - - if (cmp == 0) { - assert(root->key == seg); - - if (root->right != NULL) { - Snode *tmp = root->right; - while (tmp->left) tmp = tmp->left; - suc = tmp; - } - - return; - } - - if (cmp > 0) { - suc = root; - succ_(root->left, seg, suc); - } else { - succ_(root->right, seg, suc); - } -} - -void Status::erase(Segment *seg) -{ - root = erase_(root, seg); -} - -Snode *Status::erase_(Snode *root, Segment *seg) -{ - if (root == NULL) return NULL; - - E_Int cmp = Segment_cmp(root->key, seg, rx, ry); - - if (cmp < 0) { - root->right = erase_(root->right, seg); - return root; - } else if (cmp > 0) { - root->left = erase_(root->left, seg); - return root; - } - - assert(root->key == seg); - - if (root->left == NULL) { - Snode *tmp = root->right; - delete root; - return tmp; - } else if (root->right == NULL) { - Snode *tmp = root->left; - delete root; - return tmp; - } else { - Snode *succ_parent = root; - - Snode *succ = root->right; - while (succ->left) { - succ_parent = succ; - succ = succ->left; - } - - if (succ_parent != root) succ_parent->left = succ->right; - else succ_parent->right = succ->right; - - root->key = succ->key; - root->inf = succ->inf; - - delete succ; - return root; - } -} - -void Status::print() -{ - return Snode::print_tree(root); -} diff --git a/Cassiopee/XCore/XCore/intersectMesh/status.h b/Cassiopee/XCore/XCore/intersectMesh/status.h deleted file mode 100644 index 0cad6c59a..000000000 --- a/Cassiopee/XCore/XCore/intersectMesh/status.h +++ /dev/null @@ -1,60 +0,0 @@ -/* - Copyright 2013-2024 Onera. - - This file is part of Cassiopee. - - Cassiopee is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - Cassiopee is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with Cassiopee. If not, see . -*/ -#pragma once - -#include - -#include "snode.h" - -struct Status { - Snode *root; - E_Float rx, ry; - - Status(); - - Snode *insert(Segment *key, void *inf = NULL); - - Snode *lookup(Segment *seg); - - Snode *locate(Segment *seg); - - Snode *pred(Snode *sit); - - Snode *pred(Segment *seg); - - Snode *succ(Snode *sit); - - Snode *succ(Segment *seg); - - void erase(Segment *seg); - - void print(); - - Snode *insert_(Snode *& root, Segment *key, void *inf); - - Snode *lookup_(Snode *root, Segment *seg); - - Snode *locate_(Snode *root, Segment *seg); - - void pred_(Snode *root, Segment *seg, Snode *&pre); - - void succ_(Snode *root, Segment *seg, Snode *&suc); - - Snode *erase_(Snode *root, Segment *seg); -}; diff --git a/Cassiopee/XCore/XCore/intersectMesh/triangle.h b/Cassiopee/XCore/XCore/intersectMesh/triangle.h index fbcdc4988..13f2846b0 100644 --- a/Cassiopee/XCore/XCore/intersectMesh/triangle.h +++ b/Cassiopee/XCore/XCore/intersectMesh/triangle.h @@ -18,10 +18,7 @@ */ #pragma once -#include - -#include "point.h" -#include "smesh.h" +#include "xcore.h" struct Triangle { E_Int a, b, c; @@ -43,3 +40,14 @@ struct Triangle { E_Float by, E_Float bz, E_Float cx, E_Float cy, E_Float cz, E_Float &u, E_Float &v, E_Float &w, E_Float &t, E_Float &x, E_Float &y, E_Float &z); }; + +struct TriangleIntersection { + E_Float x, y, z; + E_Float u, v, w; + E_Float t = -1; + E_Int face = -1; + E_Int tri = -1; + E_Int eid = -1; + E_Int vid = -1; + E_Int pid = -1; +}; diff --git a/Cassiopee/XCore/XCore/intersectMesh/triangleIntersection.h b/Cassiopee/XCore/XCore/intersectMesh/triangleIntersection.h deleted file mode 100644 index a69e5900d..000000000 --- a/Cassiopee/XCore/XCore/intersectMesh/triangleIntersection.h +++ /dev/null @@ -1,33 +0,0 @@ -/* - Copyright 2013-2024 Onera. - - This file is part of Cassiopee. - - Cassiopee is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - Cassiopee is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with Cassiopee. If not, see . -*/ -#pragma once - -#include "xcore.h" -#include "common/common.h" - -struct TriangleIntersection { - E_Float x, y, z; - E_Float u, v, w; - E_Float t = -1; - E_Int face = -1; - E_Int tri = -1; - E_Int eid = -1; - E_Int vid = -1; - E_Int pid = -1; -}; diff --git a/Cassiopee/XCore/XCore/intersectMesh/vec3.cpp b/Cassiopee/XCore/XCore/intersectMesh/vec3.cpp deleted file mode 100644 index 9fe3b0253..000000000 --- a/Cassiopee/XCore/XCore/intersectMesh/vec3.cpp +++ /dev/null @@ -1,67 +0,0 @@ -/* - Copyright 2013-2024 Onera. - - This file is part of Cassiopee. - - Cassiopee is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - Cassiopee is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with Cassiopee. If not, see . -*/ -#include "vec3.h" - -Vec3::Vec3() -{} - -Vec3::Vec3(E_Float X, E_Float Y, E_Float Z) -{ - ptr[0] = X; - ptr[1] = Y; - ptr[2] = Z; -} - -Vec3 Vec3::operator-(const Vec3 &p) const -{ - Vec3 ret; - for (E_Int i = 0; i < 3; i++) ret[i] = ptr[i] - p[i]; - return ret; -} - -Vec3 Vec3::operator+(const Vec3 &p) const -{ - Vec3 ret; - for (E_Int i = 0; i < 3; i++) ret[i] = ptr[i] + p[i]; - return ret; -} - -Vec3 Vec3::operator*(E_Float a) const -{ - Vec3 ret; - for (E_Int i = 0; i < 3; i++) ret[i] = a * ptr[i]; - return ret; -} - -Vec3 operator*(E_Float a, const Vec3 & v) -{ - Vec3 ret; - for (E_Int i = 0; i < 3; i++) ret[i] = a * v[i]; - return ret; -} - -E_Float &Vec3::operator[](E_Int idx) -{ - return ptr[idx]; -} - -E_Float Vec3::operator[](E_Int idx) const -{ - return ptr[idx]; -} diff --git a/Cassiopee/XCore/XCore/intersectMesh/vec3.h b/Cassiopee/XCore/XCore/intersectMesh/vec3.h deleted file mode 100644 index b0db340c4..000000000 --- a/Cassiopee/XCore/XCore/intersectMesh/vec3.h +++ /dev/null @@ -1,42 +0,0 @@ -/* - Copyright 2013-2024 Onera. - - This file is part of Cassiopee. - - Cassiopee is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - Cassiopee is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with Cassiopee. If not, see . -*/ -#pragma once - -#include "xcore.h" -#include "common/common.h" - -struct Vec3 { - E_Float ptr[3]; - - Vec3(); - - Vec3(E_Float X, E_Float Y, E_Float Z); - - Vec3 operator-(const Vec3 &v) const; - - Vec3 operator+(const Vec3 &v) const; - - Vec3 operator*(E_Float a) const; - - E_Float &operator[](E_Int idx); - - E_Float operator[](E_Int idx) const; -}; - -Vec3 operator*(E_Float a, const Vec3 &v); diff --git a/Cassiopee/XCore/XCore/intersectMesh/vertex.cpp b/Cassiopee/XCore/XCore/intersectMesh/vertex.cpp deleted file mode 100644 index 8f9b4db45..000000000 --- a/Cassiopee/XCore/XCore/intersectMesh/vertex.cpp +++ /dev/null @@ -1,39 +0,0 @@ -/* - Copyright 2013-2024 Onera. - - This file is part of Cassiopee. - - Cassiopee is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - Cassiopee is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with Cassiopee. If not, see . -*/ -#include "vertex.h" -#include "primitives.h" - -Vertex::Vertex(E_Float X, E_Float Y, E_Float Z, E_Int Oid, E_Int color) -: x(X), y(Y), z(Z), rep(NULL), id(-1), left(NULL) -{ - oid[color] = Oid; - oid[(color+1)%2] = -1; -} - -Vertex::Vertex(E_Float X, E_Float Y, E_Float Z) -: x(X), y(Y), z(Z), rep(NULL), id(-1), left(NULL) -{ - oid[0] = -1; - oid[1] = -1; -} - -E_Int cmp_vtx(Vertex *a, Vertex *b) -{ - return cmp_points(a->x, a->y, a->z, b->x, b->y, b->z); -} diff --git a/Cassiopee/XCore/XCore/intersectMesh/vertex.h b/Cassiopee/XCore/XCore/intersectMesh/vertex.h deleted file mode 100644 index 40d4faf7c..000000000 --- a/Cassiopee/XCore/XCore/intersectMesh/vertex.h +++ /dev/null @@ -1,50 +0,0 @@ -/* - Copyright 2013-2024 Onera. - - This file is part of Cassiopee. - - Cassiopee is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - Cassiopee is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with Cassiopee. If not, see . -*/ -#pragma once - -#include - -#include "xcore.h" -#include "common/common.h" -#include "point.h" - -struct Hedge; - -struct Vertex { - E_Float x, y, z; - Hedge *rep; - E_Int id; - Hedge *left; - E_Int oid[2]; - - PointLoc loc; - - //Hedge *xhedge = NULL; - E_Int meid = -1; - - E_Float d = 0; - - Vertex(E_Float X, E_Float Y, E_Float Z, E_Int Oid, E_Int color); - - Vertex(E_Float X, E_Float Y, E_Float Z); - - inline void print() { printf("P" SF_D_ ": %f %f %f\n", id, x, y, z); } -}; - -E_Int cmp_vtx(Vertex *a, Vertex *b); diff --git a/Cassiopee/XCore/srcs.py b/Cassiopee/XCore/srcs.py index 2b2bb64ac..16aa1c1a2 100644 --- a/Cassiopee/XCore/srcs.py +++ b/Cassiopee/XCore/srcs.py @@ -25,7 +25,6 @@ 'XCore/intersectMesh/icapsule_refine.cpp', 'XCore/intersectMesh/triangulate.cpp', - 'XCore/intersectMesh/sgraph.cpp', 'XCore/intersectMesh/smesh.cpp', 'XCore/intersectMesh/smesh_locate.cpp', @@ -33,6 +32,13 @@ 'XCore/intersectMesh/smesh_refine.cpp', 'XCore/intersectMesh/smesh_extract.cpp', 'XCore/intersectMesh/smesh_bvh.cpp', + 'XCore/intersectMesh/smesh_geom.cpp', + + 'XCore/intersectMesh/dcel.cpp', + 'XCore/intersectMesh/dcel_extract.cpp', + 'XCore/intersectMesh/dcel_io.cpp', + #'XCore/intersectMesh/dcel_trace.cpp', + #'XCore/intersectMesh/dcel_cut.cpp', 'XCore/intersectMesh/AABB.cpp', @@ -48,32 +54,17 @@ 'XCore/intersectMesh/intersectMesh.cpp', 'XCore/intersectMesh/removeIntersectingKPlanes.cpp', 'XCore/intersectMesh/prepareMeshesForIntersection.cpp', - 'XCore/intersectMesh/cycle.cpp', - 'XCore/intersectMesh/dcel.cpp', - 'XCore/intersectMesh/trace.cpp', - 'XCore/intersectMesh/cut.cpp', - 'XCore/intersectMesh/event.cpp', - 'XCore/intersectMesh/hedge.cpp', - 'XCore/intersectMesh/face.cpp', - 'XCore/intersectMesh/vertex.cpp', - 'XCore/intersectMesh/event.cpp', - 'XCore/intersectMesh/status.cpp', - 'XCore/intersectMesh/snode.cpp', - 'XCore/intersectMesh/queue.cpp', - 'XCore/intersectMesh/segment.cpp', 'XCore/intersectMesh/mesh.cpp', 'XCore/intersectMesh/meshRefine.cpp', 'XCore/intersectMesh/meshTopo.cpp', 'XCore/intersectMesh/io.cpp', 'XCore/intersectMesh/primitives.cpp', - 'XCore/intersectMesh/vec3.cpp', 'XCore/intersectMesh/triangle.cpp', 'XCore/intersectMesh/point.cpp', 'XCore/intersectMesh/ray.cpp', 'XCore/intersectMesh/meshExport.cpp', 'XCore/intersectMesh/DDA.cpp', - 'XCore/AdaptMesh/AdaptMesh_Init.cpp', 'XCore/AdaptMesh/AdaptMesh_ExtractMesh.cpp', 'XCore/AdaptMesh/AdaptMesh_AssignRefData.cpp', @@ -122,8 +113,6 @@ 'XCore/AdaptMesh/DynMeshTopo.cpp', 'XCore/AdaptMesh/TriGraph.cpp', - - 'XCore/extractFacesFromPointTag.cpp', ] if mpi: # source that requires mpi From 97ee8f6da6ba5e74648a7a2398ce463f6a617fc2 Mon Sep 17 00:00:00 2001 From: imadhammani Date: Fri, 18 Oct 2024 14:06:07 +0200 Subject: [PATCH 63/86] XCore intersectMesh: fixed MollerTrumboreAnyDir --- .../XCore/XCore/intersectMesh/icapsule.cpp | 3 +- .../XCore/intersectMesh/icapsule_refine.cpp | 54 +++++-------------- Cassiopee/XCore/XCore/intersectMesh/ray.cpp | 12 ++--- Cassiopee/XCore/XCore/intersectMesh/smesh.h | 3 +- .../XCore/intersectMesh/smesh_extract.cpp | 3 ++ .../XCore/XCore/intersectMesh/smesh_geom.cpp | 3 +- .../XCore/intersectMesh/smesh_locate.cpp | 13 +++++ 7 files changed, 40 insertions(+), 51 deletions(-) diff --git a/Cassiopee/XCore/XCore/intersectMesh/icapsule.cpp b/Cassiopee/XCore/XCore/intersectMesh/icapsule.cpp index 34e6b41ef..091543647 100644 --- a/Cassiopee/XCore/XCore/intersectMesh/icapsule.cpp +++ b/Cassiopee/XCore/XCore/intersectMesh/icapsule.cpp @@ -68,6 +68,8 @@ ICapsule::ICapsule(const Karray &marray, const std::vector &sarrays, // Refinement loop refine(Mf, bfaces, Sf, plocs); + //Sf.write_ngon("refined_Sf.im"); + //Mf.write_ngon("refined_Mf.im"); bfaces = Mf.extract_bounding_faces(Sf, plocs); //Mf.write_ngon("bounding_after.im", bfaces); @@ -82,7 +84,6 @@ ICapsule::ICapsule(const Karray &marray, const std::vector &sarrays, Dcel Db(Bf, Dcel::RED); Db.write_inner_cycles("Db.im"); - Sf.write_ngon("refinement_Sf.im"); Dcel Ds(Sf, Dcel::BLACK); Ds.write_inner_cycles("Ds_inner.im"); diff --git a/Cassiopee/XCore/XCore/intersectMesh/icapsule_refine.cpp b/Cassiopee/XCore/XCore/intersectMesh/icapsule_refine.cpp index 782817b3a..be3111475 100644 --- a/Cassiopee/XCore/XCore/intersectMesh/icapsule_refine.cpp +++ b/Cassiopee/XCore/XCore/intersectMesh/icapsule_refine.cpp @@ -75,9 +75,6 @@ void Smesh::project(const Smesh &Mf, const std::vector &mpids, { for (size_t i = 0; i < mpids.size(); i++) { E_Int mpid = mpids[i]; - assert(mpid >= 0); - assert(mpid < Mf.np); - assert(Mf.pnormals.size() == (size_t)(3*Mf.np)); const E_Float *N = &Mf.pnormals[3*mpid]; E_Float mx = Mf.X[mpid]; E_Float my = Mf.Y[mpid]; @@ -98,26 +95,6 @@ void Smesh::project(const Smesh &Mf, const std::vector &mpids, } } -void Smesh::project_and_replace(Smesh &Mf, E_Int start) const -{ - E_Int NP = Mf.np - start; - std::vector pids(NP); - for (E_Int i = 0; i < NP; i++) pids[i] = start+i; - - std::vector plocs(NP); - - project(Mf, pids, plocs); - - // Replace - for (E_Int i = 0; i < NP; i++) { - assert(plocs[i].fid != -1); - E_Int pid = pids[i]; - Mf.X[pid] = plocs[i].x; - Mf.Y[pid] = plocs[i].y; - Mf.Z[pid] = plocs[i].z; - } -} - std::vector Smesh::deduce_ref_faces(const std::vector &mpids, const std::vector &plocs_m, const Smesh &Mf, std::vector &ref_faces) @@ -203,26 +180,16 @@ void ICapsule::refine(Smesh &Mf, std::set &mfids, Smesh &Sf, // Deduce sfids to refine std::vector sref_faces; Sf.deduce_ref_faces(mpids, plocs_m, Mf, sref_faces); + printf("Fat sfids: %lu\n", sref_faces.size()); - for (const E_Int sfid : sref_faces) { - fat_sfids.push_back(sfid); - } - printf("Fat sfids: %lu\n", fat_sfids.size()); - + // Refine ref_S = sref_faces.size(); if (ref_S > 0) { - // Cache the number of points before refinement - E_Int NP = Sf.np; Sf.refine(sref_faces); Sf.conformize(); - Sf.hash_faces(); Sf.make_pnormals(); - Mf.project_and_replace(Sf, NP); - //Sf.write_ngon("refined_Sf"); } - - plocs_s = Mf.locate(Sf); - + /*********************** Mf refinement ***********************/ @@ -231,20 +198,20 @@ void ICapsule::refine(Smesh &Mf, std::set &mfids, Smesh &Sf, spids.reserve(Sf.np); for (E_Int i = 0; i < Sf.np; i++) spids.push_back(i); + // Reproject spids on mfaces + plocs_s.resize(Sf.np); + Mf.project(Sf, spids, plocs_s); + Sf.replace_by_projections(spids, plocs_s); + // Deduce mfids to refine std::vector mref_faces; Mf.deduce_ref_faces(spids, plocs_s, Sf, mref_faces); - - for (const E_Int mfid : mref_faces) { - fat_mfids.push_back(mfid); - } - printf("Fat mfids: %lu\n", fat_mfids.size()); + printf("Fat mfids: %lu\n", mref_faces.size()); ref_M = mref_faces.size(); if (ref_M > 0) { Mf.refine(mref_faces); Mf.conformize(); - Mf.hash_faces(); Mf.make_pnormals(); // update mfids for (E_Int fparent : mref_faces) { @@ -257,5 +224,8 @@ void ICapsule::refine(Smesh &Mf, std::set &mfids, Smesh &Sf, Sf.destroy_BVH(Sf.bvh_root); } while (ref_M > 0 || ref_S > 0); + Mf.hash_faces(); + Sf.hash_faces(); + //point_write("projections", projections); } diff --git a/Cassiopee/XCore/XCore/intersectMesh/ray.cpp b/Cassiopee/XCore/XCore/intersectMesh/ray.cpp index 671de6ebf..b907e38fb 100644 --- a/Cassiopee/XCore/XCore/intersectMesh/ray.cpp +++ b/Cassiopee/XCore/XCore/intersectMesh/ray.cpp @@ -123,17 +123,17 @@ bool MollerTrumboreAnyDir( E_Float inv_det = 1.0 / det; E_Float s[3] = {ox-ax, oy-ay, oz-az}; - u = K_MATH::dot(s, h, 3) * inv_det; - if (u < -TOL || u > 1+TOL) return false; + v = K_MATH::dot(s, h, 3) * inv_det; + if (v < -TOL || v > 1+TOL) return false; E_Float q[3]; K_MATH::cross(s, v1, q); - v = K_MATH::dot(d, q, 3) * inv_det; - if (v < -TOL || v > 1+TOL) return false; - - w = 1 - u - v; + w = K_MATH::dot(d, q, 3) * inv_det; if (w < -TOL || w > 1+TOL) return false; + u = 1 - v - w; + if (u < -TOL || u > 1+TOL) return false; + t = K_MATH::dot(v2, q, 3) * inv_det; x = ox + t * dx; y = oy + t * dy; diff --git a/Cassiopee/XCore/XCore/intersectMesh/smesh.h b/Cassiopee/XCore/XCore/intersectMesh/smesh.h index 581060e02..86f1bcc72 100644 --- a/Cassiopee/XCore/XCore/intersectMesh/smesh.h +++ b/Cassiopee/XCore/XCore/intersectMesh/smesh.h @@ -112,7 +112,8 @@ struct Smesh { void compute_min_distance_between_points(); void project(const Smesh &Mf, const std::vector &mpids, std::vector &plocs) const; - void project_and_replace(Smesh &Mf, E_Int start) const; + void replace_by_projections(const std::vector &pids, + const std::vector &plocs); void ray_BVH_intersect(E_Float ox, E_Float oy, E_Float oz, E_Float dx, E_Float dy, E_Float dz, BVH_node *node, std::vector &plocs) const; diff --git a/Cassiopee/XCore/XCore/intersectMesh/smesh_extract.cpp b/Cassiopee/XCore/XCore/intersectMesh/smesh_extract.cpp index 5ee9e9c18..58ffe3005 100644 --- a/Cassiopee/XCore/XCore/intersectMesh/smesh_extract.cpp +++ b/Cassiopee/XCore/XCore/intersectMesh/smesh_extract.cpp @@ -3,6 +3,7 @@ #include "smesh.h" #include "primitives.h" #include "ray.h" +#include "io.h" void Smesh::get_shared_faces(const PointLoc &loc, std::vector &ret, E_Int &pid, E_Int &eid) const @@ -138,6 +139,8 @@ std::set Smesh::extract_bounding_faces(const Smesh &Sf, get_shared_faces(plocs[p], orig_faces, last_vertex, last_edge); get_shared_faces(plocs[q], tail_faces, dummy, dummy); + //write_ngon("shared", orig_faces); + E_Int starting_face = deduce_face(orig_faces, px, py, pz, D, last_vertex, last_edge); assert(starting_face != -1); diff --git a/Cassiopee/XCore/XCore/intersectMesh/smesh_geom.cpp b/Cassiopee/XCore/XCore/intersectMesh/smesh_geom.cpp index 0d6c7372c..1b3b10688 100644 --- a/Cassiopee/XCore/XCore/intersectMesh/smesh_geom.cpp +++ b/Cassiopee/XCore/XCore/intersectMesh/smesh_geom.cpp @@ -1,5 +1,6 @@ #include "smesh.h" #include "primitives.h" +#include "io.h" void Smesh::get_unit_projected_direction(E_Int fid, const E_Float D[3], E_Float proj[3]) const @@ -80,4 +81,4 @@ E_Int Smesh::deduce_face(const std::vector &pf, assert(faces_hit > 0); return ret_face; -} \ No newline at end of file +} diff --git a/Cassiopee/XCore/XCore/intersectMesh/smesh_locate.cpp b/Cassiopee/XCore/XCore/intersectMesh/smesh_locate.cpp index 339e02be6..a6c0e0b3f 100644 --- a/Cassiopee/XCore/XCore/intersectMesh/smesh_locate.cpp +++ b/Cassiopee/XCore/XCore/intersectMesh/smesh_locate.cpp @@ -3,6 +3,19 @@ #include "primitives.h" #include "io.h" +void Smesh::replace_by_projections(const std::vector &pids, + const std::vector &plocs) +{ + for (size_t i = 0; i < pids.size(); i++) { + E_Int pid = pids[i]; + assert(pid == i); + const auto &ploc = plocs[pid]; + X[pid] = ploc.x; + Y[pid] = ploc.y; + Z[pid] = ploc.z; + } +} + void Smesh::correct_near_points_and_edges(Smesh &Sf, std::vector &plocs) { From 988e064740d0e130bc0d60876c5a377adb783f55 Mon Sep 17 00:00:00 2001 From: imadhammani Date: Fri, 18 Oct 2024 14:10:10 +0200 Subject: [PATCH 64/86] icapsule_refine comments --- .../XCore/XCore/intersectMesh/icapsule_refine.cpp | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/Cassiopee/XCore/XCore/intersectMesh/icapsule_refine.cpp b/Cassiopee/XCore/XCore/intersectMesh/icapsule_refine.cpp index be3111475..0ff4eed60 100644 --- a/Cassiopee/XCore/XCore/intersectMesh/icapsule_refine.cpp +++ b/Cassiopee/XCore/XCore/intersectMesh/icapsule_refine.cpp @@ -159,6 +159,7 @@ void ICapsule::refine(Smesh &Mf, std::set &mfids, Smesh &Sf, std::vector fat_sfids; std::vector fat_mfids; + puts("Making BVHs"); Sf.make_BVH(); Mf.make_BVH(); @@ -175,6 +176,7 @@ void ICapsule::refine(Smesh &Mf, std::set &mfids, Smesh &Sf, // Project mpids on Sf std::vector plocs_m(mpids.size()); + puts("Projecting"); Sf.project(Mf, mpids, plocs_m); // Deduce sfids to refine @@ -185,8 +187,11 @@ void ICapsule::refine(Smesh &Mf, std::set &mfids, Smesh &Sf, // Refine ref_S = sref_faces.size(); if (ref_S > 0) { + puts("Refining"); Sf.refine(sref_faces); + puts("Conformizing"); Sf.conformize(); + puts("Making pnormals"); Sf.make_pnormals(); } @@ -200,26 +205,34 @@ void ICapsule::refine(Smesh &Mf, std::set &mfids, Smesh &Sf, // Reproject spids on mfaces plocs_s.resize(Sf.np); + puts("Projecting"); Mf.project(Sf, spids, plocs_s); + puts("Replacing"); Sf.replace_by_projections(spids, plocs_s); // Deduce mfids to refine std::vector mref_faces; + puts("Deducing fat faces"); Mf.deduce_ref_faces(spids, plocs_s, Sf, mref_faces); printf("Fat mfids: %lu\n", mref_faces.size()); ref_M = mref_faces.size(); if (ref_M > 0) { + puts("Refining"); Mf.refine(mref_faces); + puts("Conformizing"); Mf.conformize(); + puts("Making pnormals"); Mf.make_pnormals(); // update mfids + puts("Updating mfids"); for (E_Int fparent : mref_faces) { const auto &children = Mf.fchildren[fparent].back(); for (E_Int child : children) mfids.insert(child); } } + puts("Destroying BVHs"); Mf.destroy_BVH(Mf.bvh_root); Sf.destroy_BVH(Sf.bvh_root); } while (ref_M > 0 || ref_S > 0); From 6b011a756f8429648ee0e0b56ccd696452fe8459 Mon Sep 17 00:00:00 2001 From: imadhammani Date: Fri, 18 Oct 2024 14:53:21 +0200 Subject: [PATCH 65/86] XCore intersectMesh: faster BVH projection. --- Cassiopee/XCore/XCore/intersectMesh/dcel.cpp | 3 +- .../XCore/XCore/intersectMesh/dcel_io.cpp | 3 +- .../XCore/XCore/intersectMesh/icapsule.cpp | 6 +++- .../XCore/intersectMesh/icapsule_refine.cpp | 4 +-- Cassiopee/XCore/XCore/intersectMesh/smesh.h | 3 +- .../XCore/XCore/intersectMesh/smesh_bvh.cpp | 29 +++++++++++++------ .../XCore/intersectMesh/smesh_locate.cpp | 1 - 7 files changed, 32 insertions(+), 17 deletions(-) diff --git a/Cassiopee/XCore/XCore/intersectMesh/dcel.cpp b/Cassiopee/XCore/XCore/intersectMesh/dcel.cpp index 7ad7d050f..95114c9b8 100644 --- a/Cassiopee/XCore/XCore/intersectMesh/dcel.cpp +++ b/Cassiopee/XCore/XCore/intersectMesh/dcel.cpp @@ -327,7 +327,8 @@ void Dcel::set_cycles_inout(const Smesh &Mf, E_Int color) const E_Float *N = &Mf.pnormals[3*pid]; - E_Float cmp = K_MATH::dot(N, cp, 3); + E_Float dp = K_MATH::dot(N, cp, 3); + E_Int cmp = Sign(dp); if (cmp < 0) { c->inout = Cycle::OUTER; diff --git a/Cassiopee/XCore/XCore/intersectMesh/dcel_io.cpp b/Cassiopee/XCore/XCore/intersectMesh/dcel_io.cpp index f15effc1a..5a42d1331 100644 --- a/Cassiopee/XCore/XCore/intersectMesh/dcel_io.cpp +++ b/Cassiopee/XCore/XCore/intersectMesh/dcel_io.cpp @@ -128,7 +128,6 @@ void Dcel::write_outer_cycles(const char *fname) const write_cycles_of_type(fname, Cycle::OUTER); } - void Dcel::write_ngon(const char *fname, const std::vector &cycles) const { FILE *fh = fopen(fname, "w"); @@ -218,4 +217,4 @@ void Dcel::write_ngon(const char *fname, const std::vector &cycles) con fprintf(fh, SF_D_ " ", i); fclose(fh); -} \ No newline at end of file +} diff --git a/Cassiopee/XCore/XCore/intersectMesh/icapsule.cpp b/Cassiopee/XCore/XCore/intersectMesh/icapsule.cpp index 091543647..04ac88e90 100644 --- a/Cassiopee/XCore/XCore/intersectMesh/icapsule.cpp +++ b/Cassiopee/XCore/XCore/intersectMesh/icapsule.cpp @@ -71,8 +71,11 @@ ICapsule::ICapsule(const Karray &marray, const std::vector &sarrays, //Sf.write_ngon("refined_Sf.im"); //Mf.write_ngon("refined_Mf.im"); + assert(Sf.check_Euler); + assert(Sf.np - Sf.ne + Sf.nf + 1 == 2); + bfaces = Mf.extract_bounding_faces(Sf, plocs); - //Mf.write_ngon("bounding_after.im", bfaces); + Mf.write_ngon("bounding_after.im", bfaces); // Make a patch out of Mf bounding faces Smesh Bf(Mf, bfaces, false); @@ -89,6 +92,7 @@ ICapsule::ICapsule(const Karray &marray, const std::vector &sarrays, Ds.write_inner_cycles("Ds_inner.im"); Ds.write_outer_cycles("Ds_outer.im"); Ds.write_hole_cycles("Ds_hole.im"); + Ds.write_degen_cycles("Ds_degen.im"); // Add Sf spatches.push_back(Sf); diff --git a/Cassiopee/XCore/XCore/intersectMesh/icapsule_refine.cpp b/Cassiopee/XCore/XCore/intersectMesh/icapsule_refine.cpp index 0ff4eed60..43e33693a 100644 --- a/Cassiopee/XCore/XCore/intersectMesh/icapsule_refine.cpp +++ b/Cassiopee/XCore/XCore/intersectMesh/icapsule_refine.cpp @@ -15,7 +15,7 @@ void Smesh::ray_BVH_intersect(E_Float ox, E_Float oy, E_Float oz, if (!node->left && !node->right) { for (E_Int i = node->start; i < node->end; i++) { - E_Int fid = bvh_indices[i]; + E_Int fid = bvh_fids[i]; const auto &pn = Fc[fid]; const E_Float *fc = &fcenters[3*fid]; @@ -161,7 +161,7 @@ void ICapsule::refine(Smesh &Mf, std::set &mfids, Smesh &Sf, puts("Making BVHs"); Sf.make_BVH(); - Mf.make_BVH(); + Mf.make_BVH(mfids); /*********************** Sf refinement ***********************/ diff --git a/Cassiopee/XCore/XCore/intersectMesh/smesh.h b/Cassiopee/XCore/XCore/intersectMesh/smesh.h index 86f1bcc72..5f0a13cc3 100644 --- a/Cassiopee/XCore/XCore/intersectMesh/smesh.h +++ b/Cassiopee/XCore/XCore/intersectMesh/smesh.h @@ -125,7 +125,7 @@ struct Smesh { E_Float xmin, xmax, ymin, ymax, zmin, zmax; E_Float HX, HY, HZ; std::map> bin_faces; - std::vector bvh_indices; + std::vector bvh_fids; static const E_Int MAX_FACES_PER_BVH_LEAF = 8; BVH_node *bvh_root = NULL; @@ -137,6 +137,7 @@ struct Smesh { return i + NX*j + NXY*k; } void make_BVH(); + void make_BVH(const std::set &fids); AABB make_AABB(E_Int start, E_Int end); BVH_node *make_BVH_node(const AABB &box, E_Int start, E_Int end, BVH_node *left, BVH_node *right); diff --git a/Cassiopee/XCore/XCore/intersectMesh/smesh_bvh.cpp b/Cassiopee/XCore/XCore/intersectMesh/smesh_bvh.cpp index 4ca77b4a1..5202ee5d3 100644 --- a/Cassiopee/XCore/XCore/intersectMesh/smesh_bvh.cpp +++ b/Cassiopee/XCore/XCore/intersectMesh/smesh_bvh.cpp @@ -9,7 +9,7 @@ AABB Smesh::make_AABB(E_Int start, E_Int end) xmax = ymax = zmax = EFLOATMIN; for (E_Int i = start; i < end; i++) { - E_Int fid = bvh_indices[i]; + E_Int fid = bvh_fids[i]; const auto &pn = F[fid]; for (E_Int p : pn) { if (X[p] < xmin) xmin = X[p]; @@ -70,10 +70,10 @@ BVH_node *Smesh::make_BVH_subtree(E_Int start, E_Int end, const AABB &parent) dim = 2; } - std::sort(bvh_indices.begin() + start, bvh_indices.begin() + end, - [&] (E_Int i, E_Int j) { - E_Float *fci = &fcenters[3*i]; - E_Float *fcj = &fcenters[3*j]; + std::sort(bvh_fids.begin() + start, bvh_fids.begin() + end, + [&] (E_Int fi, E_Int fj) { + E_Float *fci = &fcenters[3*fi]; + E_Float *fcj = &fcenters[3*fj]; return fci[dim] < fcj[dim]; } ); @@ -88,13 +88,24 @@ BVH_node *Smesh::make_BVH_subtree(E_Int start, E_Int end, const AABB &parent) void Smesh::make_BVH() { - bvh_indices.clear(); - bvh_indices.reserve(nf); - for (E_Int i = 0; i < nf; i++) bvh_indices.push_back(i); + bvh_fids.clear(); + bvh_fids.reserve(nf); + for (E_Int i = 0; i < nf; i++) { + bvh_fids.push_back(i); + } bvh_root = make_BVH_subtree(0, nf, AABB_HUGE); } +void Smesh::make_BVH(const std::set &fids) +{ + bvh_fids.clear(); + bvh_fids.reserve(fids.size()); + for (auto fid : fids) bvh_fids.push_back(fid); + + bvh_root = make_BVH_subtree(0, fids.size(), AABB_HUGE); +} + void Smesh::destroy_BVH(BVH_node *root) { if (root == NULL) return; @@ -103,4 +114,4 @@ void Smesh::destroy_BVH(BVH_node *root) destroy_BVH(root->right); delete root; -} \ No newline at end of file +} diff --git a/Cassiopee/XCore/XCore/intersectMesh/smesh_locate.cpp b/Cassiopee/XCore/XCore/intersectMesh/smesh_locate.cpp index a6c0e0b3f..252b5efea 100644 --- a/Cassiopee/XCore/XCore/intersectMesh/smesh_locate.cpp +++ b/Cassiopee/XCore/XCore/intersectMesh/smesh_locate.cpp @@ -8,7 +8,6 @@ void Smesh::replace_by_projections(const std::vector &pids, { for (size_t i = 0; i < pids.size(); i++) { E_Int pid = pids[i]; - assert(pid == i); const auto &ploc = plocs[pid]; X[pid] = ploc.x; Y[pid] = ploc.y; From f3a6ced9c230803c43ed3231c68ae3e42724b939 Mon Sep 17 00:00:00 2001 From: imadhammani Date: Mon, 21 Oct 2024 18:50:01 +0200 Subject: [PATCH 66/86] XCore intersectMesh: problem with collinear edges --- Cassiopee/XCore/XCore/intersectMesh/dcel.cpp | 976 ++++++++++-------- Cassiopee/XCore/XCore/intersectMesh/dcel.h | 78 +- .../XCore/XCore/intersectMesh/dcel_cut.cpp | 118 --- .../XCore/XCore/intersectMesh/dcel_io.cpp | 2 +- .../XCore/XCore/intersectMesh/dcel_trace.cpp | 227 ---- .../XCore/XCore/intersectMesh/icapsule.cpp | 38 +- .../XCore/intersectMesh/icapsule_refine.cpp | 18 +- .../XCore/XCore/intersectMesh/primitives.cpp | 9 + Cassiopee/XCore/XCore/intersectMesh/smesh.h | 1 - Cassiopee/XCore/srcs.py | 2 - 10 files changed, 594 insertions(+), 875 deletions(-) delete mode 100644 Cassiopee/XCore/XCore/intersectMesh/dcel_cut.cpp delete mode 100644 Cassiopee/XCore/XCore/intersectMesh/dcel_trace.cpp diff --git a/Cassiopee/XCore/XCore/intersectMesh/dcel.cpp b/Cassiopee/XCore/XCore/intersectMesh/dcel.cpp index 95114c9b8..0a809c068 100644 --- a/Cassiopee/XCore/XCore/intersectMesh/dcel.cpp +++ b/Cassiopee/XCore/XCore/intersectMesh/dcel.cpp @@ -27,7 +27,45 @@ #include "smesh.h" #include "triangle.h" -Dcel::Dcel(const Smesh &Mf, E_Int color) +void Dcel::init_vertices(const Smesh &Mf, const Smesh &Sf, + const std::vector &plocs) +{ + E_Int duplicate_vertices = 0; + + for (E_Int i = 0; i < Mf.np; i++) { + Vertex *v = new Vertex(Mf.X[i], Mf.Y[i], Mf.Z[i]); + v->oids[Dcel::RED] = i; + vertex_set.insert(v); + } + + for (E_Int i = 0; i < Sf.np; i++) { + Vertex tmp(Sf.X[i], Sf.Y[i], Sf.Z[i]); + auto it = vertex_set.find(&tmp); + const auto &ploc = plocs[i]; + Vertex *v = NULL; + if (it == vertex_set.end()) { + v = new Vertex(Sf.X[i], Sf.Y[i], Sf.Z[i]); + v->oids[Dcel::BLACK] = i; + vertex_set.insert(v); + } else { + v = *it; + v->oids[Dcel::BLACK] = i; + duplicate_vertices++; + } + v->ploc = plocs[i]; + } + + V.reserve(vertex_set.size()); + for (Vertex *v : vertex_set) { + v->id = V.size(); + V.push_back(v); + } + assert(V.back()->id == V.size()-1); + + printf("Duplicate vertices: %d\n", duplicate_vertices); +} + +Dcel::Dcel(const Smesh &Mf, int color) { const auto &X = Mf.X; const auto &Y = Mf.Y; @@ -53,16 +91,445 @@ Dcel::Dcel(const Smesh &Mf, E_Int color) } make_cycles(); - set_cycles_inout(Mf, color); + set_cycles_inout(false); } -void Dcel::init_hedges_and_faces(const Smesh &Mf, E_Int color) +Dcel::Dcel(const Smesh &Mf, const Smesh &Sf, const std::vector &plocs) +{ + init_vertices(Mf, Sf, plocs); + + init_hedges_and_faces(Mf, RED); + init_hedges_and_faces(Sf, BLACK); + + if (check_hedges(H) != 0) { + fprintf(stderr, "Dcel: Inconsistent half-edge records!\n"); + abort(); + } + + if (check_faces(H, F) != 0) { + fprintf(stderr, "Dcel: Inconsistent face records!\n"); + abort(); + } + + make_cycles(); + set_cycles_inout(false); + + std::vector xpoints; + + // Register the intersections between Sf points and Mf edges + E_Int v_on_e = 0; + for (Vertex *v : V) { + // Strictly the Sf points + if (v->oids[0] == -1 && v->oids[1] != -1) { + const auto &ploc = v->ploc; + if (ploc.e_idx == -1) continue; + + // Set the reference edge for normal computation + E_Int fid = ploc.fid; + const auto &pe = Mf.F2E[fid]; + E_Int e = pe[ploc.e_idx]; + + // Add the vertex to hedge intersections + Hedge *h = H[2*e]; + assert(h->color == RED); + Vertex *O = h->orig; + Vertex *T = h->twin->orig; + if (cmp_vtx(O, T) > 0) h = h->twin; + hedge_intersections[h].push_back(v); + + xpoints.push_back({v->x,v->y,v->z}); + + v_on_e++; + } + } + printf("Sf points on Mf edges: %d\n", v_on_e); + point_write("xpoints.im", xpoints); + + // Trace + for (E_Int eid_s = 0; eid_s < Sf.ne; eid_s++) { + Hedge *hs = H[2*(Mf.ne + eid_s)]; + assert(hs->color == BLACK); + Vertex *O = hs->orig; + Vertex *T = hs->twin->orig; + if (cmp_vtx(O, T) > 0) hs = hs->twin; + + E_Int p = hs->orig->oids[1]; + E_Int q = hs->twin->orig->oids[1]; + + E_Float spx = Sf.X[p], spy = Sf.Y[p], spz = Sf.Z[p]; + E_Float sqx = Sf.X[q], sqy = Sf.Y[q], sqz = Sf.Z[q]; + + E_Float D[3] = {sqx-spx, sqy-spy, sqz-spz}; + E_Float NORM = K_MATH::norm(D, 3); + D[0] /= NORM, D[1] /= NORM, D[2] /= NORM; + + std::vector orig_faces; + std::vector tail_faces; + + E_Int last_vertex = -1, last_edge = -1, dummy; + + Mf.get_shared_faces(plocs[p], orig_faces, last_vertex, last_edge); + Mf.get_shared_faces(plocs[q], tail_faces, dummy, dummy); + + E_Int starting_face = Mf.deduce_face(orig_faces, spx, spy, spz, + D, last_vertex, last_edge); + assert(starting_face != -1); + + bool found_tail = false; + E_Int cur_fid = starting_face; + E_Float cur_pos[3] = {spx, spy, spz}; + + E_Int walk = 0; + E_Int max_walks = 20; + + while (!found_tail && walk <= max_walks) { + + for (auto fid : tail_faces) { + if (fid == cur_fid) { + found_tail = true; + break; + } + } + + if (found_tail) break; + + E_Float proj[3]; + Mf.get_unit_projected_direction(cur_fid, D, proj); + + const auto &pn = Mf.Fc[cur_fid]; + const auto &pe = Mf.F2E[cur_fid]; + assert(pe.size() == pn.size()); + const E_Float *fN = &Mf.fnormals[3*cur_fid]; + + E_Int next_fid = -1; + E_Float next_pos[3] = {EFLOATMAX, EFLOATMAX, EFLOATMAX}; + + bool hit = false; + + for (size_t i = 0; i < pn.size(); i++) { + E_Int p = pn[i]; + E_Int q = pn[(i+1)%pn.size()]; + E_Int e = pe[i]; + + if (p == last_vertex || q == last_vertex || e == last_edge) + continue; + + E_Float px = Mf.X[p], py = Mf.Y[p], pz = Mf.Z[p]; + E_Float qx = Mf.X[q], qy = Mf.Y[q], qz = Mf.Z[q]; + + E_Float t, s; + hit = ray_edge_intersect( + cur_pos[0], cur_pos[1], cur_pos[2], + proj[0], proj[1], proj[2], + px, py, pz, qx, qy, qz, + t, s + ); + + if (hit) { + if (s > TOL && s < 1 - TOL) { + // Hit edge middle + const auto &pe = Mf.F2E[cur_fid]; + E_Int eid_m = pe[i]; + last_edge = eid_m; + last_vertex = -1; + assert(Mf.E2F[eid_m][0] == cur_fid || Mf.E2F[eid_m][1] == cur_fid); + if (Mf.E2F[eid_m][0] == cur_fid) next_fid = Mf.E2F[eid_m][1]; + else next_fid = Mf.E2F[eid_m][0]; + + next_pos[0] = cur_pos[0] + t * proj[0]; + next_pos[1] = cur_pos[1] + t * proj[1]; + next_pos[2] = cur_pos[2] + t * proj[2]; + + // Create a new intersection vertex + Vertex tmp(next_pos[0], next_pos[1], next_pos[2]); + assert(vertex_set.find(&tmp) == vertex_set.end()); + Vertex *x = new Vertex(next_pos[0], next_pos[1], + next_pos[2]); + + x->ploc.fid = cur_fid; + x->ploc.e_idx = i; + + x->id = V.size(); + V.push_back(x); + vertex_set.insert(x); + xpoints.push_back({x->x,x->y,x->z}); + + // Register the intersection + Hedge *hm = H[2*eid_m]; + assert(hm->color == RED); + Vertex *O = hm->orig; + Vertex *T = hm->twin->orig; + if (cmp_vtx(O, T) > 0) hm = hm->twin; + + hedge_intersections[hm].push_back(x); + hedge_intersections[hs].push_back(x); + } else { + // Hit an edge endpoint + bool hit_p = (s <= TOL); + bool hit_q = (s >= 1 - TOL); + assert(!(hit_p && hit_q)); + last_edge = -1; + if (hit_p) last_vertex = p; + else last_vertex = q; + next_pos[0] = Mf.X[last_vertex]; + next_pos[1] = Mf.Y[last_vertex]; + next_pos[2] = Mf.Z[last_vertex]; + const auto &pf = Mf.P2F[last_vertex]; + next_fid = Mf.deduce_face(pf, + next_pos[0], next_pos[1], next_pos[2], + D, last_vertex, last_edge + ); + assert(next_fid != -1); + + // Find Vertex corresponding to hit vertex + Vertex tmp(Mf.X[last_vertex], Mf.Y[last_vertex], Mf.Z[last_vertex]); + auto it = vertex_set.find(&tmp); + assert(it != vertex_set.end()); + Vertex *x = *it; + + // Register the intersection + hedge_intersections[hs].push_back(x); + } + break; + } + } + + assert(hit); + assert(next_fid != cur_fid); + cur_fid = next_fid; + cur_pos[0] = next_pos[0]; + cur_pos[1] = next_pos[1]; + cur_pos[2] = next_pos[2]; + walk++; + } + + assert(found_tail); + assert(walk <= max_walks); + } + + // Cut + for (auto &h2x : hedge_intersections) { + Hedge *h = h2x.first; + auto &xs = h2x.second; + + Vertex *o = h->orig; + + // TODO(Imad): check that the intersections are 'sufficiently' spaced out + for (Vertex *x : xs) { + E_Float D[3] = {x->x-o->x, x->y-o->y, x->z-o->z}; + x->d2 = K_MATH::dot(D, D, 3); + } + + std::sort(xs.begin(), xs.end(), [&] (const Vertex *a, const Vertex *b) + { + assert(Sign(a->d2-b->d2) != 0); + return a->d2 < b->d2; + }); + + Hedge *current_h = h; + Hedge *t = h->twin; + + Hedge *t_next = t->next; + Hedge *h_next = h->next; + + for (Vertex *x : xs) { + Hedge *e1 = new Hedge(x, current_h->color); + Hedge *e2 = new Hedge(x, t->color); + + H.push_back(e1); + H.push_back(e2); + + e1->left = current_h->left; + e2->left = t->left; + + current_h->twin = e2; + e2->twin = current_h; + t->twin = e1; + e1->twin = t; + + current_h->next = e1; + e1->prev = current_h; + t->next = e2; + e2->prev = t; + + current_h = e1; + } + + //t_next->prev = h->twin; + //h->twin->next = t_next; + //h_next->prev = current_h; + //current_h->next = h_next; + } + + // Resolve + std::vector> list(V.size()); + for (Hedge *h : H) { + Vertex *o = h->orig; + list[o->id].push_back(h); + } + + for (size_t vid = 0; vid < V.size(); vid++) { + Vertex *v = V[vid]; + + E_Float N[3] = {0, 0, 0}; + + if (v->oids[0] != -1) { + const E_Float *pN = &Mf.pnormals[3*v->oids[0]]; + for (E_Int i = 0; i < 3; i++) N[i] = pN[i]; + } else if (v->oids[1] != -1) { + const E_Float *fN = &Mf.fnormals[3*v->ploc.fid]; + for (E_Int i = 0; i < 3; i++) N[i] = fN[i]; + } else { + E_Int fid_m = v->ploc.fid; + E_Int eid_m = Mf.F2E[fid_m][v->ploc.e_idx]; + const auto &pf = Mf.E2F[eid_m]; + assert(pf[0] == fid_m || pf[1] == fid_m); + const E_Float *fN1 = &Mf.fnormals[3*pf[0]]; + const E_Float *fN2 = &Mf.fnormals[3*pf[1]]; + for (int i = 0; i < 3; i++) N[i] += fN1[i] + fN2[i]; + E_Float NORM = K_MATH::norm(N, 3); + for (int i = 0; i < 3; i++) N[i] /= NORM; + } + + auto &leaving = list[vid]; + + for (Hedge *h : leaving) assert(h->orig == v); + + /* + bool do_sort = false; + for (size_t i = 1; i < leaving.size(); i++) { + if (leaving[i]->color != leaving[0]->color) { + do_sort = true; + break; + } + } + if (!do_sort) continue; + */ + + sort_leaving_hedges(leaving, N); + + for (size_t i = 0; i < leaving.size(); i++) { + Hedge *h = leaving[i]; + Hedge *w = leaving[(i+1)%leaving.size()]; + h->twin->next = w; + w->prev = h->twin; + } + } + + if (check_hedges(H) != 0) { + fprintf(stderr, "Dcel: Inconsistent half-edge records!\n"); + assert(0); + abort(); + } + + make_cycles(); + set_cycles_inout(true); + + auto new_F = make_cycle_faces(C); + printf("Non-hole faces: %lu\n", new_F.size()); + + set_face_labels(new_F); + + /* + update_hedge_faces(new_F); + + for (Face *f : F) delete f; + F = new_F; + + check_faces(H, F); + */ + + + puts("ok"); +} + +void Dcel::set_face_labels(std::vector &new_F) +{ + // Label each face with the ids of the original faces containing it + + for (size_t i = 0; i < new_F.size(); i++) { + Face *f = new_F[i]; + + // Get the first RED and BLACK half-edges in the face cycle + Hedge *h = f->rep; + + Hedge *R = NULL; + Hedge *B = NULL; + E_Int RB = 0; + + if (h->color == Dcel::RED) { + R = h; + B = get_hedge_of_color(f, Dcel::BLACK); + if (B) RB = 1; + } else if (h->color == Dcel::BLACK) { + B = h; + R = get_hedge_of_color(f, Dcel::RED); + if (R) RB = 1; + } else { + assert(0); + } + + if (RB) { + // RED face should always exist + assert(R->left); + f->oids[Dcel::RED] = R->left->oids[Dcel::RED]; + assert(f->oids[Dcel::RED] != -1); + + // BLACK face might not exist + f->oids[Dcel::BLACK] = (B->left) ? B->left->oids[Dcel::BLACK] : -1; + } else { + // Only single color possible is RED + assert(R && !B); + //Hedge *REP = (R != NULL) ? R : B; + //if (REP != R) { + // hedge_write("black", REP); + //} + f->oids[Dcel::RED] = R->left->oids[Dcel::RED]; + } + } +} + +Dcel::Hedge *Dcel::get_hedge_of_color(Face *f, int color) +{ + Hedge *h = f->rep; + if (h->color == color) return h; + Hedge *w = h->next; + while (w != h) { + if (w->color == color) return w; + w = w->next; + } + return NULL; +} + +std::vector Dcel::make_cycle_faces(const std::vector &C) +{ + std::vector new_F; + + for (Cycle *c : C) { + if (c->inout == Cycle::HOLE) continue; + + // Create a face record + Face *f = new Face; + + // Set its rep hedge to some edge of the cycle + Hedge *h = c->rep; + f->rep = h; + + new_F.push_back(f); + } + + return new_F; +} + +void Dcel::init_hedges_and_faces(const Smesh &Mf, int color) { printf("Doing color %d\n", color); - H.reserve(Mf.ne*2); + size_t current_nh = H.size(); - std::vector> list(Mf.np); + H.reserve(current_nh + Mf.ne*2); + + std::vector> list(Mf.np); // Create hedge records @@ -74,13 +541,26 @@ void Dcel::init_hedges_and_faces(const Smesh &Mf, E_Int color) E_Int p = e.p; E_Int q = e.q; - Vertex *P = V[p]; - Hedge *h = new Hedge(P, color); - list[p].push_back(h); - - Vertex *Q = V[q]; - Hedge *t = new Hedge(Q, color); - list[q].push_back(t); + Hedge *h = NULL; + Hedge *t = NULL; + + { + Vertex tmp(Mf.X[p], Mf.Y[p], Mf.Z[p]); + auto it = vertex_set.find(&tmp); + assert(it != vertex_set.end()); + Vertex *P = *it; + h = new Hedge(P, color); + list[p].push_back(h); + } + + { + Vertex tmp(Mf.X[q], Mf.Y[q], Mf.Z[q]); + auto it = vertex_set.find(&tmp); + assert(it != vertex_set.end()); + Vertex *Q = *it; + t = new Hedge(Q, color); + list[q].push_back(t); + } h->twin = t; t->twin = h; @@ -95,7 +575,6 @@ void Dcel::init_hedges_and_faces(const Smesh &Mf, E_Int color) for (E_Int pid = 0; pid < Mf.np; pid++) { auto &hedges = list[pid]; - assert(hedges.size() >= 2); const E_Float *N = &pnormals[3*pid]; sort_leaving_hedges(hedges, N); @@ -113,14 +592,16 @@ void Dcel::init_hedges_and_faces(const Smesh &Mf, E_Int color) const auto &F2E = Mf.F2E; const auto &E2F = Mf.E2F; - F.reserve(Mf.nf); + size_t current_nf = F.size(); + + F.reserve(current_nf + Mf.nf); for (E_Int fid = 0; fid < Mf.nf; fid++) { const auto &pe = F2E[fid]; E_Int first_edge = pe[0]; E_Int where = 2*first_edge; - Hedge *h = H[where]; - Hedge *t = H[where + 1]; + Hedge *h = H[current_nh + where]; + Hedge *t = H[current_nh + where + 1]; assert(h->twin == t); assert(t->twin == h); @@ -203,12 +684,19 @@ void Dcel::sort_leaving_hedges(std::vector &leaving, Hedge *h = leaving[i]; Hedge *w = leaving[j]; - + assert(h->color != w->color); - Vertex *P = h->orig; - Vertex *Q = h->twin->orig; - if (cmp_vtx(P, Q) < 0) return true; + Vertex *O_h = h->orig; + Vertex *T_h = h->twin->orig; + + Vertex *O_w = w->orig; + Vertex *T_w = w->twin->orig; + + assert(O_w == O_h); + assert(T_w == T_h); + + if (cmp_vtx(O_w, T_w) < 0) return true; return false; }); @@ -255,6 +743,7 @@ E_Int Dcel::check_faces(const std::vector &H, void Dcel::make_cycles() { C.clear(); + for (Hedge *h : H) h->cycle = NULL; for (size_t i = 0; i < H.size(); i++) { Hedge *h = H[i]; @@ -274,78 +763,73 @@ void Dcel::make_cycles() } } -void Dcel::set_cycles_inout(const Smesh &Mf, E_Int color) +void Dcel::set_cycles_inout(bool intersected) { inner = 0; outer = 0; degen = 0; hole = 0; - for (Cycle *c : C) { - Hedge *h = c->rep; - if (h->left == NULL) { - c->inout = Cycle::HOLE; + for (Cycle *cycle : C) { + Hedge *h = cycle->rep; + + bool is_hole = (intersected && h->left == NULL && h->color == RED) || + (!intersected && h->left == NULL); + + if (is_hole) { + cycle->inout = Cycle::HOLE; hole++; continue; } // Get the leftmost vertex in the cycle - Vertex *leftmost = h->orig; + Vertex *b = h->orig; Hedge *e2 = h; // Half-edge starting at leftmost vertex - Hedge *e1 = h->prev; // Half-edge ending at leftmost vertex Hedge *w = h->next; while (w != h) { Vertex *p = w->orig; - E_Int cmp = cmp_vtx(p, leftmost); + E_Int cmp = cmp_vtx(p, b); if (cmp < 0) { - leftmost = p; + b = p; e2 = w; - e1 = w->prev; } w = w->next; } - assert(e2->orig == leftmost); - assert(e1->twin->orig == leftmost); + Hedge *e1 = e2->prev; - Vertex *a = e1->orig; - Vertex *b = e2->twin->orig; - - E_Float px = leftmost->x - a->x; - E_Float py = leftmost->y - a->y; - E_Float pz = leftmost->z - a->z; - E_Float nx = b->x - leftmost->x; - E_Float ny = b->y - leftmost->y; - E_Float nz = b->z - leftmost->z; + assert(e2->orig == b); + assert(e1->twin->orig == b); - E_Float cp[3] = {py*nz - pz*ny, pz*nx - px*nz, px*ny - py*nx}; - - E_Int pid = leftmost->oids[color]; + Vertex *a = e1->orig; + Vertex *c = e2->twin->orig; - const E_Float *N = &Mf.pnormals[3*pid]; + // Vectors ab and bc + E_Float ab[3] = {b->x-a->x, b->y-a->y, b->z-a->z}; + E_Float bc[3] = {c->x-b->x, c->y-b->y, c->z-b->z}; - E_Float dp = K_MATH::dot(N, cp, 3); - E_Int cmp = Sign(dp); + E_Float N[3]; + K_MATH::cross(ab, bc, N); - if (cmp < 0) { - c->inout = Cycle::OUTER; - outer++; - } else if (cmp == 0) { - c->inout = Cycle::DEGEN; + if (Sign(K_MATH::norm(N, 3) == 0)) { + cycle->inout = Cycle::DEGEN; degen++; } else { - c->inout = Cycle::INNER; + cycle->inout = Cycle::INNER; inner++; } } printf("Inner cycles: " SF_D_ "\n", inner); - printf("Outer cycles: " SF_D_ "\n", outer); printf("Degen cycles: " SF_D_ "\n", degen); printf("Hole cycles: " SF_D_ "\n", hole); + + write_degen_cycles("degen.im"); + write_inner_cycles("inner.im"); + write_hole_cycles("hole.im"); } Dcel::~Dcel() @@ -356,23 +840,8 @@ Dcel::~Dcel() for (Cycle *c : C) delete c; } -/* - -void Dcel::init_vertices(const Smesh &M0, const Smesh &M1) -{ - assert(Q.empty()); - - for (E_Int i = 0; i < M0.np; i++) { - //Q.insert(M0.X[i], M0.Y[i], M0.Z[i], M0.l2gp.at(i), Dcel::RED); - Q.insert(M0.X[i], M0.Y[i], M0.Z[i], i, Dcel::RED); - } - - for (E_Int i = 0; i < M1.np; i++) { - //Q.insert(M1.X[i], M1.Y[i], M1.Z[i], M1.l2gp.at(i), Dcel::BLACK); - Q.insert(M1.X[i], M1.Y[i], M1.Z[i], i, Dcel::BLACK); - } -} +/* void Dcel::update_hedge_faces(const std::vector &F) { for (Face *f : F) { @@ -386,373 +855,6 @@ void Dcel::update_hedge_faces(const std::vector &F) } } -std::vector Dcel::make_cycle_faces(const std::vector &C) -{ - std::vector new_F; - - for (Cycle *c : C) { - - // Create a face record - Face *f = new Face; - - // Set its rep hedge to some edge of the cycle - Hedge *h = c->rep; - f->rep = h; - - new_F.push_back(f); - } - - return new_F; -} - -void Dcel::set_face_labels(std::vector &F) -{ - // Label each face with the ids of the original faces containing it - - for (size_t i = 0; i < F.size(); i++) { - Face *f = F[i]; - - // Get the first RED and BLACK half-edges in the face cycle. - Hedge *h = f->rep; - - Hedge *R = NULL; - Hedge *B = NULL; - E_Int RB = 0; - - if (h->color == Dcel::RED) { - R = h; - B = get_hedge_of_color(f, Dcel::BLACK); - if (B) RB = 1; - } else if (h->color == Dcel::BLACK) { - B = h; - R = get_hedge_of_color(f, Dcel::RED); - if (R) RB = 1; - } else { - assert(0); - } - - if (RB) { - // First case: R and B both exist - assert(R->left); - assert(B->left); - assert(R->color == Dcel::RED); - assert(B->color == Dcel::BLACK); - f->oid[Dcel::RED] = R->left->oid[Dcel::RED]; - f->oid[Dcel::BLACK] = B->left->oid[Dcel::BLACK]; - } else { - // Second case: the face is single color - // Only single color possible is RED, otherwise intersection problem - // is ill-posed - Hedge *REP = (R != NULL) ? R : B; - if (REP != R) { - hedge_write("black", REP); - } - assert(REP == R); - assert(REP->color == Dcel::RED); - assert(REP->left); - f->oid[REP->color] = REP->left->oid[REP->color]; - } - } -} - -Hedge *Dcel::get_hedge_of_color(Face *f, E_Int color) -{ - Hedge *h = f->rep; - if (h->color == color) return h; - Hedge *w = h->next; - while (w != h) { - if (w->color == color) return w; - w = w->next; - } - return NULL; -} - -Dcel::Dcel(Smesh &M0, Smesh &M1) -{ - init_vertices(M0, M1); - Q.inorder(V); - size_t count = 0; - for (size_t i = 0; i < V.size(); i++) { - V[i]->id = i; - if (V[i]->oid[0] != -1 && V[i]->oid[1] != -1) count++; - } - printf("Duplicate points: %lu\n", count); - - init_hedges_and_faces(M0, RED); - - init_hedges_and_faces(M1, BLACK); - - assert(check_hedges(H)); - - assert(check_faces(H, F)); -} - -std::vector Dcel::get_face_vertices(Face *f) -{ - std::vector ret; - Hedge *h = f->rep; - ret.push_back(h->orig); - Hedge *w = h->next; - while (w != h) { - ret.push_back(w->orig); - w = w->next; - } - return ret; -} - -void Dcel::cut_hedge_at_vertex(Hedge *e, Vertex *x) -{ - // Create two new half-edge records with x as their origin - Hedge *e1 = new Hedge(x); - Hedge *e2 = new Hedge(x); - - e1->color = e->color; - e2->color = e->color; - - Hedge *t = e->twin; - - // Copy the face record - e1->left = e->left; - e2->left = t->left; - - // Pair-up the new half-edges - e->twin = e2; - e1->twin = t; - t->twin = e1; - e2->twin = e; - - // Set prev and next pointers at the endpoints - e1->next = e->next; - e2->next = t->next; - e->next->prev = e1; - t->next->prev = e2; - - H.push_back(e1); - H.push_back(e2); - - e->next = e1; - t->next = e2; - - e1->prev = e; - e2->prev = t; - - Cp[x].push_back(e1); - Cp[x].push_back(e2); -} - -std::vector points; - -void Dcel::find_intersections_3D(const Smesh &M, const Smesh &S) -{ - puts(" Isolating s_hedges..."); - - std::vector s_hedges; - - for (E_Int i = 2*M.ne; i < 2*(M.ne + S.ne); i += 2) { - Hedge *h = H[i]; - assert(h->twin == H[i+1]); - assert(h->color == Dcel::BLACK); - Hedge *t = h->twin; - assert(h != NULL); - assert(t != NULL); - Vertex *p = h->orig; - Vertex *q = t->orig; - assert(p != NULL); - assert(q != NULL); - E_Int cmp = cmp_vtx(p, q); - assert(cmp != 0); - if (cmp_vtx(p, q) < 0) { - s_hedges.push_back(h); - } else { - s_hedges.push_back(t); - } - } - - puts(" Sorting s_hedges..."); - - std::sort(s_hedges.begin(), s_hedges.end(), [&] (Hedge *h, Hedge *w) - { - assert(h->twin != w); - assert(w->twin != h); - - E_Int cmp = cmp_vtx(h->orig, w->orig); - if (cmp < 0) return true; - if (cmp > 0) return false; - - cmp = cmp_vtx(h->twin->orig, w->twin->orig); - assert(cmp != 0); - - if (cmp < 0) return true; - return false; - }); - - puts(" Registering endpoint-edge intersections..."); - - init_mh_sv_intersections(M); - - puts(" Tracing edges..."); - - size_t before = V.size(); - - for (size_t hid = 0; hid < s_hedges.size(); hid++) { - Hedge *sh = s_hedges[hid]; - - //printf("Tracing hedge %zu / %zu\n", hid+1, s_hedges.size()); - - //trace_hedge(sh, M, S, hid); - trace_hedge_2(sh, M, S, hid); - } - - size_t after = V.size(); - - printf("Duplicate intersections: %d\n", dup_x); - printf("Vertices crossed: %lu\n", vertices_crossed.size()); - - std::vector xpoints; - for (size_t i = before; i < after; i++) { - Vertex *v = V[i]; - xpoints.push_back(Point(v->x, v->y, v->z)); - } - point_write("xpoints", xpoints); - - cut_hedges(); -} - -void Dcel::resolve_hedges(const Smesh &M, const Smesh &S) -{ - assert(Up.empty()); - assert(Lp.empty()); - - Up.clear(); - Lp.clear(); - - for (Hedge *h : H) { - - Hedge *t = h->twin; - - Vertex *p = h->orig; - Vertex *q = t->orig; - - if (cmp_vtx(p, q) <= 0) { - - Up[p].push_back(h); - Up[q].push_back(t); - - } - } - - puts("Resolving vertices..."); - - for (size_t i = 0; i < V.size(); i++) { - - //printf("Resolving vertex %d / %zu\n", i+1, V.size()); - - Vertex *v = V[i]; - - std::vector leaving; - - for (Hedge *h : Up[v]) { - assert(h->orig == v); - leaving.push_back(h); - } - - E_Float N[3] = {0}; - - // M point - if (v->oid[0] != -1) { - - E_Int mpid = v->oid[0]; - - const E_Float *pN = &M.pnormals[3*mpid]; - for (E_Int i = 0; i < 3; i++) N[i] = pN[i]; - - } - - // S point - else if (v->oid[1] != -1) { - - const auto &loc = v->loc; - - E_Int mfid = loc.fid; - - if (loc.e_idx != -1) { - - const auto &pe = M.F2E[mfid]; - E_Int eid = pe[loc.e_idx]; - const auto &pf = M.E2F[eid]; - assert(mfid == pf[0] || mfid == pf[1]); - - E_Int mf1 = pf[0]; - E_Int mf2 = pf[1]; - - const E_Float *fN1 = &M.fnormals[3*mf1]; - const E_Float *fN2 = &M.fnormals[3*mf2]; - - for (E_Int i = 0; i < 3; i++) { - N[i] += fN1[i]; - N[i] += fN2[i]; - } - - E_Float NORM = K_MATH::norm(N, 3); - for (E_Int i = 0; i < 3; i++) N[i] /= NORM; - - } else if (loc.v_idx != -1) { - - const auto &pn = M.F[mfid]; - E_Int mpid = pn[loc.v_idx]; - const E_Float *pN = &M.pnormals[3*mpid]; - for (E_Int i = 0; i < 3; i++) N[i] = pN[i]; - - } else { - - const E_Float *fN = &M.fnormals[3*mfid]; - - for (E_Int i = 0; i < 3; i++) N[i] = fN[i]; - - } - - } - - // Intersection - else { - - //Hedge *h = v->xhedge; - //assert(h); - //Face *f1 = h->left; - //Face *f2 = h->twin->left; - //E_Int mf1 = f1->oid[0]; - //E_Int mf2 = f2->oid[0]; - - E_Int eid = v->meid; - const auto &pf = M.E2F[eid]; - - E_Int mf1 = pf[0]; - E_Int mf2 = pf[1]; - assert(mf2 != -1); - - const E_Float *fN1 = &M.fnormals[3*mf1]; - const E_Float *fN2 = &M.fnormals[3*mf2]; - - for (E_Int i = 0; i < 3; i++) { - N[i] += fN1[i]; - N[i] += fN2[i]; - } - - E_Float NORM = K_MATH::norm(N, 3); - for (E_Int i = 0; i < 3; i++) N[i] /= NORM; - } - - sort_leaving_hedges(leaving, N, M); - - for (size_t i = 0; i < leaving.size(); i++) { - Hedge *h = leaving[i]; - Hedge *w = leaving[(i+1)%leaving.size()]; - h->twin->next = w; - w->prev = h->twin; - } - } -} - void Dcel::reconstruct(const Smesh &M, const Smesh &S) { check_hedges(H); diff --git a/Cassiopee/XCore/XCore/intersectMesh/dcel.h b/Cassiopee/XCore/XCore/intersectMesh/dcel.h index 16f35af21..86c54f7c0 100644 --- a/Cassiopee/XCore/XCore/intersectMesh/dcel.h +++ b/Cassiopee/XCore/XCore/intersectMesh/dcel.h @@ -39,6 +39,9 @@ struct Dcel { E_Int oids[2] = {-1, -1}; E_Int id = -1; + PointLoc ploc; + E_Float d2; + Vertex(E_Float x_, E_Float y_, E_Float z_) { x = x_; @@ -54,6 +57,13 @@ struct Dcel { return cmp_points(p->x, p->y, p->z, q->x, q->y, q->z); } + struct cmp_vertex { + bool operator()(const Vertex *p, const Vertex *q) const + { + return cmp_points(p->x, p->y, p->z, q->x, q->y, q->z) < 0; + } + }; + struct Face; struct Cycle; @@ -97,69 +107,45 @@ struct Dcel { std::vector F; std::vector C; + std::set vertex_set; + E_Int inner = 0; E_Int outer = 0; E_Int degen = 0; E_Int hole = 0; - E_Int dup_x = 0; // Number of duplicate intersections - std::set vertices_crossed; // M vertices crossed by S hedges std::map> hedge_intersections; - std::map> grid; - - Dcel(const Smesh &M, E_Int color); - - Dcel(Smesh &M0, Smesh &M1); - + Dcel(const Smesh &Mf, const Smesh &Sf, const std::vector &plocs); + Dcel(const Smesh &Mf, int color); ~Dcel(); - - void init_mh_sv_intersections(const Smesh &M); - void init_vertices(const Smesh &M0, const Smesh &M1); - - void init_hedges_and_faces(const Smesh &M, E_Int color); - - static E_Int check_hedges(const std::vector &H); + // Intersection - static E_Int check_faces(const std::vector &H, - const std::vector &F); - + void init_vertices(const Smesh &Mf, const Smesh &Sf, + const std::vector &plocs); + void init_hedges_and_faces(const Smesh &Mf, int color); + void sort_leaving_hedges(std::vector &leaving, + const E_Float N[3]) const; void make_cycles(); - + void set_cycles_inout(bool intersected); void set_face_labels(std::vector &F); - - Hedge *get_hedge_of_color(Face *f, E_Int color); - std::vector make_cycle_faces(const std::vector &C); + void reconstruct(const Smesh &Mf, const Smesh &Sf); - void update_hedge_faces(const std::vector &F); - - void set_cycles_inout(const Smesh &M, E_Int color); + // Checks + static E_Int check_hedges(const std::vector &H); + static E_Int check_faces(const std::vector &H, + const std::vector &F); + // Helpers - static std::vector get_face_vertices(Face *f); - - void locate_spoints(const Smesh &M, const Smesh &S); - - void find_intersections_3D(const Smesh &M, const Smesh &S); - - void cut_hedge_at_vertex(Hedge *h, Vertex *v); - - void resolve_hedges(const Smesh &M, const Smesh &S); - - void reconstruct(const Smesh &M, const Smesh &S); - - E_Int get_next_face(const Smesh &M, E_Float px, E_Float py, E_Float pz, - const std::vector &pf, E_Float dir[3], E_Int hid); - - E_Int trace_hedge_2(Hedge *sh, const Smesh &M, const Smesh &S, E_Int hid); + Hedge *get_hedge_of_color(Face *f, int color); + void update_hedge_faces(const std::vector &F); - void cut_hedges(); + // Export - void sort_leaving_hedges(std::vector &leaving, const E_Float N[3]) const; - Smesh export_smesh(bool check_Euler=true) const; // Extract @@ -175,11 +161,11 @@ struct Dcel { E_Float scale = 1.0) const; void write_hedge(const char *fname, const Hedge *h) const; void write_point(const char *fname, const Vertex *v) const; - void write_point(const char *fname, const std::vector &I) const; + void write_point(const char *fname, const std::vector &I) const; void write_ngon(const char *fname, const std::vector &cycles) const; void write_degen_cycles(const char *fname) const; void write_inner_cycles(const char *fname) const; void write_hole_cycles(const char *fname) const; void write_outer_cycles(const char *fname) const; - void write_cycles_of_type(const char *fname, E_Int type) const; + void write_cycles_of_type(const char *fname, int type) const; }; diff --git a/Cassiopee/XCore/XCore/intersectMesh/dcel_cut.cpp b/Cassiopee/XCore/XCore/intersectMesh/dcel_cut.cpp deleted file mode 100644 index 49e6324c1..000000000 --- a/Cassiopee/XCore/XCore/intersectMesh/dcel_cut.cpp +++ /dev/null @@ -1,118 +0,0 @@ -#include "dcel.h" -#include "primitives.h" -#include "smesh.h" -#include "io.h" - -void Dcel::init_mh_sv_intersections(const Smesh &M) -{ - for (Vertex *v : V) { - - // Strictly S points - - if (v->oid[0] == -1 && v->oid[1] != -1) { - const auto &loc = v->loc; - if (loc.e_idx == -1) continue; - - // Set the reference edge for normal computation - E_Int fid = loc.fid; - const auto &pe = M.F2E[fid]; - E_Int e = pe[loc.e_idx]; - v->meid = e; - - // Add the vertex to hedge intersections - // TODO(Imad): do we need to take the correctly-oriented hedge? - Hedge *h = H[2*e]; - if (cmp_vtx(h->orig, h->twin->orig) > 0) - h = h->twin; - hedge_intersections[h].push_back(v); - } - } -} - -void Dcel::cut_hedges() -{ - size_t hid = 0; - - for (auto &hdata : hedge_intersections) { - Hedge *h = hdata.first; - auto &xs = hdata.second; - - // Distances (squared) of intersections to sh origin - - Vertex *o = h->orig; - - for (size_t i = 0; i < xs.size()-1; i++) { - assert(cmp_vtx(xs[i], xs[i+1]) != 0); - } - - for (Vertex *x : xs) { - E_Float D[3] = {x->x-o->x, x->y-o->y, x->z-o->z}; - x->d = K_MATH::dot(D, D, 3); - } - - std::sort(xs.begin(), xs.end(), [&] (const Vertex *a, const Vertex *b) - { - if (Sign(a->d - b->d) == 0) { - hedge_write("hedge", h); - point_write("a", a->x, a->y, a->z); - point_write("b", b->x, b->y, b->z); - assert(Sign(a->d - b->d) != 0); - } - return a->d < b->d; - }); - - Hedge *current_h = h; - Hedge *current_t = h->twin; - - // Cache original connectivity - Vertex *tail = current_t->orig; - //Hedge *h_next = h->next; - //Hedge *h_prev = h->prev; - - assert(current_h->color == current_t->color); - - for (Vertex *x : xs) { - // Create two new hedges with x as their origin - Hedge *e1 = new Hedge(x); - Hedge *e2 = new Hedge(x); - - // Add to hedges collection - H.push_back(e1); - H.push_back(e2); - - // Copy the color - e1->color = current_h->color; - e2->color = current_t->color; - - // Copy the face record - e1->left = current_h->left; - e2->left = current_t->left; - - // Pair-up the new half-edges - current_h->twin = e2; - e2->twin = current_h; - current_t->twin = e1; - e1->twin = current_t; - - // Set prev and next pointers at the endpoints - //e1->next = current_h->next; - //e2->next = current_t->next; - //current_h->next->prev = e1; - //current_t->next->prev = e2; - - // Set prev and next pointers at x - current_h->next = e1; - e1->prev = current_h; - current_t->next = e2; - e2->prev = current_t; - - // Keep going - current_h = e1; - } - - assert(current_h->twin->orig == tail); - - hid++; - } -} - diff --git a/Cassiopee/XCore/XCore/intersectMesh/dcel_io.cpp b/Cassiopee/XCore/XCore/intersectMesh/dcel_io.cpp index 5a42d1331..18a746492 100644 --- a/Cassiopee/XCore/XCore/intersectMesh/dcel_io.cpp +++ b/Cassiopee/XCore/XCore/intersectMesh/dcel_io.cpp @@ -101,7 +101,7 @@ void Dcel::write_point(const char *fname, fclose(fh); } -void Dcel::write_cycles_of_type(const char *fname, E_Int type) const +void Dcel::write_cycles_of_type(const char *fname, int type) const { auto indices = extract_indices_of_type(type); auto cids = extract_cycles_of_indices(indices); diff --git a/Cassiopee/XCore/XCore/intersectMesh/dcel_trace.cpp b/Cassiopee/XCore/XCore/intersectMesh/dcel_trace.cpp deleted file mode 100644 index 5a45a2385..000000000 --- a/Cassiopee/XCore/XCore/intersectMesh/dcel_trace.cpp +++ /dev/null @@ -1,227 +0,0 @@ -#include "dcel.h" -#include "smesh.h" -#include "primitives.h" -#include "io.h" - - - - - -E_Int Dcel::trace_hedge_2(Hedge *sh, const Smesh &M, const Smesh &S, E_Int hid) -{ - assert(0); - /* - Vertex *O = sh->orig; - Vertex *T = sh->twin->orig; - E_Float D[3] = {T->x-O->x, T->y-O->y, T->z-O->z}; - E_Float NORM = K_MATH::norm(D, 3); - D[0] /= NORM, D[1] /= NORM, D[2] /= NORM; - - // The origin could be inside a face, on an edge or on a vertex - // If it is inside a face, no problem - // If it is on an edge/vertex, which face is intersected first by sh? - - std::vector orig_faces, tail_faces; - E_Int last_vertex = -1, last_edge = -1; - E_Int dummy; - M.get_shared_faces(O->loc, orig_faces, last_vertex, last_edge); - M.get_shared_faces(T->loc, tail_faces, dummy, dummy); - - // If O is inside fid, we could skip this check - // We keep it for consistency - E_Int starting_face = M.deduce_face( - orig_faces, O->x, O->y, O->z, D, - last_vertex, last_edge - ); - assert(starting_face != -1); - - bool found_tail = false; - E_Int current_fid = starting_face; - E_Float current_pos[3] = {O->x, O->y, O->z}; - - E_Int walk = 0; - E_Int max_walks = 20; - - //if (hid == hid) hedge_write("sh", sh); - - while (!found_tail && walk <= max_walks) { - - //if (hid == hid) face_write("current_face", F[current_fid]); - - // We are on current_face - - // If the current_face shares the tail, stop - for (auto fid : tail_faces) { - if (fid == current_fid) { - found_tail = true; - break; - } - } - - if (found_tail) break; - - // The tail is not within current_face, nor is it on one of its - // edges, nor is it one of its vertices - // So we must: - // 1 - project the traced hedge direction on the current face - // 2 - shoot a ray {current position, projected dir} and intersect xedge - // 3 - if intersection is on an xedge endpoint, deduce the next face - // else, travel to the neighbour face of current face wrt to xedge - - // Project D onto current face - E_Float proj[3]; - M.get_unit_projected_direction(current_fid, D, proj); - - E_Int next_fid = -1; - E_Float next_pos[3] = {EFLOATMAX, EFLOATMAX, EFLOATMAX}; - - // Ray-edge intersection - const auto &pn = M.F[current_fid]; - const auto &pe = M.F2E[current_fid]; - bool hit = false; - for (size_t i = 0; i < pn.size(); i++) { - E_Int p = pn[i]; - E_Int q = pn[(i+1)%pn.size()]; - E_Int e = pe[i]; - if (p == last_vertex || q == last_vertex || e == last_edge) - continue; - - E_Float t, s; - hit = ray_edge_intersect( - current_pos[0], current_pos[1], current_pos[2], - proj[0], proj[1], proj[2], - M.X[p], M.Y[p], M.Z[p], - M.X[q], M.Y[q], M.Z[q], - t, s - ); - - if (hit) { - - //if (hid == hid) point_write("hit", current_pos[0] + t * proj[0], current_pos[1] + t * proj[1], current_pos[2] + t * proj[2]); - - // Intersection within the edge - if (s > TOL && s < 1 - TOL) { - - // Simply move to the neighbour face - const auto &pe = M.F2E[current_fid]; - E_Int eid = pe[i]; - last_edge = eid; - last_vertex = -1; - const auto &e = M.E[eid]; - if (e.p == p) assert(e.q == q); - else { - assert(e.p == q); - assert(e.q == p); - } - assert(M.E2F[eid][0] == current_fid || - M.E2F[eid][1] == current_fid); - if (M.E2F[eid][0] == current_fid) - next_fid = M.E2F[eid][1]; - else - next_fid = M.E2F[eid][0]; - // We should be within M still - assert(next_fid != -1); - - // Compute the next_pos - next_pos[0] = current_pos[0] + t * proj[0]; - next_pos[1] = current_pos[1] + t * proj[1]; - next_pos[2] = current_pos[2] + t * proj[2]; - - // Register intersection - Event *xit = Q.lookup(next_pos[0], next_pos[1], next_pos[2]); - Vertex *x = NULL; - if (xit == NULL) { - xit = Q.insert(next_pos[0], next_pos[1], next_pos[2]); - x = xit->key; - x->id = V.size(); - V.push_back(x); - x->meid = last_edge; - } else { - x = xit->key; - dup_x++; - } - - hedge_intersections[sh].push_back(x); - // TODO(Imad): H[eid] or its twin? - Hedge *mh = H[2*eid]; - if (cmp_vtx(mh->orig, mh->twin->orig) > 0) - mh = mh->twin; - hedge_intersections[mh].push_back(x); - } - - // Intersection on an endpoint - else { - bool hit_p = (s <= TOL); - bool hit_q = (s >= 1 - TOL); - - - last_edge = -1; - - if (hit_p) { - assert(hit_q == false); - - last_vertex = p; - - } else if (hit_q) { - - last_vertex = q; - } - - next_pos[0] = M.X[last_vertex]; - next_pos[1] = M.Y[last_vertex]; - next_pos[2] = M.Z[last_vertex]; - - const auto &pf = M.P2F[last_vertex]; - - next_fid = M.deduce_face(pf, - next_pos[0], next_pos[1], next_pos[2], D, - last_vertex, last_edge - ); - assert(next_fid != -1); - - // Register intersection - - Event *xit = Q.lookup(M.X[last_vertex], - M.Y[last_vertex], M.Z[last_vertex]); - assert(xit != NULL); - Vertex *x = xit->key; - - // Edges from S do not cross - assert(x->oid[1] == -1); - - assert(vertices_crossed.find(x) == vertices_crossed.end()); - vertices_crossed.insert(x); - - hedge_intersections[sh].push_back(x); - - } - - break; - } - } - - if (!hit) { - hedge_write("sh", sh); - face_write("current_face", F[current_fid]); - assert(0); - } - - assert(next_fid != current_fid); - current_fid = next_fid; - current_pos[0] = next_pos[0]; - current_pos[1] = next_pos[1]; - current_pos[2] = next_pos[2]; - walk++; - } - - if (walk > max_walks) { - fprintf(stderr, "Warning : Could not reach the tail of edge %d after %d max walks!", hid, max_walks); - assert(0); - return 1; - } - - assert(found_tail); - */ - - return 0; -} diff --git a/Cassiopee/XCore/XCore/intersectMesh/icapsule.cpp b/Cassiopee/XCore/XCore/intersectMesh/icapsule.cpp index 04ac88e90..64b7c99e5 100644 --- a/Cassiopee/XCore/XCore/intersectMesh/icapsule.cpp +++ b/Cassiopee/XCore/XCore/intersectMesh/icapsule.cpp @@ -28,11 +28,6 @@ ICapsule::ICapsule(const Karray &marray, const std::vector &sarrays, Ss.reserve(sarrays.size()); spatches.reserve(sarrays.size()); - std::vector> plocs_list; - plocs_list.reserve(sarrays.size()); - std::vector> bfaces_list; - bfaces_list.reserve(sarrays.size()); - for (size_t i = 0; i < sarrays.size(); i++) { printf("S%lu\n", i); @@ -41,7 +36,7 @@ ICapsule::ICapsule(const Karray &marray, const std::vector &sarrays, IMesh S(sarrays[i]); S.set_tolerances(NEAR_VERTEX_TOL, NEAR_EDGE_TOL); S.make_skin(); - S.orient_skin(OUT); + S.orient_skin(IN); S.triangulate_skin(); Ss.push_back(S); @@ -54,52 +49,37 @@ ICapsule::ICapsule(const Karray &marray, const std::vector &sarrays, // Locate Sf points on Mf faces auto plocs = Mf.locate(Sf); - //Mf.correct_near_points_and_edges(Sf, plocs); - - // Correct AABB and Sf faces hash - Sf.make_bbox(); - Sf.hash_faces(); // Extract the initial Mf faces that bound Sf auto bfaces = Mf.extract_bounding_faces(Sf, plocs); - //Mf.write_ngon("bounding_before", bfaces); - - //Sf.write_ngon("Sf"); // Refinement loop refine(Mf, bfaces, Sf, plocs); - //Sf.write_ngon("refined_Sf.im"); - //Mf.write_ngon("refined_Mf.im"); assert(Sf.check_Euler); assert(Sf.np - Sf.ne + Sf.nf + 1 == 2); bfaces = Mf.extract_bounding_faces(Sf, plocs); - Mf.write_ngon("bounding_after.im", bfaces); // Make a patch out of Mf bounding faces Smesh Bf(Mf, bfaces, false); Bf.make_fcenters(); Bf.make_fnormals(); Bf.make_pnormals(); - - // Make two DCELs out of Bf and Sf - Dcel Db(Bf, Dcel::RED); - Db.write_inner_cycles("Db.im"); + Bf.make_bbox(); + Bf.hash_faces(); + // Update plocs to local ids of Bf + plocs = Bf.locate(Sf); - Dcel Ds(Sf, Dcel::BLACK); - Ds.write_inner_cycles("Ds_inner.im"); - Ds.write_outer_cycles("Ds_outer.im"); - Ds.write_hole_cycles("Ds_hole.im"); - Ds.write_degen_cycles("Ds_degen.im"); + // Intersect + Bf.write_ngon("Bf.im"); + Sf.write_ngon("Sf.im"); + Dcel D(Bf, Sf, plocs); // Add Sf spatches.push_back(Sf); - // Add plocs - plocs_list.push_back(plocs); - puts(""); } diff --git a/Cassiopee/XCore/XCore/intersectMesh/icapsule_refine.cpp b/Cassiopee/XCore/XCore/intersectMesh/icapsule_refine.cpp index 43e33693a..5338384c1 100644 --- a/Cassiopee/XCore/XCore/intersectMesh/icapsule_refine.cpp +++ b/Cassiopee/XCore/XCore/intersectMesh/icapsule_refine.cpp @@ -158,8 +158,7 @@ void ICapsule::refine(Smesh &Mf, std::set &mfids, Smesh &Sf, std::vector fat_sfids; std::vector fat_mfids; - - puts("Making BVHs"); + Sf.make_BVH(); Mf.make_BVH(mfids); @@ -176,7 +175,6 @@ void ICapsule::refine(Smesh &Mf, std::set &mfids, Smesh &Sf, // Project mpids on Sf std::vector plocs_m(mpids.size()); - puts("Projecting"); Sf.project(Mf, mpids, plocs_m); // Deduce sfids to refine @@ -187,11 +185,8 @@ void ICapsule::refine(Smesh &Mf, std::set &mfids, Smesh &Sf, // Refine ref_S = sref_faces.size(); if (ref_S > 0) { - puts("Refining"); Sf.refine(sref_faces); - puts("Conformizing"); Sf.conformize(); - puts("Making pnormals"); Sf.make_pnormals(); } @@ -205,39 +200,34 @@ void ICapsule::refine(Smesh &Mf, std::set &mfids, Smesh &Sf, // Reproject spids on mfaces plocs_s.resize(Sf.np); - puts("Projecting"); Mf.project(Sf, spids, plocs_s); - puts("Replacing"); Sf.replace_by_projections(spids, plocs_s); // Deduce mfids to refine std::vector mref_faces; - puts("Deducing fat faces"); Mf.deduce_ref_faces(spids, plocs_s, Sf, mref_faces); printf("Fat mfids: %lu\n", mref_faces.size()); ref_M = mref_faces.size(); if (ref_M > 0) { - puts("Refining"); Mf.refine(mref_faces); - puts("Conformizing"); Mf.conformize(); - puts("Making pnormals"); Mf.make_pnormals(); // update mfids - puts("Updating mfids"); for (E_Int fparent : mref_faces) { const auto &children = Mf.fchildren[fparent].back(); for (E_Int child : children) mfids.insert(child); } } - puts("Destroying BVHs"); Mf.destroy_BVH(Mf.bvh_root); Sf.destroy_BVH(Sf.bvh_root); } while (ref_M > 0 || ref_S > 0); + Mf.make_bbox(); Mf.hash_faces(); + + Sf.make_bbox(); Sf.hash_faces(); //point_write("projections", projections); diff --git a/Cassiopee/XCore/XCore/intersectMesh/primitives.cpp b/Cassiopee/XCore/XCore/intersectMesh/primitives.cpp index acb4c846f..00b766921 100644 --- a/Cassiopee/XCore/XCore/intersectMesh/primitives.cpp +++ b/Cassiopee/XCore/XCore/intersectMesh/primitives.cpp @@ -32,6 +32,14 @@ E_Int Sign(E_Float x, E_Float tol) E_Int cmp_points(E_Float x1, E_Float y1, E_Float z1, E_Float x2, E_Float y2, E_Float z2) { + if (x1 < x2) return -1; + if (x1 > x2) return 1; + if (y1 < y2) return -1; + if (y1 > y2) return 1; + if (z1 < z2) return -1; + if (z1 > z2) return 1; + return 0; + /* E_Float t = x1 - x2; E_Int s = Sign(t); if (s) return s; @@ -42,6 +50,7 @@ E_Int cmp_points(E_Float x1, E_Float y1, E_Float z1, t = z1 - z2; return Sign(t); + */ } bool ray_edge_intersect(E_Float ox, E_Float oy, E_Float oz, diff --git a/Cassiopee/XCore/XCore/intersectMesh/smesh.h b/Cassiopee/XCore/XCore/intersectMesh/smesh.h index 5f0a13cc3..687e2cacd 100644 --- a/Cassiopee/XCore/XCore/intersectMesh/smesh.h +++ b/Cassiopee/XCore/XCore/intersectMesh/smesh.h @@ -87,7 +87,6 @@ struct Smesh { const std::vector &skin, bool check_Euler=true); static Smesh Smesh_from_mesh_patch(const IMesh &M, bool check_Euler=true); - //Smesh(const IMesh &M, const std::vector &faces); void make_edges(); void clear(); diff --git a/Cassiopee/XCore/srcs.py b/Cassiopee/XCore/srcs.py index 16aa1c1a2..05782f6d2 100644 --- a/Cassiopee/XCore/srcs.py +++ b/Cassiopee/XCore/srcs.py @@ -37,8 +37,6 @@ 'XCore/intersectMesh/dcel.cpp', 'XCore/intersectMesh/dcel_extract.cpp', 'XCore/intersectMesh/dcel_io.cpp', - #'XCore/intersectMesh/dcel_trace.cpp', - #'XCore/intersectMesh/dcel_cut.cpp', 'XCore/intersectMesh/AABB.cpp', From 4a297b73b8974459447d28602b7afa2333c57f87 Mon Sep 17 00:00:00 2001 From: imadhammani Date: Mon, 21 Oct 2024 22:37:51 +0200 Subject: [PATCH 67/86] XCore intersectMesh: fixed problem with collinear edges --- Cassiopee/XCore/XCore/intersectMesh/dcel.cpp | 146 ++++++++++++------ .../XCore/XCore/intersectMesh/icapsule.cpp | 43 ++++++ 2 files changed, 139 insertions(+), 50 deletions(-) diff --git a/Cassiopee/XCore/XCore/intersectMesh/dcel.cpp b/Cassiopee/XCore/XCore/intersectMesh/dcel.cpp index 0a809c068..b4667dcc6 100644 --- a/Cassiopee/XCore/XCore/intersectMesh/dcel.cpp +++ b/Cassiopee/XCore/XCore/intersectMesh/dcel.cpp @@ -65,35 +65,6 @@ void Dcel::init_vertices(const Smesh &Mf, const Smesh &Sf, printf("Duplicate vertices: %d\n", duplicate_vertices); } -Dcel::Dcel(const Smesh &Mf, int color) -{ - const auto &X = Mf.X; - const auto &Y = Mf.Y; - const auto &Z = Mf.Z; - - V.reserve(Mf.np); - for (E_Int pid = 0; pid < Mf.np; pid++) { - Vertex *v = new Vertex(X[pid], Y[pid], Z[pid]); - v->oids[color] = pid; - V.push_back(v); - } - - init_hedges_and_faces(Mf, color); - - if (check_hedges(H) != 0) { - fprintf(stderr, "Dcel: Inconsistent half-edge records!\n"); - abort(); - } - - if (check_faces(H, F) != 0) { - fprintf(stderr, "Dcel: Inconsistent face records!\n"); - abort(); - } - - make_cycles(); - set_cycles_inout(false); -} - Dcel::Dcel(const Smesh &Mf, const Smesh &Sf, const std::vector &plocs) { init_vertices(Mf, Sf, plocs); @@ -111,8 +82,8 @@ Dcel::Dcel(const Smesh &Mf, const Smesh &Sf, const std::vector &plocs) abort(); } - make_cycles(); - set_cycles_inout(false); + //make_cycles(); + //set_cycles_inout(false); std::vector xpoints; @@ -143,7 +114,6 @@ Dcel::Dcel(const Smesh &Mf, const Smesh &Sf, const std::vector &plocs) } } printf("Sf points on Mf edges: %d\n", v_on_e); - point_write("xpoints.im", xpoints); // Trace for (E_Int eid_s = 0; eid_s < Sf.ne; eid_s++) { @@ -252,7 +222,6 @@ Dcel::Dcel(const Smesh &Mf, const Smesh &Sf, const std::vector &plocs) x->id = V.size(); V.push_back(x); vertex_set.insert(x); - xpoints.push_back({x->x,x->y,x->z}); // Register the intersection Hedge *hm = H[2*eid_m]; @@ -289,6 +258,8 @@ Dcel::Dcel(const Smesh &Mf, const Smesh &Sf, const std::vector &plocs) // Register the intersection hedge_intersections[hs].push_back(x); + + xpoints.push_back({x->x, x->y, x->z}); } break; } @@ -307,12 +278,19 @@ Dcel::Dcel(const Smesh &Mf, const Smesh &Sf, const std::vector &plocs) assert(walk <= max_walks); } + point_write("xpoints.im", xpoints); + // Cut for (auto &h2x : hedge_intersections) { Hedge *h = h2x.first; + auto it = hedge_intersections.find(h->twin); + assert(it == hedge_intersections.end()); + auto &xs = h2x.second; Vertex *o = h->orig; + Vertex *tail = h->twin->orig; + assert(cmp_vtx(o, tail) < 0); // TODO(Imad): check that the intersections are 'sufficiently' spaced out for (Vertex *x : xs) { @@ -370,6 +348,8 @@ Dcel::Dcel(const Smesh &Mf, const Smesh &Sf, const std::vector &plocs) for (size_t vid = 0; vid < V.size(); vid++) { Vertex *v = V[vid]; + //printf("vid = %d - vertex id %d\n", vid, v->id); + assert(v->id == vid); E_Float N[3] = {0, 0, 0}; @@ -393,8 +373,6 @@ Dcel::Dcel(const Smesh &Mf, const Smesh &Sf, const std::vector &plocs) auto &leaving = list[vid]; - for (Hedge *h : leaving) assert(h->orig == v); - /* bool do_sort = false; for (size_t i = 1; i < leaving.size(); i++) { @@ -408,6 +386,13 @@ Dcel::Dcel(const Smesh &Mf, const Smesh &Sf, const std::vector &plocs) sort_leaving_hedges(leaving, N); + /* + for (Hedge *h : leaving) { + printf("%d ", h->twin->orig->id); + puts(""); + } + */ + for (size_t i = 0; i < leaving.size(); i++) { Hedge *h = leaving[i]; Hedge *w = leaving[(i+1)%leaving.size()]; @@ -425,10 +410,27 @@ Dcel::Dcel(const Smesh &Mf, const Smesh &Sf, const std::vector &plocs) make_cycles(); set_cycles_inout(true); - auto new_F = make_cycle_faces(C); - printf("Non-hole faces: %lu\n", new_F.size()); + /* + for (Cycle *c : C) { + if (c->inout == Cycle::INNER) puts("inner"); + else if (c->inout == Cycle::HOLE) puts("hole"); + else if (c->inout == Cycle::DEGEN) puts("degen"); + Hedge *h = c->rep; + Vertex *v = h->orig; + printf("%d ", v->id); + Hedge *w = h->next; + while (w != h) { + v = w->orig; + printf("%d ", v->id); + w = w->next; + } + puts(""); + } + */ - set_face_labels(new_F); + //auto new_F = make_cycle_faces(C); + + //set_face_labels(new_F); /* update_hedge_faces(new_F); @@ -440,7 +442,7 @@ Dcel::Dcel(const Smesh &Mf, const Smesh &Sf, const std::vector &plocs) */ - puts("ok"); + //puts("ok"); } void Dcel::set_face_labels(std::vector &new_F) @@ -696,9 +698,14 @@ void Dcel::sort_leaving_hedges(std::vector &leaving, assert(O_w == O_h); assert(T_w == T_h); - if (cmp_vtx(O_w, T_w) < 0) return true; - - return false; + // If this is the origin: red comes first + if (cmp_vtx(O_w, T_w) < 0) { + if (h->color == RED) return true; + return false; + } else { + if (h->color == RED) return false; + return true; + } }); std::vector tmp(leaving); @@ -766,15 +773,27 @@ void Dcel::make_cycles() void Dcel::set_cycles_inout(bool intersected) { inner = 0; - outer = 0; degen = 0; hole = 0; for (Cycle *cycle : C) { - Hedge *h = cycle->rep; - bool is_hole = (intersected && h->left == NULL && h->color == RED) || - (!intersected && h->left == NULL); + // Hole cycle is a cycle where all hedges have a null left face + bool is_hole = true; + + Hedge *h = cycle->rep; + if (!h->left) { + Hedge *w = h->next; + while (w != h) { + if (w->left) { + is_hole = false; + break; + } + w = w->next; + } + } else { + is_hole = false; + } if (is_hole) { cycle->inout = Cycle::HOLE; @@ -826,10 +845,6 @@ void Dcel::set_cycles_inout(bool intersected) printf("Inner cycles: " SF_D_ "\n", inner); printf("Degen cycles: " SF_D_ "\n", degen); printf("Hole cycles: " SF_D_ "\n", hole); - - write_degen_cycles("degen.im"); - write_inner_cycles("inner.im"); - write_hole_cycles("hole.im"); } Dcel::~Dcel() @@ -879,3 +894,34 @@ void Dcel::reconstruct(const Smesh &M, const Smesh &S) write_outer_faces("outer"); } */ + +Dcel::Dcel(const Smesh &Mf, int color) +{ + const auto &X = Mf.X; + const auto &Y = Mf.Y; + const auto &Z = Mf.Z; + + V.reserve(Mf.np); + for (E_Int pid = 0; pid < Mf.np; pid++) { + Vertex *v = new Vertex(X[pid], Y[pid], Z[pid]); + v->oids[color] = pid; + V.push_back(v); + } + + init_hedges_and_faces(Mf, color); + + if (check_hedges(H) != 0) { + fprintf(stderr, "Dcel: Inconsistent half-edge records!\n"); + abort(); + } + + if (check_faces(H, F) != 0) { + fprintf(stderr, "Dcel: Inconsistent face records!\n"); + abort(); + } + + make_cycles(); + set_cycles_inout(false); +} + + diff --git a/Cassiopee/XCore/XCore/intersectMesh/icapsule.cpp b/Cassiopee/XCore/XCore/intersectMesh/icapsule.cpp index 64b7c99e5..f1f1d5193 100644 --- a/Cassiopee/XCore/XCore/intersectMesh/icapsule.cpp +++ b/Cassiopee/XCore/XCore/intersectMesh/icapsule.cpp @@ -10,6 +10,46 @@ ICapsule::ICapsule(const Karray &marray, const std::vector &sarrays, const std::vector &ptags) { + /* + { + Smesh Mf; + Mf.np = 3, Mf.nf = 1; + Mf.check_Euler = true; + Mf.X.push_back(0); Mf.Y.push_back(0); Mf.Z.push_back(0); + Mf.X.push_back(2); Mf.Y.push_back(0); Mf.Z.push_back(0); + Mf.X.push_back(2); Mf.Y.push_back(2); Mf.Z.push_back(0); + Mf.F.push_back({0, 1, 2}); + Mf.Fc = Mf.F; + Mf.conformize(); + Mf.make_fcenters(); + Mf.make_fnormals(); + Mf.make_pnormals(); + Mf.make_bbox(); + Mf.hash_faces(); + + + Smesh Sf; + Sf.np = 3, Sf.nf = 1; + Sf.check_Euler = true; + Sf.X.push_back(0); Sf.Y.push_back(0); Sf.Z.push_back(0); + Sf.X.push_back(1); Sf.Y.push_back(0); Sf.Z.push_back(0); + Sf.X.push_back(1); Sf.Y.push_back(1); Sf.Z.push_back(0); + Sf.F.push_back({0, 1, 2}); + Sf.Fc = Sf.F; + Sf.conformize(); + Sf.make_fcenters(); + Sf.make_fnormals(); + Sf.make_pnormals(); + auto plocs = Mf.locate(Sf); + + Dcel D(Mf, Sf, plocs); + D.write_hole_cycles("hole.im"); + D.write_inner_cycles("inner.im"); + D.write_degen_cycles("degen.im"); + exit(0); + } + */ + M = IMesh(marray); M.set_tolerances(NEAR_VERTEX_TOL, NEAR_EDGE_TOL); M.make_skin(); @@ -76,6 +116,9 @@ ICapsule::ICapsule(const Karray &marray, const std::vector &sarrays, Bf.write_ngon("Bf.im"); Sf.write_ngon("Sf.im"); Dcel D(Bf, Sf, plocs); + D.write_hole_cycles("hole.im"); + D.write_degen_cycles("degen.im"); + D.write_inner_cycles("inner.im"); // Add Sf spatches.push_back(Sf); From 844eb18b405b3596dd9fa5b1747e38a8584ba862 Mon Sep 17 00:00:00 2001 From: imadhammani Date: Thu, 24 Oct 2024 19:10:50 +0200 Subject: [PATCH 68/86] XCore intersectMesh: one -> eno ok until check_faces after set_face_labels --- Cassiopee/XCore/XCore/intersectMesh/dcel.cpp | 181 +++++++------- Cassiopee/XCore/XCore/intersectMesh/dcel.h | 4 +- .../XCore/XCore/intersectMesh/icapsule.cpp | 107 +++------ .../XCore/XCore/intersectMesh/icapsule.h | 15 +- .../XCore/intersectMesh/icapsule_refine.cpp | 124 ++++++---- .../XCore/XCore/intersectMesh/primitives.h | 2 +- Cassiopee/XCore/XCore/intersectMesh/smesh.cpp | 33 +-- Cassiopee/XCore/XCore/intersectMesh/smesh.h | 10 +- .../XCore/intersectMesh/smesh_extract.cpp | 11 +- .../XCore/XCore/intersectMesh/smesh_geom.cpp | 64 ++++- .../XCore/intersectMesh/smesh_locate.cpp | 227 +++++++++--------- .../XCore/intersectMesh/smesh_refine.cpp | 6 +- 12 files changed, 407 insertions(+), 377 deletions(-) diff --git a/Cassiopee/XCore/XCore/intersectMesh/dcel.cpp b/Cassiopee/XCore/XCore/intersectMesh/dcel.cpp index b4667dcc6..f76b900d8 100644 --- a/Cassiopee/XCore/XCore/intersectMesh/dcel.cpp +++ b/Cassiopee/XCore/XCore/intersectMesh/dcel.cpp @@ -76,17 +76,20 @@ Dcel::Dcel(const Smesh &Mf, const Smesh &Sf, const std::vector &plocs) fprintf(stderr, "Dcel: Inconsistent half-edge records!\n"); abort(); } + + make_cycles(); + set_cycles_inout(); if (check_faces(H, F) != 0) { fprintf(stderr, "Dcel: Inconsistent face records!\n"); abort(); } - //make_cycles(); - //set_cycles_inout(false); std::vector xpoints; + std::vector dpoints; + // Register the intersections between Sf points and Mf edges E_Int v_on_e = 0; for (Vertex *v : V) { @@ -108,12 +111,13 @@ Dcel::Dcel(const Smesh &Mf, const Smesh &Sf, const std::vector &plocs) if (cmp_vtx(O, T) > 0) h = h->twin; hedge_intersections[h].push_back(v); - xpoints.push_back({v->x,v->y,v->z}); + dpoints.push_back({v->x,v->y,v->z}); v_on_e++; } } printf("Sf points on Mf edges: %d\n", v_on_e); + //point_write("dpoints.im", dpoints); // Trace for (E_Int eid_s = 0; eid_s < Sf.ne; eid_s++) { @@ -141,8 +145,15 @@ Dcel::Dcel(const Smesh &Mf, const Smesh &Sf, const std::vector &plocs) Mf.get_shared_faces(plocs[p], orig_faces, last_vertex, last_edge); Mf.get_shared_faces(plocs[q], tail_faces, dummy, dummy); + //if (eid_s == 133) { + // point_write("O.im", O->x, O->y, O->z); + // point_write("T.im", T->x, T->y, T->z); + // Mf.write_ngon("ofaces.im", orig_faces); + // Mf.write_ngon("tfaces.im", tail_faces); + //} + E_Int starting_face = Mf.deduce_face(orig_faces, spx, spy, spz, - D, last_vertex, last_edge); + D, last_vertex, last_edge, eid_s); assert(starting_face != -1); bool found_tail = false; @@ -246,7 +257,7 @@ Dcel::Dcel(const Smesh &Mf, const Smesh &Sf, const std::vector &plocs) const auto &pf = Mf.P2F[last_vertex]; next_fid = Mf.deduce_face(pf, next_pos[0], next_pos[1], next_pos[2], - D, last_vertex, last_edge + D, last_vertex, last_edge, eid_s ); assert(next_fid != -1); @@ -332,11 +343,6 @@ Dcel::Dcel(const Smesh &Mf, const Smesh &Sf, const std::vector &plocs) current_h = e1; } - - //t_next->prev = h->twin; - //h->twin->next = t_next; - //h_next->prev = current_h; - //current_h->next = h_next; } // Resolve @@ -348,8 +354,6 @@ Dcel::Dcel(const Smesh &Mf, const Smesh &Sf, const std::vector &plocs) for (size_t vid = 0; vid < V.size(); vid++) { Vertex *v = V[vid]; - //printf("vid = %d - vertex id %d\n", vid, v->id); - assert(v->id == vid); E_Float N[3] = {0, 0, 0}; @@ -373,26 +377,8 @@ Dcel::Dcel(const Smesh &Mf, const Smesh &Sf, const std::vector &plocs) auto &leaving = list[vid]; - /* - bool do_sort = false; - for (size_t i = 1; i < leaving.size(); i++) { - if (leaving[i]->color != leaving[0]->color) { - do_sort = true; - break; - } - } - if (!do_sort) continue; - */ - sort_leaving_hedges(leaving, N); - /* - for (Hedge *h : leaving) { - printf("%d ", h->twin->orig->id); - puts(""); - } - */ - for (size_t i = 0; i < leaving.size(); i++) { Hedge *h = leaving[i]; Hedge *w = leaving[(i+1)%leaving.size()]; @@ -408,43 +394,84 @@ Dcel::Dcel(const Smesh &Mf, const Smesh &Sf, const std::vector &plocs) } make_cycles(); - set_cycles_inout(true); + set_cycles_inout(); + + write_hole_cycles("hole.im"); + write_degen_cycles("degen.im"); + write_inner_cycles("inner.im"); + + auto new_F = make_cycle_faces(C); + set_face_labels(new_F); + update_hedge_faces(new_F); + check_faces(H, new_F); + + for (Face *f : F) delete f; + F = new_F; + + puts("ok"); +} + +void Dcel::update_hedge_faces(std::vector &new_F) +{ + for (Hedge *h : H) h->left = NULL; + + for (Face *f : new_F) { + assert(f); + + Hedge *h = f->rep; + assert(h); + Cycle *c = h->cycle; + assert(c->inout == Cycle::INNER); + + h->left = f; + assert(f->rep->left == f); - /* - for (Cycle *c : C) { - if (c->inout == Cycle::INNER) puts("inner"); - else if (c->inout == Cycle::HOLE) puts("hole"); - else if (c->inout == Cycle::DEGEN) puts("degen"); - Hedge *h = c->rep; - Vertex *v = h->orig; - printf("%d ", v->id); Hedge *w = h->next; while (w != h) { - v = w->orig; - printf("%d ", v->id); + assert(w->left == NULL); + w->left = f; w = w->next; } - puts(""); } - */ - //auto new_F = make_cycle_faces(C); - - //set_face_labels(new_F); + for (Face *f : new_F) { + assert(f->rep->left == f); + } - /* - update_hedge_faces(new_F); + for (Hedge *h : H) { + Face *f = h->left; + Hedge *w = h->next; + while (w != h) { + assert(w->left == f); + w = w->next; + } + } +} - for (Face *f : F) delete f; - F = new_F; +E_Int Dcel::check_faces(const std::vector &H, + const std::vector &F) +{ + for (size_t i = 0; i < H.size(); i++) { + Hedge *h = H[i]; + if (h->prev->left != h->left) { assert(0); return 1; } + if (h->next->left != h->left) { assert(0); return 1; } + } - check_faces(H, F); - */ + for (size_t i = 0; i < F.size(); i++) { + Face *f = F[i]; + //Hedge *h = f->rep; + //Cycle *c = h->cycle; + //assert(c->inout == Cycle::DEGEN || c->inout == Cycle::INNER); + if (f->rep->left != f) { assert(0); return 1; } + } + puts("CHECK: FACES OK."); - //puts("ok"); + return 0; } + + void Dcel::set_face_labels(std::vector &new_F) { // Label each face with the ids of the original faces containing it @@ -455,6 +482,9 @@ void Dcel::set_face_labels(std::vector &new_F) // Get the first RED and BLACK half-edges in the face cycle Hedge *h = f->rep; + Cycle *c = h->cycle; + assert(c->inout == Cycle::INNER); + Hedge *R = NULL; Hedge *B = NULL; E_Int RB = 0; @@ -481,6 +511,10 @@ void Dcel::set_face_labels(std::vector &new_F) f->oids[Dcel::BLACK] = (B->left) ? B->left->oids[Dcel::BLACK] : -1; } else { // Only single color possible is RED + if (!R && B) { + write_hedge("black.im", B); + point_write("orig.im", B->orig->x, B->orig->y, B->orig->z); + } assert(R && !B); //Hedge *REP = (R != NULL) ? R : B; //if (REP != R) { @@ -508,7 +542,8 @@ std::vector Dcel::make_cycle_faces(const std::vector &C) std::vector new_F; for (Cycle *c : C) { - if (c->inout == Cycle::HOLE) continue; + //if (c->inout == Cycle::HOLE) continue; + if (c->inout != Cycle::INNER) continue; // Create a face record Face *f = new Face; @@ -728,25 +763,6 @@ E_Int Dcel::check_hedges(const std::vector &H) return 0; } -E_Int Dcel::check_faces(const std::vector &H, - const std::vector &F) -{ - for (size_t i = 0; i < H.size(); i++) { - Hedge *h = H[i]; - if (h->prev->left != h->left) { assert(0); return 1; } - if (h->next->left != h->left) { assert(0); return 1; } - } - - for (size_t i = 0; i < F.size(); i++) { - Face *f = F[i]; - if (f->rep->left != f) { assert(0); return 1; } - } - - puts("CHECK: FACES OK."); - - return 0; -} - void Dcel::make_cycles() { C.clear(); @@ -770,7 +786,7 @@ void Dcel::make_cycles() } } -void Dcel::set_cycles_inout(bool intersected) +void Dcel::set_cycles_inout() { inner = 0; degen = 0; @@ -855,21 +871,7 @@ Dcel::~Dcel() for (Cycle *c : C) delete c; } - /* -void Dcel::update_hedge_faces(const std::vector &F) -{ - for (Face *f : F) { - Hedge *h = f->rep; - h->left = f; - Hedge *w = h->next; - while (w != h) { - w->left = f; - w = w->next; - } - } -} - void Dcel::reconstruct(const Smesh &M, const Smesh &S) { check_hedges(H); @@ -905,6 +907,7 @@ Dcel::Dcel(const Smesh &Mf, int color) for (E_Int pid = 0; pid < Mf.np; pid++) { Vertex *v = new Vertex(X[pid], Y[pid], Z[pid]); v->oids[color] = pid; + vertex_set.insert(v); V.push_back(v); } @@ -921,7 +924,7 @@ Dcel::Dcel(const Smesh &Mf, int color) } make_cycles(); - set_cycles_inout(false); + set_cycles_inout(); } diff --git a/Cassiopee/XCore/XCore/intersectMesh/dcel.h b/Cassiopee/XCore/XCore/intersectMesh/dcel.h index 86c54f7c0..d73325e13 100644 --- a/Cassiopee/XCore/XCore/intersectMesh/dcel.h +++ b/Cassiopee/XCore/XCore/intersectMesh/dcel.h @@ -128,7 +128,7 @@ struct Dcel { void sort_leaving_hedges(std::vector &leaving, const E_Float N[3]) const; void make_cycles(); - void set_cycles_inout(bool intersected); + void set_cycles_inout(); void set_face_labels(std::vector &F); std::vector make_cycle_faces(const std::vector &C); void reconstruct(const Smesh &Mf, const Smesh &Sf); @@ -142,7 +142,7 @@ struct Dcel { // Helpers Hedge *get_hedge_of_color(Face *f, int color); - void update_hedge_faces(const std::vector &F); + void update_hedge_faces(std::vector &F); // Export diff --git a/Cassiopee/XCore/XCore/intersectMesh/icapsule.cpp b/Cassiopee/XCore/XCore/intersectMesh/icapsule.cpp index f1f1d5193..b22bc26fd 100644 --- a/Cassiopee/XCore/XCore/intersectMesh/icapsule.cpp +++ b/Cassiopee/XCore/XCore/intersectMesh/icapsule.cpp @@ -7,57 +7,18 @@ #include "primitives.h" #include "dcel.h" -ICapsule::ICapsule(const Karray &marray, const std::vector &sarrays, - const std::vector &ptags) +ICapsule ICapsule::do_it(const Karray &marray, + const std::vector &sarrays, const std::vector &ptags) { - /* - { - Smesh Mf; - Mf.np = 3, Mf.nf = 1; - Mf.check_Euler = true; - Mf.X.push_back(0); Mf.Y.push_back(0); Mf.Z.push_back(0); - Mf.X.push_back(2); Mf.Y.push_back(0); Mf.Z.push_back(0); - Mf.X.push_back(2); Mf.Y.push_back(2); Mf.Z.push_back(0); - Mf.F.push_back({0, 1, 2}); - Mf.Fc = Mf.F; - Mf.conformize(); - Mf.make_fcenters(); - Mf.make_fnormals(); - Mf.make_pnormals(); - Mf.make_bbox(); - Mf.hash_faces(); - - - Smesh Sf; - Sf.np = 3, Sf.nf = 1; - Sf.check_Euler = true; - Sf.X.push_back(0); Sf.Y.push_back(0); Sf.Z.push_back(0); - Sf.X.push_back(1); Sf.Y.push_back(0); Sf.Z.push_back(0); - Sf.X.push_back(1); Sf.Y.push_back(1); Sf.Z.push_back(0); - Sf.F.push_back({0, 1, 2}); - Sf.Fc = Sf.F; - Sf.conformize(); - Sf.make_fcenters(); - Sf.make_fnormals(); - Sf.make_pnormals(); - auto plocs = Mf.locate(Sf); - - Dcel D(Mf, Sf, plocs); - D.write_hole_cycles("hole.im"); - D.write_inner_cycles("inner.im"); - D.write_degen_cycles("degen.im"); - exit(0); - } - */ - - M = IMesh(marray); + E_Float NEAR_VERTEX_TOL = 1e-3; + E_Float NEAR_EDGE_TOL = 1e-3; + auto M = IMesh(marray); M.set_tolerances(NEAR_VERTEX_TOL, NEAR_EDGE_TOL); M.make_skin(); M.orient_skin(OUT); M.triangulate_skin(); M.make_bbox(); M.hash_skin(); - //M.make_skin_graph(); Smesh Mf(M, M.skin, false); Mf.make_bbox(); Mf.hash_faces(); @@ -65,8 +26,7 @@ ICapsule::ICapsule(const Karray &marray, const std::vector &sarrays, Mf.make_fnormals(); Mf.make_pnormals(); - Ss.reserve(sarrays.size()); - spatches.reserve(sarrays.size()); + Mf.write_ngon("Mf_raw.im"); for (size_t i = 0; i < sarrays.size(); i++) { @@ -78,28 +38,36 @@ ICapsule::ICapsule(const Karray &marray, const std::vector &sarrays, S.make_skin(); S.orient_skin(IN); S.triangulate_skin(); - Ss.push_back(S); // Create SMesh Sf Smesh Sf = Smesh::Smesh_from_point_tags(S, ptags[i]); Sf.make_fcenters(); Sf.make_fnormals(); Sf.make_pnormals(); + Sf.make_bbox(); + Sf.hash_faces(); Sf.compute_min_distance_between_points(); + printf("Min dist: %f\n", Sf.min_pdist); + + Sf.write_ngon("Sf_raw.im"); // Locate Sf points on Mf faces auto plocs = Mf.locate(Sf); - - // Extract the initial Mf faces that bound Sf - auto bfaces = Mf.extract_bounding_faces(Sf, plocs); + std::vector spids(Sf.np); + for (int i = 0; i < Sf.np; i++) spids[i] = i; + Sf.replace_by_projections(spids, plocs); + + // Extract the initial Mf faces that cover Sf + auto bfaces = Mf.extract_covering_faces(Sf, plocs); + { + Smesh If(Mf, bfaces, false); + If.write_ngon("If.im"); + } // Refinement loop - refine(Mf, bfaces, Sf, plocs); - - assert(Sf.check_Euler); - assert(Sf.np - Sf.ne + Sf.nf + 1 == 2); + plocs = refine(Mf, bfaces, Sf); - bfaces = Mf.extract_bounding_faces(Sf, plocs); + bfaces = Mf.extract_covering_faces(Sf, plocs); // Make a patch out of Mf bounding faces Smesh Bf(Mf, bfaces, false); @@ -109,31 +77,32 @@ ICapsule::ICapsule(const Karray &marray, const std::vector &sarrays, Bf.make_bbox(); Bf.hash_faces(); - // Update plocs to local ids of Bf plocs = Bf.locate(Sf); - // Intersect Bf.write_ngon("Bf.im"); Sf.write_ngon("Sf.im"); - Dcel D(Bf, Sf, plocs); - D.write_hole_cycles("hole.im"); - D.write_degen_cycles("degen.im"); - D.write_inner_cycles("inner.im"); - // Add Sf - spatches.push_back(Sf); + { + Dcel Db(Bf, Dcel::RED); + Dcel Ds(Sf, Dcel::BLACK); + } + + // Intersect + Dcel D(Bf, Sf, plocs); puts(""); } Mf.write_ngon("refined_Mf.im"); - + return ICapsule(); } PyObject *K_XCORE::icapsule_extract_master(PyObject *self, PyObject *args) { + return Py_None; + /* PyObject *ICAPSULE; if (!PYPARSETUPLE_(args, O_, &ICAPSULE)) { RAISE("Bad input."); @@ -150,10 +119,13 @@ PyObject *K_XCORE::icapsule_extract_master(PyObject *self, PyObject *args) auto Mout = icap->M.export_karray(); return Mout; + */ } PyObject *K_XCORE::icapsule_extract_slave(PyObject *self, PyObject *args) { + return Py_None; + /* PyObject *ICAPSULE; E_Int INDEX; if (!PYPARSETUPLE_(args, O_ I_, &ICAPSULE, &INDEX)) { @@ -176,6 +148,7 @@ PyObject *K_XCORE::icapsule_extract_slave(PyObject *self, PyObject *args) auto Sout = icap->Ss[INDEX].export_karray(); return Sout; + */ } PyObject *K_XCORE::icapsule_init(PyObject *self, PyObject *args) @@ -238,13 +211,11 @@ PyObject *K_XCORE::icapsule_init(PyObject *self, PyObject *args) } } - ICapsule *icap = new ICapsule(marray, sarrays, ptags); - - PyObject *out = PyCapsule_New((void *)icap, "ICapsule", NULL); + ICapsule capsule = ICapsule::do_it(marray, sarrays, ptags); Karray_free_ngon(marray); for (E_Int i = 0; i < nslaves; i++) Karray_free_ngon(sarrays[i]); - return out; + return Py_None; } diff --git a/Cassiopee/XCore/XCore/intersectMesh/icapsule.h b/Cassiopee/XCore/XCore/intersectMesh/icapsule.h index e92485506..17b7db3a5 100644 --- a/Cassiopee/XCore/XCore/intersectMesh/icapsule.h +++ b/Cassiopee/XCore/XCore/intersectMesh/icapsule.h @@ -3,17 +3,10 @@ #include "mesh.h" struct ICapsule { - IMesh M; - std::vector Ss; - std::vector mpatches; - std::vector spatches; - - E_Float NEAR_VERTEX_TOL = 1e-3; - E_Float NEAR_EDGE_TOL = 1e-3; - - ICapsule(const Karray &marray, const std::vector &sarray, + static ICapsule do_it(const Karray &marray, + const std::vector &sarray, const std::vector &ptags); - void refine(Smesh &Mf, std::set &mfids, Smesh &Sf, - std::vector &plocs_s); + static std::vector refine(Smesh &Mf, + std::set &mfids, Smesh &Sf); }; diff --git a/Cassiopee/XCore/XCore/intersectMesh/icapsule_refine.cpp b/Cassiopee/XCore/XCore/intersectMesh/icapsule_refine.cpp index 5338384c1..460df4a6c 100644 --- a/Cassiopee/XCore/XCore/intersectMesh/icapsule_refine.cpp +++ b/Cassiopee/XCore/XCore/intersectMesh/icapsule_refine.cpp @@ -46,14 +46,29 @@ void Smesh::ray_BVH_intersect(E_Float ox, E_Float oy, E_Float oz, ploc.z = z; // on p - if (Sign(1-u, NEAR_VERTEX_TOL) == 0) + if (Sign(1-u, NEAR_VERTEX_TOL) == 0) { ploc.v_idx = j; + ploc.bcrd[0] = 1, ploc.bcrd[1] = 0, ploc.bcrd[2] = 0; + ploc.x = X[p]; + ploc.y = Y[p]; + ploc.z = Z[p]; + } // on q - else if (Sign(1-v, NEAR_VERTEX_TOL) == 0) + else if (Sign(1-v, NEAR_VERTEX_TOL) == 0) { ploc.v_idx = (j+1)%pn.size(); + ploc.bcrd[0] = 0, ploc.bcrd[1] = 1, ploc.bcrd[2] = 0; + ploc.x = X[q]; + ploc.y = Y[q]; + ploc.z = Z[q]; + } // on edge {p, q} - else if (Sign(w, NEAR_EDGE_TOL) == 0) + else if (Sign(w, NEAR_EDGE_TOL) == 0) { ploc.e_idx = j; + ploc.bcrd[0] = u, ploc.bcrd[1] = 1-u, ploc.bcrd[2] = 0; + ploc.x = u*X[p] + (1-u)*X[q]; + ploc.y = u*Y[p] + (1-u)*Y[q]; + ploc.z = u*Z[p] + (1-u)*Z[q]; + } plocs.push_back(ploc); @@ -68,20 +83,22 @@ void Smesh::ray_BVH_intersect(E_Float ox, E_Float oy, E_Float oz, ray_BVH_intersect(ox, oy, oz, dx, dy, dz, node->right, plocs); } -std::vector projections; - -void Smesh::project(const Smesh &Mf, const std::vector &mpids, - std::vector &plocs) const +std::vector Smesh::project(const Smesh &Mf, + const std::vector &mpids) const { + std::vector plocs; + plocs.reserve(mpids.size()); + for (size_t i = 0; i < mpids.size(); i++) { E_Int mpid = mpids[i]; + //printf("%lu\n", i); const E_Float *N = &Mf.pnormals[3*mpid]; E_Float mx = Mf.X[mpid]; E_Float my = Mf.Y[mpid]; E_Float mz = Mf.Z[mpid]; std::vector mlocs; // to parse ray_BVH_intersect(mx, my, mz, N[0], N[1], N[2], bvh_root, mlocs); - auto &ploc = plocs[i]; + PointLoc ploc; E_Float min_abs_t = EFLOATMAX; for (const auto &mloc : mlocs) { if (fabs(mloc.t) < min_abs_t) { @@ -89,10 +106,10 @@ void Smesh::project(const Smesh &Mf, const std::vector &mpids, ploc = mloc; } } - if (ploc.fid != -1) { - projections.push_back({ploc.x, ploc.y, ploc.z}); - } + plocs.push_back(ploc); } + + return plocs; } std::vector Smesh::deduce_ref_faces(const std::vector &mpids, @@ -146,12 +163,14 @@ std::vector Smesh::deduce_ref_faces(const std::vector &mpids, return ref_faces; } -void ICapsule::refine(Smesh &Mf, std::set &mfids, Smesh &Sf, - std::vector &plocs_s) +std::vector ICapsule::refine(Smesh &Mf, std::set &mfids, + Smesh &Sf) { size_t ref_M, ref_S; E_Int iter = 0; + + std::vector plocs_s; do { iter++; @@ -160,36 +179,13 @@ void ICapsule::refine(Smesh &Mf, std::set &mfids, Smesh &Sf, std::vector fat_mfids; Sf.make_BVH(); - Mf.make_BVH(mfids); - - /*********************** Sf refinement ***********************/ + //Mf.make_BVH(mfids); - // Isolate the points to project - std::set mpids_set; - for (E_Int fid : mfids) { - const auto &pn = Mf.F[fid]; - for (E_Int p : pn) mpids_set.insert(p); - } - std::vector mpids; - for (E_Int p : mpids_set) mpids.push_back(p); - - // Project mpids on Sf - std::vector plocs_m(mpids.size()); - Sf.project(Mf, mpids, plocs_m); - - // Deduce sfids to refine - std::vector sref_faces; - Sf.deduce_ref_faces(mpids, plocs_m, Mf, sref_faces); - printf("Fat sfids: %lu\n", sref_faces.size()); - - // Refine - ref_S = sref_faces.size(); - if (ref_S > 0) { - Sf.refine(sref_faces); - Sf.conformize(); - Sf.make_pnormals(); - } + //Sf.make_bbox(); + //Sf.hash_faces(); + Mf.make_bbox(); + Mf.hash_faces(); /*********************** Mf refinement ***********************/ @@ -199,10 +195,10 @@ void ICapsule::refine(Smesh &Mf, std::set &mfids, Smesh &Sf, for (E_Int i = 0; i < Sf.np; i++) spids.push_back(i); // Reproject spids on mfaces - plocs_s.resize(Sf.np); - Mf.project(Sf, spids, plocs_s); + Mf.make_fcenters(); + plocs_s = Mf.locate(Sf); Sf.replace_by_projections(spids, plocs_s); - + // Deduce mfids to refine std::vector mref_faces; Mf.deduce_ref_faces(spids, plocs_s, Sf, mref_faces); @@ -220,15 +216,39 @@ void ICapsule::refine(Smesh &Mf, std::set &mfids, Smesh &Sf, } } - Mf.destroy_BVH(Mf.bvh_root); + /*********************** Sf refinement ***********************/ + + // Isolate the points to project + std::set mpids_set; + for (E_Int fid : mfids) { + const auto &pn = Mf.Fc[fid]; + for (E_Int p : pn) mpids_set.insert(p); + } + std::vector mpids; + for (E_Int p : mpids_set) mpids.push_back(p); + + // Project mpids on Sf + puts("making Sf centers"); + Sf.make_fcenters(); + puts("projecting mpids on Sf"); + auto plocs_m = Sf.project(Mf, mpids); + + // Deduce sfids to refine + std::vector sref_faces; + Sf.deduce_ref_faces(mpids, plocs_m, Mf, sref_faces); + printf("Fat sfids: %lu\n", sref_faces.size()); + + // Refine + ref_S = sref_faces.size(); + if (ref_S > 0) { + Sf.refine(sref_faces); + Sf.conformize(); + Sf.make_pnormals(); + } + + //Mf.destroy_BVH(Mf.bvh_root); Sf.destroy_BVH(Sf.bvh_root); } while (ref_M > 0 || ref_S > 0); - Mf.make_bbox(); - Mf.hash_faces(); - - Sf.make_bbox(); - Sf.hash_faces(); - - //point_write("projections", projections); + return plocs_s; } diff --git a/Cassiopee/XCore/XCore/intersectMesh/primitives.h b/Cassiopee/XCore/XCore/intersectMesh/primitives.h index bc4e453a7..dea039941 100644 --- a/Cassiopee/XCore/XCore/intersectMesh/primitives.h +++ b/Cassiopee/XCore/XCore/intersectMesh/primitives.h @@ -22,7 +22,7 @@ #include "common/common.h" -constexpr E_Float TOL = 1e-12; +constexpr E_Float TOL = 1e-11; E_Int Sign(E_Float x, E_Float tol=TOL); diff --git a/Cassiopee/XCore/XCore/intersectMesh/smesh.cpp b/Cassiopee/XCore/XCore/intersectMesh/smesh.cpp index 6feffd352..38c566634 100644 --- a/Cassiopee/XCore/XCore/intersectMesh/smesh.cpp +++ b/Cassiopee/XCore/XCore/intersectMesh/smesh.cpp @@ -448,7 +448,7 @@ void Smesh::make_fcenters() fcenters.resize(3*nf, 0); for (E_Int fid = 0; fid < nf; fid++) { E_Float *fc = &fcenters[3*fid]; - const auto &pn = F[fid]; + const auto &pn = Fc[fid]; for (E_Int p : pn) { fc[0] += X[p]; fc[1] += Y[p]; @@ -495,7 +495,7 @@ void Smesh::make_fnormals() fnormals.resize(3*nf, 0); for (E_Int fid = 0; fid < nf; fid++) { - const auto &pn = F[fid]; + const auto &pn = Fc[fid]; const E_Float *fc = &fcenters[3*fid]; E_Int a = pn[0], b = pn[1]; E_Float v0[3] = {X[a]-fc[0], Y[a]-fc[1], Z[a]-fc[2]}; @@ -532,35 +532,6 @@ void Smesh::make_pnormals() } } -void Smesh::compute_min_distance_between_points() -{ - min_pdist_squared = EFLOATMAX; - E_Int ndists = 0; - - for (E_Int i = 0; i < np; i++) { - E_Float xi = X[i]; - E_Float yi = Y[i]; - E_Float zi = Z[i]; - for (E_Int j = i+1; j < np; j++) { - E_Float xj = X[j]; - E_Float yj = Y[j]; - E_Float zj = Z[j]; - - E_Float dx = xj-xi; - E_Float dy = yj-yi; - E_Float dz = zj-zi; - - E_Float dist = dx*dx + dy*dy + dz*dz; - - if (dist < min_pdist_squared) min_pdist_squared = dist; - - ndists++; - } - } - - assert(ndists == np*(np-1)/2); -} - void Smesh::clear() { np = ne = nf = 0; diff --git a/Cassiopee/XCore/XCore/intersectMesh/smesh.h b/Cassiopee/XCore/XCore/intersectMesh/smesh.h index 687e2cacd..533caf429 100644 --- a/Cassiopee/XCore/XCore/intersectMesh/smesh.h +++ b/Cassiopee/XCore/XCore/intersectMesh/smesh.h @@ -95,7 +95,7 @@ struct Smesh { std::vector fcenters; std::vector fnormals; std::vector pnormals; - E_Float min_pdist_squared = EFLOATMIN; + E_Float min_pdist = EFLOATMIN; E_Float NEAR_VERTEX_TOL = 1e-3; E_Float NEAR_EDGE_TOL = 1e-3; @@ -109,8 +109,8 @@ struct Smesh { void get_unit_projected_direction(E_Int fid, const E_Float D[3], E_Float proj[3]) const; void compute_min_distance_between_points(); - void project(const Smesh &Mf, const std::vector &mpids, - std::vector &plocs) const; + std::vector project(const Smesh &Mf, + const std::vector &mpids) const; void replace_by_projections(const std::vector &pids, const std::vector &plocs); void ray_BVH_intersect(E_Float ox, E_Float oy, E_Float oz, @@ -166,11 +166,11 @@ struct Smesh { bool check_Euler = true; - std::set extract_bounding_faces(const Smesh &Sf, + std::set extract_covering_faces(const Smesh &Sf, const std::vector &plocs) const; E_Int deduce_face(const std::vector &pf, E_Float ox, E_Float oy, E_Float oz, E_Float D[3], - E_Int last_vertex, E_Int last_edge) const; + E_Int last_vertex, E_Int last_edge, E_Int eid) const; void get_shared_faces(const PointLoc &loc, std::vector &ret, E_Int &pid, E_Int &eid) const; Smesh extract_smesh(const std::set &fids, bool check_Euler=true); diff --git a/Cassiopee/XCore/XCore/intersectMesh/smesh_extract.cpp b/Cassiopee/XCore/XCore/intersectMesh/smesh_extract.cpp index 58ffe3005..477573981 100644 --- a/Cassiopee/XCore/XCore/intersectMesh/smesh_extract.cpp +++ b/Cassiopee/XCore/XCore/intersectMesh/smesh_extract.cpp @@ -49,7 +49,7 @@ std::set ewalls; std::set fwalls; std::vector pchains; -std::set Smesh::extract_bounding_faces(const Smesh &Sf, +std::set Smesh::extract_covering_faces(const Smesh &Sf, const std::vector &plocs) const { // Get boundary edges from spatch @@ -94,6 +94,7 @@ std::set Smesh::extract_bounding_faces(const Smesh &Sf, assert(pchain.size() == nbedges); + /* // Sort the pchain counterclockwise E_Int a = pchain[0], b = pchain[1], c = pchain[2]; E_Float ux = Sf.X[b] - Sf.X[a]; @@ -109,6 +110,7 @@ std::set Smesh::extract_bounding_faces(const Smesh &Sf, E_Int cmp = Sign(dp); assert(cmp != 0); if (cmp < 0) std::reverse(pchain.begin(), pchain.end()); + */ Sf.write_points("pchain.im", pchain); @@ -142,7 +144,7 @@ std::set Smesh::extract_bounding_faces(const Smesh &Sf, //write_ngon("shared", orig_faces); E_Int starting_face = deduce_face(orig_faces, px, py, pz, - D, last_vertex, last_edge); + D, last_vertex, last_edge, dummy); assert(starting_face != -1); bool found_tail = false; @@ -241,8 +243,7 @@ std::set Smesh::extract_bounding_faces(const Smesh &Sf, const auto &pf = P2F[last_vertex]; next_fid = deduce_face(pf, next_pos[0], next_pos[1], next_pos[2], - D, last_vertex, last_edge - ); + D, last_vertex, last_edge, dummy); assert(next_fid != -1); } break; @@ -262,6 +263,8 @@ std::set Smesh::extract_bounding_faces(const Smesh &Sf, assert(walk <= max_walks); } + write_edges("wall", weids); + // TODO(Imad): project wpids on best-fit plane and jarvis march // BFS to get the smesh mpids diff --git a/Cassiopee/XCore/XCore/intersectMesh/smesh_geom.cpp b/Cassiopee/XCore/XCore/intersectMesh/smesh_geom.cpp index 1b3b10688..adb6bfbb9 100644 --- a/Cassiopee/XCore/XCore/intersectMesh/smesh_geom.cpp +++ b/Cassiopee/XCore/XCore/intersectMesh/smesh_geom.cpp @@ -2,6 +2,59 @@ #include "primitives.h" #include "io.h" +void Smesh::replace_by_projections(const std::vector &pids, + const std::vector &plocs) +{ + for (size_t i = 0; i < pids.size(); i++) { + E_Int pid = pids[i]; + const auto &ploc = plocs[pid]; + if (ploc.v_idx != -1 || ploc.e_idx != -1) { + E_Float dx = X[pid]-ploc.x; + E_Float dy = Y[pid]-ploc.y; + E_Float dz = Z[pid]-ploc.z; + E_Float d = sqrt(dx*dx + dy*dy + dz*dz); + if (d >= min_pdist) { + fprintf(stderr, "Tight near vertex/edge situation!\n"); + point_write("orig", X[pid], Y[pid], Z[pid]); + point_write("dest", ploc.x, ploc.y, ploc.z); + assert(0); + } + X[pid] = ploc.x; + Y[pid] = ploc.y; + Z[pid] = ploc.z; + } + } +} + +void Smesh::compute_min_distance_between_points() +{ + min_pdist = EFLOATMAX; + size_t ndists = 0; + + for (E_Int i = 0; i < np; i++) { + E_Float xi = X[i]; + E_Float yi = Y[i]; + E_Float zi = Z[i]; + for (E_Int j = i+1; j < np; j++) { + E_Float xj = X[j]; + E_Float yj = Y[j]; + E_Float zj = Z[j]; + + E_Float dx = xj-xi; + E_Float dy = yj-yi; + E_Float dz = zj-zi; + + E_Float dist = sqrt(dx*dx + dy*dy + dz*dz); + + if (dist < min_pdist) min_pdist = dist; + + ndists++; + } + } + + assert(ndists == (size_t)np*((size_t)np-1)/2); +} + void Smesh::get_unit_projected_direction(E_Int fid, const E_Float D[3], E_Float proj[3]) const { @@ -22,7 +75,7 @@ void Smesh::get_unit_projected_direction(E_Int fid, const E_Float D[3], E_Int Smesh::deduce_face(const std::vector &pf, E_Float ox, E_Float oy, E_Float oz, E_Float D[3], - E_Int last_vertex, E_Int last_edge) const + E_Int last_vertex, E_Int last_edge, E_Int eid) const { // Intersect the projection of D with all the faces in pf // At least one intersection must exist @@ -56,6 +109,11 @@ E_Int Smesh::deduce_face(const std::vector &pf, E_Float t, s; + //if (eid == 133) { + // point_write("p.im", X[p], Y[p], Z[p]); + // point_write("q.im", X[q], Y[q], Z[q]); + //} + bool hit = ray_edge_intersect(ox, oy, oz, proj[0], proj[1], proj[2], X[p], Y[p], Z[p], @@ -78,6 +136,10 @@ E_Int Smesh::deduce_face(const std::vector &pf, } // We must have hit a face + if (faces_hit == 0) { + write_ngon("pf.im", pf); + edge_write("ray.im", ox, oy, oz, ox+D[0], oy+D[1], oz+D[2]); + } assert(faces_hit > 0); return ret_face; diff --git a/Cassiopee/XCore/XCore/intersectMesh/smesh_locate.cpp b/Cassiopee/XCore/XCore/intersectMesh/smesh_locate.cpp index 252b5efea..0f9dd8283 100644 --- a/Cassiopee/XCore/XCore/intersectMesh/smesh_locate.cpp +++ b/Cassiopee/XCore/XCore/intersectMesh/smesh_locate.cpp @@ -3,18 +3,98 @@ #include "primitives.h" #include "io.h" -void Smesh::replace_by_projections(const std::vector &pids, - const std::vector &plocs) +std::vector Smesh::locate(const Smesh &Sf) const { - for (size_t i = 0; i < pids.size(); i++) { - E_Int pid = pids[i]; - const auto &ploc = plocs[pid]; - X[pid] = ploc.x; - Y[pid] = ploc.y; - Z[pid] = ploc.z; + std::vector ploc(Sf.np); + + for (E_Int pid = 0; pid < Sf.np; pid++) { + + E_Float x = Sf.X[pid]; + E_Float y = Sf.Y[pid]; + E_Float z = Sf.Z[pid]; + + E_Int I = floor((x - xmin) / HX); + E_Int J = floor((y - ymin) / HY); + E_Int K = floor((z - zmin) / HZ); + E_Int voxel = get_voxel(I, J, K); + + const auto &pf = bin_faces.at(voxel); + + bool found = false; + + auto &loc = ploc[pid]; + + for (size_t i = 0; i < pf.size() && !found; i++) { + E_Int fid = pf[i]; + const auto &pn = Fc[fid]; + const E_Float *fc = &fcenters[3*fid]; + + for (size_t j = 0; j < pn.size(); j++) { + E_Int p = pn[j]; + E_Int q = pn[(j+1)%pn.size()]; + + E_Float u, v, w; + + found = Triangle::is_point_inside(x, y, z, + X[p], Y[p], Z[p], + X[q], Y[q], Z[q], + fc[0], fc[1], fc[2], + u, v, w + ); + + if (found) { + loc.fid = fid; + loc.sub = j; + loc.bcrd[0] = u; + loc.bcrd[1] = v; + loc.bcrd[2] = w; + + /* + if (pid == 107) { + printf("fid: %d - size: %d\n", fid, pn.size()); + printf("u: %f - v: %f - w: %f\n", u, v, w); + printf("%f %f %f\n", fc[0], fc[1], fc[2]); + } + */ + + // on p + if (Sign(1-u, NEAR_VERTEX_TOL) == 0) { + loc.v_idx = j; + loc.x = X[p]; loc.y = Y[p]; loc.z = Z[p]; + loc.bcrd[0] = 1; loc.bcrd[1] = 0; loc.bcrd[2] = 0; + } + // on q + else if (Sign(1-v, NEAR_VERTEX_TOL) == 0) { + loc.v_idx = (j+1)%pn.size(); + loc.x = X[q]; loc.y = Y[q]; loc.z = Z[q]; + loc.bcrd[0] = 0; loc.bcrd[1] = 1; loc.bcrd[2] = 0; + } + // on edge {p, q} + else if (Sign(w, NEAR_EDGE_TOL) == 0) { + loc.e_idx = j; + loc.x = u*X[p] + (1-u)*X[q]; + loc.y = u*Y[p] + (1-u)*Y[q]; + loc.z = u*Z[p] + (1-u)*Z[q]; + loc.bcrd[1] = 1-u; loc.bcrd[2] = 0; + } + + break; + } + } + } + + if (!found) { + point_write("lost", x, y, z); + write_ngon("bin", pf); + } + + assert(found); } + + return ploc; } +/* void Smesh::correct_near_points_and_edges(Smesh &Sf, std::vector &plocs) { @@ -23,7 +103,7 @@ void Smesh::correct_near_points_and_edges(Smesh &Sf, auto &ploc = plocs[i]; E_Int fid = ploc.fid; - assert(fid < nf); + assert(fid != -1); const auto &pn = Fc[fid]; if (ploc.v_idx != -1) { @@ -49,17 +129,35 @@ void Smesh::correct_near_points_and_edges(Smesh &Sf, E_Float v = ploc.bcrd[1]; E_Float w = ploc.bcrd[2]; assert(Sign(w, NEAR_EDGE_TOL) == 0); - u += w; - assert(Sign(u+v-1) == 0); + v = 1 - u, w = 0; + E_Int p = pn[ploc.e_idx]; E_Int q = pn[(ploc.e_idx+1)%pn.size()]; - Sf.X[i] = u*X[p] + v*X[q]; - Sf.Y[i] = u*Y[p] + v*Y[q]; - Sf.Z[i] = u*Z[p] + v*Z[q]; + E_Float new_x = u*X[p] + v*X[q]; + E_Float new_y = u*Y[p] + v*Y[q]; + E_Float new_z = u*Z[p] + v*Z[q]; + + E_Float dx = new_x-Sf.X[i]; + E_Float dy = new_y-Sf.Y[i]; + E_Float dz = new_z-Sf.Z[i]; + E_Float dist = dx*dx + dy*dy + dz*dz; + if (dist >= Sf.min_pdist_squared) { + fprintf(stderr, "Tight near-edge situation!\n"); + point_write("mpoint", X[p], Y[p], Z[p]); + point_write("spoint", Sf.X[i], Sf.Y[i], Sf.Z[i]); + assert(0); + } else { + ploc.bcrd[1] = v; ploc.bcrd[2] = 0; + + Sf.X[i] = new_x; + Sf.Y[i] = new_y; + Sf.Z[i] = new_z; + } } } printf("on vertex: %d - on edge: %d\n", on_vertex, on_edge); } +*/ void Smesh::make_bbox() { @@ -69,8 +167,8 @@ void Smesh::make_bbox() NXY = NX * NY; NXYZ = NXY * NZ; - xmin = ymin = zmin = std::numeric_limits::max(); - xmax = ymax = zmax = std::numeric_limits::min(); + xmin = ymin = zmin = EFLOATMAX; + xmax = ymax = zmax = EFLOATMIN; for (E_Int i = 0; i < np; i++) { if (X[i] < xmin) xmin = X[i]; @@ -92,9 +190,9 @@ void Smesh::make_bbox() ymax = ymax + dy*0.01; zmax = zmax + dz*0.01; - HX = (xmax - xmin) / NX; - HY = (ymax - ymin) / NY; - HZ = (zmax - zmin) / NZ; + HX = (dx != 0) ? (xmax - xmin) / NX : 1; + HY = (dy != 0) ? (ymax - ymin) / NY : 1; + HZ = (dz != 0) ? (zmax - zmin) / NZ : 1; } inline @@ -145,94 +243,3 @@ void Smesh::hash_faces() bin_face(fid); } } - -std::vector Smesh::locate(const Smesh &Sf) const -{ - std::vector ploc(Sf.np); - - for (E_Int pid = 0; pid < Sf.np; pid++) { - - E_Float x = Sf.X[pid]; - E_Float y = Sf.Y[pid]; - E_Float z = Sf.Z[pid]; - - E_Int I = floor((x - xmin) / HX); - E_Int J = floor((y - ymin) / HY); - E_Int K = floor((z - zmin) / HZ); - E_Int voxel = get_voxel(I, J, K); - - const auto &pf = bin_faces.at(voxel); - - bool found = false; - - auto &loc = ploc[pid]; - - /* - if (pid == 371) - point_write("lost", x, y, z); - */ - - for (size_t i = 0; i < pf.size() && !found; i++) { - E_Int fid = pf[i]; - const auto &pn = Fc[fid]; - const E_Float *fc = &fcenters[3*fid]; - - /* - if (pid == 371) { - write_face("fid", fid); - point_write("fc", fc[0], fc[1], fc[2]); - } - */ - - for (size_t j = 0; j < pn.size(); j++) { - E_Int p = pn[j]; - E_Int q = pn[(j+1)%pn.size()]; - - /* - if (pid == 371) { - point_write("p", X[p], Y[p], Z[p]); - point_write("q", X[q], Y[q], Z[q]); - } - */ - - E_Float u, v, w; - - found = Triangle::is_point_inside(x, y, z, - X[p], Y[p], Z[p], - X[q], Y[q], Z[q], - fc[0], fc[1], fc[2], - u, v, w - ); - - if (found) { - loc.fid = fid; - loc.sub = j; - loc.bcrd[0] = u; - loc.bcrd[1] = v; - loc.bcrd[2] = w; - - // on p - if (Sign(1-u, NEAR_VERTEX_TOL) == 0) - loc.v_idx = j; - // on q - else if (Sign(1-v, NEAR_VERTEX_TOL) == 0) - loc.v_idx = (j+1)%pn.size(); - // on edge {p, q} - else if (Sign(w, NEAR_EDGE_TOL) == 0) - loc.e_idx = j; - - break; - } - } - } - - if (!found) { - point_write("lost", x, y, z); - write_ngon("bin", pf); - } - - assert(found); - } - - return ploc; -} diff --git a/Cassiopee/XCore/XCore/intersectMesh/smesh_refine.cpp b/Cassiopee/XCore/XCore/intersectMesh/smesh_refine.cpp index 2bff6930a..51500dd2c 100644 --- a/Cassiopee/XCore/XCore/intersectMesh/smesh_refine.cpp +++ b/Cassiopee/XCore/XCore/intersectMesh/smesh_refine.cpp @@ -43,7 +43,7 @@ void Smesh::compute_face_center(E_Int fid) { E_Float *fc = &fcenters[3*fid]; fc[0] = fc[1] = fc[2] = 0; - const auto &pn = F[fid]; + const auto &pn = Fc[fid]; for (E_Int p : pn) { fc[0] += X[p]; fc[1] += Y[p]; @@ -89,8 +89,8 @@ void Smesh::refine_tri(E_Int fid) for (E_Int j = 0; j < 3; j++) fN[j] = N[j]; } - compute_face_center(fid); - for (E_Int i = 0; i < 3; i++) compute_face_center(nf+i); + //compute_face_center(fid); + //for (E_Int i = 0; i < 3; i++) compute_face_center(nf+i); nf += 3; } From 37dc89e6c03aea93bd7ea419ae7eea30ab3ad016 Mon Sep 17 00:00:00 2001 From: imadhammani Date: Tue, 29 Oct 2024 11:30:34 +0100 Subject: [PATCH 69/86] XCore intersectMesh: added Smesh reconstruction after Dcel intersection --- Cassiopee/XCore/XCore/intersectMesh/dcel.cpp | 114 +++++++++++++----- Cassiopee/XCore/XCore/intersectMesh/dcel.h | 3 + .../XCore/XCore/intersectMesh/dcel_io.cpp | 91 ++++++++++++++ 3 files changed, 176 insertions(+), 32 deletions(-) diff --git a/Cassiopee/XCore/XCore/intersectMesh/dcel.cpp b/Cassiopee/XCore/XCore/intersectMesh/dcel.cpp index f76b900d8..a04d68f9a 100644 --- a/Cassiopee/XCore/XCore/intersectMesh/dcel.cpp +++ b/Cassiopee/XCore/XCore/intersectMesh/dcel.cpp @@ -41,7 +41,6 @@ void Dcel::init_vertices(const Smesh &Mf, const Smesh &Sf, for (E_Int i = 0; i < Sf.np; i++) { Vertex tmp(Sf.X[i], Sf.Y[i], Sf.Z[i]); auto it = vertex_set.find(&tmp); - const auto &ploc = plocs[i]; Vertex *v = NULL; if (it == vertex_set.end()) { v = new Vertex(Sf.X[i], Sf.Y[i], Sf.Z[i]); @@ -60,11 +59,91 @@ void Dcel::init_vertices(const Smesh &Mf, const Smesh &Sf, v->id = V.size(); V.push_back(v); } - assert(V.back()->id == V.size()-1); printf("Duplicate vertices: %d\n", duplicate_vertices); } +std::vector Dcel::get_face_vertices(const Face *f) const +{ + assert(f); + std::vector ret; + Hedge *h = f->rep; + ret.push_back(h->orig); + Hedge *w = h->next; + while (w != h) { + ret.push_back(w->orig); + w = w->next; + } + return ret; +} + +Smesh Dcel::reconstruct(const Smesh &Mf, int color, bool check_Euler) const +{ + Smesh ret; + ret.check_Euler = check_Euler; + auto &new_F = ret.F; + std::map new_pids; + ret.np = ret.nf = 0; + + std::vector fids; + + for (size_t i = 0; i < F.size(); i++) { + Face *f = F[i]; + Hedge *h = f->rep; + if (h->color != color) continue; + Hedge *w = h->next; + while (w != h) { + if (w->color != h->color) break; + w = w->next; + } + if (w == h) { + fids.push_back(f); + } + } + + char fname[128] = {0}; + sprintf(fname, "single_color_%d.im", color); + write_ngon(fname, fids); + + for (Face *f : F) { + if (f->oids[color] == -1) continue; + + std::vector pn; + + std::vector vertices = get_face_vertices(f); + for (Vertex *v : vertices) { + auto it = new_pids.find(v); + if (it == new_pids.end()) { + new_pids[v] = ret.np; + pn.push_back(ret.np); + ret.np++; + } else { + pn.push_back(it->second); + } + } + + new_F.push_back(pn); + ret.nf++; + } + + auto &new_X = ret.X; + auto &new_Y = ret.Y; + auto &new_Z = ret.Z; + + new_X.resize(ret.np), new_Y.resize(ret.np), new_Z.resize(ret.np); + for (const auto &vdat : new_pids) { + new_X[vdat.second] = vdat.first->x; + new_Y[vdat.second] = vdat.first->y; + new_Z[vdat.second] = vdat.first->z; + } + + ret.Fc = ret.F; + + ret.make_edges(); + + return ret; +} + Dcel::Dcel(const Smesh &Mf, const Smesh &Sf, const std::vector &plocs) { init_vertices(Mf, Sf, plocs); @@ -180,7 +259,7 @@ Dcel::Dcel(const Smesh &Mf, const Smesh &Sf, const std::vector &plocs) const auto &pn = Mf.Fc[cur_fid]; const auto &pe = Mf.F2E[cur_fid]; assert(pe.size() == pn.size()); - const E_Float *fN = &Mf.fnormals[3*cur_fid]; + //const E_Float *fN = &Mf.fnormals[3*cur_fid]; E_Int next_fid = -1; E_Float next_pos[3] = {EFLOATMAX, EFLOATMAX, EFLOATMAX}; @@ -318,9 +397,6 @@ Dcel::Dcel(const Smesh &Mf, const Smesh &Sf, const std::vector &plocs) Hedge *current_h = h; Hedge *t = h->twin; - Hedge *t_next = t->next; - Hedge *h_next = h->next; - for (Vertex *x : xs) { Hedge *e1 = new Hedge(x, current_h->color); Hedge *e2 = new Hedge(x, t->color); @@ -871,32 +947,6 @@ Dcel::~Dcel() for (Cycle *c : C) delete c; } -/* -void Dcel::reconstruct(const Smesh &M, const Smesh &S) -{ - check_hedges(H); - - make_cycles(); - assert(0); - set_cycles_inout(M, 0); - - auto new_F = make_cycle_faces(C); - - set_face_labels(new_F); - - update_hedge_faces(new_F); - - for (Face *f : F) delete f; - F = new_F; - - check_faces(H, F); - - write_degen_faces("degen"); - write_inner_faces("inner"); - write_outer_faces("outer"); -} -*/ - Dcel::Dcel(const Smesh &Mf, int color) { const auto &X = Mf.X; diff --git a/Cassiopee/XCore/XCore/intersectMesh/dcel.h b/Cassiopee/XCore/XCore/intersectMesh/dcel.h index d73325e13..eff8d77d5 100644 --- a/Cassiopee/XCore/XCore/intersectMesh/dcel.h +++ b/Cassiopee/XCore/XCore/intersectMesh/dcel.h @@ -143,10 +143,12 @@ struct Dcel { Hedge *get_hedge_of_color(Face *f, int color); void update_hedge_faces(std::vector &F); + std::vector get_face_vertices(const Face *f) const; // Export Smesh export_smesh(bool check_Euler=true) const; + Smesh reconstruct(const Smesh &Mf, int color, bool check_Euler) const; // Extract @@ -163,6 +165,7 @@ struct Dcel { void write_point(const char *fname, const Vertex *v) const; void write_point(const char *fname, const std::vector &I) const; void write_ngon(const char *fname, const std::vector &cycles) const; + void write_ngon(const char *fname, const std::vector &faces) const; void write_degen_cycles(const char *fname) const; void write_inner_cycles(const char *fname) const; void write_hole_cycles(const char *fname) const; diff --git a/Cassiopee/XCore/XCore/intersectMesh/dcel_io.cpp b/Cassiopee/XCore/XCore/intersectMesh/dcel_io.cpp index 18a746492..a29b2b3b8 100644 --- a/Cassiopee/XCore/XCore/intersectMesh/dcel_io.cpp +++ b/Cassiopee/XCore/XCore/intersectMesh/dcel_io.cpp @@ -218,3 +218,94 @@ void Dcel::write_ngon(const char *fname, const std::vector &cycles) con fclose(fh); } + +void Dcel::write_ngon(const char *fname, const std::vector &faces) const +{ + FILE *fh = fopen(fname, "w"); + assert(fh); + + E_Int np = 0; + E_Int ne = 0; + E_Int nf = (E_Int)faces.size(); + + std::map vmap; + std::vector new_pids; + + for (size_t i = 0; i < faces.size(); i++) { + Face *c = faces[i]; + Hedge *h = c->rep; + ne++; + Vertex *p = h->orig; + if (vmap.find(p) == vmap.end()) { + vmap[p] = np++; + new_pids.push_back(p); + } + Hedge *w = h->next; + while (w != h) { + p = w->orig; + if (vmap.find(p) == vmap.end()) { + vmap[p] = np++; + new_pids.push_back(p); + } + ne++; + w = w->next; + } + } + + fprintf(fh, "POINTS\n"); + fprintf(fh, SF_D_ "\n", np); + for (const auto &v : new_pids) { + fprintf(fh, "%f %f %f\n", v->x, v->y, v->z); + } + + fprintf(fh, "INDPG\n"); + fprintf(fh, SF_D_ "\n", ne+1); + E_Int sizeNGon = 0; + fprintf(fh, SF_D_ " ", sizeNGon); + for (E_Int i = 0; i < ne; i++) { + sizeNGon += 2; + fprintf(fh, SF_D_ " ", sizeNGon); + } + assert(sizeNGon == 2*ne); + fprintf(fh, "\n"); + + fprintf(fh, "NGON\n"); + fprintf(fh, SF_D_ "\n", sizeNGon); + for (Face *c : faces) { + Hedge *h = c->rep; + Vertex *p = h->orig; + Vertex *q = h->twin->orig; + fprintf(fh, SF_D_ " " SF_D_ " ", vmap[p], vmap[q]); + Hedge *w = h->next; + while (w != h) { + p = w->orig; + q = w->twin->orig; + fprintf(fh, SF_D_ " " SF_D_ " ", vmap[p], vmap[q]); + w = w->next; + } + } + fprintf(fh, "\n"); + + fprintf(fh, "INDPH\n"); + fprintf(fh, SF_D_ "\n", nf+1); + E_Int sizeNFace = 0; + fprintf(fh, SF_D_ " ", sizeNFace); + for (Face *c : faces) { + Hedge *h = c->rep; + sizeNFace += 1; + Hedge *w = h->next; + while (w != h) { + sizeNFace += 1; + w = w->next; + } + fprintf(fh, SF_D_ " ", sizeNFace); + } + fprintf(fh, "\n"); + + fprintf(fh, "NFACE\n"); + fprintf(fh, SF_D_ "\n", sizeNFace); + for (E_Int i = 0; i < sizeNFace; i++) + fprintf(fh, SF_D_ " ", i); + + fclose(fh); +} \ No newline at end of file From 2c3b607da4979e9bef33196aeafcf739d9494c8e Mon Sep 17 00:00:00 2001 From: imadhammani Date: Tue, 29 Oct 2024 18:09:47 +0100 Subject: [PATCH 70/86] XCore intersectMesh: support multiple zones per intersected base --- Cassiopee/XCore/XCore/PyTree.py | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/Cassiopee/XCore/XCore/PyTree.py b/Cassiopee/XCore/XCore/PyTree.py index 2d00c662c..6050d360d 100644 --- a/Cassiopee/XCore/XCore/PyTree.py +++ b/Cassiopee/XCore/XCore/PyTree.py @@ -491,11 +491,12 @@ def icapsule_init(mp, sp): bases = I.getBases(sp) for base in bases: - zs = I.getZones(base)[0] - sarr = C.getFields(I.__GridCoordinates__, zs, api=3)[0] - sarrs.append(sarr) - tag = I.getNodeFromName(zs, 'tag')[1] - tags.append(tag) + zones = I.getZones(base) + for zone in zones: + sarr = C.getFields(I.__GridCoordinates__, zone, api=3)[0] + sarrs.append(sarr) + tag = I.getNodeFromName(zone, 'tag')[1] + tags.append(tag) return xcore.icapsule_init(marr, sarrs, tags) From da8e5a230ee7288602f314957ec2ad334b5ee8f1 Mon Sep 17 00:00:00 2001 From: imadhammani Date: Tue, 29 Oct 2024 18:10:50 +0100 Subject: [PATCH 71/86] XCore intersectMesh: replaced DDA projection with BVH project. BVH traversal needs to be faster. --- .../removeIntersectingKPlanes.cpp | 31 +++++++++++++++++-- 1 file changed, 29 insertions(+), 2 deletions(-) diff --git a/Cassiopee/XCore/XCore/intersectMesh/removeIntersectingKPlanes.cpp b/Cassiopee/XCore/XCore/intersectMesh/removeIntersectingKPlanes.cpp index b502b3b1c..152d89f6d 100644 --- a/Cassiopee/XCore/XCore/intersectMesh/removeIntersectingKPlanes.cpp +++ b/Cassiopee/XCore/XCore/intersectMesh/removeIntersectingKPlanes.cpp @@ -55,7 +55,7 @@ void construct_faces(std::vector> &faces, NF++; } -PyObject *handle_slave(IMesh *M, Karray& sarray) +PyObject *handle_slave(const IMesh *M, const Smesh &Mf, Karray& sarray) { E_Int ni = sarray.ni; E_Int nj = sarray.nj; @@ -120,6 +120,7 @@ PyObject *handle_slave(IMesh *M, Karray& sarray) dx /= NORM, dy /= NORM, dz /= NORM; + /* TriangleIntersection TI; E_Int hit = M->project_point(px, py, pz, dx, dy, dz, TI, i); @@ -129,6 +130,23 @@ PyObject *handle_slave(IMesh *M, Karray& sarray) TI.pid = p; point_hit_table[p] = TI; + */ + + std::vector mlocs; + Mf.ray_BVH_intersect(px, py, pz, dx, dy, dz, Mf.bvh_root, mlocs); + PointLoc ploc; + E_Float min_abs_t = EFLOATMAX; + for (const auto &mloc : mlocs) { + if (fabs(mloc.t) < min_abs_t) { + min_abs_t = fabs(mloc.t); + ploc = mloc; + } + } + + TriangleIntersection TI; + TI.pid = p; + TI.x = ploc.x, TI.y = ploc.y, TI.z = ploc.z; + point_hit_table[p] = TI; } // Construct the new faces and cells @@ -510,6 +528,7 @@ PyObject *handle_slave2(IMesh *M, Karray& sarray, E_Int kmax) return out; } +#include "smesh.h" PyObject *K_XCORE::removeIntersectingKPlanes(PyObject *self, PyObject *args) { @@ -530,6 +549,12 @@ PyObject *K_XCORE::removeIntersectingKPlanes(PyObject *self, PyObject *args) M->make_skin(); M->make_bbox(); M->hash_skin(); + //M->make_bvh(); + + Smesh Mf = Smesh::Smesh_from_mesh_skin(*M, M->skin, false); + printf("Mf: %d tris\n", Mf.nf); + Mf.make_fcenters(); + Mf.make_BVH(); E_Int nslaves = PyList_Size(SLAVES); E_Int i, ret; @@ -571,11 +596,13 @@ PyObject *K_XCORE::removeIntersectingKPlanes(PyObject *self, PyObject *args) for (E_Int i = 0; i < nslaves; i++) { printf("Projecting %d / %d\n", i+1, nslaves); //PyObject *st = handle_slave2(M, sarrays[i], kmax); - PyObject *st = handle_slave(M, sarrays[i]); + PyObject *st = handle_slave(M, Mf, sarrays[i]); PyList_Append(slaves_out, st); Py_DECREF(st); Karray_free_structured(sarrays[i]); } + Mf.destroy_BVH(Mf.bvh_root); + return slaves_out; } From a254dd32b8675ceedf4d2701470dae90b67ae6be Mon Sep 17 00:00:00 2001 From: imadhammani Date: Tue, 29 Oct 2024 18:12:29 +0100 Subject: [PATCH 72/86] XCore intersectMesh: icapsule small update --- .../XCore/XCore/intersectMesh/icapsule.cpp | 20 +++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) diff --git a/Cassiopee/XCore/XCore/intersectMesh/icapsule.cpp b/Cassiopee/XCore/XCore/intersectMesh/icapsule.cpp index b22bc26fd..ae4ff813e 100644 --- a/Cassiopee/XCore/XCore/intersectMesh/icapsule.cpp +++ b/Cassiopee/XCore/XCore/intersectMesh/icapsule.cpp @@ -40,7 +40,8 @@ ICapsule ICapsule::do_it(const Karray &marray, S.triangulate_skin(); // Create SMesh Sf - Smesh Sf = Smesh::Smesh_from_point_tags(S, ptags[i]); + Smesh Sf = Smesh::Smesh_from_point_tags(S, ptags[i], true); + Sf.make_fcenters(); Sf.make_fnormals(); Sf.make_pnormals(); @@ -59,10 +60,6 @@ ICapsule ICapsule::do_it(const Karray &marray, // Extract the initial Mf faces that cover Sf auto bfaces = Mf.extract_covering_faces(Sf, plocs); - { - Smesh If(Mf, bfaces, false); - If.write_ngon("If.im"); - } // Refinement loop plocs = refine(Mf, bfaces, Sf); @@ -82,14 +79,25 @@ ICapsule ICapsule::do_it(const Karray &marray, Bf.write_ngon("Bf.im"); Sf.write_ngon("Sf.im"); + /* { Dcel Db(Bf, Dcel::RED); Dcel Ds(Sf, Dcel::BLACK); } + */ // Intersect Dcel D(Bf, Sf, plocs); + { + Smesh new_Bf = D.reconstruct(Bf, Dcel::RED, false); + new_Bf.write_ngon("new_Bf.im"); + puts("reconstruted new Bf"); + Smesh new_Sf = D.reconstruct(Sf, Dcel::BLACK, true); + new_Sf.write_ngon("new_Sf.im"); + puts("reconstruted new Sf"); + } + puts(""); } @@ -211,7 +219,7 @@ PyObject *K_XCORE::icapsule_init(PyObject *self, PyObject *args) } } - ICapsule capsule = ICapsule::do_it(marray, sarrays, ptags); + ICapsule::do_it(marray, sarrays, ptags); Karray_free_ngon(marray); for (E_Int i = 0; i < nslaves; i++) From 2cddd3966304acf7b6f6272d73f173fefbd0aa0f Mon Sep 17 00:00:00 2001 From: imadhammani Date: Wed, 30 Oct 2024 16:12:06 +0100 Subject: [PATCH 73/86] XCore intersectMesh: faster BVH traversal --- Cassiopee/XCore/XCore/intersectMesh/AABB.h | 5 +- Cassiopee/XCore/XCore/intersectMesh/BVH.h | 8 +- .../XCore/intersectMesh/icapsule_refine.cpp | 88 +----- .../removeIntersectingKPlanes.cpp | 5 +- Cassiopee/XCore/XCore/intersectMesh/smesh.h | 26 +- .../XCore/XCore/intersectMesh/smesh_bvh.cpp | 251 +++++++++++++----- 6 files changed, 213 insertions(+), 170 deletions(-) diff --git a/Cassiopee/XCore/XCore/intersectMesh/AABB.h b/Cassiopee/XCore/XCore/intersectMesh/AABB.h index b34155205..ebafdafa2 100644 --- a/Cassiopee/XCore/XCore/intersectMesh/AABB.h +++ b/Cassiopee/XCore/XCore/intersectMesh/AABB.h @@ -9,9 +9,12 @@ struct AABB { E_Float xmax; E_Float ymax; E_Float zmax; + E_Float dx; + E_Float dy; + E_Float dz; }; const AABB AABB_HUGE = {EFLOATMIN, EFLOATMIN, EFLOATMIN, EFLOATMAX, EFLOATMAX, EFLOATMAX}; -void AABB_clamp(AABB &box, const AABB &parent); \ No newline at end of file +void AABB_clamp(AABB &box, const AABB &parent); diff --git a/Cassiopee/XCore/XCore/intersectMesh/BVH.h b/Cassiopee/XCore/XCore/intersectMesh/BVH.h index 458bea6d7..026e1c6b0 100644 --- a/Cassiopee/XCore/XCore/intersectMesh/BVH.h +++ b/Cassiopee/XCore/XCore/intersectMesh/BVH.h @@ -4,8 +4,6 @@ struct BVH_node { AABB box = AABB_HUGE; - E_Int start = -1; - E_Int end = -1; - BVH_node *left = NULL; - BVH_node *right = NULL; -}; \ No newline at end of file + E_Int left_node, first_tri_idx, tri_count; + bool is_leaf() const { return tri_count > 0; } +}; diff --git a/Cassiopee/XCore/XCore/intersectMesh/icapsule_refine.cpp b/Cassiopee/XCore/XCore/intersectMesh/icapsule_refine.cpp index 460df4a6c..385b5ffd1 100644 --- a/Cassiopee/XCore/XCore/intersectMesh/icapsule_refine.cpp +++ b/Cassiopee/XCore/XCore/intersectMesh/icapsule_refine.cpp @@ -4,85 +4,6 @@ #include "io.h" #include "primitives.h" -// Returns a list of all the intersections, forwards and backwards -// Up to the caller to parse the data -void Smesh::ray_BVH_intersect(E_Float ox, E_Float oy, E_Float oz, - E_Float dx, E_Float dy, E_Float dz, BVH_node *node, - std::vector &plocs) const -{ - bool hit = ray_AABB_intersect(ox, oy, oz, dx, dy, dz, node->box); - if (!hit) return; - - if (!node->left && !node->right) { - for (E_Int i = node->start; i < node->end; i++) { - E_Int fid = bvh_fids[i]; - const auto &pn = Fc[fid]; - const E_Float *fc = &fcenters[3*fid]; - - for (size_t j = 0; j < pn.size(); j++) { - E_Int p = pn[j]; - E_Int q = pn[(j+1)%pn.size()]; - - E_Float u, v, w, t, x, y, z; - - bool hit = MollerTrumboreAnyDir( - ox, oy, oz, dx, dy, dz, - X[p], Y[p], Z[p], - X[q], Y[q], Z[q], - fc[0], fc[1], fc[2], - u, v, w, t, x, y, z - ); - - if (hit) { - PointLoc ploc; - ploc.fid = fid; - ploc.sub = j; - ploc.bcrd[0] = u; - ploc.bcrd[1] = v; - ploc.bcrd[2] = w; - ploc.t = t; - ploc.x = x; - ploc.y = y; - ploc.z = z; - - // on p - if (Sign(1-u, NEAR_VERTEX_TOL) == 0) { - ploc.v_idx = j; - ploc.bcrd[0] = 1, ploc.bcrd[1] = 0, ploc.bcrd[2] = 0; - ploc.x = X[p]; - ploc.y = Y[p]; - ploc.z = Z[p]; - } - // on q - else if (Sign(1-v, NEAR_VERTEX_TOL) == 0) { - ploc.v_idx = (j+1)%pn.size(); - ploc.bcrd[0] = 0, ploc.bcrd[1] = 1, ploc.bcrd[2] = 0; - ploc.x = X[q]; - ploc.y = Y[q]; - ploc.z = Z[q]; - } - // on edge {p, q} - else if (Sign(w, NEAR_EDGE_TOL) == 0) { - ploc.e_idx = j; - ploc.bcrd[0] = u, ploc.bcrd[1] = 1-u, ploc.bcrd[2] = 0; - ploc.x = u*X[p] + (1-u)*X[q]; - ploc.y = u*Y[p] + (1-u)*Y[q]; - ploc.z = u*Z[p] + (1-u)*Z[q]; - } - - plocs.push_back(ploc); - - break; - } - } - } - return; - } - - ray_BVH_intersect(ox, oy, oz, dx, dy, dz, node->left, plocs); - ray_BVH_intersect(ox, oy, oz, dx, dy, dz, node->right, plocs); -} - std::vector Smesh::project(const Smesh &Mf, const std::vector &mpids) const { @@ -91,13 +12,12 @@ std::vector Smesh::project(const Smesh &Mf, for (size_t i = 0; i < mpids.size(); i++) { E_Int mpid = mpids[i]; - //printf("%lu\n", i); const E_Float *N = &Mf.pnormals[3*mpid]; E_Float mx = Mf.X[mpid]; E_Float my = Mf.Y[mpid]; E_Float mz = Mf.Z[mpid]; std::vector mlocs; // to parse - ray_BVH_intersect(mx, my, mz, N[0], N[1], N[2], bvh_root, mlocs); + ray_intersect_BVH(mx, my, mz, N[0], N[1], N[2], root_node_idx, mlocs); PointLoc ploc; E_Float min_abs_t = EFLOATMAX; for (const auto &mloc : mlocs) { @@ -179,10 +99,6 @@ std::vector ICapsule::refine(Smesh &Mf, std::set &mfids, std::vector fat_mfids; Sf.make_BVH(); - //Mf.make_BVH(mfids); - - //Sf.make_bbox(); - //Sf.hash_faces(); Mf.make_bbox(); Mf.hash_faces(); @@ -246,8 +162,6 @@ std::vector ICapsule::refine(Smesh &Mf, std::set &mfids, Sf.make_pnormals(); } - //Mf.destroy_BVH(Mf.bvh_root); - Sf.destroy_BVH(Sf.bvh_root); } while (ref_M > 0 || ref_S > 0); return plocs_s; diff --git a/Cassiopee/XCore/XCore/intersectMesh/removeIntersectingKPlanes.cpp b/Cassiopee/XCore/XCore/intersectMesh/removeIntersectingKPlanes.cpp index 152d89f6d..31962019a 100644 --- a/Cassiopee/XCore/XCore/intersectMesh/removeIntersectingKPlanes.cpp +++ b/Cassiopee/XCore/XCore/intersectMesh/removeIntersectingKPlanes.cpp @@ -133,7 +133,7 @@ PyObject *handle_slave(const IMesh *M, const Smesh &Mf, Karray& sarray) */ std::vector mlocs; - Mf.ray_BVH_intersect(px, py, pz, dx, dy, dz, Mf.bvh_root, mlocs); + Mf.ray_intersect_BVH(px, py, pz, dx, dy, dz, Mf.root_node_idx, mlocs); PointLoc ploc; E_Float min_abs_t = EFLOATMAX; for (const auto &mloc : mlocs) { @@ -549,7 +549,6 @@ PyObject *K_XCORE::removeIntersectingKPlanes(PyObject *self, PyObject *args) M->make_skin(); M->make_bbox(); M->hash_skin(); - //M->make_bvh(); Smesh Mf = Smesh::Smesh_from_mesh_skin(*M, M->skin, false); printf("Mf: %d tris\n", Mf.nf); @@ -602,7 +601,5 @@ PyObject *K_XCORE::removeIntersectingKPlanes(PyObject *self, PyObject *args) Karray_free_structured(sarrays[i]); } - Mf.destroy_BVH(Mf.bvh_root); - return slaves_out; } diff --git a/Cassiopee/XCore/XCore/intersectMesh/smesh.h b/Cassiopee/XCore/XCore/intersectMesh/smesh.h index 533caf429..5ca20e743 100644 --- a/Cassiopee/XCore/XCore/intersectMesh/smesh.h +++ b/Cassiopee/XCore/XCore/intersectMesh/smesh.h @@ -25,10 +25,10 @@ #include "xcore.h" #include "point.h" +#include "BVH.h" struct IMesh; struct AABB; -struct BVH_node; struct o_edge { E_Int p, q; @@ -113,9 +113,6 @@ struct Smesh { const std::vector &mpids) const; void replace_by_projections(const std::vector &pids, const std::vector &plocs); - void ray_BVH_intersect(E_Float ox, E_Float oy, E_Float oz, - E_Float dx, E_Float dy, E_Float dz, BVH_node *node, - std::vector &plocs) const; inline void compute_face_center(E_Int fid); // Hash @@ -124,9 +121,6 @@ struct Smesh { E_Float xmin, xmax, ymin, ymax, zmin, zmax; E_Float HX, HY, HZ; std::map> bin_faces; - std::vector bvh_fids; - static const E_Int MAX_FACES_PER_BVH_LEAF = 8; - BVH_node *bvh_root = NULL; void make_bbox(); inline void bin_face(E_Int fid); @@ -135,13 +129,21 @@ struct Smesh { { return i + NX*j + NXY*k; } + + + // BVH + + E_Int root_node_idx, nodes_used; + std::vector tri_idx; + std::vector bvh_nodes; + static const E_Int MAX_TRIS_PER_BVH_LEAF = 2; void make_BVH(); void make_BVH(const std::set &fids); - AABB make_AABB(E_Int start, E_Int end); - BVH_node *make_BVH_node(const AABB &box, E_Int start, E_Int end, - BVH_node *left, BVH_node *right); - BVH_node *make_BVH_subtree(E_Int start, E_Int end, const AABB &parent); - void destroy_BVH(BVH_node *root); + void update_node_bounds(E_Int node_idx); + void BVH_subdivide(E_Int node_idx); + void ray_intersect_BVH(E_Float ox, E_Float oy, E_Float oz, + E_Float dx, E_Float dy, E_Float dz, E_Int node_idx, + std::vector &plocs) const; // Adaptation diff --git a/Cassiopee/XCore/XCore/intersectMesh/smesh_bvh.cpp b/Cassiopee/XCore/XCore/intersectMesh/smesh_bvh.cpp index 5202ee5d3..5289eeb83 100644 --- a/Cassiopee/XCore/XCore/intersectMesh/smesh_bvh.cpp +++ b/Cassiopee/XCore/XCore/intersectMesh/smesh_bvh.cpp @@ -1,7 +1,9 @@ #include "smesh.h" -#include "AABB.h" #include "BVH.h" +#include "ray.h" +#include "primitives.h" +/* AABB Smesh::make_AABB(E_Int start, E_Int end) { E_Float xmin, ymin, zmin, xmax, ymax, zmax; @@ -34,84 +36,211 @@ AABB Smesh::make_AABB(E_Int start, E_Int end) return {xmin, ymin, zmin, xmax, ymax, zmax}; } +*/ -BVH_node *Smesh::make_BVH_node(const AABB &box, E_Int start, E_Int end, - BVH_node *left, BVH_node *right) +void Smesh::make_BVH() { - BVH_node *node = new BVH_node; - node->box = box; - node->start = start; - node->end = end; - node->left = left; - node->right = right; - return node; + bvh_nodes.clear(); + bvh_nodes.resize(2*nf - 1); + root_node_idx = 0, nodes_used = 1; + + tri_idx.clear(); + tri_idx.resize(nf); + for (E_Int i = 0; i < nf; i++) tri_idx[i] = i; + assert(fcenters.size() == nf*3); + + // Assign all triangles to root node + BVH_node &root = bvh_nodes[root_node_idx]; + root.left_node = 1; + root.first_tri_idx = 0; + root.tri_count = nf; + update_node_bounds(root_node_idx); + BVH_subdivide(root_node_idx); } -BVH_node *Smesh::make_BVH_subtree(E_Int start, E_Int end, const AABB &parent) +void Smesh::update_node_bounds(E_Int node_idx) { - AABB box = make_AABB(start, end); - AABB_clamp(box, parent); - - E_Int count = end - start; - if (count <= Smesh::MAX_FACES_PER_BVH_LEAF) { - return make_BVH_node(box, start, end, NULL, NULL); - } - - E_Float dx = box.xmax - box.xmin; - E_Float dy = box.ymax - box.ymin; - E_Float dz = box.zmax - box.zmin; - - E_Int dim = -1; - if (dx >= dy && dx >= dz) { - dim = 0; - } else if (dy >= dz) { - dim = 1; - } else { - dim = 2; - } - - std::sort(bvh_fids.begin() + start, bvh_fids.begin() + end, - [&] (E_Int fi, E_Int fj) { - E_Float *fci = &fcenters[3*fi]; - E_Float *fcj = &fcenters[3*fj]; - return fci[dim] < fcj[dim]; + BVH_node &node = bvh_nodes[node_idx]; + node.box.xmin = node.box.ymin = node.box.zmin = EFLOATMAX; + node.box.xmax = node.box.ymax = node.box.zmax = EFLOATMIN; + for (E_Int first = node.first_tri_idx, i = 0; i < node.tri_count; i++) { + E_Int leaf_tri_idx = tri_idx[first + i]; + const auto &pn = F[leaf_tri_idx]; + for (E_Int p : pn) { + node.box.xmin = std::min(node.box.xmin, X[p]); + node.box.ymin = std::min(node.box.ymin, Y[p]); + node.box.zmin = std::min(node.box.zmin, Z[p]); + node.box.xmax = std::max(node.box.xmax, X[p]); + node.box.ymax = std::max(node.box.ymax, Y[p]); + node.box.zmax = std::max(node.box.zmax, Z[p]); } - ); - - E_Int mid = start + count/2; - - BVH_node *left = make_BVH_subtree(start, mid, box); - BVH_node *right = make_BVH_subtree(mid, end, box); - - return make_BVH_node(box, start, end, left, right); + node.box.dx = node.box.xmax - node.box.xmin; + node.box.dy = node.box.ymax - node.box.ymin; + node.box.dz = node.box.zmax - node.box.zmin; + } } -void Smesh::make_BVH() +void Smesh::BVH_subdivide(E_Int node_idx) { - bvh_fids.clear(); - bvh_fids.reserve(nf); - for (E_Int i = 0; i < nf; i++) { - bvh_fids.push_back(i); + // Terminate recursion + BVH_node &node = bvh_nodes[node_idx]; + if (node.tri_count <= MAX_TRIS_PER_BVH_LEAF) return; + + // Determine split axis and position + int axis; + E_Float split_pos; + if (node.box.dx > node.box.dy && node.box.dx > node.box.dz) { + axis = 0; + split_pos = node.box.xmin + node.box.dx*0.5; + } + else if (node.box.dy > node.box.dz) { + axis = 1; + split_pos = node.box.ymin + node.box.dy*0.5; + } + else { + axis = 2; + split_pos = node.box.zmin + node.box.dz*0.5; } - bvh_root = make_BVH_subtree(0, nf, AABB_HUGE); + // In-place partition + E_Int i = node.first_tri_idx; + E_Int j = i + node.tri_count - 1; + while (i <= j) { + const E_Float *fc = &fcenters[3*tri_idx[i]]; + if (fc[axis] < split_pos) + i++; + else + std::swap(tri_idx[i], tri_idx[j--]); + } + + // Abort split if one of the sides is empty + E_Int left_count = i - node.first_tri_idx; + if (left_count == 0 || left_count == node.tri_count) return; + + // Create child nodes + E_Int left_child_idx = nodes_used++; + E_Int right_child_idx = nodes_used++; + bvh_nodes[left_child_idx].first_tri_idx = node.first_tri_idx; + bvh_nodes[left_child_idx].tri_count = left_count; + bvh_nodes[right_child_idx].first_tri_idx = i; + bvh_nodes[right_child_idx].tri_count = node.tri_count - left_count; + node.left_node = left_child_idx; + node.tri_count = 0; + update_node_bounds(left_child_idx); + update_node_bounds(right_child_idx); + + // Recurse + BVH_subdivide(left_child_idx); + BVH_subdivide(right_child_idx); } void Smesh::make_BVH(const std::set &fids) { - bvh_fids.clear(); - bvh_fids.reserve(fids.size()); - for (auto fid : fids) bvh_fids.push_back(fid); - - bvh_root = make_BVH_subtree(0, fids.size(), AABB_HUGE); + bvh_nodes.clear(); + size_t NF = fids.size(); + bvh_nodes.resize(2*NF - 1); + root_node_idx = 0, nodes_used = 1; + + tri_idx.clear(); + tri_idx.reserve(NF); + for (E_Int fid : fids) tri_idx.push_back(fid); + + // Assign all triangles to root node + BVH_node &root = bvh_nodes[root_node_idx]; + root.left_node = 1; + root.first_tri_idx = 0; + root.tri_count = NF; + update_node_bounds(root_node_idx); + BVH_subdivide(root_node_idx); } -void Smesh::destroy_BVH(BVH_node *root) +static +bool ray_intersect_AABB(E_Float ox, E_Float oy, E_Float oz, + E_Float dx, E_Float dy, E_Float dz, const AABB &box) { - if (root == NULL) return; + E_Float tx1 = (box.xmin - ox) / dx, tx2 = (box.xmax - ox) / dx; + E_Float tmin = std::min(tx1, tx2), tmax = std::max(tx1, tx2); + E_Float ty1 = (box.ymin - oy) / dy, ty2 = (box.ymax - oy) / dy; + tmin = std::max(tmin, std::min(ty1, ty2)); + tmax = std::min(tmax, std::max(ty1, ty2)); + E_Float tz1 = (box.zmin - oz) / dz, tz2 = (box.zmax - oz) / dz; + tmin = std::max(tmin, std::min(tz1, tz2)); + tmax = std::min(tmax, std::max(tz1, tz2)); + return tmax >= tmin; +} - destroy_BVH(root->left); - destroy_BVH(root->right); +void Smesh::ray_intersect_BVH(E_Float ox, E_Float oy, E_Float oz, + E_Float dx, E_Float dy, E_Float dz, E_Int node_idx, + std::vector &plocs) const +{ + const BVH_node &node = bvh_nodes[node_idx]; + if (!ray_intersect_AABB(ox, oy, oz, dx, dy, dz, node.box)) return; + if (node.is_leaf()) { + for (E_Int i = 0; i < node.tri_count; i++) { + E_Int tri = tri_idx[node.first_tri_idx+i]; + const auto &pn = Fc[tri]; + const E_Float *fc = &fcenters[3*tri]; + + for (size_t j = 0; j < pn.size(); j++) { + E_Int p = pn[j]; + E_Int q = pn[(j+1)%pn.size()]; + E_Float u, v, w, t, x, y, z; + + bool hit = MollerTrumboreAnyDir( + ox, oy, oz, dx, dy, dz, + X[p], Y[p], Z[p], + X[q], Y[q], Z[q], + fc[0], fc[1], fc[2], + u, v, w, t, x, y, z + ); + + if (hit) { + PointLoc ploc; + ploc.fid = tri; + ploc.sub = j; + ploc.bcrd[0] = u; + ploc.bcrd[1] = v; + ploc.bcrd[2] = w; + ploc.t = t; + ploc.x = x; + ploc.y = y; + ploc.z = z; + + // on p + if (Sign(1-u, NEAR_VERTEX_TOL) == 0) { + ploc.v_idx = j; + ploc.bcrd[0] = 1, ploc.bcrd[1] = 0, ploc.bcrd[2] = 0; + ploc.x = X[p]; + ploc.y = Y[p]; + ploc.z = Z[p]; + } + // on q + else if (Sign(1-v, NEAR_VERTEX_TOL) == 0) { + ploc.v_idx = (j+1)%pn.size(); + ploc.bcrd[0] = 0, ploc.bcrd[1] = 1, ploc.bcrd[2] = 0; + ploc.x = X[q]; + ploc.y = Y[q]; + ploc.z = Z[q]; + } + // on edge {p, q} + else if (Sign(w, NEAR_EDGE_TOL) == 0) { + ploc.e_idx = j; + ploc.bcrd[0] = u, ploc.bcrd[1] = 1-u, ploc.bcrd[2] = 0; + ploc.x = u*X[p] + (1-u)*X[q]; + ploc.y = u*Y[p] + (1-u)*Y[q]; + ploc.z = u*Z[p] + (1-u)*Z[q]; + } + + plocs.push_back(ploc); + + break; + } + } + } + return ; + } - delete root; + ray_intersect_BVH(ox, oy, oz, dx, dy, dz, node.left_node, plocs); + ray_intersect_BVH(ox, oy, oz, dx, dy, dz, node.left_node+1, plocs); } + From ee9816c7d7adc6030e333e27c24081582de8c08d Mon Sep 17 00:00:00 2001 From: imadhammani Date: Mon, 4 Nov 2024 13:50:47 +0100 Subject: [PATCH 74/86] XCore intersectMesh: ok adaptation loop --- .../intersectMesh/IntersectMesh_Init.cpp | 2 +- Cassiopee/XCore/XCore/intersectMesh/dcel.h | 2 + .../XCore/intersectMesh/dcel_extract.cpp | 93 ++++++- .../XCore/XCore/intersectMesh/extract.cpp | 2 +- .../XCore/XCore/intersectMesh/icapsule.cpp | 96 +++++-- .../XCore/XCore/intersectMesh/icapsule.h | 3 + .../XCore/intersectMesh/icapsule_refine.cpp | 2 - Cassiopee/XCore/XCore/intersectMesh/mesh.cpp | 231 +++-------------- Cassiopee/XCore/XCore/intersectMesh/mesh.h | 21 +- .../XCore/XCore/intersectMesh/mesh_io.cpp | 155 ++++++++++++ Cassiopee/XCore/XCore/intersectMesh/smesh.cpp | 239 ++++++++---------- Cassiopee/XCore/XCore/intersectMesh/smesh.h | 14 +- .../XCore/intersectMesh/smesh_reconstruct.cpp | 198 +++++++++++++++ .../XCore/intersectMesh/smesh_refine.cpp | 4 - .../XCore/XCore/intersectMesh/triangulate.cpp | 5 + Cassiopee/XCore/srcs.py | 3 + 16 files changed, 683 insertions(+), 387 deletions(-) create mode 100644 Cassiopee/XCore/XCore/intersectMesh/mesh_io.cpp create mode 100644 Cassiopee/XCore/XCore/intersectMesh/smesh_reconstruct.cpp diff --git a/Cassiopee/XCore/XCore/intersectMesh/IntersectMesh_Init.cpp b/Cassiopee/XCore/XCore/intersectMesh/IntersectMesh_Init.cpp index 2f46a16d5..baf1395aa 100644 --- a/Cassiopee/XCore/XCore/intersectMesh/IntersectMesh_Init.cpp +++ b/Cassiopee/XCore/XCore/intersectMesh/IntersectMesh_Init.cpp @@ -39,7 +39,7 @@ PyObject *K_XCORE::IntersectMesh_Init(PyObject *self, PyObject *args) // Init mesh - IMesh *M = new IMesh(*karray.cn, karray.X(), karray.Y(), karray.Z(), karray.npts); + IMesh *M = new IMesh(karray); /* M->make_skin(); puts("Making BVH"); diff --git a/Cassiopee/XCore/XCore/intersectMesh/dcel.h b/Cassiopee/XCore/XCore/intersectMesh/dcel.h index eff8d77d5..037e84a60 100644 --- a/Cassiopee/XCore/XCore/intersectMesh/dcel.h +++ b/Cassiopee/XCore/XCore/intersectMesh/dcel.h @@ -149,6 +149,8 @@ struct Dcel { Smesh export_smesh(bool check_Euler=true) const; Smesh reconstruct(const Smesh &Mf, int color, bool check_Euler) const; + void reconstruct_smesh(Smesh &Mf, int color, bool check_Euler) const; + // Extract diff --git a/Cassiopee/XCore/XCore/intersectMesh/dcel_extract.cpp b/Cassiopee/XCore/XCore/intersectMesh/dcel_extract.cpp index 9eb0fc2d1..3cd0262c0 100644 --- a/Cassiopee/XCore/XCore/intersectMesh/dcel_extract.cpp +++ b/Cassiopee/XCore/XCore/intersectMesh/dcel_extract.cpp @@ -1,6 +1,97 @@ #include "dcel.h" #include "smesh.h" +void Dcel::reconstruct_smesh(Smesh &Mf, int color, bool check_Euler) const +{ + std::map> oid_to_faces; + + std::map new_pids; + + E_Int NP = Mf.np; + + E_Int face_incr = 0; + + // Which faces to keep? + for (Face *f : F) { + if (f->oids[color] == -1) continue; + + oid_to_faces[f->oids[color]].push_back(f); + + // Which points to keep? + + auto vertices = get_face_vertices(f); + + for (Vertex *v : vertices) { + auto it = new_pids.find(v); + if (it == new_pids.end()) { + // Was this point before the intersection? + if (v->oids[color] != -1) { + // Yes, keep its original id + new_pids[v] = v->oids[color]; + } else { + // No, add it + new_pids[v] = NP++; + } + } + } + + face_incr++; + } + + face_incr -= oid_to_faces.size(); + + // Replace the old faces with the new intersection faces + + Mf.F.resize(Mf.nf+face_incr); + Mf.Fc.resize(Mf.nf+face_incr); + E_Int NF = Mf.nf; + for (const auto &fdat : oid_to_faces) { + E_Int fid = fdat.first; + const auto &faces = fdat.second; + + std::vector new_pn; + + // Replace fid with the first face and add the rest of the faces + for (size_t i = 0; i < faces.size(); i++) { + new_pn.clear(); + auto vertices = get_face_vertices(faces[i]); + for (Vertex *v : vertices) new_pn.push_back(new_pids[v]); + if (i > 0) { + Mf.F[NF] = new_pn; + Mf.Fc[NF] = new_pn; + NF++; + } else { + Mf.F[fid] = new_pn; + Mf.Fc[fid] = new_pn; + } + } + } + + + // Resize the points + Mf.X.resize(NP, EFLOATMAX); + Mf.Y.resize(NP, EFLOATMAX); + Mf.Z.resize(NP, EFLOATMAX); + + for (const auto &vdat : new_pids) { + Vertex *v = vdat.first; + E_Int new_pid = vdat.second; + if (v->oids[color] == -1) { + assert(Mf.X[new_pid] == EFLOATMAX); + assert(Mf.Y[new_pid] == EFLOATMAX); + assert(Mf.Z[new_pid] == EFLOATMAX); + Mf.X[new_pid] = v->x; + Mf.Y[new_pid] = v->y; + Mf.Z[new_pid] = v->z; + } + } + + + Mf.nf = NF; + Mf.np = NP; +} + + Smesh Dcel::export_smesh(bool check_Euler) const { Smesh smesh; @@ -66,4 +157,4 @@ std::vector Dcel::extract_indices_of_type(int type) const } return ret; -} \ No newline at end of file +} diff --git a/Cassiopee/XCore/XCore/intersectMesh/extract.cpp b/Cassiopee/XCore/XCore/intersectMesh/extract.cpp index 5d9edb524..50b432743 100644 --- a/Cassiopee/XCore/XCore/intersectMesh/extract.cpp +++ b/Cassiopee/XCore/XCore/intersectMesh/extract.cpp @@ -19,7 +19,7 @@ PyObject *K_XCORE::extractCell(PyObject *self, PyObject *args) if (ret != 0) return NULL; - IMesh M(*marray.cn, marray.X(), marray.Y(), marray.Z(), marray.npts); + IMesh M(marray); IMesh M_out; diff --git a/Cassiopee/XCore/XCore/intersectMesh/icapsule.cpp b/Cassiopee/XCore/XCore/intersectMesh/icapsule.cpp index ae4ff813e..733895020 100644 --- a/Cassiopee/XCore/XCore/intersectMesh/icapsule.cpp +++ b/Cassiopee/XCore/XCore/intersectMesh/icapsule.cpp @@ -10,16 +10,31 @@ ICapsule ICapsule::do_it(const Karray &marray, const std::vector &sarrays, const std::vector &ptags) { + ICapsule icap; + auto &M = icap.M; + auto &Ss = icap.Ss; + E_Float NEAR_VERTEX_TOL = 1e-3; E_Float NEAR_EDGE_TOL = 1e-3; - auto M = IMesh(marray); + + puts("Creating mesh from karray"); + M = IMesh(marray); M.set_tolerances(NEAR_VERTEX_TOL, NEAR_EDGE_TOL); + puts("Making skin"); M.make_skin(); + puts("Orienting skin"); M.orient_skin(OUT); + puts("Triangulating skin"); M.triangulate_skin(); + puts("Making edge data"); + M.make_edges(); + puts("Making bbox"); M.make_bbox(); + puts("Hashing skin"); M.hash_skin(); + puts("Creating surface mesh"); Smesh Mf(M, M.skin, false); + puts("Making surface mesh data"); Mf.make_bbox(); Mf.hash_faces(); Mf.make_fcenters(); @@ -28,6 +43,10 @@ ICapsule ICapsule::do_it(const Karray &marray, Mf.write_ngon("Mf_raw.im"); + Ss.reserve(sarrays.size()); + + // Adapt + for (size_t i = 0; i < sarrays.size(); i++) { printf("S%lu\n", i); @@ -38,10 +57,16 @@ ICapsule ICapsule::do_it(const Karray &marray, S.make_skin(); S.orient_skin(IN); S.triangulate_skin(); + S.make_edges(); // Create SMesh Sf Smesh Sf = Smesh::Smesh_from_point_tags(S, ptags[i], true); + for (E_Int fid = 0; fid < Sf.nf; fid++) { + E_Int gfid = Sf.l2gf.at(fid); + assert(S.neigh[gfid] == -1); + } + Sf.make_fcenters(); Sf.make_fnormals(); Sf.make_pnormals(); @@ -62,12 +87,39 @@ ICapsule ICapsule::do_it(const Karray &marray, auto bfaces = Mf.extract_covering_faces(Sf, plocs); // Refinement loop - plocs = refine(Mf, bfaces, Sf); + refine(Mf, bfaces, Sf); + + // Reconstruct S + Sf.reconstruct(S); + + // TODO(Imad): Tag Sf faces + Sf.tag_faces(S); + + // Append + Ss.push_back(S); + + puts(""); + } + + Mf.reconstruct(M); + + return icap; + + /* + // Intersect + + for (size_t i = 0; i < sarrays.size(); i++) { + + // Make Sf + Smesh Sf = Smesh::Smesh_from_tagged_faces(Ss[i], true); - bfaces = Mf.extract_covering_faces(Sf, plocs); + // Make Bf + M.make_skin(); + Smesh Mf(M, M.skin, false); + auto plocs = Mf.locate(Sf); - // Make a patch out of Mf bounding faces - Smesh Bf(Mf, bfaces, false); + auto bfaces = Mf.extract_covering_faces(Sf, plocs); + Smesh Bf = Smesh::make_sub(Mf, bfaces, false); Bf.make_fcenters(); Bf.make_fnormals(); Bf.make_pnormals(); @@ -76,19 +128,13 @@ ICapsule ICapsule::do_it(const Karray &marray, plocs = Bf.locate(Sf); - Bf.write_ngon("Bf.im"); - Sf.write_ngon("Sf.im"); - - /* - { - Dcel Db(Bf, Dcel::RED); - Dcel Ds(Sf, Dcel::BLACK); - } - */ - // Intersect Dcel D(Bf, Sf, plocs); + // Reconstruct Bf and Sf + D.reconstruct_smesh(Bf, Dcel::RED, false); + D.reconstruct_smesh(Sf, Dcel::BLACK, true); + { Smesh new_Bf = D.reconstruct(Bf, Dcel::RED, false); new_Bf.write_ngon("new_Bf.im"); @@ -98,19 +144,20 @@ ICapsule ICapsule::do_it(const Karray &marray, puts("reconstruted new Sf"); } + // Reconstruct M and S + Bf.reconstruct(M); + Sf.reconstruct(Ss[i]); + puts(""); } Mf.write_ngon("refined_Mf.im"); - - return ICapsule(); + */ } PyObject *K_XCORE::icapsule_extract_master(PyObject *self, PyObject *args) { - return Py_None; - /* PyObject *ICAPSULE; if (!PYPARSETUPLE_(args, O_, &ICAPSULE)) { RAISE("Bad input."); @@ -127,13 +174,10 @@ PyObject *K_XCORE::icapsule_extract_master(PyObject *self, PyObject *args) auto Mout = icap->M.export_karray(); return Mout; - */ } PyObject *K_XCORE::icapsule_extract_slave(PyObject *self, PyObject *args) { - return Py_None; - /* PyObject *ICAPSULE; E_Int INDEX; if (!PYPARSETUPLE_(args, O_ I_, &ICAPSULE, &INDEX)) { @@ -156,7 +200,6 @@ PyObject *K_XCORE::icapsule_extract_slave(PyObject *self, PyObject *args) auto Sout = icap->Ss[INDEX].export_karray(); return Sout; - */ } PyObject *K_XCORE::icapsule_init(PyObject *self, PyObject *args) @@ -219,11 +262,14 @@ PyObject *K_XCORE::icapsule_init(PyObject *self, PyObject *args) } } - ICapsule::do_it(marray, sarrays, ptags); + ICapsule *icap = new ICapsule(); + *icap = ICapsule::do_it(marray, sarrays, ptags); Karray_free_ngon(marray); for (E_Int i = 0; i < nslaves; i++) Karray_free_ngon(sarrays[i]); + + PyObject *hook = PyCapsule_New((void *)icap, "ICapsule", NULL); - return Py_None; + return hook; } diff --git a/Cassiopee/XCore/XCore/intersectMesh/icapsule.h b/Cassiopee/XCore/XCore/intersectMesh/icapsule.h index 17b7db3a5..382d49f13 100644 --- a/Cassiopee/XCore/XCore/intersectMesh/icapsule.h +++ b/Cassiopee/XCore/XCore/intersectMesh/icapsule.h @@ -3,6 +3,9 @@ #include "mesh.h" struct ICapsule { + IMesh M; + std::vector Ss; + static ICapsule do_it(const Karray &marray, const std::vector &sarray, const std::vector &ptags); diff --git a/Cassiopee/XCore/XCore/intersectMesh/icapsule_refine.cpp b/Cassiopee/XCore/XCore/intersectMesh/icapsule_refine.cpp index 385b5ffd1..85a81e973 100644 --- a/Cassiopee/XCore/XCore/intersectMesh/icapsule_refine.cpp +++ b/Cassiopee/XCore/XCore/intersectMesh/icapsule_refine.cpp @@ -144,9 +144,7 @@ std::vector ICapsule::refine(Smesh &Mf, std::set &mfids, for (E_Int p : mpids_set) mpids.push_back(p); // Project mpids on Sf - puts("making Sf centers"); Sf.make_fcenters(); - puts("projecting mpids on Sf"); auto plocs_m = Sf.project(Mf, mpids); // Deduce sfids to refine diff --git a/Cassiopee/XCore/XCore/intersectMesh/mesh.cpp b/Cassiopee/XCore/XCore/intersectMesh/mesh.cpp index bca626da7..1c73cf88c 100644 --- a/Cassiopee/XCore/XCore/intersectMesh/mesh.cpp +++ b/Cassiopee/XCore/XCore/intersectMesh/mesh.cpp @@ -124,93 +124,62 @@ void IMesh::triangulate_face_set(bool propagate) F.resize(NF); } -struct DEdge { - E_Int p, q; - - DEdge(E_Int P, E_Int Q) : p(P), q(Q) {} - - bool operator<(const DEdge &f) const +struct o_edge_cmp { + bool operator()(const o_edge &e, const o_edge &f) const { - E_Int ep = std::min(p, q); - E_Int eq = std::max(p, q); - E_Int fp = std::min(f.p, f.q); - E_Int fq = std::max(f.p, f.q); - return (ep < fp) || (ep == fp && eq < fq); + E_Int e_p = std::min(e.p, e.q); + E_Int e_q = std::max(e.p, e.q); + E_Int f_p = std::min(f.p, f.q); + E_Int f_q = std::max(f.p, f.q); + return (e_p < f_p) || + (e_p == f_p && e_q < f_q); } }; void IMesh::make_edges() { - std::map edges; + F2E.clear(); + F2E.resize(F.size()); + std::map edges; + E.clear(); + assert(E.empty()); ne = 0; - F2E.resize(nf); - - for (E_Int i = 0; i < nf; i++) { - const auto &pn = F[i]; - - F2E[i].resize(pn.size()); - + for (E_Int fid = 0; fid < nf; fid++) { + auto &pn = F[fid]; for (size_t j = 0; j < pn.size(); j++) { E_Int p = pn[j]; E_Int q = pn[(j+1)%pn.size()]; - DEdge e(p, q); - auto it = edges.find(e); + o_edge EDGE(p, q); + auto it = edges.find(EDGE); if (it == edges.end()) { - F2E[i][j] = ne; - edges[e] = ne; + F2E[fid].push_back(ne); + edges[EDGE] = ne; + E.push_back(EDGE); ne++; } else { - F2E[i][j] = it->second; + F2E[fid].push_back(it->second); } } } - E.resize(ne); - - for (const auto &edata : edges) { - E[edata.second][0] = edata.first.p; - E[edata.second][1] = edata.first.q; - } -} - -void IMesh::init_adaptation_data() -{ - flevel.resize(nf, 0); - - for (E_Int i = 0; i < nf; i++) factive.insert(i); -} - -bool IMesh::faces_are_dups(E_Int mface, E_Int sface, const IMesh &S) -{ - const auto &pnm = F[mface]; - const auto &pns = S.F[sface]; + assert((size_t)ne == E.size()); - assert(face_is_quad(mface) || face_is_tri(mface)); - assert(S.face_is_quad(sface) || S.face_is_tri(sface)); + E2F.clear(); + E2F.resize(ne); - if (pnm.size() != pns.size()) return false; - - E_Int mfound[4] = { 0, 0, 0, 0 }; + for (E_Int fid = 0; fid < nf; fid++) { + const auto &pe = F2E[fid]; - for (size_t i = 0; i < pnm.size(); i++) { - E_Int pm = pnm[i]; - for (size_t j = 0; j < pns.size(); j++) { - E_Int ps = pns[j]; - if (cmp_points(X[pm], Y[pm], Z[pm], S.X[ps], S.Y[ps], S.Z[ps]) == 0) { - assert(mfound[i] == 0); - mfound[i] = 1; - break; - } + for (E_Int eid : pe) { + E2F[eid].push_back(fid); } - - if (mfound[i] == 0) return false; } - - return true; } + + IMesh::IMesh() {} @@ -250,63 +219,6 @@ IMesh::IMesh(const Karray &karray) } } -IMesh::IMesh(K_FLD::FldArrayI &cn, E_Float *x, E_Float *y, E_Float *z, E_Int npts) -{ - NX = 100; - NY = 100; - NZ = 100; - NXY = NX * NY; - NXYZ = NXY * NZ; - - np = npts; - ne = 0; - nf = cn.getNFaces(); - nc = cn.getNElts(); - - X.resize(np); - Y.resize(np); - Z.resize(np); - for (E_Int i = 0; i < np; i++) { - X[i] = x[i]; - Y[i] = y[i]; - Z[i] = z[i]; - } - - F.reserve(nf); - E_Int *indPG = cn.getIndPG(); - E_Int *ngon = cn.getNGon(); - for (E_Int i = 0; i < nf; i++) { - E_Int np = -1; - E_Int *pn = cn.getFace(i, np, ngon, indPG); - std::vector points(np); - for (E_Int j = 0; j < np; j++) - points[j] = pn[j] - 1; - F.push_back(points); - } - - C.reserve(nc); - E_Int *indPH = cn.getIndPH(); - E_Int *nface = cn.getNFace(); - for (E_Int i = 0; i < nc; i++) { - E_Int nf = -1; - E_Int *pf = cn.getElt(i, nf, nface, indPH); - std::vector faces(nf); - for (E_Int j = 0; j < nf; j++) - faces[j] = pf[j] - 1; - C.push_back(faces); - } - - //make_skin(); - - //make_bbox(); - - //hash_skin(); - - //make_point_faces(); - - //init_adaptation_data(); -} - void IMesh::make_point_faces() { P2F.clear(); @@ -812,89 +724,6 @@ void IMesh::write_face(const char *fname, E_Int fid) const fclose(fh); } -void IMesh::write_faces(const char *fname, const std::vector &faces) const -{ - FILE *fh = fopen(fname, "w"); - assert(fh); - - std::map new_pids; - std::map old_pids; - - E_Int npts = 0; - - for (E_Int face : faces) { - const auto &pn = F[face]; - - for (E_Int p : pn) { - if (new_pids.find(p) == new_pids.end()) { - new_pids[p] = npts; - old_pids[npts] = p; - npts++; - } - } - } - - fprintf(fh, "POINTS\n"); - fprintf(fh, "%d\n", npts); - for (E_Int i = 0; i < npts; i++) { - E_Int opid = old_pids[i]; - fprintf(fh, "%f %f %f\n", X[opid], Y[opid], Z[opid]); - } - - fclose(fh); -} - -void IMesh::write_ngon(const char *fname) -{ - FILE *fh = fopen(fname, "w"); - assert(fh); - - fprintf(fh, "POINTS\n"); - fprintf(fh, SF_D_ "\n", np); - for (E_Int i = 0; i < np; i++) { - fprintf(fh, "%f %f %f\n", X[i], Y[i], Z[i]); - } - - fprintf(fh, "INDPG\n"); - fprintf(fh, SF_D_ "\n", nf+1); - E_Int sizeNGon = 0; - fprintf(fh, SF_D_ " ", sizeNGon); - for (E_Int i = 0; i < nf; i++) { - sizeNGon += F[i].size(); - fprintf(fh, SF_D_ " ", sizeNGon); - } - fprintf(fh, "\n"); - - fprintf(fh, "NGON\n"); - fprintf(fh, SF_D_ "\n", sizeNGon); - for (E_Int i = 0; i < nf; i++) { - for (E_Int p : F[i]) - fprintf(fh, SF_D_ " ", p); - } - fprintf(fh, "\n"); - - fprintf(fh, "INDPH\n"); - fprintf(fh, SF_D_ "\n", nc+1); - E_Int sizeNFace = 0; - fprintf(fh, SF_D_ " ", sizeNFace); - for (E_Int i = 0; i < nc; i++) { - sizeNFace += C[i].size(); - fprintf(fh, SF_D_ " ", sizeNFace); - } - fprintf(fh, "\n"); - - fprintf(fh, "NFace\n"); - fprintf(fh, SF_D_ "\n", sizeNFace); - for (E_Int i = 0; i < nc; i++) { - for (E_Int p : C[i]) - fprintf(fh, SF_D_ " ", p); - } - fprintf(fh, "\n"); - - fclose(fh); -} - - bool IMesh::face_contains_sface(E_Int face, E_Int sface, const IMesh &S) const { // face containes mface iff it contains all its points diff --git a/Cassiopee/XCore/XCore/intersectMesh/mesh.h b/Cassiopee/XCore/XCore/intersectMesh/mesh.h index 9316a419c..992ab5f5d 100644 --- a/Cassiopee/XCore/XCore/intersectMesh/mesh.h +++ b/Cassiopee/XCore/XCore/intersectMesh/mesh.h @@ -62,11 +62,13 @@ struct IMesh { E_Int np, ne, nf, nc; std::vector X, Y, Z; + std::vector> F; + std::vector> P2F; + std::vector> P2E; - std::vector> E; - - std::vector> F; + std::vector E; + std::vector> E2F; std::vector> F2E; std::vector> C; @@ -74,7 +76,7 @@ struct IMesh { std::vector skin; std::vector owner; std::vector neigh; - Sgraph sgraph; + E_Float NEAR_VERTEX_TOL = 1e-3; E_Float NEAR_EDGE_TOL = 1e-3; @@ -87,8 +89,7 @@ struct IMesh { std::vector> bin_faces; std::set patch; - - std::vector entries; + std::vector ftag; std::vector ctag; @@ -98,8 +99,6 @@ struct IMesh { NEAR_EDGE_TOL = near_edge_tol; } - void make_skin_graph(); - inline E_Int get_voxel(E_Int I, E_Int J, E_Int K) const { return I + J * NX + (NX * NY) * K; @@ -125,7 +124,7 @@ struct IMesh { IMesh(const Karray &karray); - IMesh(K_FLD::FldArrayI &cn, E_Float *X, E_Float *Y, E_Float *Z, E_Int npts); + //IMesh(K_FLD::FldArrayI &cn, E_Float *X, E_Float *Y, E_Float *Z, E_Int npts); void make_patch(E_Int *faces, E_Int nfaces); @@ -147,7 +146,9 @@ struct IMesh { void write_ngon(const char *fname); - void write_faces(const char *fname, const std::vector &faces) const; + void write_ngon(const char *fname, const std::vector &faces) const; + + void write_ngon(const char *fname, const std::set &fset) const; void write_face(const char *fname, E_Int fid) const; diff --git a/Cassiopee/XCore/XCore/intersectMesh/mesh_io.cpp b/Cassiopee/XCore/XCore/intersectMesh/mesh_io.cpp new file mode 100644 index 000000000..22c686f62 --- /dev/null +++ b/Cassiopee/XCore/XCore/intersectMesh/mesh_io.cpp @@ -0,0 +1,155 @@ +#include "mesh.h" + +void IMesh::write_ngon(const char *fname, const std::set &fset) const +{ + std::vector flist; + flist.reserve(fset.size()); + for (E_Int fid : fset) flist.push_back(fid); + write_ngon(fname, flist); +} + +void IMesh::write_ngon(const char *fname, const std::vector &faces) const +{ + std::vector INDPH(faces.size() + 1); + INDPH[0] = 0; + + std::map new_pids; + std::map new_eids; + E_Int idx = 0; + E_Int NP = 0; + E_Int NE = 0; + E_Int NF = (E_Int)faces.size(); + + for (E_Int fid : faces) { + const auto &pn = F[fid]; + const auto &pe = F2E[fid]; + + INDPH[idx+1] = INDPH[idx] + (E_Int)pn.size(); + idx++; + + for (E_Int pid : pn) { + if (new_pids.find(pid) == new_pids.end()) { + new_pids[pid] = NP; + NP++; + } + } + + for (E_Int eid : pe) { + if (new_eids.find(eid) == new_eids.end()) { + new_eids[eid] = NE; + NE++; + } + } + } + + FILE *fh = fopen(fname, "w"); + assert(fh); + fprintf(fh, "POINTS\n"); + fprintf(fh, "%lu\n", new_pids.size()); + + std::vector nX(NP), nY(NP), nZ(NP); + for (const auto &pids : new_pids) { + E_Int opid = pids.first; + E_Int npid = pids.second; + nX[npid] = X[opid]; + nY[npid] = Y[opid]; + nZ[npid] = Z[opid]; + } + + for (E_Int pid = 0; pid < NP; pid++) { + fprintf(fh, "%f %f %f\n", nX[pid], nY[pid], nZ[pid]); + } + + fprintf(fh, "INDPG\n"); + fprintf(fh, "%lu\n", new_eids.size()+1); + E_Int sizeNGon = -2; + for (size_t i = 0; i < new_eids.size() + 1; i++) { + sizeNGon += 2; + fprintf(fh, "%d ", sizeNGon); + } + fprintf(fh, "\n"); + assert(sizeNGon == 2*NE); + + std::vector nE(new_eids.size(), {-1, -1}); + for (const auto &eids : new_eids) { + E_Int oeid = eids.first; + E_Int neid = eids.second; + nE[neid].p = new_pids[E[oeid].p]; + nE[neid].q = new_pids[E[oeid].q]; + } + + fprintf(fh, "NGON\n"); + fprintf(fh, "%d\n", 2*NE); + for (const auto &e : nE) { + fprintf(fh, "%d %d ", e.p, e.q); + } + fprintf(fh, "\n"); + + fprintf(fh, "INDPH\n"); + fprintf(fh, "%d\n", NF+1); + for (E_Int i = 0; i < NF+1; i++) + fprintf(fh, "%d ", INDPH[i]); + fprintf(fh, "\n"); + + fprintf(fh, "NFACE\n"); + fprintf(fh, "%d\n", INDPH[NF]); + for (size_t i = 0; i < faces.size(); i++) { + const auto &pe = F2E[faces[i]]; + for (E_Int eid : pe) { + fprintf(fh, "%d ", new_eids[eid]); + } + } + fprintf(fh, "\n"); + + fclose(fh); +} + +void IMesh::write_ngon(const char *fname) +{ + FILE *fh = fopen(fname, "w"); + assert(fh); + + fprintf(fh, "POINTS\n"); + fprintf(fh, SF_D_ "\n", np); + for (E_Int i = 0; i < np; i++) { + fprintf(fh, "%f %f %f\n", X[i], Y[i], Z[i]); + } + + fprintf(fh, "INDPG\n"); + fprintf(fh, SF_D_ "\n", nf+1); + E_Int sizeNGon = 0; + fprintf(fh, SF_D_ " ", sizeNGon); + for (E_Int i = 0; i < nf; i++) { + sizeNGon += F[i].size(); + fprintf(fh, SF_D_ " ", sizeNGon); + } + fprintf(fh, "\n"); + + fprintf(fh, "NGON\n"); + fprintf(fh, SF_D_ "\n", sizeNGon); + for (E_Int i = 0; i < nf; i++) { + for (E_Int p : F[i]) + fprintf(fh, SF_D_ " ", p); + } + fprintf(fh, "\n"); + + fprintf(fh, "INDPH\n"); + fprintf(fh, SF_D_ "\n", nc+1); + E_Int sizeNFace = 0; + fprintf(fh, SF_D_ " ", sizeNFace); + for (E_Int i = 0; i < nc; i++) { + sizeNFace += C[i].size(); + fprintf(fh, SF_D_ " ", sizeNFace); + } + fprintf(fh, "\n"); + + fprintf(fh, "NFace\n"); + fprintf(fh, SF_D_ "\n", sizeNFace); + for (E_Int i = 0; i < nc; i++) { + for (E_Int p : C[i]) + fprintf(fh, SF_D_ " ", p); + } + fprintf(fh, "\n"); + + fclose(fh); +} diff --git a/Cassiopee/XCore/XCore/intersectMesh/smesh.cpp b/Cassiopee/XCore/XCore/intersectMesh/smesh.cpp index 38c566634..cf383ba29 100644 --- a/Cassiopee/XCore/XCore/intersectMesh/smesh.cpp +++ b/Cassiopee/XCore/XCore/intersectMesh/smesh.cpp @@ -31,22 +31,18 @@ #include #include -#define LEFT 0 -#define RIGHT 1 - -void Smesh::get_edge_centers(E_Int p, E_Int q, std::list &edge_centers, - E_Int left_right) +void Smesh::get_edge_centers(E_Int p, E_Int q, std::vector &edge_centers) { u_edge e(p, q); auto it = ecenter.find(e); - if (it == ecenter.end()) return; + if (it == ecenter.end()) { + edge_centers.push_back(p); + return; + } E_Int ec = it->second; - if (left_right == LEFT) edge_centers.push_front(ec); - else edge_centers.push_back(ec); - - get_edge_centers(p, ec, edge_centers, LEFT); - get_edge_centers(ec, q, edge_centers, RIGHT); + get_edge_centers(p, ec, edge_centers); + get_edge_centers(ec, q, edge_centers); } void Smesh::clear_conformal_data() @@ -74,6 +70,7 @@ void Smesh::conformize() std::vector new_pn; + /* for (size_t i = 0; i < pn.size(); i++) { E_Int p = pn[i]; E_Int q = pn[(i+1)%pn.size()]; @@ -83,6 +80,18 @@ void Smesh::conformize() std::list edge_points; get_edge_centers(p, q, edge_points, LEFT); for (E_Int ep : edge_points) new_pn.push_back(ep); + assert(new_pn.back() != q); + } + */ + + for (size_t i = 0; i < pn.size(); i++) { + E_Int p = pn[i]; + E_Int q = pn[(i+1)%pn.size()]; + + std::vector local; + get_edge_centers(p, q, local); + for (E_Int p : local) new_pn.push_back(p); + assert(local[0] == p); } new_Fc[fid] = new_pn; @@ -98,10 +107,53 @@ void Smesh::conformize() Smesh::Smesh() {} -Smesh::Smesh(const Smesh &Mf, const std::set &fids, bool check_Euler_) +Smesh Smesh::Smesh_from_mesh_skin(const IMesh &M, + const std::vector &skin, bool check_Euler) { - NEAR_VERTEX_TOL = Mf.NEAR_VERTEX_TOL; - NEAR_EDGE_TOL = Mf.NEAR_EDGE_TOL; + return Smesh(M, skin, check_Euler); +} + +Smesh Smesh::Smesh_from_point_tags(const IMesh &M, const E_Float *ptag, + bool check_Euler) +{ + std::vector fids; + + for (E_Int fid : M.skin) { + const auto &pn = M.F[fid]; + bool keep = true; + for (E_Int pid : pn) { + if (ptag[pid] != 1) { + keep = false; + break; + } + } + if (keep) fids.push_back(fid); + } + + return Smesh(M, fids, check_Euler); +} + +Smesh Smesh::Smesh_from_mesh_patch(const IMesh &M, bool check_Euler) +{ + std::vector fids; + + for (E_Int fid : M.patch) { + fids.push_back(fid); + } + + return Smesh(M, fids, check_Euler); +} + +Smesh Smesh::Smesh_from_tagged_faces(const IMesh &M, bool check_Euler) +{ + assert(0); + return Smesh(); +} + +Smesh::Smesh(const IMesh &M, const std::vector &fids, bool check_Euler_) +{ + NEAR_VERTEX_TOL = M.NEAR_VERTEX_TOL; + NEAR_EDGE_TOL = M.NEAR_EDGE_TOL; check_Euler = check_Euler_; @@ -117,7 +169,7 @@ Smesh::Smesh(const Smesh &Mf, const std::set &fids, bool check_Euler_) auto &pn = F[nf]; - for (E_Int gp : Mf.Fc[gf]) { + for (E_Int gp : M.F[gf]) { auto it = g2lp.find(gp); if (it == g2lp.end()) { @@ -136,15 +188,19 @@ Smesh::Smesh(const Smesh &Mf, const std::set &fids, bool check_Euler_) assert((size_t)np == g2lp.size()); assert((size_t)np == l2gp.size()); + // Cache the original number of points and faces + np_before_adapt = np; + nf_before_adapt = nf; + // Get the points X.resize(np); Y.resize(np); Z.resize(np); for (const auto &pids : g2lp) { - X[pids.second] = Mf.X[pids.first]; - Y[pids.second] = Mf.Y[pids.first]; - Z[pids.second] = Mf.Z[pids.first]; + X[pids.second] = M.X[pids.first]; + Y[pids.second] = M.Y[pids.first]; + Z[pids.second] = M.Z[pids.first]; } Fc = F; @@ -153,47 +209,10 @@ Smesh::Smesh(const Smesh &Mf, const std::set &fids, bool check_Euler_) make_point_edges(); } -Smesh Smesh::Smesh_from_mesh_skin(const IMesh &M, - const std::vector &skin, bool check_Euler) -{ - return Smesh(M, skin, check_Euler); -} - -Smesh Smesh::Smesh_from_point_tags(const IMesh &M, const E_Float *ptag, - bool check_Euler) -{ - std::vector fids; - - for (E_Int fid : M.skin) { - const auto &pn = M.F[fid]; - bool keep = true; - for (E_Int pid : pn) { - if (ptag[pid] != 1) { - keep = false; - break; - } - } - if (keep) fids.push_back(fid); - } - - return Smesh(M, fids, check_Euler); -} - -Smesh Smesh::Smesh_from_mesh_patch(const IMesh &M, bool check_Euler) -{ - std::vector fids; - - for (E_Int fid : M.patch) { - fids.push_back(fid); - } - - return Smesh(M, fids, check_Euler); -} - -Smesh::Smesh(const IMesh &M, const std::vector &fids, bool check_Euler_) +Smesh::Smesh(const Smesh &Mf, const std::set &fids, bool check_Euler_) { - NEAR_VERTEX_TOL = M.NEAR_VERTEX_TOL; - NEAR_EDGE_TOL = M.NEAR_EDGE_TOL; + NEAR_VERTEX_TOL = Mf.NEAR_VERTEX_TOL; + NEAR_EDGE_TOL = Mf.NEAR_EDGE_TOL; check_Euler = check_Euler_; @@ -209,7 +228,7 @@ Smesh::Smesh(const IMesh &M, const std::vector &fids, bool check_Euler_) auto &pn = F[nf]; - for (E_Int gp : M.F[gf]) { + for (E_Int gp : Mf.Fc[gf]) { auto it = g2lp.find(gp); if (it == g2lp.end()) { @@ -228,15 +247,19 @@ Smesh::Smesh(const IMesh &M, const std::vector &fids, bool check_Euler_) assert((size_t)np == g2lp.size()); assert((size_t)np == l2gp.size()); + // Cache the original number of points and faces + np_before_adapt = np; + nf_before_adapt = nf; + // Get the points X.resize(np); Y.resize(np); Z.resize(np); for (const auto &pids : g2lp) { - X[pids.second] = M.X[pids.first]; - Y[pids.second] = M.Y[pids.first]; - Z[pids.second] = M.Z[pids.first]; + X[pids.second] = Mf.X[pids.first]; + Y[pids.second] = Mf.Y[pids.first]; + Z[pids.second] = Mf.Z[pids.first]; } Fc = F; @@ -271,10 +294,10 @@ void Smesh::make_edges() ne = 0; for (E_Int i = 0; i < nf; i++) { - auto &face = Fc[i]; - for (size_t j = 0; j < face.size(); j++) { - E_Int p = face[j]; - E_Int q = face[(j+1)%face.size()]; + auto &pn = Fc[i]; + for (size_t j = 0; j < pn.size(); j++) { + E_Int p = pn[j]; + E_Int q = pn[(j+1)%pn.size()]; o_edge EDGE(p, q); auto it = edges.find(EDGE); if (it == edges.end()) { @@ -366,80 +389,6 @@ void Smesh::make_edges() else neis.push_back(E2F[e][0]); } } - - /* - // Traverse the face list breadth-first and adjust edges accordingly - std::vector visited(nf, 0); - std::queue Q; - Q.push(0); - visited[0] = 1; - - while (!Q.empty()) { - E_Int f = Q.front(); - Q.pop(); - - assert(f != -1); - - visited[f] = 1; - - auto &neis = F2F[f]; - auto &pe = F2E[f]; - auto &pn = Fc[f]; - - for (size_t j = 0; j < pn.size(); j++) { - E_Int nei = neis[j]; - - E_Int p = pn[j]; - E_Int q = pn[(j+1)%pn.size()]; - - E_Int e = pe[j]; - - if (nei == -1) { - assert(E[e].p == p); - assert(E[e].q == q); - continue; - } - - if (visited[nei]) { - assert(E2F[e][0] == nei); - assert(E2F[e][1] == f); - assert(E[e].p == q); - assert(E[e].q == p); - continue; - } - - if (E[e].p != p) { - assert(visited[nei] == 0); - assert(E[e].q == p); - assert(E[e].p == q); - std::swap(E[e].p, E[e].q); - E2F[e][0] = f; - E2F[e][1] = nei; - Q.push(nei); - } - } - } - - // Check - for (E_Int i = 0; i < nf; i++) { - const auto &pn = Fc[i]; - for (size_t j = 0; j < pn.size(); j++) { - E_Int e = F2E[i][j]; - E_Int p = pn[j]; - E_Int q = pn[(j+1)%pn.size()]; - - if (E[e].p == p) { - assert(E[e].q == q); - assert(E2F[e][0] == i); - } else if (E[e].q == p) { - assert(E[e].p == q); - assert(E2F[e][1] == i); - } else { - assert(0); - } - } - } - */ } void Smesh::make_fcenters() @@ -550,3 +499,13 @@ void Smesh::clear() g2lf.clear(); l2gf.clear(); } + +void Smesh::tag_faces(IMesh &M) const +{ + M.ftag.clear(); + M.ftag.reserve(nf); + + for (E_Int fid = 0; fid < nf; fid++) { + M.ftag.push_back(l2gf.at(fid)); + } +} \ No newline at end of file diff --git a/Cassiopee/XCore/XCore/intersectMesh/smesh.h b/Cassiopee/XCore/XCore/intersectMesh/smesh.h index 5ca20e743..b7d9f154f 100644 --- a/Cassiopee/XCore/XCore/intersectMesh/smesh.h +++ b/Cassiopee/XCore/XCore/intersectMesh/smesh.h @@ -27,6 +27,9 @@ #include "point.h" #include "BVH.h" +#define LEFT 0 +#define RIGHT 1 + struct IMesh; struct AABB; @@ -76,6 +79,8 @@ struct Smesh { std::map g2lf; std::map l2gf; + void reconstruct(IMesh &M); + // Constructors Smesh(); @@ -87,8 +92,12 @@ struct Smesh { const std::vector &skin, bool check_Euler=true); static Smesh Smesh_from_mesh_patch(const IMesh &M, bool check_Euler=true); + static Smesh Smesh_from_tagged_faces(const IMesh &M, bool check_Euler); + static Smesh make_sub(const Smesh &Mf, const std::set &bfaces, + bool check_Euler); void make_edges(); void clear(); + void tag_faces(IMesh &M) const; // Geometry @@ -149,6 +158,8 @@ struct Smesh { std::map ecenter; std::map>> fchildren; + E_Int np_before_adapt; + E_Int nf_before_adapt; void resize_for_refinement(size_t nref_faces); void refine(const std::vector &ref_faces); @@ -158,8 +169,7 @@ struct Smesh { void update_plocs(const std::vector &parents, std::vector &plocs); void conformize(); - void get_edge_centers(E_Int p, E_Int q, std::list &edge_centers, - E_Int left_right); + void get_edge_centers(E_Int p, E_Int q, std::vector &edge_centers); std::vector deduce_ref_faces(const std::vector &mpids, const std::vector &plocs_m, const Smesh &Mf, std::vector &ref_faces); diff --git a/Cassiopee/XCore/XCore/intersectMesh/smesh_reconstruct.cpp b/Cassiopee/XCore/XCore/intersectMesh/smesh_reconstruct.cpp new file mode 100644 index 000000000..46e7c9677 --- /dev/null +++ b/Cassiopee/XCore/XCore/intersectMesh/smesh_reconstruct.cpp @@ -0,0 +1,198 @@ +#include "smesh.h" +#include "mesh.h" +#include "io.h" + +void Smesh::get_leaves(E_Int fid, std::vector &leaves) const +{ + leaves.push_back(fid); + auto it = fchildren.find(fid); + if (it == fchildren.end()) return; + + const auto &children_lists = it->second; + for (const auto &children_list : children_lists) { + for (E_Int child : children_list) + get_leaves(child, leaves); + } +} + +void Smesh::reconstruct(IMesh &M) +{ + // POINTS + + E_Int NP = M.np + (np - np_before_adapt); + + M.X.resize(NP); + M.Y.resize(NP); + M.Z.resize(NP); + + NP = M.np; + + std::vector points; + + for (E_Int pid = np_before_adapt; pid < np; pid++) { + assert(l2gp.find(pid) == l2gp.end()); + l2gp[pid] = NP; + g2lp[NP] = pid; + + M.X[NP] = X[pid]; + M.Y[NP] = Y[pid]; + M.Z[NP] = Z[pid]; + + points.push_back({M.X[NP], M.Y[NP], M.Z[NP]}); + + NP++; + } + + // Isolate the smesh cells + + std::set conf_cells; + + for (E_Int fid = 0; fid < nf_before_adapt; fid++) { + E_Int own = M.owner[l2gf.at(fid)]; + assert(M.neigh[l2gf.at(fid)] == -1); + conf_cells.insert(own); + } + + // Isolate the faces to conformize + std::set conf_faces; + + for (E_Int cid : conf_cells) { + const auto &pf = M.C[cid]; + for (E_Int fid : pf) { + if (g2lf.find(fid) == g2lf.end()) conf_faces.insert(fid); + } + } + + // Delete from owners the smesh faces + + for (E_Int cid : conf_cells) { + const auto &pf = M.C[cid]; + std::vector PF; + for (E_Int fid : pf) { + if (g2lf.find(fid) == g2lf.end()) PF.push_back(fid); + } + M.C[cid] = PF; + } + + // FACES + + E_Int NF = M.nf + (nf - nf_before_adapt); + + M.F.resize(NF); + M.owner.resize(NF); + M.neigh.resize(NF, -1); + + NF = M.nf; + + for (E_Int fid = nf_before_adapt; fid < nf; fid++) { + assert(l2gf.find(fid) == l2gf.end()); + l2gf[fid] = NF; + assert(g2lf.find(NF) == g2lf.end()); + g2lf[NF] = fid; + NF++; + } + + // Update old faces and add new faces + + for (E_Int fid = 0; fid < nf; fid++) { + std::vector PN(Fc[fid]); + for (auto &pid : PN) pid = l2gp.at(pid); + + E_Int gfid = l2gf.at(fid); + assert(M.neigh[gfid] == -1); + + M.F[gfid] = PN; + } + + + for (E_Int fid : conf_faces) { + auto it = g2lf.find(fid); + assert (it == g2lf.end()); + + const auto &pn = M.F[fid]; + + std::vector new_pn; + + for (size_t i = 0; i < pn.size(); i++) { + E_Int gp = pn[i]; + E_Int gq = pn[(i+1)%pn.size()]; + + auto itp = g2lp.find(gp); + auto itq = g2lp.find(gq); + + if (itp == g2lp.end() || itq == g2lp.end()) { + new_pn.push_back(gp); + continue; + } + + E_Int lp = itp->second; + E_Int lq = itq->second; + + std::vector local; + get_edge_centers(lp, lq, local); + for (auto p : local) new_pn.push_back(l2gp.at(p)); + } + + M.F[fid] = new_pn; + } + + // Add skin faces leaves to owners + + for (E_Int fid = 0; fid < nf_before_adapt; fid++) { + std::vector leaves; + get_leaves(fid, leaves); + + // Parent element to update + E_Int gfid = l2gf.at(fid); + assert(M.owner[gfid] != -1); + assert(M.neigh[gfid] == -1); + E_Int own = M.owner[gfid]; + assert(conf_cells.find(own) != conf_cells.end()); + auto &pf = M.C[own]; + + // Add the children + for (E_Int leaf : leaves) { + E_Int gleaf = l2gf.at(leaf); + pf.push_back(gleaf); + + M.owner[gleaf] = own; + M.neigh[gleaf] = -1; + } + } + + /* + { + if (M.nc > 27555) { + auto pf = M.C[27555]; + std::map local_map; + int npts = 0; + int i = 0; + for (E_Int fid : pf) { + const auto &pn = M.F[fid]; + printf("face%d: ", i); + for (E_Int p : pn) { + auto it = local_map.find(p); + if (it == local_map.end()) { + local_map[p] = npts; + printf("%d ", npts); + + if (npts == 19) { + point_write("point19.im", M.X[p], M.Y[p], M.Z[p]); + } + + npts++; + } else { + printf("%d ", it->second); + } + } + puts(""); + i++; + } + + } + } + */ + + M.np = NP; + M.nf = NF; +} \ No newline at end of file diff --git a/Cassiopee/XCore/XCore/intersectMesh/smesh_refine.cpp b/Cassiopee/XCore/XCore/intersectMesh/smesh_refine.cpp index 51500dd2c..815c22cba 100644 --- a/Cassiopee/XCore/XCore/intersectMesh/smesh_refine.cpp +++ b/Cassiopee/XCore/XCore/intersectMesh/smesh_refine.cpp @@ -114,7 +114,3 @@ void Smesh::refine(const std::vector &ref_faces) for (E_Int fid : ref_faces) refine_tri(fid); } - -void Smesh::get_leaves(E_Int fid, std::vector &leaves) const -{ -} diff --git a/Cassiopee/XCore/XCore/intersectMesh/triangulate.cpp b/Cassiopee/XCore/XCore/intersectMesh/triangulate.cpp index 5e6f8b8f6..55c65e314 100644 --- a/Cassiopee/XCore/XCore/intersectMesh/triangulate.cpp +++ b/Cassiopee/XCore/XCore/intersectMesh/triangulate.cpp @@ -28,6 +28,9 @@ void IMesh::triangulate_skin() { E_Int NF = nf; + owner.resize(nf + skin.size(), -1); + neigh.resize(nf + skin.size(), -1); + for (auto fid : skin) { assert(neigh[fid] == -1); @@ -46,6 +49,8 @@ void IMesh::triangulate_skin() auto &pf = C[own]; pf.push_back(nf); + owner[nf] = own; + nf++; } diff --git a/Cassiopee/XCore/srcs.py b/Cassiopee/XCore/srcs.py index 05782f6d2..6c840b75f 100644 --- a/Cassiopee/XCore/srcs.py +++ b/Cassiopee/XCore/srcs.py @@ -25,6 +25,8 @@ 'XCore/intersectMesh/icapsule_refine.cpp', 'XCore/intersectMesh/triangulate.cpp', + + 'XCore/intersectMesh/mesh_io.cpp', 'XCore/intersectMesh/smesh.cpp', 'XCore/intersectMesh/smesh_locate.cpp', @@ -33,6 +35,7 @@ 'XCore/intersectMesh/smesh_extract.cpp', 'XCore/intersectMesh/smesh_bvh.cpp', 'XCore/intersectMesh/smesh_geom.cpp', + 'XCore/intersectMesh/smesh_reconstruct.cpp', 'XCore/intersectMesh/dcel.cpp', 'XCore/intersectMesh/dcel_extract.cpp', From 9d03b2a21db365db0f56e68ee24e377f28db76ca Mon Sep 17 00:00:00 2001 From: imadhammani Date: Tue, 5 Nov 2024 14:36:44 +0100 Subject: [PATCH 75/86] XCore intersectMesh: separate adapt and intersect --- Cassiopee/XCore/XCore/PyTree.py | 22 +- Cassiopee/XCore/XCore/intersectMesh/dcel.cpp | 233 +++++++-------- Cassiopee/XCore/XCore/intersectMesh/dcel.h | 14 +- .../XCore/intersectMesh/dcel_extract.cpp | 110 +++---- .../XCore/XCore/intersectMesh/dcel_io.cpp | 7 + .../XCore/intersectMesh/dcel_reconstruct.cpp | 135 +++++++++ .../XCore/XCore/intersectMesh/icapsule.cpp | 282 +++++++++++++----- .../XCore/XCore/intersectMesh/icapsule.h | 3 +- Cassiopee/XCore/XCore/intersectMesh/mesh.h | 2 +- .../XCore/XCore/intersectMesh/primitives.h | 3 +- Cassiopee/XCore/XCore/intersectMesh/smesh.cpp | 17 +- Cassiopee/XCore/XCore/intersectMesh/smesh.h | 16 +- .../XCore/XCore/intersectMesh/smesh_bvh.cpp | 2 +- .../XCore/intersectMesh/smesh_extract.cpp | 4 +- .../XCore/intersectMesh/smesh_reconstruct.cpp | 24 +- Cassiopee/XCore/XCore/intersectMesh/u_edge.h | 16 + Cassiopee/XCore/XCore/xcore.cpp | 5 + Cassiopee/XCore/XCore/xcore.h | 5 + Cassiopee/XCore/srcs.py | 1 + 19 files changed, 579 insertions(+), 322 deletions(-) create mode 100644 Cassiopee/XCore/XCore/intersectMesh/dcel_reconstruct.cpp create mode 100644 Cassiopee/XCore/XCore/intersectMesh/u_edge.h diff --git a/Cassiopee/XCore/XCore/PyTree.py b/Cassiopee/XCore/XCore/PyTree.py index 6050d360d..19c46d375 100644 --- a/Cassiopee/XCore/XCore/PyTree.py +++ b/Cassiopee/XCore/XCore/PyTree.py @@ -500,16 +500,30 @@ def icapsule_init(mp, sp): return xcore.icapsule_init(marr, sarrs, tags) -def icapsule_extract_master(icap): - marr = xcore.icapsule_extract_master(icap) +def icapsule_adapt(IC): + return xcore.icapsule_adapt(IC) + +def icapsule_intersect(IC): + return xcore.icapsule_intersect(IC) + +def icapsule_extract_master(IC): + marr = xcore.icapsule_extract_master(IC) zm = I.createZoneNode("master", marr) return zm -def icapsule_extract_slave(icap, index=0): - sarr = xcore.icapsule_extract_slave(icap, index) +def icapsule_extract_slave(IC, index=0): + sarr = xcore.icapsule_extract_slave(IC, index) zs = I.createZoneNode("slave", sarr) return zs +def icapsule_extract_slaves(IC): + sarrs = xcore.icapsule_extract_slaves(IC) + zs = [] + for i in range(len(sarrs)): + z = I.createZoneNode("slave"+str(i), sarrs[i]) + zs.append(z) + return zs + def triangulate_skin(m): zm = I.getZones(m)[0] marr = C.getFields(I.__GridCoordinates__, zm, api=3)[0] diff --git a/Cassiopee/XCore/XCore/intersectMesh/dcel.cpp b/Cassiopee/XCore/XCore/intersectMesh/dcel.cpp index a04d68f9a..0fcbe40df 100644 --- a/Cassiopee/XCore/XCore/intersectMesh/dcel.cpp +++ b/Cassiopee/XCore/XCore/intersectMesh/dcel.cpp @@ -27,6 +27,9 @@ #include "smesh.h" #include "triangle.h" +Dcel::Dcel() +{} + void Dcel::init_vertices(const Smesh &Mf, const Smesh &Sf, const std::vector &plocs) { @@ -77,101 +80,38 @@ std::vector Dcel::get_face_vertices(const Face *f) const return ret; } -Smesh Dcel::reconstruct(const Smesh &Mf, int color, bool check_Euler) const -{ - Smesh ret; - ret.check_Euler = check_Euler; - auto &new_F = ret.F; - std::map new_pids; - ret.np = ret.nf = 0; - - std::vector fids; - - for (size_t i = 0; i < F.size(); i++) { - Face *f = F[i]; - Hedge *h = f->rep; - if (h->color != color) continue; - Hedge *w = h->next; - while (w != h) { - if (w->color != h->color) break; - w = w->next; - } - if (w == h) { - fids.push_back(f); - } - } - - char fname[128] = {0}; - sprintf(fname, "single_color_%d.im", color); - write_ngon(fname, fids); - - for (Face *f : F) { - if (f->oids[color] == -1) continue; - - std::vector pn; - - std::vector vertices = get_face_vertices(f); - for (Vertex *v : vertices) { - auto it = new_pids.find(v); - if (it == new_pids.end()) { - new_pids[v] = ret.np; - pn.push_back(ret.np); - ret.np++; - } else { - pn.push_back(it->second); - } - } - - new_F.push_back(pn); - ret.nf++; - } - - auto &new_X = ret.X; - auto &new_Y = ret.Y; - auto &new_Z = ret.Z; - - new_X.resize(ret.np), new_Y.resize(ret.np), new_Z.resize(ret.np); - for (const auto &vdat : new_pids) { - new_X[vdat.second] = vdat.first->x; - new_Y[vdat.second] = vdat.first->y; - new_Z[vdat.second] = vdat.first->z; - } - - ret.Fc = ret.F; - - ret.make_edges(); +struct HitData { + E_Float t, s; +}; - return ret; -} - -Dcel::Dcel(const Smesh &Mf, const Smesh &Sf, const std::vector &plocs) +Dcel Dcel::intersect(const Smesh &Mf, const Smesh &Sf, + const std::vector &plocs) { - init_vertices(Mf, Sf, plocs); + Dcel D; + D.init_vertices(Mf, Sf, plocs); - init_hedges_and_faces(Mf, RED); - init_hedges_and_faces(Sf, BLACK); + D.init_hedges_and_faces(Mf, RED); + D.init_hedges_and_faces(Sf, BLACK); - if (check_hedges(H) != 0) { + if (D.check_hedges(D.H) != 0) { fprintf(stderr, "Dcel: Inconsistent half-edge records!\n"); abort(); } - make_cycles(); - set_cycles_inout(); + D.make_cycles(); + D.set_cycles_inout(); - if (check_faces(H, F) != 0) { + if (check_faces(D.H, D.F) != 0) { fprintf(stderr, "Dcel: Inconsistent face records!\n"); abort(); } - - std::vector xpoints; - - std::vector dpoints; + //std::vector xpoints; + //std::vector dpoints; // Register the intersections between Sf points and Mf edges E_Int v_on_e = 0; - for (Vertex *v : V) { + for (Vertex *v : D.V) { // Strictly the Sf points if (v->oids[0] == -1 && v->oids[1] != -1) { const auto &ploc = v->ploc; @@ -183,14 +123,14 @@ Dcel::Dcel(const Smesh &Mf, const Smesh &Sf, const std::vector &plocs) E_Int e = pe[ploc.e_idx]; // Add the vertex to hedge intersections - Hedge *h = H[2*e]; + Hedge *h = D.H[2*e]; assert(h->color == RED); Vertex *O = h->orig; Vertex *T = h->twin->orig; - if (cmp_vtx(O, T) > 0) h = h->twin; - hedge_intersections[h].push_back(v); + if (D.cmp_vtx(O, T) > 0) h = h->twin; + D.hedge_intersections[h].push_back(v); - dpoints.push_back({v->x,v->y,v->z}); + //dpoints.push_back({v->x,v->y,v->z}); v_on_e++; } @@ -200,11 +140,11 @@ Dcel::Dcel(const Smesh &Mf, const Smesh &Sf, const std::vector &plocs) // Trace for (E_Int eid_s = 0; eid_s < Sf.ne; eid_s++) { - Hedge *hs = H[2*(Mf.ne + eid_s)]; + Hedge *hs = D.H[2*(Mf.ne + eid_s)]; assert(hs->color == BLACK); Vertex *O = hs->orig; Vertex *T = hs->twin->orig; - if (cmp_vtx(O, T) > 0) hs = hs->twin; + if (D.cmp_vtx(O, T) > 0) hs = hs->twin; E_Int p = hs->orig->oids[1]; E_Int q = hs->twin->orig->oids[1]; @@ -212,9 +152,9 @@ Dcel::Dcel(const Smesh &Mf, const Smesh &Sf, const std::vector &plocs) E_Float spx = Sf.X[p], spy = Sf.Y[p], spz = Sf.Z[p]; E_Float sqx = Sf.X[q], sqy = Sf.Y[q], sqz = Sf.Z[q]; - E_Float D[3] = {sqx-spx, sqy-spy, sqz-spz}; - E_Float NORM = K_MATH::norm(D, 3); - D[0] /= NORM, D[1] /= NORM, D[2] /= NORM; + E_Float DIR[3] = {sqx-spx, sqy-spy, sqz-spz}; + E_Float NORM = K_MATH::norm(DIR, 3); + DIR[0] /= NORM, DIR[1] /= NORM, DIR[2] /= NORM; std::vector orig_faces; std::vector tail_faces; @@ -232,7 +172,7 @@ Dcel::Dcel(const Smesh &Mf, const Smesh &Sf, const std::vector &plocs) //} E_Int starting_face = Mf.deduce_face(orig_faces, spx, spy, spz, - D, last_vertex, last_edge, eid_s); + DIR, last_vertex, last_edge, eid_s); assert(starting_face != -1); bool found_tail = false; @@ -254,7 +194,7 @@ Dcel::Dcel(const Smesh &Mf, const Smesh &Sf, const std::vector &plocs) if (found_tail) break; E_Float proj[3]; - Mf.get_unit_projected_direction(cur_fid, D, proj); + Mf.get_unit_projected_direction(cur_fid, DIR, proj); const auto &pn = Mf.Fc[cur_fid]; const auto &pe = Mf.F2E[cur_fid]; @@ -266,6 +206,8 @@ Dcel::Dcel(const Smesh &Mf, const Smesh &Sf, const std::vector &plocs) bool hit = false; + std::vector hitData; + for (size_t i = 0; i < pn.size(); i++) { E_Int p = pn[i]; E_Int q = pn[(i+1)%pn.size()]; @@ -277,7 +219,7 @@ Dcel::Dcel(const Smesh &Mf, const Smesh &Sf, const std::vector &plocs) E_Float px = Mf.X[p], py = Mf.Y[p], pz = Mf.Z[p]; E_Float qx = Mf.X[q], qy = Mf.Y[q], qz = Mf.Z[q]; - E_Float t, s; + E_Float t = -1.0, s = -1.0; hit = ray_edge_intersect( cur_pos[0], cur_pos[1], cur_pos[2], proj[0], proj[1], proj[2], @@ -285,6 +227,8 @@ Dcel::Dcel(const Smesh &Mf, const Smesh &Sf, const std::vector &plocs) t, s ); + hitData.push_back({t, s}); + if (hit) { if (s > TOL && s < 1 - TOL) { // Hit edge middle @@ -302,26 +246,27 @@ Dcel::Dcel(const Smesh &Mf, const Smesh &Sf, const std::vector &plocs) // Create a new intersection vertex Vertex tmp(next_pos[0], next_pos[1], next_pos[2]); - assert(vertex_set.find(&tmp) == vertex_set.end()); + assert(D.vertex_set.find(&tmp) == D.vertex_set.end()); Vertex *x = new Vertex(next_pos[0], next_pos[1], next_pos[2]); x->ploc.fid = cur_fid; x->ploc.e_idx = i; - x->id = V.size(); - V.push_back(x); - vertex_set.insert(x); + x->id = D.V.size(); + D.V.push_back(x); + D.vertex_set.insert(x); // Register the intersection - Hedge *hm = H[2*eid_m]; + Hedge *hm = D.H[2*eid_m]; assert(hm->color == RED); Vertex *O = hm->orig; Vertex *T = hm->twin->orig; - if (cmp_vtx(O, T) > 0) hm = hm->twin; + if (D.cmp_vtx(O, T) > 0) hm = hm->twin; + + D.hedge_intersections[hm].push_back(x); + D.hedge_intersections[hs].push_back(x); - hedge_intersections[hm].push_back(x); - hedge_intersections[hs].push_back(x); } else { // Hit an edge endpoint bool hit_p = (s <= TOL); @@ -336,25 +281,35 @@ Dcel::Dcel(const Smesh &Mf, const Smesh &Sf, const std::vector &plocs) const auto &pf = Mf.P2F[last_vertex]; next_fid = Mf.deduce_face(pf, next_pos[0], next_pos[1], next_pos[2], - D, last_vertex, last_edge, eid_s + DIR, last_vertex, last_edge, eid_s ); assert(next_fid != -1); // Find Vertex corresponding to hit vertex Vertex tmp(Mf.X[last_vertex], Mf.Y[last_vertex], Mf.Z[last_vertex]); - auto it = vertex_set.find(&tmp); - assert(it != vertex_set.end()); + auto it = D.vertex_set.find(&tmp); + assert(it != D.vertex_set.end()); Vertex *x = *it; // Register the intersection - hedge_intersections[hs].push_back(x); + D.hedge_intersections[hs].push_back(x); - xpoints.push_back({x->x, x->y, x->z}); + //xpoints.push_back({x->x, x->y, x->z}); } break; } } - + if (!hit) { + for (const auto &hd : hitData) { + printf("t = %.12e | s = %.12e\n", hd.t, hd.s); + } + fflush(stdout); + std::vector fids; + fids.push_back(cur_fid); + Mf.write_ngon("cur_fid.im", fids); + edge_write("cur_sedge.im", cur_pos[0], cur_pos[1], cur_pos[2], + proj[0], proj[1], proj[2]); + } assert(hit); assert(next_fid != cur_fid); cur_fid = next_fid; @@ -368,24 +323,24 @@ Dcel::Dcel(const Smesh &Mf, const Smesh &Sf, const std::vector &plocs) assert(walk <= max_walks); } - point_write("xpoints.im", xpoints); + //point_write("xpoints.im", xpoints); // Cut - for (auto &h2x : hedge_intersections) { + for (auto &h2x : D.hedge_intersections) { Hedge *h = h2x.first; - auto it = hedge_intersections.find(h->twin); - assert(it == hedge_intersections.end()); + auto it = D.hedge_intersections.find(h->twin); + assert(it == D.hedge_intersections.end()); auto &xs = h2x.second; Vertex *o = h->orig; Vertex *tail = h->twin->orig; - assert(cmp_vtx(o, tail) < 0); + assert(D.cmp_vtx(o, tail) < 0); // TODO(Imad): check that the intersections are 'sufficiently' spaced out for (Vertex *x : xs) { - E_Float D[3] = {x->x-o->x, x->y-o->y, x->z-o->z}; - x->d2 = K_MATH::dot(D, D, 3); + E_Float d[3] = {x->x-o->x, x->y-o->y, x->z-o->z}; + x->d2 = K_MATH::dot(d, d, 3); } std::sort(xs.begin(), xs.end(), [&] (const Vertex *a, const Vertex *b) @@ -394,6 +349,17 @@ Dcel::Dcel(const Smesh &Mf, const Smesh &Sf, const std::vector &plocs) return a->d2 < b->d2; }); + // Before cutting, cache the intersections for volume mesh reconstruction + { + Vertex *start = o; + Vertex *end = tail; + for (size_t i = 0; i < xs.size(); i++) { + D.vcenter[h->color][{start, end}] = xs[i]; + start = xs[i]; + } + } + + // Cut Hedge *current_h = h; Hedge *t = h->twin; @@ -401,8 +367,8 @@ Dcel::Dcel(const Smesh &Mf, const Smesh &Sf, const std::vector &plocs) Hedge *e1 = new Hedge(x, current_h->color); Hedge *e2 = new Hedge(x, t->color); - H.push_back(e1); - H.push_back(e2); + D.H.push_back(e1); + D.H.push_back(e2); e1->left = current_h->left; e2->left = t->left; @@ -422,14 +388,14 @@ Dcel::Dcel(const Smesh &Mf, const Smesh &Sf, const std::vector &plocs) } // Resolve - std::vector> list(V.size()); - for (Hedge *h : H) { + std::vector> list(D.V.size()); + for (Hedge *h : D.H) { Vertex *o = h->orig; list[o->id].push_back(h); } - for (size_t vid = 0; vid < V.size(); vid++) { - Vertex *v = V[vid]; + for (size_t vid = 0; vid < D.V.size(); vid++) { + Vertex *v = D.V[vid]; E_Float N[3] = {0, 0, 0}; @@ -453,7 +419,7 @@ Dcel::Dcel(const Smesh &Mf, const Smesh &Sf, const std::vector &plocs) auto &leaving = list[vid]; - sort_leaving_hedges(leaving, N); + D.sort_leaving_hedges(leaving, N); for (size_t i = 0; i < leaving.size(); i++) { Hedge *h = leaving[i]; @@ -463,28 +429,28 @@ Dcel::Dcel(const Smesh &Mf, const Smesh &Sf, const std::vector &plocs) } } - if (check_hedges(H) != 0) { + if (D.check_hedges(D.H) != 0) { fprintf(stderr, "Dcel: Inconsistent half-edge records!\n"); assert(0); abort(); } - make_cycles(); - set_cycles_inout(); + D.make_cycles(); + D.set_cycles_inout(); - write_hole_cycles("hole.im"); - write_degen_cycles("degen.im"); - write_inner_cycles("inner.im"); + //write_hole_cycles("hole.im"); + //write_degen_cycles("degen.im"); + //write_inner_cycles("inner.im"); - auto new_F = make_cycle_faces(C); - set_face_labels(new_F); - update_hedge_faces(new_F); - check_faces(H, new_F); + auto new_F = D.make_cycle_faces(D.C); + D.set_face_labels(new_F); + D.update_hedge_faces(new_F); + D.check_faces(D.H, new_F); - for (Face *f : F) delete f; - F = new_F; + for (Face *f : D.F) delete f; + D.F = new_F; - puts("ok"); + return D; } void Dcel::update_hedge_faces(std::vector &new_F) @@ -678,6 +644,9 @@ void Dcel::init_hedges_and_faces(const Smesh &Mf, int color) h->twin = t; t->twin = h; + //h->oid = i; + //t->oid = i; + H.push_back(h); H.push_back(t); } diff --git a/Cassiopee/XCore/XCore/intersectMesh/dcel.h b/Cassiopee/XCore/XCore/intersectMesh/dcel.h index 037e84a60..4a0b8d443 100644 --- a/Cassiopee/XCore/XCore/intersectMesh/dcel.h +++ b/Cassiopee/XCore/XCore/intersectMesh/dcel.h @@ -25,6 +25,7 @@ #include "common/common.h" #include "point.h" #include "primitives.h" +#include "u_edge.h" struct Smesh; @@ -115,7 +116,14 @@ struct Dcel { E_Int hole = 0; std::map> hedge_intersections; + std::map, Vertex *> vcenter[2]; + std::map l2gp; + std::map g2lp; + std::map l2gf; + std::map g2lf; + + Dcel(); Dcel(const Smesh &Mf, const Smesh &Sf, const std::vector &plocs); Dcel(const Smesh &Mf, int color); ~Dcel(); @@ -132,6 +140,8 @@ struct Dcel { void set_face_labels(std::vector &F); std::vector make_cycle_faces(const std::vector &C); void reconstruct(const Smesh &Mf, const Smesh &Sf); + static Dcel intersect(const Smesh &Mf, const Smesh &Sf, + const std::vector &plocs); // Checks @@ -148,8 +158,7 @@ struct Dcel { // Export Smesh export_smesh(bool check_Euler=true) const; - Smesh reconstruct(const Smesh &Mf, int color, bool check_Euler) const; - void reconstruct_smesh(Smesh &Mf, int color, bool check_Euler) const; + void reconstruct(Smesh &Mf, int color) const; // Extract @@ -168,6 +177,7 @@ struct Dcel { void write_point(const char *fname, const std::vector &I) const; void write_ngon(const char *fname, const std::vector &cycles) const; void write_ngon(const char *fname, const std::vector &faces) const; + void write_ngon(const char *fname, const std::vector &fids) const; void write_degen_cycles(const char *fname) const; void write_inner_cycles(const char *fname) const; void write_hole_cycles(const char *fname) const; diff --git a/Cassiopee/XCore/XCore/intersectMesh/dcel_extract.cpp b/Cassiopee/XCore/XCore/intersectMesh/dcel_extract.cpp index 3cd0262c0..12634c788 100644 --- a/Cassiopee/XCore/XCore/intersectMesh/dcel_extract.cpp +++ b/Cassiopee/XCore/XCore/intersectMesh/dcel_extract.cpp @@ -1,96 +1,72 @@ #include "dcel.h" #include "smesh.h" -void Dcel::reconstruct_smesh(Smesh &Mf, int color, bool check_Euler) const +/* +void Dcel::reconstruct(Smesh &Mf, int color, bool check_Euler) const { - std::map> oid_to_faces; - + Smesh ret; + ret.check_Euler = check_Euler; + auto &new_F = ret.F; std::map new_pids; + ret.np = ret.nf = 0; + + std::vector fids; - E_Int NP = Mf.np; + for (size_t i = 0; i < F.size(); i++) { + Face *f = F[i]; + Hedge *h = f->rep; + if (h->color != color) continue; + Hedge *w = h->next; + while (w != h) { + if (w->color != h->color) break; + w = w->next; + } + if (w == h) { + fids.push_back(f); + } + } - E_Int face_incr = 0; + char fname[128] = {0}; + sprintf(fname, "single_color_%d.im", color); + write_ngon(fname, fids); - // Which faces to keep? for (Face *f : F) { if (f->oids[color] == -1) continue; - oid_to_faces[f->oids[color]].push_back(f); - - // Which points to keep? - - auto vertices = get_face_vertices(f); + std::vector pn; + std::vector vertices = get_face_vertices(f); for (Vertex *v : vertices) { auto it = new_pids.find(v); if (it == new_pids.end()) { - // Was this point before the intersection? - if (v->oids[color] != -1) { - // Yes, keep its original id - new_pids[v] = v->oids[color]; - } else { - // No, add it - new_pids[v] = NP++; - } - } - } - - face_incr++; - } - - face_incr -= oid_to_faces.size(); - - // Replace the old faces with the new intersection faces - - Mf.F.resize(Mf.nf+face_incr); - Mf.Fc.resize(Mf.nf+face_incr); - E_Int NF = Mf.nf; - for (const auto &fdat : oid_to_faces) { - E_Int fid = fdat.first; - const auto &faces = fdat.second; - - std::vector new_pn; - - // Replace fid with the first face and add the rest of the faces - for (size_t i = 0; i < faces.size(); i++) { - new_pn.clear(); - auto vertices = get_face_vertices(faces[i]); - for (Vertex *v : vertices) new_pn.push_back(new_pids[v]); - if (i > 0) { - Mf.F[NF] = new_pn; - Mf.Fc[NF] = new_pn; - NF++; + new_pids[v] = ret.np; + pn.push_back(ret.np); + ret.np++; } else { - Mf.F[fid] = new_pn; - Mf.Fc[fid] = new_pn; + pn.push_back(it->second); } } - } + new_F.push_back(pn); + ret.nf++; + } - // Resize the points - Mf.X.resize(NP, EFLOATMAX); - Mf.Y.resize(NP, EFLOATMAX); - Mf.Z.resize(NP, EFLOATMAX); + auto &new_X = ret.X; + auto &new_Y = ret.Y; + auto &new_Z = ret.Z; + new_X.resize(ret.np), new_Y.resize(ret.np), new_Z.resize(ret.np); for (const auto &vdat : new_pids) { - Vertex *v = vdat.first; - E_Int new_pid = vdat.second; - if (v->oids[color] == -1) { - assert(Mf.X[new_pid] == EFLOATMAX); - assert(Mf.Y[new_pid] == EFLOATMAX); - assert(Mf.Z[new_pid] == EFLOATMAX); - Mf.X[new_pid] = v->x; - Mf.Y[new_pid] = v->y; - Mf.Z[new_pid] = v->z; - } + new_X[vdat.second] = vdat.first->x; + new_Y[vdat.second] = vdat.first->y; + new_Z[vdat.second] = vdat.first->z; } + ret.Fc = ret.F; - Mf.nf = NF; - Mf.np = NP; + ret.make_edges(); } - +*/ Smesh Dcel::export_smesh(bool check_Euler) const { diff --git a/Cassiopee/XCore/XCore/intersectMesh/dcel_io.cpp b/Cassiopee/XCore/XCore/intersectMesh/dcel_io.cpp index a29b2b3b8..216c82c42 100644 --- a/Cassiopee/XCore/XCore/intersectMesh/dcel_io.cpp +++ b/Cassiopee/XCore/XCore/intersectMesh/dcel_io.cpp @@ -219,6 +219,13 @@ void Dcel::write_ngon(const char *fname, const std::vector &cycles) con fclose(fh); } +void Dcel::write_ngon(const char *fname, const std::vector &fids) const +{ + std::vector faces; + for (E_Int fid : fids) faces.push_back(F[fid]); + write_ngon(fname, faces); +} + void Dcel::write_ngon(const char *fname, const std::vector &faces) const { FILE *fh = fopen(fname, "w"); diff --git a/Cassiopee/XCore/XCore/intersectMesh/dcel_reconstruct.cpp b/Cassiopee/XCore/XCore/intersectMesh/dcel_reconstruct.cpp new file mode 100644 index 000000000..200888ef7 --- /dev/null +++ b/Cassiopee/XCore/XCore/intersectMesh/dcel_reconstruct.cpp @@ -0,0 +1,135 @@ +#include "dcel.h" +#include "smesh.h" + +void Dcel::reconstruct(Smesh &Mf, int color) const +{ + std::map> ofid_to_ifids; + + std::vector faces_to_keep; + + E_Int nif = 0; + + for (size_t fid = 0; fid < F.size(); fid++) { + Face *f = F[fid]; + E_Int ofid = f->oids[color]; + if (ofid == -1) continue; + + ofid_to_ifids[ofid].push_back(fid); + + faces_to_keep.push_back(fid); + + nif++; + } + + //write_ngon("keep.im", faces_to_keep); + + Mf.F.resize(faces_to_keep.size()); + + // POINTS + + std::map new_pids; + E_Int NP = Mf.np; + + for (size_t i = 0; i < faces_to_keep.size(); i++) { + E_Int fid = faces_to_keep[i]; + Face *f = F[fid]; + auto vertices = get_face_vertices(f); + for (size_t j = 0; j < vertices.size(); j++) { + Vertex *v = vertices[j]; + if (v->oids[color] != -1) continue; + E_Int vid = v->id; + auto it = new_pids.find(vid); + if (it == new_pids.end()) { + new_pids[vid] = NP; + NP++; + } + } + } + + E_Int NF = Mf.nf; + + for (const auto &fdat : ofid_to_ifids) { + E_Int parent = fdat.first; + const auto &children = fdat.second; + + // In Mf, replace parent with first child + auto vertices = get_face_vertices(F[children[0]]); + std::vector PN(vertices.size()); + for (size_t i = 0; i < vertices.size(); i++) { + Vertex *v = vertices[i]; + E_Int oid = v->oids[color]; + if (oid != -1) { + PN[i] = oid; + } else { + PN[i] = new_pids.at(v->id); + } + } + Mf.F[parent] = PN; + + // Construct fchildren for volume mesh reconstruction + std::vector fchildren(children.size()-1); + + // Add the rest of the children + for (size_t i = 1; i < children.size(); i++) { + Face *f = F[children[i]]; + auto vertices = get_face_vertices(f); + std::vector PN(vertices.size()); + for (size_t j = 0; j < vertices.size(); j++) { + Vertex *v = vertices[j]; + E_Int oid = v->oids[color]; + if (oid != -1) { + PN[j] = oid; + } else { + PN[j] = new_pids.at(v->id); + } + } + Mf.F[NF] = PN; + + fchildren[i-1] = NF; + + NF++; + } + + Mf.fchildren[parent].push_back(fchildren); + } + + Mf.Fc = Mf.F; + + Mf.X.resize(NP); + Mf.Y.resize(NP); + Mf.Z.resize(NP); + + for (const auto &pdat : new_pids) { + E_Int vid = pdat.first; + E_Int pid = pdat.second; + Mf.X[pid] = V[vid]->x; + Mf.Y[pid] = V[vid]->y; + Mf.Z[pid] = V[vid]->z; + } + + Mf.nf = NF; + Mf.np = NP; + + Mf.clear_conformal_data(); + Mf.make_edges(); + Mf.make_point_faces(); + Mf.make_point_edges(); + + // Construct edge centers for volume mesh reconstruction + + const auto &vc = vcenter[color]; + + for (const auto &vdat : vc) { + const std::pair &e = vdat.first; + const Vertex *c = vdat.second; + const Vertex *p = e.first; + const Vertex *q = e.second; + + E_Int pid = p->oids[color] != -1 ? p->oids[color] : new_pids.at(p->id); + E_Int qid = q->oids[color] != -1 ? q->oids[color] : new_pids.at(q->id); + + Mf.ecenter[{pid, qid}] = new_pids.at(c->id); + } + + puts("constructed ecenters"); +} \ No newline at end of file diff --git a/Cassiopee/XCore/XCore/intersectMesh/icapsule.cpp b/Cassiopee/XCore/XCore/intersectMesh/icapsule.cpp index 733895020..ec79460b7 100644 --- a/Cassiopee/XCore/XCore/intersectMesh/icapsule.cpp +++ b/Cassiopee/XCore/XCore/intersectMesh/icapsule.cpp @@ -7,6 +7,7 @@ #include "primitives.h" #include "dcel.h" +/* ICapsule ICapsule::do_it(const Karray &marray, const std::vector &sarrays, const std::vector &ptags) { @@ -20,18 +21,9 @@ ICapsule ICapsule::do_it(const Karray &marray, puts("Creating mesh from karray"); M = IMesh(marray); M.set_tolerances(NEAR_VERTEX_TOL, NEAR_EDGE_TOL); - puts("Making skin"); M.make_skin(); - puts("Orienting skin"); M.orient_skin(OUT); - puts("Triangulating skin"); M.triangulate_skin(); - puts("Making edge data"); - M.make_edges(); - puts("Making bbox"); - M.make_bbox(); - puts("Hashing skin"); - M.hash_skin(); puts("Creating surface mesh"); Smesh Mf(M, M.skin, false); puts("Making surface mesh data"); @@ -41,12 +33,13 @@ ICapsule ICapsule::do_it(const Karray &marray, Mf.make_fnormals(); Mf.make_pnormals(); - Mf.write_ngon("Mf_raw.im"); + //Mf.write_ngon("Mf_raw.im"); Ss.reserve(sarrays.size()); // Adapt + //for (size_t i = 0; i < 4; i++) { for (size_t i = 0; i < sarrays.size(); i++) { printf("S%lu\n", i); @@ -62,11 +55,6 @@ ICapsule ICapsule::do_it(const Karray &marray, // Create SMesh Sf Smesh Sf = Smesh::Smesh_from_point_tags(S, ptags[i], true); - for (E_Int fid = 0; fid < Sf.nf; fid++) { - E_Int gfid = Sf.l2gf.at(fid); - assert(S.neigh[gfid] == -1); - } - Sf.make_fcenters(); Sf.make_fnormals(); Sf.make_pnormals(); @@ -75,7 +63,7 @@ ICapsule ICapsule::do_it(const Karray &marray, Sf.compute_min_distance_between_points(); printf("Min dist: %f\n", Sf.min_pdist); - Sf.write_ngon("Sf_raw.im"); + //Sf.write_ngon("Sf_raw.im"); // Locate Sf points on Mf faces auto plocs = Mf.locate(Sf); @@ -104,56 +92,8 @@ ICapsule ICapsule::do_it(const Karray &marray, Mf.reconstruct(M); return icap; - - /* - // Intersect - - for (size_t i = 0; i < sarrays.size(); i++) { - - // Make Sf - Smesh Sf = Smesh::Smesh_from_tagged_faces(Ss[i], true); - - // Make Bf - M.make_skin(); - Smesh Mf(M, M.skin, false); - auto plocs = Mf.locate(Sf); - - auto bfaces = Mf.extract_covering_faces(Sf, plocs); - Smesh Bf = Smesh::make_sub(Mf, bfaces, false); - Bf.make_fcenters(); - Bf.make_fnormals(); - Bf.make_pnormals(); - Bf.make_bbox(); - Bf.hash_faces(); - - plocs = Bf.locate(Sf); - - // Intersect - Dcel D(Bf, Sf, plocs); - - // Reconstruct Bf and Sf - D.reconstruct_smesh(Bf, Dcel::RED, false); - D.reconstruct_smesh(Sf, Dcel::BLACK, true); - - { - Smesh new_Bf = D.reconstruct(Bf, Dcel::RED, false); - new_Bf.write_ngon("new_Bf.im"); - puts("reconstruted new Bf"); - Smesh new_Sf = D.reconstruct(Sf, Dcel::BLACK, true); - new_Sf.write_ngon("new_Sf.im"); - puts("reconstruted new Sf"); - } - - // Reconstruct M and S - Bf.reconstruct(M); - Sf.reconstruct(Ss[i]); - - puts(""); - } - - Mf.write_ngon("refined_Mf.im"); - */ } +*/ PyObject *K_XCORE::icapsule_extract_master(PyObject *self, PyObject *args) @@ -164,12 +104,12 @@ PyObject *K_XCORE::icapsule_extract_master(PyObject *self, PyObject *args) return NULL; } - if (!PyCapsule_IsValid(ICAPSULE, "ICapsule")) { + if (!PyCapsule_IsValid(ICAPSULE, "ICAPSULE")) { RAISE("Bad ICapsule hook."); return NULL; } - ICapsule *icap = (ICapsule *)PyCapsule_GetPointer(ICAPSULE, "ICapsule"); + ICapsule *icap = (ICapsule *)PyCapsule_GetPointer(ICAPSULE, "ICAPSULE"); auto Mout = icap->M.export_karray(); @@ -185,12 +125,12 @@ PyObject *K_XCORE::icapsule_extract_slave(PyObject *self, PyObject *args) return NULL; } - if (!PyCapsule_IsValid(ICAPSULE, "ICapsule")) { + if (!PyCapsule_IsValid(ICAPSULE, "ICAPSULE")) { RAISE("Bad ICapsule hook."); return NULL; } - ICapsule *icap = (ICapsule *)PyCapsule_GetPointer(ICAPSULE, "ICapsule"); + ICapsule *icap = (ICapsule *)PyCapsule_GetPointer(ICAPSULE, "ICAPSULE"); if (INDEX >= (E_Int)icap->Ss.size()) { RAISE("Bad slave index."); @@ -202,6 +142,57 @@ PyObject *K_XCORE::icapsule_extract_slave(PyObject *self, PyObject *args) return Sout; } +PyObject *K_XCORE::icapsule_extract_slaves(PyObject *self, PyObject *args) +{ + PyObject *ICAPSULE; + + if (!PYPARSETUPLE_(args, O_, &ICAPSULE)) { + RAISE("Bad input."); + return NULL; + } + + if (!PyCapsule_IsValid(ICAPSULE, "ICAPSULE")) { + RAISE("Bad ICapsule hook."); + return NULL; + } + + ICapsule *icap = (ICapsule *)PyCapsule_GetPointer(ICAPSULE, "ICAPSULE"); + + PyObject *out = PyList_New(0); + + for (size_t i = 0; i < icap->Ss.size(); i++) { + PyObject *sarray = icap->Ss[i].export_karray(); + PyList_Append(out, sarray); + Py_DECREF(sarray); + } + + return out; +} + +ICapsule::ICapsule(const Karray &marray, const std::vector &sarrays, + const std::vector &ptags) +{ + E_Float NEAR_VERTEX_TOL = 1e-3; + E_Float NEAR_EDGE_TOL = 1e-3; + + M = IMesh(marray); + M.set_tolerances(NEAR_VERTEX_TOL, NEAR_EDGE_TOL); + M.make_skin(); + M.orient_skin(OUT); + M.triangulate_skin(); + + Ss.reserve(sarrays.size()); + for (size_t i = 0; i < sarrays.size(); i++) { + Ss.push_back(sarrays[i]); + Ss[i].set_tolerances(NEAR_VERTEX_TOL, NEAR_EDGE_TOL); + Ss[i].make_skin(); + Ss[i].orient_skin(IN); + Ss[i].triangulate_skin(); + Ss[i].ptag.resize(Ss[i].np); + memcpy(Ss[i].ptag.data(), ptags[i], Ss[i].np*sizeof(E_Float)); + } +} + PyObject *K_XCORE::icapsule_init(PyObject *self, PyObject *args) { PyObject *MASTER, *SLAVES, *PTAGS; @@ -262,14 +253,153 @@ PyObject *K_XCORE::icapsule_init(PyObject *self, PyObject *args) } } - ICapsule *icap = new ICapsule(); - *icap = ICapsule::do_it(marray, sarrays, ptags); + ICapsule *icap = new ICapsule(marray, sarrays, ptags); - Karray_free_ngon(marray); - for (E_Int i = 0; i < nslaves; i++) - Karray_free_ngon(sarrays[i]); - - PyObject *hook = PyCapsule_New((void *)icap, "ICapsule", NULL); + PyObject *hook = PyCapsule_New((void *)icap, "ICAPSULE", NULL); return hook; } + +PyObject *K_XCORE::icapsule_adapt(PyObject *self, PyObject *args) +{ + PyObject *ICAPSULE; + if (!PYPARSETUPLE_(args, O_, &ICAPSULE)) { + RAISE("Bad input."); + return NULL; + } + + if (!PyCapsule_IsValid(ICAPSULE, "ICAPSULE")) { + RAISE("Bad capsule hook."); + return NULL; + } + + ICapsule *icap = (ICapsule *)PyCapsule_GetPointer(ICAPSULE, "ICAPSULE"); + + auto &M = icap->M; + auto &Ss = icap->Ss; + + Smesh Mf(M, M.skin, false); + puts("Making surface mesh data"); + Mf.make_bbox(); + Mf.hash_faces(); + Mf.make_fcenters(); + Mf.make_fnormals(); + Mf.make_pnormals(); + Mf.write_ngon("Mf_before_inter.im"); + + for (size_t i = 0; i < Ss.size(); i++) { + printf("S%lu\n", i); + auto &S = Ss[i]; + + Smesh Sf = Smesh::Smesh_from_point_tags(S, S.ptag.data(), true); + + Sf.make_fcenters(); + Sf.make_fnormals(); + Sf.make_pnormals(); + Sf.make_bbox(); + Sf.hash_faces(); + Sf.compute_min_distance_between_points(); + printf("Min dist: %f\n", Sf.min_pdist); + + Sf.write_ngon("Sf_before_inter.im"); + + // Locate Sf points on Mf faces + auto plocs = Mf.locate(Sf); + std::vector spids(Sf.np); + for (int i = 0; i < Sf.np; i++) spids[i] = i; + Sf.replace_by_projections(spids, plocs); + + // Extract the initial Mf faces that cover Sf + auto bfaces = Mf.extract_covering_faces(Sf, plocs); + + // Refinement loop + ICapsule::refine(Mf, bfaces, Sf); + + // Reconstruct S + Sf.reconstruct(S); + + // Reconstruct S skin + S.make_skin(); + + // Tag Sf faces + Sf.tag_faces(S); + } + + Mf.reconstruct(M); + + //PyObject *marray = M.export_karray(); + //PyObject *sarrays = PyList_New(0); + //for (const auto &Ss) + + return Py_None; +} + +PyObject *K_XCORE::icapsule_intersect(PyObject *self, PyObject *args) +{ + PyObject *ICAPSULE; + if (!PYPARSETUPLE_(args, O_, &ICAPSULE)) { + RAISE("Bad input."); + return NULL; + } + + if (!PyCapsule_IsValid(ICAPSULE, "ICAPSULE")) { + RAISE("Bad capsule hook."); + return NULL; + } + + ICapsule *icap = (ICapsule *)PyCapsule_GetPointer(ICAPSULE, "ICAPSULE"); + + // Intersect + auto &M = icap->M; + auto &Ss = icap->Ss; + + M.make_skin(); + M.orient_skin(OUT); + Smesh Mf(M, M.skin, false); + + //for (size_t i = 0; i < 4; i++) { + for (size_t i = 0; i < Ss.size(); i++) { + + Mf.make_bbox(); + Mf.hash_faces(); + Mf.make_fcenters(); + Mf.make_fnormals(); + Mf.make_pnormals(); + Mf.write_ngon("Mf.im"); + + auto &S = Ss[i]; + + Smesh Sf = Smesh::Smesh_from_tagged_faces(S, true); + Sf.make_fcenters(); + Sf.make_fnormals(); + Sf.make_pnormals(); + + auto plocs = Mf.locate(Sf); + + Dcel D = Dcel::intersect(Mf, Sf, plocs); + + D.reconstruct(Mf, Dcel::RED); + Mf.write_ngon("Mf.im"); + D.reconstruct(Sf, Dcel::BLACK); + Sf.write_ngon("Sf.im"); + + { + D.write_inner_cycles("intersected.im"); + } + + Sf.reconstruct(Ss[i]); + + // Tag the new Sf faces + //S.ftag.resize(S.nf, 0); + //for (E_Int fid = 0; fid < Sf.nf; fid++) { + // E_Int gfid = Sf.g2lf.at(fid); + // S.ftag[gfid] = 1; + //} + + puts(""); + } + + Mf.reconstruct(M); + + return Py_None; +} \ No newline at end of file diff --git a/Cassiopee/XCore/XCore/intersectMesh/icapsule.h b/Cassiopee/XCore/XCore/intersectMesh/icapsule.h index 382d49f13..d155035e9 100644 --- a/Cassiopee/XCore/XCore/intersectMesh/icapsule.h +++ b/Cassiopee/XCore/XCore/intersectMesh/icapsule.h @@ -6,8 +6,7 @@ struct ICapsule { IMesh M; std::vector Ss; - static ICapsule do_it(const Karray &marray, - const std::vector &sarray, + ICapsule(const Karray &marray, const std::vector &sarrays, const std::vector &ptags); static std::vector refine(Smesh &Mf, diff --git a/Cassiopee/XCore/XCore/intersectMesh/mesh.h b/Cassiopee/XCore/XCore/intersectMesh/mesh.h index 992ab5f5d..2b703b40b 100644 --- a/Cassiopee/XCore/XCore/intersectMesh/mesh.h +++ b/Cassiopee/XCore/XCore/intersectMesh/mesh.h @@ -90,7 +90,7 @@ struct IMesh { std::set patch; std::vector ftag; - + std::vector ptag; std::vector ctag; void set_tolerances(E_Float near_vertex_tol, E_Float near_edge_tol) diff --git a/Cassiopee/XCore/XCore/intersectMesh/primitives.h b/Cassiopee/XCore/XCore/intersectMesh/primitives.h index dea039941..8e4ad235c 100644 --- a/Cassiopee/XCore/XCore/intersectMesh/primitives.h +++ b/Cassiopee/XCore/XCore/intersectMesh/primitives.h @@ -22,7 +22,8 @@ #include "common/common.h" -constexpr E_Float TOL = 1e-11; +constexpr E_Float TOL = 1e-9; +//constexpr E_Float RAY_EDGE_TOL = 1e-6; E_Int Sign(E_Float x, E_Float tol=TOL); diff --git a/Cassiopee/XCore/XCore/intersectMesh/smesh.cpp b/Cassiopee/XCore/XCore/intersectMesh/smesh.cpp index cf383ba29..1b11de699 100644 --- a/Cassiopee/XCore/XCore/intersectMesh/smesh.cpp +++ b/Cassiopee/XCore/XCore/intersectMesh/smesh.cpp @@ -70,20 +70,6 @@ void Smesh::conformize() std::vector new_pn; - /* - for (size_t i = 0; i < pn.size(); i++) { - E_Int p = pn[i]; - E_Int q = pn[(i+1)%pn.size()]; - - new_pn.push_back(p); - - std::list edge_points; - get_edge_centers(p, q, edge_points, LEFT); - for (E_Int ep : edge_points) new_pn.push_back(ep); - assert(new_pn.back() != q); - } - */ - for (size_t i = 0; i < pn.size(); i++) { E_Int p = pn[i]; E_Int q = pn[(i+1)%pn.size()]; @@ -146,8 +132,7 @@ Smesh Smesh::Smesh_from_mesh_patch(const IMesh &M, bool check_Euler) Smesh Smesh::Smesh_from_tagged_faces(const IMesh &M, bool check_Euler) { - assert(0); - return Smesh(); + return Smesh(M, M.ftag, check_Euler); } Smesh::Smesh(const IMesh &M, const std::vector &fids, bool check_Euler_) diff --git a/Cassiopee/XCore/XCore/intersectMesh/smesh.h b/Cassiopee/XCore/XCore/intersectMesh/smesh.h index b7d9f154f..92e2caf8a 100644 --- a/Cassiopee/XCore/XCore/intersectMesh/smesh.h +++ b/Cassiopee/XCore/XCore/intersectMesh/smesh.h @@ -24,6 +24,7 @@ #include #include "xcore.h" +#include "u_edge.h" #include "point.h" #include "BVH.h" @@ -39,19 +40,6 @@ struct o_edge { o_edge(E_Int P, E_Int Q); }; -struct u_edge { - E_Int p, q; - - u_edge(E_Int P, E_Int Q) - : p(std::min(P, Q)), q(std::max(P, Q)) - {} - - bool operator<(const u_edge& e) const - { - return (p < e.p) || (p == e.p && q < e.q); - } -}; - struct Smesh { // Universal data @@ -157,7 +145,7 @@ struct Smesh { // Adaptation std::map ecenter; - std::map>> fchildren; + std::map>> fchildren; E_Int np_before_adapt; E_Int nf_before_adapt; diff --git a/Cassiopee/XCore/XCore/intersectMesh/smesh_bvh.cpp b/Cassiopee/XCore/XCore/intersectMesh/smesh_bvh.cpp index 5289eeb83..c9f1c1a11 100644 --- a/Cassiopee/XCore/XCore/intersectMesh/smesh_bvh.cpp +++ b/Cassiopee/XCore/XCore/intersectMesh/smesh_bvh.cpp @@ -47,7 +47,7 @@ void Smesh::make_BVH() tri_idx.clear(); tri_idx.resize(nf); for (E_Int i = 0; i < nf; i++) tri_idx[i] = i; - assert(fcenters.size() == nf*3); + assert(fcenters.size() == (size_t)nf*3); // Assign all triangles to root node BVH_node &root = bvh_nodes[root_node_idx]; diff --git a/Cassiopee/XCore/XCore/intersectMesh/smesh_extract.cpp b/Cassiopee/XCore/XCore/intersectMesh/smesh_extract.cpp index 477573981..d02a0a19d 100644 --- a/Cassiopee/XCore/XCore/intersectMesh/smesh_extract.cpp +++ b/Cassiopee/XCore/XCore/intersectMesh/smesh_extract.cpp @@ -112,7 +112,7 @@ std::set Smesh::extract_covering_faces(const Smesh &Sf, if (cmp < 0) std::reverse(pchain.begin(), pchain.end()); */ - Sf.write_points("pchain.im", pchain); + //Sf.write_points("pchain.im", pchain); for (E_Int p : pchain) pchains.push_back({Sf.X[p], Sf.Y[p], Sf.Z[p]}); @@ -263,7 +263,7 @@ std::set Smesh::extract_covering_faces(const Smesh &Sf, assert(walk <= max_walks); } - write_edges("wall", weids); + //write_edges("wall", weids); // TODO(Imad): project wpids on best-fit plane and jarvis march diff --git a/Cassiopee/XCore/XCore/intersectMesh/smesh_reconstruct.cpp b/Cassiopee/XCore/XCore/intersectMesh/smesh_reconstruct.cpp index 46e7c9677..256168170 100644 --- a/Cassiopee/XCore/XCore/intersectMesh/smesh_reconstruct.cpp +++ b/Cassiopee/XCore/XCore/intersectMesh/smesh_reconstruct.cpp @@ -162,8 +162,8 @@ void Smesh::reconstruct(IMesh &M) /* { - if (M.nc > 27555) { - auto pf = M.C[27555]; + if (M.nc > 24) { + auto pf = M.C[24]; std::map local_map; int npts = 0; int i = 0; @@ -176,8 +176,24 @@ void Smesh::reconstruct(IMesh &M) local_map[p] = npts; printf("%d ", npts); - if (npts == 19) { - point_write("point19.im", M.X[p], M.Y[p], M.Z[p]); + if (npts == 10) { + point_write("10.im", M.X[p], M.Y[p], M.Z[p]); + } + + if (npts == 11) { + point_write("11.im", M.X[p], M.Y[p], M.Z[p]); + } + + if (npts == 12) { + point_write("12.im", M.X[p], M.Y[p], M.Z[p]); + } + + if (npts == 13) { + point_write("13.im", M.X[p], M.Y[p], M.Z[p]); + } + + if (npts == 14) { + point_write("14.im", M.X[p], M.Y[p], M.Z[p]); } npts++; diff --git a/Cassiopee/XCore/XCore/intersectMesh/u_edge.h b/Cassiopee/XCore/XCore/intersectMesh/u_edge.h new file mode 100644 index 000000000..050cf627b --- /dev/null +++ b/Cassiopee/XCore/XCore/intersectMesh/u_edge.h @@ -0,0 +1,16 @@ +#pragma once + +#include "xcore.h" + +struct u_edge { + E_Int p, q; + + u_edge(E_Int P, E_Int Q) + : p(std::min(P, Q)), q(std::max(P, Q)) + {} + + bool operator<(const u_edge& e) const + { + return (p < e.p) || (p == e.p && q < e.q); + } +}; \ No newline at end of file diff --git a/Cassiopee/XCore/XCore/xcore.cpp b/Cassiopee/XCore/XCore/xcore.cpp index a43c2eb23..9bd3931ad 100644 --- a/Cassiopee/XCore/XCore/xcore.cpp +++ b/Cassiopee/XCore/XCore/xcore.cpp @@ -61,8 +61,13 @@ static PyMethodDef Pyxcore [] = {"IntersectMesh_Merge", K_XCORE::IntersectMesh_Merge, METH_VARARGS}, {"icapsule_init", K_XCORE::icapsule_init, METH_VARARGS}, + {"icapsule_adapt", K_XCORE::icapsule_adapt, METH_VARARGS}, + {"icapsule_intersect", K_XCORE::icapsule_intersect, METH_VARARGS}, + {"icapsule_extract_master", K_XCORE::icapsule_extract_master, METH_VARARGS}, {"icapsule_extract_slave", K_XCORE::icapsule_extract_slave, METH_VARARGS}, + {"icapsule_extract_slaves", K_XCORE::icapsule_extract_slaves, METH_VARARGS}, + {"triangulate_skin", K_XCORE::triangulate_skin, METH_VARARGS}, {"extractCell", K_XCORE::extractCell, METH_VARARGS}, diff --git a/Cassiopee/XCore/XCore/xcore.h b/Cassiopee/XCore/XCore/xcore.h index b44a83a88..96ef59b50 100644 --- a/Cassiopee/XCore/XCore/xcore.h +++ b/Cassiopee/XCore/XCore/xcore.h @@ -73,8 +73,13 @@ namespace K_XCORE PyObject *IntersectMesh_Merge(PyObject *self, PyObject *args); PyObject *icapsule_init(PyObject *self, PyObject *args); + PyObject *icapsule_adapt(PyObject *self, PyObject *args); + PyObject *icapsule_intersect(PyObject *self, PyObject *args); PyObject *icapsule_extract_master(PyObject *self, PyObject *args); PyObject *icapsule_extract_slave(PyObject *self, PyObject *args); + PyObject *icapsule_extract_slaves(PyObject *self, PyObject *args); + + PyObject *triangulate_skin(PyObject *self, PyObject *args); PyObject *extractCell(PyObject *self, PyObject *args); diff --git a/Cassiopee/XCore/srcs.py b/Cassiopee/XCore/srcs.py index 6c840b75f..6db1086b5 100644 --- a/Cassiopee/XCore/srcs.py +++ b/Cassiopee/XCore/srcs.py @@ -40,6 +40,7 @@ 'XCore/intersectMesh/dcel.cpp', 'XCore/intersectMesh/dcel_extract.cpp', 'XCore/intersectMesh/dcel_io.cpp', + 'XCore/intersectMesh/dcel_reconstruct.cpp', 'XCore/intersectMesh/AABB.cpp', From a7c777ff74d64d0e65b950bb8e5f3be073cc21d7 Mon Sep 17 00:00:00 2001 From: imadhammani Date: Tue, 5 Nov 2024 18:01:36 +0100 Subject: [PATCH 76/86] XCore intersectMesh: started ear-clipping algorithm --- Cassiopee/XCore/XCore/intersectMesh/dcel.cpp | 230 +++++++++++++++++- Cassiopee/XCore/XCore/intersectMesh/dcel.h | 3 + .../XCore/XCore/intersectMesh/icapsule.cpp | 20 +- .../XCore/XCore/intersectMesh/primitives.h | 2 +- .../XCore/intersectMesh/smesh_locate.cpp | 9 + 5 files changed, 249 insertions(+), 15 deletions(-) diff --git a/Cassiopee/XCore/XCore/intersectMesh/dcel.cpp b/Cassiopee/XCore/XCore/intersectMesh/dcel.cpp index 0fcbe40df..e89d344af 100644 --- a/Cassiopee/XCore/XCore/intersectMesh/dcel.cpp +++ b/Cassiopee/XCore/XCore/intersectMesh/dcel.cpp @@ -164,12 +164,12 @@ Dcel Dcel::intersect(const Smesh &Mf, const Smesh &Sf, Mf.get_shared_faces(plocs[p], orig_faces, last_vertex, last_edge); Mf.get_shared_faces(plocs[q], tail_faces, dummy, dummy); - //if (eid_s == 133) { - // point_write("O.im", O->x, O->y, O->z); - // point_write("T.im", T->x, T->y, T->z); - // Mf.write_ngon("ofaces.im", orig_faces); - // Mf.write_ngon("tfaces.im", tail_faces); - //} + if (eid_s == 490) { + point_write("O.im", O->x, O->y, O->z); + point_write("T.im", T->x, T->y, T->z); + Mf.write_ngon("ofaces.im", orig_faces); + Mf.write_ngon("tfaces.im", tail_faces); + } E_Int starting_face = Mf.deduce_face(orig_faces, spx, spy, spz, DIR, last_vertex, last_edge, eid_s); @@ -450,9 +450,227 @@ Dcel Dcel::intersect(const Smesh &Mf, const Smesh &Sf, for (Face *f : D.F) delete f; D.F = new_F; + D.triangulate(Mf, Sf); + return D; } +void Dcel::get_vertex_normal(Vertex *q, const Smesh &Mf, E_Float N[3]) +{ + N[0] = N[1] = N[2] = 0; + if (q->oids[0] != -1) { + const E_Float *pN = &Mf.pnormals[3*q->oids[0]]; + for (E_Int i = 0; i < 3; i++) N[i] = pN[i]; + } else if (q->oids[1] != -1) { + const E_Float *fN = &Mf.fnormals[3*q->ploc.fid]; + for (E_Int i = 0; i < 3; i++) N[i] = fN[i]; + } else { + E_Int fid_m = q->ploc.fid; + E_Int eid_m = Mf.F2E[fid_m][q->ploc.e_idx]; + const auto &pf = Mf.E2F[eid_m]; + assert(pf[0] == fid_m || pf[1] == fid_m); + const E_Float *fN1 = &Mf.fnormals[3*pf[0]]; + const E_Float *fN2 = &Mf.fnormals[3*pf[1]]; + for (int i = 0; i < 3; i++) N[i] += fN1[i] + fN2[i]; + E_Float NORM = K_MATH::norm(N, 3); + for (int i = 0; i < 3; i++) N[i] /= NORM; + } +} + +bool Dcel::is_vertex_in_triangle(Vertex *v, Vertex *a, Vertex *b, Vertex *c) +{ + assert(0); + return true; +} + +// Circular doubly linked list + +struct VNode { + Dcel::Vertex *v; + VNode *next; + VNode *prev; + + VNode(Dcel::Vertex *V) + { + v = V; + next = this; + prev = this; + } +}; + +void VNode_push_front(VNode **head, Dcel::Vertex *v) +{ + VNode *node = new VNode(v); + if (*head == NULL) { + *head = node; + } else { + VNode *last = (*head)->prev; + node->next = *head; + node->prev = last; + last->next = node; + (*head)->prev = node; + *head = node; + } +} + +void VNode_push_back(VNode **head, Dcel::Vertex *v) +{ + VNode *node = new VNode(v); + if (*head == NULL) { + *head = node; + } else { + VNode *last = (*head)->prev; + node->next = *head; + node->prev = last; + last->next = node; + (*head)->prev = node; + } +} + +void VNode_erase(VNode **head, Dcel::Vertex *v) +{ + if (*head == NULL) return; + + VNode *current = *head; + do { + if (current->v == v) { + if (current->next == current) { + // Single node in the list + *head = NULL; + } else { + VNode *prev = current->prev; + VNode *next = current->next; + prev->next = next; + next->prev = prev; + if (current == *head) { + // If head to be deleted, set it to the next element + *head = next; + } + } + delete current; + return; + } + current = current->next; + } while (current != *head); + + assert(0); +} + +void VNode_free_list(VNode *head) +{ + if (!head) return; + VNode *current = head; + do { + VNode *next = current->next; + delete current; + current = next; + } while (current != head); +} + +void Dcel::triangulate(const Smesh &Mf, const Smesh &Sf) +{ + E_Int non_convex_count = 0; + std::vector non_convex_faces; + + for (size_t fid = 0; fid < F.size(); fid++) { + Face *f = F[fid]; + // TODO(Imad): skip single color faces + + auto vertices = get_face_vertices(f); + + for (size_t i = 0; i < vertices.size(); i++) { + Vertex *p = vertices[i]; + Vertex *q = vertices[(i+1)%vertices.size()]; + Vertex *r = vertices[(i+2)%vertices.size()]; + + E_Float A[3] = {q->x-p->x, q->y-p->y, q->z-p->z}; + E_Float B[3] = {r->x-q->x, r->y-q->y, r->z-q->z}; + E_Float C[3]; + K_MATH::cross(A, B, C); + + E_Float N[3]; + get_vertex_normal(q, Mf, N); + + E_Float dp = K_MATH::dot(C, N, 3); + if (dp < 0) { + non_convex_faces.push_back(f); + non_convex_count++; + break; + } + } + } + + printf("Total faces: %lu\n", F.size()); + printf("Non-convex count: %d\n", non_convex_count); + write_ngon("non_convex.im", non_convex_faces); + + for (size_t i = 0; i < non_convex_faces.size(); i++) { + Face *f = non_convex_faces[i]; + + // Store the polygon + + auto vertices = get_face_vertices(f); + + VNode *polygon = NULL; + for (Vertex *v : vertices) VNode_push_back(&polygon, v); + + // Find the convex/reflex vertices + + VNode *convex = NULL, *reflex = NULL; + + for (size_t j = 0; j < vertices.size(); j++) { + Vertex *p = vertices[j]; + Vertex *q = vertices[(j+1)%vertices.size()]; + Vertex *r = vertices[(j+2)%vertices.size()]; + + E_Float A[3] = {q->x-p->x, q->y-p->y, q->z-p->z}; + E_Float B[3] = {r->x-q->x, r->y-q->y, r->z-q->z}; + E_Float C[3]; + K_MATH::cross(A, B, C); + + E_Float N[3]; + get_vertex_normal(q, Mf, N); + + E_Float dp = K_MATH::dot(C, N, 3); + + if (dp < 0) VNode_push_back(&reflex, q); + else VNode_push_back(&convex, q); + } + + // Store the ears + + VNode *ear_tips = NULL; + + for (size_t j = 0; j < vertices.size(); j++) { + Vertex *p = vertices[j]; + Vertex *q = vertices[(j+1)%vertices.size()]; + Vertex *r = vertices[(j+2)%vertices.size()]; + + // An ear does not include any reflex vertex + bool is_ear = true; + VNode *current = reflex; + + do { + Vertex *v = current->v; + if (v != p && v != q && v != r) { + is_ear = !is_vertex_in_triangle(v, p, q, r); + } + current = current->next; + } while (current != reflex && is_ear); + + if (is_ear) + VNode_push_back(&ear_tips, q); + } + + // Ear-clipping algorithm + //while (polygon.size() > 3) { + // + // + //} + + } +} + void Dcel::update_hedge_faces(std::vector &new_F) { for (Hedge *h : H) h->left = NULL; diff --git a/Cassiopee/XCore/XCore/intersectMesh/dcel.h b/Cassiopee/XCore/XCore/intersectMesh/dcel.h index 4a0b8d443..6c9eeffe6 100644 --- a/Cassiopee/XCore/XCore/intersectMesh/dcel.h +++ b/Cassiopee/XCore/XCore/intersectMesh/dcel.h @@ -142,6 +142,7 @@ struct Dcel { void reconstruct(const Smesh &Mf, const Smesh &Sf); static Dcel intersect(const Smesh &Mf, const Smesh &Sf, const std::vector &plocs); + void triangulate(const Smesh &Mf, const Smesh &Sf); // Checks @@ -154,6 +155,8 @@ struct Dcel { Hedge *get_hedge_of_color(Face *f, int color); void update_hedge_faces(std::vector &F); std::vector get_face_vertices(const Face *f) const; + void get_vertex_normal(Vertex *q, const Smesh &Mf, E_Float N[3]); + bool is_vertex_in_triangle(Vertex *v, Vertex *a, Vertex *b, Vertex *c); // Export diff --git a/Cassiopee/XCore/XCore/intersectMesh/icapsule.cpp b/Cassiopee/XCore/XCore/intersectMesh/icapsule.cpp index ec79460b7..7159d3f66 100644 --- a/Cassiopee/XCore/XCore/intersectMesh/icapsule.cpp +++ b/Cassiopee/XCore/XCore/intersectMesh/icapsule.cpp @@ -365,7 +365,7 @@ PyObject *K_XCORE::icapsule_intersect(PyObject *self, PyObject *args) Mf.make_fcenters(); Mf.make_fnormals(); Mf.make_pnormals(); - Mf.write_ngon("Mf.im"); + Mf.write_ngon("Mf_before_intersect.im"); auto &S = Ss[i]; @@ -373,15 +373,19 @@ PyObject *K_XCORE::icapsule_intersect(PyObject *self, PyObject *args) Sf.make_fcenters(); Sf.make_fnormals(); Sf.make_pnormals(); + Sf.write_ngon("Sf_before_intersect.im"); + printf("Sf points: %d\n", Sf.np); auto plocs = Mf.locate(Sf); Dcel D = Dcel::intersect(Mf, Sf, plocs); + E_Int nf_before_intersect = Sf.nf; + D.reconstruct(Mf, Dcel::RED); - Mf.write_ngon("Mf.im"); + Mf.write_ngon("Mf_after_intersect.im"); D.reconstruct(Sf, Dcel::BLACK); - Sf.write_ngon("Sf.im"); + Sf.write_ngon("Sf_after_intersect.im"); { D.write_inner_cycles("intersected.im"); @@ -390,11 +394,11 @@ PyObject *K_XCORE::icapsule_intersect(PyObject *self, PyObject *args) Sf.reconstruct(Ss[i]); // Tag the new Sf faces - //S.ftag.resize(S.nf, 0); - //for (E_Int fid = 0; fid < Sf.nf; fid++) { - // E_Int gfid = Sf.g2lf.at(fid); - // S.ftag[gfid] = 1; - //} + for (E_Int fid = nf_before_intersect; fid < Sf.nf; fid++) { + E_Int gfid = Sf.l2gf.at(fid); + S.ftag.push_back(gfid); + } + assert(S.ftag.size() == Sf.nf); puts(""); } diff --git a/Cassiopee/XCore/XCore/intersectMesh/primitives.h b/Cassiopee/XCore/XCore/intersectMesh/primitives.h index 8e4ad235c..e38935c4d 100644 --- a/Cassiopee/XCore/XCore/intersectMesh/primitives.h +++ b/Cassiopee/XCore/XCore/intersectMesh/primitives.h @@ -22,7 +22,7 @@ #include "common/common.h" -constexpr E_Float TOL = 1e-9; +constexpr E_Float TOL = 1e-11; //constexpr E_Float RAY_EDGE_TOL = 1e-6; E_Int Sign(E_Float x, E_Float tol=TOL); diff --git a/Cassiopee/XCore/XCore/intersectMesh/smesh_locate.cpp b/Cassiopee/XCore/XCore/intersectMesh/smesh_locate.cpp index 0f9dd8283..e7f1c98af 100644 --- a/Cassiopee/XCore/XCore/intersectMesh/smesh_locate.cpp +++ b/Cassiopee/XCore/XCore/intersectMesh/smesh_locate.cpp @@ -29,10 +29,19 @@ std::vector Smesh::locate(const Smesh &Sf) const const auto &pn = Fc[fid]; const E_Float *fc = &fcenters[3*fid]; + if (pid == 276) { + point_write("fc.im", fc[0], fc[1], fc[2]); + } + for (size_t j = 0; j < pn.size(); j++) { E_Int p = pn[j]; E_Int q = pn[(j+1)%pn.size()]; + if (pid == 276) { + point_write("p.im", X[p], Y[p], Z[p]); + point_write("q.im", X[q], Y[q], Z[q]); + } + E_Float u, v, w; found = Triangle::is_point_inside(x, y, z, From d4f0224ec7db18c3f1247341a8e67ab7bb7cc41d Mon Sep 17 00:00:00 2001 From: imadhammani Date: Wed, 13 Nov 2024 17:08:39 +0100 Subject: [PATCH 77/86] OK ENOVAL merged sp with tol = 1e-4 --- Cassiopee/XCore/XCore/PyTree.py | 48 +- Cassiopee/XCore/XCore/intersectMesh/dcel.cpp | 410 +++++++++++++++--- Cassiopee/XCore/XCore/intersectMesh/dcel.h | 13 +- .../XCore/XCore/intersectMesh/dcel_io.cpp | 2 +- .../XCore/intersectMesh/dcel_reconstruct.cpp | 6 +- .../XCore/XCore/intersectMesh/icapsule.cpp | 156 +++++-- .../XCore/intersectMesh/icapsule_refine.cpp | 2 +- Cassiopee/XCore/XCore/intersectMesh/mesh.h | 6 +- .../XCore/XCore/intersectMesh/meshExport.cpp | 6 +- .../XCore/XCore/intersectMesh/primitives.cpp | 2 +- .../XCore/XCore/intersectMesh/primitives.h | 2 +- Cassiopee/XCore/XCore/intersectMesh/smesh.h | 17 + .../XCore/XCore/intersectMesh/smesh_geom.cpp | 1 + .../XCore/intersectMesh/smesh_locate.cpp | 167 +++++++ .../XCore/XCore/intersectMesh/triangle.cpp | 35 +- 15 files changed, 732 insertions(+), 141 deletions(-) diff --git a/Cassiopee/XCore/XCore/PyTree.py b/Cassiopee/XCore/XCore/PyTree.py index 19c46d375..fc6a60f8e 100644 --- a/Cassiopee/XCore/XCore/PyTree.py +++ b/Cassiopee/XCore/XCore/PyTree.py @@ -352,7 +352,7 @@ def removeIntersectingKPlanes(IM, slave_struct): ts = I.newCGNSTree() for slave_base in slave_bases: - + iter = iter + 1 zs = I.getZones(slave_base) @@ -501,10 +501,50 @@ def icapsule_init(mp, sp): return xcore.icapsule_init(marr, sarrs, tags) def icapsule_adapt(IC): - return xcore.icapsule_adapt(IC) + marr, sarrs, stags = xcore.icapsule_adapt(IC) + zm = I.createZoneNode("ma", marr) + assert(len(sarrs) == len(stags)) + slave_zones = [] + for i in range(len(sarrs)): + zs = I.createZoneNode("sa"+str(i), sarrs[i]) + cont = I.createUniqueChild(zs, 'ZoneBC', 'ZoneBC_t') + bc = I.newBC(name="IntersectionFaces", pointList=stags[i], + family="IntersectionFaces", parent=cont) + slave_zones.append(zs) + tm = C.newPyTree(['Base', zm]) + ts = C.newPyTree(['Base', slave_zones]) + return tm, ts + +def icapsule_intersect(ma, sa): + zm = I.getZones(ma)[0] + marr = C.getFields(I.__GridCoordinates__, zm, api=3)[0] + + zs = I.getZones(sa) + sarrs = [] + stags = [] + for zone in zs: + sarr = C.getFields(I.__GridCoordinates__, zone, api=3)[0] + sarrs.append(sarr) + zonebc = I.getNodeFromType(zs, 'ZoneBC_t') + zbc = I.getNodesFromType(zonebc, 'BC_t') + stag = I.getNodeFromName(zbc, 'PointList')[1] + stags.append(stag) + + marr_i, slist_i, stags_i = xcore.icapsule_intersect(marr, sarrs, stags) + + zm = I.createZoneNode("mi", marr_i) + assert(len(slist_i) == len(stags_i)) + slave_zones = [] + for i in range(len(slist_i)): + zs = I.createZoneNode("si"+str(i), slist_i[i]) + cont = I.createUniqueChild(zs, 'ZoneBC', 'ZoneBC_t') + bc = I.newBC(name="IntersectionFaces", pointList=stags_i[i], + family="IntersectionFaces", parent=cont) + slave_zones.append(zs) + tm = C.newPyTree(['Base', zm]) + ts = C.newPyTree(['Base', slave_zones]) + return tm, ts -def icapsule_intersect(IC): - return xcore.icapsule_intersect(IC) def icapsule_extract_master(IC): marr = xcore.icapsule_extract_master(IC) diff --git a/Cassiopee/XCore/XCore/intersectMesh/dcel.cpp b/Cassiopee/XCore/XCore/intersectMesh/dcel.cpp index e89d344af..e3d175d0b 100644 --- a/Cassiopee/XCore/XCore/intersectMesh/dcel.cpp +++ b/Cassiopee/XCore/XCore/intersectMesh/dcel.cpp @@ -66,10 +66,10 @@ void Dcel::init_vertices(const Smesh &Mf, const Smesh &Sf, printf("Duplicate vertices: %d\n", duplicate_vertices); } -std::vector Dcel::get_face_vertices(const Face *f) const +void Dcel::get_face_vertices(const Face *f, std::vector &ret) { assert(f); - std::vector ret; + ret.clear(); Hedge *h = f->rep; ret.push_back(h->orig); Hedge *w = h->next; @@ -77,7 +77,6 @@ std::vector Dcel::get_face_vertices(const Face *f) const ret.push_back(w->orig); w = w->next; } - return ret; } struct HitData { @@ -164,13 +163,6 @@ Dcel Dcel::intersect(const Smesh &Mf, const Smesh &Sf, Mf.get_shared_faces(plocs[p], orig_faces, last_vertex, last_edge); Mf.get_shared_faces(plocs[q], tail_faces, dummy, dummy); - if (eid_s == 490) { - point_write("O.im", O->x, O->y, O->z); - point_write("T.im", T->x, T->y, T->z); - Mf.write_ngon("ofaces.im", orig_faces); - Mf.write_ngon("tfaces.im", tail_faces); - } - E_Int starting_face = Mf.deduce_face(orig_faces, spx, spy, spz, DIR, last_vertex, last_edge, eid_s); assert(starting_face != -1); @@ -182,8 +174,12 @@ Dcel Dcel::intersect(const Smesh &Mf, const Smesh &Sf, E_Int walk = 0; E_Int max_walks = 20; + std::vector path; + while (!found_tail && walk <= max_walks) { + path.push_back(cur_fid); + for (auto fid : tail_faces) { if (fid == cur_fid) { found_tail = true; @@ -193,6 +189,14 @@ Dcel Dcel::intersect(const Smesh &Mf, const Smesh &Sf, if (found_tail) break; + // Update the direction + DIR[0] = sqx-cur_pos[0]; + DIR[1] = sqy-cur_pos[1]; + DIR[2] = sqz-cur_pos[2]; + E_Float NORM = K_MATH::norm(DIR, 3); + DIR[0] /= NORM, DIR[1] /= NORM, DIR[2] /= NORM; + + // Project E_Float proj[3]; Mf.get_unit_projected_direction(cur_fid, DIR, proj); @@ -230,7 +234,7 @@ Dcel Dcel::intersect(const Smesh &Mf, const Smesh &Sf, hitData.push_back({t, s}); if (hit) { - if (s > TOL && s < 1 - TOL) { + if (s > RAY_EDGE_TOL && s < 1 - RAY_EDGE_TOL) { // Hit edge middle const auto &pe = Mf.F2E[cur_fid]; E_Int eid_m = pe[i]; @@ -244,6 +248,10 @@ Dcel Dcel::intersect(const Smesh &Mf, const Smesh &Sf, next_pos[1] = cur_pos[1] + t * proj[1]; next_pos[2] = cur_pos[2] + t * proj[2]; + if (eid_s == 80) { + point_write("x.im", next_pos[0], next_pos[1], next_pos[2]); + } + // Create a new intersection vertex Vertex tmp(next_pos[0], next_pos[1], next_pos[2]); assert(D.vertex_set.find(&tmp) == D.vertex_set.end()); @@ -269,8 +277,8 @@ Dcel Dcel::intersect(const Smesh &Mf, const Smesh &Sf, } else { // Hit an edge endpoint - bool hit_p = (s <= TOL); - bool hit_q = (s >= 1 - TOL); + bool hit_p = (s <= RAY_EDGE_TOL); + bool hit_q = (s >= 1 - RAY_EDGE_TOL); assert(!(hit_p && hit_q)); last_edge = -1; if (hit_p) last_vertex = p; @@ -279,6 +287,12 @@ Dcel Dcel::intersect(const Smesh &Mf, const Smesh &Sf, next_pos[1] = Mf.Y[last_vertex]; next_pos[2] = Mf.Z[last_vertex]; const auto &pf = Mf.P2F[last_vertex]; + + if (eid_s == 80) { + Mf.write_ngon("pf.im", pf); + point_write("x.im", next_pos[0], next_pos[1], next_pos[2]); + } + next_fid = Mf.deduce_face(pf, next_pos[0], next_pos[1], next_pos[2], DIR, last_vertex, last_edge, eid_s @@ -319,6 +333,13 @@ Dcel Dcel::intersect(const Smesh &Mf, const Smesh &Sf, walk++; } + if (!found_tail) { + edge_write("lost_edge.im", spx, spy, spz, sqx, sqy, sqz); + Mf.write_ngon("orig_faces.im", orig_faces); + Mf.write_ngon("tail_faces.im", tail_faces); + Mf.write_ngon("path.im", path); + } + assert(found_tail); assert(walk <= max_walks); } @@ -450,12 +471,18 @@ Dcel Dcel::intersect(const Smesh &Mf, const Smesh &Sf, for (Face *f : D.F) delete f; D.F = new_F; - D.triangulate(Mf, Sf); + D.Fv.resize(D.F.size()); + for (size_t fid = 0; fid < D.F.size(); fid++) { + D.get_face_vertices(D.F[fid], D.Fv[fid]); + } + + //D.triangulate(Mf, Sf); return D; } -void Dcel::get_vertex_normal(Vertex *q, const Smesh &Mf, E_Float N[3]) +static +void get_vertex_normal(const Dcel::Vertex *q, const Smesh &Mf, E_Float N[3]) { N[0] = N[1] = N[2] = 0; if (q->oids[0] != -1) { @@ -477,12 +504,6 @@ void Dcel::get_vertex_normal(Vertex *q, const Smesh &Mf, E_Float N[3]) } } -bool Dcel::is_vertex_in_triangle(Vertex *v, Vertex *a, Vertex *b, Vertex *c) -{ - assert(0); - return true; -} - // Circular doubly linked list struct VNode { @@ -527,9 +548,9 @@ void VNode_push_back(VNode **head, Dcel::Vertex *v) } } -void VNode_erase(VNode **head, Dcel::Vertex *v) +bool VNode_erase(VNode **head, Dcel::Vertex *v) { - if (*head == NULL) return; + if (*head == NULL) return false; VNode *current = *head; do { @@ -548,12 +569,73 @@ void VNode_erase(VNode **head, Dcel::Vertex *v) } } delete current; - return; + return true; } current = current->next; } while (current != *head); assert(0); + return false; +} + +VNode *VNode_find(const VNode *head, const Dcel::Vertex *v) +{ + if (!head) return NULL; + + VNode *current = (VNode *)head; + do { + if (current->v == v) return current; + current = current->next; + } while (current != head); + return NULL; +} + +static +bool vertex_is_in_triangle(const Dcel::Vertex *v, const Dcel::Vertex *a, + const Dcel::Vertex *b, const Dcel::Vertex *c) +{ + return Triangle::is_point_inside(v->x, v->y, v->z, + a->x, a->y, a->z, b->x, b->y, b->z, c->x, c->y, c->z); +} + +static +bool vertex_is_ear(const Dcel::Vertex *b, const VNode *polygon, + const VNode *convex, const VNode *reflex) +{ + // Polygon empty + if (!polygon) return false; + + // Vertex not in polygon + VNode *node = VNode_find(polygon, b); + if (!node) return false; + + // Vertex not convex + if (!VNode_find(convex, b)) return false; + + // No reflex vertices + if (!reflex) return true; + + const Dcel::Vertex *a = node->prev->v; + const Dcel::Vertex *c = node->next->v; + + // Test the inclusion of all reflex vertices within triangle {a, b, c} + VNode *current = (VNode *)reflex; + bool is_ear = true; + + do { + Dcel::Vertex *v = current->v; + + if (v != a && v != b && v != c && + vertex_is_in_triangle(v, a, b, c)) { + is_ear = false; + break; + } + + current = current->next; + + } while (current != reflex); + + return is_ear; } void VNode_free_list(VNode *head) @@ -567,22 +649,73 @@ void VNode_free_list(VNode *head) } while (current != head); } +void VNode_print_list(const VNode *head) +{ + if (!head) return; + + VNode *current = (VNode *)head; + + do { + printf("%d ", current->v->id); + current = current->next; + } while (current != head); + + printf("\n"); + fflush(stdout); +} + +struct Vertex_triple +{ + Dcel::Vertex *a, *b, *c; +}; + +static +bool vertex_list_is_convex(const Dcel::Vertex *p, const Dcel::Vertex *q, + const Dcel::Vertex *r, const Smesh &Mf) +{ + E_Float A[3] = {q->x-p->x, q->y-p->y, q->z-p->z}; + E_Float B[3] = {r->x-q->x, r->y-q->y, r->z-q->z}; + E_Float C[3]; + K_MATH::cross(A, B, C); + + E_Float N[3]; + get_vertex_normal(q, Mf, N); + + E_Float dp = K_MATH::dot(C, N, 3); + if (dp > TOL) return true; + return false; +} + +static +bool vertex_is_convex(const Dcel::Vertex *b, const VNode *polygon, + const Smesh &Mf) +{ + VNode *node = VNode_find(polygon, b); + if (!node) return false; + + const Dcel::Vertex *a = node->prev->v; + const Dcel::Vertex *c = node->next->v; + + return vertex_list_is_convex(a, b, c, Mf); +} + void Dcel::triangulate(const Smesh &Mf, const Smesh &Sf) { E_Int non_convex_count = 0; - std::vector non_convex_faces; + std::vector non_convex_faces; for (size_t fid = 0; fid < F.size(); fid++) { Face *f = F[fid]; // TODO(Imad): skip single color faces - auto vertices = get_face_vertices(f); + const auto &vertices = Fv[fid]; + if (vertices.size() == 3) continue; for (size_t i = 0; i < vertices.size(); i++) { Vertex *p = vertices[i]; Vertex *q = vertices[(i+1)%vertices.size()]; Vertex *r = vertices[(i+2)%vertices.size()]; - + E_Float A[3] = {q->x-p->x, q->y-p->y, q->z-p->z}; E_Float B[3] = {r->x-q->x, r->y-q->y, r->z-q->z}; E_Float C[3]; @@ -593,7 +726,19 @@ void Dcel::triangulate(const Smesh &Mf, const Smesh &Sf) E_Float dp = K_MATH::dot(C, N, 3); if (dp < 0) { - non_convex_faces.push_back(f); + /* + write_vertex("p.im", p); + write_vertex("q.im", q); + write_vertex("r.im", r); + */ + + std::vector face; + face.push_back(fid); + char fname[16] = {0}; + sprintf(fname, "fid%d.im", non_convex_count); + write_ngon(fname, face); + + non_convex_faces.push_back(fid); non_convex_count++; break; } @@ -604,71 +749,197 @@ void Dcel::triangulate(const Smesh &Mf, const Smesh &Sf) printf("Non-convex count: %d\n", non_convex_count); write_ngon("non_convex.im", non_convex_faces); + std::vector new_faces; + for (size_t i = 0; i < non_convex_faces.size(); i++) { - Face *f = non_convex_faces[i]; + E_Int fid = non_convex_faces[i]; - // Store the polygon + const auto &vertices = Fv[fid]; + assert(vertices.size() > 3); - auto vertices = get_face_vertices(f); + // Store the polygon VNode *polygon = NULL; for (Vertex *v : vertices) VNode_push_back(&polygon, v); + { + VNode *current = polygon; + E_Int vid = 0; + do { + Vertex *v = current->v; + char fname[16] = {0}; + sprintf(fname, "vertex%d.im", vid); + point_write(fname, v->x, v->y, v->z); + current = current->next; + vid++; + } while (current != polygon); + } + // Find the convex/reflex vertices VNode *convex = NULL, *reflex = NULL; + VNode *current = polygon; + do { + if (vertex_is_convex(current->v, polygon, Mf)) { + VNode_push_back(&convex, current->v); + } else { + VNode_push_back(&reflex, current->v); + } - for (size_t j = 0; j < vertices.size(); j++) { - Vertex *p = vertices[j]; - Vertex *q = vertices[(j+1)%vertices.size()]; - Vertex *r = vertices[(j+2)%vertices.size()]; + current = current->next; + } while (current != polygon); - E_Float A[3] = {q->x-p->x, q->y-p->y, q->z-p->z}; - E_Float B[3] = {r->x-q->x, r->y-q->y, r->z-q->z}; - E_Float C[3]; - K_MATH::cross(A, B, C); + // Store the ears - E_Float N[3]; - get_vertex_normal(q, Mf, N); + VNode *ears = NULL; + assert(current == polygon); + do { + if (vertex_is_ear(current->v, polygon, convex, reflex)) + VNode_push_back(&ears, current->v); + current = current->next; + } while (current != polygon); - E_Float dp = K_MATH::dot(C, N, 3); + // Ear-clipping algorithm + + size_t polygon_size = vertices.size(); + + std::vector tris; - if (dp < 0) VNode_push_back(&reflex, q); - else VNode_push_back(&convex, q); + if (i == 0) { + point_write("polygon_head.im", polygon->v->x, polygon->v->y, polygon->v->z); + printf("polygon before: "); + VNode_print_list(polygon); + printf("ears before: "); + VNode_print_list(ears); + printf("convex before: "); + VNode_print_list(convex); + printf("reflex before: "); + VNode_print_list(reflex); } - // Store the ears + while (polygon_size != 3) { + // Current ear is one of the resulting triangles + Vertex *b = ears->v; + VNode *node = VNode_find(polygon, b); + Vertex *a = node->prev->v; + Vertex *c = node->next->v; + tris.push_back({a, b, c}); + + if (i == 0) { + point_write("a.im", a->x, a->y, a->z); + point_write("b.im", b->x, b->y, b->z); + point_write("c.im", c->x, c->y, c->z); + } - VNode *ear_tips = NULL; + // Delete current ear tip from ear tip list + VNode_erase(&ears, b); - for (size_t j = 0; j < vertices.size(); j++) { - Vertex *p = vertices[j]; - Vertex *q = vertices[(j+1)%vertices.size()]; - Vertex *r = vertices[(j+2)%vertices.size()]; + // Delete current ear tip from polygon + VNode_erase(&polygon, b); + polygon_size--; - // An ear does not include any reflex vertex - bool is_ear = true; - VNode *current = reflex; - - do { - Vertex *v = current->v; - if (v != p && v != q && v != r) { - is_ear = !is_vertex_in_triangle(v, p, q, r); + // Delete current ear tip from convex list + VNode_erase(&convex, b); + + // Rules after ear tip deletion: + // - if an adjacent vertex was convex, it remains convex, and may become an ear. + // - if an adjacent vertex was an ear, it does not necessarily remains an ear. + // - if an adjacent vertex was reflex, it may become convex and possibly and ear. + + // Update prev + + bool was_convex = (VNode_find(convex, a) != NULL); + if (was_convex) { + if (!VNode_find(ears, a)) { + if (vertex_is_ear(a, polygon, convex, reflex)) { + VNode_push_back(&ears, a); + } } - current = current->next; - } while (current != reflex && is_ear); + } else { + assert(VNode_find(reflex, a)); + if (vertex_is_convex(a, polygon, Mf)) { + VNode_erase(&reflex, a); + VNode_push_back(&convex, a); + + assert(!VNode_find(ears, a)); + if (vertex_is_ear(a, polygon, convex, reflex)) { + VNode_push_back(&ears, a); + } + } + } - if (is_ear) - VNode_push_back(&ear_tips, q); + // Update next + + was_convex = (VNode_find(convex, c) != NULL); + if (was_convex) { + if (!VNode_find(ears, c)) { + if (vertex_is_ear(c, polygon, convex, reflex)) { + VNode_push_back(&ears, c); + } + } + } else { + assert(VNode_find(reflex, c)); + if (vertex_is_convex(c, polygon, Mf)) { + VNode_erase(&reflex, c); + VNode_push_back(&convex, c); + + assert(!VNode_find(ears, c)); + if (vertex_is_ear(c, polygon, convex, reflex)) { + VNode_push_back(&ears, c); + } + } + } } - // Ear-clipping algorithm - //while (polygon.size() > 3) { - // - // - //} + if (i == 0) { + printf("polygon after: "); + VNode_print_list(polygon); + printf("ears after: "); + VNode_print_list(ears); + printf("convex after: "); + VNode_print_list(convex); + printf("reflex after: "); + VNode_print_list(reflex); + puts(""); + } + + tris.push_back({polygon->prev->v, polygon->v, polygon->next->v}); + + assert(tris.size() == vertices.size()-2); + + // From the triangles, create new face records. + // These face records inherit the color of the parent face. + if (i == 0) { + for (size_t j = 0; j < tris.size(); j++) { + write_vertex("a.im", tris[j].a); + write_vertex("b.im", tris[j].b); + write_vertex("c.im", tris[j].c); + printf("bleu"); + } + } + // Replace fid by the first + + for (size_t j = 0; j < tris.size(); j++) { + const auto &tri = tris[j]; + if (j == 0) { + Fv[fid] = {tri.a, tri.b, tri.c}; + } else { + Face *new_f = new Face; + new_f->oids[0] = F[fid]->oids[0]; + new_f->oids[1] = F[fid]->oids[1]; + Fv.push_back({tri.a, tri.b, tri.c}); + F.push_back(new_f); + } + } + + VNode_free_list(polygon); + VNode_free_list(reflex); + VNode_free_list(ears); + VNode_free_list(convex); } + + //printf("Total faces: %lu\n", F.size()); } void Dcel::update_hedge_faces(std::vector &new_F) @@ -985,6 +1256,11 @@ void Dcel::sort_leaving_hedges(std::vector &leaving, Hedge *h = leaving[i]; Hedge *w = leaving[j]; + if (h->color == w->color) { + write_hedge("h.im", h); + write_hedge("w.im", w); + } + assert(h->color != w->color); Vertex *O_h = h->orig; diff --git a/Cassiopee/XCore/XCore/intersectMesh/dcel.h b/Cassiopee/XCore/XCore/intersectMesh/dcel.h index 6c9eeffe6..b2bc357ff 100644 --- a/Cassiopee/XCore/XCore/intersectMesh/dcel.h +++ b/Cassiopee/XCore/XCore/intersectMesh/dcel.h @@ -108,6 +108,8 @@ struct Dcel { std::vector F; std::vector C; + std::vector> Fv; + std::set vertex_set; E_Int inner = 0; @@ -154,16 +156,17 @@ struct Dcel { Hedge *get_hedge_of_color(Face *f, int color); void update_hedge_faces(std::vector &F); - std::vector get_face_vertices(const Face *f) const; - void get_vertex_normal(Vertex *q, const Smesh &Mf, E_Float N[3]); - bool is_vertex_in_triangle(Vertex *v, Vertex *a, Vertex *b, Vertex *c); + void get_face_vertices(const Face *f, std::vector &vertices); + //void get_vertex_normal(Vertex *q, const Smesh &Mf, E_Float N[3]); + //bool is_vertex_in_triangle(Vertex *v, Vertex *a, Vertex *b, Vertex *c); + //bool vertex_list_is_convex(const Vertex *a, const Vertex *b, + // const Vertex *c, const Smesh &Mf); // Export Smesh export_smesh(bool check_Euler=true) const; void reconstruct(Smesh &Mf, int color) const; - // Extract std::vector extract_indices_of_type(int inout) const; @@ -176,7 +179,7 @@ struct Dcel { void write_faces(const char *fname, const std::vector &faces, E_Float scale = 1.0) const; void write_hedge(const char *fname, const Hedge *h) const; - void write_point(const char *fname, const Vertex *v) const; + void write_vertex(const char *fname, const Vertex *v) const; void write_point(const char *fname, const std::vector &I) const; void write_ngon(const char *fname, const std::vector &cycles) const; void write_ngon(const char *fname, const std::vector &faces) const; diff --git a/Cassiopee/XCore/XCore/intersectMesh/dcel_io.cpp b/Cassiopee/XCore/XCore/intersectMesh/dcel_io.cpp index 216c82c42..d8ee0f44a 100644 --- a/Cassiopee/XCore/XCore/intersectMesh/dcel_io.cpp +++ b/Cassiopee/XCore/XCore/intersectMesh/dcel_io.cpp @@ -80,7 +80,7 @@ void Dcel::write_hedge(const char *fname, const Hedge *h) const fclose(fh); } -void Dcel::write_point(const char *fname, const Vertex *v) const +void Dcel::write_vertex(const char *fname, const Vertex *v) const { FILE *fh = fopen(fname, "w"); assert(fh); diff --git a/Cassiopee/XCore/XCore/intersectMesh/dcel_reconstruct.cpp b/Cassiopee/XCore/XCore/intersectMesh/dcel_reconstruct.cpp index 200888ef7..f717887d4 100644 --- a/Cassiopee/XCore/XCore/intersectMesh/dcel_reconstruct.cpp +++ b/Cassiopee/XCore/XCore/intersectMesh/dcel_reconstruct.cpp @@ -33,7 +33,7 @@ void Dcel::reconstruct(Smesh &Mf, int color) const for (size_t i = 0; i < faces_to_keep.size(); i++) { E_Int fid = faces_to_keep[i]; Face *f = F[fid]; - auto vertices = get_face_vertices(f); + const auto &vertices = Fv[fid]; for (size_t j = 0; j < vertices.size(); j++) { Vertex *v = vertices[j]; if (v->oids[color] != -1) continue; @@ -53,7 +53,7 @@ void Dcel::reconstruct(Smesh &Mf, int color) const const auto &children = fdat.second; // In Mf, replace parent with first child - auto vertices = get_face_vertices(F[children[0]]); + const auto &vertices = Fv[children[0]]; std::vector PN(vertices.size()); for (size_t i = 0; i < vertices.size(); i++) { Vertex *v = vertices[i]; @@ -72,7 +72,7 @@ void Dcel::reconstruct(Smesh &Mf, int color) const // Add the rest of the children for (size_t i = 1; i < children.size(); i++) { Face *f = F[children[i]]; - auto vertices = get_face_vertices(f); + const auto &vertices = Fv[children[i]]; std::vector PN(vertices.size()); for (size_t j = 0; j < vertices.size(); j++) { Vertex *v = vertices[j]; diff --git a/Cassiopee/XCore/XCore/intersectMesh/icapsule.cpp b/Cassiopee/XCore/XCore/intersectMesh/icapsule.cpp index 7159d3f66..6aa1723ad 100644 --- a/Cassiopee/XCore/XCore/intersectMesh/icapsule.cpp +++ b/Cassiopee/XCore/XCore/intersectMesh/icapsule.cpp @@ -280,15 +280,19 @@ PyObject *K_XCORE::icapsule_adapt(PyObject *self, PyObject *args) Smesh Mf(M, M.skin, false); puts("Making surface mesh data"); - Mf.make_bbox(); - Mf.hash_faces(); - Mf.make_fcenters(); - Mf.make_fnormals(); - Mf.make_pnormals(); + Mf.write_ngon("Mf_before_inter.im"); for (size_t i = 0; i < Ss.size(); i++) { printf("S%lu\n", i); + + Mf.make_bbox(); + Mf.hash_faces(); + Mf.make_fcenters(); + Mf.make_fnormals(); + Mf.make_pnormals(); + Mf.make_point_faces(); + auto &S = Ss[i]; Smesh Sf = Smesh::Smesh_from_point_tags(S, S.ptag.data(), true); @@ -299,12 +303,12 @@ PyObject *K_XCORE::icapsule_adapt(PyObject *self, PyObject *args) Sf.make_bbox(); Sf.hash_faces(); Sf.compute_min_distance_between_points(); - printf("Min dist: %f\n", Sf.min_pdist); + //printf("Min dist: %f\n", Sf.min_pdist); - Sf.write_ngon("Sf_before_inter.im"); + //Sf.write_ngon("Sf_before_inter.im"); // Locate Sf points on Mf faces - auto plocs = Mf.locate(Sf); + auto plocs = Mf.locate2(Sf); std::vector spids(Sf.np); for (int i = 0; i < Sf.np; i++) spids[i] = i; Sf.replace_by_projections(spids, plocs); @@ -327,44 +331,89 @@ PyObject *K_XCORE::icapsule_adapt(PyObject *self, PyObject *args) Mf.reconstruct(M); - //PyObject *marray = M.export_karray(); - //PyObject *sarrays = PyList_New(0); - //for (const auto &Ss) + PyObject *out = PyList_New(0); + PyList_Append(out, M.export_karray()); + + PyObject *slist = PyList_New(0); + for (const auto &S : Ss) { + PyList_Append(slist, S.export_karray()); + } + PyList_Append(out, slist); + Py_DECREF(slist); + + PyObject *tlist = PyList_New(0); + for (const auto &S : Ss) { + npy_intp dims[2]; + dims[0] = (npy_intp)S.ftag.size(); + dims[1] = 1; + PyArrayObject *arr = (PyArrayObject *)PyArray_SimpleNew(1, dims, E_NPY_INT); + E_Int *ptr = (E_Int *)PyArray_DATA(arr); + for (size_t i = 0; i < S.ftag.size(); i++) ptr[i] = S.ftag[i]+1; + PyList_Append(tlist, (PyObject *)arr); + Py_DECREF(arr); + } + PyList_Append(out, tlist); + Py_DECREF(tlist); - return Py_None; + return out; } PyObject *K_XCORE::icapsule_intersect(PyObject *self, PyObject *args) { - PyObject *ICAPSULE; - if (!PYPARSETUPLE_(args, O_, &ICAPSULE)) { + PyObject *MASTER, *SLAVES, *STAGS; + if (!PYPARSETUPLE_(args, OOO_, &MASTER, &SLAVES, &STAGS)) { RAISE("Bad input."); return NULL; } - if (!PyCapsule_IsValid(ICAPSULE, "ICAPSULE")) { - RAISE("Bad capsule hook."); + Karray marray; + int ret = Karray_parse_ngon(MASTER, marray); + if (ret != 0) { + RAISE("Bad master mesh."); return NULL; } + IMesh M(marray); - ICapsule *icap = (ICapsule *)PyCapsule_GetPointer(ICAPSULE, "ICAPSULE"); + int slave_count = PyList_Size(SLAVES); + std::vector Ss; + Ss.reserve(slave_count); - // Intersect - auto &M = icap->M; - auto &Ss = icap->Ss; + for (int i = 0; i < slave_count; i++) { + Karray sarray; + ret = Karray_parse_ngon(PyList_GetItem(SLAVES, i), sarray); + assert(ret == 0); + IMesh S(sarray); + S.make_skin(); + S.orient_skin(IN); + + PyObject *STAG = PyList_GetItem(STAGS, i); + E_Int *tag = NULL; + E_Int tag_size = -1; + ret = K_NUMPY::getFromNumpyArray(STAG, tag, tag_size, true); + assert(ret == 1); + printf("tag_size = %lu\n", tag_size); + S.ftag.reserve(tag_size); + for (int j = 0; j < tag_size; j++) S.ftag.push_back(tag[j]-1); + + Ss.push_back(S); + } M.make_skin(); M.orient_skin(OUT); Smesh Mf(M, M.skin, false); - //for (size_t i = 0; i < 4; i++) { - for (size_t i = 0; i < Ss.size(); i++) { + for (E_Int i = Ss.size()-1; i >= 0; i--) { + //for (size_t i = 0; i < Ss.size(); i++) { + + printf("Intersecting slave %d\n", i); Mf.make_bbox(); Mf.hash_faces(); Mf.make_fcenters(); Mf.make_fnormals(); Mf.make_pnormals(); + Mf.make_point_faces(); + Mf.write_ngon("Mf_before_intersect.im"); auto &S = Ss[i]; @@ -373,10 +422,14 @@ PyObject *K_XCORE::icapsule_intersect(PyObject *self, PyObject *args) Sf.make_fcenters(); Sf.make_fnormals(); Sf.make_pnormals(); - Sf.write_ngon("Sf_before_intersect.im"); - printf("Sf points: %d\n", Sf.np); + + { + char fname[32] = {0}; + sprintf(fname, "Sf_before_intersect_%d.im", i); + Sf.write_ngon(fname); + } - auto plocs = Mf.locate(Sf); + auto plocs = Mf.locate2(Sf); Dcel D = Dcel::intersect(Mf, Sf, plocs); @@ -384,26 +437,57 @@ PyObject *K_XCORE::icapsule_intersect(PyObject *self, PyObject *args) D.reconstruct(Mf, Dcel::RED); Mf.write_ngon("Mf_after_intersect.im"); + D.reconstruct(Sf, Dcel::BLACK); - Sf.write_ngon("Sf_after_intersect.im"); { - D.write_inner_cycles("intersected.im"); + char fname[32] = {0}; + sprintf(fname, "Sf_after_intersect_%d.im", i); + Sf.write_ngon(fname); } - Sf.reconstruct(Ss[i]); - - // Tag the new Sf faces - for (E_Int fid = nf_before_intersect; fid < Sf.nf; fid++) { - E_Int gfid = Sf.l2gf.at(fid); - S.ftag.push_back(gfid); + { + char fname[32] = {0}; + sprintf(fname, "intersected_enoval_%d.im", i); + D.write_inner_cycles(fname); } - assert(S.ftag.size() == Sf.nf); + + Sf.reconstruct(S); + + // Tag Sf faces + Sf.tag_faces(S); puts(""); } Mf.reconstruct(M); - return Py_None; -} \ No newline at end of file + PyObject *out = PyList_New(0); + + PyList_Append(out, M.export_karray()); + + PyObject *slist = PyList_New(0); + + for (const auto &S : Ss) { + PyList_Append(slist, S.export_karray()); + } + + PyList_Append(out, slist); + Py_DECREF(slist); + + PyObject *tlist = PyList_New(0); + for (const auto &S : Ss) { + npy_intp dims[2]; + dims[0] = (npy_intp)S.ftag.size(); + dims[1] = 1; + PyArrayObject *arr = (PyArrayObject *)PyArray_SimpleNew(1, dims, E_NPY_INT); + E_Int *ptr = (E_Int *)PyArray_DATA(arr); + for (size_t i = 0; i < S.ftag.size(); i++) ptr[i] = S.ftag[i]+1; + PyList_Append(tlist, (PyObject *)arr); + Py_DECREF(arr); + } + PyList_Append(out, tlist); + Py_DECREF(tlist); + + return out; +} diff --git a/Cassiopee/XCore/XCore/intersectMesh/icapsule_refine.cpp b/Cassiopee/XCore/XCore/intersectMesh/icapsule_refine.cpp index 85a81e973..70d4e0261 100644 --- a/Cassiopee/XCore/XCore/intersectMesh/icapsule_refine.cpp +++ b/Cassiopee/XCore/XCore/intersectMesh/icapsule_refine.cpp @@ -112,7 +112,7 @@ std::vector ICapsule::refine(Smesh &Mf, std::set &mfids, // Reproject spids on mfaces Mf.make_fcenters(); - plocs_s = Mf.locate(Sf); + plocs_s = Mf.locate2(Sf); Sf.replace_by_projections(spids, plocs_s); // Deduce mfids to refine diff --git a/Cassiopee/XCore/XCore/intersectMesh/mesh.h b/Cassiopee/XCore/XCore/intersectMesh/mesh.h index 2b703b40b..390f840d8 100644 --- a/Cassiopee/XCore/XCore/intersectMesh/mesh.h +++ b/Cassiopee/XCore/XCore/intersectMesh/mesh.h @@ -200,11 +200,11 @@ struct IMesh { void get_fleaves(E_Int face, std::vector &fleaves); - PyObject *export_karray(E_Int remove_periodic = 0); + PyObject *export_karray(E_Int remove_periodic = 0) const; - PyObject *export_karray_orig(); + PyObject *export_karray_orig() const; - PyObject *export_karray_periodic(); + PyObject *export_karray_periodic() const; /* TOPO */ diff --git a/Cassiopee/XCore/XCore/intersectMesh/meshExport.cpp b/Cassiopee/XCore/XCore/intersectMesh/meshExport.cpp index ba3d7c72e..50a7f310d 100644 --- a/Cassiopee/XCore/XCore/intersectMesh/meshExport.cpp +++ b/Cassiopee/XCore/XCore/intersectMesh/meshExport.cpp @@ -1,13 +1,13 @@ #include "mesh.h" -PyObject *IMesh::export_karray(E_Int remove_periodic) +PyObject *IMesh::export_karray(E_Int remove_periodic) const { if (remove_periodic) return export_karray_periodic(); return export_karray_orig(); } -PyObject *IMesh::export_karray_periodic() +PyObject *IMesh::export_karray_periodic() const { // Keep the cells whose tag is 1 @@ -141,7 +141,7 @@ PyObject *IMesh::export_karray_periodic() return array; } -PyObject *IMesh::export_karray_orig() +PyObject *IMesh::export_karray_orig() const { E_Int sizeNGon = 0, sizeNFace = 0; diff --git a/Cassiopee/XCore/XCore/intersectMesh/primitives.cpp b/Cassiopee/XCore/XCore/intersectMesh/primitives.cpp index 00b766921..c788780ab 100644 --- a/Cassiopee/XCore/XCore/intersectMesh/primitives.cpp +++ b/Cassiopee/XCore/XCore/intersectMesh/primitives.cpp @@ -92,7 +92,7 @@ bool ray_edge_intersect(E_Float ox, E_Float oy, E_Float oz, u = K_MATH::dot(tmp, n, 3) / denom; - if (u < -TOL || u > 1 + TOL) return false; + if (u < -RAY_EDGE_TOL || u > 1 + RAY_EDGE_TOL) return false; return true; } diff --git a/Cassiopee/XCore/XCore/intersectMesh/primitives.h b/Cassiopee/XCore/XCore/intersectMesh/primitives.h index e38935c4d..977dcfc39 100644 --- a/Cassiopee/XCore/XCore/intersectMesh/primitives.h +++ b/Cassiopee/XCore/XCore/intersectMesh/primitives.h @@ -23,7 +23,7 @@ #include "common/common.h" constexpr E_Float TOL = 1e-11; -//constexpr E_Float RAY_EDGE_TOL = 1e-6; +constexpr E_Float RAY_EDGE_TOL = 1e-5; E_Int Sign(E_Float x, E_Float tol=TOL); diff --git a/Cassiopee/XCore/XCore/intersectMesh/smesh.h b/Cassiopee/XCore/XCore/intersectMesh/smesh.h index 92e2caf8a..a8ad66739 100644 --- a/Cassiopee/XCore/XCore/intersectMesh/smesh.h +++ b/Cassiopee/XCore/XCore/intersectMesh/smesh.h @@ -31,6 +31,16 @@ #define LEFT 0 #define RIGHT 1 +struct Point3D +{ + E_Float x, y, z; +}; + +struct Point2D +{ + E_Float x, y; +}; + struct IMesh; struct AABB; @@ -95,6 +105,12 @@ struct Smesh { E_Float min_pdist = EFLOATMIN; E_Float NEAR_VERTEX_TOL = 1e-3; E_Float NEAR_EDGE_TOL = 1e-3; + + bool is_point_in_3D_polygon(E_Float x, E_Float y, E_Float z, E_Int fid) const; + bool is_point_on_a_polygon_edge(E_Float x, E_Float y, E_Float z, E_Int fid, + PointLoc &ploc) const; + bool is_point_a_polygon_vertex(E_Float x, E_Float y, E_Float z, E_Int fid, + PointLoc &ploc) const; void make_fcenters(); void make_fnormals(); @@ -102,6 +118,7 @@ struct Smesh { void make_point_faces(); void make_point_edges(); std::vector locate(const Smesh &Sf) const; + std::vector locate2(const Smesh &Sf) const; void correct_near_points_and_edges(Smesh &Sf, std::vector &plocs); void get_unit_projected_direction(E_Int fid, const E_Float D[3], E_Float proj[3]) const; diff --git a/Cassiopee/XCore/XCore/intersectMesh/smesh_geom.cpp b/Cassiopee/XCore/XCore/intersectMesh/smesh_geom.cpp index adb6bfbb9..f6ab0ab02 100644 --- a/Cassiopee/XCore/XCore/intersectMesh/smesh_geom.cpp +++ b/Cassiopee/XCore/XCore/intersectMesh/smesh_geom.cpp @@ -63,6 +63,7 @@ void Smesh::get_unit_projected_direction(E_Int fid, const E_Float D[3], // Unit normal const E_Float *fN = &fnormals[3*fid]; + assert(Sign(K_MATH::norm(fN, 3)) != 0); E_Float dp = K_MATH::dot(D, fN, 3); diff --git a/Cassiopee/XCore/XCore/intersectMesh/smesh_locate.cpp b/Cassiopee/XCore/XCore/intersectMesh/smesh_locate.cpp index e7f1c98af..97dcaa948 100644 --- a/Cassiopee/XCore/XCore/intersectMesh/smesh_locate.cpp +++ b/Cassiopee/XCore/XCore/intersectMesh/smesh_locate.cpp @@ -3,6 +3,173 @@ #include "primitives.h" #include "io.h" +bool is_point_in_2D_polygon(Point2D point, Point2D *polygon, int num_points) +{ + bool inside = false; + + for (int i = 0, j = num_points-1; i < num_points; j = i++) { + if (((polygon[i].y > point.y) != (polygon[j].y > point.y)) && + (point.x < (polygon[j].x - polygon[i].x) * (point.y - polygon[i].y) / + (polygon[j].y - polygon[i].y) + polygon[i].x)) { + inside = !inside; + } + } + return inside; +} + +Point2D project_to_2D(Point3D point, const E_Float *N) +{ + Point2D projected; + + if (fabs(N[2]) > fabs(N[0]) && fabs(N[2]) > fabs(N[1])) { + projected.x = point.x; + projected.y = point.y; + } else if (fabs(N[1]) > fabs(N[0])) { + projected.x = point.x; + projected.y = point.z; + } else { + projected.x = point.y; + projected.y = point.z; + } + + return projected; +} + +bool Smesh::is_point_in_3D_polygon(E_Float x, E_Float y, E_Float z, E_Int fid) const +{ + const auto &pn = Fc[fid]; + const auto *fN = &fnormals[3*fid]; + int a = pn[0]; + E_Float ap[3] = {x-X[a], y-Y[a], z-Z[a]}; + E_Float dp = fabs(K_MATH::dot(ap, fN, 3)); + if (dp > TOL) return false; + + Point2D projected_polygon[pn.size()]; + for (int i = 0; i < pn.size(); i++) { + Point3D p = {X[pn[i]], Y[pn[i]], Z[pn[i]]}; + projected_polygon[i] = project_to_2D(p, fN); + } + Point2D projected_point = project_to_2D({x, y, z}, fN); + + + return is_point_in_2D_polygon(projected_point, projected_polygon, pn.size()); +} + +bool Smesh::is_point_a_polygon_vertex(E_Float x, E_Float y, E_Float z, + E_Int fid, PointLoc &ploc) const +{ + const auto &pn = Fc[fid]; + + for (size_t i = 0; i < pn.size(); i++) { + E_Int p = pn[i]; + E_Float dist = (x-X[p])*(x-X[p]) + (y-Y[p])*(y-Y[p]) + (z-Z[p])*(z-Z[p]); + dist = sqrt(dist); + if (dist < 1e-6) { + ploc.v_idx = i; + ploc.x = X[p]; + ploc.y = Y[p]; + ploc.z = Z[p]; + return true; + } + } + + return false; +} + +bool Smesh::is_point_on_a_polygon_edge(E_Float x, E_Float y, E_Float z, + E_Int fid, PointLoc &ploc) const +{ + const auto &pn = Fc[fid]; + + for (size_t i = 0; i < pn.size(); i++) { + E_Int a = pn[i]; + E_Int b = pn[(i+1)%pn.size()]; + + // Check collinearity of ap with ab + E_Float ap[3] = {x-X[a], y-Y[a], z-Z[a]}; + E_Float ab[3] = {X[b]-X[a], Y[b]-Y[a], Z[b]-Z[a]}; + E_Float C[3]; + K_MATH::cross(ap, ab, C); + if (fabs(K_MATH::norm(C, 3)) > TOL) continue; + E_Float dp1 = K_MATH::dot(ap, ab, 3); + E_Float dp2 = K_MATH::dot(ab, ab, 3); + if (dp1 >= 0 && dp1 <= dp2) { + ploc.e_idx = i; + E_Float t; + if (fabs(X[a]-X[b]) > TOL) t = (x-X[a])/(X[b]-X[a]); + else if (fabs(Y[a]-Y[b]) > TOL) t = (y-Y[a])/(Y[b]-Y[a]); + else t = (z-Z[a])/(Z[b]-Z[a]); + ploc.x = X[a] + t * (X[b]-X[a]); + ploc.y = Y[a] + t * (Y[b]-Y[a]); + ploc.z = Z[a] + t * (Z[b]-Z[a]); + return true; + } + } + + return false; +} + +std::vector Smesh::locate2(const Smesh &Sf) const +{ + std::vector plocs(Sf.np); + + size_t on_vertex = 0, on_edge = 0; + + std::vector oedge, dedge; + + for (E_Int pid = 0; pid < Sf.np; pid++) { + E_Float x = Sf.X[pid]; + E_Float y = Sf.Y[pid]; + E_Float z = Sf.Z[pid]; + + E_Int I = floor((x - xmin) / HX); + E_Int J = floor((y - ymin) / HY); + E_Int K = floor((z - zmin) / HZ); + E_Int voxel = get_voxel(I, J, K); + + const auto &pf = bin_faces.at(voxel); + + bool found = false; + + auto &ploc = plocs[pid]; + + for (auto fid : pf) { + found = is_point_in_3D_polygon(x, y, z, fid); + + if (found) { + + ploc.fid = fid; + + if (is_point_a_polygon_vertex(x, y, z, fid, ploc)) { + on_vertex++; + } else if (is_point_on_a_polygon_edge(x, y, z, fid, ploc)) { + oedge.push_back({x, y, z}); + dedge.push_back({ploc.x, ploc.y, ploc.z}); + on_edge++; + } + + break; + } + } + + if (!found) { + fprintf(stderr, "Couldn't locate point %d\n", pid); + point_write("lost.im", x, y, z); + write_ngon("bin.im", pf); + } + + assert(found); + } + + printf("on vertex: %lu\n", on_vertex); + printf("on edge: %lu\n", on_edge); + + point_write("oedge.im", oedge); + point_write("dedge.im", dedge); + + return plocs; +} + std::vector Smesh::locate(const Smesh &Sf) const { std::vector ploc(Sf.np); diff --git a/Cassiopee/XCore/XCore/intersectMesh/triangle.cpp b/Cassiopee/XCore/XCore/intersectMesh/triangle.cpp index 55bb35a0e..43cf77336 100644 --- a/Cassiopee/XCore/XCore/intersectMesh/triangle.cpp +++ b/Cassiopee/XCore/XCore/intersectMesh/triangle.cpp @@ -69,33 +69,36 @@ E_Int Triangle::is_point_inside(E_Float px, E_Float py, E_Float pz, E_Float cx, E_Float cy, E_Float cz) { // Normal vector to the plane - E_Float Y[3] = {bx-ax, by-ay, bz-az}; - E_Float Z[3] = {cx-ax, cy-ay, cz-az}; + E_Float v0[3] = {bx-ax, by-ay, bz-az}; + E_Float v1[3] = {cx-ax, cy-ay, cz-az}; + E_Float v2[3] = {px-ax, py-ay, pz-az}; + E_Float N[3]; - K_MATH::cross(Y, Z, N); + K_MATH::cross(v0, v1, N); - E_Float X[3] = {px-ax, py-ay, pz-az}; + // TODO(Imad): check degenerate triangle with |N| = 0 - E_Float dp = K_MATH::dot(N, X, 3); + E_Float dp = K_MATH::dot(N, v2, 3); // Is the point on the plane? if (dp < -TOL || dp > TOL) return 0; - E_Float x1 = K_MATH::dot(X, Y, 3); - E_Float y1 = K_MATH::dot(Y, Y, 3); - E_Float z1 = K_MATH::dot(Z, Y, 3); - E_Float x2 = K_MATH::dot(X, Z, 3); - E_Float y2 = K_MATH::dot(Y, Z, 3); - E_Float z2 = K_MATH::dot(Z, Z, 3); + E_Float d00 = K_MATH::dot(v0, v0, 3); + E_Float d01 = K_MATH::dot(v0, v1, 3); + E_Float d11 = K_MATH::dot(v1, v1, 3); + E_Float d20 = K_MATH::dot(v2, v0, 3); + E_Float d21 = K_MATH::dot(v2, v1, 3); - E_Float u = (x1*z2 - x2*z1) / (y1*z2 - y2*z1); - if (u < -TOL || u > 1 + TOL) return 0; + E_Float denom = d00 * d11 - d01 * d01; - E_Float v = (-x1*y2 + x2*y1) / (y1*z2 - y2*z1); + E_Float v = (d11*d20 - d01*d21) / denom; if (v < -TOL || v > 1 + TOL) return 0; - - E_Float w = 1 - u - v; + + E_Float w = (d00*d21 - d01*d20) / denom; if (w < -TOL || w > 1 + TOL) return 0; + E_Float u = 1 - v - w; + if (u < -TOL || u > 1 + TOL) return 0; + return 1; } From 1e487d081959e5dd19e112f98c89d93374bc2469 Mon Sep 17 00:00:00 2001 From: imadhammani Date: Thu, 14 Nov 2024 15:16:28 +0100 Subject: [PATCH 78/86] XCore intersectMesh: fixed bug in slave face tags extraction --- Cassiopee/XCore/XCore/PyTree.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cassiopee/XCore/XCore/PyTree.py b/Cassiopee/XCore/XCore/PyTree.py index fc6a60f8e..51289998e 100644 --- a/Cassiopee/XCore/XCore/PyTree.py +++ b/Cassiopee/XCore/XCore/PyTree.py @@ -525,7 +525,7 @@ def icapsule_intersect(ma, sa): for zone in zs: sarr = C.getFields(I.__GridCoordinates__, zone, api=3)[0] sarrs.append(sarr) - zonebc = I.getNodeFromType(zs, 'ZoneBC_t') + zonebc = I.getNodeFromType(zone, 'ZoneBC_t') zbc = I.getNodesFromType(zonebc, 'BC_t') stag = I.getNodeFromName(zbc, 'PointList')[1] stags.append(stag) From 05190f5dbfdd03628ad9174785702a39430b2dda Mon Sep 17 00:00:00 2001 From: imadhammani Date: Thu, 14 Nov 2024 15:22:21 +0100 Subject: [PATCH 79/86] XCore intersectMesh: fixed k-plane for i-j lines completely outside of master mesh --- .../removeIntersectingKPlanes.cpp | 49 ++++++++++++------- 1 file changed, 32 insertions(+), 17 deletions(-) diff --git a/Cassiopee/XCore/XCore/intersectMesh/removeIntersectingKPlanes.cpp b/Cassiopee/XCore/XCore/intersectMesh/removeIntersectingKPlanes.cpp index 31962019a..1bb39b4e7 100644 --- a/Cassiopee/XCore/XCore/intersectMesh/removeIntersectingKPlanes.cpp +++ b/Cassiopee/XCore/XCore/intersectMesh/removeIntersectingKPlanes.cpp @@ -76,6 +76,7 @@ PyObject *handle_slave(const IMesh *M, const Smesh &Mf, Karray& sarray) for (E_Int i = 0; i < ni; i++) { E_Int base = i + ni*j; + bool was_inside = false; for (E_Int k = 0; k < nk; k++) { @@ -91,49 +92,59 @@ PyObject *handle_slave(const IMesh *M, const Smesh &Mf, Karray& sarray) // Cache the point to be projected E_Int proj_id = base + nij*kmax[base]; proj_points.push_back(proj_id); + + was_inside = true; break; } } + + if (!was_inside) { + // i-j line completely outside of M + // Projection points is the last point + kmax[base] = nk-1; + E_Int proj_id = base + nij*kmax[base]; + proj_points.push_back(proj_id); + } } } - //point_write("proj_points", Xs, Ys, Zs, proj_points); + assert(proj_points.size() == (size_t)nij); + + //point_write("proj_points.im", Xs, Ys, Zs, proj_points); + //printf("points written!\n"); + //fflush(stdout); E_Int np = ni*nj*nk; // Project points onto marray surface std::unordered_map point_hit_table; + //std::vector projections; + for (E_Int i = 0; i < nij; i++) { E_Int p = proj_points[i]; - E_Int q = p + nij; + E_Int q = p - nij; E_Float px = Xs[p]; E_Float py = Ys[p]; E_Float pz = Zs[p]; - E_Float dx = Xs[q] - Xs[p]; - E_Float dy = Ys[q] - Ys[p]; - E_Float dz = Zs[q] - Zs[p]; + E_Float dx = Xs[p] - Xs[q]; + E_Float dy = Ys[p] - Ys[q]; + E_Float dz = Zs[p] - Zs[q]; E_Float NORM = sqrt(dx*dx + dy*dy + dz*dz); dx /= NORM, dy /= NORM, dz /= NORM; - /* - TriangleIntersection TI; - - E_Int hit = M->project_point(px, py, pz, dx, dy, dz, TI, i); - - assert(hit); - - TI.pid = p; - - point_hit_table[p] = TI; - */ - std::vector mlocs; Mf.ray_intersect_BVH(px, py, pz, dx, dy, dz, Mf.root_node_idx, mlocs); + + //if (mlocs.empty()) { + // point_write("lost.im", px, py, pz); + //} + + assert(mlocs.size() > 0); PointLoc ploc; E_Float min_abs_t = EFLOATMAX; for (const auto &mloc : mlocs) { @@ -147,8 +158,12 @@ PyObject *handle_slave(const IMesh *M, const Smesh &Mf, Karray& sarray) TI.pid = p; TI.x = ploc.x, TI.y = ploc.y, TI.z = ploc.z; point_hit_table[p] = TI; + + //projections.push_back({ploc.x, ploc.y, ploc.z}); } + //point_write("projections.im", projections); + // Construct the new faces and cells std::vector> faces; From 790b9785aab337b0614d17dd95f6e5286ee7946f Mon Sep 17 00:00:00 2001 From: imadhammani Date: Thu, 14 Nov 2024 17:22:20 +0100 Subject: [PATCH 80/86] XCore intersectMesh: better ray-aabb intersection in case of dx/dy/dz = 0 --- .../XCore/XCore/intersectMesh/smesh_bvh.cpp | 33 +++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/Cassiopee/XCore/XCore/intersectMesh/smesh_bvh.cpp b/Cassiopee/XCore/XCore/intersectMesh/smesh_bvh.cpp index c9f1c1a11..b70d867e1 100644 --- a/Cassiopee/XCore/XCore/intersectMesh/smesh_bvh.cpp +++ b/Cassiopee/XCore/XCore/intersectMesh/smesh_bvh.cpp @@ -158,6 +158,38 @@ static bool ray_intersect_AABB(E_Float ox, E_Float oy, E_Float oz, E_Float dx, E_Float dy, E_Float dz, const AABB &box) { + E_Float tmin = 0; + E_Float tmax = EFLOATMAX; + + E_Float origin[3] = { ox, oy, oz }; + E_Float direction[3] = { dx, dy, dz }; + E_Float boxMin[3] = { box.xmin, box.ymin, box.zmin }; + E_Float boxMax[3] = { box.xmax, box.ymax, box.zmax }; + + for (int i = 0; i < 3; i++) { + E_Float o = origin[i]; + E_Float d = direction[i]; + E_Float bmin = boxMin[i]; + E_Float bmax = boxMax[i]; + + if (d != 0) { + E_Float t1 = (bmin - o) / d; + E_Float t2 = (bmax - o) / d; + + if (t1 > t2) { E_Float temp = t1; t1 = t2; t2 = temp; } + + tmin = (t1 > tmin) ? t1 : tmin; + tmax = (t2 < tmax) ? t2 : tmax; + + if (tmin > tmax) return false; // No intersection + } else { + if (o < bmin || o > bmax) return false; // Parallel and outside slab + } + } + + return true; + + /* E_Float tx1 = (box.xmin - ox) / dx, tx2 = (box.xmax - ox) / dx; E_Float tmin = std::min(tx1, tx2), tmax = std::max(tx1, tx2); E_Float ty1 = (box.ymin - oy) / dy, ty2 = (box.ymax - oy) / dy; @@ -167,6 +199,7 @@ bool ray_intersect_AABB(E_Float ox, E_Float oy, E_Float oz, tmin = std::max(tmin, std::min(tz1, tz2)); tmax = std::min(tmax, std::max(tz1, tz2)); return tmax >= tmin; + */ } void Smesh::ray_intersect_BVH(E_Float ox, E_Float oy, E_Float oz, From 1b1a1d1b920aeb1e2300cf3c8260b37750a5a6b8 Mon Sep 17 00:00:00 2001 From: imadhammani Date: Thu, 14 Nov 2024 17:43:16 +0100 Subject: [PATCH 81/86] XCore intersectMesh: update --- .../XCore/XCore/intersectMesh/icapsule.cpp | 52 +++++++++++-------- Cassiopee/XCore/XCore/intersectMesh/smesh.cpp | 6 ++- Cassiopee/XCore/XCore/intersectMesh/smesh.h | 4 +- .../XCore/XCore/intersectMesh/smesh_geom.cpp | 6 +-- .../XCore/intersectMesh/smesh_locate.cpp | 30 ++++++----- 5 files changed, 56 insertions(+), 42 deletions(-) diff --git a/Cassiopee/XCore/XCore/intersectMesh/icapsule.cpp b/Cassiopee/XCore/XCore/intersectMesh/icapsule.cpp index 6aa1723ad..5e0638a89 100644 --- a/Cassiopee/XCore/XCore/intersectMesh/icapsule.cpp +++ b/Cassiopee/XCore/XCore/intersectMesh/icapsule.cpp @@ -283,6 +283,7 @@ PyObject *K_XCORE::icapsule_adapt(PyObject *self, PyObject *args) Mf.write_ngon("Mf_before_inter.im"); + //for (E_Int i = 25; i < 26; i++) { for (size_t i = 0; i < Ss.size(); i++) { printf("S%lu\n", i); @@ -303,7 +304,7 @@ PyObject *K_XCORE::icapsule_adapt(PyObject *self, PyObject *args) Sf.make_bbox(); Sf.hash_faces(); Sf.compute_min_distance_between_points(); - //printf("Min dist: %f\n", Sf.min_pdist); + printf("Min dist: %f\n", Sf.min_pdist); //Sf.write_ngon("Sf_before_inter.im"); @@ -378,6 +379,8 @@ PyObject *K_XCORE::icapsule_intersect(PyObject *self, PyObject *args) std::vector Ss; Ss.reserve(slave_count); + assert(PyList_Size(SLAVES) == PyList_Size(STAGS)); + for (int i = 0; i < slave_count; i++) { Karray sarray; ret = Karray_parse_ngon(PyList_GetItem(SLAVES, i), sarray); @@ -391,9 +394,12 @@ PyObject *K_XCORE::icapsule_intersect(PyObject *self, PyObject *args) E_Int tag_size = -1; ret = K_NUMPY::getFromNumpyArray(STAG, tag, tag_size, true); assert(ret == 1); - printf("tag_size = %lu\n", tag_size); S.ftag.reserve(tag_size); - for (int j = 0; j < tag_size; j++) S.ftag.push_back(tag[j]-1); + for (int j = 0; j < tag_size; j++) { + E_Int fid = tag[j]-1; + assert(fid < S.nf); + S.ftag.push_back(fid); + } Ss.push_back(S); } @@ -402,8 +408,7 @@ PyObject *K_XCORE::icapsule_intersect(PyObject *self, PyObject *args) M.orient_skin(OUT); Smesh Mf(M, M.skin, false); - for (E_Int i = Ss.size()-1; i >= 0; i--) { - //for (size_t i = 0; i < Ss.size(); i++) { + for (size_t i = 0; i < Ss.size(); i++) { printf("Intersecting slave %d\n", i); @@ -414,7 +419,7 @@ PyObject *K_XCORE::icapsule_intersect(PyObject *self, PyObject *args) Mf.make_pnormals(); Mf.make_point_faces(); - Mf.write_ngon("Mf_before_intersect.im"); + //Mf.write_ngon("Mf_before_intersect.im"); auto &S = Ss[i]; @@ -423,11 +428,11 @@ PyObject *K_XCORE::icapsule_intersect(PyObject *self, PyObject *args) Sf.make_fnormals(); Sf.make_pnormals(); - { - char fname[32] = {0}; - sprintf(fname, "Sf_before_intersect_%d.im", i); - Sf.write_ngon(fname); - } + //{ + // char fname[32] = {0}; + // sprintf(fname, "Sf_before_intersect_%d.im", i); + // Sf.write_ngon(fname); + //} auto plocs = Mf.locate2(Sf); @@ -436,28 +441,29 @@ PyObject *K_XCORE::icapsule_intersect(PyObject *self, PyObject *args) E_Int nf_before_intersect = Sf.nf; D.reconstruct(Mf, Dcel::RED); - Mf.write_ngon("Mf_after_intersect.im"); + //Mf.write_ngon("Mf_after_intersect.im"); D.reconstruct(Sf, Dcel::BLACK); - { - char fname[32] = {0}; - sprintf(fname, "Sf_after_intersect_%d.im", i); - Sf.write_ngon(fname); - } + //{ + // char fname[32] = {0}; + // sprintf(fname, "Sf_after_intersect_%d.im", i); + // Sf.write_ngon(fname); + //} - { - char fname[32] = {0}; - sprintf(fname, "intersected_enoval_%d.im", i); - D.write_inner_cycles(fname); - } + //{ + // char fname[32] = {0}; + // sprintf(fname, "intersected_%d.im", i); + // D.write_inner_cycles(fname); + //} Sf.reconstruct(S); // Tag Sf faces Sf.tag_faces(S); - puts(""); + puts("Intersection OK\n"); + fflush(stdout); } Mf.reconstruct(M); diff --git a/Cassiopee/XCore/XCore/intersectMesh/smesh.cpp b/Cassiopee/XCore/XCore/intersectMesh/smesh.cpp index 1b11de699..287d5e8cb 100644 --- a/Cassiopee/XCore/XCore/intersectMesh/smesh.cpp +++ b/Cassiopee/XCore/XCore/intersectMesh/smesh.cpp @@ -491,6 +491,8 @@ void Smesh::tag_faces(IMesh &M) const M.ftag.reserve(nf); for (E_Int fid = 0; fid < nf; fid++) { - M.ftag.push_back(l2gf.at(fid)); + E_Int gfid = l2gf.at(fid); + assert(gfid < M.nf); + M.ftag.push_back(gfid); } -} \ No newline at end of file +} diff --git a/Cassiopee/XCore/XCore/intersectMesh/smesh.h b/Cassiopee/XCore/XCore/intersectMesh/smesh.h index a8ad66739..55c2832e3 100644 --- a/Cassiopee/XCore/XCore/intersectMesh/smesh.h +++ b/Cassiopee/XCore/XCore/intersectMesh/smesh.h @@ -108,9 +108,9 @@ struct Smesh { bool is_point_in_3D_polygon(E_Float x, E_Float y, E_Float z, E_Int fid) const; bool is_point_on_a_polygon_edge(E_Float x, E_Float y, E_Float z, E_Int fid, - PointLoc &ploc) const; + PointLoc &ploc, E_Float min_pdist) const; bool is_point_a_polygon_vertex(E_Float x, E_Float y, E_Float z, E_Int fid, - PointLoc &ploc) const; + PointLoc &ploc, E_Float min_pdist) const; void make_fcenters(); void make_fnormals(); diff --git a/Cassiopee/XCore/XCore/intersectMesh/smesh_geom.cpp b/Cassiopee/XCore/XCore/intersectMesh/smesh_geom.cpp index f6ab0ab02..da684c9df 100644 --- a/Cassiopee/XCore/XCore/intersectMesh/smesh_geom.cpp +++ b/Cassiopee/XCore/XCore/intersectMesh/smesh_geom.cpp @@ -13,10 +13,10 @@ void Smesh::replace_by_projections(const std::vector &pids, E_Float dy = Y[pid]-ploc.y; E_Float dz = Z[pid]-ploc.z; E_Float d = sqrt(dx*dx + dy*dy + dz*dz); - if (d >= min_pdist) { + if (d >= min_pdist/10) { fprintf(stderr, "Tight near vertex/edge situation!\n"); - point_write("orig", X[pid], Y[pid], Z[pid]); - point_write("dest", ploc.x, ploc.y, ploc.z); + point_write("orig.im", X[pid], Y[pid], Z[pid]); + point_write("dest.im", ploc.x, ploc.y, ploc.z); assert(0); } X[pid] = ploc.x; diff --git a/Cassiopee/XCore/XCore/intersectMesh/smesh_locate.cpp b/Cassiopee/XCore/XCore/intersectMesh/smesh_locate.cpp index 97dcaa948..e89d2ac0d 100644 --- a/Cassiopee/XCore/XCore/intersectMesh/smesh_locate.cpp +++ b/Cassiopee/XCore/XCore/intersectMesh/smesh_locate.cpp @@ -56,7 +56,7 @@ bool Smesh::is_point_in_3D_polygon(E_Float x, E_Float y, E_Float z, E_Int fid) c } bool Smesh::is_point_a_polygon_vertex(E_Float x, E_Float y, E_Float z, - E_Int fid, PointLoc &ploc) const + E_Int fid, PointLoc &ploc, E_Float min_pdist) const { const auto &pn = Fc[fid]; @@ -64,7 +64,7 @@ bool Smesh::is_point_a_polygon_vertex(E_Float x, E_Float y, E_Float z, E_Int p = pn[i]; E_Float dist = (x-X[p])*(x-X[p]) + (y-Y[p])*(y-Y[p]) + (z-Z[p])*(z-Z[p]); dist = sqrt(dist); - if (dist < 1e-6) { + if (dist < min_pdist/10) { ploc.v_idx = i; ploc.x = X[p]; ploc.y = Y[p]; @@ -77,7 +77,7 @@ bool Smesh::is_point_a_polygon_vertex(E_Float x, E_Float y, E_Float z, } bool Smesh::is_point_on_a_polygon_edge(E_Float x, E_Float y, E_Float z, - E_Int fid, PointLoc &ploc) const + E_Int fid, PointLoc &ploc, E_Float min_pdist) const { const auto &pn = Fc[fid]; @@ -96,8 +96,8 @@ bool Smesh::is_point_on_a_polygon_edge(E_Float x, E_Float y, E_Float z, if (dp1 >= 0 && dp1 <= dp2) { ploc.e_idx = i; E_Float t; - if (fabs(X[a]-X[b]) > TOL) t = (x-X[a])/(X[b]-X[a]); - else if (fabs(Y[a]-Y[b]) > TOL) t = (y-Y[a])/(Y[b]-Y[a]); + if (fabs(X[a]-X[b]) > 1e-3) t = (x-X[a])/(X[b]-X[a]); + else if (fabs(Y[a]-Y[b]) > 1e-3) t = (y-Y[a])/(Y[b]-Y[a]); else t = (z-Z[a])/(Z[b]-Z[a]); ploc.x = X[a] + t * (X[b]-X[a]); ploc.y = Y[a] + t * (Y[b]-Y[a]); @@ -115,7 +115,7 @@ std::vector Smesh::locate2(const Smesh &Sf) const size_t on_vertex = 0, on_edge = 0; - std::vector oedge, dedge; + //std::vector oedge, dedge, vpoints; for (E_Int pid = 0; pid < Sf.np; pid++) { E_Float x = Sf.X[pid]; @@ -129,6 +129,8 @@ std::vector Smesh::locate2(const Smesh &Sf) const const auto &pf = bin_faces.at(voxel); + //if (pid == 332) write_ngon("pf.im", pf); + bool found = false; auto &ploc = plocs[pid]; @@ -138,13 +140,16 @@ std::vector Smesh::locate2(const Smesh &Sf) const if (found) { + //if (pid == 332) write_face("fid.im", fid); + ploc.fid = fid; - if (is_point_a_polygon_vertex(x, y, z, fid, ploc)) { + if (is_point_a_polygon_vertex(x, y, z, fid, ploc, Sf.min_pdist)) { on_vertex++; - } else if (is_point_on_a_polygon_edge(x, y, z, fid, ploc)) { - oedge.push_back({x, y, z}); - dedge.push_back({ploc.x, ploc.y, ploc.z}); + //vpoints.push_back({x, y, z}); + } else if (is_point_on_a_polygon_edge(x, y, z, fid, ploc, Sf.min_pdist)) { + //oedge.push_back({x, y, z}); + //dedge.push_back({ploc.x, ploc.y, ploc.z}); on_edge++; } @@ -164,8 +169,9 @@ std::vector Smesh::locate2(const Smesh &Sf) const printf("on vertex: %lu\n", on_vertex); printf("on edge: %lu\n", on_edge); - point_write("oedge.im", oedge); - point_write("dedge.im", dedge); + //point_write("oedge.im", oedge); + //point_write("dedge.im", dedge); + //point_write("vpoints.im", vpoints); return plocs; } From 11ef26aedd0c97ea4ccf94322af0fe3c258e2e21 Mon Sep 17 00:00:00 2001 From: imadhammani Date: Mon, 18 Nov 2024 18:09:18 +0100 Subject: [PATCH 82/86] XCore intersectMesh: in-plane triangulateSkin Signed-off-by: imadhammani --- Cassiopee/XCore/XCore/PyTree.py | 31 +++-- Cassiopee/XCore/XCore/intersectMesh/mesh.h | 11 +- .../XCore/XCore/intersectMesh/triangulate.cpp | 113 +++++++++++++++++- 3 files changed, 141 insertions(+), 14 deletions(-) diff --git a/Cassiopee/XCore/XCore/PyTree.py b/Cassiopee/XCore/XCore/PyTree.py index 51289998e..3ac2ee7f1 100644 --- a/Cassiopee/XCore/XCore/PyTree.py +++ b/Cassiopee/XCore/XCore/PyTree.py @@ -564,10 +564,27 @@ def icapsule_extract_slaves(IC): zs.append(z) return zs -def triangulate_skin(m): - zm = I.getZones(m)[0] - marr = C.getFields(I.__GridCoordinates__, zm, api=3)[0] - mo = xcore.triangulate_skin(marr) - zo = I.createZoneNode("triangulated", mo) - return zo - +def triangulateSkin(m): + m_copy = I.copyRef(m) + _triangulateSkin(m_copy) + return m_copy + +def _triangulateSkin(m): + zones = I.getNodesFromType(m, 'Zone_t') + for i, zone in enumerate(zones): + marr = C.getFields(I.__GridCoordinates__, zone, api=3)[0] + zbc = I.getNodeFromType(zone, 'ZoneBC_t') + ptlists = [] + if zbc is not None: + bcs = I.getNodesFromType(zbc, 'BC_t') + for bc in bcs: + ptlists.append(I.getNodeFromName(bc, 'PointList')[1][0]) + m_out, ptlists_out = xcore.triangulate_skin(marr, ptlists) + C.setFields([m_out], zone, 'nodes') + if zbc is not None: + bcs = I.getNodesFromType(zbc, 'BC_t') + for j, bc in enumerate(bcs): + ptlist = I.getNodeFromName(bc, 'PointList') + ptlist[1] = ptlists_out[j] + + return None \ No newline at end of file diff --git a/Cassiopee/XCore/XCore/intersectMesh/mesh.h b/Cassiopee/XCore/XCore/intersectMesh/mesh.h index 390f840d8..55d172610 100644 --- a/Cassiopee/XCore/XCore/intersectMesh/mesh.h +++ b/Cassiopee/XCore/XCore/intersectMesh/mesh.h @@ -23,6 +23,7 @@ #include #include #include +#include #include "point.h" #include "xcore.h" @@ -58,6 +59,11 @@ struct Sgraph { std::vector fadj; }; +struct Py_BC { + E_Int size; + E_Int *ptr; +}; + struct IMesh { E_Int np, ne, nf, nc; @@ -91,7 +97,7 @@ struct IMesh { std::set patch; std::vector ftag; std::vector ptag; - std::vector ctag; + std::vector ctag; void set_tolerances(E_Float near_vertex_tol, E_Float near_edge_tol) { @@ -114,6 +120,9 @@ struct IMesh { void triangulate_face_set(bool propagate = true); + std::vector triangulate_skin(const std::vector &bcs_in, + const std::unordered_map &fid_to_bc); + void triangulate_skin(); size_t refine_slave(const IMesh &master); diff --git a/Cassiopee/XCore/XCore/intersectMesh/triangulate.cpp b/Cassiopee/XCore/XCore/intersectMesh/triangulate.cpp index 55c65e314..d09ace588 100644 --- a/Cassiopee/XCore/XCore/intersectMesh/triangulate.cpp +++ b/Cassiopee/XCore/XCore/intersectMesh/triangulate.cpp @@ -3,8 +3,8 @@ PyObject *K_XCORE::triangulate_skin(PyObject *self, PyObject *args) { - PyObject *MESH; - if (!PYPARSETUPLE_(args, O_, &MESH)) { + PyObject *MESH, *PTLISTS; + if (!PYPARSETUPLE_(args, OO_, &MESH, &PTLISTS)) { RAISE("Bad input."); return NULL; } @@ -16,12 +16,113 @@ PyObject *K_XCORE::triangulate_skin(PyObject *self, PyObject *args) } IMesh M(array); - M.make_skin(); - M.triangulate_skin(); + std::vector bcs_in; + + if (PTLISTS != Py_None) { + E_Int nbcs = PyList_Size(PTLISTS); + for (E_Int i = 0; i < nbcs; i++) { + PyObject *PTLIST = PyList_GetItem(PTLISTS, i); + Py_BC bc; + E_Int ret = K_NUMPY::getFromNumpyArray(PTLIST, bc.ptr, bc.size, true); + Py_DECREF(PTLIST); + if (ret != 1) { + RAISE("Couldn't extract pointlists."); + Karray_free_ngon(array); + return NULL; + } + bcs_in.push_back(bc); + } + + std::unordered_map fid_to_bc; + + for (size_t i = 0; i < bcs_in.size(); i++) { + const auto &bc = bcs_in[i]; + for (E_Int j = 0; j < bc.size; j++) { + E_Int fid = bc.ptr[j]; + fid_to_bc[fid] = i; + } + } + + std::vector new_bcs = M.triangulate_skin(bcs_in, fid_to_bc); + + PyObject *out = PyList_New(0); + PyList_Append(out, M.export_karray()); + PyObject *bcs_out = PyList_New(0); + for (const auto &new_bc : new_bcs) { + PyList_Append(bcs_out, (PyObject *)new_bc); + Py_DECREF(new_bc); + } + PyList_Append(out, bcs_out); + Py_DECREF(bcs_out); + return out; + } else { + M.triangulate_skin(); + return M.export_karray(); + } +} + +std::vector IMesh::triangulate_skin(const std::vector &bcs_in, + const std::unordered_map &fid_to_bc) +{ + E_Int NF = nf; + + owner.resize(nf + skin.size(), -1); + neigh.resize(nf + skin.size(), -1); + + std::vector new_bcs(bcs_in.size()); + std::vector ptrs(bcs_in.size()); + std::vector counts(bcs_in.size(), 0); + + for (size_t i = 0; i < bcs_in.size(); i++) { + E_Int new_size = bcs_in[i].size * 2; + npy_intp dims[2]; + dims[0] = (npy_intp)new_size; + dims[1] = 1; + new_bcs[i] = (PyArrayObject *)PyArray_SimpleNew(1, dims, E_NPY_INT); + ptrs[i] = (E_Int *)PyArray_DATA(new_bcs[i]); + } + + for (auto fid : skin) { + assert(neigh[fid] == -1); + + const auto &pn = F[fid]; + if (pn.size() == 3) continue; + + assert(pn.size() == 4); + + E_Int nodes[4] = {pn[0], pn[1], pn[2], pn[3]}; - return M.export_karray(); + F.push_back({nodes[2], nodes[3], nodes[0]}); + F[fid] = {nodes[0], nodes[1], nodes[2]}; + assert(F[fid].size() == 3); + + E_Int own = owner[fid]; + auto &pf = C[own]; + pf.push_back(nf); + + owner[nf] = own; + + // Which bc (if any) does fid belong to? + auto it = fid_to_bc.find(fid+1); + if (it != fid_to_bc.end()) { + E_Int bc_id = it->second; + ptrs[bc_id][counts[bc_id]++] = fid+1; + ptrs[bc_id][counts[bc_id]++] = nf+1; + } + + nf++; + } + + for (E_Int i = NF; i < nf; i++) + skin.push_back(i); + + for (size_t i = 0; i < counts.size(); i++) { + assert(counts[i] == 2*bcs_in[i].size); + } + + return new_bcs; } void IMesh::triangulate_skin() @@ -56,4 +157,4 @@ void IMesh::triangulate_skin() for (E_Int i = NF; i < nf; i++) skin.push_back(i); -} +} \ No newline at end of file From 26d7f67b1d2047306ce4c294aa7c7bdd45683d1a Mon Sep 17 00:00:00 2001 From: imadhammani Date: Mon, 18 Nov 2024 18:12:45 +0100 Subject: [PATCH 83/86] Modif. checkAssemblyForlSolver Signed-off-by: imadhammani --- Cassiopee/Intersector/Intersector/PyTree.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/Cassiopee/Intersector/Intersector/PyTree.py b/Cassiopee/Intersector/Intersector/PyTree.py index 3b52a0663..e07e0c9a7 100644 --- a/Cassiopee/Intersector/Intersector/PyTree.py +++ b/Cassiopee/Intersector/Intersector/PyTree.py @@ -314,6 +314,8 @@ def checkAssemblyForlSolver(t, fullcheck=False, nb_comps=1): print('Boolean WARNING : quality might be not good enough for solver') #import sys; sys.exit() + if fullcheck == False: return + # VERIFICATION 4 : VOL MIN print("Check min cell volume ...") (vmin, cellid, zoneid) = checkCellsVolume(t) @@ -321,9 +323,6 @@ def checkAssemblyForlSolver(t, fullcheck=False, nb_comps=1): if vmin < VOLMIN_SOLVER: print('Boolean ERROR : too small cells detected : under solver threshold') - if fullcheck == False: - return - # print("Check cell volume extrema...") # res = statsSize(t, 1) # dMax = res[0] From 661b6ee08d41abbb8d7c2fbacfccd307c40514b3 Mon Sep 17 00:00:00 2001 From: imadhammani Date: Mon, 18 Nov 2024 18:13:34 +0100 Subject: [PATCH 84/86] XCore intersectMesh: better point-edge nudge Signed-off-by: imadhammani --- Cassiopee/XCore/XCore/intersectMesh/smesh_locate.cpp | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/Cassiopee/XCore/XCore/intersectMesh/smesh_locate.cpp b/Cassiopee/XCore/XCore/intersectMesh/smesh_locate.cpp index e89d2ac0d..5039f294c 100644 --- a/Cassiopee/XCore/XCore/intersectMesh/smesh_locate.cpp +++ b/Cassiopee/XCore/XCore/intersectMesh/smesh_locate.cpp @@ -96,8 +96,11 @@ bool Smesh::is_point_on_a_polygon_edge(E_Float x, E_Float y, E_Float z, if (dp1 >= 0 && dp1 <= dp2) { ploc.e_idx = i; E_Float t; - if (fabs(X[a]-X[b]) > 1e-3) t = (x-X[a])/(X[b]-X[a]); - else if (fabs(Y[a]-Y[b]) > 1e-3) t = (y-Y[a])/(Y[b]-Y[a]); + E_Float dx = fabs(X[a]-X[b]); + E_Float dy = fabs(Y[a]-Y[b]); + E_Float dz = fabs(Z[a]-Z[b]); + if (dx > dy && dx > dz) t = (x-X[a])/(X[b]-X[a]); + else if (dy > dz) t = (y-Y[a])/(Y[b]-Y[a]); else t = (z-Z[a])/(Z[b]-Z[a]); ploc.x = X[a] + t * (X[b]-X[a]); ploc.y = Y[a] + t * (Y[b]-Y[a]); From 8ec3bfa53ce532ccabcb7d6f0e36c7f16b2f80d8 Mon Sep 17 00:00:00 2001 From: imadhammani Date: Thu, 21 Nov 2024 11:23:58 +0100 Subject: [PATCH 85/86] XCore: update --- Cassiopee/XCore/XCore/AdaptMesh/DynMesh.cpp | 6 ++--- .../intersectMesh/IntersectMesh_Merge.cpp | 24 +++++++++---------- .../removeIntersectingKPlanes.cpp | 18 +++++++------- 3 files changed, 24 insertions(+), 24 deletions(-) diff --git a/Cassiopee/XCore/XCore/AdaptMesh/DynMesh.cpp b/Cassiopee/XCore/XCore/AdaptMesh/DynMesh.cpp index 7c1a5dc44..ef9e9b910 100644 --- a/Cassiopee/XCore/XCore/AdaptMesh/DynMesh.cpp +++ b/Cassiopee/XCore/XCore/AdaptMesh/DynMesh.cpp @@ -19,9 +19,9 @@ DynMesh::DynMesh(Karray *karray) X.resize(np); Y.resize(np); Z.resize(np); - memcpy(X.data(), karray->X(), np * sizeof(E_Float)); - memcpy(Y.data(), karray->Y(), np * sizeof(E_Float)); - memcpy(Z.data(), karray->Z(), np * sizeof(E_Float)); + memcpy(X.data(), karray->x, np * sizeof(E_Float)); + memcpy(Y.data(), karray->y, np * sizeof(E_Float)); + memcpy(Z.data(), karray->z, np * sizeof(E_Float)); F.reserve(nf); diff --git a/Cassiopee/XCore/XCore/intersectMesh/IntersectMesh_Merge.cpp b/Cassiopee/XCore/XCore/intersectMesh/IntersectMesh_Merge.cpp index a8915a801..49d2d0b1a 100644 --- a/Cassiopee/XCore/XCore/intersectMesh/IntersectMesh_Merge.cpp +++ b/Cassiopee/XCore/XCore/intersectMesh/IntersectMesh_Merge.cpp @@ -106,9 +106,9 @@ PyObject *K_XCORE::IntersectMesh_Merge(PyObject *self, PyObject *args) std::set points; // Master points - E_Float *X = marray.X(); - E_Float *Y = marray.Y(); - E_Float *Z = marray.Z(); + E_Float *X = marray.x; + E_Float *Y = marray.y; + E_Float *Z = marray.z; printf("M points: %d\n", marray.npts); printf("S points: %d\n", sarray.npts); @@ -128,9 +128,9 @@ PyObject *K_XCORE::IntersectMesh_Merge(PyObject *self, PyObject *args) assert((size_t)NP == points.size()); // Slave points - X = sarray.X(); - Y = sarray.Y(); - Z = sarray.Z(); + X = sarray.x; + Y = sarray.y; + Z = sarray.z; for (E_Int i = 0; i < sarray.npts; i++) { Vtx xyz(X[i], Y[i], Z[i]); @@ -151,9 +151,9 @@ PyObject *K_XCORE::IntersectMesh_Merge(PyObject *self, PyObject *args) // Change the points ids within marray - X = marray.X(); - Y = marray.Y(); - Z = marray.Z(); + X = marray.x; + Y = marray.y; + Z = marray.z; for (E_Int fid = 0; fid < marray.nfaces(); fid++) { E_Int np = -1; @@ -169,9 +169,9 @@ PyObject *K_XCORE::IntersectMesh_Merge(PyObject *self, PyObject *args) // Change the points within sarray - X = sarray.X(); - Y = sarray.Y(); - Z = sarray.Z(); + X = sarray.x; + Y = sarray.y; + Z = sarray.z; for (E_Int fid = 0; fid < sarray.nfaces(); fid++) { E_Int np = -1; diff --git a/Cassiopee/XCore/XCore/intersectMesh/removeIntersectingKPlanes.cpp b/Cassiopee/XCore/XCore/intersectMesh/removeIntersectingKPlanes.cpp index 1bb39b4e7..5e8c66231 100644 --- a/Cassiopee/XCore/XCore/intersectMesh/removeIntersectingKPlanes.cpp +++ b/Cassiopee/XCore/XCore/intersectMesh/removeIntersectingKPlanes.cpp @@ -62,9 +62,9 @@ PyObject *handle_slave(const IMesh *M, const Smesh &Mf, Karray& sarray) E_Int nk = sarray.nk; E_Int nij = ni * nj; - E_Float *Xs = sarray.X(); - E_Float *Ys = sarray.Y(); - E_Float *Zs = sarray.Z(); + E_Float *Xs = sarray.x; + E_Float *Ys = sarray.y; + E_Float *Zs = sarray.z; // Last k-plane outside of M std::vector kmax(nij, -1); @@ -400,9 +400,9 @@ E_Int get_kmax(IMesh *M, Karray& sarray) E_Int nk = sarray.nk; E_Int nij = ni * nj; - E_Float *Xs = sarray.X(); - E_Float *Ys = sarray.Y(); - E_Float *Zs = sarray.Z(); + E_Float *Xs = sarray.x; + E_Float *Ys = sarray.y; + E_Float *Zs = sarray.z; E_Int kmax = -1; @@ -434,9 +434,9 @@ PyObject *handle_slave2(IMesh *M, Karray& sarray, E_Int kmax) E_Int nk = sarray.nk; E_Int nij = ni * nj; - E_Float *Xs = sarray.X(); - E_Float *Ys = sarray.Y(); - E_Float *Zs = sarray.Z(); + E_Float *Xs = sarray.x; + E_Float *Ys = sarray.y; + E_Float *Zs = sarray.z; // Indices of points to be projected std::vector proj_points; From 5fb17a52a8369ce7dd397daaf184f3c3f6934585 Mon Sep 17 00:00:00 2001 From: imadhammani Date: Thu, 21 Nov 2024 11:48:06 +0100 Subject: [PATCH 86/86] XCore: remove warnings --- Cassiopee/XCore/XCore/intersectMesh/dcel.cpp | 3 +-- Cassiopee/XCore/XCore/intersectMesh/dcel_reconstruct.cpp | 4 ++-- Cassiopee/XCore/XCore/intersectMesh/icapsule.cpp | 4 ++-- Cassiopee/XCore/XCore/intersectMesh/smesh_locate.cpp | 7 +++++-- 4 files changed, 10 insertions(+), 8 deletions(-) diff --git a/Cassiopee/XCore/XCore/intersectMesh/dcel.cpp b/Cassiopee/XCore/XCore/intersectMesh/dcel.cpp index e3d175d0b..f3388a360 100644 --- a/Cassiopee/XCore/XCore/intersectMesh/dcel.cpp +++ b/Cassiopee/XCore/XCore/intersectMesh/dcel.cpp @@ -705,7 +705,6 @@ void Dcel::triangulate(const Smesh &Mf, const Smesh &Sf) std::vector non_convex_faces; for (size_t fid = 0; fid < F.size(); fid++) { - Face *f = F[fid]; // TODO(Imad): skip single color faces const auto &vertices = Fv[fid]; @@ -767,7 +766,7 @@ void Dcel::triangulate(const Smesh &Mf, const Smesh &Sf) E_Int vid = 0; do { Vertex *v = current->v; - char fname[16] = {0}; + char fname[128] = {0}; sprintf(fname, "vertex%d.im", vid); point_write(fname, v->x, v->y, v->z); current = current->next; diff --git a/Cassiopee/XCore/XCore/intersectMesh/dcel_reconstruct.cpp b/Cassiopee/XCore/XCore/intersectMesh/dcel_reconstruct.cpp index f717887d4..129f73b3f 100644 --- a/Cassiopee/XCore/XCore/intersectMesh/dcel_reconstruct.cpp +++ b/Cassiopee/XCore/XCore/intersectMesh/dcel_reconstruct.cpp @@ -32,7 +32,7 @@ void Dcel::reconstruct(Smesh &Mf, int color) const for (size_t i = 0; i < faces_to_keep.size(); i++) { E_Int fid = faces_to_keep[i]; - Face *f = F[fid]; + //Face *f = F[fid]; const auto &vertices = Fv[fid]; for (size_t j = 0; j < vertices.size(); j++) { Vertex *v = vertices[j]; @@ -71,7 +71,7 @@ void Dcel::reconstruct(Smesh &Mf, int color) const // Add the rest of the children for (size_t i = 1; i < children.size(); i++) { - Face *f = F[children[i]]; + //Face *f = F[children[i]]; const auto &vertices = Fv[children[i]]; std::vector PN(vertices.size()); for (size_t j = 0; j < vertices.size(); j++) { diff --git a/Cassiopee/XCore/XCore/intersectMesh/icapsule.cpp b/Cassiopee/XCore/XCore/intersectMesh/icapsule.cpp index 5e0638a89..54bed37e4 100644 --- a/Cassiopee/XCore/XCore/intersectMesh/icapsule.cpp +++ b/Cassiopee/XCore/XCore/intersectMesh/icapsule.cpp @@ -410,7 +410,7 @@ PyObject *K_XCORE::icapsule_intersect(PyObject *self, PyObject *args) for (size_t i = 0; i < Ss.size(); i++) { - printf("Intersecting slave %d\n", i); + printf("Intersecting slave %lu\n", i); Mf.make_bbox(); Mf.hash_faces(); @@ -438,7 +438,7 @@ PyObject *K_XCORE::icapsule_intersect(PyObject *self, PyObject *args) Dcel D = Dcel::intersect(Mf, Sf, plocs); - E_Int nf_before_intersect = Sf.nf; + //E_Int nf_before_intersect = Sf.nf; D.reconstruct(Mf, Dcel::RED); //Mf.write_ngon("Mf_after_intersect.im"); diff --git a/Cassiopee/XCore/XCore/intersectMesh/smesh_locate.cpp b/Cassiopee/XCore/XCore/intersectMesh/smesh_locate.cpp index 5039f294c..d673bbe68 100644 --- a/Cassiopee/XCore/XCore/intersectMesh/smesh_locate.cpp +++ b/Cassiopee/XCore/XCore/intersectMesh/smesh_locate.cpp @@ -35,6 +35,8 @@ Point2D project_to_2D(Point3D point, const E_Float *N) return projected; } +#define MAX_PTS 100 + bool Smesh::is_point_in_3D_polygon(E_Float x, E_Float y, E_Float z, E_Int fid) const { const auto &pn = Fc[fid]; @@ -44,8 +46,9 @@ bool Smesh::is_point_in_3D_polygon(E_Float x, E_Float y, E_Float z, E_Int fid) c E_Float dp = fabs(K_MATH::dot(ap, fN, 3)); if (dp > TOL) return false; - Point2D projected_polygon[pn.size()]; - for (int i = 0; i < pn.size(); i++) { + assert(pn.size() <= MAX_PTS); + Point2D projected_polygon[MAX_PTS]; + for (size_t i = 0; i < pn.size(); i++) { Point3D p = {X[pn[i]], Y[pn[i]], Z[pn[i]]}; projected_polygon[i] = project_to_2D(p, fN); }