1
2#include "Shape.h"
3
4#include <algorithm>
5#include "arithmetics.hpp"
6
7namespace msdfgen {
8
9Shape::Shape() : inverseYAxis(false) { }
10
11void Shape::addContour(const Contour &contour) {
12 contours.push_back(contour);
13}
14
15#ifdef MSDFGEN_USE_CPP11
16void Shape::addContour(Contour &&contour) {
17 contours.push_back((Contour &&) contour);
18}
19#endif
20
21Contour & Shape::addContour() {
22 contours.resize(contours.size()+1);
23 return contours.back();
24}
25
26bool Shape::validate() const {
27 for (std::vector<Contour>::const_iterator contour = contours.begin(); contour != contours.end(); ++contour) {
28 if (!contour->edges.empty()) {
29 Point2 corner = contour->edges.back()->point(1);
30 for (std::vector<EdgeHolder>::const_iterator edge = contour->edges.begin(); edge != contour->edges.end(); ++edge) {
31 if (!*edge)
32 return false;
33 if ((*edge)->point(0) != corner)
34 return false;
35 corner = (*edge)->point(1);
36 }
37 }
38 }
39 return true;
40}
41
42static void deconvergeEdge(EdgeHolder &edgeHolder, int param) {
43 {
44 const QuadraticSegment *quadraticSegment = dynamic_cast<const QuadraticSegment *>(&*edgeHolder);
45 if (quadraticSegment)
46 edgeHolder = quadraticSegment->convertToCubic();
47 }
48 {
49 CubicSegment *cubicSegment = dynamic_cast<CubicSegment *>(&*edgeHolder);
50 if (cubicSegment)
51 cubicSegment->deconverge(param, MSDFGEN_DECONVERGENCE_FACTOR);
52 }
53}
54
55void Shape::normalize() {
56 for (std::vector<Contour>::iterator contour = contours.begin(); contour != contours.end(); ++contour) {
57 if (contour->edges.size() == 1) {
58 EdgeSegment *parts[3] = { };
59 contour->edges[0]->splitInThirds(parts[0], parts[1], parts[2]);
60 contour->edges.clear();
61 contour->edges.push_back(EdgeHolder(parts[0]));
62 contour->edges.push_back(EdgeHolder(parts[1]));
63 contour->edges.push_back(EdgeHolder(parts[2]));
64 } else {
65 EdgeHolder *prevEdge = &contour->edges.back();
66 for (std::vector<EdgeHolder>::iterator edge = contour->edges.begin(); edge != contour->edges.end(); ++edge) {
67 Vector2 prevDir = (*prevEdge)->direction(1).normalize();
68 Vector2 curDir = (*edge)->direction(0).normalize();
69 if (dotProduct(prevDir, curDir) < MSDFGEN_CORNER_DOT_EPSILON-1) {
70 deconvergeEdge(*prevEdge, 1);
71 deconvergeEdge(*edge, 0);
72 }
73 prevEdge = &*edge;
74 }
75 }
76 }
77}
78
79void Shape::bound(double &l, double &b, double &r, double &t) const {
80 for (std::vector<Contour>::const_iterator contour = contours.begin(); contour != contours.end(); ++contour)
81 contour->bound(l, b, r, t);
82}
83
84void Shape::boundMiters(double &l, double &b, double &r, double &t, double border, double miterLimit, int polarity) const {
85 for (std::vector<Contour>::const_iterator contour = contours.begin(); contour != contours.end(); ++contour)
86 contour->boundMiters(l, b, r, t, border, miterLimit, polarity);
87}
88
89Shape::Bounds Shape::getBounds(double border, double miterLimit, int polarity) const {
90 static const double LARGE_VALUE = 1e240;
91 Shape::Bounds bounds = { +LARGE_VALUE, +LARGE_VALUE, -LARGE_VALUE, -LARGE_VALUE };
92 bound(bounds.l, bounds.b, bounds.r, bounds.t);
93 if (border > 0) {
94 bounds.l -= border, bounds.b -= border;
95 bounds.r += border, bounds.t += border;
96 if (miterLimit > 0)
97 boundMiters(bounds.l, bounds.b, bounds.r, bounds.t, border, miterLimit, polarity);
98 }
99 return bounds;
100}
101
102void Shape::scanline(Scanline &line, double y) const {
103 std::vector<Scanline::Intersection> intersections;
104 double x[3];
105 int dy[3];
106 for (std::vector<Contour>::const_iterator contour = contours.begin(); contour != contours.end(); ++contour) {
107 for (std::vector<EdgeHolder>::const_iterator edge = contour->edges.begin(); edge != contour->edges.end(); ++edge) {
108 int n = (*edge)->scanlineIntersections(x, dy, y);
109 for (int i = 0; i < n; ++i) {
110 Scanline::Intersection intersection = { x[i], dy[i] };
111 intersections.push_back(intersection);
112 }
113 }
114 }
115#ifdef MSDFGEN_USE_CPP11
116 line.setIntersections((std::vector<Scanline::Intersection> &&) intersections);
117#else
118 line.setIntersections(intersections);
119#endif
120}
121
122int Shape::edgeCount() const {
123 int total = 0;
124 for (std::vector<Contour>::const_iterator contour = contours.begin(); contour != contours.end(); ++contour)
125 total += (int) contour->edges.size();
126 return total;
127}
128
129void Shape::orientContours() {
130 struct Intersection {
131 double x;
132 int direction;
133 int contourIndex;
134
135 static int compare(const void *a, const void *b) {
136 return sign(reinterpret_cast<const Intersection *>(a)->x-reinterpret_cast<const Intersection *>(b)->x);
137 }
138 };
139
140 const double ratio = .5*(sqrt(5)-1); // an irrational number to minimize chance of intersecting a corner or other point of interest
141 std::vector<int> orientations(contours.size());
142 std::vector<Intersection> intersections;
143 for (int i = 0; i < (int) contours.size(); ++i) {
144 if (!orientations[i] && !contours[i].edges.empty()) {
145 // Find an Y that crosses the contour
146 double y0 = contours[i].edges.front()->point(0).y;
147 double y1 = y0;
148 for (std::vector<EdgeHolder>::const_iterator edge = contours[i].edges.begin(); edge != contours[i].edges.end() && y0 == y1; ++edge)
149 y1 = (*edge)->point(1).y;
150 for (std::vector<EdgeHolder>::const_iterator edge = contours[i].edges.begin(); edge != contours[i].edges.end() && y0 == y1; ++edge)
151 y1 = (*edge)->point(ratio).y; // in case all endpoints are in a horizontal line
152 double y = mix(y0, y1, ratio);
153 // Scanline through whole shape at Y
154 double x[3];
155 int dy[3];
156 for (int j = 0; j < (int) contours.size(); ++j) {
157 for (std::vector<EdgeHolder>::const_iterator edge = contours[j].edges.begin(); edge != contours[j].edges.end(); ++edge) {
158 int n = (*edge)->scanlineIntersections(x, dy, y);
159 for (int k = 0; k < n; ++k) {
160 Intersection intersection = { x[k], dy[k], j };
161 intersections.push_back(intersection);
162 }
163 }
164 }
165 qsort(&intersections[0], intersections.size(), sizeof(Intersection), &Intersection::compare);
166 // Disqualify multiple intersections
167 for (int j = 1; j < (int) intersections.size(); ++j)
168 if (intersections[j].x == intersections[j-1].x)
169 intersections[j].direction = intersections[j-1].direction = 0;
170 // Inspect scanline and deduce orientations of intersected contours
171 for (int j = 0; j < (int) intersections.size(); ++j)
172 if (intersections[j].direction)
173 orientations[intersections[j].contourIndex] += 2*((j&1)^(intersections[j].direction > 0))-1;
174 intersections.clear();
175 }
176 }
177 // Reverse contours that have the opposite orientation
178 for (int i = 0; i < (int) contours.size(); ++i)
179 if (orientations[i] < 0)
180 contours[i].reverse();
181}
182
183}
184