#include "Shape.h" #include "arithmetics.hpp" namespace msdfgen { Shape::Shape() : inverseYAxis(false) { } void Shape::addContour(const Contour &contour) { contours.push_back(contour); } #ifdef MSDFGEN_USE_CPP11 void Shape::addContour(Contour &&contour) { contours.push_back((Contour &&) contour); } #endif Contour & Shape::addContour() { contours.resize(contours.size()+1); return contours.back(); } bool Shape::validate() const { for (std::vector::const_iterator contour = contours.begin(); contour != contours.end(); ++contour) { if (!contour->edges.empty()) { Point2 corner = contour->edges.back()->point(1); for (std::vector::const_iterator edge = contour->edges.begin(); edge != contour->edges.end(); ++edge) { if (!*edge) return false; if ((*edge)->point(0) != corner) return false; corner = (*edge)->point(1); } } } return true; } void Shape::normalize() { 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]); contour->edges.clear(); contour->edges.push_back(EdgeHolder(parts[0])); contour->edges.push_back(EdgeHolder(parts[1])); contour->edges.push_back(EdgeHolder(parts[2])); } else { EdgeHolder *prevEdge = &contour->edges.back(); for (std::vector::iterator edge = contour->edges.begin(); edge != contour->edges.end(); ++edge) { Vector2 prevDir = (*prevEdge)->direction(1).normalize(); Vector2 curDir = (*edge)->direction(0).normalize(); if (dotProduct(prevDir, curDir) < MSDFGEN_CORNER_DOT_EPSILON-1) { Vector2 prevTendency = (*prevEdge)->directionTendency(1, 1); Vector2 curTendency = (*edge)->directionTendency(0, -1); int winding = nonZeroSign(crossProduct(prevTendency, curTendency)); EdgeSegment *newEdge = (*prevEdge)->makeDivergent(0, winding); if (newEdge) *prevEdge = newEdge; newEdge = (*edge)->makeDivergent(winding, 0); if (newEdge) *edge = newEdge; } prevEdge = &*edge; } } } } void Shape::bound(double &l, double &b, double &r, double &t) const { for (std::vector::const_iterator contour = contours.begin(); contour != contours.end(); ++contour) contour->bound(l, b, r, t); } void Shape::boundMiters(double &l, double &b, double &r, double &t, double border, double miterLimit, int polarity) const { for (std::vector::const_iterator contour = contours.begin(); contour != contours.end(); ++contour) contour->boundMiters(l, b, r, t, border, miterLimit, polarity); } Shape::Bounds Shape::getBounds(double border, double miterLimit, int polarity) const { static const double LARGE_VALUE = 1e240; Shape::Bounds bounds = { +LARGE_VALUE, +LARGE_VALUE, -LARGE_VALUE, -LARGE_VALUE }; bound(bounds.l, bounds.b, bounds.r, bounds.t); if (border > 0) { bounds.l -= border, bounds.b -= border; bounds.r += border, bounds.t += border; if (miterLimit > 0) boundMiters(bounds.l, bounds.b, bounds.r, bounds.t, border, miterLimit, polarity); } return bounds; } void Shape::scanline(Scanline &line, double y) const { std::vector intersections; double x[3]; int dy[3]; for (std::vector::const_iterator contour = contours.begin(); contour != contours.end(); ++contour) { for (std::vector::const_iterator edge = contour->edges.begin(); edge != contour->edges.end(); ++edge) { int n = (*edge)->scanlineIntersections(x, dy, y); for (int i = 0; i < n; ++i) { Scanline::Intersection intersection = { x[i], dy[i] }; intersections.push_back(intersection); } } } #ifdef MSDFGEN_USE_CPP11 line.setIntersections((std::vector &&) intersections); #else line.setIntersections(intersections); #endif } int Shape::edgeCount() const { int total = 0; for (std::vector::const_iterator contour = contours.begin(); contour != contours.end(); ++contour) total += (int) contour->edges.size(); return total; } }