edge-selectors.cpp 8.0 KB

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