blender/extern/carve/lib/intersect_classify_edge.cpp
Sergey Sharybin cba3498629 Update Carve to latest upstream version
This brings new copyright header which supports GPL2 and 3.

It wasn't really an issue before because we had agreement with
Tobias, but now it's all documented in sources.
2014-06-27 15:56:50 +06:00

821 lines
33 KiB
C++

// Begin License:
// Copyright (C) 2006-2014 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 either the GNU General
// Public License version 2 or 3 (at your option) as published by the
// Free Software Foundation and appearing in the files LICENSE.GPL2
// and LICENSE.GPL3 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:
#if defined(HAVE_CONFIG_H)
# include <carve_config.h>
#endif
#if defined(HAVE_STDINT_H)
#include <stdint.h>
#endif
#include <carve/csg.hpp>
#include <carve/debug_hooks.hpp>
#include <carve/colour.hpp>
#include <list>
#include <set>
#include <iostream>
#include <algorithm>
#include "csg_detail.hpp"
#include "intersect_common.hpp"
#include "intersect_classify_common.hpp"
#define ANGLE_EPSILON 1e-6
namespace carve {
namespace csg {
namespace {
inline bool single_bit_set(uint32_t v) {
v &= v - 1;
return v == 0;
}
struct EdgeSurface {
FaceLoop *fwd;
double fwd_ang;
FaceLoop *rev;
double rev_ang;
EdgeSurface() : fwd(NULL), fwd_ang(0.0), rev(NULL), rev_ang(0.0) { }
};
typedef std::map<const carve::mesh::MeshSet<3>::mesh_t *, EdgeSurface> GrpEdgeSurfMap;
typedef std::pair<FaceLoopGroup *, const carve::mesh::MeshSet<3>::mesh_t *> ClassificationKey;
struct ClassificationData {
uint32_t class_bits : 5;
uint32_t class_decided : 1;
int c[5];
ClassificationData() {
class_bits = FACE_ANY_BIT;
class_decided = 0;
memset(c, 0, sizeof(c));
}
};
struct hash_classification {
size_t operator()(const ClassificationKey &f) const {
return (size_t)f.first ^ (size_t)f.second;
}
};
typedef std::unordered_map<ClassificationKey, ClassificationData, hash_classification> Classification;
struct hash_group_ptr {
size_t operator()(const FaceLoopGroup * const &f) const {
return (size_t)f;
}
};
typedef std::pair<size_t, const carve::mesh::MeshSet<3>::vertex_t *> PerimKey;
struct hash_perim_key {
size_t operator()(const PerimKey &v) const {
return (size_t)v.first ^ (size_t)v.second;
}
};
typedef std::unordered_map<std::pair<size_t, const carve::mesh::MeshSet<3>::vertex_t *>,
std::unordered_set<FaceLoopGroup *, hash_group_ptr>,
hash_perim_key> PerimMap;
struct hash_group_pair {
size_t operator()(const std::pair<int, const FaceLoopGroup *> &v) const {
return (size_t)v.first ^ (size_t)v.second;
}
};
typedef std::unordered_map<const FaceLoopGroup *,
std::unordered_set<std::pair<int, const FaceLoopGroup *>, hash_group_pair>,
hash_group_ptr> CandidateOnMap;
static inline void remove(carve::mesh::MeshSet<3>::vertex_t *a,
carve::mesh::MeshSet<3>::vertex_t *b,
carve::csg::detail::VVSMap &shared_edge_graph) {
carve::csg::detail::VVSMap::iterator i = shared_edge_graph.find(a);
CARVE_ASSERT(i != shared_edge_graph.end());
size_t n = (*i).second.erase(b);
CARVE_ASSERT(n == 1);
if ((*i).second.size() == 0) shared_edge_graph.erase(i);
}
static inline void remove(V2 edge,
carve::csg::detail::VVSMap &shared_edge_graph) {
remove(edge.first, edge.second, shared_edge_graph);
remove(edge.second, edge.first, shared_edge_graph);
}
static void walkGraphSegment(carve::csg::detail::VVSMap &shared_edge_graph,
const carve::csg::detail::VSet &branch_points,
V2 initial,
const carve::csg::detail::LoopEdges & /* a_edge_map */,
const carve::csg::detail::LoopEdges & /* b_edge_map */,
std::list<V2> &out) {
V2 curr;
curr = initial;
bool closed = false;
out.clear();
for (;;) {
// walk forward.
out.push_back(curr);
remove(curr, shared_edge_graph);
if (curr.second == initial.first) { closed = true; break; }
if (branch_points.find(curr.second) != branch_points.end()) break;
carve::csg::detail::VVSMap::const_iterator o = shared_edge_graph.find(curr.second);
if (o == shared_edge_graph.end()) break;
CARVE_ASSERT((*o).second.size() == 1);
curr.first = curr.second;
curr.second = *((*o).second.begin());
// test here that the set of incident groups hasn't changed.
}
if (!closed) {
// walk backward.
curr = initial;
for (;;) {
if (branch_points.find(curr.first) != branch_points.end()) break;
carve::csg::detail::VVSMap::const_iterator o = shared_edge_graph.find(curr.first);
if (o == shared_edge_graph.end()) break;
curr.second = curr.first;
curr.first = *((*o).second.begin());
// test here that the set of incident groups hasn't changed.
out.push_front(curr);
remove(curr, shared_edge_graph);
}
}
#if defined(CARVE_DEBUG)
std::cerr << "intersection segment: " << out.size() << " edges." << std::endl;
#if defined(DEBUG_DRAW_INTERSECTION_LINE)
{
static float H = 0.0, S = 1.0, V = 1.0;
float r, g, b;
H = fmod((H + .37), 1.0);
S = 0.5 + fmod((S - 0.37), 0.5);
carve::colour::HSV2RGB(H, S, V, r, g, b);
if (out.size() > 1) {
drawEdges(out.begin(), ++out.begin(),
0.0, 0.0, 0.0, 1.0,
r, g, b, 1.0,
3.0);
drawEdges(++out.begin(), --out.end(),
r, g, b, 1.0,
r, g, b, 1.0,
3.0);
drawEdges(--out.end(), out.end(),
r, g, b, 1.0,
1.0, 1.0, 1.0, 1.0,
3.0);
} else {
drawEdges(out.begin(), out.end(),
r, g, b, 1.0,
r, g, b, 1.0,
3.0);
}
}
#endif
#endif
}
static carve::geom3d::Vector perpendicular(const carve::geom3d::Vector &v) {
if (fabs(v.x) < fabs(v.y)) {
if (fabs(v.x) < fabs(v.z)) {
return cross(v, carve::geom::VECTOR(1.0, 0.0, 0.0)).normalized();
} else {
return cross(v, carve::geom::VECTOR(0.0, 0.0, 1.0)).normalized();
}
} else {
if (fabs(v.y) < fabs(v.z)) {
return cross(v, carve::geom::VECTOR(0.0, 1.0, 0.0)).normalized();
} else {
return cross(v, carve::geom::VECTOR(1.0, 0.0, 1.0)).normalized();
}
}
}
static void classifyAB(const GrpEdgeSurfMap &a_edge_surfaces,
const GrpEdgeSurfMap &b_edge_surfaces,
Classification &classifications) {
// two faces in the a surface
for (GrpEdgeSurfMap::const_iterator ib = b_edge_surfaces.begin(), eb = b_edge_surfaces.end(); ib != eb; ++ib) {
if ((*ib).second.fwd) {
FaceLoopGroup *b_grp = ((*ib).second.fwd->group);
for (GrpEdgeSurfMap::const_iterator ia = a_edge_surfaces.begin(), ea = a_edge_surfaces.end(); ia != ea; ++ia) {
if ((*ia).second.fwd && (*ia).second.rev) {
const carve::mesh::MeshSet<3>::mesh_t *a_gid = (*ia).first;
ClassificationData &data = classifications[std::make_pair(b_grp, a_gid)];
if (data.class_decided) continue;
// an angle between (*ia).fwd_ang and (*ia).rev_ang is outside/above group a.
FaceClass fc;
if (fabs((*ib).second.fwd_ang - (*ia).second.fwd_ang) < ANGLE_EPSILON) {
fc = FACE_ON_ORIENT_OUT;
} else if (fabs((*ib).second.fwd_ang - (*ia).second.rev_ang) < ANGLE_EPSILON) {
fc = FACE_ON_ORIENT_IN;
} else {
double a1 = (*ia).second.fwd_ang;
double a2 = (*ia).second.rev_ang;
if (a1 < a2) {
if (a1 < (*ib).second.fwd_ang && (*ib).second.fwd_ang < a2) {
fc = FACE_IN;
} else {
fc = FACE_OUT;
}
} else {
if (a2 < (*ib).second.fwd_ang && (*ib).second.fwd_ang < a1) {
fc = FACE_OUT;
} else {
fc = FACE_IN;
}
}
}
data.c[fc + 2]++;
}
}
}
if ((*ib).second.rev) {
FaceLoopGroup *b_grp = ((*ib).second.rev->group);
for (GrpEdgeSurfMap::const_iterator ia = a_edge_surfaces.begin(), ea = a_edge_surfaces.end(); ia != ea; ++ia) {
if ((*ia).second.fwd && (*ia).second.rev) {
const carve::mesh::MeshSet<3>::mesh_t *a_gid = (*ia).first;
ClassificationData &data = (classifications[std::make_pair(b_grp, a_gid)]);
if (data.class_decided) continue;
// an angle between (*ia).fwd_ang and (*ia).rev_ang is outside/above group a.
FaceClass fc;
if (fabs((*ib).second.rev_ang - (*ia).second.fwd_ang) < ANGLE_EPSILON) {
fc = FACE_ON_ORIENT_IN;
} else if (fabs((*ib).second.rev_ang - (*ia).second.rev_ang) < ANGLE_EPSILON) {
fc = FACE_ON_ORIENT_OUT;
} else {
double a1 = (*ia).second.fwd_ang;
double a2 = (*ia).second.rev_ang;
if (a1 < a2) {
if (a1 < (*ib).second.rev_ang && (*ib).second.rev_ang < a2) {
fc = FACE_IN;
} else {
fc = FACE_OUT;
}
} else {
if (a2 < (*ib).second.rev_ang && (*ib).second.rev_ang < a1) {
fc = FACE_OUT;
} else {
fc = FACE_IN;
}
}
}
data.c[fc + 2]++;
}
}
}
}
}
static bool processForwardEdgeSurfaces(GrpEdgeSurfMap &edge_surfaces,
const std::list<FaceLoop *> &fwd,
const carve::geom3d::Vector &edge_vector,
const carve::geom3d::Vector &base_vector) {
for (std::list<FaceLoop *>::const_iterator i = fwd.begin(), e = fwd.end(); i != e; ++i) {
EdgeSurface &es = (edge_surfaces[(*i)->orig_face->mesh]);
if (es.fwd != NULL) return false;
es.fwd = (*i);
es.fwd_ang = carve::geom3d::antiClockwiseAngle((*i)->orig_face->plane.N, base_vector, edge_vector);
}
return true;
}
static bool processReverseEdgeSurfaces(GrpEdgeSurfMap &edge_surfaces,
const std::list<FaceLoop *> &rev,
const carve::geom3d::Vector &edge_vector,
const carve::geom3d::Vector &base_vector) {
for (std::list<FaceLoop *>::const_iterator i = rev.begin(), e = rev.end(); i != e; ++i) {
EdgeSurface &es = (edge_surfaces[(*i)->orig_face->mesh]);
if (es.rev != NULL) return false;
es.rev = (*i);
es.rev_ang = carve::geom3d::antiClockwiseAngle(-(*i)->orig_face->plane.N, base_vector, edge_vector);
}
return true;
}
static void processOneEdge(const V2 &edge,
const carve::csg::detail::LoopEdges &a_edge_map,
const carve::csg::detail::LoopEdges &b_edge_map,
Classification &a_classification,
Classification &b_classification) {
GrpEdgeSurfMap a_edge_surfaces;
GrpEdgeSurfMap b_edge_surfaces;
carve::geom3d::Vector edge_vector = (edge.second->v - edge.first->v).normalized();
carve::geom3d::Vector base_vector = perpendicular(edge_vector);
carve::csg::detail::LoopEdges::const_iterator ae_f = a_edge_map.find(edge);
carve::csg::detail::LoopEdges::const_iterator ae_r = a_edge_map.find(flip(edge));
CARVE_ASSERT(ae_f != a_edge_map.end() || ae_r != a_edge_map.end());
carve::csg::detail::LoopEdges::const_iterator be_f = b_edge_map.find(edge);
carve::csg::detail::LoopEdges::const_iterator be_r = b_edge_map.find(flip(edge));
CARVE_ASSERT(be_f != b_edge_map.end() || be_r != b_edge_map.end());
if (ae_f != a_edge_map.end() && !processForwardEdgeSurfaces(a_edge_surfaces, (*ae_f).second, edge_vector, base_vector)) return;
if (ae_r != a_edge_map.end() && !processReverseEdgeSurfaces(a_edge_surfaces, (*ae_r).second, edge_vector, base_vector)) return;
if (be_f != b_edge_map.end() && !processForwardEdgeSurfaces(b_edge_surfaces, (*be_f).second, edge_vector, base_vector)) return;
if (be_r != b_edge_map.end() && !processReverseEdgeSurfaces(b_edge_surfaces, (*be_r).second, edge_vector, base_vector)) return;
classifyAB(a_edge_surfaces, b_edge_surfaces, b_classification);
classifyAB(b_edge_surfaces, a_edge_surfaces, a_classification);
}
static void traceIntersectionGraph(const V2Set &shared_edges,
const FLGroupList & /* a_loops_grouped */,
const FLGroupList & /* b_loops_grouped */,
const carve::csg::detail::LoopEdges &a_edge_map,
const carve::csg::detail::LoopEdges &b_edge_map) {
carve::csg::detail::VVSMap shared_edge_graph;
carve::csg::detail::VSet branch_points;
// first, make the intersection graph.
for (V2Set::const_iterator i = shared_edges.begin(); i != shared_edges.end(); ++i) {
const V2Set::key_type &edge = (*i);
carve::csg::detail::VVSMap::mapped_type &out = (shared_edge_graph[edge.first]);
out.insert(edge.second);
if (out.size() == 3) branch_points.insert(edge.first);
#if defined(CARVE_DEBUG) && defined(DEBUG_DRAW_INTERSECTION_LINE)
HOOK(drawEdge(edge.first, edge.second, 1, 1, 1, 1, 1, 1, 1, 1, 1.0););
#endif
}
#if defined(CARVE_DEBUG)
std::cerr << "graph nodes: " << shared_edge_graph.size() << std::endl;
std::cerr << "branch nodes: " << branch_points.size() << std::endl;
#endif
std::list<V2> out;
while (shared_edge_graph.size()) {
carve::csg::detail::VVSMap::iterator i = shared_edge_graph.begin();
carve::mesh::MeshSet<3>::vertex_t *v1 = (*i).first;
carve::mesh::MeshSet<3>::vertex_t *v2 = *((*i).second.begin());
walkGraphSegment(shared_edge_graph, branch_points, V2(v1, v2), a_edge_map, b_edge_map, out);
}
}
void hashByPerimeter(FLGroupList &grp, PerimMap &perim_map) {
for (FLGroupList::iterator i = grp.begin(); i != grp.end(); ++i) {
size_t perim_size = (*i).perimeter.size();
// can be the case for non intersecting groups. (and groups that intersect at a point?)
if (!perim_size) continue;
const carve::mesh::MeshSet<3>::vertex_t *perim_min = std::min_element((*i).perimeter.begin(), (*i).perimeter.end())->first;
perim_map[std::make_pair(perim_size, perim_min)].insert(&(*i));
}
}
bool same_edge_set_fwd(const V2Set &a, const V2Set &b) {
if (a.size() != b.size()) return false;
for (V2Set::const_iterator i = a.begin(), e = a.end(); i != e; ++i) {
if (b.find(*i) == b.end()) return false;
}
return true;
}
bool same_edge_set_rev(const V2Set &a, const V2Set &b) {
if (a.size() != b.size()) return false;
for (V2Set::const_iterator i = a.begin(), e = a.end(); i != e; ++i) {
if (b.find(std::make_pair((*i).second, (*i).first)) == b.end()) return false;
}
return true;
}
int same_edge_set(const V2Set &a, const V2Set &b) {
if (same_edge_set_fwd(a, b)) return +1;
if (same_edge_set_rev(a, b)) return -1;
return 0;
}
void generateCandidateOnSets(FLGroupList &a_grp,
FLGroupList &b_grp,
CandidateOnMap &candidate_on_map,
Classification &a_classification,
Classification &b_classification) {
PerimMap a_grp_by_perim, b_grp_by_perim;
hashByPerimeter(a_grp, a_grp_by_perim);
hashByPerimeter(b_grp, b_grp_by_perim);
for (PerimMap::iterator i = a_grp_by_perim.begin(), ie = a_grp_by_perim.end(); i != ie; ++i) {
PerimMap::iterator j = b_grp_by_perim.find((*i).first);
if (j == b_grp_by_perim.end()) continue;
for (PerimMap::mapped_type::iterator a = (*i).second.begin(), ae = (*i).second.end(); a != ae; ++a) {
for (PerimMap::mapped_type::iterator b = (*j).second.begin(), be = (*j).second.end(); b != be; ++b) {
int x = same_edge_set((*a)->perimeter, (*b)->perimeter);
if (!x) continue;
candidate_on_map[(*a)].insert(std::make_pair(x, (*b)));
if ((*a)->face_loops.count == 1 && (*b)->face_loops.count == 1) {
uint32_t fcb = x == +1 ? FACE_ON_ORIENT_OUT_BIT : FACE_ON_ORIENT_IN_BIT;
#if defined(CARVE_DEBUG)
std::cerr << "paired groups: " << (*a) << ", " << (*b) << std::endl;
#endif
ClassificationData &a_data = a_classification[std::make_pair((*a), (*b)->face_loops.head->orig_face->mesh)];
a_data.class_bits = fcb; a_data.class_decided = 1;
ClassificationData &b_data = b_classification[std::make_pair((*b), (*a)->face_loops.head->orig_face->mesh)];
b_data.class_bits = fcb; b_data.class_decided = 1;
}
}
}
}
}
}
static inline std::string CODE(const FaceLoopGroup *grp) {
const std::list<ClassificationInfo> &cinfo = (grp->classification);
if (cinfo.size() == 0) {
return "?";
}
FaceClass fc = FACE_UNCLASSIFIED;
for (std::list<ClassificationInfo>::const_iterator i = grp->classification.begin(), e = grp->classification.end(); i != e; ++i) {
if ((*i).intersected_mesh == NULL) {
// classifier only returns global info
fc = (*i).classification;
break;
}
if ((*i).intersectedMeshIsClosed()) {
if ((*i).classification == FACE_UNCLASSIFIED) continue;
if (fc == FACE_UNCLASSIFIED) {
fc = (*i).classification;
} else if (fc != (*i).classification) {
return "X";
}
}
}
if (fc == FACE_IN) return "I";
if (fc == FACE_ON_ORIENT_IN) return "<";
if (fc == FACE_ON_ORIENT_OUT) return ">";
if (fc == FACE_OUT) return "O";
return "*";
}
void CSG::classifyFaceGroupsEdge(const V2Set &shared_edges,
VertexClassification &vclass,
carve::mesh::MeshSet<3> *poly_a,
const face_rtree_t *poly_a_rtree,
FLGroupList &a_loops_grouped,
const detail::LoopEdges &a_edge_map,
carve::mesh::MeshSet<3> *poly_b,
const face_rtree_t *poly_b_rtree,
FLGroupList &b_loops_grouped,
const detail::LoopEdges &b_edge_map,
CSG::Collector &collector) {
Classification a_classification;
Classification b_classification;
CandidateOnMap candidate_on_map;
#if defined(CARVE_DEBUG)
std::cerr << "a input loops (" << a_loops_grouped.size() << "): ";
for (FLGroupList::iterator i = a_loops_grouped.begin(); i != a_loops_grouped.end(); ++i) {
std::cerr << &*i << " ";
}
std::cerr << std::endl;
std::cerr << "b input loops (" << b_loops_grouped.size() << "): ";
for (FLGroupList::iterator i = b_loops_grouped.begin(); i != b_loops_grouped.end(); ++i) {
std::cerr << &*i << " ";
}
std::cerr << std::endl;
#endif
#if defined(DISPLAY_GRP_GRAPH)
// XXX: this is hopelessly inefficient.
std::map<const FaceLoopGroup *, std::set<const FaceLoopGroup *> > grp_graph_fwd, grp_graph_rev;
{
for (FLGroupList::iterator i = a_loops_grouped.begin(); i != a_loops_grouped.end(); ++i) {
FaceLoopGroup *src = &(*i);
for (V2Set::const_iterator k = src->perimeter.begin(); k != src->perimeter.end(); ++k) {
V2 fwd = *k;
V2 rev = std::make_pair(fwd.second, fwd.first);
for (FLGroupList::iterator j = a_loops_grouped.begin(); j != a_loops_grouped.end(); ++j) {
FaceLoopGroup *tgt = &(*j);
if (tgt->perimeter.find(fwd) != tgt->perimeter.end()) { grp_graph_fwd[src].insert(tgt); }
if (tgt->perimeter.find(rev) != tgt->perimeter.end()) { grp_graph_rev[src].insert(tgt); }
}
for (FLGroupList::iterator j = b_loops_grouped.begin(); j != b_loops_grouped.end(); ++j) {
FaceLoopGroup *tgt = &(*j);
if (tgt->perimeter.find(fwd) != tgt->perimeter.end()) { grp_graph_fwd[src].insert(tgt); }
if (tgt->perimeter.find(rev) != tgt->perimeter.end()) { grp_graph_rev[src].insert(tgt); }
}
}
}
for (FLGroupList::iterator i = b_loops_grouped.begin(); i != b_loops_grouped.end(); ++i) {
FaceLoopGroup *src = &(*i);
for (V2Set::const_iterator k = src->perimeter.begin(); k != src->perimeter.end(); ++k) {
V2 fwd = *k;
V2 rev = std::make_pair(fwd.second, fwd.first);
for (FLGroupList::iterator j = a_loops_grouped.begin(); j != a_loops_grouped.end(); ++j) {
FaceLoopGroup *tgt = &(*j);
if (tgt->perimeter.find(fwd) != tgt->perimeter.end()) { grp_graph_fwd[src].insert(tgt); }
if (tgt->perimeter.find(rev) != tgt->perimeter.end()) { grp_graph_rev[src].insert(tgt); }
}
for (FLGroupList::iterator j = b_loops_grouped.begin(); j != b_loops_grouped.end(); ++j) {
FaceLoopGroup *tgt = &(*j);
if (tgt->perimeter.find(fwd) != tgt->perimeter.end()) { grp_graph_fwd[src].insert(tgt); }
if (tgt->perimeter.find(rev) != tgt->perimeter.end()) { grp_graph_rev[src].insert(tgt); }
}
}
}
}
#endif
generateCandidateOnSets(a_loops_grouped, b_loops_grouped, candidate_on_map, a_classification, b_classification);
for (V2Set::const_iterator i = shared_edges.begin(); i != shared_edges.end(); ++i) {
const V2 &edge = (*i);
processOneEdge(edge, a_edge_map, b_edge_map, a_classification, b_classification);
}
for (Classification::iterator i = a_classification.begin(), e = a_classification.end(); i != e; ++i) {
if (!(*i).second.class_decided) {
if ((*i).second.c[FACE_IN + 2] == 0) (*i).second.class_bits &= ~ FACE_IN_BIT;
if ((*i).second.c[FACE_ON_ORIENT_IN + 2] == 0) (*i).second.class_bits &= ~ FACE_ON_ORIENT_IN_BIT;
if ((*i).second.c[FACE_ON_ORIENT_OUT + 2] == 0) (*i).second.class_bits &= ~ FACE_ON_ORIENT_OUT_BIT;
if ((*i).second.c[FACE_OUT + 2] == 0) (*i).second.class_bits &= ~ FACE_OUT_BIT;
// XXX: this is the wrong thing to do. It's intended just as a test.
if ((*i).second.class_bits == (FACE_IN_BIT | FACE_OUT_BIT)) {
if ((*i).second.c[FACE_OUT + 2] > (*i).second.c[FACE_IN + 2]) {
(*i).second.class_bits = FACE_OUT_BIT;
} else {
(*i).second.class_bits = FACE_IN_BIT;
}
}
if (single_bit_set((*i).second.class_bits)) (*i).second.class_decided = 1;
}
}
for (Classification::iterator i = b_classification.begin(), e = b_classification.end(); i != e; ++i) {
if (!(*i).second.class_decided) {
if ((*i).second.c[FACE_IN + 2] == 0) (*i).second.class_bits &= ~ FACE_IN_BIT;
if ((*i).second.c[FACE_ON_ORIENT_IN + 2] == 0) (*i).second.class_bits &= ~ FACE_ON_ORIENT_IN_BIT;
if ((*i).second.c[FACE_ON_ORIENT_OUT + 2] == 0) (*i).second.class_bits &= ~ FACE_ON_ORIENT_OUT_BIT;
if ((*i).second.c[FACE_OUT + 2] == 0) (*i).second.class_bits &= ~ FACE_OUT_BIT;
// XXX: this is the wrong thing to do. It's intended just as a test.
if ((*i).second.class_bits == (FACE_IN_BIT | FACE_OUT_BIT)) {
if ((*i).second.c[FACE_OUT + 2] > (*i).second.c[FACE_IN + 2]) {
(*i).second.class_bits = FACE_OUT_BIT;
} else {
(*i).second.class_bits = FACE_IN_BIT;
}
}
if (single_bit_set((*i).second.class_bits)) (*i).second.class_decided = 1;
}
}
#if defined(CARVE_DEBUG)
std::cerr << "poly a:" << std::endl;
for (Classification::iterator i = a_classification.begin(), e = a_classification.end(); i != e; ++i) {
FaceLoopGroup *grp = ((*i).first.first);
std::cerr << " group: " << grp << " gid: " << (*i).first.second
<< " "
<< ((*i).second.class_decided ? "+" : "-")
<< " "
<< ((*i).second.class_bits & FACE_IN_BIT ? "I" : ".")
<< ((*i).second.class_bits & FACE_ON_ORIENT_IN_BIT ? "<" : ".")
<< ((*i).second.class_bits & FACE_ON_ORIENT_OUT_BIT ? ">" : ".")
<< ((*i).second.class_bits & FACE_OUT_BIT ? "O" : ".")
<< " ["
<< std::setw(4) << (*i).second.c[0] << " "
<< std::setw(4) << (*i).second.c[1] << " "
<< std::setw(4) << (*i).second.c[2] << " "
<< std::setw(4) << (*i).second.c[3] << " "
<< std::setw(4) << (*i).second.c[4] << "]" << std::endl;
}
std::cerr << "poly b:" << std::endl;
for (Classification::iterator i = b_classification.begin(), e = b_classification.end(); i != e; ++i) {
FaceLoopGroup *grp = ((*i).first.first);
std::cerr << " group: " << grp << " gid: " << (*i).first.second
<< " "
<< ((*i).second.class_decided ? "+" : "-")
<< " "
<< ((*i).second.class_bits & FACE_IN_BIT ? "I" : ".")
<< ((*i).second.class_bits & FACE_ON_ORIENT_IN_BIT ? "<" : ".")
<< ((*i).second.class_bits & FACE_ON_ORIENT_OUT_BIT ? ">" : ".")
<< ((*i).second.class_bits & FACE_OUT_BIT ? "O" : ".")
<< " ["
<< std::setw(4) << (*i).second.c[0] << " "
<< std::setw(4) << (*i).second.c[1] << " "
<< std::setw(4) << (*i).second.c[2] << " "
<< std::setw(4) << (*i).second.c[3] << " "
<< std::setw(4) << (*i).second.c[4] << "]" << std::endl;
}
#endif
for (Classification::iterator i = a_classification.begin(), e = a_classification.end(); i != e; ++i) {
FaceLoopGroup *grp = ((*i).first.first);
grp->classification.push_back(ClassificationInfo());
ClassificationInfo &info = grp->classification.back();
info.intersected_mesh = (*i).first.second;
if ((*i).second.class_decided) {
info.classification = class_bit_to_class((*i).second.class_bits);
} else {
info.classification = FACE_UNCLASSIFIED;
}
}
for (Classification::iterator i = b_classification.begin(), e = b_classification.end(); i != e; ++i) {
FaceLoopGroup *grp = ((*i).first.first);
grp->classification.push_back(ClassificationInfo());
ClassificationInfo &info = grp->classification.back();
info.intersected_mesh = (*i).first.second;
if ((*i).second.class_decided) {
info.classification = class_bit_to_class((*i).second.class_bits);
} else {
info.classification = FACE_UNCLASSIFIED;
}
}
for (FLGroupList::iterator i = a_loops_grouped.begin(); i != a_loops_grouped.end(); ++i) {
if ((*i).classification.size() == 0) {
#if defined(CARVE_DEBUG)
std::cerr << " non intersecting group (poly a): " << &(*i) << std::endl;
#endif
bool classified = false;
for (FaceLoop *fl = (*i).face_loops.head; !classified && fl != NULL; fl = fl->next) {
for (size_t fli = 0; !classified && fli < fl->vertices.size(); ++fli) {
if (vclass[fl->vertices[fli]].cls[1] == POINT_UNK) {
vclass[fl->vertices[fli]].cls[1] = carve::mesh::classifyPoint(poly_b, poly_b_rtree, fl->vertices[fli]->v);
}
switch (vclass[fl->vertices[fli]].cls[1]) {
case POINT_IN:
(*i).classification.push_back(ClassificationInfo(NULL, FACE_IN));
classified = true;
break;
case POINT_OUT:
(*i).classification.push_back(ClassificationInfo(NULL, FACE_OUT));
classified = true;
break;
default:
break;
}
}
}
if (!classified) {
throw carve::exception("non intersecting group is not IN or OUT! (poly_a)");
}
}
}
for (FLGroupList::iterator i = b_loops_grouped.begin(); i != b_loops_grouped.end(); ++i) {
if ((*i).classification.size() == 0) {
#if defined(CARVE_DEBUG)
std::cerr << " non intersecting group (poly b): " << &(*i) << std::endl;
#endif
bool classified = false;
for (FaceLoop *fl = (*i).face_loops.head; !classified && fl != NULL; fl = fl->next) {
for (size_t fli = 0; !classified && fli < fl->vertices.size(); ++fli) {
if (vclass[fl->vertices[fli]].cls[0] == POINT_UNK) {
vclass[fl->vertices[fli]].cls[0] = carve::mesh::classifyPoint(poly_a, poly_a_rtree, fl->vertices[fli]->v);
}
switch (vclass[fl->vertices[fli]].cls[0]) {
case POINT_IN:
(*i).classification.push_back(ClassificationInfo(NULL, FACE_IN));
classified = true;
break;
case POINT_OUT:
(*i).classification.push_back(ClassificationInfo(NULL, FACE_OUT));
classified = true;
break;
default:
break;
}
}
}
if (!classified) {
throw carve::exception("non intersecting group is not IN or OUT! (poly_b)");
}
}
}
#if defined(DISPLAY_GRP_GRAPH)
#define POLY(grp) (std::string((grp)->face_loops.head->orig_face->polyhedron == poly_a ? "[A:" : "[B:") + CODE(grp) + "]")
for (std::map<const FaceLoopGroup *, std::set<const FaceLoopGroup *> >::iterator i = grp_graph_fwd.begin(); i != grp_graph_fwd.end(); ++i) {
const FaceLoopGroup *grp = (*i).first;
std::cerr << "GRP: " << grp << POLY(grp) << std::endl;
std::set<const FaceLoopGroup *> &fwd_set = grp_graph_fwd[grp];
std::set<const FaceLoopGroup *> &rev_set = grp_graph_rev[grp];
std::cerr << " FWD: ";
for (std::set<const FaceLoopGroup *>::const_iterator j = fwd_set.begin(); j != fwd_set.end(); ++j) {
std::cerr << " " << (*j) << POLY(*j);
}
std::cerr << std::endl;
std::cerr << " REV: ";
for (std::set<const FaceLoopGroup *>::const_iterator j = rev_set.begin(); j != rev_set.end(); ++j) {
std::cerr << " " << (*j) << POLY(*j);
}
std::cerr << std::endl;
}
#endif
for (FLGroupList::iterator i = a_loops_grouped.begin(); i != a_loops_grouped.end(); ++i) {
collector.collect(&*i, hooks);
}
for (FLGroupList::iterator i = b_loops_grouped.begin(); i != b_loops_grouped.end(); ++i) {
collector.collect(&*i, hooks);
}
// traceIntersectionGraph(shared_edges, a_loops_grouped, b_loops_grouped, a_edge_map, b_edge_map);
}
}
}