diff options
Diffstat (limited to 'extern/carve/include/carve/mesh.hpp')
-rw-r--r-- | extern/carve/include/carve/mesh.hpp | 845 |
1 files changed, 845 insertions, 0 deletions
diff --git a/extern/carve/include/carve/mesh.hpp b/extern/carve/include/carve/mesh.hpp new file mode 100644 index 00000000000..d4170e55133 --- /dev/null +++ b/extern/carve/include/carve/mesh.hpp @@ -0,0 +1,845 @@ +// Begin License: +// Copyright (C) 2006-2011 Tobias Sargeant (tobias.sargeant@gmail.com). +// All rights reserved. +// +// This file is part of the Carve CSG Library (http://carve-csg.com/) +// +// This file may be used under the terms of the GNU General Public +// License version 2.0 as published by the Free Software Foundation +// and appearing in the file LICENSE.GPL2 included in the packaging of +// this file. +// +// This file is provided "AS IS" with NO WARRANTY OF ANY KIND, +// INCLUDING THE WARRANTIES OF DESIGN, MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE. +// End: + + +#pragma once + +#include <carve/carve.hpp> + +#include <carve/geom.hpp> +#include <carve/geom3d.hpp> +#include <carve/tag.hpp> +#include <carve/djset.hpp> +#include <carve/aabb.hpp> +#include <carve/rtree.hpp> + +#include <iostream> + +namespace carve { + namespace poly { + class Polyhedron; + } + + namespace mesh { + + + template<unsigned ndim> class Edge; + template<unsigned ndim> class Face; + template<unsigned ndim> class Mesh; + template<unsigned ndim> class MeshSet; + + + + // A Vertex may participate in several meshes. If the Mesh belongs + // to a MeshSet, then the vertices come from the vertex_storage + // member of the MeshSet. This allows one to construct one or more + // Meshes out of sets of connected faces (possibly using vertices + // from a variety of MeshSets, and other storage), then create a + // MeshSet from the Mesh(es), causing the vertices to be + // collected, cloned and repointed into the MeshSet. + + // Normally, in a half-edge structure, Vertex would have a member + // pointing to an incident edge, allowing the enumeration of + // adjacent faces and edges. Because we want to support vertex + // sharing between Meshes and groups of Faces, this is made more + // complex. If Vertex contained a list of incident edges, one from + // each disjoint face set, then this could be done (with the + // caveat that you'd need to pass in a Mesh pointer to the + // adjacency queries). However, it seems that this would + // unavoidably complicate the process of incorporating or removing + // a vertex into an edge. + + // In most cases it is expected that a vertex will be arrived at + // via an edge or face in the mesh (implicit or explicit) of + // interest, so not storing this information will not hurt, + // overly. + template<unsigned ndim> + class Vertex : public tagable { + public: + typedef carve::geom::vector<ndim> vector_t; + typedef MeshSet<ndim> owner_t; + typedef carve::geom::aabb<ndim> aabb_t; + + carve::geom::vector<ndim> v; + + Vertex(const vector_t &_v) : tagable(), v(_v) { + } + + Vertex() : tagable(), v() { + } + + aabb_t getAABB() const { + return aabb_t(v, carve::geom::vector<ndim>::ZERO()); + } + }; + + + + struct hash_vertex_pair { + template<unsigned ndim> + size_t operator()(const std::pair<Vertex<ndim> *, Vertex<ndim> *> &pair) const { + size_t r = (size_t)pair.first; + size_t s = (size_t)pair.second; + return r ^ ((s >> 16) | (s << 16)); + } + template<unsigned ndim> + size_t operator()(const std::pair<const Vertex<ndim> *, const Vertex<ndim> *> &pair) const { + size_t r = (size_t)pair.first; + size_t s = (size_t)pair.second; + return r ^ ((s >> 16) | (s << 16)); + } + }; + + + + struct vertex_distance { + template<unsigned ndim> + double operator()(const Vertex<ndim> &a, const Vertex<ndim> &b) const { + return carve::geom::distance(a.v, b.v); + } + + template<unsigned ndim> + double operator()(const Vertex<ndim> *a, const Vertex<ndim> *b) const { + return carve::geom::distance(a->v, b->v); + } + }; + + + + namespace detail { + template<typename list_t> struct list_iter_t; + template<typename list_t, typename mapping_t> struct mapped_list_iter_t; + } + + + + // The half-edge structure proper (Edge) is maintained by Face + // instances. Together with Face instances, the half-edge + // structure defines a simple mesh (either one or two faces + // incident on each edge). + template<unsigned ndim> + class Edge : public tagable { + public: + typedef Vertex<ndim> vertex_t; + typedef Face<ndim> face_t; + + vertex_t *vert; + face_t *face; + Edge *prev, *next, *rev; + + private: + static void _link(Edge *a, Edge *b) { + a->next = b; b->prev = a; + } + + static void _freeloop(Edge *s) { + Edge *e = s; + do { + Edge *n = e->next; + delete e; + e = n; + } while (e != s); + } + + static void _setloopface(Edge *s, face_t *f) { + Edge *e = s; + do { + e->face = f; + e = e->next; + } while (e != s); + } + + static size_t _looplen(Edge *s) { + Edge *e = s; + face_t *f = s->face; + size_t c = 0; + do { + ++c; + CARVE_ASSERT(e->rev->rev == e); + CARVE_ASSERT(e->next->prev == e); + CARVE_ASSERT(e->face == f); + e = e->next; + } while (e != s); + return c; + } + + public: + void validateLoop() { + Edge *e = this; + face_t *f = face; + size_t c = 0; + do { + ++c; + CARVE_ASSERT(e->rev == NULL || e->rev->rev == e); + CARVE_ASSERT(e->next == e || e->next->vert != e->vert); + CARVE_ASSERT(e->prev == e || e->prev->vert != e->vert); + CARVE_ASSERT(e->next->prev == e); + CARVE_ASSERT(e->prev->next == e); + CARVE_ASSERT(e->face == f); + e = e->next; + } while (e != this); + CARVE_ASSERT(f == NULL || c == f->n_edges); + } + + size_t loopLen() { + return _looplen(this); + } + + Edge *mergeFaces(); + + Edge *removeHalfEdge(); + + // Remove and delete this edge. + Edge *removeEdge(); + + // Unlink this edge from its containing edge loop. disconnect + // rev links. The rev links of the previous edge also change, as + // its successor vertex changes. + void unlink(); + + // Insert this edge into a loop before other. If edge was + // already in a loop, it needs to be removed first. + void insertBefore(Edge *other); + + // Insert this edge into a loop after other. If edge was + // already in a loop, it needs to be removed first. + void insertAfter(Edge *other); + + size_t loopSize() const; + + vertex_t *v1() { return vert; } + vertex_t *v2() { return next->vert; } + + const vertex_t *v1() const { return vert; } + const vertex_t *v2() const { return next->vert; } + + Edge *perimNext() const; + Edge *perimPrev() const; + + double length2() const { + return (v1()->v - v2()->v).length2(); + } + + double length() const { + return (v1()->v - v2()->v).length(); + } + + Edge(vertex_t *_vert, face_t *_face); + + ~Edge(); + }; + + + + // A Face contains a pointer to the beginning of the half-edge + // circular list that defines its boundary. + template<unsigned ndim> + class Face : public tagable { + public: + typedef Vertex<ndim> vertex_t; + typedef Edge<ndim> edge_t; + typedef Mesh<ndim> mesh_t; + + typedef typename Vertex<ndim>::vector_t vector_t; + typedef carve::geom::aabb<ndim> aabb_t; + typedef carve::geom::plane<ndim> plane_t; + typedef carve::geom::vector<2> (*project_t)(const vector_t &); + typedef vector_t (*unproject_t)(const carve::geom::vector<2> &, const plane_t &); + + struct vector_mapping { + typedef typename vertex_t::vector_t value_type; + + value_type operator()(const carve::geom::vector<ndim> &v) const { return v; } + value_type operator()(const carve::geom::vector<ndim> *v) const { return *v; } + value_type operator()(const Edge<ndim> &e) const { return e.vert->v; } + value_type operator()(const Edge<ndim> *e) const { return e->vert->v; } + value_type operator()(const Vertex<ndim> &v) const { return v.v; } + value_type operator()(const Vertex<ndim> *v) const { return v->v; } + }; + + struct projection_mapping { + typedef carve::geom::vector<2> value_type; + project_t proj; + projection_mapping(project_t _proj) : proj(_proj) { } + value_type operator()(const carve::geom::vector<ndim> &v) const { return proj(v); } + value_type operator()(const carve::geom::vector<ndim> *v) const { return proj(*v); } + value_type operator()(const Edge<ndim> &e) const { return proj(e.vert->v); } + value_type operator()(const Edge<ndim> *e) const { return proj(e->vert->v); } + value_type operator()(const Vertex<ndim> &v) const { return proj(v.v); } + value_type operator()(const Vertex<ndim> *v) const { return proj(v->v); } + }; + + edge_t *edge; + size_t n_edges; + mesh_t *mesh; + size_t id; + + plane_t plane; + project_t project; + unproject_t unproject; + + private: + Face &operator=(const Face &other); + + protected: + Face() : edge(NULL), n_edges(0), mesh(NULL), id(0), plane(), project(NULL), unproject(NULL) { + } + + Face(const Face &other) : + edge(NULL), n_edges(other.n_edges), mesh(NULL), id(other.id), + plane(other.plane), project(other.project), unproject(other.unproject) { + } + + project_t getProjector(bool positive_facing, int axis) const; + unproject_t getUnprojector(bool positive_facing, int axis) const; + + public: + typedef detail::list_iter_t<Edge<ndim> > edge_iter_t; + typedef detail::list_iter_t<const Edge<ndim> > const_edge_iter_t; + + edge_iter_t begin() { return edge_iter_t(edge, 0); } + edge_iter_t end() { return edge_iter_t(edge, n_edges); } + + const_edge_iter_t begin() const { return const_edge_iter_t(edge, 0); } + const_edge_iter_t end() const { return const_edge_iter_t(edge, n_edges); } + + bool containsPoint(const vector_t &p) const; + bool containsPointInProjection(const vector_t &p) const; + bool simpleLineSegmentIntersection( + const carve::geom::linesegment<ndim> &line, + vector_t &intersection) const; + IntersectionClass lineSegmentIntersection( + const carve::geom::linesegment<ndim> &line, + vector_t &intersection) const; + + aabb_t getAABB() const; + + bool recalc(); + + void clearEdges(); + + // build an edge loop in forward orientation from an iterator pair + template<typename iter_t> + void loopFwd(iter_t vbegin, iter_t vend); + + // build an edge loop in reverse orientation from an iterator pair + template<typename iter_t> + void loopRev(iter_t vbegin, iter_t vend); + + // initialize a face from an ordered list of vertices. + template<typename iter_t> + void init(iter_t begin, iter_t end); + + // initialization of a triangular face. + void init(vertex_t *a, vertex_t *b, vertex_t *c); + + // initialization of a quad face. + void init(vertex_t *a, vertex_t *b, vertex_t *c, vertex_t *d); + + void getVertices(std::vector<vertex_t *> &verts) const; + void getProjectedVertices(std::vector<carve::geom::vector<2> > &verts) const; + + projection_mapping projector() const { + return projection_mapping(project); + } + + std::pair<double, double> rangeInDirection(const vector_t &v, const vector_t &b) const { + edge_t *e = edge; + double lo, hi; + lo = hi = carve::geom::dot(v, e->vert->v - b); + e = e->next; + for (; e != edge; e = e->next) { + double d = carve::geom::dot(v, e->vert->v - b); + lo = std::min(lo, d); + hi = std::max(hi, d); + } + return std::make_pair(lo, hi); + } + + size_t nVertices() const { + return n_edges; + } + + size_t nEdges() const { + return n_edges; + } + + vector_t centroid() const; + + static Face *closeLoop(edge_t *open_edge); + + Face(edge_t *e) : edge(e), n_edges(0), mesh(NULL) { + do { + e->face = this; + n_edges++; + e = e->next; + } while (e != edge); + recalc(); + } + + Face(vertex_t *a, vertex_t *b, vertex_t *c) : edge(NULL), n_edges(0), mesh(NULL) { + init(a, b, c); + recalc(); + } + + Face(vertex_t *a, vertex_t *b, vertex_t *c, vertex_t *d) : edge(NULL), n_edges(0), mesh(NULL) { + init(a, b, c, d); + recalc(); + } + + template<typename iter_t> + Face(iter_t begin, iter_t end) : edge(NULL), n_edges(0), mesh(NULL) { + init(begin, end); + recalc(); + } + + template<typename iter_t> + Face *create(iter_t beg, iter_t end, bool reversed) const; + + Face *clone(const vertex_t *old_base, vertex_t *new_base, std::unordered_map<const edge_t *, edge_t *> &edge_map) const; + + void remove() { + edge_t *e = edge; + do { + if (e->rev) e->rev->rev = NULL; + e = e->next; + } while (e != edge); + } + + void invert() { + // We invert the direction of the edges of the face in this + // way so that the edge rev pointers (if any) are still + // correct. It is expected that invert() will be called on + // every other face in the mesh, too, otherwise everything + // will get messed up. + + { + // advance vertices. + edge_t *e = edge; + vertex_t *va = e->vert; + do { + e->vert = e->next->vert; + e = e->next; + } while (e != edge); + edge->prev->vert = va; + } + + { + // swap prev and next pointers. + edge_t *e = edge; + do { + edge_t *n = e->next; + std::swap(e->prev, e->next); + e = n; + } while (e != edge); + } + + plane.negate(); + + int da = carve::geom::largestAxis(plane.N); + + project = getProjector(plane.N.v[da] > 0, da); + unproject = getUnprojector(plane.N.v[da] > 0, da); + } + + void canonicalize(); + + ~Face() { + clearEdges(); + } + }; + + + + namespace detail { + class FaceStitcher { + typedef Vertex<3> vertex_t; + typedef Edge<3> edge_t; + typedef Face<3> face_t; + + typedef std::pair<const vertex_t *, const vertex_t *> vpair_t; + typedef std::list<edge_t *> edgelist_t; + typedef std::unordered_map<vpair_t, edgelist_t, carve::mesh::hash_vertex_pair> edge_map_t; + typedef std::unordered_map<const vertex_t *, std::set<const vertex_t *> > edge_graph_t; + + edge_map_t edges; + edge_map_t complex_edges; + + carve::djset::djset face_groups; + std::vector<bool> is_open; + + edge_graph_t edge_graph; + + struct EdgeOrderData { + size_t group_id; + bool is_reversed; + carve::geom::vector<3> face_dir; + edge_t *edge; + + EdgeOrderData(edge_t *_edge, size_t _group_id, bool _is_reversed) : + group_id(_group_id), + is_reversed(_is_reversed) { + if (is_reversed) { + face_dir = -(_edge->face->plane.N); + } else { + face_dir = (_edge->face->plane.N); + } + edge = _edge; + } + + struct TestGroups { + size_t fwd, rev; + + TestGroups(size_t _fwd, size_t _rev) : fwd(_fwd), rev(_rev) { + } + + bool operator()(const EdgeOrderData &eo) const { + return eo.group_id == (eo.is_reversed ? rev : fwd); + } + }; + + struct Cmp { + carve::geom::vector<3> edge_dir; + carve::geom::vector<3> base_dir; + + Cmp(const carve::geom::vector<3> &_edge_dir, + const carve::geom::vector<3> &_base_dir) : + edge_dir(_edge_dir), + base_dir(_base_dir) { + } + bool operator()(const EdgeOrderData &a, const EdgeOrderData &b) const; + }; + }; + + void extractConnectedEdges(std::vector<const vertex_t *>::iterator begin, + std::vector<const vertex_t *>::iterator end, + std::vector<std::vector<Edge<3> *> > &efwd, + std::vector<std::vector<Edge<3> *> > &erev); + + size_t faceGroupID(const Face<3> *face); + size_t faceGroupID(const Edge<3> *edge); + + void resolveOpenEdges(); + + void fuseEdges(std::vector<Edge<3> *> &fwd, + std::vector<Edge<3> *> &rev); + + void joinGroups(std::vector<std::vector<Edge<3> *> > &efwd, + std::vector<std::vector<Edge<3> *> > &erev, + size_t fwd_grp, + size_t rev_grp); + + void matchOrderedEdges(const std::vector<std::vector<EdgeOrderData> >::iterator begin, + const std::vector<std::vector<EdgeOrderData> >::iterator end, + std::vector<std::vector<Edge<3> *> > &efwd, + std::vector<std::vector<Edge<3> *> > &erev); + + void reorder(std::vector<EdgeOrderData> &ordering, size_t fwd_grp); + + void orderForwardAndReverseEdges(std::vector<std::vector<Edge<3> *> > &efwd, + std::vector<std::vector<Edge<3> *> > &erev, + std::vector<std::vector<EdgeOrderData> > &result); + + void edgeIncidentGroups(const vpair_t &e, + const edge_map_t &all_edges, + std::pair<std::set<size_t>, std::set<size_t> > &groups); + + void buildEdgeGraph(const edge_map_t &all_edges); + void extractPath(std::vector<const vertex_t *> &path); + void removePath(const std::vector<const vertex_t *> &path); + void matchSimpleEdges(); + void construct(); + + template<typename iter_t> + void initEdges(iter_t begin, iter_t end); + + template<typename iter_t> + void build(iter_t begin, iter_t end, std::vector<Mesh<3> *> &meshes); + + public: + template<typename iter_t> + void create(iter_t begin, iter_t end, std::vector<Mesh<3> *> &meshes); + }; + } + + + + // A Mesh is a connected set of faces. It may be open (some edges + // have NULL rev members), or closed. On destruction, a Mesh + // should free its Faces (which will in turn free Edges, but not + // Vertices). A Mesh is edge-connected, which is to say that each + // face in the mesh shares an edge with at least one other face in + // the mesh. Touching at a vertex is not sufficient. This means + // that the perimeter of an open mesh visits each vertex no more + // than once. + template<unsigned ndim> + class Mesh { + public: + typedef Vertex<ndim> vertex_t; + typedef Edge<ndim> edge_t; + typedef Face<ndim> face_t; + typedef carve::geom::aabb<ndim> aabb_t; + typedef MeshSet<ndim> meshset_t; + + std::vector<face_t *> faces; + + // open_edges is a vector of all the edges in the mesh that + // don't have a matching edge in the opposite direction. + std::vector<edge_t *> open_edges; + + // closed_edges is a vector of all the edges in the mesh that + // have a matching edge in the opposite direction, and whose + // address is lower than their counterpart. (i.e. for each pair + // of adjoining faces, one of the two half edges is stored in + // closed_edges). + std::vector<edge_t *> closed_edges; + + bool is_negative; + + meshset_t *meshset; + + protected: + Mesh(std::vector<face_t *> &_faces, + std::vector<edge_t *> &_open_edges, + std::vector<edge_t *> &_closed_edges, + bool _is_negative); + + public: + Mesh(std::vector<face_t *> &_faces); + + ~Mesh(); + + template<typename iter_t> + static void create(iter_t begin, iter_t end, std::vector<Mesh<ndim> *> &meshes); + + aabb_t getAABB() const { + return aabb_t(faces.begin(), faces.end()); + } + + bool isClosed() const { + return open_edges.size() == 0; + } + + bool isNegative() const { + return is_negative; + } + + double volume() const { + if (is_negative || !faces.size()) return 0.0; + + double vol = 0.0; + typename vertex_t::vector_t origin = faces[0]->edge->vert->v; + + for (size_t f = 0; f < faces.size(); ++f) { + face_t *face = faces[f]; + edge_t *e1 = face->edge; + for (edge_t *e2 = e1->next ;e2->next != e1; e2 = e2->next) { + vol += carve::geom3d::tetrahedronVolume(e1->vert->v, e2->vert->v, e2->next->vert->v, origin); + } + } + return vol; + } + + struct IsClosed { + bool operator()(const Mesh &mesh) const { return mesh.isClosed(); } + bool operator()(const Mesh *mesh) const { return mesh->isClosed(); } + }; + + struct IsNegative { + bool operator()(const Mesh &mesh) const { return mesh.isNegative(); } + bool operator()(const Mesh *mesh) const { return mesh->isNegative(); } + }; + + void cacheEdges(); + + void calcOrientation(); + + void recalc() { + for (size_t i = 0; i < faces.size(); ++i) faces[i]->recalc(); + calcOrientation(); + } + + void invert() { + for (size_t i = 0; i < faces.size(); ++i) { + faces[i]->invert(); + } + if (isClosed()) is_negative = !is_negative; + } + + Mesh *clone(const vertex_t *old_base, vertex_t *new_base) const; + }; + + // A MeshSet manages vertex storage, and a collection of meshes. + // It should be easy to turn a vertex pointer into its index in + // its MeshSet vertex_storage. + template<unsigned ndim> + class MeshSet { + MeshSet(); + MeshSet(const MeshSet &); + MeshSet &operator=(const MeshSet &); + + template<typename iter_t> + void _init_from_faces(iter_t begin, iter_t end); + + public: + typedef Vertex<ndim> vertex_t; + typedef Edge<ndim> edge_t; + typedef Face<ndim> face_t; + typedef Mesh<ndim> mesh_t; + typedef carve::geom::aabb<ndim> aabb_t; + + std::vector<vertex_t> vertex_storage; + std::vector<mesh_t *> meshes; + + public: + template<typename face_type> + struct FaceIter : public std::iterator<std::random_access_iterator_tag, face_type> { + typedef std::iterator<std::random_access_iterator_tag, face_type> super; + typedef typename super::difference_type difference_type; + + const MeshSet<ndim> *obj; + size_t mesh, face; + + FaceIter(const MeshSet<ndim> *_obj, size_t _mesh, size_t _face); + + void fwd(size_t n); + void rev(size_t n); + void adv(int n); + + FaceIter operator++(int) { FaceIter tmp = *this; tmp.fwd(1); return tmp; } + FaceIter operator+(int v) { FaceIter tmp = *this; tmp.adv(v); return tmp; } + FaceIter &operator++() { fwd(1); return *this; } + FaceIter &operator+=(int v) { adv(v); return *this; } + + FaceIter operator--(int) { FaceIter tmp = *this; tmp.rev(1); return tmp; } + FaceIter operator-(int v) { FaceIter tmp = *this; tmp.adv(-v); return tmp; } + FaceIter &operator--() { rev(1); return *this; } + FaceIter &operator-=(int v) { adv(-v); return *this; } + + difference_type operator-(const FaceIter &other) const; + + bool operator==(const FaceIter &other) const { + return obj == other.obj && mesh == other.mesh && face == other.face; + } + bool operator!=(const FaceIter &other) const { + return !(*this == other); + } + bool operator<(const FaceIter &other) const { + CARVE_ASSERT(obj == other.obj); + return mesh < other.mesh || (mesh == other.mesh && face < other.face); + } + bool operator>(const FaceIter &other) const { + return other < *this; + } + bool operator<=(const FaceIter &other) const { + return !(other < *this); + } + bool operator>=(const FaceIter &other) const { + return !(*this < other); + } + + face_type operator*() const { + return obj->meshes[mesh]->faces[face]; + } + }; + + typedef FaceIter<const face_t *> const_face_iter; + typedef FaceIter<face_t *> face_iter; + + face_iter faceBegin() { return face_iter(this, 0, 0); } + face_iter faceEnd() { return face_iter(this, meshes.size(), 0); } + + const_face_iter faceBegin() const { return const_face_iter(this, 0, 0); } + const_face_iter faceEnd() const { return const_face_iter(this, meshes.size(), 0); } + + aabb_t getAABB() const { + return aabb_t(meshes.begin(), meshes.end()); + } + + template<typename func_t> + void transform(func_t func) { + for (size_t i = 0; i < vertex_storage.size(); ++i) { + vertex_storage[i].v = func(vertex_storage[i].v); + } + for (size_t i = 0; i < meshes.size(); ++i) { + meshes[i]->recalc(); + } + } + + MeshSet(const std::vector<typename vertex_t::vector_t> &points, + size_t n_faces, + const std::vector<int> &face_indices); + + // Construct a mesh set from a set of disconnected faces. Takes + // posession of the face pointers. + MeshSet(std::vector<face_t *> &faces); + + MeshSet(std::list<face_t *> &faces); + + MeshSet(std::vector<vertex_t> &_vertex_storage, + std::vector<mesh_t *> &_meshes); + + // This constructor consolidates and rewrites vertex pointers in + // each mesh, repointing them to local storage. + MeshSet(std::vector<mesh_t *> &_meshes); + + MeshSet *clone() const; + + ~MeshSet(); + + bool isClosed() const { + for (size_t i = 0; i < meshes.size(); ++i) { + if (!meshes[i]->isClosed()) return false; + } + return true; + } + + + void invert() { + for (size_t i = 0; i < meshes.size(); ++i) { + meshes[i]->invert(); + } + } + + void collectVertices(); + + void canonicalize(); + }; + + + + carve::PointClass classifyPoint( + const carve::mesh::MeshSet<3> *meshset, + const carve::geom::RTreeNode<3, carve::mesh::Face<3> *> *face_rtree, + const carve::geom::vector<3> &v, + bool even_odd = false, + const carve::mesh::Mesh<3> *mesh = NULL, + const carve::mesh::Face<3> **hit_face = NULL); + + + + } + + + + mesh::MeshSet<3> *meshFromPolyhedron(const poly::Polyhedron *, int manifold_id); + poly::Polyhedron *polyhedronFromMesh(const mesh::MeshSet<3> *, int manifold_id); + + + +}; + +#include <carve/mesh_impl.hpp> |