void makeEdgePlanes(const carve::poly::Polyhedron *poly, EPMap &edge_planes) { #if defined(UNORDERED_COLLECTIONS_SUPPORT_RESIZE) edge_planes.resize(poly->edges.size()); #endif for (size_t i = 0; i < poly->edges.size(); ++i) { EdgePlane &ep(edge_planes[&poly->edges[i]]); CARVE_ASSERT(poly->edges[i].faces.size() == 2); const carve::poly::Face *f1 = poly->edges[i].faces[0]; const carve::poly::Face *f2 = poly->edges[i].faces[1]; CARVE_ASSERT(f1 && f2); ep.base = poly->edges[i].v2->v - poly->edges[i].v1->v; ep.base.normalize(); carve::geom3d::Vector d_1 = f1->plane_eqn.N + f2->plane_eqn.N; carve::geom3d::Vector d_2 = cross(f1->plane_eqn.N, ep.base) - cross(f2->plane_eqn.N, ep.base); ep.dir = d_2.length2() > d_1.length2() ? d_2 : d_1; ep.dir.normalize(); ep.norm = cross(ep.dir, ep.base); if (true) { carve::geom3d::Vector v1 = (poly->edges[i].v1->v + poly->edges[i].v2->v) / 2.0; carve::geom3d::Vector v2 = v1 + 0.075 * ep.dir; glBegin(GL_LINES); glColor4f(1.0, 1.0, 1.0, 1.0); glVertex3f(v1.x, v1.y, v1.z); glColor4f(1.0, 1.0, 1.0, 0.4); glVertex3f(v2.x, v2.y, v2.z); glEnd(); } } }
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, double EPSILON) { 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,EPSILON)) return; if (ae_r != a_edge_map.end() && !processReverseEdgeSurfaces(a_edge_surfaces, (*ae_r).second, edge_vector, base_vector,EPSILON)) return; if (be_f != b_edge_map.end() && !processForwardEdgeSurfaces(b_edge_surfaces, (*be_f).second, edge_vector, base_vector,EPSILON)) return; if (be_r != b_edge_map.end() && !processReverseEdgeSurfaces(b_edge_surfaces, (*be_r).second, edge_vector, base_vector,EPSILON)) return; classifyAB(a_edge_surfaces, b_edge_surfaces, b_classification); classifyAB(b_edge_surfaces, a_edge_surfaces, a_classification); }
bool triangle_intersection_simple(const vec2 tri_a[3], const vec2 tri_b[3]) { // triangles must be anticlockwise, or colinear. CARVE_ASSERT(orient2d_exact(tri_a[0], tri_a[1], tri_a[2]) >= 0.0); CARVE_ASSERT(orient2d_exact(tri_b[0], tri_b[1], tri_b[2]) >= 0.0); for (size_t i = 0; i < 3; ++i) { if (sat_edge(tri_a, tri_b, i) < 0) return false; } for (size_t i = 0; i < 3; ++i) { if (sat_edge(tri_b, tri_a, i) < 0) return false; } return true; }
TriangleInt triangle_intersection(const vec2 tri_a[3], const vec2 tri_b[3]) { // triangles must be anticlockwise, or colinear. CARVE_ASSERT(carve::geom2d::orient2d(tri_a[0], tri_a[1], tri_a[2]) >= 0.0); CARVE_ASSERT(carve::geom2d::orient2d(tri_b[0], tri_b[1], tri_b[2]) >= 0.0); size_t ia, ib; int sharing = test_sharing<2>(tri_a, tri_b, ia, ib); switch (std::abs(sharing)) { case 0: { // no shared vertices. if (sat_edge(tri_a, tri_b, 0) < 0) return TR_INT_NONE; if (sat_edge(tri_a, tri_b, 1) < 0) return TR_INT_NONE; if (sat_edge(tri_a, tri_b, 2) < 0) return TR_INT_NONE; if (sat_edge(tri_b, tri_a, 0) < 0) return TR_INT_NONE; if (sat_edge(tri_b, tri_a, 1) < 0) return TR_INT_NONE; if (sat_edge(tri_b, tri_a, 2) < 0) return TR_INT_NONE; return TR_INT_INT; } case 1: { // shared vertex (ia, ib) [but not shared edge] if (sat_edge(tri_a, tri_b, (ia+2)%3, ib) < 0) return TR_INT_VERT; if (sat_edge(tri_a, tri_b, ia, ib) < 0) return TR_INT_VERT; if (sat_edge(tri_b, tri_a, (ib+2)%3, ia) < 0) return TR_INT_VERT; if (sat_edge(tri_b, tri_a, ib, ia) < 0) return TR_INT_VERT; return TR_INT_INT; } case 2: { // shared edge (ia, ib) -> (ia + 1, ib + (sharing > 0) ? +1 : -1) size_t pa = (ia + 2) % 3; size_t pb = (ib + (sharing == +1 ? 2 : 1)) % 3; double sa = orient2d_exact(tri_a[ia], tri_a[(ia+1)%3], tri_a[pa]); double sb = orient2d_exact(tri_a[ia], tri_a[(ia+1)%3], tri_b[pb]); if (sa * sb < 0.0) { return TR_INT_EDGE; } return TR_INT_INT; } case 3: { return TR_INT_TRI; } default: { CARVE_FAIL("should not happen."); } } }
virtual bool key(unsigned char k, int x, int y) { const char *t; static const char *l = "1234567890!@#$%^&*()"; if (k == '\\') { for (unsigned i = 1; i < draw_flags.size(); i += 2) { draw_flags[i] = !draw_flags[i]; } } else if (k == 'n') { bool n = true; for (unsigned i = 0; i < draw_flags.size(); ++i) if (is_wireframe[i] && draw_flags[i]) n = false; for (unsigned i = 0; i < draw_flags.size(); ++i) if (is_wireframe[i]) draw_flags[i] = n; } else if (k == 'm') { bool n = true; for (unsigned i = 0; i < draw_flags.size(); ++i) if (!is_wireframe[i] && draw_flags[i]) n = false; for (unsigned i = 0; i < draw_flags.size(); ++i) if (!is_wireframe[i]) draw_flags[i] = n; } else { t = strchr(l, k); if (t != NULL) { CARVE_ASSERT(t >= l); unsigned layer = t - l; if (layer < draw_flags.size()) { draw_flags[layer] = !draw_flags[layer]; } } } return true; }
vector<ndim>& vector<ndim>::normalize() { #if defined(CARVE_DEBUG) CARVE_ASSERT(length() > 0.0); #endif *this /= length(); return *this; }
Face<ndim> *Face<ndim>::init(const Face<ndim> *base, iter_t vbegin, iter_t vend, bool flipped) { CARVE_ASSERT(vbegin < vend); vertices.reserve((size_t)std::distance(vbegin, vend)); if (flipped) { std::reverse_copy(vbegin, vend, std::back_inserter(vertices)); plane_eqn = -base->plane_eqn; } else { std::copy(vbegin, vend, std::back_inserter(vertices)); plane_eqn = base->plane_eqn; } edges.clear(); edges.resize(nVertices(), NULL); aabb.fit(vertices.begin(), vertices.end(), vec_adapt_vertex_ptr()); untag(); int da = carve::geom::largestAxis(plane_eqn.N); project = getProjector(plane_eqn.N.v[da] > 0, da); unproject = getUnprojector(plane_eqn.N.v[da] > 0, da); return this; }
TriangleIntType triangle_intersection_exact(const vec2 tri_a[3], const vec2 tri_b[3]) { // triangles must be anticlockwise, or colinear. CARVE_ASSERT(orient2d_exact(tri_a[0], tri_a[1], tri_a[2]) >= 0.0); CARVE_ASSERT(orient2d_exact(tri_b[0], tri_b[1], tri_b[2]) >= 0.0); int curr = +1; for (size_t i = 0; curr != -1 && i < 3; ++i) { curr = std::min(curr, sat_edge(tri_a, tri_b, i)); } for (size_t i = 0; curr != -1 && i < 3; ++i) { curr = std::min(curr, sat_edge(tri_b, tri_a, i)); } switch (curr) { case -1: return TR_TYPE_NONE; case 0: return TR_TYPE_TOUCH; case +1: return TR_TYPE_INT; default: CARVE_FAIL("should not happen."); } }
TriangleIntType triangle_point_intersection_exact(const vec2 tri_a[3], const vec2 &pt_b) { CARVE_ASSERT(orient2d_exact(tri_a[0], tri_a[1], tri_a[2]) >= 0.0); int m = min3(dbl_sign(orient2d_exact(tri_a[0], tri_a[1], pt_b)), dbl_sign(orient2d_exact(tri_a[1], tri_a[2], pt_b)), dbl_sign(orient2d_exact(tri_a[2], tri_a[0], pt_b))); switch (m) { case -1: return TR_TYPE_NONE; case 0: return TR_TYPE_TOUCH; default: return TR_TYPE_INT; } }
TriangleIntType triangle_linesegment_intersection_exact(const vec2 tri_a[3], const vec2 line_b[2]) { CARVE_ASSERT(orient2d_exact(tri_a[0], tri_a[1], tri_a[2]) >= 0.0); int l1 = dbl_sign(orient2d_exact(line_b[0], line_b[1], tri_a[0])); int l2 = dbl_sign(orient2d_exact(line_b[0], line_b[1], tri_a[1])); int l3 = dbl_sign(orient2d_exact(line_b[0], line_b[1], tri_a[2])); if (min3(l1,l2,l3) == +1) return TR_TYPE_NONE; if (max3(l1,l2,l3) == -1) return TR_TYPE_NONE; int m = +1; for (size_t i = 0; m != -1 && i < 3; ++i) { int n = std::max(dbl_sign(orient2d_exact(tri_a[i], tri_a[(i+1)%3], line_b[0])), dbl_sign(orient2d_exact(tri_a[i], tri_a[(i+1)%3], line_b[1]))); m = std::min(m, n); } switch (m) { case -1: return TR_TYPE_NONE; case 0: return TR_TYPE_TOUCH; default: return TR_TYPE_INT; } }
bool pointInPolySimple(const std::vector<T> &points, adapt_t adapt, const P2 &p, double EPSILON) { CARVE_ASSERT(points.size() > 0); P2Vector::size_type l = points.size(); double s = 0.0; double rp, r0, d; rp = r0 = atan2(adapt(points[0]) - p); for (P2Vector::size_type i = 1; i < l; i++) { double r = atan2(adapt(points[i]) - p); d = r - rp; if (d > M_PI) d -= M_TWOPI; if (d < -M_PI) d += M_TWOPI; s = s + d; rp = r; } d = r0 - rp; if (d > M_PI) d -= M_TWOPI; if (d < -M_PI) d += M_TWOPI; s = s + d; return !carve::math::ZERO(s,EPSILON); }
vector<ndim> vector<ndim>::normalized() const { #if defined(CARVE_DEBUG) CARVE_ASSERT(length() > 0.0); #endif return *this / length(); }
int main(int argc, char **argv) { options.parse(argc, argv); carve::mesh::MeshSet<3> *poly; if (options.axis == Options::ERR) { std::cerr << "need to specify a closure plane." << std::endl; exit(1); } if (options.file == "-") { poly = readPLYasMesh(std::cin); } else if (endswith(options.file, ".ply")) { poly = readPLYasMesh(options.file); } else if (endswith(options.file, ".vtk")) { poly = readVTKasMesh(options.file); } else if (endswith(options.file, ".obj")) { poly = readOBJasMesh(options.file); } if (poly == NULL) { std::cerr << "failed to load polyhedron" << std::endl; exit(1); } std::cerr << "poly aabb = " << poly->getAABB() << std::endl; if (poly->getAABB().compareAxis(carve::geom::axis_pos(options.axis, options.pos)) == 0) { std::cerr << "poly aabb intersects closure plane." << std::endl; exit(1); } for (size_t i = 0; i < poly->meshes.size(); ++i) { carve::mesh::MeshSet<3>::mesh_t *mesh = poly->meshes[i]; const size_t N = mesh->open_edges.size(); if (N == 0) continue; mesh->faces.reserve(N + 1); carve::mesh::MeshSet<3>::edge_t *start = mesh->open_edges[0]; std::vector<carve::mesh::MeshSet<3>::edge_t *> edges_to_close; edges_to_close.resize(N); carve::mesh::MeshSet<3>::edge_t *edge = start; size_t j = 0; do { edges_to_close[j++] = edge; edge = edge->perimNext(); } while (edge != start); CARVE_ASSERT(j == N); std::vector<carve::mesh::MeshSet<3>::vertex_t> projected; projected.resize(N); for (j = 0; j < N; ++j) { edge = edges_to_close[j]; projected[j].v = edge->vert->v; projected[j].v.v[options.axis] = options.pos; } for (j = 0; j < N; ++j) { edge = edges_to_close[j]; carve::mesh::MeshSet<3>::face_t *quad = new carve::mesh::MeshSet<3>::face_t(edge->v2(), edge->v1(), &projected[j], &projected[(j+1)%N]); quad->mesh = mesh; edge->rev = quad->edge; quad->edge->rev = edge; mesh->faces.push_back(quad); } for (j = 0; j < N; ++j) { carve::mesh::MeshSet<3>::edge_t *e1 = edges_to_close[j]->rev->prev; carve::mesh::MeshSet<3>::edge_t *e2 = edges_to_close[(j+1)%N]->rev->next; e1->rev = e2; e2->rev = e1; } for (j = 0; j < N; ++j) { edge = edges_to_close[j]->rev; edge->validateLoop(); } carve::mesh::MeshSet<3>::face_t *loop = carve::mesh::MeshSet<3>::face_t::closeLoop(edges_to_close[0]->rev->next->next); loop->mesh = mesh; mesh->faces.push_back(loop); poly->collectVertices(); } if (options.obj) { writeOBJ(std::cout, poly); } else if (options.vtk) { writeVTK(std::cout, poly); } else { writePLY(std::cout, poly, options.ascii); } return 0; }
const Vertex *operator*() const { CARVE_ASSERT(idx >= 0 && idx < base->vertexCount()); return base->vertex((size_t)idx); }
const PolylineEdge *operator*() const { CARVE_ASSERT(idx >= 0 && idx < base->edgeCount()); return base->edge((size_t)idx); }
void carve::csg::CSG::findSharedEdges(const detail::LoopEdges &edge_map_a, const detail::LoopEdges &edge_map_b, V2Set &shared_edges) { for (detail::LoopEdges::const_iterator i = edge_map_a.begin(), e = edge_map_a.end(); i != e; ++i) { detail::LoopEdges::const_iterator j = edge_map_b.find((*i).first); if (j != edge_map_b.end()) { shared_edges.insert((*i).first); } } #if defined(CARVE_DEBUG) detail::VVSMap edge_graph; for (V2Set::const_iterator i = shared_edges.begin(); i != shared_edges.end(); ++i) { edge_graph[(*i).first].insert((*i).second); edge_graph[(*i).second].insert((*i).first); } std::cerr << "*** testing consistency of edge graph" << std::endl; for (detail::VVSMap::const_iterator i = edge_graph.begin(); i != edge_graph.end(); ++i) { if ((*i).second.size() > 2) { std::cerr << "branch at: " << (*i).first << std::endl; } if ((*i).second.size() == 1) { std::cerr << "endpoint at: " << (*i).first << std::endl; std::cerr << "coordinate: " << (*i).first->v << std::endl; } } { carve::line::PolylineSet intersection_graph; intersection_graph.vertices.resize(edge_graph.size()); std::map<const carve::mesh::MeshSet<3>::vertex_t *, size_t> vmap; size_t j = 0; for (detail::VVSMap::const_iterator i = edge_graph.begin(); i != edge_graph.end(); ++i) { intersection_graph.vertices[j].v = (*i).first->v; vmap[(*i).first] = j++; } while (edge_graph.size()) { detail::VVSMap::iterator prior_i = edge_graph.begin(); carve::mesh::MeshSet<3>::vertex_t *prior = (*prior_i).first; std::vector<size_t> connected; connected.push_back(vmap[prior]); while (prior_i != edge_graph.end() && (*prior_i).second.size()) { carve::mesh::MeshSet<3>::vertex_t *next = *(*prior_i).second.begin(); detail::VVSMap::iterator next_i = edge_graph.find(next); CARVE_ASSERT(next_i != edge_graph.end()); connected.push_back(vmap[next]); (*prior_i).second.erase(next); (*next_i).second.erase(prior); if (!(*prior_i).second.size()) { edge_graph.erase(prior_i); prior_i = edge_graph.end(); } if (!(*next_i).second.size()) { edge_graph.erase(next_i); next_i = edge_graph.end(); } prior_i = next_i; prior = next; } bool closed = connected.front() == connected.back(); for (size_t k = 0; k < connected.size(); ++k) { std::cerr << " " << connected[k]; } std::cerr << std::endl; intersection_graph.addPolyline(closed, connected.begin(), connected.end()); } #if defined(CARVE_DEBUG_WRITE_PLY_DATA) std::string out("/tmp/intersection.ply"); ::writePLY(out, &intersection_graph, true); #endif } std::cerr << "*** edge graph consistency test done" << std::endl; #endif }
int main(int argc, char **argv) { carve::mesh::MeshSet<3> *a = makeTorus(30, 30, 2.0, 0.8, carve::math::Matrix::ROT(0.5, 1.0, 1.0, 1.0)); carve::input::PolyhedronData data; for (int i = 0; i < DIM; i++) { double x = -3.0 + 6.0 * i / double(DIM - 1); for (int j = 0; j < DIM; j++) { double y = -3.0 + 6.0 * j / double(DIM - 1); double z = -1.0 + 2.0 * cos(sqrt(x * x + y * y) * 2.0) / sqrt(1.0 + x * x + y * y); size_t n = data.addVertex(carve::geom::VECTOR(x, y, z)); if (i && j) { data.addFace(n - DIM - 1, n - 1, n - DIM); data.addFace(n - 1, n, n - DIM); } } } for (int i = 0; i < DIM; i++) { double x = -3.0 + 6.0 * i / double(DIM - 1); for (int j = 0; j < DIM; j++) { double y = -3.0 + 6.0 * j / double(DIM - 1); double z = 1.0 + 2.0 * cos(sqrt(x * x + y * y) * 2.0) / sqrt(1.0 + x * x + y * y); size_t n = data.addVertex(carve::geom::VECTOR(x, y, z)); if (i && j) { data.addFace(n - DIM - 1, n - 1, n - DIM); data.addFace(n - 1, n, n - DIM); } } } carve::mesh::MeshSet<3> *b = data.createMesh(carve::input::opts()); CARVE_ASSERT(b->meshes.size() == 2); Between between_collector(a, b); carve::mesh::MeshSet<3> *c = carve::csg::CSG().compute(a, b, between_collector, NULL, carve::csg::CSG::CLASSIFY_EDGE); TestScene *scene = new TestScene(argc, argv, 3); glNewList(scene->draw_list_base + 0, GL_COMPILE); drawMeshSet(a, .4, .6, .8, 1.0); glEndList(); glNewList(scene->draw_list_base + 1, GL_COMPILE); drawMeshSet(b, .8, .6, .4, 1.0); glEndList(); glNewList(scene->draw_list_base + 2, GL_COMPILE); drawMeshSet(c, .2, .2, .8, 1.0); drawMeshSetWireframe(c, -1, false, false); glEndList(); scene->run(); delete scene; delete a; delete b; delete c; return 0; }
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 }