2
0
Viktor Chlumský 5 жил өмнө
parent
commit
fd50406d67

+ 12 - 10
core/Contour.cpp

@@ -24,30 +24,32 @@ EdgeHolder & Contour::addEdge() {
     return edges.back();
 }
 
-static void pointBounds(Point2 p, double &l, double &b, double &r, double &t) {
+static void boundPoint(double &l, double &b, double &r, double &t, Point2 p) {
     if (p.x < l) l = p.x;
     if (p.y < b) b = p.y;
     if (p.x > r) r = p.x;
     if (p.y > t) t = p.y;
 }
 
-void Contour::bounds(double &l, double &b, double &r, double &t) const {
+void Contour::bound(double &l, double &b, double &r, double &t) const {
     for (std::vector<EdgeHolder>::const_iterator edge = edges.begin(); edge != edges.end(); ++edge)
-        (*edge)->bounds(l, b, r, t);
+        (*edge)->bound(l, b, r, t);
 }
 
-void Contour::miterBounds(double &l, double &b, double &r, double &t, double border, double miterLimit) const {
+void Contour::boundMiters(double &l, double &b, double &r, double &t, double border, double miterLimit, int polarity) const {
     if (edges.empty())
         return;
     Vector2 prevDir = edges.back()->direction(1).normalize(true);
     for (std::vector<EdgeHolder>::const_iterator edge = edges.begin(); edge != edges.end(); ++edge) {
         Vector2 dir = -(*edge)->direction(0).normalize(true);
-        double miterLength = miterLimit;
-        double q = .5*(1-dotProduct(prevDir, dir));
-        if (q > 0)
-            miterLength = min(1/sqrt(q), miterLimit);
-        Point2 miter = (*edge)->point(0)+border*miterLength*(prevDir+dir).normalize(true);
-        pointBounds(miter, l, b, r, t);
+        if (polarity*crossProduct(prevDir, dir) >= 0) {
+            double miterLength = miterLimit;
+            double q = .5*(1-dotProduct(prevDir, dir));
+            if (q > 0)
+                miterLength = min(1/sqrt(q), miterLimit);
+            Point2 miter = (*edge)->point(0)+border*miterLength*(prevDir+dir).normalize(true);
+            boundPoint(l, b, r, t, miter);
+        }
         prevDir = (*edge)->direction(1).normalize(true);
     }
 }

+ 2 - 2
core/Contour.h

@@ -21,9 +21,9 @@ public:
     /// Creates a new edge in the contour and returns its reference.
     EdgeHolder & addEdge();
     /// Adjusts the bounding box to fit the contour.
-    void bounds(double &l, double &b, double &r, double &t) const;
+    void bound(double &l, double &b, double &r, double &t) const;
     /// Adjusts the bounding box to fit the contour border's mitered corners.
-    void miterBounds(double &l, double &b, double &r, double &t, double border, double miterLimit) const;
+    void boundMiters(double &l, double &b, double &r, double &t, double border, double miterLimit, int polarity) const;
     /// Computes the winding of the contour. Returns 1 if positive, -1 if negative.
     int winding() const;
 

+ 17 - 4
core/Shape.cpp

@@ -48,14 +48,27 @@ void Shape::normalize() {
         }
 }
 
-void Shape::bounds(double &l, double &b, double &r, double &t) const {
+void Shape::bound(double &l, double &b, double &r, double &t) const {
     for (std::vector<Contour>::const_iterator contour = contours.begin(); contour != contours.end(); ++contour)
-        contour->bounds(l, b, r, t);
+        contour->bound(l, b, r, t);
 }
 
-void Shape::miterBounds(double &l, double &b, double &r, double &t, double border, double miterLimit) const {
+void Shape::boundMiters(double &l, double &b, double &r, double &t, double border, double miterLimit, int polarity) const {
     for (std::vector<Contour>::const_iterator contour = contours.begin(); contour != contours.end(); ++contour)
-        contour->miterBounds(l, b, r, t, border, miterLimit);
+        contour->boundMiters(l, b, r, t, border, miterLimit, polarity);
+}
+
+Shape::Bounds Shape::getBounds(double border, double miterLimit, int polarity) const {
+    static const double LARGE_VALUE = 1e240;
+    Shape::Bounds bounds = { +LARGE_VALUE, +LARGE_VALUE, -LARGE_VALUE, -LARGE_VALUE };
+    bound(bounds.l, bounds.b, bounds.r, bounds.t);
+    if (border > 0) {
+        bounds.l -= border, bounds.b -= border;
+        bounds.r += border, bounds.t += border;
+        if (miterLimit > 0)
+            boundMiters(bounds.l, bounds.b, bounds.r, bounds.t, border, miterLimit, polarity);
+    }
+    return bounds;
 }
 
 void Shape::scanline(Scanline &line, double y) const {

+ 8 - 2
core/Shape.h

@@ -11,6 +11,10 @@ namespace msdfgen {
 class Shape {
 
 public:
+    struct Bounds {
+        double l, b, r, t;
+    };
+
     /// The list of contours the shape consists of.
     std::vector<Contour> contours;
     /// Specifies whether the shape uses bottom-to-top (false) or top-to-bottom (true) Y coordinates.
@@ -29,9 +33,11 @@ public:
     /// Performs basic checks to determine if the object represents a valid shape.
     bool validate() const;
     /// Adjusts the bounding box to fit the shape.
-    void bounds(double &l, double &b, double &r, double &t) const;
+    void bound(double &l, double &b, double &r, double &t) const;
     /// Adjusts the bounding box to fit the shape border's mitered corners.
-    void miterBounds(double &l, double &b, double &r, double &t, double border, double miterLimit) const;
+    void boundMiters(double &l, double &b, double &r, double &t, double border, double miterLimit, int polarity) const;
+    /// Computes the minimum bounding box that fits the shape, optionally with a (mitered) border.
+    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;
 

+ 3 - 3
core/edge-segments.cpp

@@ -325,12 +325,12 @@ static void pointBounds(Point2 p, double &l, double &b, double &r, double &t) {
     if (p.y > t) t = p.y;
 }
 
-void LinearSegment::bounds(double &l, double &b, double &r, double &t) const {
+void LinearSegment::bound(double &l, double &b, double &r, double &t) const {
     pointBounds(p[0], l, b, r, t);
     pointBounds(p[1], l, b, r, t);
 }
 
-void QuadraticSegment::bounds(double &l, double &b, double &r, double &t) const {
+void QuadraticSegment::bound(double &l, double &b, double &r, double &t) const {
     pointBounds(p[0], l, b, r, t);
     pointBounds(p[2], l, b, r, t);
     Vector2 bot = (p[1]-p[0])-(p[2]-p[1]);
@@ -346,7 +346,7 @@ void QuadraticSegment::bounds(double &l, double &b, double &r, double &t) const
     }
 }
 
-void CubicSegment::bounds(double &l, double &b, double &r, double &t) const {
+void CubicSegment::bound(double &l, double &b, double &r, double &t) const {
     pointBounds(p[0], l, b, r, t);
     pointBounds(p[3], l, b, r, t);
     Vector2 a0 = p[1]-p[0];

+ 4 - 4
core/edge-segments.h

@@ -32,7 +32,7 @@ public:
     /// Outputs a list of (at most three) intersections (their X coordinates) with an infinite horizontal scanline at y and returns how many there are.
     virtual int scanlineIntersections(double x[3], int dy[3], double y) const = 0;
     /// Adjusts the bounding box to fit the edge segment.
-    virtual void bounds(double &l, double &b, double &r, double &t) const = 0;
+    virtual void bound(double &l, double &b, double &r, double &t) const = 0;
 
     /// Moves the start point of the edge segment.
     virtual void moveStartPoint(Point2 to) = 0;
@@ -55,7 +55,7 @@ public:
     Vector2 direction(double param) const;
     SignedDistance signedDistance(Point2 origin, double &param) const;
     int scanlineIntersections(double x[3], int dy[3], double y) const;
-    void bounds(double &l, double &b, double &r, double &t) const;
+    void bound(double &l, double &b, double &r, double &t) const;
 
     void moveStartPoint(Point2 to);
     void moveEndPoint(Point2 to);
@@ -75,7 +75,7 @@ public:
     Vector2 direction(double param) const;
     SignedDistance signedDistance(Point2 origin, double &param) const;
     int scanlineIntersections(double x[3], int dy[3], double y) const;
-    void bounds(double &l, double &b, double &r, double &t) const;
+    void bound(double &l, double &b, double &r, double &t) const;
 
     void moveStartPoint(Point2 to);
     void moveEndPoint(Point2 to);
@@ -95,7 +95,7 @@ public:
     Vector2 direction(double param) const;
     SignedDistance signedDistance(Point2 origin, double &param) const;
     int scanlineIntersections(double x[3], int dy[3], double y) const;
-    void bounds(double &l, double &b, double &r, double &t) const;
+    void bound(double &l, double &b, double &r, double &t) const;
 
     void moveStartPoint(Point2 to);
     void moveEndPoint(Point2 to);

+ 2 - 7
main.cpp

@@ -20,7 +20,6 @@
     #pragma warning(disable:4996)
 #endif
 
-#define LARGE_VALUE 1e240
 #define SDF_ERROR_ESTIMATE_PRECISION 19
 
 using namespace msdfgen;
@@ -730,13 +729,9 @@ int main(int argc, const char * const *argv) {
         shape.inverseYAxis = !shape.inverseYAxis;
 
     double avgScale = .5*(scale.x+scale.y);
-    struct {
-        double l, b, r, t;
-    } bounds = {
-        LARGE_VALUE, LARGE_VALUE, -LARGE_VALUE, -LARGE_VALUE
-    };
+    Shape::Bounds bounds = { };
     if (autoFrame || mode == METRICS || printMetrics || orientation == GUESS)
-        shape.bounds(bounds.l, bounds.b, bounds.r, bounds.t);
+        bounds = shape.getBounds();
 
     // Auto-frame
     if (autoFrame) {