diff --git a/core/Shape.cpp b/core/Shape.cpp index fc4050d..9c8b256 100644 --- a/core/Shape.cpp +++ b/core/Shape.cpp @@ -27,7 +27,7 @@ bool Shape::validate() const { for (std::vector::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::iterator contour = contours.begin(); contour != contours.end(); ++contour) + for (std::vector::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 { diff --git a/core/Vector2.cpp b/core/Vector2.cpp index 896963f..0598b3c 100644 --- a/core/Vector2.cpp +++ b/core/Vector2.cpp @@ -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; } diff --git a/core/Vector2.h b/core/Vector2.h index 47ca637..f8e9901 100644 --- a/core/Vector2.h +++ b/core/Vector2.h @@ -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). diff --git a/main.cpp b/main.cpp index bb8e1e4..b9f923a 100644 --- a/main.cpp +++ b/main.cpp @@ -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 \n" "\tRenders an image preview without flattening the color channels.\n" + " -tolerance (Default: 0.01)\n" + "\tTolerance when checking for point equality. Helps avoid artifacts in noisy/inaccurate input shapes.\n" " -translate \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 with a value >= 0.0."); + argPos += 2; + continue; + } ARG_CASE("-help", 0) ABORT(helpText); printf("Unknown setting or insufficient parameters: %s\n", arg);