Path: blob/master/thirdparty/msdfgen/core/edge-selectors.cpp
20937 views
1#include "edge-selectors.h"23#include "arithmetics.hpp"45namespace msdfgen {67#define DISTANCE_DELTA_FACTOR 1.00189TrueDistanceSelector::EdgeCache::EdgeCache() : absDistance(0) { }1011void TrueDistanceSelector::reset(const Point2 &p) {12double delta = DISTANCE_DELTA_FACTOR*(p-this->p).length();13// Since minDistance.distance is initialized to -DBL_MAX, at first glance this seems like it could make it underflow to -infinity, but in practice delta would have to be extremely high for this to happen (above 9e291)14minDistance.distance += nonZeroSign(minDistance.distance)*delta;15this->p = p;16}1718void TrueDistanceSelector::addEdge(EdgeCache &cache, const EdgeSegment *prevEdge, const EdgeSegment *edge, const EdgeSegment *nextEdge) {19double delta = DISTANCE_DELTA_FACTOR*(p-cache.point).length();20if (cache.absDistance-delta <= fabs(minDistance.distance)) {21double dummy;22SignedDistance distance = edge->signedDistance(p, dummy);23if (distance < minDistance)24minDistance = distance;25cache.point = p;26cache.absDistance = fabs(distance.distance);27}28}2930void TrueDistanceSelector::merge(const TrueDistanceSelector &other) {31if (other.minDistance < minDistance)32minDistance = other.minDistance;33}3435TrueDistanceSelector::DistanceType TrueDistanceSelector::distance() const {36return minDistance.distance;37}3839PerpendicularDistanceSelectorBase::EdgeCache::EdgeCache() : absDistance(0), aDomainDistance(0), bDomainDistance(0), aPerpendicularDistance(0), bPerpendicularDistance(0) { }4041bool PerpendicularDistanceSelectorBase::getPerpendicularDistance(double &distance, const Vector2 &ep, const Vector2 &edgeDir) {42double ts = dotProduct(ep, edgeDir);43if (ts > 0) {44double perpendicularDistance = crossProduct(ep, edgeDir);45if (fabs(perpendicularDistance) < fabs(distance)) {46distance = perpendicularDistance;47return true;48}49}50return false;51}5253PerpendicularDistanceSelectorBase::PerpendicularDistanceSelectorBase() : minNegativePerpendicularDistance(-fabs(minTrueDistance.distance)), minPositivePerpendicularDistance(fabs(minTrueDistance.distance)), nearEdge(NULL), nearEdgeParam(0) { }5455void PerpendicularDistanceSelectorBase::reset(double delta) {56minTrueDistance.distance += nonZeroSign(minTrueDistance.distance)*delta;57minNegativePerpendicularDistance = -fabs(minTrueDistance.distance);58minPositivePerpendicularDistance = fabs(minTrueDistance.distance);59nearEdge = NULL;60nearEdgeParam = 0;61}6263bool PerpendicularDistanceSelectorBase::isEdgeRelevant(const EdgeCache &cache, const EdgeSegment *, const Point2 &p) const {64double delta = DISTANCE_DELTA_FACTOR*(p-cache.point).length();65return (66cache.absDistance-delta <= fabs(minTrueDistance.distance) ||67fabs(cache.aDomainDistance) < delta ||68fabs(cache.bDomainDistance) < delta ||69(cache.aDomainDistance > 0 && (cache.aPerpendicularDistance < 0 ?70cache.aPerpendicularDistance+delta >= minNegativePerpendicularDistance :71cache.aPerpendicularDistance-delta <= minPositivePerpendicularDistance72)) ||73(cache.bDomainDistance > 0 && (cache.bPerpendicularDistance < 0 ?74cache.bPerpendicularDistance+delta >= minNegativePerpendicularDistance :75cache.bPerpendicularDistance-delta <= minPositivePerpendicularDistance76))77);78}7980void PerpendicularDistanceSelectorBase::addEdgeTrueDistance(const EdgeSegment *edge, const SignedDistance &distance, double param) {81if (distance < minTrueDistance) {82minTrueDistance = distance;83nearEdge = edge;84nearEdgeParam = param;85}86}8788void PerpendicularDistanceSelectorBase::addEdgePerpendicularDistance(double distance) {89if (distance <= 0 && distance > minNegativePerpendicularDistance)90minNegativePerpendicularDistance = distance;91if (distance >= 0 && distance < minPositivePerpendicularDistance)92minPositivePerpendicularDistance = distance;93}9495void PerpendicularDistanceSelectorBase::merge(const PerpendicularDistanceSelectorBase &other) {96if (other.minTrueDistance < minTrueDistance) {97minTrueDistance = other.minTrueDistance;98nearEdge = other.nearEdge;99nearEdgeParam = other.nearEdgeParam;100}101if (other.minNegativePerpendicularDistance > minNegativePerpendicularDistance)102minNegativePerpendicularDistance = other.minNegativePerpendicularDistance;103if (other.minPositivePerpendicularDistance < minPositivePerpendicularDistance)104minPositivePerpendicularDistance = other.minPositivePerpendicularDistance;105}106107double PerpendicularDistanceSelectorBase::computeDistance(const Point2 &p) const {108double minDistance = minTrueDistance.distance < 0 ? minNegativePerpendicularDistance : minPositivePerpendicularDistance;109if (nearEdge) {110SignedDistance distance = minTrueDistance;111nearEdge->distanceToPerpendicularDistance(distance, p, nearEdgeParam);112if (fabs(distance.distance) < fabs(minDistance))113minDistance = distance.distance;114}115return minDistance;116}117118SignedDistance PerpendicularDistanceSelectorBase::trueDistance() const {119return minTrueDistance;120}121122void PerpendicularDistanceSelector::reset(const Point2 &p) {123double delta = DISTANCE_DELTA_FACTOR*(p-this->p).length();124PerpendicularDistanceSelectorBase::reset(delta);125this->p = p;126}127128void PerpendicularDistanceSelector::addEdge(EdgeCache &cache, const EdgeSegment *prevEdge, const EdgeSegment *edge, const EdgeSegment *nextEdge) {129if (isEdgeRelevant(cache, edge, p)) {130double param;131SignedDistance distance = edge->signedDistance(p, param);132addEdgeTrueDistance(edge, distance, param);133cache.point = p;134cache.absDistance = fabs(distance.distance);135136Vector2 ap = p-edge->point(0);137Vector2 bp = p-edge->point(1);138Vector2 aDir = edge->direction(0).normalize(true);139Vector2 bDir = edge->direction(1).normalize(true);140Vector2 prevDir = prevEdge->direction(1).normalize(true);141Vector2 nextDir = nextEdge->direction(0).normalize(true);142double add = dotProduct(ap, (prevDir+aDir).normalize(true));143double bdd = -dotProduct(bp, (bDir+nextDir).normalize(true));144if (add > 0) {145double pd = distance.distance;146if (getPerpendicularDistance(pd, ap, -aDir))147addEdgePerpendicularDistance(pd = -pd);148cache.aPerpendicularDistance = pd;149}150if (bdd > 0) {151double pd = distance.distance;152if (getPerpendicularDistance(pd, bp, bDir))153addEdgePerpendicularDistance(pd);154cache.bPerpendicularDistance = pd;155}156cache.aDomainDistance = add;157cache.bDomainDistance = bdd;158}159}160161PerpendicularDistanceSelector::DistanceType PerpendicularDistanceSelector::distance() const {162return computeDistance(p);163}164165void MultiDistanceSelector::reset(const Point2 &p) {166double delta = DISTANCE_DELTA_FACTOR*(p-this->p).length();167r.reset(delta);168g.reset(delta);169b.reset(delta);170this->p = p;171}172173void MultiDistanceSelector::addEdge(EdgeCache &cache, const EdgeSegment *prevEdge, const EdgeSegment *edge, const EdgeSegment *nextEdge) {174if (175(edge->color&RED && r.isEdgeRelevant(cache, edge, p)) ||176(edge->color&GREEN && g.isEdgeRelevant(cache, edge, p)) ||177(edge->color&BLUE && b.isEdgeRelevant(cache, edge, p))178) {179double param;180SignedDistance distance = edge->signedDistance(p, param);181if (edge->color&RED)182r.addEdgeTrueDistance(edge, distance, param);183if (edge->color&GREEN)184g.addEdgeTrueDistance(edge, distance, param);185if (edge->color&BLUE)186b.addEdgeTrueDistance(edge, distance, param);187cache.point = p;188cache.absDistance = fabs(distance.distance);189190Vector2 ap = p-edge->point(0);191Vector2 bp = p-edge->point(1);192Vector2 aDir = edge->direction(0).normalize(true);193Vector2 bDir = edge->direction(1).normalize(true);194Vector2 prevDir = prevEdge->direction(1).normalize(true);195Vector2 nextDir = nextEdge->direction(0).normalize(true);196double add = dotProduct(ap, (prevDir+aDir).normalize(true));197double bdd = -dotProduct(bp, (bDir+nextDir).normalize(true));198if (add > 0) {199double pd = distance.distance;200if (PerpendicularDistanceSelectorBase::getPerpendicularDistance(pd, ap, -aDir)) {201pd = -pd;202if (edge->color&RED)203r.addEdgePerpendicularDistance(pd);204if (edge->color&GREEN)205g.addEdgePerpendicularDistance(pd);206if (edge->color&BLUE)207b.addEdgePerpendicularDistance(pd);208}209cache.aPerpendicularDistance = pd;210}211if (bdd > 0) {212double pd = distance.distance;213if (PerpendicularDistanceSelectorBase::getPerpendicularDistance(pd, bp, bDir)) {214if (edge->color&RED)215r.addEdgePerpendicularDistance(pd);216if (edge->color&GREEN)217g.addEdgePerpendicularDistance(pd);218if (edge->color&BLUE)219b.addEdgePerpendicularDistance(pd);220}221cache.bPerpendicularDistance = pd;222}223cache.aDomainDistance = add;224cache.bDomainDistance = bdd;225}226}227228void MultiDistanceSelector::merge(const MultiDistanceSelector &other) {229r.merge(other.r);230g.merge(other.g);231b.merge(other.b);232}233234MultiDistanceSelector::DistanceType MultiDistanceSelector::distance() const {235MultiDistance multiDistance;236multiDistance.r = r.computeDistance(p);237multiDistance.g = g.computeDistance(p);238multiDistance.b = b.computeDistance(p);239return multiDistance;240}241242SignedDistance MultiDistanceSelector::trueDistance() const {243SignedDistance distance = r.trueDistance();244if (g.trueDistance() < distance)245distance = g.trueDistance();246if (b.trueDistance() < distance)247distance = b.trueDistance();248return distance;249}250251MultiAndTrueDistanceSelector::DistanceType MultiAndTrueDistanceSelector::distance() const {252MultiDistance multiDistance = MultiDistanceSelector::distance();253MultiAndTrueDistance mtd;254mtd.r = multiDistance.r;255mtd.g = multiDistance.g;256mtd.b = multiDistance.b;257mtd.a = trueDistance().distance;258return mtd;259}260261}262263264