|
|
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
|