blender/extern/carve/carve-capi.cc
2017-09-15 16:33:52 +05:00

995 lines
32 KiB
C++

/*
* ***** 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>
#include <carve/csg_triangulator.hpp>
#include <carve/mesh_simplify.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::SwapableFaceEdgeAttr<OrigIndex> OrigFaceEdgeMapping;
typedef carve::interpolate::SimpleFaceEdgeAttr<bool> 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<std::pair<int, int>, int> orig_loop_index_map;
// Mapping from carve face to an original face index in DM.
std::unordered_map<const MeshSet<3>::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 <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 T1, typename T2>
bool edgeIndexMap_exists(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));
}
return found != edge_map.end();
}
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,
std::unordered_map<std::pair<int, int>, int> &orig_loop_index_map,
std::unordered_map<const MeshSet<3>::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<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[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<VertexPair, OrigIndex> *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<int, int> > &open_edges,
FaceEdgeTriangulatedFlag *face_edge_triangulated_flag,
OrigFaceEdgeMapping *orig_face_edge_mapping)
{
typedef std::unordered_set<MeshSet<3>::edge_t *> edge_set_t;
typedef std::unordered_set<MeshSet<3>::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<VertexPair, OrigIndex> 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<int, int> > 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<MeshSet<3>::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<MeshSet<3>::face_t *> &faces) {
std::vector<MeshSet<3>::face_t *> out_faces;
std::vector<MeshSet<3>::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<MeshSet<3>::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 <typename Interpolator>
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 <typename Interpolator>
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<MeshSet<3>::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<int> face_indices;
TrianglesStorage triangles_storage;
std::vector<MeshSet<3>::face_t *> faces;
std::vector<MeshSet<3>::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<MeshSet<3>::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<MeshSet<3>::edge_t*> &edges,
int start_edge_index,
CarveMeshExporter *mesh_exporter,
struct ExportMeshData *export_data,
std::unordered_map<VertexPair, OrigIndex> &edge_origindex_map,
std::unordered_map<VertexPair, int> *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<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);
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<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.
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);
}
}