2
0

edge-selectors.cpp 8.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221
  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. double PseudoDistanceSelectorBase::edgeDomainDistance(const EdgeSegment *prevEdge, const EdgeSegment *edge, const EdgeSegment *nextEdge, const Point2 &p, double param) {
  31. if (param < 0) {
  32. Vector2 prevEdgeDir = -prevEdge->direction(1).normalize(true);
  33. Vector2 edgeDir = edge->direction(0).normalize(true);
  34. Vector2 pointDir = p-edge->point(0);
  35. return dotProduct(pointDir, (prevEdgeDir-edgeDir).normalize(true));
  36. }
  37. if (param > 1) {
  38. Vector2 edgeDir = -edge->direction(1).normalize(true);
  39. Vector2 nextEdgeDir = nextEdge->direction(0).normalize(true);
  40. Vector2 pointDir = p-edge->point(1);
  41. return dotProduct(pointDir, (nextEdgeDir-edgeDir).normalize(true));
  42. }
  43. return 0;
  44. }
  45. PseudoDistanceSelectorBase::PseudoDistanceSelectorBase() : nearEdge(NULL), nearEdgeParam(0) { }
  46. void PseudoDistanceSelectorBase::reset(double delta) {
  47. minTrueDistance.distance += nonZeroSign(minTrueDistance.distance)*delta;
  48. minNegativePseudoDistance.distance = -fabs(minTrueDistance.distance);
  49. minPositivePseudoDistance.distance = fabs(minTrueDistance.distance);
  50. nearEdge = NULL;
  51. nearEdgeParam = 0;
  52. }
  53. bool PseudoDistanceSelectorBase::isEdgeRelevant(const EdgeCache &cache, const EdgeSegment *edge, const Point2 &p) const {
  54. double delta = DISTANCE_DELTA_FACTOR*(p-cache.point).length();
  55. return (
  56. cache.absDistance-delta <= fabs(minTrueDistance.distance) ||
  57. (cache.edgeDomainDistance > 0 ?
  58. cache.edgeDomainDistance-delta <= 0 :
  59. (cache.pseudoDistance < 0 ?
  60. cache.pseudoDistance+delta >= minNegativePseudoDistance.distance :
  61. cache.pseudoDistance-delta <= minPositivePseudoDistance.distance
  62. )
  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(const SignedDistance &distance) {
  74. SignedDistance &minPseudoDistance = distance.distance < 0 ? minNegativePseudoDistance : minPositivePseudoDistance;
  75. if (distance < minPseudoDistance)
  76. minPseudoDistance = 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.distance : minPositivePseudoDistance.distance;
  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. double edd = edgeDomainDistance(prevEdge, edge, nextEdge, p, param);
  112. addEdgeTrueDistance(edge, distance, param);
  113. cache.point = p;
  114. cache.absDistance = fabs(distance.distance);
  115. cache.edgeDomainDistance = edd;
  116. if (edd <= 0) {
  117. edge->distanceToPseudoDistance(distance, p, param);
  118. addEdgePseudoDistance(distance);
  119. cache.pseudoDistance = distance.distance;
  120. }
  121. }
  122. }
  123. PseudoDistanceSelector::DistanceType PseudoDistanceSelector::distance() const {
  124. return computeDistance(p);
  125. }
  126. void MultiDistanceSelector::reset(const Point2 &p) {
  127. double delta = DISTANCE_DELTA_FACTOR*(p-this->p).length();
  128. r.reset(delta);
  129. g.reset(delta);
  130. b.reset(delta);
  131. this->p = p;
  132. }
  133. void MultiDistanceSelector::addEdge(EdgeCache &cache, const EdgeSegment *prevEdge, const EdgeSegment *edge, const EdgeSegment *nextEdge) {
  134. if (
  135. (edge->color&RED && r.isEdgeRelevant(cache, edge, p)) ||
  136. (edge->color&GREEN && g.isEdgeRelevant(cache, edge, p)) ||
  137. (edge->color&BLUE && b.isEdgeRelevant(cache, edge, p))
  138. ) {
  139. double param;
  140. SignedDistance distance = edge->signedDistance(p, param);
  141. double edd = PseudoDistanceSelectorBase::edgeDomainDistance(prevEdge, edge, nextEdge, p, param);
  142. if (edge->color&RED)
  143. r.addEdgeTrueDistance(edge, distance, param);
  144. if (edge->color&GREEN)
  145. g.addEdgeTrueDistance(edge, distance, param);
  146. if (edge->color&BLUE)
  147. b.addEdgeTrueDistance(edge, distance, param);
  148. cache.point = p;
  149. cache.absDistance = fabs(distance.distance);
  150. cache.edgeDomainDistance = edd;
  151. if (edd <= 0) {
  152. edge->distanceToPseudoDistance(distance, p, param);
  153. if (edge->color&RED)
  154. r.addEdgePseudoDistance(distance);
  155. if (edge->color&GREEN)
  156. g.addEdgePseudoDistance(distance);
  157. if (edge->color&BLUE)
  158. b.addEdgePseudoDistance(distance);
  159. cache.pseudoDistance = distance.distance;
  160. }
  161. }
  162. }
  163. void MultiDistanceSelector::merge(const MultiDistanceSelector &other) {
  164. r.merge(other.r);
  165. g.merge(other.g);
  166. b.merge(other.b);
  167. }
  168. MultiDistanceSelector::DistanceType MultiDistanceSelector::distance() const {
  169. MultiDistance multiDistance;
  170. multiDistance.r = r.computeDistance(p);
  171. multiDistance.g = g.computeDistance(p);
  172. multiDistance.b = b.computeDistance(p);
  173. return multiDistance;
  174. }
  175. SignedDistance MultiDistanceSelector::trueDistance() const {
  176. SignedDistance distance = r.trueDistance();
  177. if (g.trueDistance() < distance)
  178. distance = g.trueDistance();
  179. if (b.trueDistance() < distance)
  180. distance = b.trueDistance();
  181. return distance;
  182. }
  183. MultiAndTrueDistanceSelector::DistanceType MultiAndTrueDistanceSelector::distance() const {
  184. MultiDistance multiDistance = MultiDistanceSelector::distance();
  185. MultiAndTrueDistance mtd;
  186. mtd.r = multiDistance.r;
  187. mtd.g = multiDistance.g;
  188. mtd.b = multiDistance.b;
  189. mtd.a = trueDistance().distance;
  190. return mtd;
  191. }
  192. }