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