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