edge-selectors.cpp 8.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224
  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), edgeDomainDistance(0), pseudoDistance(0) { }
  30. static double cornerEdgeDomainDistance(const EdgeSegment *a, const EdgeSegment *b, const Point2 &p, int polarity) {
  31. Vector2 aDir = a->direction(1).normalize(true);
  32. Vector2 bDir = b->direction(0).normalize(true);
  33. if (dotProduct(aDir, bDir) < MSDFGEN_CORNER_DOT_EPSILON-1) {
  34. Vector2 aTen = a->directionTendency(1, 1);
  35. Vector2 bTen = b->directionTendency(0, -1);
  36. return nonZeroSign(crossProduct(aTen, bTen))*fabs(SignedDistance::INFINITE.distance);
  37. }
  38. return polarity*dotProduct(p-b->point(0), (aDir+bDir).normalize(true));
  39. }
  40. double PseudoDistanceSelectorBase::edgeDomainDistance(const EdgeSegment *prevEdge, const EdgeSegment *edge, const EdgeSegment *nextEdge, const Point2 &p, double param) {
  41. if (param < 0)
  42. return cornerEdgeDomainDistance(prevEdge, edge, p, -1);
  43. else if (param > 1)
  44. return cornerEdgeDomainDistance(edge, nextEdge, p, 1);
  45. return 0;
  46. }
  47. PseudoDistanceSelectorBase::PseudoDistanceSelectorBase() : nearEdge(NULL), nearEdgeParam(0) { }
  48. void PseudoDistanceSelectorBase::reset(double delta) {
  49. minTrueDistance.distance += nonZeroSign(minTrueDistance.distance)*delta;
  50. minNegativePseudoDistance.distance = -fabs(minTrueDistance.distance);
  51. minPositivePseudoDistance.distance = fabs(minTrueDistance.distance);
  52. nearEdge = NULL;
  53. nearEdgeParam = 0;
  54. }
  55. bool PseudoDistanceSelectorBase::isEdgeRelevant(const EdgeCache &cache, const EdgeSegment *edge, const Point2 &p) const {
  56. double delta = DISTANCE_DELTA_FACTOR*(p-cache.point).length();
  57. return (
  58. cache.absDistance-delta <= fabs(minTrueDistance.distance) ||
  59. (cache.edgeDomainDistance > 0 ?
  60. cache.edgeDomainDistance-delta <= 0 :
  61. (cache.pseudoDistance < 0 ?
  62. cache.pseudoDistance+delta >= minNegativePseudoDistance.distance :
  63. cache.pseudoDistance-delta <= minPositivePseudoDistance.distance
  64. )
  65. )
  66. );
  67. }
  68. void PseudoDistanceSelectorBase::addEdgeTrueDistance(const EdgeSegment *edge, const SignedDistance &distance, double param) {
  69. if (distance < minTrueDistance) {
  70. minTrueDistance = distance;
  71. nearEdge = edge;
  72. nearEdgeParam = param;
  73. }
  74. }
  75. void PseudoDistanceSelectorBase::addEdgePseudoDistance(const SignedDistance &distance) {
  76. SignedDistance &minPseudoDistance = distance.distance < 0 ? minNegativePseudoDistance : minPositivePseudoDistance;
  77. if (distance < minPseudoDistance)
  78. minPseudoDistance = distance;
  79. }
  80. void PseudoDistanceSelectorBase::merge(const PseudoDistanceSelectorBase &other) {
  81. if (other.minTrueDistance < minTrueDistance) {
  82. minTrueDistance = other.minTrueDistance;
  83. nearEdge = other.nearEdge;
  84. nearEdgeParam = other.nearEdgeParam;
  85. }
  86. if (other.minNegativePseudoDistance < minNegativePseudoDistance)
  87. minNegativePseudoDistance = other.minNegativePseudoDistance;
  88. if (other.minPositivePseudoDistance < minPositivePseudoDistance)
  89. minPositivePseudoDistance = other.minPositivePseudoDistance;
  90. }
  91. double PseudoDistanceSelectorBase::computeDistance(const Point2 &p) const {
  92. double minDistance = minTrueDistance.distance < 0 ? minNegativePseudoDistance.distance : minPositivePseudoDistance.distance;
  93. if (nearEdge) {
  94. SignedDistance distance = minTrueDistance;
  95. nearEdge->distanceToPseudoDistance(distance, p, nearEdgeParam);
  96. if (fabs(distance.distance) < fabs(minDistance))
  97. minDistance = distance.distance;
  98. }
  99. return minDistance;
  100. }
  101. SignedDistance PseudoDistanceSelectorBase::trueDistance() const {
  102. return minTrueDistance;
  103. }
  104. void PseudoDistanceSelector::reset(const Point2 &p) {
  105. double delta = DISTANCE_DELTA_FACTOR*(p-this->p).length();
  106. PseudoDistanceSelectorBase::reset(delta);
  107. this->p = p;
  108. }
  109. void PseudoDistanceSelector::addEdge(EdgeCache &cache, const EdgeSegment *prevEdge, const EdgeSegment *edge, const EdgeSegment *nextEdge) {
  110. if (isEdgeRelevant(cache, edge, p)) {
  111. double param;
  112. SignedDistance distance = edge->signedDistance(p, param);
  113. double edd = edgeDomainDistance(prevEdge, edge, nextEdge, p, param);
  114. addEdgeTrueDistance(edge, distance, param);
  115. cache.point = p;
  116. cache.absDistance = fabs(distance.distance);
  117. cache.edgeDomainDistance = edd;
  118. if (edd <= 0) {
  119. edge->distanceToPseudoDistance(distance, p, param);
  120. addEdgePseudoDistance(distance);
  121. cache.pseudoDistance = distance.distance;
  122. }
  123. }
  124. }
  125. PseudoDistanceSelector::DistanceType PseudoDistanceSelector::distance() const {
  126. return computeDistance(p);
  127. }
  128. void MultiDistanceSelector::reset(const Point2 &p) {
  129. double delta = DISTANCE_DELTA_FACTOR*(p-this->p).length();
  130. r.reset(delta);
  131. g.reset(delta);
  132. b.reset(delta);
  133. this->p = p;
  134. }
  135. void MultiDistanceSelector::addEdge(EdgeCache &cache, const EdgeSegment *prevEdge, const EdgeSegment *edge, const EdgeSegment *nextEdge) {
  136. if (
  137. (edge->color&RED && r.isEdgeRelevant(cache, edge, p)) ||
  138. (edge->color&GREEN && g.isEdgeRelevant(cache, edge, p)) ||
  139. (edge->color&BLUE && b.isEdgeRelevant(cache, edge, p))
  140. ) {
  141. double param;
  142. SignedDistance distance = edge->signedDistance(p, param);
  143. double edd = PseudoDistanceSelectorBase::edgeDomainDistance(prevEdge, edge, nextEdge, p, param);
  144. if (edge->color&RED)
  145. r.addEdgeTrueDistance(edge, distance, param);
  146. if (edge->color&GREEN)
  147. g.addEdgeTrueDistance(edge, distance, param);
  148. if (edge->color&BLUE)
  149. b.addEdgeTrueDistance(edge, distance, param);
  150. cache.point = p;
  151. cache.absDistance = fabs(distance.distance);
  152. cache.edgeDomainDistance = edd;
  153. if (edd <= 0) {
  154. edge->distanceToPseudoDistance(distance, p, param);
  155. if (edge->color&RED)
  156. r.addEdgePseudoDistance(distance);
  157. if (edge->color&GREEN)
  158. g.addEdgePseudoDistance(distance);
  159. if (edge->color&BLUE)
  160. b.addEdgePseudoDistance(distance);
  161. cache.pseudoDistance = distance.distance;
  162. }
  163. }
  164. }
  165. void MultiDistanceSelector::merge(const MultiDistanceSelector &other) {
  166. r.merge(other.r);
  167. g.merge(other.g);
  168. b.merge(other.b);
  169. }
  170. MultiDistanceSelector::DistanceType MultiDistanceSelector::distance() const {
  171. MultiDistance multiDistance;
  172. multiDistance.r = r.computeDistance(p);
  173. multiDistance.g = g.computeDistance(p);
  174. multiDistance.b = b.computeDistance(p);
  175. return multiDistance;
  176. }
  177. SignedDistance MultiDistanceSelector::trueDistance() const {
  178. SignedDistance distance = r.trueDistance();
  179. if (g.trueDistance() < distance)
  180. distance = g.trueDistance();
  181. if (b.trueDistance() < distance)
  182. distance = b.trueDistance();
  183. return distance;
  184. }
  185. MultiAndTrueDistanceSelector::DistanceType MultiAndTrueDistanceSelector::distance() const {
  186. MultiDistance multiDistance = MultiDistanceSelector::distance();
  187. MultiAndTrueDistance mtd;
  188. mtd.r = multiDistance.r;
  189. mtd.g = multiDistance.g;
  190. mtd.b = multiDistance.b;
  191. mtd.a = trueDistance().distance;
  192. return mtd;
  193. }
  194. }