Blame c++/contourgl/contour.h

faaf7d
/*
faaf7d
    ......... 2015 Ivan Mahonin
faaf7d
faaf7d
    This program is free software: you can redistribute it and/or modify
faaf7d
    it under the terms of the GNU General Public License as published by
faaf7d
    the Free Software Foundation, either version 3 of the License, or
faaf7d
    (at your option) any later version.
faaf7d
faaf7d
    This program is distributed in the hope that it will be useful,
faaf7d
    but WITHOUT ANY WARRANTY; without even the implied warranty of
faaf7d
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
faaf7d
    GNU General Public License for more details.
faaf7d
faaf7d
    You should have received a copy of the GNU General Public License
faaf7d
    along with this program.  If not, see <http: licenses="" www.gnu.org="">.</http:>
faaf7d
*/
faaf7d
faaf7d
#ifndef _CONTOUR_H_
faaf7d
#define _CONTOUR_H_
faaf7d
faaf7d
#include <cstddef></cstddef>
faaf7d
#include <cmath></cmath>
faaf7d
faaf7d
#include <algorithm></algorithm>
faaf7d
#include <vector></vector>
faaf7d
faaf7d
template<typename t=""></typename>
faaf7d
bool intersects(const T &a0, const T &a1, const T &b0, const T &b1) {
faaf7d
	return !(std::max(b0, b1) < std::min(a0, a1))
faaf7d
	    && !(std::max(a0, a1) < std::min(b0, b1));
faaf7d
}
faaf7d
faaf7d
inline double wrap_angle(double a, double round) {
faaf7d
	double rounds = a/round + 0.5;
faaf7d
	return (rounds - floor(rounds) - 0.5)*round;
faaf7d
}
faaf7d
faaf7d
inline bool angle_between(double a0, double a1, double a, double round) {
faaf7d
	if (a1 < a0) std::swap(a0, a1);
faaf7d
	a0 = wrap_angle(a0, round);
faaf7d
	a1 = wrap_angle(a1, round);
faaf7d
	a = wrap_angle(a, round);
faaf7d
	if (a < a0) a += round;
faaf7d
	if (a1 < a0) a1 += round;
faaf7d
	return a0 < a && a < a1;
faaf7d
}
faaf7d
faaf7d
class Vector {
faaf7d
public:
faaf7d
	union {
faaf7d
		struct { double x, y; };
faaf7d
		struct { double coords[]; };
faaf7d
	};
faaf7d
faaf7d
	Vector():
faaf7d
		x(), y() { }
faaf7d
	Vector(double x, double y):
faaf7d
		x(x), y(y) { }
faaf7d
faaf7d
	double& operator[] (int index)
faaf7d
		{ return coords[index]; }
faaf7d
	const double& operator[] (int index) const
faaf7d
		{ return coords[index]; }
faaf7d
	bool is_equal_to(const Vector &other) const
faaf7d
		{ return fabs(x - other.x) < 1e-6 && fabs(y - other.y) < 1e-6; }
faaf7d
faaf7d
	Vector operator+(const Vector &a) const
faaf7d
		{ return Vector(x + a.x, y + a.y); }
faaf7d
	Vector operator-(const Vector &a) const
faaf7d
		{ return Vector(x - a.x, y - a.y); }
faaf7d
	Vector operator*(double a) const
faaf7d
		{ return Vector(x*a, y*a); }
faaf7d
	Vector operator/(double a) const
faaf7d
		{ return Vector(x/a, y/a); }
faaf7d
faaf7d
	static Vector zero() { return Vector(); }
faaf7d
};
faaf7d
faaf7d
class Rect {
faaf7d
public:
faaf7d
	Vector p0, p1;
faaf7d
faaf7d
    bool intersects(const Rect &other) const
faaf7d
        { return ::intersects(p0.x, p1.x, other.p0.x, other.p1.x)
faaf7d
              && ::intersects(p0.y, p1.y, other.p0.y, other.p1.y); }
faaf7d
faaf7d
    Rect expand(const Vector &p) const {
faaf7d
    	Rect r;
faaf7d
    	r.p0.x = std::min(std::min(p0.x, p1.x), p.x);
faaf7d
    	r.p0.y = std::min(std::min(p0.y, p1.y), p.y);
faaf7d
    	r.p1.x = std::max(std::max(p0.x, p1.x), p.x);
faaf7d
    	r.p1.y = std::max(std::max(p0.y, p1.y), p.y);
faaf7d
    	return r;
faaf7d
    }
faaf7d
};
faaf7d
faaf7d
inline bool intersects(const Rect &a, const Rect &b)
faaf7d
    { return a.intersects(b); }
faaf7d
faaf7d
class Contour
faaf7d
{
faaf7d
public:
faaf7d
	enum ChunkType {
faaf7d
		CLOSE,
faaf7d
		MOVE,
faaf7d
		LINE,
faaf7d
		CUBIC,
faaf7d
		CONIC
faaf7d
	};
faaf7d
faaf7d
	struct Chunk {
faaf7d
		ChunkType type;
faaf7d
		Vector p1, t0, t1;
faaf7d
		Chunk(): type() { }
faaf7d
		Chunk(ChunkType type, const Vector &p1, const Vector &t0 = Vector(), const Vector &t1 = Vector()):
faaf7d
			type(type), p1(p1), t0(t0), t1(t1) { }
faaf7d
	};
faaf7d
faaf7d
	typedef std::vector<chunk> ChunkList;</chunk>
faaf7d
faaf7d
private:
faaf7d
	static const Vector blank;
faaf7d
	ChunkList chunks;
faaf7d
	size_t first;
faaf7d
faaf7d
public:
faaf7d
	Contour(): first(0) { }
faaf7d
faaf7d
	void clear();
faaf7d
	void move_to(const Vector &v);
faaf7d
	void line_to(const Vector &v);
faaf7d
	void cubic_to(const Vector &v, const Vector &t0, const Vector &t1);
faaf7d
	void conic_to(const Vector &v, const Vector &t);
faaf7d
	void close();
faaf7d
faaf7d
	void assign(const Contour &other);
faaf7d
faaf7d
	const ChunkList& get_chunks() const { return chunks; }
faaf7d
faaf7d
	const Vector& current() const
faaf7d
		{ return chunks.empty() ? blank : chunks.back().p1; }
faaf7d
faaf7d
	void split(Contour &c, const Rect &bounds, const Vector &min_size) const;
faaf7d
faaf7d
private:
faaf7d
	void line_split(
faaf7d
		Rect &ref_line_bounds,
faaf7d
		const Rect &bounds,
faaf7d
		const Vector &min_size,
faaf7d
		const Vector &p1 );
faaf7d
faaf7d
	void conic_split(
faaf7d
		Rect &ref_line_bounds,
faaf7d
		const Rect &bounds,
faaf7d
		const Vector &min_size,
faaf7d
		const Vector &p1,
faaf7d
		const Vector ¢er,
faaf7d
		double radius,
faaf7d
		double radians0,
faaf7d
		double radians1,
faaf7d
		int level = 64 );
faaf7d
faaf7d
	void cubic_split(
faaf7d
		Rect &ref_line_bounds,
faaf7d
		const Rect &bounds,
faaf7d
		const Vector &min_size,
faaf7d
		const Vector &p1,
faaf7d
		const Vector &bezier_pp0,
faaf7d
		const Vector &bezier_pp1,
faaf7d
		int level = 64 );
faaf7d
faaf7d
	static bool conic_convert(
faaf7d
		const Vector &p0,
faaf7d
		const Vector &p1,
faaf7d
		const Vector &t,
faaf7d
		Vector &out_center,
faaf7d
		double &out_radius,
faaf7d
		double &out_radians0,
faaf7d
		double &out_radians1 );
faaf7d
faaf7d
	static Rect conic_bounds(
faaf7d
		const Vector &p0,
faaf7d
		const Vector &p1,
faaf7d
		const Vector ¢er,
faaf7d
		double radius,
faaf7d
		double radians0,
faaf7d
		double radians1 );
faaf7d
faaf7d
	static void cubic_convert(
faaf7d
		const Vector &p0,
faaf7d
		const Vector &p1,
faaf7d
		const Vector &t0,
faaf7d
		const Vector &t1,
faaf7d
		Vector &out_bezier_pp0,
faaf7d
		Vector &out_bezier_pp1 );
faaf7d
faaf7d
	static Rect cubic_bounds(
faaf7d
		const Vector &p0,
faaf7d
		const Vector &p1,
faaf7d
		const Vector &bezier_pp0,
faaf7d
		const Vector &bezier_pp1 );
faaf7d
};
faaf7d
faaf7d
#endif