mirror of https://github.com/Chlumsky/msdfgen.git
Fixed edge deconverge procedure
This commit is contained in:
parent
5dc5f6260b
commit
7bbdf32289
|
|
@ -4,6 +4,8 @@
|
||||||
#include <cstdlib>
|
#include <cstdlib>
|
||||||
#include "arithmetics.hpp"
|
#include "arithmetics.hpp"
|
||||||
|
|
||||||
|
#define DECONVERGE_OVERSHOOT 1.11111111111111111 // moves control points slightly more than necessary to account for floating-point errors
|
||||||
|
|
||||||
namespace msdfgen {
|
namespace msdfgen {
|
||||||
|
|
||||||
Shape::Shape() : inverseYAxis(false) { }
|
Shape::Shape() : inverseYAxis(false) { }
|
||||||
|
|
@ -39,13 +41,23 @@ bool Shape::validate() const {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void deconvergeEdge(EdgeHolder &edgeHolder, int param) {
|
static void deconvergeEdge(EdgeHolder &edgeHolder, int param, Vector2 vector) {
|
||||||
switch (edgeHolder->type()) {
|
switch (edgeHolder->type()) {
|
||||||
case (int) QuadraticSegment::EDGE_TYPE:
|
case (int) QuadraticSegment::EDGE_TYPE:
|
||||||
edgeHolder = static_cast<const QuadraticSegment *>(&*edgeHolder)->convertToCubic();
|
edgeHolder = static_cast<const QuadraticSegment *>(&*edgeHolder)->convertToCubic();
|
||||||
// fallthrough
|
// fallthrough
|
||||||
case (int) CubicSegment::EDGE_TYPE:
|
case (int) CubicSegment::EDGE_TYPE:
|
||||||
static_cast<CubicSegment *>(&*edgeHolder)->deconverge(param, MSDFGEN_DECONVERGENCE_FACTOR);
|
{
|
||||||
|
Point2 *p = static_cast<CubicSegment *>(&*edgeHolder)->p;
|
||||||
|
switch (param) {
|
||||||
|
case 0:
|
||||||
|
p[1] += (p[1]-p[0]).length()*vector;
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
p[2] += (p[2]-p[3]).length()*vector;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -59,13 +71,18 @@ void Shape::normalize() {
|
||||||
contour->edges.push_back(EdgeHolder(parts[1]));
|
contour->edges.push_back(EdgeHolder(parts[1]));
|
||||||
contour->edges.push_back(EdgeHolder(parts[2]));
|
contour->edges.push_back(EdgeHolder(parts[2]));
|
||||||
} else {
|
} else {
|
||||||
|
// Push apart convergent edge segments
|
||||||
EdgeHolder *prevEdge = &contour->edges.back();
|
EdgeHolder *prevEdge = &contour->edges.back();
|
||||||
for (std::vector<EdgeHolder>::iterator edge = contour->edges.begin(); edge != contour->edges.end(); ++edge) {
|
for (std::vector<EdgeHolder>::iterator edge = contour->edges.begin(); edge != contour->edges.end(); ++edge) {
|
||||||
Vector2 prevDir = (*prevEdge)->direction(1).normalize();
|
Vector2 prevDir = (*prevEdge)->direction(1).normalize();
|
||||||
Vector2 curDir = (*edge)->direction(0).normalize();
|
Vector2 curDir = (*edge)->direction(0).normalize();
|
||||||
if (dotProduct(prevDir, curDir) < MSDFGEN_CORNER_DOT_EPSILON-1) {
|
if (dotProduct(prevDir, curDir) < MSDFGEN_CORNER_DOT_EPSILON-1) {
|
||||||
deconvergeEdge(*prevEdge, 1);
|
double factor = DECONVERGE_OVERSHOOT*sqrt(1-(MSDFGEN_CORNER_DOT_EPSILON-1)*(MSDFGEN_CORNER_DOT_EPSILON-1))/(MSDFGEN_CORNER_DOT_EPSILON-1);
|
||||||
deconvergeEdge(*edge, 0);
|
Vector2 axis = factor*(prevDir-curDir).normalize();
|
||||||
|
if (crossProduct(2*(*prevEdge)->direction(1)-(*prevEdge)->directionChange(1), 2*(*edge)->direction(0)+(*edge)->directionChange(0)) < 0)
|
||||||
|
axis = -axis;
|
||||||
|
deconvergeEdge(*prevEdge, 1, axis.getOrthogonal(true));
|
||||||
|
deconvergeEdge(*edge, 0, axis.getOrthogonal(false));
|
||||||
}
|
}
|
||||||
prevEdge = &*edge;
|
prevEdge = &*edge;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -9,8 +9,6 @@ namespace msdfgen {
|
||||||
|
|
||||||
// Threshold of the dot product of adjacent edge directions to be considered convergent.
|
// Threshold of the dot product of adjacent edge directions to be considered convergent.
|
||||||
#define MSDFGEN_CORNER_DOT_EPSILON .000001
|
#define MSDFGEN_CORNER_DOT_EPSILON .000001
|
||||||
// The proportional amount by which a curve's control point will be adjusted to eliminate convergent corners.
|
|
||||||
#define MSDFGEN_DECONVERGENCE_FACTOR .000001
|
|
||||||
|
|
||||||
/// Vector shape representation.
|
/// Vector shape representation.
|
||||||
class Shape {
|
class Shape {
|
||||||
|
|
|
||||||
|
|
@ -524,18 +524,4 @@ EdgeSegment *QuadraticSegment::convertToCubic() const {
|
||||||
return new CubicSegment(p[0], mix(p[0], p[1], 2/3.), mix(p[1], p[2], 1/3.), p[2], color);
|
return new CubicSegment(p[0], mix(p[0], p[1], 2/3.), mix(p[1], p[2], 1/3.), p[2], color);
|
||||||
}
|
}
|
||||||
|
|
||||||
void CubicSegment::deconverge(int param, double amount) {
|
|
||||||
Vector2 dir = direction(param);
|
|
||||||
Vector2 normal = dir.getOrthonormal();
|
|
||||||
double h = dotProduct(directionChange(param)-dir, normal);
|
|
||||||
switch (param) {
|
|
||||||
case 0:
|
|
||||||
p[1] += amount*(dir+sign(h)*sqrt(fabs(h))*normal);
|
|
||||||
break;
|
|
||||||
case 1:
|
|
||||||
p[2] -= amount*(dir-sign(h)*sqrt(fabs(h))*normal);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -141,8 +141,6 @@ public:
|
||||||
void moveEndPoint(Point2 to);
|
void moveEndPoint(Point2 to);
|
||||||
void splitInThirds(EdgeSegment *&part0, EdgeSegment *&part1, EdgeSegment *&part2) const;
|
void splitInThirds(EdgeSegment *&part0, EdgeSegment *&part1, EdgeSegment *&part2) const;
|
||||||
|
|
||||||
void deconverge(int param, double amount);
|
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue