| 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 |