X-Git-Url: http://git.salome-platform.org/gitweb/?a=blobdiff_plain;ds=sidebyside;f=src%2FSketchPlugin%2FSketchPlugin_ConstraintFillet.cpp;h=0b45147523c952279bd3a689b3338a31d23a7d7b;hb=5d9ab62eb15fb4671fc5cd1924ecc2bc2d9726a0;hp=e094b12a76f7028e5fc073bffab02ba9bb149cd6;hpb=c3ae28ba30027cc4a6a757ef623f40adaae96ead;p=modules%2Fshaper.git diff --git a/src/SketchPlugin/SketchPlugin_ConstraintFillet.cpp b/src/SketchPlugin/SketchPlugin_ConstraintFillet.cpp index e094b12a7..0b4514752 100644 --- a/src/SketchPlugin/SketchPlugin_ConstraintFillet.cpp +++ b/src/SketchPlugin/SketchPlugin_ConstraintFillet.cpp @@ -6,7 +6,9 @@ #include "SketchPlugin_ConstraintFillet.h" +#include #include +#include #include #include #include @@ -25,6 +27,7 @@ #include #include #include +#include #include #include @@ -33,10 +36,14 @@ #include #include +#define _USE_MATH_DEFINES #include static const std::string PREVIOUS_VALUE("FilletPreviousRadius"); +const double tolerance = 1.e-7; +const double paramTolerance = 1.e-4; + /// \brief Attract specified point on theNewArc to the attribute of theFeature static void recalculateAttributes(FeaturePtr theNewArc, const std::string& theNewArcAttribute, FeaturePtr theFeature, const std::string& theFeatureAttribute); @@ -48,6 +55,15 @@ static void calculateFilletCenter(FeaturePtr theFeatureA, FeaturePtr theFeatureB std::shared_ptr& theTangentA, std::shared_ptr& theTangentB); +/// Get point on 1/3 length of edge from fillet point +static void getPointOnEdge(const FeaturePtr theFeature, + const std::shared_ptr theFilletPoint, + std::shared_ptr& thePoint); + +/// Get distance from point to feature +static double getProjectionDistance(const FeaturePtr theFeature, + const std::shared_ptr thePoint); + SketchPlugin_ConstraintFillet::SketchPlugin_ConstraintFillet() { } @@ -69,6 +85,8 @@ void SketchPlugin_ConstraintFillet::initAttributes() void SketchPlugin_ConstraintFillet::execute() { + static const double aTol = 1.e-7; + // the viewer update should be blocked in order to avoid the temporaty fillet sub-features visualization // before they are processed by the solver //std::shared_ptr aMsg = std::shared_ptr( @@ -87,6 +105,14 @@ void SketchPlugin_ConstraintFillet::execute() return; } + // Obtain fillet point + std::shared_ptr aBasePoint = std::dynamic_pointer_cast(aBaseA->attr()); + if (!aBasePoint) { + setError("Bad vertex selected"); + return; + } + std::shared_ptr aFilletPoint = aBasePoint->pnt(); + // Check the fillet shapes is not initialized yet AttributeRefListPtr aRefListOfFillet = std::dynamic_pointer_cast( aData->attribute(SketchPlugin_Constraint::ENTITY_B())); @@ -97,75 +123,10 @@ void SketchPlugin_ConstraintFillet::execute() // Obtain base features FeaturePtr anOldFeatureA, anOldFeatureB; - if(needNewObjects) { - AttributePtr anAttrBase = aBaseA->attr(); - const std::set& aRefsList = anAttrBase->owner()->data()->refsToMe(); - std::set::const_iterator aIt; - FeaturePtr aCoincident; - for (aIt = aRefsList.cbegin(); aIt != aRefsList.cend(); ++aIt) { - std::shared_ptr aAttr = (*aIt); - FeaturePtr aConstrFeature = std::dynamic_pointer_cast(aAttr->owner()); - if (aConstrFeature->getKind() == SketchPlugin_ConstraintCoincidence::ID()) { - AttributeRefAttrPtr anAttrRefA = std::dynamic_pointer_cast( - aConstrFeature->attribute(SketchPlugin_ConstraintCoincidence::ENTITY_A())); - AttributeRefAttrPtr anAttrRefB = std::dynamic_pointer_cast( - aConstrFeature->attribute(SketchPlugin_ConstraintCoincidence::ENTITY_B())); - if(anAttrRefA.get() && !anAttrRefA->isObject()) { - AttributePtr anAttrA = anAttrRefA->attr(); - if(anAttrBase == anAttrA) { - aCoincident = aConstrFeature; - break; - } - } - if(anAttrRefA.get() && !anAttrRefB->isObject()) { - AttributePtr anAttrB = anAttrRefB->attr(); - if(anAttrBase == anAttrB) { - aCoincident = aConstrFeature; - break; - } - } - } - } - - if(!aCoincident.get()) { - setError("No coincident edges at selected vertex"); - return; - } - - std::set aCoinsideLines; - SketchPlugin_Tools::findCoincidences(aCoincident, - SketchPlugin_ConstraintCoincidence::ENTITY_A(), - aCoinsideLines); - SketchPlugin_Tools::findCoincidences(aCoincident, - SketchPlugin_ConstraintCoincidence::ENTITY_B(), - aCoinsideLines); - - // Remove auxilary lines - if(aCoinsideLines.size() > 2) { - std::set aNewLines; - for(std::set::iterator anIt = aCoinsideLines.begin(); anIt != aCoinsideLines.end(); ++anIt) { - if(!(*anIt)->boolean(SketchPlugin_SketchEntity::AUXILIARY_ID())->value()) { - aNewLines.insert(*anIt); - } - } - aCoinsideLines = aNewLines; - } - - - if(aCoinsideLines.size() != 2) { - setError("At selected vertex should be two coincident lines"); - return; - } - - std::set::iterator aLinesIt = aCoinsideLines.begin(); - anOldFeatureA = *aLinesIt++; - anOldFeatureB = *aLinesIt; - } else { - std::list aNewFeatList = aRefListOfBaseLines->list(); - std::list::iterator aFeatIt = aNewFeatList.begin(); - anOldFeatureA = ModelAPI_Feature::feature(*aFeatIt++); - anOldFeatureB = ModelAPI_Feature::feature(*aFeatIt++); - } + std::list anOldFeatList = aRefListOfBaseLines->list(); + std::list::iterator aFeatIt = anOldFeatList.begin(); + anOldFeatureA = ModelAPI_Feature::feature(*aFeatIt++); + anOldFeatureB = ModelAPI_Feature::feature(*aFeatIt); if(!anOldFeatureA.get() || !anOldFeatureB.get()) { setError("One of the edges is empty"); @@ -176,7 +137,7 @@ void SketchPlugin_ConstraintFillet::execute() if (needNewObjects) { // Create list of objects composing a fillet // copy aFeatureA - aNewFeatureA = SketchPlugin_Sketch::addUniqueNamedCopiedFeature(anOldFeatureB, sketch()); + aNewFeatureA = SketchPlugin_Sketch::addUniqueNamedCopiedFeature(anOldFeatureA, sketch()); // copy aFeatureB aNewFeatureB = SketchPlugin_Sketch::addUniqueNamedCopiedFeature(anOldFeatureB, sketch()); // create filleting arc (it will be attached to the list later) @@ -220,16 +181,12 @@ void SketchPlugin_ConstraintFillet::execute() aStartEndPnt[2*i+1] = std::dynamic_pointer_cast( aFeature[i]->attribute(aEndAttr))->pnt(); } - for (int i = 0; i < aNbFeatures; i++) { - int j = aNbFeatures; - for (; j < 2 * aNbFeatures; j++) - if (aStartEndPnt[i]->distance(aStartEndPnt[j]) < 1.e-10) { - isStart[0] = i==0; - isStart[1] = j==aNbFeatures; + for (int aFeatInd = 0; aFeatInd < aNbFeatures; aFeatInd++) { + for (int j = 0; j < 2; j++) // loop on start-end of each feature + if (aStartEndPnt[aFeatInd * aNbFeatures + j]->distance(aFilletPoint) < 1.e-10) { + isStart[aFeatInd] = (j==0); break; } - if (j < 2 * aNbFeatures) - break; } // tangent directions of the features for (int i = 0; i < aNbFeatures; i++) { @@ -249,7 +206,7 @@ void SketchPlugin_ConstraintFillet::execute() double y = aDir->y(); aDir->setX(-y); aDir->setY(x); - if (!isStart[i]) + if (isStart[i] == std::dynamic_pointer_cast(aFeature[i])->isReversed()) aDir = aDir->multiplied(-1.0); } aTangentDir[i] = std::shared_ptr(new GeomAPI_Dir2d(aDir)); @@ -270,6 +227,10 @@ void SketchPlugin_ConstraintFillet::execute() // Calculate fillet arc parameters std::shared_ptr aCenter, aTangentPntA, aTangentPntB; calculateFilletCenter(anOldFeatureA, anOldFeatureB, aFilletRadius, isStart, aCenter, aTangentPntA, aTangentPntB); + if(!aCenter.get() || !aTangentPntA.get() || !aTangentPntB.get()) { + setError("Can not create fillet with the specified parameters."); + return; + } // update features std::dynamic_pointer_cast( aNewFeatureA->attribute(aFeatAttributes[isStart[0] ? 0 : 1]))->setValue( @@ -279,7 +240,9 @@ void SketchPlugin_ConstraintFillet::execute() aNewFeatureB->attribute(aFeatAttributes[2 + (isStart[1] ? 0 : 1)]))->setValue( aTangentPntB->x(), aTangentPntB->y()); aNewFeatureB->execute(); - // update fillet arc + // update fillet arc: make the arc correct for sure, so, it is not needed to process the "attribute updated" + // by arc; moreover, it may cause cyclicity in hte mechanism of updater + aNewArc->data()->blockSendAttributeUpdated(true); std::dynamic_pointer_cast( aNewArc->attribute(SketchPlugin_Arc::CENTER_ID()))->setValue( aCenter->x(), aCenter->y()); @@ -288,10 +251,17 @@ void SketchPlugin_ConstraintFillet::execute() aTangentPntA = aTangentPntB; aTangentPntB = aTmp; } - std::dynamic_pointer_cast( - aNewArc->attribute(SketchPlugin_Arc::START_ID()))->setValue(aTangentPntA->x(), aTangentPntA->y()); - std::dynamic_pointer_cast( - aNewArc->attribute(SketchPlugin_Arc::END_ID()))->setValue(aTangentPntB->x(), aTangentPntB->y()); + std::shared_ptr aStartPoint = std::dynamic_pointer_cast( + aNewArc->attribute(SketchPlugin_Arc::START_ID())); + std::shared_ptr aEndPoint = std::dynamic_pointer_cast( + aNewArc->attribute(SketchPlugin_Arc::END_ID())); + if (aStartPoint->isInitialized() && aEndPoint->isInitialized() && + (aStartPoint->pnt()->xy()->distance(aTangentPntA) > aTol || + aEndPoint->pnt()->xy()->distance(aTangentPntB) > aTol)) + std::dynamic_pointer_cast(aNewArc)->setReversed(false); + aStartPoint->setValue(aTangentPntA->x(), aTangentPntA->y()); + aEndPoint->setValue(aTangentPntB->x(), aTangentPntB->y()); + aNewArc->data()->blockSendAttributeUpdated(false); aNewArc->execute(); if (needNewObjects) { @@ -300,10 +270,6 @@ void SketchPlugin_ConstraintFillet::execute() aRefListOfFillet->append(aNewFeatureB->lastResult()); aRefListOfFillet->append(aNewArc->lastResult()); - // attach base lines to the list - aRefListOfBaseLines->append(anOldFeatureA); - aRefListOfBaseLines->append(anOldFeatureB); - myProducedFeatures.push_back(aNewFeatureA); myProducedFeatures.push_back(aNewFeatureB); myProducedFeatures.push_back(aNewArc); @@ -377,6 +343,22 @@ void SketchPlugin_ConstraintFillet::execute() aRefAttr->setAttr(aNewFeature[i]->attribute(aFeatAttributes[anAttrInd])); myProducedFeatures.push_back(aConstraint); } + // 4.1. Additional tangency constraints when the fillet is based on arcs. + // It is used to verify the created arc will be placed on a source. + for (int i = 0; i < aNbFeatures; ++i) { + if (aNewFeature[i]->getKind() != SketchPlugin_Arc::ID()) + continue; + aConstraint = sketch()->addFeature(SketchPlugin_ConstraintTangent::ID()); + aRefAttr = std::dynamic_pointer_cast( + aConstraint->attribute(SketchPlugin_Constraint::ENTITY_A())); + aRefAttr->setObject(aFeature[i]->lastResult()); + aRefAttr = std::dynamic_pointer_cast( + aConstraint->attribute(SketchPlugin_Constraint::ENTITY_B())); + aRefAttr->setObject(aNewFeature[i]->lastResult()); + aConstraint->execute(); + myProducedFeatures.push_back(aConstraint); + ModelAPI_EventCreator::get()->sendUpdated(aConstraint, anUpdateEvent); + } // 5. Tangent points should be placed on the base features for (int i = 0; i < aNbFeatures; i++) { anAttrInd = 2*i + (isStart[i] ? 0 : 1); @@ -439,6 +421,11 @@ void SketchPlugin_ConstraintFillet::attributeChanged(const std::string& theID) data()->attribute(SketchPlugin_Constraint::ENTITY_B())); aRefListOfFillet->clear(); + // clear the list of base features + AttributeRefListPtr aRefListOfBaseLines = std::dynamic_pointer_cast( + data()->attribute(SketchPlugin_Constraint::ENTITY_C())); + aRefListOfBaseLines->clear(); + // remove all produced objects and constraints DocumentPtr aDoc = sketch()->document(); std::list::iterator aCIt = myProducedFeatures.begin(); @@ -450,6 +437,107 @@ void SketchPlugin_ConstraintFillet::attributeChanged(const std::string& theID) for (aCIt = myBaseObjects.begin(); aCIt != myBaseObjects.end(); ++aCIt) (*aCIt)->boolean(SketchPlugin_SketchEntity::AUXILIARY_ID())->setValue(false); myBaseObjects.clear(); + + // Obtain fillet point + AttributeRefAttrPtr aBaseA = std::dynamic_pointer_cast( + data()->attribute(SketchPlugin_Constraint::ENTITY_A())); + if(!aBaseA->isInitialized() || aBaseA->isObject()) { + return; + } + AttributePtr anAttrBaseA = aBaseA->attr(); + std::shared_ptr aBasePoint = std::dynamic_pointer_cast(anAttrBaseA); + if (!aBasePoint) { + return; + } + std::shared_ptr aFilletPoint = aBasePoint->pnt(); + + // Obtain conicident edges + const std::set& aRefsList = anAttrBaseA->owner()->data()->refsToMe(); + std::set::const_iterator aIt; + FeaturePtr aCoincident; + for (aIt = aRefsList.cbegin(); aIt != aRefsList.cend(); ++aIt) { + std::shared_ptr aAttr = (*aIt); + FeaturePtr aConstrFeature = std::dynamic_pointer_cast(aAttr->owner()); + if (aConstrFeature->getKind() == SketchPlugin_ConstraintCoincidence::ID()) { + AttributeRefAttrPtr anAttrRefA = std::dynamic_pointer_cast( + aConstrFeature->attribute(SketchPlugin_ConstraintCoincidence::ENTITY_A())); + AttributeRefAttrPtr anAttrRefB = std::dynamic_pointer_cast( + aConstrFeature->attribute(SketchPlugin_ConstraintCoincidence::ENTITY_B())); + if(anAttrRefA.get() && !anAttrRefA->isObject()) { + AttributePtr anAttrA = anAttrRefA->attr(); + if(anAttrBaseA == anAttrA) { + aCoincident = aConstrFeature; + break; + } + } + if(anAttrRefA.get() && !anAttrRefB->isObject()) { + AttributePtr anAttrB = anAttrRefB->attr(); + if(anAttrBaseA == anAttrB) { + aCoincident = aConstrFeature; + break; + } + } + } + } + + if(!aCoincident.get()) { + setError("No coincident edges at selected vertex"); + return; + } + + std::set aCoinsides; + SketchPlugin_Tools::findCoincidences(aCoincident, + SketchPlugin_ConstraintCoincidence::ENTITY_A(), + aCoinsides); + SketchPlugin_Tools::findCoincidences(aCoincident, + SketchPlugin_ConstraintCoincidence::ENTITY_B(), + aCoinsides); + + // Remove points + std::set aNewLines; + for(std::set::iterator anIt = aCoinsides.begin(); anIt != aCoinsides.end(); ++anIt) { + if((*anIt)->getKind() != SketchPlugin_Point::ID()) { + aNewLines.insert(*anIt); + } + } + aCoinsides = aNewLines; + + // Remove auxilary lines + if(aCoinsides.size() > 2) { + aNewLines.clear(); + for(std::set::iterator anIt = aCoinsides.begin(); anIt != aCoinsides.end(); ++anIt) { + if(!(*anIt)->boolean(SketchPlugin_SketchEntity::AUXILIARY_ID())->value()) { + aNewLines.insert(*anIt); + } + } + aCoinsides = aNewLines; + } + + if(aCoinsides.size() != 2) { + setError("At selected vertex should be two coincident lines"); + return; + } + + // Store base lines + FeaturePtr anOldFeatureA, anOldFeatureB; + std::set::iterator aLinesIt = aCoinsides.begin(); + anOldFeatureA = *aLinesIt++; + anOldFeatureB = *aLinesIt; + aRefListOfBaseLines->append(anOldFeatureA); + aRefListOfBaseLines->append(anOldFeatureB); + + // Getting points located at 1/3 of edge length from fillet point + std::shared_ptr aPntA, aPntB; + getPointOnEdge(anOldFeatureA, aFilletPoint, aPntA); + getPointOnEdge(anOldFeatureB, aFilletPoint, aPntB); + + /// Getting distances + double aRadius = 1; + double aDistanceA = getProjectionDistance(anOldFeatureB, aPntA); + double aDistanceB = getProjectionDistance(anOldFeatureA, aPntB); + aRadius = aDistanceA < aDistanceB ? aDistanceA / 2.0 : aDistanceB / 2.0; + + std::dynamic_pointer_cast(data()->attribute(SketchPlugin_Constraint::VALUE()))->setValue(aRadius); } } @@ -656,23 +744,36 @@ void calculateFilletCenter(FeaturePtr theFeatureA, FeaturePtr theFeatureB, new GeomAPI_Dir2d(aEnd[1-aLineInd]->decreased(aCenter[1-aLineInd]))); double anArcAngle = aEndArcDir->angle(aStartArcDir); - // get and filter possible centers + // get possible centers and filter them std::list< std::shared_ptr > aSuspectCenters; possibleFilletCenterLineArc(aStart[aLineInd], aDirLine, aCenter[1-aLineInd], anArcRadius, theRadius, aSuspectCenters); double aDot = 0.0; + // the line is forward into the arc + double innerArc = aCenter[1-aLineInd]->decreased(aStart[aLineInd])->dot(aDirLine->xy()); std::shared_ptr aLineTgPoint, anArcTgPoint; + // The possible centers are ranged by their positions. + // If the point is not satisfy one of criteria, the weight is decreased with penalty. + int aBestWeight = 0; std::list< std::shared_ptr >::iterator anIt = aSuspectCenters.begin(); for (; anIt != aSuspectCenters.end(); anIt++) { + int aWeight = 2; aDot = aDirT->xy()->dot(aStart[aLineInd]->decreased(*anIt)); aLineTgPoint = (*anIt)->added(aDirT->xy()->multiplied(aDot)); - if (aLineTgPoint->decreased(aStart[aLineInd])->dot(aDirLine->xy()) < 0.0) - continue; // incorrect position + // Check the point is placed on the correct arc (penalty if false) + if (aCenter[1-aLineInd]->distance(*anIt) * innerArc > anArcRadius * innerArc) + aWeight -= 1; std::shared_ptr aCurDir = std::shared_ptr( new GeomAPI_Dir2d((*anIt)->decreased(aCenter[1-aLineInd]))); double aCurAngle = aCurDir->angle(aStartArcDir); if (anArcAngle < 0.0) aCurAngle *= -1.0; if (aCurAngle < 0.0 || aCurAngle > fabs(anArcAngle)) - continue; // incorrect position + continue; + if (aWeight > aBestWeight) + aBestWeight = aWeight; + else if (aWeight < aBestWeight || + aStart[aLineInd]->distance(*anIt) > + aStart[aLineInd]->distance(theCenter)) // <-- take closer point + continue; // the center is found, stop searching theCenter = *anIt; anArcTgPoint = aCenter[1-aLineInd]->added(aCurDir->xy()->multiplied(anArcRadius)); @@ -683,7 +784,7 @@ void calculateFilletCenter(FeaturePtr theFeatureA, FeaturePtr theFeatureB, theTangentA = anArcTgPoint; theTangentB = aLineTgPoint; } - return; + //return; } } else if (theFeatureA->getKind() == SketchPlugin_Arc::ID() && theFeatureB->getKind() == SketchPlugin_Arc::ID()) { @@ -727,3 +828,72 @@ void calculateFilletCenter(FeaturePtr theFeatureA, FeaturePtr theFeatureB, } } } + +void getPointOnEdge(const FeaturePtr theFeature, + const std::shared_ptr theFilletPoint, + std::shared_ptr& thePoint) { + if(theFeature->getKind() == SketchPlugin_Line::ID()) { + std::shared_ptr aPntStart = std::dynamic_pointer_cast( + theFeature->attribute(SketchPlugin_Line::START_ID()))->pnt(); + std::shared_ptr aPntEnd = std::dynamic_pointer_cast( + theFeature->attribute(SketchPlugin_Line::END_ID()))->pnt(); + if(aPntStart->distance(theFilletPoint) > 1.e-7) { + aPntStart = std::dynamic_pointer_cast( + theFeature->attribute(SketchPlugin_Line::END_ID()))->pnt(); + aPntEnd = std::dynamic_pointer_cast( + theFeature->attribute(SketchPlugin_Line::START_ID()))->pnt(); + } + thePoint.reset( new GeomAPI_Pnt2d(aPntStart->xy()->added( aPntEnd->xy()->decreased( aPntStart->xy() )->multiplied(1.0 / 3.0) ) ) ); + } else { + std::shared_ptr aPntTemp; + std::shared_ptr aPntStart = std::dynamic_pointer_cast( + theFeature->attribute(SketchPlugin_Arc::START_ID()))->pnt(); + std::shared_ptr aPntEnd = std::dynamic_pointer_cast( + theFeature->attribute(SketchPlugin_Arc::END_ID()))->pnt(); + if(theFeature->attribute(SketchPlugin_Arc::INVERSED_ID())) { + aPntTemp = aPntStart; + aPntStart = aPntEnd; + aPntEnd = aPntTemp; + } + std::shared_ptr aCenterPnt = std::dynamic_pointer_cast( + theFeature->attribute(SketchPlugin_Arc::CENTER_ID()))->pnt(); + std::shared_ptr aCirc(new GeomAPI_Circ2d(aCenterPnt, aPntStart)); + double aStartParameter(0), anEndParameter(0); + aCirc->parameter(aPntStart, paramTolerance, aStartParameter); + aCirc->parameter(aPntEnd, paramTolerance, anEndParameter); + if(aPntStart->distance(theFilletPoint) > tolerance) { + double aTmpParameter = aStartParameter; + aStartParameter = anEndParameter; + anEndParameter = aTmpParameter; + } + double aPntParameter = aStartParameter + (anEndParameter - aStartParameter) / 3.0; + aCirc->D0(aPntParameter, thePoint); + } +} + +double getProjectionDistance(const FeaturePtr theFeature, + const std::shared_ptr thePoint) +{ + std::shared_ptr aProjectPnt; + if(theFeature->getKind() == SketchPlugin_Line::ID()) { + std::shared_ptr aPntStart = std::dynamic_pointer_cast( + theFeature->attribute(SketchPlugin_Line::START_ID()))->pnt(); + std::shared_ptr aPntEnd = std::dynamic_pointer_cast( + theFeature->attribute(SketchPlugin_Line::END_ID()))->pnt(); + std::shared_ptr aLin(new GeomAPI_Lin2d(aPntStart, aPntEnd)); + aProjectPnt = aLin->project(thePoint); + } else { + std::shared_ptr aPntStart = std::dynamic_pointer_cast( + theFeature->attribute(SketchPlugin_Arc::START_ID()))->pnt(); + std::shared_ptr aPntEnd = std::dynamic_pointer_cast( + theFeature->attribute(SketchPlugin_Arc::END_ID()))->pnt(); + std::shared_ptr aCenterPnt = std::dynamic_pointer_cast( + theFeature->attribute(SketchPlugin_Arc::CENTER_ID()))->pnt(); + std::shared_ptr aCirc(new GeomAPI_Circ2d(aCenterPnt, aPntStart)); + aProjectPnt = aCirc->project(thePoint); + } + if(aProjectPnt.get()) { + return aProjectPnt->distance(thePoint); + } + return -1; +}