/* * ***** BEGIN GPL LICENSE BLOCK ***** * * This program 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 2 * of the License, or (at your option) any later version. * * This program 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 this program; if not, write to the Free Software Foundation, * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * * The Original Code is Copyright (C) 2014 Blender Foundation. * All rights reserved. * * Contributor(s): Blender Foundation, * Sergey Sharybin * * ***** END GPL LICENSE BLOCK ***** */ #include "carve-capi.h" #include "carve-util.h" #include #include #include #include using carve::mesh::MeshSet; typedef std::pair OrigIndex; typedef std::pair::vertex_t *, MeshSet<3>::vertex_t *> VertexPair; typedef carve::interpolate::VertexAttr OrigVertMapping; typedef carve::interpolate::FaceAttr OrigFaceMapping; typedef carve::interpolate::SwapableFaceEdgeAttr OrigFaceEdgeMapping; typedef carve::interpolate::SimpleFaceEdgeAttr FaceEdgeTriangulatedFlag; typedef struct CarveMeshDescr { // Stores mesh data itself. MeshSet<3> *poly; // N-th element of the vector indicates index of an original mesh loop. std::unordered_map, int> orig_loop_index_map; // Mapping from carve face to an original face index in DM. std::unordered_map::face_t *, int> orig_poly_index_map; // The folloving mapping is only filled in for output mesh. // Mapping from the face verts back to original vert index. OrigVertMapping orig_vert_mapping; // Mapping from the face edges back to (original edge index, original loop index). OrigFaceEdgeMapping orig_face_edge_mapping; FaceEdgeTriangulatedFlag face_edge_triangulated_flag; // Mapping from the faces back to original poly index. OrigFaceMapping orig_face_mapping; } CarveMeshDescr; namespace { template void edgeIndexMap_put(std::unordered_map, T2> *edge_map, const T1 &v1, const T1 &v2, const T2 &index) { if (v1 < v2) { (*edge_map)[std::make_pair(v1, v2)] = index; } else { (*edge_map)[std::make_pair(v2, v1)] = index; } } template const T2 &edgeIndexMap_get(const std::unordered_map, T2> &edge_map, const T1 &v1, const T1 &v2) { typedef std::unordered_map, T2> Map; typename Map::const_iterator found; if (v1 < v2) { found = edge_map.find(std::make_pair(v1, v2)); } else { found = edge_map.find(std::make_pair(v2, v1)); } assert(found != edge_map.end()); return found->second; } template bool edgeIndexMap_get_if_exists(const std::unordered_map, T2> &edge_map, const T1 &v1, const T1 &v2, T2 *out) { typedef std::unordered_map, T2> Map; typename Map::const_iterator found; if (v1 < v2) { found = edge_map.find(std::make_pair(v1, v2)); } else { found = edge_map.find(std::make_pair(v2, v1)); } if (found == edge_map.end()) { return false; } *out = found->second; return true; } template bool edgeIndexMap_exists(const std::unordered_map, T2> &edge_map, const T1 &v1, const T1 &v2) { typedef std::unordered_map, T2> Map; typename Map::const_iterator found; if (v1 < v2) { found = edge_map.find(std::make_pair(v1, v2)); } else { found = edge_map.find(std::make_pair(v2, v1)); } return found != edge_map.end(); } template inline int indexOf(const T *element, const std::vector &vector_from) { return element - &vector_from.at(0); } void initOrigIndexMeshFaceMapping(CarveMeshDescr *mesh, int which_mesh, std::unordered_map, int> &orig_loop_index_map, std::unordered_map::face_t*, int> &orig_poly_index_map, OrigVertMapping *orig_vert_mapping, OrigFaceEdgeMapping *orig_face_edge_mapping, FaceEdgeTriangulatedFlag *face_edge_triangulated_flag, OrigFaceMapping *orig_face_attr) { MeshSet<3> *poly = mesh->poly; std::vector::vertex_t>::iterator vertex_iter = poly->vertex_storage.begin(); for (int i = 0; vertex_iter != poly->vertex_storage.end(); ++i, ++vertex_iter) { MeshSet<3>::vertex_t *vertex = &(*vertex_iter); orig_vert_mapping->setAttribute(vertex, std::make_pair(which_mesh, i)); } MeshSet<3>::face_iter face_iter = poly->faceBegin(); for (int i = 0, loop_map_index = 0; face_iter != poly->faceEnd(); ++face_iter, ++i) { const MeshSet<3>::face_t *face = *face_iter; // Mapping from carve face back to original poly index. int orig_poly_index = orig_poly_index_map[face]; orig_face_attr->setAttribute(face, std::make_pair(which_mesh, orig_poly_index)); for (MeshSet<3>::face_t::const_edge_iter_t edge_iter = face->begin(); edge_iter != face->end(); ++edge_iter, ++loop_map_index) { int v1 = indexOf(edge_iter->v1(), poly->vertex_storage); int v2 = indexOf(edge_iter->v2(), poly->vertex_storage); int orig_loop_index; if (!edgeIndexMap_get_if_exists(orig_loop_index_map, v1, v2, &orig_loop_index)) { orig_loop_index = -1; } if (orig_loop_index != -1) { // Mapping from carve face edge back to original loop index. orig_face_edge_mapping->setAttribute(face, edge_iter.idx(), std::make_pair(which_mesh, orig_loop_index)); } else { face_edge_triangulated_flag->setAttribute(face, edge_iter.idx(), true); } } } } void initOrigIndexMapping(CarveMeshDescr *left_mesh, CarveMeshDescr *right_mesh, OrigVertMapping *orig_vert_mapping, OrigFaceEdgeMapping *orig_face_edge_mapping, FaceEdgeTriangulatedFlag *face_edge_triangulated_flag, OrigFaceMapping *orig_face_mapping) { initOrigIndexMeshFaceMapping(left_mesh, CARVE_MESH_LEFT, left_mesh->orig_loop_index_map, left_mesh->orig_poly_index_map, orig_vert_mapping, orig_face_edge_mapping, face_edge_triangulated_flag, orig_face_mapping); initOrigIndexMeshFaceMapping(right_mesh, CARVE_MESH_RIGHT, right_mesh->orig_loop_index_map, right_mesh->orig_poly_index_map, orig_vert_mapping, orig_face_edge_mapping, face_edge_triangulated_flag, orig_face_mapping); } void origEdgeMappingForFace(MeshSet<3>::face_t *face, OrigFaceEdgeMapping *orig_face_edge_mapping, std::unordered_map *edge_origindex_map) { OrigIndex origindex_none = std::make_pair((int)CARVE_MESH_NONE, -1); MeshSet<3>::edge_t *edge = face->edge; for (int i = 0; i < face->nEdges(); ++i, edge = edge->next) { MeshSet<3>::vertex_t *v1 = edge->v1(); MeshSet<3>::vertex_t *v2 = edge->v2(); OrigIndex orig_edge_index = orig_face_edge_mapping->getAttribute(edge->face, i, origindex_none); edgeIndexMap_put(edge_origindex_map, v1, v2, orig_edge_index); } } void dissolveTriangulatedEdges(MeshSet<3>::mesh_t *mesh, const std::set< std::pair > &open_edges, FaceEdgeTriangulatedFlag *face_edge_triangulated_flag, OrigFaceEdgeMapping *orig_face_edge_mapping) { typedef std::unordered_set::edge_t *> edge_set_t; typedef std::unordered_set::face_t *> face_set_t; edge_set_t triangulated_face_edges; for (int face_index = 0; face_index < mesh->faces.size(); ++face_index) { MeshSet<3>::face_t *face = mesh->faces[face_index]; MeshSet<3>::edge_t *edge = face->edge; for (int edge_index = 0; edge_index < face->nEdges(); ++edge_index, edge = edge->next) { if (edge->rev) { const bool is_triangulated_edge = face_edge_triangulated_flag->getAttribute(face, edge_index, false); if (is_triangulated_edge) { MeshSet<3>::edge_t *e1 = std::min(edge, edge->rev); int v1 = indexOf(e1->v1(), mesh->meshset->vertex_storage), v2 = indexOf(e1->v2(), mesh->meshset->vertex_storage); bool is_open = false; if (v1 < v2) { is_open = open_edges.find(std::make_pair(v1, v2)) != open_edges.end(); } else { is_open = open_edges.find(std::make_pair(v2, v1)) != open_edges.end(); } if (is_open == false) { triangulated_face_edges.insert(e1); } } } } } if (triangulated_face_edges.size()) { face_set_t triangulated_faces; std::unordered_map edge_origindex_map; for (edge_set_t::iterator it = triangulated_face_edges.begin(); it != triangulated_face_edges.end(); ++it) { MeshSet<3>::edge_t *edge = *it; origEdgeMappingForFace(edge->face, orig_face_edge_mapping, &edge_origindex_map); triangulated_faces.insert(edge->face); origEdgeMappingForFace(edge->rev->face, orig_face_edge_mapping, &edge_origindex_map); triangulated_faces.insert(edge->rev->face); } carve::mesh::MeshSimplifier simplifier; simplifier.dissolveMeshEdges(mesh, triangulated_face_edges); for (int face_index = 0; face_index < mesh->faces.size(); face_index++) { MeshSet<3>::face_t *face = mesh->faces[face_index]; if (triangulated_faces.find(face) != triangulated_faces.end()) { MeshSet<3>::edge_t *edge = face->edge; for (int edge_index = 0; edge_index < face->nEdges(); ++edge_index, edge = edge->next) { MeshSet<3>::vertex_t *v1 = edge->v1(); MeshSet<3>::vertex_t *v2 = edge->v2(); OrigIndex orig_edge_index = edgeIndexMap_get(edge_origindex_map, v1, v2); orig_face_edge_mapping->setAttribute(face, edge_index, orig_edge_index); } } } } } void dissolveTriangulatedEdges(CarveMeshDescr *mesh_descr) { MeshSet<3> *poly = mesh_descr->poly; FaceEdgeTriangulatedFlag *face_edge_triangulated_flag = &mesh_descr->face_edge_triangulated_flag; std::set< std::pair > open_edges; for (int mesh_index = 0; mesh_index < poly->meshes.size(); ++mesh_index) { const MeshSet<3>::mesh_t *mesh = poly->meshes[mesh_index]; for (int edge_index = 0; edge_index < mesh->open_edges.size(); ++edge_index) { const MeshSet<3>::edge_t *edge = mesh->open_edges[edge_index]; int v1 = indexOf(edge->v1(), poly->vertex_storage), v2 = indexOf(edge->v2(), poly->vertex_storage); if (v1 < v2) { open_edges.insert(std::make_pair(v1, v2)); } else { open_edges.insert(std::make_pair(v2, v1)); } } } for (int mesh_index = 0; mesh_index < poly->meshes.size(); ++mesh_index) { MeshSet<3>::mesh_t *mesh = poly->meshes[mesh_index]; dissolveTriangulatedEdges(mesh, open_edges, face_edge_triangulated_flag, &mesh_descr->orig_face_edge_mapping); } } void clipEar(MeshSet<3>::edge_t *ear) { MeshSet<3>::edge_t *p_edge = ear->prev; MeshSet<3>::edge_t *n_edge = ear->next; p_edge->next = n_edge; n_edge->prev = p_edge; if (ear->face->edge == ear) { ear->face->edge = n_edge; } ear->face->n_edges--; delete ear; } MeshSet<3>::edge_t *findDegenerateEar(MeshSet<3>::face_t *face) { for (MeshSet<3>::face_t::edge_iter_t edge_iter = face->begin(); edge_iter != face->end(); ++edge_iter) { MeshSet<3>::edge_t &edge = *edge_iter; if (edge.vert == edge.next->next->vert) { return edge.next->next; } } return NULL; } class EarClipper : public carve::csg::CSG::Hook { public: virtual ~EarClipper() { } virtual void processOutputFace(std::vector::face_t *> &faces, const MeshSet<3>::face_t *orig, bool flipped) { for (size_t face_index = 0; face_index < faces.size(); ++face_index) { carve::mesh::MeshSet<3>::face_t *face = faces[face_index]; // There's no ears in quads and tris. if (face->nVertices() <= 4) { continue; } MeshSet<3>::edge_t *ear; while ((ear = findDegenerateEar(face)) != NULL) { clipEar(ear); } } } }; class HoleResolver : public carve::csg::CarveHoleResolver { void removeDuplicatedFaces(std::vector::face_t *> &faces) { std::vector::face_t *> out_faces; std::vector::face_t *> duplicated_faces; for (size_t face_index = 0; face_index < faces.size(); ++face_index) { carve::mesh::MeshSet<3>::face_t *face = faces[face_index]; face->canonicalize(); } for (size_t i = 0; i < faces.size(); ++i) { carve::mesh::MeshSet<3>::face_t *face = faces[i]; bool found = false; for (size_t j = i + 1; j < faces.size() && found == false; ++j) { MeshSet<3>::face_t *cur_face = faces[j]; if (cur_face->nEdges() == face->nEdges() && cur_face->edge->vert == face->edge->vert) { MeshSet<3>::edge_t *cur_edge = cur_face->edge, *forward_edge = face->edge, *backward_edge = face->edge; bool forward_matches = true, backward_matches = true; for (int a = 0; a < cur_face->nEdges(); ++a) { if (forward_edge->vert != cur_edge->vert) { forward_matches = false; if (backward_matches == false) { break; } } if (backward_edge->vert != cur_edge->vert) { backward_matches = false; if (forward_matches == false) { break; } } cur_edge = cur_edge->next; forward_edge = forward_edge->next; backward_edge = backward_edge->prev; } if (forward_matches || backward_matches) { found = true; break; } } } if (found) { duplicated_faces.push_back(face); } else { out_faces.push_back(face); } } for (int i = 0; i < duplicated_faces.size(); ++i) { delete duplicated_faces[i]; } std::swap(faces, out_faces); } public: virtual ~HoleResolver() { } virtual void processOutputFace(std::vector::face_t *> &faces, const MeshSet<3>::face_t *orig, bool flipped) { carve::csg::CarveHoleResolver::processOutputFace(faces, orig, flipped); if (faces.size() > 1) { removeDuplicatedFaces(faces); } } }; template void copyFaceEdgeAttrs(const MeshSet<3> *poly, Interpolator *old_interpolator, Interpolator *new_interpolator) { for (MeshSet<3>::const_face_iter face_iter = poly->faceBegin(); face_iter != poly->faceEnd(); ++face_iter) { const MeshSet<3>::face_t *face = *face_iter; for (int edge_index = 0; edge_index < face->nEdges(); ++edge_index) { new_interpolator->copyAttribute(face, edge_index, old_interpolator); } } } template void cleanupFaceEdgeAttrs(const MeshSet<3> *left, const MeshSet<3> *right, Interpolator *interpolator) { Interpolator new_interpolator; copyFaceEdgeAttrs(left, interpolator, &new_interpolator); copyFaceEdgeAttrs(right, interpolator, &new_interpolator); interpolator->swapAttributes(&new_interpolator); } void cleanupFaceEdgeAttrsCallback(const MeshSet<3> *left, const MeshSet<3> *right, void *descr_v) { CarveMeshDescr *descr = (CarveMeshDescr *) descr_v; cleanupFaceEdgeAttrs(left, right, &descr->face_edge_triangulated_flag); cleanupFaceEdgeAttrs(left, right, &descr->orig_face_edge_mapping); } void copyVertexAttrsCallback(const carve::mesh::MeshSet<3>::vertex_t *orig_vert, const carve::mesh::MeshSet<3>::vertex_t *new_vert, void *descr_v) { CarveMeshDescr *descr = (CarveMeshDescr *) descr_v; if (!descr->orig_vert_mapping.hasAttribute(orig_vert)) { return; } if (descr->orig_vert_mapping.hasAttribute(new_vert)) { return; } OrigIndex attr = descr->orig_vert_mapping.getAttribute(orig_vert); descr->orig_vert_mapping.setAttribute(new_vert, attr); descr->orig_vert_mapping.removeAttribute(orig_vert); } } // namespace CarveMeshDescr *carve_addMesh(struct ImportMeshData *import_data, CarveMeshImporter *mesh_importer) { #define MAX_STATIC_VERTS 64 CarveMeshDescr *mesh_descr = new CarveMeshDescr; // Import verices from external mesh to Carve. int num_verts = mesh_importer->getNumVerts(import_data); std::vector::vertex_t> vertex_storage; vertex_storage.reserve(num_verts); for (int i = 0; i < num_verts; i++) { float position[3]; mesh_importer->getVertCoord(import_data, i, position); vertex_storage.push_back(carve::geom::VECTOR(position[0], position[1], position[2])); } // Import polys from external mesh to Carve. int verts_of_poly_static[MAX_STATIC_VERTS]; int *verts_of_poly_dynamic = NULL; int verts_of_poly_dynamic_size = 0; int num_polys = mesh_importer->getNumPolys(import_data); int loop_index = 0; std::vector face_indices; TrianglesStorage triangles_storage; std::vector::face_t *> faces; std::vector::vertex_t *> face_vertices; faces.reserve(num_polys); for (int i = 0; i < num_polys; i++) { int verts_per_poly = mesh_importer->getNumPolyVerts(import_data, i); int *verts_of_poly; if (verts_per_poly <= MAX_STATIC_VERTS) { verts_of_poly = verts_of_poly_static; } else { if (verts_of_poly_dynamic_size < verts_per_poly) { if (verts_of_poly_dynamic != NULL) { delete [] verts_of_poly_dynamic; } verts_of_poly_dynamic = new int[verts_per_poly]; verts_of_poly_dynamic_size = verts_per_poly; } verts_of_poly = verts_of_poly_dynamic; } mesh_importer->getPolyVerts(import_data, i, verts_of_poly); carve::math::Matrix3 axis_matrix; if (!carve_checkPolyPlanarAndGetNormal(vertex_storage, verts_per_poly, verts_of_poly, &axis_matrix)) { face_indices.clear(); int num_triangles = carve_triangulatePoly(import_data, mesh_importer, vertex_storage, verts_per_poly, verts_of_poly, axis_matrix, &face_indices, &triangles_storage); for (int j = 0; j < num_triangles; ++j) { MeshSet<3>::face_t *face = new MeshSet<3>::face_t( &vertex_storage[face_indices[j * 3]], &vertex_storage[face_indices[j * 3 + 1]], &vertex_storage[face_indices[j * 3 + 2]]); mesh_descr->orig_poly_index_map[face] = i; faces.push_back(face); } } else { face_vertices.clear(); face_vertices.reserve(verts_per_poly); for (int j = 0; j < verts_per_poly; ++j) { face_vertices.push_back(&vertex_storage[verts_of_poly[j]]); } MeshSet<3>::face_t *face = new MeshSet<3>::face_t(face_vertices.begin(), face_vertices.end()); mesh_descr->orig_poly_index_map[face] = i; faces.push_back(face); } for (int j = 0; j < verts_per_poly; ++j) { int v1 = verts_of_poly[j]; int v2 = verts_of_poly[(j + 1) % verts_per_poly]; edgeIndexMap_put(&mesh_descr->orig_loop_index_map, v1, v2, loop_index++); } } if (verts_of_poly_dynamic != NULL) { delete [] verts_of_poly_dynamic; } std::vector::mesh_t *> meshes; MeshSet<3>::mesh_t::create(faces.begin(), faces.end(), meshes, carve::mesh::MeshOptions()); mesh_descr->poly = new MeshSet<3> (vertex_storage, meshes); return mesh_descr; #undef MAX_STATIC_VERTS } void carve_deleteMesh(CarveMeshDescr *mesh_descr) { delete mesh_descr->poly; delete mesh_descr; } bool carve_performBooleanOperation(CarveMeshDescr *left_mesh, CarveMeshDescr *right_mesh, int operation, CarveMeshDescr **output_mesh) { *output_mesh = NULL; carve::csg::CSG::OP op; switch (operation) { #define OP_CONVERT(the_op) \ case CARVE_OP_ ## the_op: \ op = carve::csg::CSG::the_op; \ break; OP_CONVERT(UNION) OP_CONVERT(INTERSECTION) OP_CONVERT(A_MINUS_B) default: return false; #undef OP_CONVERT } CarveMeshDescr *output_descr = new CarveMeshDescr; output_descr->poly = NULL; try { MeshSet<3> *left = left_mesh->poly, *right = right_mesh->poly; carve::geom3d::Vector min, max; // TODO(sergey): Make importer/exporter to care about re-scale // to save extra mesh iteration here. carve_getRescaleMinMax(left, right, &min, &max); carve::rescale::rescale scaler(min.x, min.y, min.z, max.x, max.y, max.z); carve::rescale::fwd fwd_r(scaler); carve::rescale::rev rev_r(scaler); left->transform(fwd_r); right->transform(fwd_r); // Initialize attributes for maping from boolean result mesh back to // original geometry indices. initOrigIndexMapping(left_mesh, right_mesh, &output_descr->orig_vert_mapping, &output_descr->orig_face_edge_mapping, &output_descr->face_edge_triangulated_flag, &output_descr->orig_face_mapping); carve::csg::CSG csg; csg.hooks.registerHook(new HoleResolver, carve::csg::CSG::Hooks::PROCESS_OUTPUT_FACE_BIT); csg.hooks.registerHook(new EarClipper, carve::csg::CSG::Hooks::PROCESS_OUTPUT_FACE_BIT); output_descr->orig_vert_mapping.installHooks(csg); output_descr->orig_face_edge_mapping.installHooks(csg); output_descr->face_edge_triangulated_flag.installHooks(csg); output_descr->orig_face_mapping.installHooks(csg); // Prepare operands for actual boolean operation. // // It's needed because operands might consist of several intersecting // meshes and in case of another operands intersect an edge loop of // intersecting that meshes tessellation of operation result can't be // done properly. The only way to make such situations working is to // union intersecting meshes of the same operand. carve_unionIntersections(&csg, &left, &right, copyVertexAttrsCallback, cleanupFaceEdgeAttrsCallback, (void *) output_descr); left_mesh->poly = left; right_mesh->poly = right; if (left->meshes.size() == 0 || right->meshes.size() == 0) { // Normally shouldn't happen (zero-faces objects are handled by // modifier itself), but unioning intersecting meshes which doesn't // have consistent normals might lead to empty result which // wouldn't work here. return false; } output_descr->poly = csg.compute(left, right, op, NULL, carve::csg::CSG::CLASSIFY_EDGE); if (output_descr->poly) { output_descr->poly->transform(rev_r); dissolveTriangulatedEdges(output_descr); } } catch (carve::exception e) { std::cerr << "CSG failed, exception " << e.str() << std::endl; } catch (...) { std::cerr << "Unknown error in Carve library" << std::endl; } *output_mesh = output_descr; return output_descr->poly != NULL; } static int exportMesh_handle_edges_list(MeshSet<3> *poly, const std::vector::edge_t*> &edges, int start_edge_index, CarveMeshExporter *mesh_exporter, struct ExportMeshData *export_data, std::unordered_map &edge_origindex_map, std::unordered_map *edge_map) { int num_exported_edges = 0; for (int i = 0, edge_index = start_edge_index; i < edges.size(); ++i) { MeshSet<3>::edge_t *edge = edges.at(i); MeshSet<3>::vertex_t *v1 = edge->v1(); MeshSet<3>::vertex_t *v2 = edge->v2(); if (edgeIndexMap_exists(*edge_map, v1, v2)) { continue; } const OrigIndex &orig_edge_index = edgeIndexMap_get(edge_origindex_map, v1, v2); mesh_exporter->setEdge(export_data, edge_index, indexOf(v1, poly->vertex_storage), indexOf(v2, poly->vertex_storage), orig_edge_index.first, orig_edge_index.second); edgeIndexMap_put(edge_map, v1, v2, edge_index); ++edge_index; ++num_exported_edges; } return num_exported_edges; } void carve_exportMesh(CarveMeshDescr *mesh_descr, CarveMeshExporter *mesh_exporter, struct ExportMeshData *export_data) { OrigIndex origindex_none = std::make_pair((int)CARVE_MESH_NONE, -1); MeshSet<3> *poly = mesh_descr->poly; int num_vertices = poly->vertex_storage.size(); int num_edges = 0, num_loops = 0, num_polys = 0; // Get mapping from edge denoted by vertex pair to original edge index, // // This is needed because internally Carve interpolates data for per-face // edges rather then having some global edge storage. std::unordered_map edge_origindex_map; for (MeshSet<3>::face_iter face_iter = poly->faceBegin(); face_iter != poly->faceEnd(); ++face_iter) { MeshSet<3>::face_t *face = *face_iter; for (MeshSet<3>::face_t::edge_iter_t edge_iter = face->begin(); edge_iter != face->end(); ++edge_iter) { MeshSet<3>::edge_t &edge = *edge_iter; int edge_iter_index = edge_iter.idx(); const OrigIndex &orig_loop_index = mesh_descr->orig_face_edge_mapping.getAttribute(face, edge_iter_index, origindex_none); OrigIndex orig_edge_index; if (orig_loop_index.first != CARVE_MESH_NONE) { orig_edge_index.first = orig_loop_index.first; orig_edge_index.second = mesh_exporter->mapLoopToEdge(export_data, orig_loop_index.first, orig_loop_index.second); } else { orig_edge_index.first = CARVE_MESH_NONE; orig_edge_index.second = -1; } MeshSet<3>::vertex_t *v1 = edge.v1(); MeshSet<3>::vertex_t *v2 = edge.v2(); edgeIndexMap_put(&edge_origindex_map, v1, v2, orig_edge_index); } } num_edges = edge_origindex_map.size(); // Count polys and loops from all manifolds. for (MeshSet<3>::face_iter face_iter = poly->faceBegin(); face_iter != poly->faceEnd(); ++face_iter, ++num_polys) { MeshSet<3>::face_t *face = *face_iter; num_loops += face->nEdges(); } // Initialize arrays for geometry in exported mesh. mesh_exporter->initGeomArrays(export_data, num_vertices, num_edges, num_loops, num_polys); // Export all the vertices. std::vector::vertex_t>::iterator vertex_iter = poly->vertex_storage.begin(); for (int i = 0; vertex_iter != poly->vertex_storage.end(); ++i, ++vertex_iter) { MeshSet<3>::vertex_t *vertex = &(*vertex_iter); OrigIndex orig_vert_index = mesh_descr->orig_vert_mapping.getAttribute(vertex, origindex_none); float coord[3]; coord[0] = vertex->v[0]; coord[1] = vertex->v[1]; coord[2] = vertex->v[2]; mesh_exporter->setVert(export_data, i, coord, orig_vert_index.first, orig_vert_index.second); } // Export all the edges. std::unordered_map edge_map; for (int i = 0, edge_index = 0; i < poly->meshes.size(); ++i) { carve::mesh::Mesh<3> *mesh = poly->meshes[i]; // Export closed edges. edge_index += exportMesh_handle_edges_list(poly, mesh->closed_edges, edge_index, mesh_exporter, export_data, edge_origindex_map, &edge_map); // Export open edges. edge_index += exportMesh_handle_edges_list(poly, mesh->open_edges, edge_index, mesh_exporter, export_data, edge_origindex_map, &edge_map); } // Export all the loops and polys. MeshSet<3>::face_iter face_iter = poly->faceBegin(); for (int loop_index = 0, poly_index = 0; face_iter != poly->faceEnd(); ++face_iter, ++poly_index) { int start_loop_index = loop_index; MeshSet<3>::face_t *face = *face_iter; const OrigIndex &orig_face_index = mesh_descr->orig_face_mapping.getAttribute(face, origindex_none); for (MeshSet<3>::face_t::edge_iter_t edge_iter = face->begin(); edge_iter != face->end(); ++edge_iter, ++loop_index) { MeshSet<3>::edge_t &edge = *edge_iter; const OrigIndex &orig_loop_index = mesh_descr->orig_face_edge_mapping.getAttribute(face, edge_iter.idx(), origindex_none); mesh_exporter->setLoop(export_data, loop_index, indexOf(edge.vert, poly->vertex_storage), edgeIndexMap_get(edge_map, edge.v1(), edge.v2()), orig_loop_index.first, orig_loop_index.second); } mesh_exporter->setPoly(export_data, poly_index, start_loop_index, face->nEdges(), orig_face_index.first, orig_face_index.second); } }