1
2#include "contour-combiners.h"
3
4#include <cfloat>
5#include "arithmetics.hpp"
6
7namespace msdfgen {
8
9static void initDistance(double &distance) {
10 distance = -DBL_MAX;
11}
12
13static void initDistance(MultiDistance &distance) {
14 distance.r = -DBL_MAX;
15 distance.g = -DBL_MAX;
16 distance.b = -DBL_MAX;
17}
18
19static double resolveDistance(double distance) {
20 return distance;
21}
22
23static double resolveDistance(const MultiDistance &distance) {
24 return median(distance.r, distance.g, distance.b);
25}
26
27template <class EdgeSelector>
28SimpleContourCombiner<EdgeSelector>::SimpleContourCombiner(const Shape &shape) { }
29
30template <class EdgeSelector>
31void SimpleContourCombiner<EdgeSelector>::reset(const Point2 &p) {
32 shapeEdgeSelector.reset(p);
33}
34
35template <class EdgeSelector>
36EdgeSelector & SimpleContourCombiner<EdgeSelector>::edgeSelector(int) {
37 return shapeEdgeSelector;
38}
39
40template <class EdgeSelector>
41typename SimpleContourCombiner<EdgeSelector>::DistanceType SimpleContourCombiner<EdgeSelector>::distance() const {
42 return shapeEdgeSelector.distance();
43}
44
45template class SimpleContourCombiner<TrueDistanceSelector>;
46template class SimpleContourCombiner<PseudoDistanceSelector>;
47template class SimpleContourCombiner<MultiDistanceSelector>;
48template class SimpleContourCombiner<MultiAndTrueDistanceSelector>;
49
50template <class EdgeSelector>
51OverlappingContourCombiner<EdgeSelector>::OverlappingContourCombiner(const Shape &shape) {
52 windings.reserve(shape.contours.size());
53 for (std::vector<Contour>::const_iterator contour = shape.contours.begin(); contour != shape.contours.end(); ++contour)
54 windings.push_back(contour->winding());
55 edgeSelectors.resize(shape.contours.size());
56}
57
58template <class EdgeSelector>
59void OverlappingContourCombiner<EdgeSelector>::reset(const Point2 &p) {
60 this->p = p;
61 for (typename std::vector<EdgeSelector>::iterator contourEdgeSelector = edgeSelectors.begin(); contourEdgeSelector != edgeSelectors.end(); ++contourEdgeSelector)
62 contourEdgeSelector->reset(p);
63}
64
65template <class EdgeSelector>
66EdgeSelector & OverlappingContourCombiner<EdgeSelector>::edgeSelector(int i) {
67 return edgeSelectors[i];
68}
69
70template <class EdgeSelector>
71typename OverlappingContourCombiner<EdgeSelector>::DistanceType OverlappingContourCombiner<EdgeSelector>::distance() const {
72 int contourCount = (int) edgeSelectors.size();
73 EdgeSelector shapeEdgeSelector;
74 EdgeSelector innerEdgeSelector;
75 EdgeSelector outerEdgeSelector;
76 shapeEdgeSelector.reset(p);
77 innerEdgeSelector.reset(p);
78 outerEdgeSelector.reset(p);
79 for (int i = 0; i < contourCount; ++i) {
80 DistanceType edgeDistance = edgeSelectors[i].distance();
81 shapeEdgeSelector.merge(edgeSelectors[i]);
82 if (windings[i] > 0 && resolveDistance(edgeDistance) >= 0)
83 innerEdgeSelector.merge(edgeSelectors[i]);
84 if (windings[i] < 0 && resolveDistance(edgeDistance) <= 0)
85 outerEdgeSelector.merge(edgeSelectors[i]);
86 }
87
88 DistanceType shapeDistance = shapeEdgeSelector.distance();
89 DistanceType innerDistance = innerEdgeSelector.distance();
90 DistanceType outerDistance = outerEdgeSelector.distance();
91 double innerScalarDistance = resolveDistance(innerDistance);
92 double outerScalarDistance = resolveDistance(outerDistance);
93 DistanceType distance;
94 initDistance(distance);
95
96 int winding = 0;
97 if (innerScalarDistance >= 0 && fabs(innerScalarDistance) <= fabs(outerScalarDistance)) {
98 distance = innerDistance;
99 winding = 1;
100 for (int i = 0; i < contourCount; ++i)
101 if (windings[i] > 0) {
102 DistanceType contourDistance = edgeSelectors[i].distance();
103 if (fabs(resolveDistance(contourDistance)) < fabs(outerScalarDistance) && resolveDistance(contourDistance) > resolveDistance(distance))
104 distance = contourDistance;
105 }
106 } else if (outerScalarDistance <= 0 && fabs(outerScalarDistance) < fabs(innerScalarDistance)) {
107 distance = outerDistance;
108 winding = -1;
109 for (int i = 0; i < contourCount; ++i)
110 if (windings[i] < 0) {
111 DistanceType contourDistance = edgeSelectors[i].distance();
112 if (fabs(resolveDistance(contourDistance)) < fabs(innerScalarDistance) && resolveDistance(contourDistance) < resolveDistance(distance))
113 distance = contourDistance;
114 }
115 } else
116 return shapeDistance;
117
118 for (int i = 0; i < contourCount; ++i)
119 if (windings[i] != winding) {
120 DistanceType contourDistance = edgeSelectors[i].distance();
121 if (resolveDistance(contourDistance)*resolveDistance(distance) >= 0 && fabs(resolveDistance(contourDistance)) < fabs(resolveDistance(distance)))
122 distance = contourDistance;
123 }
124 if (resolveDistance(distance) == resolveDistance(shapeDistance))
125 distance = shapeDistance;
126 return distance;
127}
128
129template class OverlappingContourCombiner<TrueDistanceSelector>;
130template class OverlappingContourCombiner<PseudoDistanceSelector>;
131template class OverlappingContourCombiner<MultiDistanceSelector>;
132template class OverlappingContourCombiner<MultiAndTrueDistanceSelector>;
133
134}
135