Add support for point tolerance to avoid artifacts in many types of hand drawn shapes.

This commit is contained in:
Christopher Kohnert 2017-05-31 10:02:42 -07:00
parent 8b2d4636eb
commit 0fe6b377d2
4 changed files with 34 additions and 2 deletions

View File

@ -27,7 +27,7 @@ bool Shape::validate() const {
for (std::vector<EdgeHolder>::const_iterator edge = contour->edges.begin(); edge != contour->edges.end(); ++edge) {
if (!*edge)
return false;
if ((*edge)->point(0) != corner)
if (!(*edge)->point(0).same(corner) )
return false;
corner = (*edge)->point(1);
}
@ -37,7 +37,7 @@ bool Shape::validate() const {
}
void Shape::normalize() {
for (std::vector<Contour>::iterator contour = contours.begin(); contour != contours.end(); ++contour)
for (std::vector<Contour>::iterator contour = contours.begin(); contour != contours.end(); ++contour) {
if (contour->edges.size() == 1) {
EdgeSegment *parts[3] = { };
contour->edges[0]->splitInThirds(parts[0], parts[1], parts[2]);
@ -46,6 +46,21 @@ void Shape::normalize() {
contour->edges.push_back(EdgeHolder(parts[1]));
contour->edges.push_back(EdgeHolder(parts[2]));
}
else {
// Make sure that start points match end points exactly or we'll get artifacts.
int n = contour->edges.size();
for( int i = 0; i < n; i++ )
{
EdgeSegment *s1 = contour->edges[i];
EdgeSegment *s2 = contour->edges[(i + 1) % n];
if( s1->point(1) != s2->point(0) )
{
s1->moveEndPoint(s2->point(0));
}
}
}
}
}
void Shape::bounds(double &l, double &b, double &r, double &t) const {

View File

@ -65,6 +65,12 @@ bool Vector2::operator!=(const Vector2 &other) const {
return x != other.x || y != other.y;
}
double Vector2::Epsilon = 0.01;
bool Vector2::same(const Vector2 &other) const {
return fabs(x - other.x) <= Epsilon && fabs(y - other.y) <= Epsilon;
}
Vector2 Vector2::operator+() const {
return *this;
}

View File

@ -13,6 +13,8 @@ namespace msdfgen {
*/
struct Vector2 {
static double Epsilon;
double x, y;
Vector2(double val = 0);
@ -51,6 +53,7 @@ struct Vector2 {
Vector2 & operator/=(const Vector2 &other);
Vector2 & operator*=(double value);
Vector2 & operator/=(double value);
bool same(const Vector2 &other) const;
/// Dot product of two vectors.
friend double dotProduct(const Vector2 &a, const Vector2 &b);
/// A special version of the cross product for 2D vectors (returns scalar value).

View File

@ -322,6 +322,8 @@ static const char *helpText =
"\tRenders an image preview using the generated distance field and saves it as a PNG file.\n"
" -testrendermulti <filename.png> <width> <height>\n"
"\tRenders an image preview without flattening the color channels.\n"
" -tolerance <tolerance> (Default: 0.01)\n"
"\tTolerance when checking for point equality. Helps avoid artifacts in noisy/inaccurate input shapes.\n"
" -translate <x> <y>\n"
"\tSets the translation of the shape in shape units.\n"
" -reverseorder\n"
@ -601,6 +603,12 @@ int main(int argc, const char * const *argv) {
argPos += 2;
continue;
}
ARG_CASE("-tolerance", 1) {
if (!parseDouble(Vector2::Epsilon, argv[argPos+1]) || Vector2::Epsilon < 0 )
ABORT("Invalid Tolerance value. Use -tolerance <N> with a value >= 0.0.");
argPos += 2;
continue;
}
ARG_CASE("-help", 0)
ABORT(helpText);
printf("Unknown setting or insufficient parameters: %s\n", arg);