msdfgen/core/edge-segments.h

135 lines
5.2 KiB
C++

#pragma once
#include "Vector2.h"
#include "SignedDistance.h"
#include "EdgeColor.h"
namespace msdfgen {
// Parameters for iterative search of closest point on a cubic Bezier curve. Increase for higher precision.
#define MSDFGEN_CUBIC_SEARCH_STARTS 4
#define MSDFGEN_CUBIC_SEARCH_STEPS 4
// Threshold of the dot product of adjacent edge directions to be considered convergent.
#define MSDFGEN_CORNER_DOT_EPSILON 0.000001
/// An abstract edge segment.
class EdgeSegment {
public:
EdgeColor color;
EdgeSegment(EdgeColor edgeColor = WHITE) : color(edgeColor) { }
virtual ~EdgeSegment() { }
/// Creates a copy of the edge segment.
virtual EdgeSegment * clone() const = 0;
/// Returns the point on the edge specified by the parameter (between 0 and 1).
virtual Point2 point(double param) const = 0;
/// Returns the direction the edge has at the point specified by the parameter.
virtual Vector2 direction(double param) const = 0;
/// Returns the change of direction (second derivative) at the point specified by the parameter.
virtual Vector2 directionChange(double param) const = 0;
/// Returns the direction tendency vector that can resolve cases where directions converge at a corner.
virtual Vector2 directionTendency(double param, int polarity) const;
/// Returns the minimum signed distance between origin and the edge.
virtual SignedDistance signedDistance(Point2 origin, double &param) const = 0;
/// Converts a previously retrieved signed distance from origin to pseudo-distance.
virtual void distanceToPseudoDistance(SignedDistance &distance, Point2 origin, double param) const;
/// 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 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;
/// Moves the end point of the edge segment.
virtual void moveEndPoint(Point2 to) = 0;
/// Splits the edge segments into thirds which together represent the original edge.
virtual void splitInThirds(EdgeSegment *&part1, EdgeSegment *&part2, EdgeSegment *&part3) const = 0;
/// Converts convergent segment to a divergent segment. If NULL is returned, the object is already divergent and has been updated.
virtual EdgeSegment * makeDivergent(int dStart, int dEnd) = 0;
};
/// A line segment.
class LinearSegment : public EdgeSegment {
public:
Point2 p[2];
LinearSegment(Point2 p0, Point2 p1, EdgeColor edgeColor = WHITE);
LinearSegment * clone() const;
Point2 point(double param) const;
Vector2 direction(double param) const;
Vector2 directionChange(double param) const;
SignedDistance signedDistance(Point2 origin, double &param) const;
int scanlineIntersections(double x[3], int dy[3], double y) const;
void bound(double &l, double &b, double &r, double &t) const;
void moveStartPoint(Point2 to);
void moveEndPoint(Point2 to);
void splitInThirds(EdgeSegment *&part1, EdgeSegment *&part2, EdgeSegment *&part3) const;
EdgeSegment * makeDivergent(int dStart, int dEnd);
};
/// A quadratic Bezier curve.
class QuadraticSegment : public EdgeSegment {
public:
Point2 p[3];
QuadraticSegment(Point2 p0, Point2 p1, Point2 p2, EdgeColor edgeColor = WHITE);
QuadraticSegment * clone() const;
Point2 point(double param) const;
Vector2 direction(double param) const;
Vector2 directionChange(double param) const;
SignedDistance signedDistance(Point2 origin, double &param) const;
int scanlineIntersections(double x[3], int dy[3], double y) const;
void bound(double &l, double &b, double &r, double &t) const;
void moveStartPoint(Point2 to);
void moveEndPoint(Point2 to);
void splitInThirds(EdgeSegment *&part1, EdgeSegment *&part2, EdgeSegment *&part3) const;
EdgeSegment * makeDivergent(int dStart, int dEnd);
};
/// A cubic Bezier curve.
class CubicSegment : public EdgeSegment {
public:
Point2 p[4];
CubicSegment(Point2 p0, Point2 p1, Point2 p2, Point2 p3, EdgeColor edgeColor = WHITE);
CubicSegment * clone() const;
Point2 point(double param) const;
Vector2 direction(double param) const;
Vector2 directionChange(double param) const;
SignedDistance signedDistance(Point2 origin, double &param) const;
int scanlineIntersections(double x[3], int dy[3], double y) const;
void bound(double &l, double &b, double &r, double &t) const;
void moveStartPoint(Point2 to);
void moveEndPoint(Point2 to);
void splitInThirds(EdgeSegment *&part1, EdgeSegment *&part2, EdgeSegment *&part3) const;
EdgeSegment * makeDivergent(int dStart, int dEnd);
};
template <class BaseSegment>
class DivergentEdgeSegment : public BaseSegment {
public:
int dStart, dEnd;
explicit DivergentEdgeSegment(const BaseSegment &base, int dStart, int dEnd);
SignedDistance signedDistance(Point2 origin, double &param) const;
void distanceToPseudoDistance(SignedDistance &distance, Point2 origin, double param) const;
EdgeSegment * makeDivergent(int dStart, int dEnd);
};
}