////////////////////////////////////////////////////////////////////// struct Matrixf; static const double TWOPI = 2 * M_PI; static const double DEGRAD = M_PI / 180.0; ////////////////////////////////////////////////////////////////////// //inline Pointf Pointf_0 () { return Pointf(0, 0); } //inline Pointf Pointf_X () { return Pointf(1, 0); } //inline Pointf Pointf_Y () { return Pointf(0, 1); } //inline Pointf Pointf_RX () { return Pointf(-1, 1); } //inline Pointf Pointf_RY () { return Pointf(1, -1); } inline Pointf fpmin (Pointf p, Pointf q) { return Pointf(min(p.x, q.x), min(p.y, q.y)); } inline Pointf fpmax (Pointf p, Pointf q) { return Pointf(max(p.x, q.x), max(p.y, q.y)); } inline Pointf fpminmax (Pointf p, Pointf mn, Pointf mx) { return Pointf(minmax(p.x, mn.x, mx.x), minmax(p.y, mn.y, mx.y)); } inline double fpmin (Pointf p) { return min(p.x, p.y); } inline double fpmax (Pointf p) { return max(p.x, p.y); } inline double fpabsmin (Pointf p) { return min(fabs(p.x), fabs(p.y)); } inline double fpabsmax (Pointf p) { return max(fabs(p.x), fabs(p.y)); } // temporary fix by Mirek Fidler: //inline double ScalarProduct(Sizef a, Sizef b) { return a.cx * b.cx + a.cy * b.cy; } //inline double VectorProduct(Sizef a, Sizef b) { return a.cx * b.cy - a.cy * b.cx; } //inline double Squared(Sizef a) { return a.cx * a.cx + a.cy * a.cy; } //inline double Length(Sizef a) { return hypot(a.cx, a.cy); } //inline int ScalarProduct(Size a, Size b) { return a.cx * b.cx + a.cy * b.cy; } //inline int VectorProduct(Size a, Size b) { return a.cx * b.cy - a.cy * b.cx; } //inline int Squared(Size a) { return a.cx * a.cx + a.cy * a.cy; } //inline double Length(Size a) { return hypot(a.cx, a.cy); } inline Pointf Move (const Pointf& p, double dx, double dy) { return Pointf(p.x + dx, p.y + dy); } inline Pointf Mid (const Pointf& p, const Pointf& q, double wt) { return p + (q - p) * wt; } inline double Squared (const Pointf& p, const Pointf& q) { return Squared(q - p); } Pointf Length (const Pointf& p, double l); inline Pointf Unit (const Pointf& p) { return Length(p, 1); } inline Pointf Rotated (const Pointf& p, double a) { double s = sin(a), c = cos(a); return Pointf(p.x * c - p.y * s, p.x * s + p.y * c); } inline Pointf Rotated (const Pointf& p, double angle, const Pointf& c) { return c + Rotated(p - c, angle); } Pointf Project (const Pointf& p, const Pointf& a, const Pointf& b); Pointf Bezier2 (const Pointf& a, const Pointf& b, const Pointf& c, double t); double Bezier2Length(const Pointf& a, const Pointf& b, const Pointf& c, double t); Sizef Bezier2Tangent(const Pointf& a, const Pointf& b, const Pointf& c, double t); Sizef Orthogonal (const Sizef& p, const Sizef& against); Sizef Orthonormal (const Sizef& p, const Sizef& against); Sizef FarthestAxis (const Sizef& p); inline Pointf Reversed (const Pointf& p) { return Pointf(-p.x, -p.y); } inline Pointf ReversedX (const Pointf& p) { return Pointf(-p.x, p.y); } inline Pointf ReversedY (const Pointf& p) { return Pointf(p.x, -p.y); } //inline Pointf Abs (Pointf p) { return Pointf(fabs(p.x), fabs(p.y)); } inline Pointf Left (const Pointf& p) { return Pointf(-p.y, p.x); } inline Pointf Right (const Pointf& p) { return Pointf(p.y, -p.x); } inline double Bearing (const Pointf& p, const Pointf& c) { return Bearing(p - c); } inline bool Select (const Pointf& p, const Pointf& A, const Pointf& B) { return Squared(p - A) < Squared(p - B); } inline double operator ^ (const Pointf& p, const Pointf& q) { return p.x * q.x + p.y * q.y; } inline double operator % (const Pointf& p, const Pointf& q) { return p.x * q.y - p.y * q.x; } inline double operator | (const Pointf& p, const Pointf& q) { return Distance(p, q); } inline Pointf PolarPointf (double a) { return Pointf(cos(a), sin(a)); } inline Pointf PolarPointf (double r, double a) { return Pointf(r * cos(a), r * sin(a)); } inline Pointf PolarPointf (const Pointf& c, double r, double a) { return Pointf(c.x + r * cos(a), c.y + r * sin(a)); } inline Point PointfToPoint(const Pointf& p) { return Point(fround(p.x), fround(p.y)); } inline Size PointfToSize (const Pointf& p) { return Size(fround(p.x), fround(p.y)); } ////////////////////////////////////////////////////////////////////// //inline Sizef Sizef_0 () { return Sizef(0, 0); } //inline Sizef Sizef_X () { return Sizef(1, 0); } //inline Sizef Sizef_Y () { return Sizef(0, 1); } //inline Sizef Sizef_RX () { return Sizef(-1, 1); } //inline Sizef Sizef_RY () { return Sizef(1, -1); } inline Sizef fpmin (const Sizef& p, const Sizef& q) { return Sizef(min(p.cx, q.cx), min(p.cy, q.cy)); } inline Sizef fpmax (const Sizef& p, const Sizef& q) { return Sizef(max(p.cx, q.cx), max(p.cy, q.cy)); } inline Sizef fpminmax (const Sizef& p, const Sizef& mn, const Sizef& mx) { return Sizef(minmax(p.cx, mn.cx, mx.cx), minmax(p.cy, mn.cy, mx.cy)); } inline double fpmin (const Sizef& p) { return min(p.cx, p.cy); } inline double fpmax (const Sizef& p) { return max(p.cx, p.cy); } inline double AbsMin (const Sizef& p) { return min(fabs(p.cx), fabs(p.cy)); } inline double AbsMax (const Sizef& p) { return max(fabs(p.cx), fabs(p.cy)); } inline Sizef Mid (const Sizef& p, const Sizef& q) { return Sizef((p.cx + q.cx) / 2, (p.cy + q.cy) / 2); } //inline double Squared (Sizef p) { return p.cx * p.cx + p.cy * p.cy; } inline double Squared (const Sizef& p, const Sizef& q) { return Squared(q - p); } //inline double Length (Sizef p) { return sqrt(Squared(p)); } Sizef Length (const Sizef& p, double l); inline Sizef Unit (const Sizef& p) { return Length(p, 1); } inline Sizef Reversed (const Sizef& s) { return Sizef(-s.cx, -s.cy); } inline Sizef ReversedX (const Sizef& s) { return Sizef(-s.cx, s.cy); } inline Sizef ReversedY (const Sizef& s) { return Sizef(s.cx, -s.cy); } inline Sizef Abs (const Sizef& s) { return Sizef(fabs(s.cx), fabs(s.cy)); } inline Sizef Left (const Sizef& s) { return Sizef(-s.cy, s.cx); } inline Sizef Right (const Sizef& s) { return Sizef(s.cy, -s.cx); } inline Point SizefToPoint (const Sizef& s) { return Point(fround(s.cx), fround(s.cy)); } inline Size SizefToSize (const Sizef& s) { return Size(fround(s.cx), fround(s.cy)); } ////////////////////////////////////////////////////////////////////// // Rectf:: //inline Rectf Rectf_0() { return Rectf(0, 0, 0, 0); } //inline Rectf Rectf_1() { return Rectf(0, 0, 1, 1); } ////////////////////////////////////////////////////////////////////// inline Rectf operator * (const Rectf& r, double f) { return Rectf(r.left * f, r.top * f, r.right * f, r.bottom * f); } inline Rectf operator * (const Rectf& r, const Sizef& s) { return Rectf(r.left * s.cx, r.top * s.cy, r.right * s.cx, r.bottom * s.cy); } inline Rectf operator * (const Rectf& r, const Pointf& p) { return Rectf(r.left * p.x, r.top * p.y, r.right * p.x, r.bottom * p.y); } inline Rectf operator * (const Rectf& r, const Rectf& s) { return Rectf(r.left * s.left, r.top * s.top, r.right * s.right, r.bottom * s.bottom); } inline Rectf operator / (const Rectf& r, double f) { return Rectf(r.left / f, r.top / f, r.right / f, r.bottom / f); } inline Rectf operator / (const Rectf& r, const Sizef& s) { return Rectf(r.left / s.cx, r.top / s.cy, r.right / s.cx, r.bottom / s.cy); } inline Rectf operator / (const Rectf& r, const Pointf& p) { return Rectf(r.left / p.x, r.top / p.y, r.right / p.x, r.bottom / p.y); } inline Rectf operator / (const Rectf& r, const Rectf& s) { return Rectf(r.left / s.left, r.top / s.top, r.right / s.right, r.bottom / s.bottom); } extern Rectf& SetUnion (Rectf& rc, const Pointf& pt); inline Rectf GetUnion (const Rectf& rc, const Pointf& p) { Rectf tmp = rc; return SetUnion(tmp, p); } extern Rectf GetUnion (const Array& pt); extern Rectf& SetMinMaxMove(Rectf& rc, const Rectf& outer_rc); inline Rectf GetMinMaxMove(const Rectf& rc, const Rectf& outer_rc) { Rectf tmp = rc; return SetMinMaxMove(tmp, outer_rc); } extern double Distance (const Rectf& rc, const Pointf& pt); inline double Diagonal (const Rectf& rc) { return Length(rc.Size()); } inline double Area (const Rectf& rc) { return rc.Width() * rc.Height(); } inline Rectf PointfRectf (const Pointf& pt) { return Rectf(pt.x, pt.y, pt.x, pt.y); } inline Rectf SortRectf (const Pointf& p, const Pointf& q) { return Rectf(fpmin(p, q), fpmax(p, q)); } inline Rect RectfToRect (const Rectf& rc) { return Rect(fround(rc.left), fround(rc.top), fround(rc.right), fround(rc.bottom)); } inline Pointf fpminmax (const Pointf& p, const Rectf& rc) { return Pointf(minmax(p.x, rc.left, rc.right), minmax(p.y, rc.top, rc.bottom)); } ////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////// const Matrixf& Matrixf_0(); const Matrixf& Matrixf_1(); const Matrixf& Matrixf_Null(); const Matrixf& Matrixf_MirrorX(); // mirror around X axis const Matrixf& Matrixf_MirrorY(); // mirror around Y axis ////////////////////////////////////////////////////////////////////// struct Matrixf : Moveable { Pointf x, y, a; Matrixf() { *this = Matrixf_1(); } Matrixf(const Nuller&) : a(Null) {} Matrixf(Pointf x, Pointf y, Pointf a = Pointf(0, 0)) : x(x), y(y), a(a) {} Matrixf(const Matrixf& (*fn)()) { *this = fn(); } Matrixf(double xx, double xy, double yx, double yy, double ax, double ay) : x(xx, xy), y(yx, yy), a(ax, ay) {} bool IsIdentity() const { return x.x == 1 && x.y == 0 && y.x == 0 && y.y == 1 && a.x == 0 && a.y == 0; } bool IsZero() const { return x.x == 0 && x.y == 0 && y.x == 0 && y.y == 0 && a.x == 0 && a.y == 0; } void Fix(Pointf vector) { a = vector - vector.x * x - vector.y * y; } Matrixf& operator *= (const Matrixf& another); String ToString() const; }; //template DumpType; extern Matrixf MatrixfMove (Pointf vector); extern Matrixf MatrixfRotate (double angle, Pointf fix = Pointf(0, 0)); extern Matrixf MatrixfScale (double scale, Pointf fix = Pointf(0, 0)); extern Matrixf MatrixfScale (Pointf scale, Pointf fix = Pointf(0, 0)); extern Matrixf MatrixfScale (const Rectf& src, const Rectf& dest); extern Matrixf MatrixfMirror (Pointf A, Pointf B); extern Matrixf MatrixfAffine (Pointf src1, Pointf dest1, Pointf src2, Pointf dest2); extern Matrixf MatrixfAffine (Pointf src1, Pointf dest1, Pointf src2, Pointf dest2, Pointf src3, Pointf dest3); extern Matrixf MatrixfInverse(const Matrixf& mx); inline double Determinant (const Matrixf& mx) { return mx.x % mx.y; } inline bool IsReversing (const Matrixf& mx) { return Determinant(mx) < 0; } extern double MatrixfMeasure(const Matrixf& mx); template<> inline bool IsNull (const Matrixf& mx) { return IsNull(mx.a); } inline bool operator == (const Matrixf& m1, const Matrixf& m2) { return m1.x == m2.x && m1.y == m2.y && m1.a == m2.a; } inline bool operator != (const Matrixf& m1, const Matrixf& m2) { return !(m1 == m2); } inline Pointf operator % (Pointf vector, const Matrixf& matrix) { return vector.x * matrix.x + vector.y * matrix.y; } extern Pointf operator * (Pointf point, const Matrixf& matrix); extern Pointf operator / (Pointf point, const Matrixf& matrix); extern Rectf operator * (const Rectf& rect, const Matrixf& matrix); extern Rectf operator / (const Rectf& rect, const Matrixf& matrix); inline Pointf& operator %= (Pointf& point, const Matrixf& matrix) { return point = point % matrix; } inline Pointf& operator *= (Pointf& point, const Matrixf& matrix) { return point = point * matrix; } inline Matrixf operator * (const Matrixf& m1, const Matrixf& m2) { return Matrixf(m1) *= m2; } inline Matrixf operator / (const Matrixf& m1, const Matrixf& m2) { return m1 * MatrixfInverse(m2); } ////////////////////////////////////////////////////////////////////// // set distance of point from an object double Distance (Pointf X, Pointf A, Pointf B, double *arg = NULL); double Distance (Pointf X, Pointf A, Pointf B, double bulge, double *arg = NULL); double Distance (Pointf X, Pointf C, double radius, double *arg = NULL); ////////////////////////////////////////////////////////////////////// // set intersection with rectangle bool Crosses (const Rectf& R, Pointf A, Pointf B); bool Crosses (const Rectf& R, Pointf A, Pointf B, double bulge); bool Crosses (const Rectf& R, Pointf C, double radius); ////////////////////////////////////////////////////////////////////// // set intersection with polygon enum { CMP_OUT = -1, CMP_SECT = 0, CMP_IN = +1 }; int ContainsPoints(const Array& polygon, const Array& points); int ContainsPoints(const Array& polygon, const Vector& polyend, const Array& points); int ContainsPoint (const Array& polygon, Pointf pt); int ContainsPoint (const Array& polygon, const Vector& polyend, Pointf pt); int ContainsPoly (const Array& chkpoly, const Array& polygon, const Vector& polyend, bool closed); int ContainsPoly (const Array& chkpoly, const Array& polygon, bool closed); ////////////////////////////////////////////////////////////////////// bool ClipLine (Pointf& A, Pointf& B, const Rectf& box); bool ClipLine (Pointf& A, Pointf& B, const Rect& box); bool ClipLine (Point& A, Point& B, const Rect& box); ////////////////////////////////////////////////////////////////////// Vector ConvexHullOrder(const Vector& pt); Vector ConvexHullOrder(const Array& pt); ////////////////////////////////////////////////////////////////////// Rectf GetBoundingBox(const Array& vertices); Rect GetBoundingBox(const Point *vertices, int vertex_count); Rect GetBoundingBox(const Vector& vertices); void SplitPolygon (const Point *vertices, int vertex_count, const int *counts, int count_count, Vector& out_vertices, Vector& out_counts, Rect clip = Null, int max_trace_points = 8000); void SplitPolygon (const Vector& vertices, const Vector& counts, Vector& out_vertices, Vector& out_counts, Rect clip = Null, int max_trace_points = 8000); void SplitPolygon (Array::ConstIterator vertices, int vertex_count, const int *counts, int count_count, Array& out_vertices, Vector& out_counts, const Rectf& clip = Null, int max_trace_points = 8000); void SplitPolygon (const Array& vertices, const Vector& counts, Array& out_vertices, Vector& out_counts, const Rectf& clip = Null, int max_trace_points = 8000); ////////////////////////////////////////////////////////////////////// extern double Vec_outer_tolerance; // maximum reasonable coordinate value extern double Vec_tolerance; // linear tolerance extern double Vec_ang_tolerance; // angular tolerance extern bool VecTolEq (double x, double y); extern bool VecTolEq (Pointf a, Pointf b); ////////////////////////////////////////////////////////////////////// class VecLine { public: VecLine(); VecLine(Pointf A, Pointf B) : A(A), B(B) {} VecLine(double x1, double y1, double x2, double y2) : A(x1, y1), B(x2, y2) {} String ToString() const; VecLine& SetNull(); double Length() const { return A | B; } Pointf Mid() const; Pointf Right() const; Pointf Left() const; Pointf Vector() const; double GetArg(Pointf pt) const; Pointf GetPointAt(double arg) const; VecLine Reversed() const; VecLine& SetReversed(); Pointf Intersect(VecLine another) const; VecLine& SetClip(const Rectf& rect); VecLine Clip(const Rectf& rect) const { return VecLine(*this).Clip(rect); } double Distance(Pointf point, double *arg = NULL) const; bool IsNullInstance() const { return IsNull(A); } // algorithms static Pointf GetPointAt(Pointf A, Pointf B, double arg); public: Pointf A, B; }; //template BitWiseType; //template DumpType; inline Pointf operator & (VecLine l1, VecLine l2) { return l1.Intersect(l2); } inline VecLine operator & (VecLine line, const Rectf& rect) { return line.Clip(rect); } inline double operator | (VecLine ln, Pointf pt) { return ln.Distance(pt); } inline double operator | (Pointf pt, VecLine ln) { return ln.Distance(pt); } ////////////////////////////////////////////////////////////////////// class VecArc : public VecLine { public: VecArc(); VecArc(VecLine line, double bulge = 0) : VecLine(line), bulge(bulge) {} VecArc(Pointf A, Pointf B, double bulge = 0) : VecLine(A, B), bulge(bulge) {} VecArc(double x1, double y1, double x2, double y2, double bulge = 0) : VecLine(x1, y1, x2, y2), bulge(bulge) {} String ToString() const; Pointf ArcMid() const; double ArcLength() const; VecArc Reversed() const; VecArc& SetReversed(); Pointf GetPointAt(double t) const; Rectf GetBoundingBox() const; // arc algorithms static Pointf ArcMid(Pointf P, Pointf Q, double l, double h); static double ArcLength(Pointf P, Pointf Q, double l, double h); static void Bisect(Pointf P, Pointf Q, double l, double h, Pointf& centre, double& ll, double& hh); static Pointf GetPointAt(Pointf P, Pointf Q, double l, double h, double t); public: double bulge; }; //template BitWiseType; //template DumpType; ////////////////////////////////////////////////////////////////////// /* struct VecVertex : public Pointf { VecVertex(); VecVertex(Pointf point, double bulge = 0) : Pointf(point), bulge(bulge) {} VecVertex(double x, double y, double bulge = 0) : Pointf(x, y), bulge(bulge) {} String Dump() const; double bulge; // bulge of segment __ENDING AT THIS VERTEX__ }; template BitWiseType; template DumpType; */ ////////////////////////////////////////////////////////////////////// /* class VecCurve : public Vector { public: typedef Vector Base; VecCurve(); VecCurve(const VecCurve& another, int); void Add(const VecVertex& vertex); void Add(Pointf point); // can be used as lineto callback for Arc::Iterator void Add(Pointf point, double bulge); void Add(double x, double y, double bulge = 0); VecArc Segment(int i) const; Vector Check() const; // find self-intersections; empty return value = OK String Dump() const; }; template class DeepCopyOption; template DumpType; */ ////////////////////////////////////////////////////////////////////// #ifdef p #undef p #endif class VecArcInfo : public VecArc { public: VecArcInfo(); VecArcInfo(Pointf p, Pointf q) { Set(p, q); } VecArcInfo(Pointf p, Pointf q, Pointf x) { Set(p, q, x); } VecArcInfo(Pointf p, Pointf q, double bulge) { Set(p, q, bulge); } VecArcInfo(Pointf c, double r, double a, double b) { Set(c, r, a, b); } VecArcInfo(Pointf c, double r) { Set(c, r); } VecArcInfo(Pointf c, Pointf a, Pointf b, bool anticlockwise) { Set(c, a, b, anticlockwise); } VecArcInfo(const VecArc& arc) { Set(arc); } VecArcInfo(const VecArcInfo& arc) { *this = arc; } String ToString() const; void Set(Pointf P, Pointf Q); void Set(Pointf P, Pointf Q, Pointf X); void Set(Pointf P, Pointf Q, double bulge); void Set(Pointf C, double r, double a, double b); void Set(Pointf C, double r); void Set(Pointf C, Pointf A, Pointf B, bool anticlockwise); void Set(const VecArc& arc) { Set(arc.A, arc.B, arc.bulge); } void Move(Pointf offset); bool IsCircle() const { return circle; } bool IsCurved() const { return curved; } bool IsReversed() const { return reversed; } double Length() const; Pointf CentreOfMass() const; bool ContainsBearing(double bearing) const; double Distance(Pointf point, double *arg = NULL) const; bool Crosses(const Rectf& rect) const; Pointf GetPointAt(double t) const; double GetMaxDistance(Pointf point, Pointf *farthest = NULL) const; double GetArg(double bearing) const; double GetArg(Pointf point) const; VecArcInfo Subset(double start, double end) const; Rectf GetBoundingBox() const; double GetAngle() const; // oriented included angle double GetStartTangent() const; double GetEndTangent() const; Pointf GetStartDir() const; Pointf GetEndDir() const; VecArcInfo Offset(double dist) const; VecArcInfo Reversed() const { return VecArcInfo(*this).SetReversed(); } VecArcInfo& SetReversed(); Pointf C; // centre of circle (Null when not bulged) double bow; // bow length double alpha; // start angle (rad); most clockwise point on arc double beta; // end angle (rad); most anticlockwise point on arc double radius; // circle radius (Null when not bulged) bool curved; // true = it's an arc, false = it's a circle bool reversed; // true = arc has been entered as clockwise bool circle; // true = it's a full circle }; ////////////////////////////////////////////////////////////////////// class VecIntersection { public: VecIntersection() { count = 0; } void Mirror(); bool Nothing() { count = 0; return false; } void Remove(int index); bool LL(const Pointf& P1, const Pointf& Q1, const Pointf& P2, const Pointf& Q2); bool LC(const Pointf& P1, const Pointf& Q1, const Pointf& C2, double r2); bool LA(const Pointf& P1, const Pointf& Q1, const VecArcInfo& a2); bool CC(const Pointf& C1, double r1, const Pointf& C2, double r2); bool CA(const Pointf& C1, double r1, const VecArcInfo& a2); bool AA(const VecArcInfo& a1, const VecArcInfo& a2); bool IsEmpty() const { return count == 0; } int GetCount() const { return count; } public: int count; // number of intersections double t[2], u[2]; protected: void CheckBearing(double *hints, const VecArcInfo& a); }; ////////////////////////////////////////////////////////////////////// class VecArcIterator { public: typedef Callback1 DrawProc; typedef Gate2 ArcProc; VecArcIterator(const VecArc& arc, DrawProc _lineto); VecArcIterator(Pointf start, Pointf end, double bulge, DrawProc _lineto); VecArcIterator& Level(int _level) { level = _level; return *this; } VecArcIterator& Precision(double prec ) { precision = prec; return *this; } VecArcIterator& Clip(const Rectf& rect, DrawProc _mv) { clip = rect; moveto = _mv; return *this; } VecArcIterator& ArcTo(ArcProc _arc) { arcto = _arc; return *this; } void Go(); // recurse the arc public: double arclen; // degenerate to simple arc under such length int level; // maximum # segments = 2 ^ level double precision; // degenerate to line whenever |bulge| <= precision VecArc arc; // arc to interpolate Rectf clip; // clipping rectangle DrawProc moveto; // moveto callback (needed only when clipping is on) DrawProc lineto; // lineto callback ArcProc arcto; // simple arcto callback protected: enum { CF_XL = 001, CF_XG = 002, CF_YL = 010, CF_YG = 020, DEFAULT_LEVEL = 10, }; Pointf last; // last iteration point int last_clip; // clipping status of last vertex int GetClip(Pointf point) const; void Recurse(Pointf to, double l, double h, int depth, int next_flclip); }; //////////////////////////////////////////////////////////////////////