Blame c++/contourgl/triangulator.cpp

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