Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'extern/carve/carve-capi.cc')
-rw-r--r--extern/carve/carve-capi.cc580
1 files changed, 580 insertions, 0 deletions
diff --git a/extern/carve/carve-capi.cc b/extern/carve/carve-capi.cc
new file mode 100644
index 00000000000..7478c341663
--- /dev/null
+++ b/extern/carve/carve-capi.cc
@@ -0,0 +1,580 @@
+/*
+ * ***** 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 <carve/interpolator.hpp>
+#include <carve/rescale.hpp>
+
+using carve::mesh::MeshSet;
+
+typedef std::pair<int, int> OrigIndex;
+typedef std::pair<MeshSet<3>::vertex_t *, MeshSet<3>::vertex_t *> VertexPair;
+typedef carve::interpolate::VertexAttr<OrigIndex> OrigVertMapping;
+typedef carve::interpolate::FaceAttr<OrigIndex> OrigFaceMapping;
+typedef carve::interpolate::FaceEdgeAttr<OrigIndex> OrigFaceEdgeMapping;
+
+typedef struct CarveMeshDescr {
+ // Stores mesh data itself.
+ MeshSet<3> *poly;
+
+ // N-th element of the vector indicates index of an original mesh loop.
+ std::vector<int> orig_loop_index_map;
+
+ // N-th element of the vector indicates index of an original mesh poly.
+ std::vector<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;
+
+ // Mapping from the faces back to original poly index.
+ OrigFaceMapping orig_face_mapping;
+} CarveMeshDescr;
+
+namespace {
+
+template <typename T1, typename T2>
+void edgeIndexMap_put(std::unordered_map<std::pair<T1, T1>, 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 <typename T1, typename T2>
+const T2 &edgeIndexMap_get(const std::unordered_map<std::pair<T1, T1>, T2> &edge_map,
+ const T1 &v1,
+ const T1 &v2)
+{
+ typedef std::unordered_map<std::pair<T1, T1>, 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 <typename T1, typename T2>
+bool edgeIndexMap_get_if_exists(const std::unordered_map<std::pair<T1, T1>, T2> &edge_map,
+ const T1 &v1,
+ const T1 &v2,
+ T2 *out)
+{
+ typedef std::unordered_map<std::pair<T1, T1>, 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 <typename T>
+inline int indexOf(const T *element, const std::vector<T> &vector_from)
+{
+ return element - &vector_from.at(0);
+}
+
+void initOrigIndexMeshFaceMapping(CarveMeshDescr *mesh,
+ int which_mesh,
+ const std::vector<int> &orig_loop_index_map,
+ const std::vector<int> &orig_poly_index_map,
+ OrigVertMapping *orig_vert_mapping,
+ OrigFaceEdgeMapping *orig_face_edge_mapping,
+ OrigFaceMapping *orig_face_attr)
+{
+ MeshSet<3> *poly = mesh->poly;
+
+ std::vector<MeshSet<3>::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[i];
+ 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 orig_loop_index = orig_loop_index_map[loop_map_index];
+ 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));
+ }
+ }
+ }
+}
+
+void initOrigIndexMapping(CarveMeshDescr *left_mesh,
+ CarveMeshDescr *right_mesh,
+ OrigVertMapping *orig_vert_mapping,
+ OrigFaceEdgeMapping *orig_face_edge_mapping,
+ 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,
+ 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,
+ orig_face_mapping);
+}
+
+} // 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<carve::geom3d::Vector> vertices;
+ vertices.reserve(num_verts);
+ for (int i = 0; i < num_verts; i++) {
+ float position[3];
+ mesh_importer->getVertCoord(import_data, i, position);
+ vertices.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_loops = mesh_importer->getNumLoops(import_data);
+ int num_polys = mesh_importer->getNumPolys(import_data);
+ int loop_index = 0;
+ int num_tessellated_polys = 0;
+ std::vector<int> face_indices;
+ face_indices.reserve(num_loops);
+ mesh_descr->orig_loop_index_map.reserve(num_polys);
+ mesh_descr->orig_poly_index_map.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(vertices,
+ verts_per_poly,
+ verts_of_poly,
+ &axis_matrix)) {
+ int num_triangles;
+
+ num_triangles = carve_triangulatePoly(import_data,
+ mesh_importer,
+ i,
+ loop_index,
+ vertices,
+ verts_per_poly,
+ verts_of_poly,
+ axis_matrix,
+ &face_indices,
+ &mesh_descr->orig_loop_index_map,
+ &mesh_descr->orig_poly_index_map);
+
+ num_tessellated_polys += num_triangles;
+ }
+ else {
+ face_indices.push_back(verts_per_poly);
+ for (int j = 0; j < verts_per_poly; ++j) {
+ mesh_descr->orig_loop_index_map.push_back(loop_index++);
+ face_indices.push_back(verts_of_poly[j]);
+ }
+ mesh_descr->orig_poly_index_map.push_back(i);
+ num_tessellated_polys++;
+ }
+ }
+
+ if (verts_of_poly_dynamic != NULL) {
+ delete [] verts_of_poly_dynamic;
+ }
+
+ mesh_descr->poly = new MeshSet<3> (vertices,
+ num_tessellated_polys,
+ face_indices);
+
+ 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->orig_face_mapping);
+
+ carve::csg::CSG csg;
+
+ output_descr->orig_vert_mapping.installHooks(csg);
+ output_descr->orig_face_edge_mapping.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);
+ 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);
+ }
+ }
+ 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 void exportMesh_handle_edges_list(MeshSet<3> *poly,
+ const std::vector<MeshSet<3>::edge_t*> &edges,
+ int start_edge_index,
+ CarveMeshExporter *mesh_exporter,
+ struct ExportMeshData *export_data,
+ const std::unordered_map<VertexPair, OrigIndex> &edge_origindex_map,
+ std::unordered_map<VertexPair, int> *edge_map)
+{
+ for (int i = 0, edge_index = start_edge_index;
+ i < edges.size();
+ ++i, ++edge_index)
+ {
+ MeshSet<3>::edge_t *edge = edges.at(i);
+ MeshSet<3>::vertex_t *v1 = edge->vert;
+ MeshSet<3>::vertex_t *v2 = edge->next->vert;
+
+ OrigIndex orig_edge_index;
+
+ if (!edgeIndexMap_get_if_exists(edge_origindex_map,
+ v1,
+ v2,
+ &orig_edge_index))
+ {
+ orig_edge_index.first = CARVE_MESH_NONE;
+ orig_edge_index.second = -1;
+ }
+
+ 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);
+ }
+}
+
+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;
+
+ // Count edges from all manifolds.
+ for (int i = 0; i < poly->meshes.size(); ++i) {
+ carve::mesh::Mesh<3> *mesh = poly->meshes[i];
+ num_edges += mesh->closed_edges.size() + mesh->open_edges.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->n_edges;
+ }
+
+ // Initialize arrays for geometry in exported mesh.
+ mesh_exporter->initGeomArrays(export_data,
+ num_vertices,
+ num_edges,
+ num_loops,
+ num_polys);
+
+ // 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<VertexPair, OrigIndex> 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);
+
+ if (orig_loop_index.first != CARVE_MESH_NONE) {
+ OrigIndex orig_edge_index;
+
+ 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);
+
+ MeshSet<3>::vertex_t *v1 = edge.vert;
+ MeshSet<3>::vertex_t *v2 = edge.next->vert;
+
+ edgeIndexMap_put(&edge_origindex_map, v1, v2, orig_edge_index);
+ }
+ }
+ }
+
+ // Export all the vertices.
+ std::vector<MeshSet<3>::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<VertexPair, int> 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.
+ exportMesh_handle_edges_list(poly,
+ mesh->closed_edges,
+ edge_index,
+ mesh_exporter,
+ export_data,
+ edge_origindex_map,
+ &edge_map);
+
+ // Export open edges.
+ exportMesh_handle_edges_list(poly,
+ mesh->open_edges,
+ edge_index,
+ mesh_exporter,
+ export_data,
+ edge_origindex_map,
+ &edge_map);
+
+ edge_index += mesh->closed_edges.size();
+ }
+
+ // 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.vert, edge.next->vert),
+ orig_loop_index.first,
+ orig_loop_index.second);
+ }
+
+ mesh_exporter->setPoly(export_data,
+ poly_index, start_loop_index, face->n_edges,
+ orig_face_index.first, orig_face_index.second);
+ }
+}