|
|
8cd87e |
/*
|
|
|
8cd87e |
......... 2015 Ivan Mahonin
|
|
|
8cd87e |
|
|
|
8cd87e |
This program is free software: you can redistribute it and/or modify
|
|
|
8cd87e |
it under the terms of the GNU General Public License as published by
|
|
|
8cd87e |
the Free Software Foundation, either version 3 of the License, or
|
|
|
8cd87e |
(at your option) any later version.
|
|
|
8cd87e |
|
|
|
8cd87e |
This program is distributed in the hope that it will be useful,
|
|
|
8cd87e |
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
8cd87e |
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
8cd87e |
GNU General Public License for more details.
|
|
|
8cd87e |
|
|
|
8cd87e |
You should have received a copy of the GNU General Public License
|
|
|
8cd87e |
along with this program. If not, see <http: licenses="" www.gnu.org="">.</http:>
|
|
|
8cd87e |
*/
|
|
|
8cd87e |
|
|
|
8cd87e |
#include <iostream></iostream>
|
|
|
8cd87e |
|
|
|
8cd87e |
#include "triangulator.h"
|
|
|
8cd87e |
|
|
|
8cd87e |
|
|
|
8cd87e |
using namespace std;
|
|
|
8cd87e |
|
|
|
8cd87e |
|
|
|
8cd87e |
bool Triangulator::intersect_lines(Vector a0, Vector a1, Vector b0, Vector b1) {
|
|
|
8cd87e |
static const Real precision = 1e-6;
|
|
|
8cd87e |
|
|
|
8cd87e |
Vector da(a1 - a0);
|
|
|
8cd87e |
Vector pa(-da.y, da.x);
|
|
|
8cd87e |
|
|
|
8cd87e |
Real d0, d1;
|
|
|
8cd87e |
|
|
|
8cd87e |
d0 = pa.dot(b0 - a0);
|
|
|
8cd87e |
if (fabs(d0) < precision) return false;
|
|
|
8cd87e |
d1 = pa.dot(b1 - a0);
|
|
|
8cd87e |
if (fabs(d1) < precision) return false;
|
|
|
8cd87e |
if ((d0 > 0.0) == (d1 > 0.0)) return false;
|
|
|
8cd87e |
|
|
|
8cd87e |
Vector db(b1 - b0);
|
|
|
8cd87e |
Vector pb(-db.y, db.x);
|
|
|
8cd87e |
|
|
|
8cd87e |
d0 = pa.dot(a0 - b0);
|
|
|
8cd87e |
if (fabs(d0) < precision) return false;
|
|
|
8cd87e |
d1 = pa.dot(a1 - b0);
|
|
|
8cd87e |
if (fabs(d1) < precision) return false;
|
|
|
8cd87e |
if ((d0 > 0.0) == (d1 > 0.0)) return false;
|
|
|
8cd87e |
|
|
|
8cd87e |
return true;
|
|
|
8cd87e |
}
|
|
|
8cd87e |
|
|
|
8cd87e |
void Triangulator::build_path(const Contour &contour, Path &path, int index_offset) {
|
|
|
8cd87e |
// TODO: connect multiple contours
|
|
|
8cd87e |
path.clear();
|
|
|
8cd87e |
path.resize(contour.get_chunks().size());
|
|
|
8cd87e |
for(int i = 0; i < (int)contour.get_chunks().size(); ++i) {
|
|
|
8cd87e |
const Contour::Chunk &c = contour.get_chunks()[i];
|
|
|
8cd87e |
Vertex &v = path[i];
|
|
|
8cd87e |
v.index = i + index_offset;
|
|
|
8cd87e |
v.p = c.p1;
|
|
|
8cd87e |
v.next = &v + 1;
|
|
|
8cd87e |
}
|
|
|
8cd87e |
path.back().next = &path.front();
|
|
|
8cd87e |
}
|
|
|
8cd87e |
|
|
|
8cd87e |
bool Triangulator::check_triangle(Vertex *first, TriangleList &triangles) {
|
|
|
8cd87e |
// path is a dot
|
|
|
8cd87e |
if (first->next == first)
|
|
|
8cd87e |
return true;
|
|
|
8cd87e |
|
|
|
8cd87e |
// path is a two lines
|
|
|
8cd87e |
if (first->next->next == first)
|
|
|
8cd87e |
return true;
|
|
|
8cd87e |
|
|
|
8cd87e |
// path is triangle
|
|
|
8cd87e |
if (first->next->next->next == first) {
|
|
|
8cd87e |
triangles.push_back(first->index);
|
|
|
8cd87e |
triangles.push_back(first->next->index);
|
|
|
8cd87e |
triangles.push_back(first->next->next->index);
|
|
|
8cd87e |
return true;
|
|
|
8cd87e |
}
|
|
|
8cd87e |
|
|
|
8cd87e |
return false;
|
|
|
8cd87e |
}
|
|
|
8cd87e |
|
|
|
8cd87e |
void Triangulator::split_path(Vertex *first, TriangleList &triangles) {
|
|
|
8cd87e |
if (check_triangle(first, triangles))
|
|
|
8cd87e |
return;
|
|
|
8cd87e |
|
|
|
8cd87e |
// split path
|
|
|
8cd87e |
Vertex *va0 = first;
|
|
|
8cd87e |
for(Vertex *va1 = va0->next; va1 != first; va1 = va1->next) {
|
|
|
8cd87e |
if (va0 != va1 && va0->next != va1 && va1->next != va0) {
|
|
|
8cd87e |
bool intersects = false;
|
|
|
8cd87e |
for(Vertex *vb0 = first->next; vb0->next != first; vb0 = vb0->next) {
|
|
|
8cd87e |
Vertex *vb1 = vb0->next;
|
|
|
8cd87e |
if ( va0 != vb0 && va0 != vb1 && va1 != vb0 && va1 != vb1
|
|
|
8cd87e |
&& intersect_lines(va0->p, va1->p, vb0->p, vb1->p) )
|
|
|
8cd87e |
{ intersects = true; break; }
|
|
|
8cd87e |
}
|
|
|
8cd87e |
if (!intersects) {
|
|
|
8cd87e |
Vertex *next = va1->next;
|
|
|
8cd87e |
va1->next = va0;
|
|
|
8cd87e |
if (!check_triangle(va0, triangles))
|
|
|
8cd87e |
split_path(va0, triangles);
|
|
|
8cd87e |
va1->next = next;
|
|
|
8cd87e |
va0->next = va1;
|
|
|
8cd87e |
if (check_triangle(va0, triangles))
|
|
|
8cd87e |
return;
|
|
|
8cd87e |
va1 = va0;
|
|
|
8cd87e |
}
|
|
|
8cd87e |
}
|
|
|
8cd87e |
}
|
|
|
8cd87e |
|
|
|
8cd87e |
cout << "bug - path not fully triangulated" << endl;
|
|
|
8cd87e |
}
|
|
|
8cd87e |
|
|
|
8cd87e |
void Triangulator::triangulate(const Contour &contour, TriangleList &triangles, int index_offset) {
|
|
|
8cd87e |
Path path;
|
|
|
8cd87e |
build_path(contour, path, index_offset);
|
|
|
8cd87e |
triangles.reserve(triangles.size() + 3*(path.size() - 2));
|
|
|
8cd87e |
split_path(&path.front(), triangles);
|
|
|
8cd87e |
}
|
|
|
8cd87e |
|