mirror of https://github.com/Chlumsky/msdfgen.git
Common implementation for curve segment scanline
This commit is contained in:
parent
3e8774abde
commit
5f9f885c4f
|
|
@ -325,6 +325,18 @@ SignedDistance CubicSegment::signedDistance(Point2 origin, double ¶m) const
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
int LinearSegment::scanlineIntersections(double x[3], int dy[3], double y) const {
|
int LinearSegment::scanlineIntersections(double x[3], int dy[3], double y) const {
|
||||||
|
return horizontalScanlineIntersections(x, dy, y);
|
||||||
|
}
|
||||||
|
|
||||||
|
int QuadraticSegment::scanlineIntersections(double x[3], int dy[3], double y) const {
|
||||||
|
return horizontalScanlineIntersections(x, dy, y);
|
||||||
|
}
|
||||||
|
|
||||||
|
int CubicSegment::scanlineIntersections(double x[3], int dy[3], double y) const {
|
||||||
|
return horizontalScanlineIntersections(x, dy, y);
|
||||||
|
}
|
||||||
|
|
||||||
|
int LinearSegment::horizontalScanlineIntersections(double x[3], int dy[3], double y) const {
|
||||||
if ((y >= p[0].y && y < p[1].y) || (y >= p[1].y && y < p[0].y)) {
|
if ((y >= p[0].y && y < p[1].y) || (y >= p[1].y && y < p[0].y)) {
|
||||||
double param = (y-p[0].y)/(p[1].y-p[0].y);
|
double param = (y-p[0].y)/(p[1].y-p[0].y);
|
||||||
x[0] = mix(p[0].x, p[1].x, param);
|
x[0] = mix(p[0].x, p[1].x, param);
|
||||||
|
|
@ -334,120 +346,128 @@ int LinearSegment::scanlineIntersections(double x[3], int dy[3], double y) const
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int QuadraticSegment::scanlineIntersections(double x[3], int dy[3], double y) const {
|
int LinearSegment::verticalScanlineIntersections(double y[3], int dx[3], double x) const {
|
||||||
|
if ((x >= p[0].x && x < p[1].x) || (x >= p[1].x && x < p[0].x)) {
|
||||||
|
double param = (x-p[0].x)/(p[1].x-p[0].x);
|
||||||
|
y[0] = mix(p[0].y, p[1].y, param);
|
||||||
|
dx[0] = sign(p[1].x-p[0].x);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// p0, p1, q, r, s in the dimension of the scanline
|
||||||
|
// p0 = scanline - first endpoint
|
||||||
|
// p1 = scanline - last endpoint
|
||||||
|
// q, r, s = first, second, third order derivatives (see bezier-solver)
|
||||||
|
// descendingAtEnd is true if the first non-zero derivative at the last endpoint is negative
|
||||||
|
static int curveScanlineIntersections(double t[3], int d[3], double p0, double p1, double q, double r, double s, bool descendingAtEnd) {
|
||||||
int total = 0;
|
int total = 0;
|
||||||
int nextDY = y > p[0].y ? 1 : -1;
|
int nextD = p0 > 0 ? 1 : -1;
|
||||||
x[total] = p[0].x;
|
t[total] = 0;
|
||||||
if (p[0].y == y) {
|
if (p0 == 0) {
|
||||||
if (p[0].y < p[1].y || (p[0].y == p[1].y && p[0].y < p[2].y))
|
if (q > 0 || (q == 0 && (r > 0 || (r == 0 && s > 0))))
|
||||||
dy[total++] = 1;
|
d[total++] = 1;
|
||||||
else
|
else
|
||||||
nextDY = 1;
|
nextD = 1;
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
Vector2 ab = p[1]-p[0];
|
double ts[3];
|
||||||
Vector2 br = p[2]-p[1]-ab;
|
int solutions = solveCubic(ts, s, r, q, -p0);
|
||||||
double t[2];
|
|
||||||
int solutions = solveQuadratic(t, br.y, 2*ab.y, p[0].y-y);
|
|
||||||
// Sort solutions
|
// Sort solutions
|
||||||
double tmp;
|
double tmp;
|
||||||
if (solutions >= 2 && t[0] > t[1])
|
if (solutions >= 2) {
|
||||||
tmp = t[0], t[0] = t[1], t[1] = tmp;
|
if (ts[0] > ts[1])
|
||||||
for (int i = 0; i < solutions && total < 2; ++i) {
|
tmp = ts[0], ts[0] = ts[1], ts[1] = tmp;
|
||||||
if (t[i] >= 0 && t[i] <= 1) {
|
if (solutions >= 3 && ts[1] > ts[2]) {
|
||||||
x[total] = p[0].x+2*t[i]*ab.x+t[i]*t[i]*br.x;
|
tmp = ts[1], ts[1] = ts[2], ts[2] = tmp;
|
||||||
if (nextDY*(ab.y+t[i]*br.y) >= 0) {
|
if (ts[0] > ts[1])
|
||||||
dy[total++] = nextDY;
|
tmp = ts[0], ts[0] = ts[1], ts[1] = tmp;
|
||||||
nextDY = -nextDY;
|
}
|
||||||
|
}
|
||||||
|
for (int i = 0; i < solutions && total < 3; ++i) {
|
||||||
|
if (ts[i] >= 0 && ts[i] <= 1) {
|
||||||
|
t[total] = ts[i];
|
||||||
|
if (nextD*(q+(2*r+3*s*ts[i])*ts[i]) >= 0) {
|
||||||
|
d[total++] = nextD;
|
||||||
|
nextD = -nextD;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (p[2].y == y) {
|
if (p1 == 0) {
|
||||||
if (nextDY > 0 && total > 0) {
|
if (nextD > 0 && total > 0) {
|
||||||
--total;
|
--total;
|
||||||
nextDY = -1;
|
nextD = -1;
|
||||||
}
|
}
|
||||||
if ((p[2].y < p[1].y || (p[2].y == p[1].y && p[2].y < p[0].y)) && total < 2) {
|
if (descendingAtEnd && total < 3) {
|
||||||
x[total] = p[2].x;
|
t[total] = 1;
|
||||||
if (nextDY < 0) {
|
if (nextD < 0) {
|
||||||
dy[total++] = -1;
|
d[total++] = -1;
|
||||||
nextDY = 1;
|
nextD = 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (nextDY != (y >= p[2].y ? 1 : -1)) {
|
if (nextD != (p1 >= 0 ? 1 : -1)) {
|
||||||
if (total > 0)
|
if (total > 0)
|
||||||
--total;
|
--total;
|
||||||
else {
|
else {
|
||||||
if (fabs(p[2].y-y) < fabs(p[0].y-y))
|
if (fabs(p0) > fabs(p1))
|
||||||
x[total] = p[2].x;
|
t[total] = 1;
|
||||||
dy[total++] = nextDY;
|
d[total++] = nextD;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return total;
|
return total;
|
||||||
}
|
}
|
||||||
|
|
||||||
int CubicSegment::scanlineIntersections(double x[3], int dy[3], double y) const {
|
int QuadraticSegment::horizontalScanlineIntersections(double x[3], int dy[3], double y) const {
|
||||||
int total = 0;
|
double p01 = p[1].y-p[0].y;
|
||||||
int nextDY = y > p[0].y ? 1 : -1;
|
double p12 = p[2].y-p[1].y;
|
||||||
x[total] = p[0].x;
|
bool descendingAtEnd = p[2].y < p[1].y || (p[2].y == p[1].y && p[2].y < p[0].y);
|
||||||
if (p[0].y == y) {
|
double t[3] = { };
|
||||||
if (p[0].y < p[1].y || (p[0].y == p[1].y && (p[0].y < p[2].y || (p[0].y == p[2].y && p[0].y < p[3].y))))
|
int n = curveScanlineIntersections(t, dy, y-p[0].y, y-p[2].y, 2*p01, p12-p01, 0, descendingAtEnd);
|
||||||
dy[total++] = 1;
|
x[0] = point(t[0]).x;
|
||||||
else
|
x[1] = point(t[1]).x;
|
||||||
nextDY = 1;
|
x[2] = point(t[2]).x;
|
||||||
}
|
return n;
|
||||||
{
|
}
|
||||||
Vector2 ab = p[1]-p[0];
|
|
||||||
Vector2 br = p[2]-p[1]-ab;
|
int QuadraticSegment::verticalScanlineIntersections(double y[3], int dx[3], double x) const {
|
||||||
Vector2 as = (p[3]-p[2])-(p[2]-p[1])-br;
|
double p01 = p[1].x-p[0].x;
|
||||||
double t[3];
|
double p12 = p[2].x-p[1].x;
|
||||||
int solutions = solveCubic(t, as.y, 3*br.y, 3*ab.y, p[0].y-y);
|
bool descendingAtEnd = p[2].x < p[1].x || (p[2].x == p[1].x && p[2].x < p[0].x);
|
||||||
// Sort solutions
|
double t[3] = { };
|
||||||
double tmp;
|
int n = curveScanlineIntersections(t, dx, x-p[0].x, x-p[2].x, 2*p01, p12-p01, 0, descendingAtEnd);
|
||||||
if (solutions >= 2) {
|
y[0] = point(t[0]).y;
|
||||||
if (t[0] > t[1])
|
y[1] = point(t[1]).y;
|
||||||
tmp = t[0], t[0] = t[1], t[1] = tmp;
|
y[2] = point(t[2]).y;
|
||||||
if (solutions >= 3 && t[1] > t[2]) {
|
return n;
|
||||||
tmp = t[1], t[1] = t[2], t[2] = tmp;
|
}
|
||||||
if (t[0] > t[1])
|
|
||||||
tmp = t[0], t[0] = t[1], t[1] = tmp;
|
int CubicSegment::horizontalScanlineIntersections(double x[3], int dy[3], double y) const {
|
||||||
}
|
double p01 = p[1].y-p[0].y;
|
||||||
}
|
double p12 = p[2].y-p[1].y;
|
||||||
for (int i = 0; i < solutions && total < 3; ++i) {
|
double p23 = p[3].y-p[2].y;
|
||||||
if (t[i] >= 0 && t[i] <= 1) {
|
bool descendingAtEnd = p[3].y < p[2].y || (p[3].y == p[2].y && (p[3].y < p[1].y || (p[3].y == p[1].y && p[3].y < p[0].y)));
|
||||||
x[total] = p[0].x+3*t[i]*ab.x+3*t[i]*t[i]*br.x+t[i]*t[i]*t[i]*as.x;
|
double t[3] = { };
|
||||||
if (nextDY*(ab.y+2*t[i]*br.y+t[i]*t[i]*as.y) >= 0) {
|
int n = curveScanlineIntersections(t, dy, y-p[0].y, y-p[3].y, 3*p01, 3*(p12-p01), p23-2*p12+p01, descendingAtEnd);
|
||||||
dy[total++] = nextDY;
|
x[0] = point(t[0]).x;
|
||||||
nextDY = -nextDY;
|
x[1] = point(t[1]).x;
|
||||||
}
|
x[2] = point(t[2]).x;
|
||||||
}
|
return n;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
if (p[3].y == y) {
|
int CubicSegment::verticalScanlineIntersections(double y[3], int dx[3], double x) const {
|
||||||
if (nextDY > 0 && total > 0) {
|
double p01 = p[1].x-p[0].x;
|
||||||
--total;
|
double p12 = p[2].x-p[1].x;
|
||||||
nextDY = -1;
|
double p23 = p[3].x-p[2].x;
|
||||||
}
|
bool descendingAtEnd = p[3].x < p[2].x || (p[3].x == p[2].x && (p[3].x < p[1].x || (p[3].x == p[1].x && p[3].x < p[0].x)));
|
||||||
if ((p[3].y < p[2].y || (p[3].y == p[2].y && (p[3].y < p[1].y || (p[3].y == p[1].y && p[3].y < p[0].y)))) && total < 3) {
|
double t[3] = { };
|
||||||
x[total] = p[3].x;
|
int n = curveScanlineIntersections(t, dx, x-p[0].x, x-p[3].x, 3*p01, 3*(p12-p01), p23-2*p12+p01, descendingAtEnd);
|
||||||
if (nextDY < 0) {
|
y[0] = point(t[0]).y;
|
||||||
dy[total++] = -1;
|
y[1] = point(t[1]).y;
|
||||||
nextDY = 1;
|
y[2] = point(t[2]).y;
|
||||||
}
|
return n;
|
||||||
}
|
|
||||||
}
|
|
||||||
if (nextDY != (y >= p[3].y ? 1 : -1)) {
|
|
||||||
if (total > 0)
|
|
||||||
--total;
|
|
||||||
else {
|
|
||||||
if (fabs(p[3].y-y) < fabs(p[0].y-y))
|
|
||||||
x[total] = p[3].x;
|
|
||||||
dy[total++] = nextDY;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return total;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void pointBounds(Point2 p, double &l, double &b, double &r, double &t) {
|
static void pointBounds(Point2 p, double &l, double &b, double &r, double &t) {
|
||||||
|
|
|
||||||
|
|
@ -33,6 +33,9 @@ public:
|
||||||
virtual void distanceToPseudoDistance(SignedDistance &distance, Point2 origin, double param) const;
|
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.
|
/// 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;
|
virtual int scanlineIntersections(double x[3], int dy[3], double y) const = 0;
|
||||||
|
virtual int horizontalScanlineIntersections(double x[3], int dy[3], double y) const = 0;
|
||||||
|
/// Outputs a list of (at most three) intersections (their Y coordinates) with an infinite vertical scanline at x and returns how many there are.
|
||||||
|
virtual int verticalScanlineIntersections(double y[3], int dx[3], double x) const = 0;
|
||||||
/// Adjusts the bounding box to fit the edge segment.
|
/// Adjusts the bounding box to fit the edge segment.
|
||||||
virtual void bound(double &l, double &b, double &r, double &t) const = 0;
|
virtual void bound(double &l, double &b, double &r, double &t) const = 0;
|
||||||
|
|
||||||
|
|
@ -67,6 +70,8 @@ public:
|
||||||
double length() const;
|
double length() const;
|
||||||
SignedDistance signedDistance(Point2 origin, double ¶m) const;
|
SignedDistance signedDistance(Point2 origin, double ¶m) const;
|
||||||
int scanlineIntersections(double x[3], int dy[3], double y) const;
|
int scanlineIntersections(double x[3], int dy[3], double y) const;
|
||||||
|
int horizontalScanlineIntersections(double x[3], int dy[3], double y) const;
|
||||||
|
int verticalScanlineIntersections(double y[3], int dx[3], double x) const;
|
||||||
void bound(double &l, double &b, double &r, double &t) const;
|
void bound(double &l, double &b, double &r, double &t) const;
|
||||||
|
|
||||||
void reverse();
|
void reverse();
|
||||||
|
|
@ -96,6 +101,8 @@ public:
|
||||||
double length() const;
|
double length() const;
|
||||||
SignedDistance signedDistance(Point2 origin, double ¶m) const;
|
SignedDistance signedDistance(Point2 origin, double ¶m) const;
|
||||||
int scanlineIntersections(double x[3], int dy[3], double y) const;
|
int scanlineIntersections(double x[3], int dy[3], double y) const;
|
||||||
|
int horizontalScanlineIntersections(double x[3], int dy[3], double y) const;
|
||||||
|
int verticalScanlineIntersections(double y[3], int dx[3], double x) const;
|
||||||
void bound(double &l, double &b, double &r, double &t) const;
|
void bound(double &l, double &b, double &r, double &t) const;
|
||||||
|
|
||||||
void reverse();
|
void reverse();
|
||||||
|
|
@ -126,6 +133,8 @@ public:
|
||||||
Vector2 directionChange(double param) const;
|
Vector2 directionChange(double param) const;
|
||||||
SignedDistance signedDistance(Point2 origin, double ¶m) const;
|
SignedDistance signedDistance(Point2 origin, double ¶m) const;
|
||||||
int scanlineIntersections(double x[3], int dy[3], double y) const;
|
int scanlineIntersections(double x[3], int dy[3], double y) const;
|
||||||
|
int horizontalScanlineIntersections(double x[3], int dy[3], double y) const;
|
||||||
|
int verticalScanlineIntersections(double y[3], int dx[3], double x) const;
|
||||||
void bound(double &l, double &b, double &r, double &t) const;
|
void bound(double &l, double &b, double &r, double &t) const;
|
||||||
|
|
||||||
void reverse();
|
void reverse();
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue