فهرست منبع

Core algorithm performance optimization

Viktor Chlumský 5 سال پیش
والد
کامیت
8ebb37da4e
7فایلهای تغییر یافته به همراه172 افزوده شده و 69 حذف شده
  1. 7 0
      core/Shape.cpp
  2. 2 0
      core/Shape.h
  3. 24 15
      core/contour-combiners.cpp
  4. 3 5
      core/contour-combiners.h
  5. 101 36
      core/edge-selectors.cpp
  6. 26 8
      core/edge-selectors.h
  7. 9 5
      core/msdfgen.cpp

+ 7 - 0
core/Shape.cpp

@@ -91,4 +91,11 @@ void Shape::scanline(Scanline &line, double y) const {
 #endif
 }
 
+int Shape::edgeCount() const {
+    int total = 0;
+    for (std::vector<Contour>::const_iterator contour = contours.begin(); contour != contours.end(); ++contour)
+        total += contour->edges.size();
+    return total;
+}
+
 }

+ 2 - 0
core/Shape.h

@@ -40,6 +40,8 @@ public:
     Bounds getBounds(double border = 0, double miterLimit = 0, int polarity = 0) const;
     /// Outputs the scanline that intersects the shape at y.
     void scanline(Scanline &line, double y) const;
+    /// Returns the total number of edge segments
+    int edgeCount() const;
 
 };
 

+ 24 - 15
core/contour-combiners.cpp

@@ -28,12 +28,12 @@ SimpleContourCombiner<EdgeSelector>::SimpleContourCombiner(const Shape &shape) {
 
 template <class EdgeSelector>
 void SimpleContourCombiner<EdgeSelector>::reset(const Point2 &p) {
-    shapeEdgeSelector = EdgeSelector(p);
+    shapeEdgeSelector.reset(p);
 }
 
 template <class EdgeSelector>
-void SimpleContourCombiner<EdgeSelector>::setContourEdgeSelection(int i, const EdgeSelector &edgeSelector) {
-    shapeEdgeSelector.merge(edgeSelector);
+EdgeSelector & SimpleContourCombiner<EdgeSelector>::edgeSelector(int) {
+    return shapeEdgeSelector;
 }
 
 template <class EdgeSelector>
@@ -56,24 +56,34 @@ OverlappingContourCombiner<EdgeSelector>::OverlappingContourCombiner(const Shape
 
 template <class EdgeSelector>
 void OverlappingContourCombiner<EdgeSelector>::reset(const Point2 &p) {
-    shapeEdgeSelector = EdgeSelector(p);
-    innerEdgeSelector = EdgeSelector(p);
-    outerEdgeSelector = EdgeSelector(p);
+    this->p = p;
+    for (std::vector<EdgeSelector>::iterator contourEdgeSelector = edgeSelectors.begin(); contourEdgeSelector != edgeSelectors.end(); ++contourEdgeSelector)
+        contourEdgeSelector->reset(p);
 }
 
 template <class EdgeSelector>
-void OverlappingContourCombiner<EdgeSelector>::setContourEdgeSelection(int i, const EdgeSelector &edgeSelector) {
-    DistanceType edgeDistance = edgeSelector.distance();
-    edgeSelectors[i] = edgeSelector;
-    shapeEdgeSelector.merge(edgeSelector);
-    if (windings[i] > 0 && resolveDistance(edgeDistance) >= 0)
-        innerEdgeSelector.merge(edgeSelector);
-    if (windings[i] < 0 && resolveDistance(edgeDistance) <= 0)
-        outerEdgeSelector.merge(edgeSelector);
+EdgeSelector & OverlappingContourCombiner<EdgeSelector>::edgeSelector(int i) {
+    return edgeSelectors[i];
 }
 
 template <class EdgeSelector>
 typename OverlappingContourCombiner<EdgeSelector>::DistanceType OverlappingContourCombiner<EdgeSelector>::distance() const {
+    int contourCount = (int) edgeSelectors.size();
+    EdgeSelector shapeEdgeSelector;
+    EdgeSelector innerEdgeSelector;
+    EdgeSelector outerEdgeSelector;
+    shapeEdgeSelector.reset(p);
+    innerEdgeSelector.reset(p);
+    outerEdgeSelector.reset(p);
+    for (int i = 0; i < contourCount; ++i) {
+        DistanceType edgeDistance = edgeSelectors[i].distance();
+        shapeEdgeSelector.merge(edgeSelectors[i]);
+        if (windings[i] > 0 && resolveDistance(edgeDistance) >= 0)
+            innerEdgeSelector.merge(edgeSelectors[i]);
+        if (windings[i] < 0 && resolveDistance(edgeDistance) <= 0)
+            outerEdgeSelector.merge(edgeSelectors[i]);
+    }
+
     DistanceType shapeDistance = shapeEdgeSelector.distance();
     DistanceType innerDistance = innerEdgeSelector.distance();
     DistanceType outerDistance = outerEdgeSelector.distance();
@@ -81,7 +91,6 @@ typename OverlappingContourCombiner<EdgeSelector>::DistanceType OverlappingConto
     double outerScalarDistance = resolveDistance(outerDistance);
     DistanceType distance;
     initDistance(distance);
-    int contourCount = (int) windings.size();
 
     int winding = 0;
     if (innerScalarDistance >= 0 && fabs(innerScalarDistance) <= fabs(outerScalarDistance)) {

+ 3 - 5
core/contour-combiners.h

@@ -16,7 +16,7 @@ public:
 
     explicit SimpleContourCombiner(const Shape &shape);
     void reset(const Point2 &p);
-    void setContourEdgeSelection(int i, const EdgeSelector &edgeSelector);
+    EdgeSelector & edgeSelector(int i);
     DistanceType distance() const;
 
 private:
@@ -34,15 +34,13 @@ public:
 
     explicit OverlappingContourCombiner(const Shape &shape);
     void reset(const Point2 &p);
-    void setContourEdgeSelection(int i, const EdgeSelector &edgeSelector);
+    EdgeSelector & edgeSelector(int i);
     DistanceType distance() const;
 
 private:
+    Point2 p;
     std::vector<int> windings;
     std::vector<EdgeSelector> edgeSelectors;
-    EdgeSelector shapeEdgeSelector;
-    EdgeSelector innerEdgeSelector;
-    EdgeSelector outerEdgeSelector;
 
 };
 

+ 101 - 36
core/edge-selectors.cpp

@@ -1,15 +1,30 @@
 
 #include "edge-selectors.h"
 
+#include "arithmetics.hpp"
+
 namespace msdfgen {
 
-TrueDistanceSelector::TrueDistanceSelector(const Point2 &p) : p(p) { }
+#define DISTANCE_DELTA_FACTOR 1.001
+
+TrueDistanceSelector::EdgeCache::EdgeCache() : absDistance(0) { }
 
-void TrueDistanceSelector::addEdge(const EdgeSegment *prevEdge, const EdgeSegment *edge, const EdgeSegment *nextEdge) {
-    double dummy;
-    SignedDistance distance = edge->signedDistance(p, dummy);
-    if (distance < minDistance)
-        minDistance = distance;
+void TrueDistanceSelector::reset(const Point2 &p) {
+    double delta = DISTANCE_DELTA_FACTOR*(p-this->p).length();
+    minDistance.distance += nonZeroSign(minDistance.distance)*delta;
+    this->p = p;
+}
+
+void TrueDistanceSelector::addEdge(EdgeCache &cache, const EdgeSegment *prevEdge, const EdgeSegment *edge, const EdgeSegment *nextEdge) {
+    double delta = DISTANCE_DELTA_FACTOR*(p-cache.point).length();
+    if (cache.absDistance-delta <= fabs(minDistance.distance)) {
+        double dummy;
+        SignedDistance distance = edge->signedDistance(p, dummy);
+        if (distance < minDistance)
+            minDistance = distance;
+        cache.point = p;
+        cache.absDistance = fabs(distance.distance);
+    }
 }
 
 void TrueDistanceSelector::merge(const TrueDistanceSelector &other) {
@@ -21,24 +36,48 @@ TrueDistanceSelector::DistanceType TrueDistanceSelector::distance() const {
     return minDistance.distance;
 }
 
-bool PseudoDistanceSelectorBase::pointFacingEdge(const EdgeSegment *prevEdge, const EdgeSegment *edge, const EdgeSegment *nextEdge, const Point2 &p, double param) {
+PseudoDistanceSelectorBase::EdgeCache::EdgeCache() : absDistance(0), edgeDomainDistance(0), pseudoDistance(0) { }
+
+double PseudoDistanceSelectorBase::edgeDomainDistance(const EdgeSegment *prevEdge, const EdgeSegment *edge, const EdgeSegment *nextEdge, const Point2 &p, double param) {
     if (param < 0) {
         Vector2 prevEdgeDir = -prevEdge->direction(1).normalize(true);
         Vector2 edgeDir = edge->direction(0).normalize(true);
         Vector2 pointDir = p-edge->point(0);
-        return dotProduct(pointDir, edgeDir) >= dotProduct(pointDir, prevEdgeDir);
+        return dotProduct(pointDir, (prevEdgeDir-edgeDir).normalize(true));
     }
     if (param > 1) {
         Vector2 edgeDir = -edge->direction(1).normalize(true);
         Vector2 nextEdgeDir = nextEdge->direction(0).normalize(true);
         Vector2 pointDir = p-edge->point(1);
-        return dotProduct(pointDir, edgeDir) >= dotProduct(pointDir, nextEdgeDir);
+        return dotProduct(pointDir, (nextEdgeDir-edgeDir).normalize(true));
     }
-    return true;
+    return 0;
 }
 
 PseudoDistanceSelectorBase::PseudoDistanceSelectorBase() : nearEdge(NULL), nearEdgeParam(0) { }
 
+void PseudoDistanceSelectorBase::reset(double delta) {
+    minTrueDistance.distance += nonZeroSign(minTrueDistance.distance)*delta;
+    minNegativePseudoDistance.distance = -fabs(minTrueDistance.distance);
+    minPositivePseudoDistance.distance = fabs(minTrueDistance.distance);
+    nearEdge = NULL;
+    nearEdgeParam = 0;
+}
+
+bool PseudoDistanceSelectorBase::isEdgeRelevant(const EdgeCache &cache, const EdgeSegment *edge, const Point2 &p) const {
+    double delta = DISTANCE_DELTA_FACTOR*(p-cache.point).length();
+    return (
+        cache.absDistance-delta <= fabs(minTrueDistance.distance) ||
+        (cache.edgeDomainDistance > 0 ?
+            cache.edgeDomainDistance-delta <= 0 :
+            (cache.pseudoDistance < 0 ?
+                cache.pseudoDistance+delta >= minNegativePseudoDistance.distance :
+                cache.pseudoDistance-delta <= minPositivePseudoDistance.distance
+            )
+        )
+    );
+}
+
 void PseudoDistanceSelectorBase::addEdgeTrueDistance(const EdgeSegment *edge, const SignedDistance &distance, double param) {
     if (distance < minTrueDistance) {
         minTrueDistance = distance;
@@ -80,15 +119,26 @@ SignedDistance PseudoDistanceSelectorBase::trueDistance() const {
     return minTrueDistance;
 }
 
-PseudoDistanceSelector::PseudoDistanceSelector(const Point2 &p) : p(p) { }
-
-void PseudoDistanceSelector::addEdge(const EdgeSegment *prevEdge, const EdgeSegment *edge, const EdgeSegment *nextEdge) {
-    double param;
-    SignedDistance distance = edge->signedDistance(p, param);
-    addEdgeTrueDistance(edge, distance, param);
-    if (pointFacingEdge(prevEdge, edge, nextEdge, p, param)) {
-        edge->distanceToPseudoDistance(distance, p, param);
-        addEdgePseudoDistance(distance);
+void PseudoDistanceSelector::reset(const Point2 &p) {
+    double delta = DISTANCE_DELTA_FACTOR*(p-this->p).length();
+    PseudoDistanceSelectorBase::reset(delta);
+    this->p = p;
+}
+
+void PseudoDistanceSelector::addEdge(EdgeCache &cache, const EdgeSegment *prevEdge, const EdgeSegment *edge, const EdgeSegment *nextEdge) {
+    if (isEdgeRelevant(cache, edge, p)) {
+        double param;
+        SignedDistance distance = edge->signedDistance(p, param);
+        double edd = edgeDomainDistance(prevEdge, edge, nextEdge, p, param);
+        addEdgeTrueDistance(edge, distance, param);
+        cache.point = p;
+        cache.absDistance = fabs(distance.distance);
+        cache.edgeDomainDistance = edd;
+        if (edd <= 0) {
+            edge->distanceToPseudoDistance(distance, p, param);
+            addEdgePseudoDistance(distance);
+            cache.pseudoDistance = distance.distance;
+        }
     }
 }
 
@@ -96,25 +146,42 @@ PseudoDistanceSelector::DistanceType PseudoDistanceSelector::distance() const {
     return computeDistance(p);
 }
 
-MultiDistanceSelector::MultiDistanceSelector(const Point2 &p) : p(p) { }
+void MultiDistanceSelector::reset(const Point2 &p) {
+    double delta = DISTANCE_DELTA_FACTOR*(p-this->p).length();
+    r.reset(delta);
+    g.reset(delta);
+    b.reset(delta);
+    this->p = p;
+}
 
-void MultiDistanceSelector::addEdge(const EdgeSegment *prevEdge, const EdgeSegment *edge, const EdgeSegment *nextEdge) {
-    double param;
-    SignedDistance distance = edge->signedDistance(p, param);
-    if (edge->color&RED)
-        r.addEdgeTrueDistance(edge, distance, param);
-    if (edge->color&GREEN)
-        g.addEdgeTrueDistance(edge, distance, param);
-    if (edge->color&BLUE)
-        b.addEdgeTrueDistance(edge, distance, param);
-    if (PseudoDistanceSelectorBase::pointFacingEdge(prevEdge, edge, nextEdge, p, param)) {
-        edge->distanceToPseudoDistance(distance, p, param);
+void MultiDistanceSelector::addEdge(EdgeCache &cache, const EdgeSegment *prevEdge, const EdgeSegment *edge, const EdgeSegment *nextEdge) {
+    if (
+        (edge->color&RED && r.isEdgeRelevant(cache, edge, p)) ||
+        (edge->color&GREEN && g.isEdgeRelevant(cache, edge, p)) ||
+        (edge->color&BLUE && b.isEdgeRelevant(cache, edge, p))
+    ) {
+        double param;
+        SignedDistance distance = edge->signedDistance(p, param);
+        double edd = PseudoDistanceSelectorBase::edgeDomainDistance(prevEdge, edge, nextEdge, p, param);
         if (edge->color&RED)
-            r.addEdgePseudoDistance(distance);
+            r.addEdgeTrueDistance(edge, distance, param);
         if (edge->color&GREEN)
-            g.addEdgePseudoDistance(distance);
+            g.addEdgeTrueDistance(edge, distance, param);
         if (edge->color&BLUE)
-            b.addEdgePseudoDistance(distance);
+            b.addEdgeTrueDistance(edge, distance, param);
+        cache.point = p;
+        cache.absDistance = fabs(distance.distance);
+        cache.edgeDomainDistance = edd;
+        if (edd <= 0) {
+            edge->distanceToPseudoDistance(distance, p, param);
+            if (edge->color&RED)
+                r.addEdgePseudoDistance(distance);
+            if (edge->color&GREEN)
+                g.addEdgePseudoDistance(distance);
+            if (edge->color&BLUE)
+                b.addEdgePseudoDistance(distance);
+            cache.pseudoDistance = distance.distance;
+        }
     }
 }
 
@@ -141,8 +208,6 @@ SignedDistance MultiDistanceSelector::trueDistance() const {
     return distance;
 }
 
-MultiAndTrueDistanceSelector::MultiAndTrueDistanceSelector(const Point2 &p) : MultiDistanceSelector(p) { }
-
 MultiAndTrueDistanceSelector::DistanceType MultiAndTrueDistanceSelector::distance() const {
     MultiDistance multiDistance = MultiDistanceSelector::distance();
     MultiAndTrueDistance mtd;

+ 26 - 8
core/edge-selectors.h

@@ -20,8 +20,15 @@ class TrueDistanceSelector {
 public:
     typedef double DistanceType;
 
-    explicit TrueDistanceSelector(const Point2 &p = Point2());
-    void addEdge(const EdgeSegment *prevEdge, const EdgeSegment *edge, const EdgeSegment *nextEdge);
+    struct EdgeCache {
+        Point2 point;
+        double absDistance;
+
+        EdgeCache();
+    };
+
+    void reset(const Point2 &p);
+    void addEdge(EdgeCache &cache, const EdgeSegment *prevEdge, const EdgeSegment *edge, const EdgeSegment *nextEdge);
     void merge(const TrueDistanceSelector &other);
     DistanceType distance() const;
 
@@ -34,9 +41,20 @@ private:
 class PseudoDistanceSelectorBase {
 
 public:
-    static bool pointFacingEdge(const EdgeSegment *prevEdge, const EdgeSegment *edge, const EdgeSegment *nextEdge, const Point2 &p, double param);
+    struct EdgeCache {
+        Point2 point;
+        double absDistance;
+        double edgeDomainDistance;
+        double pseudoDistance;
+
+        EdgeCache();
+    };
+
+    static double edgeDomainDistance(const EdgeSegment *prevEdge, const EdgeSegment *edge, const EdgeSegment *nextEdge, const Point2 &p, double param);
 
     PseudoDistanceSelectorBase();
+    void reset(double delta);
+    bool isEdgeRelevant(const EdgeCache &cache, const EdgeSegment *edge, const Point2 &p) const;
     void addEdgeTrueDistance(const EdgeSegment *edge, const SignedDistance &distance, double param);
     void addEdgePseudoDistance(const SignedDistance &distance);
     void merge(const PseudoDistanceSelectorBase &other);
@@ -58,8 +76,8 @@ class PseudoDistanceSelector : public PseudoDistanceSelectorBase {
 public:
     typedef double DistanceType;
 
-    explicit PseudoDistanceSelector(const Point2 &p = Point2());
-    void addEdge(const EdgeSegment *prevEdge, const EdgeSegment *edge, const EdgeSegment *nextEdge);
+    void reset(const Point2 &p);
+    void addEdge(EdgeCache &cache, const EdgeSegment *prevEdge, const EdgeSegment *edge, const EdgeSegment *nextEdge);
     DistanceType distance() const;
 
 private:
@@ -72,9 +90,10 @@ class MultiDistanceSelector {
 
 public:
     typedef MultiDistance DistanceType;
+    typedef PseudoDistanceSelectorBase::EdgeCache EdgeCache;
 
-    explicit MultiDistanceSelector(const Point2 &p = Point2());
-    void addEdge(const EdgeSegment *prevEdge, const EdgeSegment *edge, const EdgeSegment *nextEdge);
+    void reset(const Point2 &p);
+    void addEdge(EdgeCache &cache, const EdgeSegment *prevEdge, const EdgeSegment *edge, const EdgeSegment *nextEdge);
     void merge(const MultiDistanceSelector &other);
     DistanceType distance() const;
     SignedDistance trueDistance() const;
@@ -91,7 +110,6 @@ class MultiAndTrueDistanceSelector : public MultiDistanceSelector {
 public:
     typedef MultiAndTrueDistance DistanceType;
 
-    explicit MultiAndTrueDistanceSelector(const Point2 &p = Point2());
     DistanceType distance() const;
 
 };

+ 9 - 5
core/msdfgen.cpp

@@ -44,11 +44,14 @@ public:
 
 template <class ContourCombiner>
 void generateDistanceField(const typename DistancePixelConversion<typename ContourCombiner::DistanceType>::BitmapRefType &output, const Shape &shape, double range, const Vector2 &scale, const Vector2 &translate) {
+    int edgeCount = shape.edgeCount();
 #ifdef MSDFGEN_USE_OPENMP
     #pragma omp parallel
 #endif
     {
         ContourCombiner contourCombiner(shape);
+        std::vector<typename ContourCombiner::EdgeSelectorType::EdgeCache> shapeEdgeCache(edgeCount);
+        bool rightToLeft = false;
         Point2 p;
 #ifdef MSDFGEN_USE_OPENMP
         #pragma omp for
@@ -56,31 +59,32 @@ void generateDistanceField(const typename DistancePixelConversion<typename Conto
         for (int y = 0; y < output.height; ++y) {
             int row = shape.inverseYAxis ? output.height-y-1 : y;
             p.y = (y+.5)/scale.y-translate.y;
-            for (int x = 0; x < output.width; ++x) {
+            for (int col = 0; col < output.width; ++col) {
+                int x = rightToLeft ? output.width-col-1 : col;
                 p.x = (x+.5)/scale.x-translate.x;
 
                 contourCombiner.reset(p);
+                typename ContourCombiner::EdgeSelectorType::EdgeCache *edgeCache = &shapeEdgeCache[0];
 
                 for (std::vector<Contour>::const_iterator contour = shape.contours.begin(); contour != shape.contours.end(); ++contour) {
                     if (!contour->edges.empty()) {
-                        typename ContourCombiner::EdgeSelectorType edgeSelector(p);
+                        typename ContourCombiner::EdgeSelectorType &edgeSelector = contourCombiner.edgeSelector(int(contour-shape.contours.begin()));
 
                         const EdgeSegment *prevEdge = contour->edges.size() >= 2 ? *(contour->edges.end()-2) : *contour->edges.begin();
                         const EdgeSegment *curEdge = contour->edges.back();
                         for (std::vector<EdgeHolder>::const_iterator edge = contour->edges.begin(); edge != contour->edges.end(); ++edge) {
                             const EdgeSegment *nextEdge = *edge;
-                            edgeSelector.addEdge(prevEdge, curEdge, nextEdge);
+                            edgeSelector.addEdge(*edgeCache++, prevEdge, curEdge, nextEdge);
                             prevEdge = curEdge;
                             curEdge = nextEdge;
                         }
-
-                        contourCombiner.setContourEdgeSelection(int(contour-shape.contours.begin()), edgeSelector);
                     }
                 }
 
                 typename ContourCombiner::DistanceType distance = contourCombiner.distance();
                 DistancePixelConversion<typename ContourCombiner::DistanceType>::convert(output(x, row), distance, range);
             }
+            rightToLeft = !rightToLeft;
         }
     }
 }