123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221 |
- #include "edge-selectors.h"
- #include "arithmetics.hpp"
- namespace msdfgen {
- #define DISTANCE_DELTA_FACTOR 1.001
- TrueDistanceSelector::EdgeCache::EdgeCache() : absDistance(0) { }
- void TrueDistanceSelector::reset(const Point2 &p) {
- double delta = DISTANCE_DELTA_FACTOR*(p-this->p).length();
- minDistance.distance += nonZeroSign(minDistance.distance)*delta;
- this->p = p;
- }
- void TrueDistanceSelector::addEdge(EdgeCache &cache, const EdgeSegment *prevEdge, const EdgeSegment *edge, const EdgeSegment *nextEdge) {
- double delta = DISTANCE_DELTA_FACTOR*(p-cache.point).length();
- if (cache.absDistance-delta <= fabs(minDistance.distance)) {
- double dummy;
- SignedDistance distance = edge->signedDistance(p, dummy);
- if (distance < minDistance)
- minDistance = distance;
- cache.point = p;
- cache.absDistance = fabs(distance.distance);
- }
- }
- void TrueDistanceSelector::merge(const TrueDistanceSelector &other) {
- if (other.minDistance < minDistance)
- minDistance = other.minDistance;
- }
- TrueDistanceSelector::DistanceType TrueDistanceSelector::distance() const {
- return minDistance.distance;
- }
- PseudoDistanceSelectorBase::EdgeCache::EdgeCache() : absDistance(0), edgeDomainDistance(0), pseudoDistance(0) { }
- double PseudoDistanceSelectorBase::edgeDomainDistance(const EdgeSegment *prevEdge, const EdgeSegment *edge, const EdgeSegment *nextEdge, const Point2 &p, double param) {
- if (param < 0) {
- Vector2 prevEdgeDir = -prevEdge->direction(1).normalize(true);
- Vector2 edgeDir = edge->direction(0).normalize(true);
- Vector2 pointDir = p-edge->point(0);
- return dotProduct(pointDir, (prevEdgeDir-edgeDir).normalize(true));
- }
- if (param > 1) {
- Vector2 edgeDir = -edge->direction(1).normalize(true);
- Vector2 nextEdgeDir = nextEdge->direction(0).normalize(true);
- Vector2 pointDir = p-edge->point(1);
- return dotProduct(pointDir, (nextEdgeDir-edgeDir).normalize(true));
- }
- return 0;
- }
- PseudoDistanceSelectorBase::PseudoDistanceSelectorBase() : nearEdge(NULL), nearEdgeParam(0) { }
- void PseudoDistanceSelectorBase::reset(double delta) {
- minTrueDistance.distance += nonZeroSign(minTrueDistance.distance)*delta;
- minNegativePseudoDistance.distance = -fabs(minTrueDistance.distance);
- minPositivePseudoDistance.distance = fabs(minTrueDistance.distance);
- nearEdge = NULL;
- nearEdgeParam = 0;
- }
- bool PseudoDistanceSelectorBase::isEdgeRelevant(const EdgeCache &cache, const EdgeSegment *edge, const Point2 &p) const {
- double delta = DISTANCE_DELTA_FACTOR*(p-cache.point).length();
- return (
- cache.absDistance-delta <= fabs(minTrueDistance.distance) ||
- (cache.edgeDomainDistance > 0 ?
- cache.edgeDomainDistance-delta <= 0 :
- (cache.pseudoDistance < 0 ?
- cache.pseudoDistance+delta >= minNegativePseudoDistance.distance :
- cache.pseudoDistance-delta <= minPositivePseudoDistance.distance
- )
- )
- );
- }
- void PseudoDistanceSelectorBase::addEdgeTrueDistance(const EdgeSegment *edge, const SignedDistance &distance, double param) {
- if (distance < minTrueDistance) {
- minTrueDistance = distance;
- nearEdge = edge;
- nearEdgeParam = param;
- }
- }
- void PseudoDistanceSelectorBase::addEdgePseudoDistance(const SignedDistance &distance) {
- SignedDistance &minPseudoDistance = distance.distance < 0 ? minNegativePseudoDistance : minPositivePseudoDistance;
- if (distance < minPseudoDistance)
- minPseudoDistance = distance;
- }
- void PseudoDistanceSelectorBase::merge(const PseudoDistanceSelectorBase &other) {
- if (other.minTrueDistance < minTrueDistance) {
- minTrueDistance = other.minTrueDistance;
- nearEdge = other.nearEdge;
- nearEdgeParam = other.nearEdgeParam;
- }
- if (other.minNegativePseudoDistance < minNegativePseudoDistance)
- minNegativePseudoDistance = other.minNegativePseudoDistance;
- if (other.minPositivePseudoDistance < minPositivePseudoDistance)
- minPositivePseudoDistance = other.minPositivePseudoDistance;
- }
- double PseudoDistanceSelectorBase::computeDistance(const Point2 &p) const {
- double minDistance = minTrueDistance.distance < 0 ? minNegativePseudoDistance.distance : minPositivePseudoDistance.distance;
- if (nearEdge) {
- SignedDistance distance = minTrueDistance;
- nearEdge->distanceToPseudoDistance(distance, p, nearEdgeParam);
- if (fabs(distance.distance) < fabs(minDistance))
- minDistance = distance.distance;
- }
- return minDistance;
- }
- SignedDistance PseudoDistanceSelectorBase::trueDistance() const {
- return minTrueDistance;
- }
- void PseudoDistanceSelector::reset(const Point2 &p) {
- double delta = DISTANCE_DELTA_FACTOR*(p-this->p).length();
- PseudoDistanceSelectorBase::reset(delta);
- this->p = p;
- }
- void PseudoDistanceSelector::addEdge(EdgeCache &cache, const EdgeSegment *prevEdge, const EdgeSegment *edge, const EdgeSegment *nextEdge) {
- if (isEdgeRelevant(cache, edge, p)) {
- double param;
- SignedDistance distance = edge->signedDistance(p, param);
- double edd = edgeDomainDistance(prevEdge, edge, nextEdge, p, param);
- addEdgeTrueDistance(edge, distance, param);
- cache.point = p;
- cache.absDistance = fabs(distance.distance);
- cache.edgeDomainDistance = edd;
- if (edd <= 0) {
- edge->distanceToPseudoDistance(distance, p, param);
- addEdgePseudoDistance(distance);
- cache.pseudoDistance = distance.distance;
- }
- }
- }
- PseudoDistanceSelector::DistanceType PseudoDistanceSelector::distance() const {
- return computeDistance(p);
- }
- void MultiDistanceSelector::reset(const Point2 &p) {
- double delta = DISTANCE_DELTA_FACTOR*(p-this->p).length();
- r.reset(delta);
- g.reset(delta);
- b.reset(delta);
- this->p = p;
- }
- void MultiDistanceSelector::addEdge(EdgeCache &cache, const EdgeSegment *prevEdge, const EdgeSegment *edge, const EdgeSegment *nextEdge) {
- if (
- (edge->color&RED && r.isEdgeRelevant(cache, edge, p)) ||
- (edge->color&GREEN && g.isEdgeRelevant(cache, edge, p)) ||
- (edge->color&BLUE && b.isEdgeRelevant(cache, edge, p))
- ) {
- double param;
- SignedDistance distance = edge->signedDistance(p, param);
- double edd = PseudoDistanceSelectorBase::edgeDomainDistance(prevEdge, edge, nextEdge, p, param);
- if (edge->color&RED)
- r.addEdgeTrueDistance(edge, distance, param);
- if (edge->color&GREEN)
- g.addEdgeTrueDistance(edge, distance, param);
- if (edge->color&BLUE)
- b.addEdgeTrueDistance(edge, distance, param);
- cache.point = p;
- cache.absDistance = fabs(distance.distance);
- cache.edgeDomainDistance = edd;
- if (edd <= 0) {
- edge->distanceToPseudoDistance(distance, p, param);
- if (edge->color&RED)
- r.addEdgePseudoDistance(distance);
- if (edge->color&GREEN)
- g.addEdgePseudoDistance(distance);
- if (edge->color&BLUE)
- b.addEdgePseudoDistance(distance);
- cache.pseudoDistance = distance.distance;
- }
- }
- }
- void MultiDistanceSelector::merge(const MultiDistanceSelector &other) {
- r.merge(other.r);
- g.merge(other.g);
- b.merge(other.b);
- }
- MultiDistanceSelector::DistanceType MultiDistanceSelector::distance() const {
- MultiDistance multiDistance;
- multiDistance.r = r.computeDistance(p);
- multiDistance.g = g.computeDistance(p);
- multiDistance.b = b.computeDistance(p);
- return multiDistance;
- }
- SignedDistance MultiDistanceSelector::trueDistance() const {
- SignedDistance distance = r.trueDistance();
- if (g.trueDistance() < distance)
- distance = g.trueDistance();
- if (b.trueDistance() < distance)
- distance = b.trueDistance();
- return distance;
- }
- MultiAndTrueDistanceSelector::DistanceType MultiAndTrueDistanceSelector::distance() const {
- MultiDistance multiDistance = MultiDistanceSelector::distance();
- MultiAndTrueDistance mtd;
- mtd.r = multiDistance.r;
- mtd.g = multiDistance.g;
- mtd.b = multiDistance.b;
- mtd.a = trueDistance().distance;
- return mtd;
- }
- }
|