1 | |
---|---|
2 | #include "contour-combiners.h" |
3 | |
4 | #include <cfloat> |
5 | #include "arithmetics.hpp" |
6 | |
7 | namespace msdfgen { |
8 | |
9 | static void initDistance(double &distance) { |
10 | distance = -DBL_MAX; |
11 | } |
12 | |
13 | static void initDistance(MultiDistance &distance) { |
14 | distance.r = -DBL_MAX; |
15 | distance.g = -DBL_MAX; |
16 | distance.b = -DBL_MAX; |
17 | } |
18 | |
19 | static double resolveDistance(double distance) { |
20 | return distance; |
21 | } |
22 | |
23 | static double resolveDistance(const MultiDistance &distance) { |
24 | return median(distance.r, distance.g, distance.b); |
25 | } |
26 | |
27 | template <class EdgeSelector> |
28 | SimpleContourCombiner<EdgeSelector>::SimpleContourCombiner(const Shape &shape) { } |
29 | |
30 | template <class EdgeSelector> |
31 | void SimpleContourCombiner<EdgeSelector>::reset(const Point2 &p) { |
32 | shapeEdgeSelector.reset(p); |
33 | } |
34 | |
35 | template <class EdgeSelector> |
36 | EdgeSelector & SimpleContourCombiner<EdgeSelector>::edgeSelector(int) { |
37 | return shapeEdgeSelector; |
38 | } |
39 | |
40 | template <class EdgeSelector> |
41 | typename SimpleContourCombiner<EdgeSelector>::DistanceType SimpleContourCombiner<EdgeSelector>::distance() const { |
42 | return shapeEdgeSelector.distance(); |
43 | } |
44 | |
45 | template class SimpleContourCombiner<TrueDistanceSelector>; |
46 | template class SimpleContourCombiner<PseudoDistanceSelector>; |
47 | template class SimpleContourCombiner<MultiDistanceSelector>; |
48 | template class SimpleContourCombiner<MultiAndTrueDistanceSelector>; |
49 | |
50 | template <class EdgeSelector> |
51 | OverlappingContourCombiner<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 | |
58 | template <class EdgeSelector> |
59 | void 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 | |
65 | template <class EdgeSelector> |
66 | EdgeSelector & OverlappingContourCombiner<EdgeSelector>::edgeSelector(int i) { |
67 | return edgeSelectors[i]; |
68 | } |
69 | |
70 | template <class EdgeSelector> |
71 | typename 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 | |
129 | template class OverlappingContourCombiner<TrueDistanceSelector>; |
130 | template class OverlappingContourCombiner<PseudoDistanceSelector>; |
131 | template class OverlappingContourCombiner<MultiDistanceSelector>; |
132 | template class OverlappingContourCombiner<MultiAndTrueDistanceSelector>; |
133 | |
134 | } |
135 |