Contour.cpp 2.8 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091
  1. #include "Contour.h"
  2. #include "arithmetics.hpp"
  3. namespace msdfgen {
  4. static double shoelace(const Point2 &a, const Point2 &b) {
  5. return (b.x-a.x)*(a.y+b.y);
  6. }
  7. void Contour::addEdge(const EdgeHolder &edge) {
  8. edges.push_back(edge);
  9. }
  10. #ifdef MSDFGEN_USE_CPP11
  11. void Contour::addEdge(EdgeHolder &&edge) {
  12. edges.push_back((EdgeHolder &&) edge);
  13. }
  14. #endif
  15. EdgeHolder & Contour::addEdge() {
  16. edges.resize(edges.size()+1);
  17. return edges.back();
  18. }
  19. static void boundPoint(double &l, double &b, double &r, double &t, Point2 p) {
  20. if (p.x < l) l = p.x;
  21. if (p.y < b) b = p.y;
  22. if (p.x > r) r = p.x;
  23. if (p.y > t) t = p.y;
  24. }
  25. void Contour::bound(double &l, double &b, double &r, double &t) const {
  26. for (std::vector<EdgeHolder>::const_iterator edge = edges.begin(); edge != edges.end(); ++edge)
  27. (*edge)->bound(l, b, r, t);
  28. }
  29. void Contour::boundMiters(double &l, double &b, double &r, double &t, double border, double miterLimit, int polarity) const {
  30. if (edges.empty())
  31. return;
  32. Vector2 prevDir = edges.back()->direction(1).normalize(true);
  33. for (std::vector<EdgeHolder>::const_iterator edge = edges.begin(); edge != edges.end(); ++edge) {
  34. Vector2 dir = -(*edge)->direction(0).normalize(true);
  35. if (polarity*crossProduct(prevDir, dir) >= 0) {
  36. double miterLength = miterLimit;
  37. double q = .5*(1-dotProduct(prevDir, dir));
  38. if (q > 0)
  39. miterLength = min(1/sqrt(q), miterLimit);
  40. Point2 miter = (*edge)->point(0)+border*miterLength*(prevDir+dir).normalize(true);
  41. boundPoint(l, b, r, t, miter);
  42. }
  43. prevDir = (*edge)->direction(1).normalize(true);
  44. }
  45. }
  46. int Contour::winding() const {
  47. if (edges.empty())
  48. return 0;
  49. double total = 0;
  50. if (edges.size() == 1) {
  51. Point2 a = edges[0]->point(0), b = edges[0]->point(1/3.), c = edges[0]->point(2/3.);
  52. total += shoelace(a, b);
  53. total += shoelace(b, c);
  54. total += shoelace(c, a);
  55. } else if (edges.size() == 2) {
  56. Point2 a = edges[0]->point(0), b = edges[0]->point(.5), c = edges[1]->point(0), d = edges[1]->point(.5);
  57. total += shoelace(a, b);
  58. total += shoelace(b, c);
  59. total += shoelace(c, d);
  60. total += shoelace(d, a);
  61. } else {
  62. Point2 prev = edges.back()->point(0);
  63. for (std::vector<EdgeHolder>::const_iterator edge = edges.begin(); edge != edges.end(); ++edge) {
  64. Point2 cur = (*edge)->point(0);
  65. total += shoelace(prev, cur);
  66. prev = cur;
  67. }
  68. }
  69. return sign(total);
  70. }
  71. void Contour::reverse() {
  72. for (int i = (int) edges.size()/2; i > 0; --i)
  73. EdgeHolder::swap(edges[i-1], edges[edges.size()-i]);
  74. for (std::vector<EdgeHolder>::iterator edge = edges.begin(); edge != edges.end(); ++edge)
  75. (*edge)->reverse();
  76. }
  77. }