Skip to content

Commit

Permalink
Shape bounds refactor
Browse files Browse the repository at this point in the history
  • Loading branch information
Chlumsky committed Mar 6, 2020
1 parent e88da21 commit fd50406
Show file tree
Hide file tree
Showing 7 changed files with 48 additions and 32 deletions.
22 changes: 12 additions & 10 deletions core/Contour.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}
}
Expand Down
4 changes: 2 additions & 2 deletions core/Contour.h
Original file line number Diff line number Diff line change
Expand Up @@ -21,9 +21,9 @@ class Contour {
/// 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;

Expand Down
21 changes: 17 additions & 4 deletions core/Shape.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down
10 changes: 8 additions & 2 deletions core/Shape.h
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand All @@ -29,9 +33,11 @@ class Shape {
/// 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;

Expand Down
6 changes: 3 additions & 3 deletions core/edge-segments.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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]);
Expand All @@ -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];
Expand Down
8 changes: 4 additions & 4 deletions core/edge-segments.h
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ class EdgeSegment {
/// 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;
Expand All @@ -55,7 +55,7 @@ class LinearSegment : public EdgeSegment {
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);
Expand All @@ -75,7 +75,7 @@ class QuadraticSegment : public EdgeSegment {
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);
Expand All @@ -95,7 +95,7 @@ class CubicSegment : public EdgeSegment {
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);
Expand Down
9 changes: 2 additions & 7 deletions main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,6 @@
#pragma warning(disable:4996)
#endif

#define LARGE_VALUE 1e240
#define SDF_ERROR_ESTIMATE_PRECISION 19

using namespace msdfgen;
Expand Down Expand Up @@ -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) {
Expand Down

0 comments on commit fd50406

Please sign in to comment.