edge-selectors.cpp 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262
  1. #include "edge-selectors.h"
  2. #include "arithmetics.hpp"
  3. namespace msdfgen {
  4. #define DISTANCE_DELTA_FACTOR 1.001
  5. TrueDistanceSelector::EdgeCache::EdgeCache() : absDistance(0) { }
  6. void TrueDistanceSelector::reset(const Point2 &p) {
  7. double delta = DISTANCE_DELTA_FACTOR*(p-this->p).length();
  8. // Since minDistance.distance is initialized to -DBL_MAX, at first glance this seems like it could make it underflow to -infinity, but in practice delta would have to be extremely high for this to happen (above 9e291)
  9. minDistance.distance += nonZeroSign(minDistance.distance)*delta;
  10. this->p = p;
  11. }
  12. void TrueDistanceSelector::addEdge(EdgeCache &cache, const EdgeSegment *prevEdge, const EdgeSegment *edge, const EdgeSegment *nextEdge) {
  13. double delta = DISTANCE_DELTA_FACTOR*(p-cache.point).length();
  14. if (cache.absDistance-delta <= fabs(minDistance.distance)) {
  15. double dummy;
  16. SignedDistance distance = edge->signedDistance(p, dummy);
  17. if (distance < minDistance)
  18. minDistance = distance;
  19. cache.point = p;
  20. cache.absDistance = fabs(distance.distance);
  21. }
  22. }
  23. void TrueDistanceSelector::merge(const TrueDistanceSelector &other) {
  24. if (other.minDistance < minDistance)
  25. minDistance = other.minDistance;
  26. }
  27. TrueDistanceSelector::DistanceType TrueDistanceSelector::distance() const {
  28. return minDistance.distance;
  29. }
  30. PerpendicularDistanceSelectorBase::EdgeCache::EdgeCache() : absDistance(0), aDomainDistance(0), bDomainDistance(0), aPerpendicularDistance(0), bPerpendicularDistance(0) { }
  31. bool PerpendicularDistanceSelectorBase::getPerpendicularDistance(double &distance, const Vector2 &ep, const Vector2 &edgeDir) {
  32. double ts = dotProduct(ep, edgeDir);
  33. if (ts > 0) {
  34. double perpendicularDistance = crossProduct(ep, edgeDir);
  35. if (fabs(perpendicularDistance) < fabs(distance)) {
  36. distance = perpendicularDistance;
  37. return true;
  38. }
  39. }
  40. return false;
  41. }
  42. PerpendicularDistanceSelectorBase::PerpendicularDistanceSelectorBase() : minNegativePerpendicularDistance(-fabs(minTrueDistance.distance)), minPositivePerpendicularDistance(fabs(minTrueDistance.distance)), nearEdge(NULL), nearEdgeParam(0) { }
  43. void PerpendicularDistanceSelectorBase::reset(double delta) {
  44. minTrueDistance.distance += nonZeroSign(minTrueDistance.distance)*delta;
  45. minNegativePerpendicularDistance = -fabs(minTrueDistance.distance);
  46. minPositivePerpendicularDistance = fabs(minTrueDistance.distance);
  47. nearEdge = NULL;
  48. nearEdgeParam = 0;
  49. }
  50. bool PerpendicularDistanceSelectorBase::isEdgeRelevant(const EdgeCache &cache, const EdgeSegment *, const Point2 &p) const {
  51. double delta = DISTANCE_DELTA_FACTOR*(p-cache.point).length();
  52. return (
  53. cache.absDistance-delta <= fabs(minTrueDistance.distance) ||
  54. fabs(cache.aDomainDistance) < delta ||
  55. fabs(cache.bDomainDistance) < delta ||
  56. (cache.aDomainDistance > 0 && (cache.aPerpendicularDistance < 0 ?
  57. cache.aPerpendicularDistance+delta >= minNegativePerpendicularDistance :
  58. cache.aPerpendicularDistance-delta <= minPositivePerpendicularDistance
  59. )) ||
  60. (cache.bDomainDistance > 0 && (cache.bPerpendicularDistance < 0 ?
  61. cache.bPerpendicularDistance+delta >= minNegativePerpendicularDistance :
  62. cache.bPerpendicularDistance-delta <= minPositivePerpendicularDistance
  63. ))
  64. );
  65. }
  66. void PerpendicularDistanceSelectorBase::addEdgeTrueDistance(const EdgeSegment *edge, const SignedDistance &distance, double param) {
  67. if (distance < minTrueDistance) {
  68. minTrueDistance = distance;
  69. nearEdge = edge;
  70. nearEdgeParam = param;
  71. }
  72. }
  73. void PerpendicularDistanceSelectorBase::addEdgePerpendicularDistance(double distance) {
  74. if (distance <= 0 && distance > minNegativePerpendicularDistance)
  75. minNegativePerpendicularDistance = distance;
  76. if (distance >= 0 && distance < minPositivePerpendicularDistance)
  77. minPositivePerpendicularDistance = distance;
  78. }
  79. void PerpendicularDistanceSelectorBase::merge(const PerpendicularDistanceSelectorBase &other) {
  80. if (other.minTrueDistance < minTrueDistance) {
  81. minTrueDistance = other.minTrueDistance;
  82. nearEdge = other.nearEdge;
  83. nearEdgeParam = other.nearEdgeParam;
  84. }
  85. if (other.minNegativePerpendicularDistance > minNegativePerpendicularDistance)
  86. minNegativePerpendicularDistance = other.minNegativePerpendicularDistance;
  87. if (other.minPositivePerpendicularDistance < minPositivePerpendicularDistance)
  88. minPositivePerpendicularDistance = other.minPositivePerpendicularDistance;
  89. }
  90. double PerpendicularDistanceSelectorBase::computeDistance(const Point2 &p) const {
  91. double minDistance = minTrueDistance.distance < 0 ? minNegativePerpendicularDistance : minPositivePerpendicularDistance;
  92. if (nearEdge) {
  93. SignedDistance distance = minTrueDistance;
  94. nearEdge->distanceToPerpendicularDistance(distance, p, nearEdgeParam);
  95. if (fabs(distance.distance) < fabs(minDistance))
  96. minDistance = distance.distance;
  97. }
  98. return minDistance;
  99. }
  100. SignedDistance PerpendicularDistanceSelectorBase::trueDistance() const {
  101. return minTrueDistance;
  102. }
  103. void PerpendicularDistanceSelector::reset(const Point2 &p) {
  104. double delta = DISTANCE_DELTA_FACTOR*(p-this->p).length();
  105. PerpendicularDistanceSelectorBase::reset(delta);
  106. this->p = p;
  107. }
  108. void PerpendicularDistanceSelector::addEdge(EdgeCache &cache, const EdgeSegment *prevEdge, const EdgeSegment *edge, const EdgeSegment *nextEdge) {
  109. if (isEdgeRelevant(cache, edge, p)) {
  110. double param;
  111. SignedDistance distance = edge->signedDistance(p, param);
  112. addEdgeTrueDistance(edge, distance, param);
  113. cache.point = p;
  114. cache.absDistance = fabs(distance.distance);
  115. Vector2 ap = p-edge->point(0);
  116. Vector2 bp = p-edge->point(1);
  117. Vector2 aDir = edge->direction(0).normalize(true);
  118. Vector2 bDir = edge->direction(1).normalize(true);
  119. Vector2 prevDir = prevEdge->direction(1).normalize(true);
  120. Vector2 nextDir = nextEdge->direction(0).normalize(true);
  121. double add = dotProduct(ap, (prevDir+aDir).normalize(true));
  122. double bdd = -dotProduct(bp, (bDir+nextDir).normalize(true));
  123. if (add > 0) {
  124. double pd = distance.distance;
  125. if (getPerpendicularDistance(pd, ap, -aDir))
  126. addEdgePerpendicularDistance(pd = -pd);
  127. cache.aPerpendicularDistance = pd;
  128. }
  129. if (bdd > 0) {
  130. double pd = distance.distance;
  131. if (getPerpendicularDistance(pd, bp, bDir))
  132. addEdgePerpendicularDistance(pd);
  133. cache.bPerpendicularDistance = pd;
  134. }
  135. cache.aDomainDistance = add;
  136. cache.bDomainDistance = bdd;
  137. }
  138. }
  139. PerpendicularDistanceSelector::DistanceType PerpendicularDistanceSelector::distance() const {
  140. return computeDistance(p);
  141. }
  142. void MultiDistanceSelector::reset(const Point2 &p) {
  143. double delta = DISTANCE_DELTA_FACTOR*(p-this->p).length();
  144. r.reset(delta);
  145. g.reset(delta);
  146. b.reset(delta);
  147. this->p = p;
  148. }
  149. void MultiDistanceSelector::addEdge(EdgeCache &cache, const EdgeSegment *prevEdge, const EdgeSegment *edge, const EdgeSegment *nextEdge) {
  150. if (
  151. (edge->color&RED && r.isEdgeRelevant(cache, edge, p)) ||
  152. (edge->color&GREEN && g.isEdgeRelevant(cache, edge, p)) ||
  153. (edge->color&BLUE && b.isEdgeRelevant(cache, edge, p))
  154. ) {
  155. double param;
  156. SignedDistance distance = edge->signedDistance(p, param);
  157. if (edge->color&RED)
  158. r.addEdgeTrueDistance(edge, distance, param);
  159. if (edge->color&GREEN)
  160. g.addEdgeTrueDistance(edge, distance, param);
  161. if (edge->color&BLUE)
  162. b.addEdgeTrueDistance(edge, distance, param);
  163. cache.point = p;
  164. cache.absDistance = fabs(distance.distance);
  165. Vector2 ap = p-edge->point(0);
  166. Vector2 bp = p-edge->point(1);
  167. Vector2 aDir = edge->direction(0).normalize(true);
  168. Vector2 bDir = edge->direction(1).normalize(true);
  169. Vector2 prevDir = prevEdge->direction(1).normalize(true);
  170. Vector2 nextDir = nextEdge->direction(0).normalize(true);
  171. double add = dotProduct(ap, (prevDir+aDir).normalize(true));
  172. double bdd = -dotProduct(bp, (bDir+nextDir).normalize(true));
  173. if (add > 0) {
  174. double pd = distance.distance;
  175. if (PerpendicularDistanceSelectorBase::getPerpendicularDistance(pd, ap, -aDir)) {
  176. pd = -pd;
  177. if (edge->color&RED)
  178. r.addEdgePerpendicularDistance(pd);
  179. if (edge->color&GREEN)
  180. g.addEdgePerpendicularDistance(pd);
  181. if (edge->color&BLUE)
  182. b.addEdgePerpendicularDistance(pd);
  183. }
  184. cache.aPerpendicularDistance = pd;
  185. }
  186. if (bdd > 0) {
  187. double pd = distance.distance;
  188. if (PerpendicularDistanceSelectorBase::getPerpendicularDistance(pd, bp, bDir)) {
  189. if (edge->color&RED)
  190. r.addEdgePerpendicularDistance(pd);
  191. if (edge->color&GREEN)
  192. g.addEdgePerpendicularDistance(pd);
  193. if (edge->color&BLUE)
  194. b.addEdgePerpendicularDistance(pd);
  195. }
  196. cache.bPerpendicularDistance = pd;
  197. }
  198. cache.aDomainDistance = add;
  199. cache.bDomainDistance = bdd;
  200. }
  201. }
  202. void MultiDistanceSelector::merge(const MultiDistanceSelector &other) {
  203. r.merge(other.r);
  204. g.merge(other.g);
  205. b.merge(other.b);
  206. }
  207. MultiDistanceSelector::DistanceType MultiDistanceSelector::distance() const {
  208. MultiDistance multiDistance;
  209. multiDistance.r = r.computeDistance(p);
  210. multiDistance.g = g.computeDistance(p);
  211. multiDistance.b = b.computeDistance(p);
  212. return multiDistance;
  213. }
  214. SignedDistance MultiDistanceSelector::trueDistance() const {
  215. SignedDistance distance = r.trueDistance();
  216. if (g.trueDistance() < distance)
  217. distance = g.trueDistance();
  218. if (b.trueDistance() < distance)
  219. distance = b.trueDistance();
  220. return distance;
  221. }
  222. MultiAndTrueDistanceSelector::DistanceType MultiAndTrueDistanceSelector::distance() const {
  223. MultiDistance multiDistance = MultiDistanceSelector::distance();
  224. MultiAndTrueDistance mtd;
  225. mtd.r = multiDistance.r;
  226. mtd.g = multiDistance.g;
  227. mtd.b = multiDistance.b;
  228. mtd.a = trueDistance().distance;
  229. return mtd;
  230. }
  231. }