2
0

edge-selectors.cpp 9.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262
  1. #include "edge-selectors.h"
  2. #include <cstddef>
  3. #include "arithmetics.hpp"
  4. namespace msdfgen {
  5. #define DISTANCE_DELTA_FACTOR 1.001
  6. TrueDistanceSelector::EdgeCache::EdgeCache() : absDistance(0) { }
  7. void TrueDistanceSelector::reset(const Point2 &p) {
  8. double delta = DISTANCE_DELTA_FACTOR*(p-this->p).length();
  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. PseudoDistanceSelectorBase::EdgeCache::EdgeCache() : absDistance(0), aDomainDistance(0), bDomainDistance(0), aPseudoDistance(0), bPseudoDistance(0) { }
  31. bool PseudoDistanceSelectorBase::getPseudoDistance(double &distance, const Vector2 &ep, const Vector2 &edgeDir) {
  32. double ts = dotProduct(ep, edgeDir);
  33. if (ts > 0) {
  34. double pseudoDistance = crossProduct(ep, edgeDir);
  35. if (fabs(pseudoDistance) < fabs(distance)) {
  36. distance = pseudoDistance;
  37. return true;
  38. }
  39. }
  40. return false;
  41. }
  42. PseudoDistanceSelectorBase::PseudoDistanceSelectorBase() : minNegativePseudoDistance(-fabs(minTrueDistance.distance)), minPositivePseudoDistance(fabs(minTrueDistance.distance)), nearEdge(NULL), nearEdgeParam(0) { }
  43. void PseudoDistanceSelectorBase::reset(double delta) {
  44. minTrueDistance.distance += nonZeroSign(minTrueDistance.distance)*delta;
  45. minNegativePseudoDistance = -fabs(minTrueDistance.distance);
  46. minPositivePseudoDistance = fabs(minTrueDistance.distance);
  47. nearEdge = NULL;
  48. nearEdgeParam = 0;
  49. }
  50. bool PseudoDistanceSelectorBase::isEdgeRelevant(const EdgeCache &cache, const EdgeSegment *edge, 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.aPseudoDistance < 0 ?
  57. cache.aPseudoDistance+delta >= minNegativePseudoDistance :
  58. cache.aPseudoDistance-delta <= minPositivePseudoDistance
  59. )) ||
  60. (cache.bDomainDistance > 0 && (cache.bPseudoDistance < 0 ?
  61. cache.bPseudoDistance+delta >= minNegativePseudoDistance :
  62. cache.bPseudoDistance-delta <= minPositivePseudoDistance
  63. ))
  64. );
  65. }
  66. void PseudoDistanceSelectorBase::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 PseudoDistanceSelectorBase::addEdgePseudoDistance(double distance) {
  74. if (distance <= 0 && distance > minNegativePseudoDistance)
  75. minNegativePseudoDistance = distance;
  76. if (distance >= 0 && distance < minPositivePseudoDistance)
  77. minPositivePseudoDistance = distance;
  78. }
  79. void PseudoDistanceSelectorBase::merge(const PseudoDistanceSelectorBase &other) {
  80. if (other.minTrueDistance < minTrueDistance) {
  81. minTrueDistance = other.minTrueDistance;
  82. nearEdge = other.nearEdge;
  83. nearEdgeParam = other.nearEdgeParam;
  84. }
  85. if (other.minNegativePseudoDistance > minNegativePseudoDistance)
  86. minNegativePseudoDistance = other.minNegativePseudoDistance;
  87. if (other.minPositivePseudoDistance < minPositivePseudoDistance)
  88. minPositivePseudoDistance = other.minPositivePseudoDistance;
  89. }
  90. double PseudoDistanceSelectorBase::computeDistance(const Point2 &p) const {
  91. double minDistance = minTrueDistance.distance < 0 ? minNegativePseudoDistance : minPositivePseudoDistance;
  92. if (nearEdge) {
  93. SignedDistance distance = minTrueDistance;
  94. nearEdge->distanceToPseudoDistance(distance, p, nearEdgeParam);
  95. if (fabs(distance.distance) < fabs(minDistance))
  96. minDistance = distance.distance;
  97. }
  98. return minDistance;
  99. }
  100. SignedDistance PseudoDistanceSelectorBase::trueDistance() const {
  101. return minTrueDistance;
  102. }
  103. void PseudoDistanceSelector::reset(const Point2 &p) {
  104. double delta = DISTANCE_DELTA_FACTOR*(p-this->p).length();
  105. PseudoDistanceSelectorBase::reset(delta);
  106. this->p = p;
  107. }
  108. void PseudoDistanceSelector::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 (getPseudoDistance(pd, ap, -aDir))
  126. addEdgePseudoDistance(pd = -pd);
  127. cache.aPseudoDistance = pd;
  128. }
  129. if (bdd > 0) {
  130. double pd = distance.distance;
  131. if (getPseudoDistance(pd, bp, bDir))
  132. addEdgePseudoDistance(pd);
  133. cache.bPseudoDistance = pd;
  134. }
  135. cache.aDomainDistance = add;
  136. cache.bDomainDistance = bdd;
  137. }
  138. }
  139. PseudoDistanceSelector::DistanceType PseudoDistanceSelector::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 (PseudoDistanceSelectorBase::getPseudoDistance(pd, ap, -aDir)) {
  176. pd = -pd;
  177. if (edge->color&RED)
  178. r.addEdgePseudoDistance(pd);
  179. if (edge->color&GREEN)
  180. g.addEdgePseudoDistance(pd);
  181. if (edge->color&BLUE)
  182. b.addEdgePseudoDistance(pd);
  183. }
  184. cache.aPseudoDistance = pd;
  185. }
  186. if (bdd > 0) {
  187. double pd = distance.distance;
  188. if (PseudoDistanceSelectorBase::getPseudoDistance(pd, bp, bDir)) {
  189. if (edge->color&RED)
  190. r.addEdgePseudoDistance(pd);
  191. if (edge->color&GREEN)
  192. g.addEdgePseudoDistance(pd);
  193. if (edge->color&BLUE)
  194. b.addEdgePseudoDistance(pd);
  195. }
  196. cache.bPseudoDistance = 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. }