1
2#include "Contour.h"
3
4#include "arithmetics.hpp"
5
6namespace msdfgen {
7
8static double shoelace(const Point2 &a, const Point2 &b) {
9 return (b.x-a.x)*(a.y+b.y);
10}
11
12void Contour::addEdge(const EdgeHolder &edge) {
13 edges.push_back(edge);
14}
15
16#ifdef MSDFGEN_USE_CPP11
17void Contour::addEdge(EdgeHolder &&edge) {
18 edges.push_back((EdgeHolder &&) edge);
19}
20#endif
21
22EdgeHolder & Contour::addEdge() {
23 edges.resize(edges.size()+1);
24 return edges.back();
25}
26
27static void boundPoint(double &l, double &b, double &r, double &t, Point2 p) {
28 if (p.x < l) l = p.x;
29 if (p.y < b) b = p.y;
30 if (p.x > r) r = p.x;
31 if (p.y > t) t = p.y;
32}
33
34void Contour::bound(double &l, double &b, double &r, double &t) const {
35 for (std::vector<EdgeHolder>::const_iterator edge = edges.begin(); edge != edges.end(); ++edge)
36 (*edge)->bound(l, b, r, t);
37}
38
39void Contour::boundMiters(double &l, double &b, double &r, double &t, double border, double miterLimit, int polarity) const {
40 if (edges.empty())
41 return;
42 Vector2 prevDir = edges.back()->direction(1).normalize(true);
43 for (std::vector<EdgeHolder>::const_iterator edge = edges.begin(); edge != edges.end(); ++edge) {
44 Vector2 dir = -(*edge)->direction(0).normalize(true);
45 if (polarity*crossProduct(prevDir, dir) >= 0) {
46 double miterLength = miterLimit;
47 double q = .5*(1-dotProduct(prevDir, dir));
48 if (q > 0)
49 miterLength = min(1/sqrt(q), miterLimit);
50 Point2 miter = (*edge)->point(0)+border*miterLength*(prevDir+dir).normalize(true);
51 boundPoint(l, b, r, t, miter);
52 }
53 prevDir = (*edge)->direction(1).normalize(true);
54 }
55}
56
57int Contour::winding() const {
58 if (edges.empty())
59 return 0;
60 double total = 0;
61 if (edges.size() == 1) {
62 Point2 a = edges[0]->point(0), b = edges[0]->point(1/3.), c = edges[0]->point(2/3.);
63 total += shoelace(a, b);
64 total += shoelace(b, c);
65 total += shoelace(c, a);
66 } else if (edges.size() == 2) {
67 Point2 a = edges[0]->point(0), b = edges[0]->point(.5), c = edges[1]->point(0), d = edges[1]->point(.5);
68 total += shoelace(a, b);
69 total += shoelace(b, c);
70 total += shoelace(c, d);
71 total += shoelace(d, a);
72 } else {
73 Point2 prev = edges.back()->point(0);
74 for (std::vector<EdgeHolder>::const_iterator edge = edges.begin(); edge != edges.end(); ++edge) {
75 Point2 cur = (*edge)->point(0);
76 total += shoelace(prev, cur);
77 prev = cur;
78 }
79 }
80 return sign(total);
81}
82
83void Contour::reverse() {
84 for (int i = (int) edges.size()/2; i > 0; --i)
85 EdgeHolder::swap(edges[i-1], edges[edges.size()-i]);
86 for (std::vector<EdgeHolder>::iterator edge = edges.begin(); edge != edges.end(); ++edge)
87 (*edge)->reverse();
88}
89
90}
91