blender/extern/carve/carve-util.h

289 lines
8.8 KiB
C
Raw Normal View History

/*
* ***** 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 *****
*/
#ifndef __CARVE_UTIL_H__
#define __CARVE_UTIL_H__
#include <carve/csg.hpp>
#include <carve/geom3d.hpp>
#include <carve/interpolator.hpp>
#include <carve/mesh.hpp>
Fix T38918: Boolean modifier crashes when using specific topology There were loads of issues in the code still which are mow likely fixed: - Hole resolver hook had memory leak -- it didn't free face with holes when triangulating it. - Original edge mapping didn't work correct. old code related on the fact that loop order is not changing when constructing the MeshSet class, but in fact it does change. Currently used edge map for this because it was easiest way to do it now, but after the release we're to change it. Main reason is that face mapping is not correct as well (and it was never correct actually). So we'll need to construct Mesh structures by our own to be sure we're using correct original index mapping. - Carve might produce faces with ears, which is forbidden in Blender. it wasn't an issue in old integration because triangulation will remove the ears. So for now simply added ears removing back as a hook. But actual reason of the ears is to be investigated really. This hook will only work for NGons, quads are assumed not be able to have ears. So this additional hook shouldn't slow down things much. - Carve's hole resolver produces duplicated faces in some cases. Still not sure what is the reason of this. Code here is not so much straightforward, this is to be investigated later. For now solved the issue as own hole resolver which checks for duplicated faces after the hole resolving. The additional checks here will only run if the mesh actually have hole and wouldn't introduce slowdown for faces which doesn't have holes. - Made it so if edge user triangulation gets a split (for example, in cases when this edge intersects with the second operand) it wouldn't be dissolved. This prevents cases of crappy topology after dissolving in several cases. - Edge dissolver didn't check for whether edge is a non-manifold. We couldn't really dissolve open manifold edges. The bad thing about this is that mesh triangulation might produce non-manifold edges and they wouldn't be dissolved. Not worst case in the world, but would be nice to have it solved somehow. - Exporting mesh form Carve to Blender might have produced duplicated edges in cases when several non-manifold faces shared the edge. This is also fixed now. - Mesh triangulation might have produced duplicated faces, which is really bad. Fixed by keeping a track on which faces we've created and skipping adding new triangle if we already have one. This all might introduce some slowdown, but we're too close to the release now, so would rather have it slower but robust. After the release we might look into ways to speed things up.
2014-03-04 14:01:58 +00:00
#include <carve/triangulator.hpp>
#include "carve-capi.h"
Fix T38918: Boolean modifier crashes when using specific topology There were loads of issues in the code still which are mow likely fixed: - Hole resolver hook had memory leak -- it didn't free face with holes when triangulating it. - Original edge mapping didn't work correct. old code related on the fact that loop order is not changing when constructing the MeshSet class, but in fact it does change. Currently used edge map for this because it was easiest way to do it now, but after the release we're to change it. Main reason is that face mapping is not correct as well (and it was never correct actually). So we'll need to construct Mesh structures by our own to be sure we're using correct original index mapping. - Carve might produce faces with ears, which is forbidden in Blender. it wasn't an issue in old integration because triangulation will remove the ears. So for now simply added ears removing back as a hook. But actual reason of the ears is to be investigated really. This hook will only work for NGons, quads are assumed not be able to have ears. So this additional hook shouldn't slow down things much. - Carve's hole resolver produces duplicated faces in some cases. Still not sure what is the reason of this. Code here is not so much straightforward, this is to be investigated later. For now solved the issue as own hole resolver which checks for duplicated faces after the hole resolving. The additional checks here will only run if the mesh actually have hole and wouldn't introduce slowdown for faces which doesn't have holes. - Made it so if edge user triangulation gets a split (for example, in cases when this edge intersects with the second operand) it wouldn't be dissolved. This prevents cases of crappy topology after dissolving in several cases. - Edge dissolver didn't check for whether edge is a non-manifold. We couldn't really dissolve open manifold edges. The bad thing about this is that mesh triangulation might produce non-manifold edges and they wouldn't be dissolved. Not worst case in the world, but would be nice to have it solved somehow. - Exporting mesh form Carve to Blender might have produced duplicated edges in cases when several non-manifold faces shared the edge. This is also fixed now. - Mesh triangulation might have produced duplicated faces, which is really bad. Fixed by keeping a track on which faces we've created and skipping adding new triangle if we already have one. This all might introduce some slowdown, but we're too close to the release now, so would rather have it slower but robust. After the release we might look into ways to speed things up.
2014-03-04 14:01:58 +00:00
struct TriIdxCompare {
bool operator() (const carve::triangulate::tri_idx &left,
2014-03-04 14:36:05 +00:00
const carve::triangulate::tri_idx &right) const {
Fix T38918: Boolean modifier crashes when using specific topology There were loads of issues in the code still which are mow likely fixed: - Hole resolver hook had memory leak -- it didn't free face with holes when triangulating it. - Original edge mapping didn't work correct. old code related on the fact that loop order is not changing when constructing the MeshSet class, but in fact it does change. Currently used edge map for this because it was easiest way to do it now, but after the release we're to change it. Main reason is that face mapping is not correct as well (and it was never correct actually). So we'll need to construct Mesh structures by our own to be sure we're using correct original index mapping. - Carve might produce faces with ears, which is forbidden in Blender. it wasn't an issue in old integration because triangulation will remove the ears. So for now simply added ears removing back as a hook. But actual reason of the ears is to be investigated really. This hook will only work for NGons, quads are assumed not be able to have ears. So this additional hook shouldn't slow down things much. - Carve's hole resolver produces duplicated faces in some cases. Still not sure what is the reason of this. Code here is not so much straightforward, this is to be investigated later. For now solved the issue as own hole resolver which checks for duplicated faces after the hole resolving. The additional checks here will only run if the mesh actually have hole and wouldn't introduce slowdown for faces which doesn't have holes. - Made it so if edge user triangulation gets a split (for example, in cases when this edge intersects with the second operand) it wouldn't be dissolved. This prevents cases of crappy topology after dissolving in several cases. - Edge dissolver didn't check for whether edge is a non-manifold. We couldn't really dissolve open manifold edges. The bad thing about this is that mesh triangulation might produce non-manifold edges and they wouldn't be dissolved. Not worst case in the world, but would be nice to have it solved somehow. - Exporting mesh form Carve to Blender might have produced duplicated edges in cases when several non-manifold faces shared the edge. This is also fixed now. - Mesh triangulation might have produced duplicated faces, which is really bad. Fixed by keeping a track on which faces we've created and skipping adding new triangle if we already have one. This all might introduce some slowdown, but we're too close to the release now, so would rather have it slower but robust. After the release we might look into ways to speed things up.
2014-03-04 14:01:58 +00:00
if (left.a < right.a) {
return true;
}
else if (left.a > right.a) {
return false;
}
if (left.b < right.b) {
return true;
}
else if (left.b > right.b) {
return false;
}
if (left.c < right.c) {
return true;
}
else if (left.c > right.c) {
return false;
}
return false;
}
};
typedef std::set<carve::triangulate::tri_idx, TriIdxCompare> TrianglesStorage;
void carve_getRescaleMinMax(const carve::mesh::MeshSet<3> *left,
const carve::mesh::MeshSet<3> *right,
carve::geom3d::Vector *min,
carve::geom3d::Vector *max);
typedef void (*UnionIntersectionsCallback) (const carve::mesh::MeshSet<3> *left,
const carve::mesh::MeshSet<3> *right,
void *userdata);
void carve_unionIntersections(carve::csg::CSG *csg,
carve::mesh::MeshSet<3> **left_r,
carve::mesh::MeshSet<3> **right_r,
UnionIntersectionsCallback callback,
void *user_data);
bool carve_checkPolyPlanarAndGetNormal(const std::vector<carve::mesh::MeshSet<3>::vertex_t> &vertex_storage,
const int verts_per_poly,
const int *verts_of_poly,
carve::math::Matrix3 *axis_matrix_r);
int carve_triangulatePoly(struct ImportMeshData *import_data,
CarveMeshImporter *mesh_importer,
const std::vector<carve::mesh::MeshSet<3>::vertex_t> &vertex_storage,
const int verts_per_poly,
const int *verts_of_poly,
const carve::math::Matrix3 &axis_matrix,
std::vector<int> *face_indices,
Fix T38918: Boolean modifier crashes when using specific topology There were loads of issues in the code still which are mow likely fixed: - Hole resolver hook had memory leak -- it didn't free face with holes when triangulating it. - Original edge mapping didn't work correct. old code related on the fact that loop order is not changing when constructing the MeshSet class, but in fact it does change. Currently used edge map for this because it was easiest way to do it now, but after the release we're to change it. Main reason is that face mapping is not correct as well (and it was never correct actually). So we'll need to construct Mesh structures by our own to be sure we're using correct original index mapping. - Carve might produce faces with ears, which is forbidden in Blender. it wasn't an issue in old integration because triangulation will remove the ears. So for now simply added ears removing back as a hook. But actual reason of the ears is to be investigated really. This hook will only work for NGons, quads are assumed not be able to have ears. So this additional hook shouldn't slow down things much. - Carve's hole resolver produces duplicated faces in some cases. Still not sure what is the reason of this. Code here is not so much straightforward, this is to be investigated later. For now solved the issue as own hole resolver which checks for duplicated faces after the hole resolving. The additional checks here will only run if the mesh actually have hole and wouldn't introduce slowdown for faces which doesn't have holes. - Made it so if edge user triangulation gets a split (for example, in cases when this edge intersects with the second operand) it wouldn't be dissolved. This prevents cases of crappy topology after dissolving in several cases. - Edge dissolver didn't check for whether edge is a non-manifold. We couldn't really dissolve open manifold edges. The bad thing about this is that mesh triangulation might produce non-manifold edges and they wouldn't be dissolved. Not worst case in the world, but would be nice to have it solved somehow. - Exporting mesh form Carve to Blender might have produced duplicated edges in cases when several non-manifold faces shared the edge. This is also fixed now. - Mesh triangulation might have produced duplicated faces, which is really bad. Fixed by keeping a track on which faces we've created and skipping adding new triangle if we already have one. This all might introduce some slowdown, but we're too close to the release now, so would rather have it slower but robust. After the release we might look into ways to speed things up.
2014-03-04 14:01:58 +00:00
TrianglesStorage *triangles_storage);
namespace carve {
namespace interpolate {
template<typename attr_t>
class VertexAttr : public Interpolator {
public:
typedef const meshset_t::vertex_t *key_t;
protected:
typedef std::unordered_map<key_t, attr_t> attrmap_t;
attrmap_t attrs;
virtual void resultFace(const carve::csg::CSG &csg,
const meshset_t::face_t *new_face,
const meshset_t::face_t *orig_face,
bool flipped)
{
typedef meshset_t::face_t::const_edge_iter_t const_edge_iter_t;
for (const_edge_iter_t new_edge_iter = new_face->begin();
new_edge_iter != new_face->end();
++new_edge_iter)
{
typename attrmap_t::const_iterator found =
attrs.find(new_edge_iter->vert);
if (found == attrs.end()) {
for (const_edge_iter_t orig_edge_iter = orig_face->begin();
orig_edge_iter != orig_face->end();
++orig_edge_iter)
{
if ((orig_edge_iter->vert->v - new_edge_iter->vert->v).length2() < 1e-5) {
attrs[new_edge_iter->vert] = attrs[orig_edge_iter->vert];
}
}
}
}
}
public:
bool hasAttribute(const meshset_t::vertex_t *v) {
return attrs.find(v) != attrs.end();
}
const attr_t &getAttribute(const meshset_t::vertex_t *v, const attr_t &def = attr_t()) {
typename attrmap_t::const_iterator found = attrs.find(v);
if (found != attrs.end()) {
return found->second;
}
return def;
}
void setAttribute(const meshset_t::vertex_t *v, const attr_t &attr) {
attrs[v] = attr;
}
};
Fix T38918: Boolean modifier crashes when using specific topology There were loads of issues in the code still which are mow likely fixed: - Hole resolver hook had memory leak -- it didn't free face with holes when triangulating it. - Original edge mapping didn't work correct. old code related on the fact that loop order is not changing when constructing the MeshSet class, but in fact it does change. Currently used edge map for this because it was easiest way to do it now, but after the release we're to change it. Main reason is that face mapping is not correct as well (and it was never correct actually). So we'll need to construct Mesh structures by our own to be sure we're using correct original index mapping. - Carve might produce faces with ears, which is forbidden in Blender. it wasn't an issue in old integration because triangulation will remove the ears. So for now simply added ears removing back as a hook. But actual reason of the ears is to be investigated really. This hook will only work for NGons, quads are assumed not be able to have ears. So this additional hook shouldn't slow down things much. - Carve's hole resolver produces duplicated faces in some cases. Still not sure what is the reason of this. Code here is not so much straightforward, this is to be investigated later. For now solved the issue as own hole resolver which checks for duplicated faces after the hole resolving. The additional checks here will only run if the mesh actually have hole and wouldn't introduce slowdown for faces which doesn't have holes. - Made it so if edge user triangulation gets a split (for example, in cases when this edge intersects with the second operand) it wouldn't be dissolved. This prevents cases of crappy topology after dissolving in several cases. - Edge dissolver didn't check for whether edge is a non-manifold. We couldn't really dissolve open manifold edges. The bad thing about this is that mesh triangulation might produce non-manifold edges and they wouldn't be dissolved. Not worst case in the world, but would be nice to have it solved somehow. - Exporting mesh form Carve to Blender might have produced duplicated edges in cases when several non-manifold faces shared the edge. This is also fixed now. - Mesh triangulation might have produced duplicated faces, which is really bad. Fixed by keeping a track on which faces we've created and skipping adding new triangle if we already have one. This all might introduce some slowdown, but we're too close to the release now, so would rather have it slower but robust. After the release we might look into ways to speed things up.
2014-03-04 14:01:58 +00:00
template<typename attr_t>
class SimpleFaceEdgeAttr : public Interpolator {
public:
typedef std::pair<const meshset_t::face_t *, unsigned> key_t;
protected:
typedef std::pair<const meshset_t::vertex_t *, const meshset_t::vertex_t *> vpair_t;
struct key_hash {
size_t operator()(const key_t &v) const {
return size_t(v.first) ^ size_t(v.second);
}
};
struct vpair_hash {
size_t operator()(const vpair_t &v) const {
return size_t(v.first) ^ size_t(v.second);
}
};
typedef std::unordered_map<key_t, attr_t, key_hash> attrmap_t;
typedef std::unordered_map<vpair_t, key_t, vpair_hash> edgedivmap_t;
attrmap_t attrs;
struct Hook : public Interpolator::Hook {
public:
virtual unsigned hookBits() const {
return carve::csg::CSG::Hooks::PROCESS_OUTPUT_FACE_BIT;
}
Hook(Interpolator *_interpolator, const carve::csg::CSG &_csg) : Interpolator::Hook(_interpolator, _csg) {
}
virtual ~Hook() {
}
};
virtual Interpolator::Hook *makeHook(carve::csg::CSG &csg) {
return new Hook(this, csg);
}
virtual void processOutputFace(const carve::csg::CSG &csg,
std::vector<carve::mesh::MeshSet<3>::face_t *> &new_faces,
const meshset_t::face_t *orig_face,
bool flipped) {
edgedivmap_t undiv;
for (meshset_t::face_t::const_edge_iter_t e = orig_face->begin(); e != orig_face->end(); ++e) {
key_t k(orig_face, e.idx());
typename attrmap_t::const_iterator attr_i = attrs.find(k);
if (attr_i == attrs.end()) {
continue;
} else {
undiv[vpair_t(e->v1(), e->v2())] = k;
}
}
for (size_t fnum = 0; fnum < new_faces.size(); ++fnum) {
const carve::mesh::MeshSet<3>::face_t *new_face = new_faces[fnum];
for (meshset_t::face_t::const_edge_iter_t e = new_face->begin(); e != new_face->end(); ++e) {
key_t k(new_face, e.idx());
vpair_t vp;
if (!flipped) {
vp = vpair_t(e->v1(), e->v2());
} else {
vp = vpair_t(e->v2(), e->v1());
}
typename edgedivmap_t::const_iterator vp_i;
if ((vp_i = undiv.find(vp)) != undiv.end()) {
attrs[k] = attrs[vp_i->second];
}
}
}
}
public:
bool hasAttribute(const meshset_t::face_t *f, unsigned e) {
return attrs.find(std::make_pair(f, e)) != attrs.end();
}
attr_t getAttribute(const meshset_t::face_t *f, unsigned e, const attr_t &def = attr_t()) {
typename attrmap_t::const_iterator fv = attrs.find(std::make_pair(f, e));
if (fv != attrs.end()) {
return (*fv).second;
}
return def;
}
void setAttribute(const meshset_t::face_t *f, unsigned e, const attr_t &attr) {
attrs[std::make_pair(f, e)] = attr;
}
void copyAttribute(const meshset_t::face_t *face,
unsigned edge,
SimpleFaceEdgeAttr<attr_t> *interpolator) {
key_t key(face, edge);
typename attrmap_t::const_iterator fv = interpolator->attrs.find(key);
if (fv != interpolator->attrs.end()) {
attrs[key] = (*fv).second;
}
}
void swapAttributes(SimpleFaceEdgeAttr<attr_t> *interpolator) {
attrs.swap(interpolator->attrs);
}
Fix T38918: Boolean modifier crashes when using specific topology There were loads of issues in the code still which are mow likely fixed: - Hole resolver hook had memory leak -- it didn't free face with holes when triangulating it. - Original edge mapping didn't work correct. old code related on the fact that loop order is not changing when constructing the MeshSet class, but in fact it does change. Currently used edge map for this because it was easiest way to do it now, but after the release we're to change it. Main reason is that face mapping is not correct as well (and it was never correct actually). So we'll need to construct Mesh structures by our own to be sure we're using correct original index mapping. - Carve might produce faces with ears, which is forbidden in Blender. it wasn't an issue in old integration because triangulation will remove the ears. So for now simply added ears removing back as a hook. But actual reason of the ears is to be investigated really. This hook will only work for NGons, quads are assumed not be able to have ears. So this additional hook shouldn't slow down things much. - Carve's hole resolver produces duplicated faces in some cases. Still not sure what is the reason of this. Code here is not so much straightforward, this is to be investigated later. For now solved the issue as own hole resolver which checks for duplicated faces after the hole resolving. The additional checks here will only run if the mesh actually have hole and wouldn't introduce slowdown for faces which doesn't have holes. - Made it so if edge user triangulation gets a split (for example, in cases when this edge intersects with the second operand) it wouldn't be dissolved. This prevents cases of crappy topology after dissolving in several cases. - Edge dissolver didn't check for whether edge is a non-manifold. We couldn't really dissolve open manifold edges. The bad thing about this is that mesh triangulation might produce non-manifold edges and they wouldn't be dissolved. Not worst case in the world, but would be nice to have it solved somehow. - Exporting mesh form Carve to Blender might have produced duplicated edges in cases when several non-manifold faces shared the edge. This is also fixed now. - Mesh triangulation might have produced duplicated faces, which is really bad. Fixed by keeping a track on which faces we've created and skipping adding new triangle if we already have one. This all might introduce some slowdown, but we're too close to the release now, so would rather have it slower but robust. After the release we might look into ways to speed things up.
2014-03-04 14:01:58 +00:00
SimpleFaceEdgeAttr() : Interpolator() {
}
virtual ~SimpleFaceEdgeAttr() {
}
};
template<typename attr_t>
class SwapableFaceEdgeAttr : public FaceEdgeAttr<attr_t> {
public:
typedef carve::mesh::MeshSet<3> meshset_t;
void copyAttribute(const meshset_t::face_t *face,
unsigned edge,
SwapableFaceEdgeAttr<attr_t> *interpolator) {
typename FaceEdgeAttr<attr_t>::key_t key(face, edge);
typename FaceEdgeAttr<attr_t>::attrmap_t::const_iterator fv = interpolator->attrs.find(key);
if (fv != interpolator->attrs.end()) {
this->attrs[key] = (*fv).second;
}
}
void swapAttributes(SwapableFaceEdgeAttr<attr_t> *interpolator) {
this->attrs.swap(interpolator->attrs);
}
};
} // namespace interpolate
} // namespace carve
#endif // __CARVE_UTIL_H__