Blame c++/contourgl/triangulator.cpp

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