Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'extern/carve/include/carve/mesh_ops.hpp')
-rw-r--r--extern/carve/include/carve/mesh_ops.hpp975
1 files changed, 0 insertions, 975 deletions
diff --git a/extern/carve/include/carve/mesh_ops.hpp b/extern/carve/include/carve/mesh_ops.hpp
deleted file mode 100644
index cb79682a1f7..00000000000
--- a/extern/carve/include/carve/mesh_ops.hpp
+++ /dev/null
@@ -1,975 +0,0 @@
-// 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:
-
-
-#pragma once
-
-#include <carve/carve.hpp>
-
-#include <carve/mesh.hpp>
-
-#include <iostream>
-#include <fstream>
-
-namespace carve {
- namespace mesh {
- namespace detail {
- // make a triangle out of three edges.
- template<unsigned ndim>
- void link(Edge<ndim> *e1, Edge<ndim> *e2, Edge<ndim> *e3, Face<ndim> *f = NULL) {
- e1->next = e2; e2->next = e3; e3->next = e1;
- e3->prev = e2; e2->prev = e1; e1->prev = e3;
- e1->face = e2->face = e3->face = f;
- if (f) {
- f->edge = e1;
- f->recalc();
- }
- }
-
-
-
- template<unsigned ndim, typename proj_t>
- double loopArea(carve::mesh::Edge<ndim> *edge, proj_t proj) {
- double A = 0.0;
- carve::mesh::Edge<3> *e = edge;
- do {
- carve::geom2d::P2 p1 = proj(e->vert->v);
- carve::geom2d::P2 p2 = proj(e->next->vert->v);
- A += (p2.y + p1.y) * (p2.x - p1.x);
- e = e->next;
- } while (e != edge);
- return A / 2.0;
- }
-
-
-
- template<unsigned ndim, typename proj_t>
- struct TriangulationData {
- typedef Edge<ndim> edge_t;
-
- struct VertexInfo {
- double score;
- carve::geom2d::P2 p;
- bool convex;
- bool failed;
- VertexInfo *next, *prev;
- edge_t *edge;
-
- VertexInfo(edge_t *_edge,
- const carve::geom2d::P2 &_p) :
- score(0.0), p(_p), convex(false), failed(false), next(NULL), prev(NULL), edge(_edge) {
- }
-
- bool isCandidate() const {
- return convex && !failed;
- }
-
- void fail() {
- failed = true;
- }
-
- static bool isLeft(const VertexInfo *a, const VertexInfo *b, const geom2d::P2 &p) {
- if (a < b) {
- return carve::geom2d::orient2d(a->p, b->p, p) > 0.0;
- } else {
- return carve::geom2d::orient2d(b->p, a->p, p) < 0.0;
- }
- }
-
- // is the ear prev->edge->next convex?
- bool testForConvexVertex() const {
- return isLeft(next, prev, p);
- }
-
- static double triScore(const geom2d::P2 &a, const geom2d::P2 &b, const geom2d::P2 &c) {
- // score is in the range: [0, 1]
- // equilateral triangles score 1
- // sliver triangles score 0
- double dab = (a - b).length();
- double dbc = (b - c).length();
- double dca = (c - a).length();
-
- if (dab < 1e-10 || dbc < 1e-10 || dca < 1e-10) return 0.0;
-
- return std::max(std::min((dab + dbc) / dca, std::min((dab + dca) / dbc, (dbc + dca) / dab)) - 1.0, 0.0);
- }
-
- // calculate a score for the ear edge.
- double calcScore() const {
- double this_tri = triScore(prev->p, p, next->p);
- double next_tri = triScore(prev->p, next->p, next->next->p);
- double prev_tri = triScore(prev->prev->p, prev->p, next->p);
-
- return this_tri + std::max(next_tri, prev_tri) * .2;
- }
-
- void recompute() {
- convex = testForConvexVertex();
- failed = false;
- if (convex) {
- score = calcScore();
- } else {
- score = -1e-5;
- }
- }
-
- static bool inTriangle(const VertexInfo *a,
- const VertexInfo *b,
- const VertexInfo *c,
- const geom2d::P2 &e) {
- return !isLeft(b, a, e) && !isLeft(c, b, e) && !isLeft(a, c, e);
- }
-
-
- bool isClipable() const {
- for (const VertexInfo *v_test = next->next; v_test != prev; v_test = v_test->next) {
- if (v_test->convex) {
- continue;
- }
-
- if (v_test->p == prev->p || v_test->p == next->p) {
- continue;
- }
-
- if (v_test->p == p) {
- if (v_test->next->p == prev->p && v_test->prev->p == next->p) {
- return false;
- }
-
- if (v_test->next->p == prev->p || v_test->prev->p == next->p) {
- continue;
- }
- }
-
- if (inTriangle(prev, this, next, v_test->p)) {
- return false;
- }
- }
- return true;
- }
- };
-
- struct order_by_score {
- bool operator()(const VertexInfo *a, const VertexInfo *b) const {
- return a->score < b->score;
- }
- };
-
- typedef std::pair<VertexInfo *, VertexInfo *> diag_t;
-
- proj_t proj;
-
- geom2d::P2 P(const VertexInfo *vi) const {
- return vi->p;
- }
-
- geom2d::P2 P(const edge_t *edge) const {
- return proj(edge->vert->v);
- }
-
- bool isLeft(const edge_t *a, const edge_t *b, const geom2d::P2 &p) const {
- if (a < b) {
- return carve::geom2d::orient2d(P(a), P(b), p) > 0.0;
- } else {
- return carve::geom2d::orient2d(P(b), P(a), p) < 0.0;
- }
- }
-
- bool testForConvexVertex(const edge_t *vert) const {
- return isLeft(vert->next, vert->prev, P(vert));
- }
-
- bool inCone(const VertexInfo *vert, const geom2d::P2 &p) const {
- return geom2d::internalToAngle(P(vert->next), P(vert), P(vert->prev), p);
- }
-
- int windingNumber(VertexInfo *vert, const carve::geom2d::P2 &point) const {
- int wn = 0;
-
- VertexInfo *v = vert;
- geom2d::P2 v_p = P(vert);
- do {
- geom2d::P2 n_p = P(v->next);
-
- if (v_p.y <= point.y) {
- if (n_p.y > point.y && carve::geom2d::orient2d(v_p, n_p, point) > 0.0) {
- ++wn;
- }
- } else {
- if (n_p.y <= point.y && carve::geom2d::orient2d(v_p, n_p, point) < 0.0) {
- --wn;
- }
- }
- v = v->next;
- v_p = n_p;
- } while (v != vert);
-
- return wn;
- }
-
- bool diagonalIsCandidate(diag_t diag) const {
- VertexInfo *v1 = diag.first;
- VertexInfo *v2 = diag.second;
- return (inCone(v1, P(v2)) && inCone(v2, P(v1)));
- }
-
- bool testDiagonal(diag_t diag) const {
- // test whether v1-v2 is a valid diagonal.
- VertexInfo *v1 = diag.first;
- VertexInfo *v2 = diag.second;
- geom2d::P2 v1p = P(v1);
- geom2d::P2 v2p = P(v2);
-
- bool intersected = false;
-
- for (VertexInfo *t = v1->next; !intersected && t != v1->prev; t = t->next) {
- VertexInfo *u = t->next;
- if (t == v2 || u == v2) continue;
-
- geom2d::P2 tp = P(t);
- geom2d::P2 up = P(u);
-
- double l_a1 = carve::geom2d::orient2d(v1p, v2p, tp);
- double l_a2 = carve::geom2d::orient2d(v1p, v2p, up);
-
- double l_b1 = carve::geom2d::orient2d(tp, up, v1p);
- double l_b2 = carve::geom2d::orient2d(tp, up, v2p);
-
- if (l_a1 > l_a2) std::swap(l_a1, l_a2);
- if (l_b1 > l_b2) std::swap(l_b1, l_b2);
-
- if (l_a1 == 0.0 && l_a2 == 0.0 &&
- l_b1 == 0.0 && l_b2 == 0.0) {
- // colinear
- if (std::max(tp.x, up.x) >= std::min(v1p.x, v2p.x) && std::min(tp.x, up.x) <= std::max(v1p.x, v2p.x)) {
- // colinear and intersecting
- intersected = true;
- }
- continue;
- }
-
- if (l_a2 <= 0.0 || l_a1 >= 0.0 || l_b2 <= 0.0 || l_b1 >= 0.0) {
- // no intersection
- continue;
- }
-
- intersected = true;
- }
-
- if (!intersected) {
- // test whether midpoint winding == 1
-
- carve::geom2d::P2 mid = (v1p + v2p) / 2;
- if (windingNumber(v1, mid) == 1) {
- // this diagonal is ok
- return true;
- }
- }
- return false;
- }
-
- // Find the vertex half way around the loop (rounds upwards).
- VertexInfo *findMidpoint(VertexInfo *vert) const {
- VertexInfo *v = vert;
- VertexInfo *r = vert;
- while (1) {
- r = r->next;
- v = v->next; if (v == vert) return r;
- v = v->next; if (v == vert) return r;
- }
- }
-
- // Test all diagonals with a separation of a-b by walking both
- // pointers around the loop. In the case where a-b divides the
- // loop exactly in half, this will test each diagonal twice,
- // but avoiding this case is not worth the extra effort
- // required.
- diag_t scanDiagonals(VertexInfo *a, VertexInfo *b) const {
- VertexInfo *v1 = a;
- VertexInfo *v2 = b;
-
- do {
- diag_t d(v1, v2);
- if (diagonalIsCandidate(d) && testDiagonal(d)) {
- return d;
- }
- v1 = v1->next;
- v2 = v2->next;
- } while (v1 != a);
-
- return diag_t(NULL, NULL);
- }
-
- diag_t scanAllDiagonals(VertexInfo *a) const {
- // Rationale: We want to find a diagonal that splits the
- // loop into two as evenly as possible, to reduce the number
- // of times that diagonal splitting is required. Start by
- // scanning all diagonals separated by loop_len / 2, then
- // decrease the separation until we find something.
-
- // loops of length 2 or 3 have no possible diagonal.
- if (a->next == a || a->next->next == a) return diag_t(NULL, NULL);
-
- VertexInfo *b = findMidpoint(a);
- while (b != a->next) {
- diag_t d = scanDiagonals(a, b);
- if (d != diag_t(NULL, NULL)) return d;
- b = b->prev;
- }
-
- return diag_t(NULL, NULL);
- }
-
- diag_t findDiagonal(VertexInfo *vert) const {
- return scanAllDiagonals(vert);
- }
-
- diag_t findHighScoringDiagonal(VertexInfo *vert) const {
- typedef std::pair<double, diag_t> heap_entry_t;
- VertexInfo *v1, *v2;
- std::vector<heap_entry_t> heap;
- size_t loop_len = 0;
-
- v1 = vert;
- do {
- ++loop_len;
- v1 = v1->next;
- } while (v1 != vert);
-
- v1 = vert;
- do {
- v2 = v1->next->next;
- size_t dist = 2;
- do {
- if (diagonalIsCandidate(diag_t(v1, v2))) {
- double score = std::min(dist, loop_len - dist);
- // double score = (v1->edge->vert->v - v2->edge->vert->v).length2();
- heap.push_back(heap_entry_t(score, diag_t(v1, v2)));
- }
- v2 = v2->next;
- ++dist;
- } while (v2 != vert && v2 != v1->prev);
- v1 = v1->next;
- } while (v1->next->next != vert);
-
- std::make_heap(heap.begin(), heap.end());
-
- while (heap.size()) {
- std::pop_heap(heap.begin(), heap.end());
- heap_entry_t h = heap.back();
- heap.pop_back();
-
- if (testDiagonal(h.second)) return h.second;
- }
-
- // couldn't find a diagonal that was ok.
- return diag_t(NULL, NULL);
- }
-
- void splitEdgeLoop(VertexInfo *v1, VertexInfo *v2) {
- VertexInfo *v1_copy = new VertexInfo(new Edge<ndim>(v1->edge->vert, NULL), v1->p);
- VertexInfo *v2_copy = new VertexInfo(new Edge<ndim>(v2->edge->vert, NULL), v2->p);
-
- v1_copy->edge->rev = v2_copy->edge;
- v2_copy->edge->rev = v1_copy->edge;
-
- v1_copy->edge->prev = v1->edge->prev;
- v1_copy->edge->next = v2->edge;
-
- v2_copy->edge->prev = v2->edge->prev;
- v2_copy->edge->next = v1->edge;
-
- v1->edge->prev->next = v1_copy->edge;
- v1->edge->prev = v2_copy->edge;
-
- v2->edge->prev->next = v2_copy->edge;
- v2->edge->prev = v1_copy->edge;
-
- v1_copy->prev = v1->prev;
- v1_copy->next = v2;
-
- v2_copy->prev = v2->prev;
- v2_copy->next = v1;
-
- v1->prev->next = v1_copy;
- v1->prev = v2_copy;
-
- v2->prev->next = v2_copy;
- v2->prev = v1_copy;
- }
-
- VertexInfo *findDegenerateEar(VertexInfo *edge) {
- VertexInfo *v = edge;
-
- if (v->next == v || v->next->next == v) return NULL;
-
- do {
- if (P(v) == P(v->next)) {
- return v;
- } else if (P(v) == P(v->next->next)) {
- if (P(v->next) == P(v->next->next->next)) {
- // a 'z' in the loop: z (a) b a b c -> remove a-b-a -> z (a) a b c -> remove a-a-b (next loop) -> z a b c
- // z --(a)-- b
- // /
- // /
- // a -- b -- d
- return v->next;
- } else {
- // a 'shard' in the loop: z (a) b a c d -> remove a-b-a -> z (a) a b c d -> remove a-a-b (next loop) -> z a b c d
- // z --(a)-- b
- // /
- // /
- // a -- c -- d
- // n.b. can only do this if the shard is pointing out of the polygon. i.e. b is outside z-a-c
- if (!carve::geom2d::internalToAngle(P(v->next->next->next), P(v), P(v->prev), P(v->next))) {
- return v->next;
- }
- }
- }
- v = v->next;
- } while (v != edge);
-
- return NULL;
- }
-
- // Clip off a vertex at vert, producing a triangle (with appropriate rev pointers)
- template<typename out_iter_t>
- VertexInfo *clipEar(VertexInfo *vert, out_iter_t out) {
- CARVE_ASSERT(testForConvexVertex(vert->edge));
-
- edge_t *p_edge = vert->edge->prev;
- edge_t *n_edge = vert->edge->next;
-
- edge_t *p_copy = new edge_t(p_edge->vert, NULL);
- edge_t *n_copy = new edge_t(n_edge->vert, NULL);
-
- n_copy->next = p_copy;
- n_copy->prev = vert->edge;
-
- p_copy->next = vert->edge;
- p_copy->prev = n_copy;
-
- vert->edge->next = n_copy;
- vert->edge->prev = p_copy;
-
- p_edge->next = n_edge;
- n_edge->prev = p_edge;
-
- if (p_edge->rev) {
- p_edge->rev->rev = p_copy;
- }
- p_copy->rev = p_edge->rev;
-
- p_edge->rev = n_copy;
- n_copy->rev = p_edge;
-
- *out++ = vert->edge;
-
- if (vert->edge->face) {
- if (vert->edge->face->edge == vert->edge) {
- vert->edge->face->edge = n_edge;
- }
- vert->edge->face->n_edges--;
- vert->edge->face = NULL;
- }
-
- vert->next->prev = vert->prev;
- vert->prev->next = vert->next;
-
- VertexInfo *n = vert->next;
- delete vert;
- return n;
- }
-
- template<typename out_iter_t>
- size_t removeDegeneracies(VertexInfo *&begin, out_iter_t out) {
- VertexInfo *v;
- size_t count = 0;
-
- while ((v = findDegenerateEar(begin)) != NULL) {
- begin = clipEar(v, out);
- ++count;
- }
- return count;
- }
-
- template<typename out_iter_t>
- bool splitAndResume(VertexInfo *begin, out_iter_t out) {
- diag_t diag;
-
- diag = findDiagonal(begin);
- if (diag == diag_t(NULL, NULL)) {
- std::cerr << "failed to find diagonal" << std::endl;
- return false;
- }
-
- // add a splitting edge between v1 and v2.
- VertexInfo *v1 = diag.first;
- VertexInfo *v2 = diag.second;
-
- splitEdgeLoop(v1, v2);
-
- v1->recompute();
- v1->next->recompute();
-
- v2->recompute();
- v2->next->recompute();
-
-#if defined(CARVE_DEBUG)
- dumpPoly(v1->edge, v2->edge);
-#endif
-
-#if defined(CARVE_DEBUG)
- CARVE_ASSERT(!checkSelfIntersection(v1));
- CARVE_ASSERT(!checkSelfIntersection(v2));
-#endif
-
- bool r1 = doTriangulate(v1, out);
- bool r2 = doTriangulate(v2, out);
-
- return r1 && r2;
- }
-
- template<typename out_iter_t>
- bool doTriangulate(VertexInfo *begin, out_iter_t out);
-
- TriangulationData(proj_t _proj) : proj(_proj) {
- }
-
- VertexInfo *init(edge_t *begin) {
- edge_t *e = begin;
- VertexInfo *head = NULL, *tail = NULL, *v;
- do {
- VertexInfo *v = new VertexInfo(e, proj(e->vert->v));
- if (tail != NULL) {
- tail->next = v;
- v->prev = tail;
- } else {
- head = v;
- }
- tail = v;
-
- e = e->next;
- } while (e != begin);
- tail->next = head;
- head->prev = tail;
-
- v = head;
- do {
- v->recompute();
- v = v->next;
- } while (v != head);
- return head;
- }
-
- class EarQueue {
- TriangulationData &data;
- std::vector<VertexInfo *> queue;
-
- void checkheap() {
-#if defined(HAVE_IS_HEAP)
- CARVE_ASSERT(std::__is_heap(queue.begin(), queue.end(), order_by_score()));
-#endif
- }
-
- public:
- EarQueue(TriangulationData &_data) : data(_data), queue() {
- }
-
- size_t size() const {
- return queue.size();
- }
-
- void push(VertexInfo *v) {
-#if defined(CARVE_DEBUG)
- checkheap();
-#endif
- queue.push_back(v);
- std::push_heap(queue.begin(), queue.end(), order_by_score());
- }
-
- VertexInfo *pop() {
-#if defined(CARVE_DEBUG)
- checkheap();
-#endif
- std::pop_heap(queue.begin(), queue.end(), order_by_score());
- VertexInfo *v = queue.back();
- queue.pop_back();
- return v;
- }
-
- void remove(VertexInfo *v) {
-#if defined(CARVE_DEBUG)
- checkheap();
-#endif
- CARVE_ASSERT(std::find(queue.begin(), queue.end(), v) != queue.end());
- double score = v->score;
- if (v != queue[0]) {
- v->score = queue[0]->score + 1;
- std::make_heap(queue.begin(), queue.end(), order_by_score());
- }
- CARVE_ASSERT(v == queue[0]);
- std::pop_heap(queue.begin(), queue.end(), order_by_score());
- CARVE_ASSERT(queue.back() == v);
- queue.pop_back();
- v->score = score;
- }
-
- void changeScore(VertexInfo *v, double s_from, double s_to) {
-#if defined(CARVE_DEBUG)
- checkheap();
-#endif
- CARVE_ASSERT(std::find(queue.begin(), queue.end(), v) != queue.end());
- if (s_from != s_to) {
- v->score = s_to;
- std::make_heap(queue.begin(), queue.end(), order_by_score());
- }
- }
-
- void update(VertexInfo *v) {
- VertexInfo pre = *v;
- v->recompute();
- VertexInfo post = *v;
-
- if (pre.isCandidate()) {
- if (post.isCandidate()) {
- changeScore(v, pre.score, post.score);
- } else {
- remove(v);
- }
- } else {
- if (post.isCandidate()) {
- push(v);
- }
- }
- }
- };
-
-
- bool checkSelfIntersection(const VertexInfo *vert) {
- const VertexInfo *v1 = vert;
- do {
- const VertexInfo *v2 = vert->next->next;
- do {
- carve::geom2d::P2 a = v1->p;
- carve::geom2d::P2 b = v1->next->p;
- CARVE_ASSERT(a == proj(v1->edge->vert->v));
- CARVE_ASSERT(b == proj(v1->edge->next->vert->v));
-
- carve::geom2d::P2 c = v2->p;
- carve::geom2d::P2 d = v2->next->p;
- CARVE_ASSERT(c == proj(v2->edge->vert->v));
- CARVE_ASSERT(d == proj(v2->edge->next->vert->v));
-
- bool intersected = false;
- if (a == c || a == d || b == c || b == d) {
- } else {
- intersected = true;
-
- double l_a1 = carve::geom2d::orient2d(a, b, c);
- double l_a2 = carve::geom2d::orient2d(a, b, d);
- if (l_a1 > l_a2) std::swap(l_a1, l_a2);
- if (l_a2 <= 0.0 || l_a1 >= 0.0) {
- intersected = false;
- }
-
- double l_b1 = carve::geom2d::orient2d(c, d, a);
- double l_b2 = carve::geom2d::orient2d(c, d, b);
- if (l_b1 > l_b2) std::swap(l_b1, l_b2);
- if (l_b2 <= 0.0 || l_b1 >= 0.0) {
- intersected = false;
- }
-
- if (l_a1 == 0.0 && l_a2 == 0.0 && l_b1 == 0.0 && l_b2 == 0.0) {
- if (std::max(a.x, b.x) >= std::min(c.x, d.x) && std::min(a.x, b.x) <= std::max(c.x, d.x)) {
- // colinear and intersecting.
- } else {
- // colinear but not intersecting.
- intersected = false;
- }
- }
- }
- if (intersected) {
- carve::geom2d::P2 p[4] = { a, b, c, d };
- carve::geom::aabb<2> A(p, p+4);
- A.expand(5);
-
- std::cerr << "\
-<?xml version=\"1.0\" encoding=\"utf-8\"?>\n\
-<!DOCTYPE svg PUBLIC \"-//W3C//DTD SVG 1.1//EN\" \"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd\">\n\
-<svg version=\"1.1\" xmlns=\"http://www.w3.org/2000/svg\" xmlns:xlink=\"http://www.w3.org/1999/xlink\"\n\
- x=\"" << A.min().x << "px\" y=\"" << A.min().y << "\"\n\
- width=\"" << A.extent.x * 2 << "\" height=\"" << A.extent.y * 2 << "\"\n\
- viewBox=\"" << A.min().x << " " << A.min().y << " " << A.max().x << " " << A.max().y << "\"\n\
- enable-background=\"new " << A.min().x << " " << A.min().y << " " << A.max().x << " " << A.max().y << "\"\n\
- xml:space=\"preserve\">\n\
-<line fill=\"none\" stroke=\"#000000\" x1=\"" << a.x << "\" y1=\"" << a.y << "\" x2=\"" << b.x << "\" y2=\"" << b.y << "\"/>\n\
-<line fill=\"none\" stroke=\"#000000\" x1=\"" << c.x << "\" y1=\"" << c.y << "\" x2=\"" << d.x << "\" y2=\"" << d.y << "\"/>\n\
-</svg>\n";
- return true;
- }
- v2 = v2->next;
- } while (v2 != vert);
- v1 = v1->next;
- } while (v1 != vert);
- return false;
- }
-
- carve::geom::aabb<2> make2d(const edge_t *edge, std::vector<geom2d::P2> &points) {
- const edge_t *e = edge;
- do {
- points.push_back(P(e));
- e = e->next;
- } while(e != edge);
- return carve::geom::aabb<2>(points.begin(), points.end());
- }
-
- void dumpLoop(std::ostream &out,
- const std::vector<carve::geom2d::P2> &points,
- const char *fill,
- const char *stroke,
- double stroke_width,
- double offx,
- double offy,
- double scale
- ) {
- out << "<polygon fill=\"" << fill << "\" stroke=\"" << stroke << "\" stroke-width=\"" << stroke_width << "\" points=\"";
- for (size_t i = 0; i < points.size(); ++i) {
- if (i) out << ' ';
- double x, y;
- x = scale * (points[i].x - offx) + 5;
- y = scale * (points[i].y - offy) + 5;
- out << x << ',' << y;
- }
- out << "\" />" << std::endl;
- }
-
- void dumpPoly(const edge_t *edge, const edge_t *edge2 = NULL, const char *pfx = "poly_") {
- static int step = 0;
- std::ostringstream filename;
- filename << pfx << step++ << ".svg";
- std::cerr << "dumping to " << filename.str() << std::endl;
- std::ofstream out(filename.str().c_str());
-
- std::vector <geom2d::P2> points, points2;
-
- carve::geom::aabb<2> A = make2d(edge, points);
- if (edge2) {
- A.unionAABB(make2d(edge2, points2));
- }
- A.expand(5);
-
- out << "\
-<?xml version=\"1.0\"?>\n\
-<!DOCTYPE svg PUBLIC \"-//W3C//DTD SVG 1.1//EN\" \"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd\">\n\
-<svg\n\
- x=\"" << A.min().x << "px\" y=\"" << A.min().y << "\"\n\
- width=\"" << A.extent.x * 2 << "\" height=\"" << A.extent.y * 2 << "\"\n\
- viewBox=\"" << A.min().x << " " << A.min().y << " " << A.max().x << " " << A.max().y << "\"\n\
- enable-background=\"new " << A.min().x << " " << A.min().y << " " << A.max().x << " " << A.max().y << "\"\n\
- xml:space=\"preserve\">\n";
-
- dumpLoop(out, points, "rgb(0,0,0)", "blue", 0.1, 0, 0, 1);
- if (points2.size()) dumpLoop(out, points2, "rgb(255,0,0)", "blue", 0.1, 0, 0, 1);
-
- out << "</svg>" << std::endl;
- }
- };
-
- template<unsigned ndim, typename proj_t>
- template<typename out_iter_t>
- bool TriangulationData<ndim, proj_t>::doTriangulate(VertexInfo *begin, out_iter_t out) {
- EarQueue vq(*this);
-
-#if defined(CARVE_DEBUG)
- dumpPoly(begin->edge, NULL, "input_");
- CARVE_ASSERT(!checkSelfIntersection(begin));
-#endif
-
- VertexInfo *v = begin, *n, *p;
- size_t remain = 0;
- do {
- if (v->isCandidate()) vq.push(v);
- v = v->next;
- remain++;
- } while (v != begin);
-
- while (remain > 3 && vq.size()) {
- { static int __c = 0; if (++__c % 50 == 0) { break; } }
- v = vq.pop();
- if (!v->isClipable()) {
- v->fail();
- continue;
- }
-
- continue_clipping:
- n = clipEar(v, out);
- p = n->prev;
- begin = n;
- if (--remain == 3) break;
- // if (checkSelfIntersection(begin)) {
- // dumpPoly(begin->edge, NULL, "badclip_");
- // CARVE_ASSERT(!!!"clip created self intersection");
- // }
-
- vq.update(n);
- vq.update(p);
-
- if (n->score < p->score) { std::swap(n, p); }
- if (n->score > 0.25 && n->isCandidate() && n->isClipable()) {
- vq.remove(n);
- v = n;
- goto continue_clipping;
- }
- if (p->score > 0.25 && p->isCandidate() && p->isClipable()) {
- vq.remove(p);
- v = p;
- goto continue_clipping;
- }
- }
-
- bool ret = false;
-
-#if defined(CARVE_DEBUG)
- dumpPoly(begin->edge, NULL, "remainder_");
-#endif
-
- if (remain > 3) {
- std::vector<carve::geom2d::P2> temp;
- temp.reserve(remain);
- VertexInfo *v = begin;
- do {
- temp.push_back(P(v));
- v = v->next;
- } while (v != begin);
-
- if (carve::geom2d::signedArea(temp) == 0) {
- // XXX: this test will fail in cases where the boundary is
- // twisted so that a negative area balances a positive area.
- std::cerr << "got to here" << std::endl;
- dumpPoly(begin->edge, NULL, "interesting_case_");
- goto done;
- }
- }
-
- if (remain > 3) {
- remain -= removeDegeneracies(begin, out);
- }
-
- if (remain > 3) {
- return splitAndResume(begin, out);
- }
-
- { double a = loopArea(begin->edge, proj); CARVE_ASSERT(a <= 0.0); }
- *out++ = begin->edge;
-
- v = begin;
- do {
- n = v->next;
- delete v;
- v = n;
- } while (v != begin);
-
- ret = true;
-
- done:
- return ret;
- }
- }
-
-
-
- template<unsigned ndim, typename proj_t, typename out_iter_t>
- void triangulate(Edge<ndim> *edge, proj_t proj, out_iter_t out) {
- detail::TriangulationData<ndim, proj_t> triangulator(proj);
- typename detail::TriangulationData<ndim, proj_t>::VertexInfo *v = triangulator.init(edge);
- triangulator.removeDegeneracies(v, out);
- triangulator.doTriangulate(v, out);
- }
-
- // given edge a-b, part of triangles a-b-c and b-a-d, make triangles c-a-d and b-c-d
- template<unsigned ndim>
- void flipTriEdge(Edge<ndim> *edge) {
- CARVE_ASSERT(edge->rev != NULL);
- CARVE_ASSERT(edge->face->nEdges() == 3);
- CARVE_ASSERT(edge->rev->face->nEdges() == 3);
-
- CARVE_ASSERT(edge->prev != edge);
- CARVE_ASSERT(edge->next != edge);
- CARVE_ASSERT(edge->rev->prev != edge->rev);
- CARVE_ASSERT(edge->rev->next != edge->rev);
-
- typedef Edge<ndim> edge_t;
- typedef Face<ndim> face_t;
-
- edge_t *t1[3], *t2[3];
- face_t *f1, *f2;
-
- t1[1] = edge; t2[1] = edge->rev;
- t1[0] = t1[1]->prev; t1[2] = t1[1]->next;
- t2[0] = t2[1]->prev; t2[2] = t2[1]->next;
-
- f1 = t1[1]->face; f2 = t2[1]->face;
-
- // std::cerr << t1[0]->vert << "->" << t1[1]->vert << "->" << t1[2]->vert << std::endl;
- // std::cerr << t2[0]->vert << "->" << t2[1]->vert << "->" << t2[2]->vert << std::endl;
-
- t1[1]->vert = t2[0]->vert;
- t2[1]->vert = t1[0]->vert;
-
- // std::cerr << t1[0]->vert << "->" << t2[2]->vert << "->" << t1[1]->vert << std::endl;
- // std::cerr << t2[0]->vert << "->" << t1[2]->vert << "->" << t2[1]->vert << std::endl;
-
- detail::link(t1[0], t2[2], t1[1], f1);
- detail::link(t2[0], t1[2], t2[1], f2);
-
- if (t1[0]->rev) CARVE_ASSERT(t1[0]->v2() == t1[0]->rev->v1());
- if (t2[0]->rev) CARVE_ASSERT(t2[0]->v2() == t2[0]->rev->v1());
- if (t1[2]->rev) CARVE_ASSERT(t1[2]->v2() == t1[2]->rev->v1());
- if (t2[2]->rev) CARVE_ASSERT(t2[2]->v2() == t2[2]->rev->v1());
- }
-
- template<unsigned ndim>
- void splitEdgeLoop(Edge<ndim> *v1, Edge<ndim> *v2) {
- // v1 and v2 end up on different sides of the split.
- Edge<ndim> *v1_copy = new Edge<ndim>(v1->vert, NULL);
- Edge<ndim> *v2_copy = new Edge<ndim>(v2->vert, NULL);
-
- v1_copy->rev = v2_copy;
- v2_copy->rev = v1_copy;
-
- v1_copy->prev = v1->prev;
- v1_copy->next = v2;
-
- v2_copy->prev = v2->prev;
- v2_copy->next = v1;
-
- v1->prev->next = v1_copy;
- v1->prev = v2_copy;
-
- v2->prev->next = v2_copy;
- v2->prev = v1_copy;
- }
-
- template<unsigned ndim>
- Edge<ndim> *clipVertex(Edge<ndim> *edge) {
- Edge<ndim> *prev = edge->prev;
- Edge<ndim> *next = edge->next;
- splitEdgeLoop(edge->prev, edge->next);
- return next;
- }
- }
-}