From: dbv Date: Fri, 10 Mar 2017 08:55:38 +0000 (+0300) Subject: Issue #2026: Removal of construction lines automatically created by Fillet X-Git-Tag: V_2.7.0~237 X-Git-Url: http://git.salome-platform.org/gitweb/?a=commitdiff_plain;h=c92ed07b94514f5fa8f6c6cdd27d661e2f893c3e;p=modules%2Fshaper.git Issue #2026: Removal of construction lines automatically created by Fillet Creation fillet by one point. --- diff --git a/src/PartSet/PartSet_SketcherMgr.cpp b/src/PartSet/PartSet_SketcherMgr.cpp index ccd18aed0..5497da37a 100755 --- a/src/PartSet/PartSet_SketcherMgr.cpp +++ b/src/PartSet/PartSet_SketcherMgr.cpp @@ -60,7 +60,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/src/SketchAPI/SketchAPI_Sketch.cpp b/src/SketchAPI/SketchAPI_Sketch.cpp index fdc8a71fb..e9953784c 100644 --- a/src/SketchAPI/SketchAPI_Sketch.cpp +++ b/src/SketchAPI/SketchAPI_Sketch.cpp @@ -14,7 +14,7 @@ #include #include #include -#include +#include #include #include #include @@ -607,7 +607,7 @@ std::shared_ptr SketchAPI_Sketch::setFillet( const ModelHighAPI_Double & theRadius) { std::shared_ptr aFeature = - compositeFeature()->addFeature(SketchPlugin_ConstraintFillet::ID()); + compositeFeature()->addFeature(SketchPlugin_Fillet::ID()); fillAttribute(thePoints, aFeature->data()->refattrlist(SketchPlugin_Constraint::ENTITY_A())); fillAttribute(theRadius, aFeature->real(SketchPlugin_Constraint::VALUE())); aFeature->execute(); diff --git a/src/SketchPlugin/CMakeLists.txt b/src/SketchPlugin/CMakeLists.txt index a6c654e09..46448c8a4 100644 --- a/src/SketchPlugin/CMakeLists.txt +++ b/src/SketchPlugin/CMakeLists.txt @@ -14,7 +14,7 @@ SET(PROJECT_HEADERS SketchPlugin_ConstraintCollinear.h SketchPlugin_ConstraintDistance.h SketchPlugin_ConstraintEqual.h - SketchPlugin_ConstraintFillet.h + SketchPlugin_Fillet.h SketchPlugin_ConstraintHorizontal.h SketchPlugin_ConstraintLength.h SketchPlugin_ConstraintMiddle.h @@ -52,7 +52,7 @@ SET(PROJECT_SOURCES SketchPlugin_ConstraintCollinear.cpp SketchPlugin_ConstraintDistance.cpp SketchPlugin_ConstraintEqual.cpp - SketchPlugin_ConstraintFillet.cpp + SketchPlugin_Fillet.cpp SketchPlugin_ConstraintHorizontal.cpp SketchPlugin_ConstraintLength.cpp SketchPlugin_ConstraintMiddle.cpp @@ -139,7 +139,6 @@ ADD_UNIT_TESTS(TestSketchPointLine.py TestConstraintMiddlePoint.py TestMultiRotation.py TestMultiTranslation.py - TestFillet.py TestRectangle.py TestProjection.py TestSplit.py diff --git a/src/SketchPlugin/SketchPlugin_ConstraintFillet.cpp b/src/SketchPlugin/SketchPlugin_ConstraintFillet.cpp deleted file mode 100644 index 83fde70e8..000000000 --- a/src/SketchPlugin/SketchPlugin_ConstraintFillet.cpp +++ /dev/null @@ -1,1119 +0,0 @@ -// Copyright (C) 2014-20xx CEA/DEN, EDF R&D --> - -// File: SketchPlugin_ConstraintFillet.cpp -// Created: 19 Mar 2015 -// Author: Artem ZHIDKOV - -#include "SketchPlugin_ConstraintFillet.h" - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -#include - -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); - -/// \brief Calculates center of fillet arc and coordinates of tangency points -static void calculateFilletCenter(FeaturePtr theFeatureA, FeaturePtr theFeatureB, - double theRadius, bool theNotInversed[2], - std::shared_ptr& theCenter, - 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); - -/// Get coincide edges for fillet -static std::set getCoincides(const FeaturePtr& theConstraintCoincidence); - -SketchPlugin_ConstraintFillet::SketchPlugin_ConstraintFillet() -: myListOfPointsChangedInCode(false), - myRadiusChangedByUser(false), - myRadiusChangedInCode(false), - myRadiusInitialized(false) -{ -} - -void SketchPlugin_ConstraintFillet::initAttributes() -{ - data()->addAttribute(SketchPlugin_Constraint::VALUE(), ModelAPI_AttributeDouble::typeId()); - data()->addAttribute(SketchPlugin_Constraint::ENTITY_A(), - ModelAPI_AttributeRefAttrList::typeId()); -} - -void SketchPlugin_ConstraintFillet::execute() -{ - std::shared_ptr aData = data(); - - // Check the base objects are initialized. - AttributeRefAttrListPtr aPointsRefList = std::dynamic_pointer_cast( - aData->attribute(SketchPlugin_Constraint::ENTITY_A())); - if(!aPointsRefList->isInitialized()) { - setError("Error: List of points is not initialized."); - return; - } - - // Get fillet radius. - double aFilletRadius = std::dynamic_pointer_cast( - aData->attribute(SketchPlugin_Constraint::VALUE()))->value(); - - // Wait all constraints being created, then send update events - static Events_ID anUpdateEvent = Events_Loop::eventByName(EVENT_OBJECT_UPDATED); - bool isUpdateFlushed = Events_Loop::loop()->isFlushed(anUpdateEvent); - if (isUpdateFlushed) - Events_Loop::loop()->setFlushed(anUpdateEvent, false); - - for(std::set::iterator aPointsIter = myNewPoints.begin(); - aPointsIter != myNewPoints.end(); - ++aPointsIter) { - AttributePtr aPointAttr = *aPointsIter; - std::shared_ptr aFilletPoint2d = - std::dynamic_pointer_cast(aPointAttr); - if(!aFilletPoint2d.get()) { - setError("Error: One of the selected points is empty."); - return; - } - std::shared_ptr aFilletPnt2d = aFilletPoint2d->pnt(); - - // Obtain base lines for fillet. - bool anIsNeedNewObjects = true; - FilletFeatures aFilletFeatures; - std::map::iterator aPrevPointsIter = - myPointFeaturesMap.find(aPointAttr); - if(aPrevPointsIter != myPointFeaturesMap.end()) { - anIsNeedNewObjects = false; - aFilletFeatures = aPrevPointsIter->second; - } - FeaturePtr aBaseEdgeA, aBaseEdgeB; - if(!anIsNeedNewObjects) { - aBaseEdgeA = aFilletFeatures.baseEdgesState.front().first; - aBaseEdgeB = aFilletFeatures.baseEdgesState.back().first; - } else { - // Obtain constraint coincidence for the fillet point. - FeaturePtr aConstraintCoincidence; - const std::set& aRefsList = aFilletPoint2d->owner()->data()->refsToMe(); - for(std::set::const_iterator - anIt = aRefsList.cbegin(); anIt != aRefsList.cend(); ++anIt) { - std::shared_ptr anAttr = (*anIt); - FeaturePtr aConstrFeature = std::dynamic_pointer_cast(anAttr->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(aFilletPoint2d == anAttrA) { - aConstraintCoincidence = aConstrFeature; - break; - } - } - if(anAttrRefB.get() && !anAttrRefB->isObject()) { - AttributePtr anAttrB = anAttrRefB->attr(); - if(aFilletPoint2d == anAttrB) { - aConstraintCoincidence = aConstrFeature; - break; - } - } - } - } - - if(!aConstraintCoincidence.get()) { - setError("Error: No coincident edges at one of the selected points."); - return; - } - - // Get coincide edges. - std::set aCoincides = getCoincides(aConstraintCoincidence); - if(aCoincides.size() != 2) { - setError("Error: One of the selected points does not have two suitable edges for fillet."); - return; - } - - std::set::iterator aLinesIt = aCoincides.begin(); - aBaseEdgeA = *aLinesIt++; - aBaseEdgeB = *aLinesIt; - - std::pair aBasePairA = - std::make_pair(aBaseEdgeA, - aBaseEdgeA->boolean(SketchPlugin_SketchEntity::AUXILIARY_ID())->value()); - std::pair aBasePairB = - std::make_pair(aBaseEdgeB, - aBaseEdgeB->boolean(SketchPlugin_SketchEntity::AUXILIARY_ID())->value()); - aFilletFeatures.baseEdgesState.push_back(aBasePairA); - aFilletFeatures.baseEdgesState.push_back(aBasePairB); - } - - if(!aBaseEdgeA.get() || !aBaseEdgeB.get()) { - setError("Error: One of the base edges is empty."); - return; - } - - // Create new edges and arc if needed. - FeaturePtr aResultEdgeA, aResultEdgeB, aResultArc; - if(!anIsNeedNewObjects) { - // Obtain features from the list. - std::list::iterator aResultEdgesIt = aFilletFeatures.resultEdges.begin(); - aResultEdgeA = *aResultEdgesIt++; - aResultEdgeB = *aResultEdgesIt++; - aResultArc = *aResultEdgesIt; - } else { - // Copy edges and create arc. - aResultEdgeA = SketchPlugin_Sketch::addUniqueNamedCopiedFeature(aBaseEdgeA, sketch()); - aResultEdgeA->boolean(SketchPlugin_SketchEntity::AUXILIARY_ID())->setValue(false); - aResultEdgeB = SketchPlugin_Sketch::addUniqueNamedCopiedFeature(aBaseEdgeB, sketch()); - aResultEdgeB->boolean(SketchPlugin_SketchEntity::AUXILIARY_ID())->setValue(false); - aResultArc = sketch()->addFeature(SketchPlugin_Arc::ID()); - - aFilletFeatures.resultEdges.push_back(aResultEdgeA); - aFilletFeatures.resultEdges.push_back(aResultEdgeB); - aFilletFeatures.resultEdges.push_back(aResultArc); - } - - // Calculate arc attributes - static const int aNbFeatures = 2; - FeaturePtr aBaseFeatures[aNbFeatures] = {aBaseEdgeA, aBaseEdgeB}; - FeaturePtr aResultFeatures[aNbFeatures] = {aResultEdgeA, aResultEdgeB}; - // tangent directions of the features in coincident point - std::shared_ptr aTangentDir[aNbFeatures]; - bool isStart[aNbFeatures]; // indicates which point the features share - // first pair of points relate to first feature, second pair - to second - std::shared_ptr aStartEndPnt[aNbFeatures * 2]; - std::string aFeatAttributes[aNbFeatures * 2]; // attributes of features - for (int i = 0; i < aNbFeatures; i++) { - std::string aStartAttr, aEndAttr; - if (aResultFeatures[i]->getKind() == SketchPlugin_Line::ID()) { - aStartAttr = SketchPlugin_Line::START_ID(); - aEndAttr = SketchPlugin_Line::END_ID(); - } else if (aResultFeatures[i]->getKind() == SketchPlugin_Arc::ID()) { - aStartAttr = SketchPlugin_Arc::START_ID(); - aEndAttr = SketchPlugin_Arc::END_ID(); - } else { // wrong argument - setError("Error: One of the points has wrong coincide feature"); - return; - } - aFeatAttributes[2*i] = aStartAttr; - aStartEndPnt[2*i] = std::dynamic_pointer_cast( - aBaseFeatures[i]->attribute(aStartAttr))->pnt(); - aFeatAttributes[2*i+1] = aEndAttr; - aStartEndPnt[2*i+1] = std::dynamic_pointer_cast( - aBaseFeatures[i]->attribute(aEndAttr))->pnt(); - } - 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(aFilletPnt2d) < 1.e-10) { - isStart[aFeatInd] = (j==0); - break; - } - } - // tangent directions of the features - for (int i = 0; i < aNbFeatures; i++) { - std::shared_ptr aDir; - if (aResultFeatures[i]->getKind() == SketchPlugin_Line::ID()) { - aDir = aStartEndPnt[2*i+1]->xy()->decreased(aStartEndPnt[2*i]->xy()); - if (!isStart[i]) - aDir = aDir->multiplied(-1.0); - } else if (aResultFeatures[i]->getKind() == SketchPlugin_Arc::ID()) { - std::shared_ptr aCenterPoint = - std::dynamic_pointer_cast( - aResultFeatures[i]->attribute(SketchPlugin_Arc::CENTER_ID()))->pnt(); - aDir = isStart[i] ? aStartEndPnt[2*i]->xy() : aStartEndPnt[2*i+1]->xy(); - aDir = aDir->decreased(aCenterPoint->xy()); - - double x = aDir->x(); - double y = aDir->y(); - aDir->setX(-y); - aDir->setY(x); - if (isStart[i] == - std::dynamic_pointer_cast(aBaseFeatures[i])->isReversed()) - aDir = aDir->multiplied(-1.0); - } - aTangentDir[i] = std::shared_ptr(new GeomAPI_Dir2d(aDir)); - } - - // By default, the start point of fillet arc is connected to FeatureA, - // and the end point - to FeatureB. But when the angle between TangentDirA and - // TangentDirB greater 180 degree, the sequaence of features need to be reversed. - double cosBA = aTangentDir[0]->cross(aTangentDir[1]); // cos(B-A), - // where A and B - angles between corresponding tanget direction and the X axis - bool isReversed = cosBA > 0.0; - - // Calculate fillet arc parameters - std::shared_ptr aCenter, aTangentPntA, aTangentPntB; - calculateFilletCenter(aBaseEdgeA, aBaseEdgeB, 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( - aResultEdgeA->attribute(aFeatAttributes[isStart[0] ? 0 : 1]))-> - setValue(aTangentPntA->x(), aTangentPntA->y()); - aResultEdgeA->execute(); - std::dynamic_pointer_cast( - aResultEdgeB->attribute(aFeatAttributes[2 + (isStart[1] ? 0 : 1)]))-> - setValue(aTangentPntB->x(), aTangentPntB->y()); - aResultEdgeB->execute(); - // 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 - bool aWasBlocked = aResultArc->data()->blockSendAttributeUpdated(true); - std::dynamic_pointer_cast( - aResultArc->attribute(SketchPlugin_Arc::CENTER_ID()))->setValue(aCenter->x(), aCenter->y()); - if(isReversed) { - std::shared_ptr aTmp = aTangentPntA; - aTangentPntA = aTangentPntB; - aTangentPntB = aTmp; - } - std::shared_ptr aStartPoint = - std::dynamic_pointer_cast( - aResultArc->attribute(SketchPlugin_Arc::START_ID())); - std::shared_ptr aEndPoint = std::dynamic_pointer_cast( - aResultArc->attribute(SketchPlugin_Arc::END_ID())); - if(aStartPoint->isInitialized() && aEndPoint->isInitialized() && - (aStartPoint->pnt()->xy()->distance(aTangentPntA) > tolerance || - aEndPoint->pnt()->xy()->distance(aTangentPntB) > tolerance)) { - std::dynamic_pointer_cast(aResultArc)->setReversed(false); - } - aStartPoint->setValue(aTangentPntA->x(), aTangentPntA->y()); - aEndPoint->setValue(aTangentPntB->x(), aTangentPntB->y()); - aResultArc->data()->blockSendAttributeUpdated(aWasBlocked); - aResultArc->execute(); - - if(anIsNeedNewObjects) { - // Create list of additional constraints: - // 1. Coincidence of boundary points of features (copied lines/arcs) and fillet arc - // 1.1. coincidence - FeaturePtr aConstraint = sketch()->addFeature(SketchPlugin_ConstraintCoincidence::ID()); - AttributeRefAttrPtr aRefAttr = std::dynamic_pointer_cast( - aConstraint->attribute(SketchPlugin_Constraint::ENTITY_A())); - aRefAttr->setAttr(aResultArc->attribute(SketchPlugin_Arc::START_ID())); - aRefAttr = std::dynamic_pointer_cast( - aConstraint->attribute(SketchPlugin_Constraint::ENTITY_B())); - int aFeatInd = isReversed ? 1 : 0; - int anAttrInd = (isReversed ? 2 : 0) + (isStart[isReversed ? 1 : 0] ? 0 : 1); - aRefAttr->setAttr(aResultFeatures[aFeatInd]->attribute(aFeatAttributes[anAttrInd])); - recalculateAttributes(aResultArc, SketchPlugin_Arc::START_ID(), - aResultFeatures[aFeatInd], aFeatAttributes[anAttrInd]); - aConstraint->execute(); - aFilletFeatures.resultConstraints.push_back(aConstraint); - ModelAPI_EventCreator::get()->sendUpdated(aConstraint, anUpdateEvent); - // 1.2. coincidence - aConstraint = sketch()->addFeature(SketchPlugin_ConstraintCoincidence::ID()); - aRefAttr = std::dynamic_pointer_cast( - aConstraint->attribute(SketchPlugin_Constraint::ENTITY_A())); - aRefAttr->setAttr(aResultArc->attribute(SketchPlugin_Arc::END_ID())); - aRefAttr = std::dynamic_pointer_cast( - aConstraint->attribute(SketchPlugin_Constraint::ENTITY_B())); - aFeatInd = isReversed ? 0 : 1; - anAttrInd = (isReversed ? 0 : 2) + (isStart[isReversed ? 0 : 1] ? 0 : 1); - aRefAttr->setAttr(aResultFeatures[aFeatInd]->attribute(aFeatAttributes[anAttrInd])); - recalculateAttributes(aResultArc, SketchPlugin_Arc::END_ID(), - aResultFeatures[aFeatInd], aFeatAttributes[anAttrInd]); - aConstraint->execute(); - aFilletFeatures.resultConstraints.push_back(aConstraint); - ModelAPI_EventCreator::get()->sendUpdated(aConstraint, anUpdateEvent); - // 2. Fillet arc radius - //aConstraint = sketch()->addFeature(SketchPlugin_ConstraintRadius::ID()); - //aRefAttr = std::dynamic_pointer_cast( - // aConstraint->attribute(SketchPlugin_Constraint::ENTITY_A())); - //aRefAttr->setObject(aNewArc->lastResult()); - //std::dynamic_pointer_cast( - // aConstraint->attribute(SketchPlugin_Constraint::VALUE()))->setValue(aFilletRadius); - //std::dynamic_pointer_cast( - // aConstraint->attribute(SketchPlugin_Constraint::FLYOUT_VALUE_PNT()))->setValue( - // isStart[0] ? aStartEndPnt[0] : aStartEndPnt[1]); - //aConstraint->execute(); - //myProducedFeatures.push_back(aConstraint); - //ModelAPI_EventCreator::get()->sendUpdated(aConstraint, anUpdateEvent); - // 3. Tangency of fillet arc and features - for (int i = 0; i < aNbFeatures; i++) { - aConstraint = sketch()->addFeature(SketchPlugin_ConstraintTangent::ID()); - aRefAttr = std::dynamic_pointer_cast( - aConstraint->attribute(SketchPlugin_Constraint::ENTITY_A())); - aRefAttr->setObject(aResultArc->lastResult()); - aRefAttr = std::dynamic_pointer_cast( - aConstraint->attribute(SketchPlugin_Constraint::ENTITY_B())); - bool isArc = aResultFeatures[i]->getKind() == SketchPlugin_Arc::ID(); - aRefAttr->setObject(isArc ? aResultFeatures[i]->lastResult() : - aResultFeatures[i]->firstResult()); - aConstraint->execute(); - aFilletFeatures.resultConstraints.push_back(aConstraint); - ModelAPI_EventCreator::get()->sendUpdated(aConstraint, anUpdateEvent); - } - // 4. Coincidence of free boundaries of base and copied features - for (int i = 0; i < aNbFeatures; i++) { - anAttrInd = 2*i + (isStart[i] ? 1 : 0); - aConstraint = sketch()->addFeature(SketchPlugin_ConstraintCoincidence::ID()); - aRefAttr = std::dynamic_pointer_cast( - aConstraint->attribute(SketchPlugin_Constraint::ENTITY_A())); - aRefAttr->setAttr(aBaseFeatures[i]->attribute(aFeatAttributes[anAttrInd])); - aRefAttr = std::dynamic_pointer_cast( - aConstraint->attribute(SketchPlugin_Constraint::ENTITY_B())); - aRefAttr->setAttr(aResultFeatures[i]->attribute(aFeatAttributes[anAttrInd])); - aFilletFeatures.resultConstraints.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 (aResultFeatures[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(aBaseFeatures[i]->lastResult()); - aRefAttr = std::dynamic_pointer_cast( - aConstraint->attribute(SketchPlugin_Constraint::ENTITY_B())); - aRefAttr->setObject(aResultFeatures[i]->lastResult()); - aConstraint->execute(); - aFilletFeatures.resultConstraints.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); - aConstraint = sketch()->addFeature(SketchPlugin_ConstraintCoincidence::ID()); - aRefAttr = std::dynamic_pointer_cast( - aConstraint->attribute(SketchPlugin_Constraint::ENTITY_A())); - aRefAttr->setAttr(aResultFeatures[i]->attribute(aFeatAttributes[anAttrInd])); - aRefAttr = std::dynamic_pointer_cast( - aConstraint->attribute(SketchPlugin_Constraint::ENTITY_B())); - aRefAttr->setObject(aBaseFeatures[i]->lastResult()); - aFilletFeatures.resultConstraints.push_back(aConstraint); - } - // make base features auxiliary - aBaseEdgeA->boolean(SketchPlugin_SketchEntity::AUXILIARY_ID())->setValue(true); - aBaseEdgeB->boolean(SketchPlugin_SketchEntity::AUXILIARY_ID())->setValue(true); - - // exchange the naming IDs of newly created and old line that become auxiliary - sketch()->exchangeIDs(aBaseEdgeA, aResultEdgeA); - sketch()->exchangeIDs(aBaseEdgeB, aResultEdgeB); - - // store point and features in the map. - myPointFeaturesMap[aPointAttr] = aFilletFeatures; - } else { - // Update radius value - int aNbSubs = sketch()->numberOfSubs(); - FeaturePtr aSubFeature; - for (int aSub = 0; aSub < aNbSubs; aSub++) { - aSubFeature = sketch()->subFeature(aSub); - if (aSubFeature->getKind() != SketchPlugin_ConstraintRadius::ID()) - continue; - AttributeRefAttrPtr aRefAttr = std::dynamic_pointer_cast( - aSubFeature->attribute(SketchPlugin_Constraint::ENTITY_A())); - if (!aRefAttr || !aRefAttr->isObject()) - continue; - FeaturePtr aFeature = ModelAPI_Feature::feature(aRefAttr->object()); - if (aFeature == aResultArc) { - AttributeDoublePtr aRadius = std::dynamic_pointer_cast( - aSubFeature->attribute(SketchPlugin_Constraint::VALUE())); - aRadius->setValue(aFilletRadius); - break; - } - } - } - } - - // Send events to update the sub-features by the solver. - if(isUpdateFlushed) { - Events_Loop::loop()->setFlushed(anUpdateEvent, true); - } -} - -void SketchPlugin_ConstraintFillet::attributeChanged(const std::string& theID) -{ - if(theID == SketchPlugin_Constraint::ENTITY_A()) { - if(myListOfPointsChangedInCode) { - return; - } - - // Clear results. - clearResults(); - - // Clear list of new points. - myNewPoints.clear(); - - // Get list of points for fillets and current radius. - AttributeRefAttrListPtr aRefListOfFilletPoints = - std::dynamic_pointer_cast( - data()->attribute(SketchPlugin_Constraint::ENTITY_A())); - AttributeDoublePtr aRadiusAttribute = real(VALUE()); - int aListSize = aRefListOfFilletPoints->size(); - if(aListSize == 0 && !myRadiusChangedByUser) { - // If list is empty reset radius to zero (if it was not changed by user). - myRadiusChangedInCode = true; - aRadiusAttribute->setValue(0); - myRadiusChangedInCode = false; - return; - } - - // Iterate over points to get base lines an calculate radius for fillets. - double aMinimumRadius = 0; - std::list> - aSelectedPointsList = aRefListOfFilletPoints->list(); - std::list>::iterator anIter = aSelectedPointsList.begin(); - std::set aPointsToSkeep; - for(int anIndex = 0; anIndex < aListSize; anIndex++, anIter++) { - AttributePtr aFilletPointAttr = (*anIter).second; - std::shared_ptr aFilletPoint2D = - std::dynamic_pointer_cast(aFilletPointAttr); - if(!aFilletPoint2D.get()) { - myNewPoints.clear(); - setError("Error: One of the selected points is invalid."); - return; - } - - // If point or coincident point is already in list remove it from attribute. - if(aPointsToSkeep.find(aFilletPointAttr) != aPointsToSkeep.end()) { - myListOfPointsChangedInCode = true; - aRefListOfFilletPoints->remove(aFilletPointAttr); - myListOfPointsChangedInCode = false; - continue; - } - - // Obtain constraint coincidence for the fillet point. - FeaturePtr aConstraintCoincidence; - const std::set& aRefsList = aFilletPointAttr->owner()->data()->refsToMe(); - for(std::set::const_iterator - anIt = aRefsList.cbegin(); anIt != aRefsList.cend(); ++anIt) { - std::shared_ptr anAttr = (*anIt); - FeaturePtr aConstrFeature = std::dynamic_pointer_cast(anAttr->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()) { - AttributePtr anAttrA = anAttrRefA->attr(); - if(aFilletPointAttr == anAttrA) { - aConstraintCoincidence = aConstrFeature; - break; - } - } - if(anAttrRefB.get()) { - AttributePtr anAttrB = anAttrRefB->attr(); - if(aFilletPointAttr == anAttrB) { - aConstraintCoincidence = aConstrFeature; - break; - } - } - } - } - - if(!aConstraintCoincidence.get()) { - myNewPoints.clear(); - setError("Error: No coincident edges at one of the selected points."); - return; - } - - // Get coincides from constraint. - std::set aCoincides; - - - SketchPlugin_Tools::findCoincidences(aConstraintCoincidence, - SketchPlugin_ConstraintCoincidence::ENTITY_A(), - aCoincides); - SketchPlugin_Tools::findCoincidences(aConstraintCoincidence, - SketchPlugin_ConstraintCoincidence::ENTITY_B(), - aCoincides); - - // Remove points from set of coincides. - // Also get all attributes which is equal to this point to exclude it. - std::shared_ptr aFilletPnt2d = aFilletPoint2D->pnt(); - std::set aNewSetOfCoincides; - for(std::set::iterator - anIt = aCoincides.begin(); anIt != aCoincides.end(); ++anIt) { - std::string aFeatureKind = (*anIt)->getKind(); - if(aFeatureKind == SketchPlugin_Point::ID()) { - AttributePtr anAttr = (*anIt)->attribute(SketchPlugin_Point::COORD_ID()); - std::shared_ptr aPoint2D = - std::dynamic_pointer_cast(anAttr); - if(aPoint2D.get() && aFilletPnt2d->isEqual(aPoint2D->pnt())) { - aPointsToSkeep.insert(anAttr); - } - } else if(aFeatureKind == SketchPlugin_Line::ID()) { - AttributePtr anAttrStart = (*anIt)->attribute(SketchPlugin_Line::START_ID()); - std::shared_ptr aPointStart2D = - std::dynamic_pointer_cast(anAttrStart); - if(aPointStart2D.get() && aFilletPnt2d->isEqual(aPointStart2D->pnt())) { - aPointsToSkeep.insert(anAttrStart); - } - AttributePtr anAttrEnd = (*anIt)->attribute(SketchPlugin_Line::END_ID()); - std::shared_ptr aPointEnd2D = - std::dynamic_pointer_cast(anAttrEnd); - if(aPointEnd2D.get() && aFilletPnt2d->isEqual(aPointEnd2D->pnt())) { - aPointsToSkeep.insert(anAttrEnd); - } - aNewSetOfCoincides.insert(*anIt); - } else if(aFeatureKind == SketchPlugin_Arc::ID() ) { - AttributePtr anAttrCenter = (*anIt)->attribute(SketchPlugin_Arc::CENTER_ID()); - std::shared_ptr aPointCenter2D = - std::dynamic_pointer_cast(anAttrCenter); - if(aPointCenter2D.get() && aFilletPnt2d->isEqual(aPointCenter2D->pnt())) { - aPointsToSkeep.insert(anAttrCenter); - continue; - } - AttributePtr anAttrStart = (*anIt)->attribute(SketchPlugin_Arc::START_ID()); - std::shared_ptr aPointStart2D = - std::dynamic_pointer_cast(anAttrStart); - if(aPointStart2D.get() && aFilletPnt2d->isEqual(aPointStart2D->pnt())) { - aPointsToSkeep.insert(anAttrStart); - } - AttributePtr anAttrEnd = (*anIt)->attribute(SketchPlugin_Arc::END_ID()); - std::shared_ptr aPointEnd2D = - std::dynamic_pointer_cast(anAttrEnd); - if(aPointEnd2D.get() && aFilletPnt2d->isEqual(aPointEnd2D->pnt())) { - aPointsToSkeep.insert(anAttrEnd); - } - aNewSetOfCoincides.insert(*anIt); - } - } - aCoincides = aNewSetOfCoincides; - - // If we still have more than two coincides remove auxilary entities from set of coincides. - if(aCoincides.size() > 2) { - aNewSetOfCoincides.clear(); - for(std::set::iterator - anIt = aCoincides.begin(); anIt != aCoincides.end(); ++anIt) { - if(!(*anIt)->boolean(SketchPlugin_SketchEntity::AUXILIARY_ID())->value()) { - aNewSetOfCoincides.insert(*anIt); - } - } - aCoincides = aNewSetOfCoincides; - } - - if(aCoincides.size() != 2) { - myNewPoints.clear(); - setError("Error: One of the selected points does not have two suitable edges for fillet."); - return; - } - - // Store base point for fillet. - aPointsToSkeep.insert(aFilletPointAttr); - myNewPoints.insert(aFilletPointAttr); - - // Get base lines for fillet. - FeaturePtr anOldFeatureA, anOldFeatureB; - std::set::iterator aLinesIt = aCoincides.begin(); - anOldFeatureA = *aLinesIt++; - anOldFeatureB = *aLinesIt; - - // Getting radius value if it was not changed by user. - if(!myRadiusChangedByUser) { - // Getting points located at 1/3 of edge length from fillet point. - std::shared_ptr aFilletPnt2d = aFilletPoint2D->pnt(); - std::shared_ptr aPntA, aPntB; - getPointOnEdge(anOldFeatureA, aFilletPnt2d, aPntA); - getPointOnEdge(anOldFeatureB, aFilletPnt2d, aPntB); - - /// Getting distances. - double aDistanceA = getProjectionDistance(anOldFeatureB, aPntA); - double aDistanceB = getProjectionDistance(anOldFeatureA, aPntB); - double aRadius = aDistanceA < aDistanceB ? aDistanceA / 2.0 : aDistanceB / 2.0; - aMinimumRadius = aMinimumRadius == 0 ? aRadius : - aRadius < aMinimumRadius ? aRadius : aMinimumRadius; - } - } - - // Set new default radius if it was not changed by user. - if(!myRadiusChangedByUser) { - myRadiusChangedInCode = true; - aRadiusAttribute->setValue(aMinimumRadius); - myRadiusChangedInCode = false; - } - - } else if(theID == SketchPlugin_Constraint::VALUE()) { - if(myRadiusInitialized && !myRadiusChangedInCode) { - myRadiusChangedByUser = true; - } - if(!myRadiusInitialized) { - myRadiusInitialized = true; - } - } -} - -AISObjectPtr SketchPlugin_ConstraintFillet::getAISObject(AISObjectPtr thePrevious) -{ - if (!sketch()) - return thePrevious; - - AISObjectPtr anAIS = thePrevious; - /// TODO: Equal constraint presentation should be put here - return anAIS; -} - -bool SketchPlugin_ConstraintFillet::isMacro() const -{ - return true; -} - -void SketchPlugin_ConstraintFillet::clearResults() -{ - // Clear auxiliary flag on initial objects. - for(std::map::iterator aPointsIter = myPointFeaturesMap.begin(); - aPointsIter != myPointFeaturesMap.end();) { - const FilletFeatures& aFilletFeatures = aPointsIter->second; - std::list>::const_iterator aFeatureIt; - for(aFeatureIt = aFilletFeatures.baseEdgesState.cbegin(); - aFeatureIt != aFilletFeatures.baseEdgesState.cend(); - ++aFeatureIt) { - aFeatureIt->first->boolean( - SketchPlugin_SketchEntity::AUXILIARY_ID())->setValue(aFeatureIt->second); - } - ++aPointsIter; - } - - // And remove all produced features. - DocumentPtr aDoc = sketch()->document(); - for(std::map::iterator aPointsIter = myPointFeaturesMap.begin(); - aPointsIter != myPointFeaturesMap.end();) { - // Remove all produced constraints. - const FilletFeatures& aFilletFeatures = aPointsIter->second; - std::list::const_iterator aFeatureIt; - for(aFeatureIt = aFilletFeatures.resultConstraints.cbegin(); - aFeatureIt != aFilletFeatures.resultConstraints.cend(); - ++aFeatureIt) { - aDoc->removeFeature(*aFeatureIt); - } - - // Remove all result edges. - for(aFeatureIt = aFilletFeatures.resultEdges.cbegin(); - aFeatureIt != aFilletFeatures.resultEdges.cend(); - ++aFeatureIt) { - aDoc->removeFeature(*aFeatureIt); - } - - // Remove point from map. - myPointFeaturesMap.erase(aPointsIter++); - } -}; - - -// ========= Auxiliary functions ================= -void recalculateAttributes(FeaturePtr theNewArc, const std::string& theNewArcAttribute, - FeaturePtr theFeature, const std::string& theFeatureAttribute) -{ - std::shared_ptr anArcPoint = std::dynamic_pointer_cast( - theNewArc->attribute(theNewArcAttribute))->pnt(); - std::dynamic_pointer_cast( - theFeature->attribute(theFeatureAttribute))->setValue(anArcPoint->x(), anArcPoint->y()); -} - -/// \brief Find intersections of lines shifted along normal direction -void possibleFilletCenterLineLine( - std::shared_ptr thePointA, std::shared_ptr theDirA, - std::shared_ptr thePointB, std::shared_ptr theDirB, - double theRadius, std::list< std::shared_ptr >& theCenters) -{ - std::shared_ptr aDirAT(new GeomAPI_Dir2d(-theDirA->y(), theDirA->x())); - std::shared_ptr aDirBT(new GeomAPI_Dir2d(-theDirB->y(), theDirB->x())); - std::shared_ptr aPntA, aPntB; - double aDet = theDirA->cross(theDirB); - for (double aStepA = -1.0; aStepA <= 1.0; aStepA += 2.0) { - aPntA = thePointA->added(aDirAT->xy()->multiplied(aStepA * theRadius)); - for (double aStepB = -1.0; aStepB <= 1.0; aStepB += 2.0) { - aPntB = thePointB->added(aDirBT->xy()->multiplied(aStepB * theRadius)); - double aVX = aDirAT->xy()->dot(aPntA); - double aVY = aDirBT->xy()->dot(aPntB); - std::shared_ptr aPoint(new GeomAPI_XY( - (theDirB->x() * aVX - theDirA->x() * aVY) / aDet, - (theDirB->y() * aVX - theDirA->y() * aVY) / aDet)); - theCenters.push_back(aPoint); - } - } -} - -/// \brief Find intersections of line shifted along normal direction in both sides -/// and a circle with extended radius -void possibleFilletCenterLineArc( - std::shared_ptr theStartLine, std::shared_ptr theDirLine, - std::shared_ptr theCenterArc, double theRadiusArc, - double theRadius, std::list< std::shared_ptr >& theCenters) -{ - std::shared_ptr aDirT(new GeomAPI_Dir2d(-theDirLine->y(), theDirLine->x())); - std::shared_ptr aPnt; - double aDirNorm2 = theDirLine->dot(theDirLine); - double aRad = 0.0; - double aDirX = theDirLine->x(); - double aDirX2 = theDirLine->x() * theDirLine->x(); - double aDirY2 = theDirLine->y() * theDirLine->y(); - double aDirXY = theDirLine->x() * theDirLine->y(); - for (double aStepA = -1.0; aStepA <= 1.0; aStepA += 2.0) { - aPnt = theStartLine->added(aDirT->xy()->multiplied(aStepA * theRadius)); - double aCoeff = aDirT->xy()->dot(aPnt->decreased(theCenterArc)); - double aCoeff2 = aCoeff * aCoeff; - for (double aStepB = -1.0; aStepB <= 1.0; aStepB += 2.0) { - aRad = theRadiusArc + aStepB * theRadius; - double aD = aRad * aRad * aDirNorm2 - aCoeff2; - if (aD < 0.0) - continue; - double aDs = sqrt(aD); - double x1 = theCenterArc->x() + (aCoeff * aDirT->x() - aDirT->y() * aDs) / aDirNorm2; - double x2 = theCenterArc->x() + (aCoeff * aDirT->x() + aDirT->y() * aDs) / aDirNorm2; - double y1 = (aDirX2 * aPnt->y() + aDirY2 * theCenterArc->y() - - aDirXY * (aPnt->x() - theCenterArc->x()) - theDirLine->y() * aDs) / aDirNorm2; - double y2 = (aDirX2 * aPnt->y() + aDirY2 * theCenterArc->y() - - aDirXY * (aPnt->x() - theCenterArc->x()) + theDirLine->y() * aDs) / aDirNorm2; - - std::shared_ptr aPoint1(new GeomAPI_XY(x1, y1)); - theCenters.push_back(aPoint1); - std::shared_ptr aPoint2(new GeomAPI_XY(x2, y2)); - theCenters.push_back(aPoint2); - } - } -} - -/// \brief Find intersections of two circles with extended radii -void possibleFilletCenterArcArc( - std::shared_ptr theCenterA, double theRadiusA, - std::shared_ptr theCenterB, double theRadiusB, - double theRadius, std::list< std::shared_ptr >& theCenters) -{ - std::shared_ptr aCenterDir = theCenterB->decreased(theCenterA); - double aCenterDist2 = aCenterDir->dot(aCenterDir); - double aCenterDist = sqrt(aCenterDist2); - - double aRadA, aRadB; - for (double aStepA = -1.0; aStepA <= 1.0; aStepA += 2.0) { - aRadA = theRadiusA + aStepA * theRadius; - for (double aStepB = -1.0; aStepB <= 1.0; aStepB += 2.0) { - aRadB = theRadiusB + aStepB * theRadius; - if (aRadA + aRadB < aCenterDist || fabs(aRadA - aRadB) > aCenterDist) - continue; // there is no intersections - - double aMedDist = (aRadA * aRadA - aRadB * aRadB + aCenterDist2) / (2.0 * aCenterDist); - double aHeight = sqrt(aRadA * aRadA - aMedDist * aMedDist); - - double x1 = theCenterA->x() + - (aMedDist * aCenterDir->x() + aCenterDir->y() * aHeight) / aCenterDist; - double y1 = theCenterA->y() + - (aMedDist * aCenterDir->y() - aCenterDir->x() * aHeight) / aCenterDist; - - double x2 = theCenterA->x() + - (aMedDist * aCenterDir->x() - aCenterDir->y() * aHeight) / aCenterDist; - double y2 = theCenterA->y() + - (aMedDist * aCenterDir->y() + aCenterDir->x() * aHeight) / aCenterDist; - - std::shared_ptr aPoint1(new GeomAPI_XY(x1, y1)); - theCenters.push_back(aPoint1); - std::shared_ptr aPoint2(new GeomAPI_XY(x2, y2)); - theCenters.push_back(aPoint2); - } - } -} - -void calculateFilletCenter(FeaturePtr theFeatureA, FeaturePtr theFeatureB, - double theRadius, bool theNotInversed[2], - std::shared_ptr& theCenter, - std::shared_ptr& theTangentA, - std::shared_ptr& theTangentB) -{ - static const int aNbFeatures = 2; - FeaturePtr aFeature[aNbFeatures] = {theFeatureA, theFeatureB}; - std::shared_ptr aStart[aNbFeatures], aEnd[aNbFeatures], aCenter[aNbFeatures]; - std::shared_ptr aStartPoint, aEndPoint; - - for (int i = 0; i < aNbFeatures; i++) { - if (aFeature[i]->getKind() == SketchPlugin_Line::ID()) { - aStartPoint = std::dynamic_pointer_cast( - aFeature[i]->attribute(SketchPlugin_Line::START_ID())); - aEndPoint = std::dynamic_pointer_cast( - aFeature[i]->attribute(SketchPlugin_Line::END_ID())); - } else if (aFeature[i]->getKind() == SketchPlugin_Arc::ID()) { - aStartPoint = std::dynamic_pointer_cast( - aFeature[i]->attribute(SketchPlugin_Arc::START_ID())); - aEndPoint = std::dynamic_pointer_cast( - aFeature[i]->attribute(SketchPlugin_Arc::END_ID())); - aCenter[i] = std::dynamic_pointer_cast( - aFeature[i]->attribute(SketchPlugin_Arc::CENTER_ID()))->pnt()->xy(); - } else - return; - aStart[i] = std::shared_ptr(theNotInversed[i] ? - new GeomAPI_XY(aStartPoint->x(), aStartPoint->y()) : - new GeomAPI_XY(aEndPoint->x(), aEndPoint->y())); - aEnd[i] = std::shared_ptr(theNotInversed[i] ? - new GeomAPI_XY(aEndPoint->x(), aEndPoint->y()) : - new GeomAPI_XY(aStartPoint->x(), aStartPoint->y())); - } - - if (theFeatureA->getKind() == SketchPlugin_Line::ID() && - theFeatureB->getKind() == SketchPlugin_Line::ID()) { - std::shared_ptr aDir[2]; - std::shared_ptr aDirT[2]; - for (int i = 0; i < aNbFeatures; i++) { - aDir[i] = std::shared_ptr(new GeomAPI_Dir2d(aEnd[i]->decreased(aStart[i]))); - aDirT[i] = std::shared_ptr(new GeomAPI_Dir2d(-aDir[i]->y(), aDir[i]->x())); - } - - // get and filter possible centers - std::list< std::shared_ptr > aSuspectCenters; - possibleFilletCenterLineLine(aStart[0], aDir[0], aStart[1], aDir[1], - theRadius, aSuspectCenters); - double aDot = 0.0; - std::list< std::shared_ptr >::iterator anIt = aSuspectCenters.begin(); - for (; anIt != aSuspectCenters.end(); anIt++) { - aDot = aDirT[0]->xy()->dot(aStart[0]->decreased(*anIt)); - theTangentA = (*anIt)->added(aDirT[0]->xy()->multiplied(aDot)); - if (theTangentA->decreased(aStart[0])->dot(aDir[0]->xy()) < 0.0) - continue; // incorrect position - aDot = aDirT[1]->xy()->dot(aStart[1]->decreased(*anIt)); - theTangentB = (*anIt)->added(aDirT[1]->xy()->multiplied(aDot)); - if (theTangentB->decreased(aStart[1])->dot(aDir[1]->xy()) < 0.0) - continue; // incorrect position - // the center is found, stop searching - theCenter = *anIt; - return; - } - } else if ((theFeatureA->getKind() == SketchPlugin_Arc::ID() && - theFeatureB->getKind() == SketchPlugin_Line::ID()) || - (theFeatureA->getKind() == SketchPlugin_Line::ID() && - theFeatureB->getKind() == SketchPlugin_Arc::ID())) { - int aLineInd = theFeatureA->getKind() == SketchPlugin_Line::ID() ? 0 : 1; - double anArcRadius = aStart[1-aLineInd]->distance(aCenter[1-aLineInd]); - std::shared_ptr aDirLine = std::shared_ptr( - new GeomAPI_Dir2d(aEnd[aLineInd]->decreased(aStart[aLineInd]))); - std::shared_ptr aDirT = std::shared_ptr( - new GeomAPI_Dir2d(-aDirLine->y(), aDirLine->x())); - - std::shared_ptr aStartArcDir = std::shared_ptr( - new GeomAPI_Dir2d(aStart[1-aLineInd]->decreased(aCenter[1-aLineInd]))); - std::shared_ptr aEndArcDir = std::shared_ptr( - new GeomAPI_Dir2d(aEnd[1-aLineInd]->decreased(aCenter[1-aLineInd]))); - double anArcAngle = aEndArcDir->angle(aStartArcDir); - - // 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)); - // 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; - 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)); - if (theFeatureA->getKind() == SketchPlugin_Line::ID()) { - theTangentA = aLineTgPoint; - theTangentB = anArcTgPoint; - } else { - theTangentA = anArcTgPoint; - theTangentB = aLineTgPoint; - } - //return; - } - } else if (theFeatureA->getKind() == SketchPlugin_Arc::ID() && - theFeatureB->getKind() == SketchPlugin_Arc::ID()) { - double anArcRadius[aNbFeatures]; - double anArcAngle[aNbFeatures]; - std::shared_ptr aStartArcDir[aNbFeatures]; - for (int i = 0; i < aNbFeatures; i++) { - anArcRadius[i] = aStart[i]->distance(aCenter[i]); - aStartArcDir[i] = std::shared_ptr( - new GeomAPI_Dir2d(aStart[i]->decreased(aCenter[i]))); - std::shared_ptr aEndArcDir = std::shared_ptr( - new GeomAPI_Dir2d(aEnd[i]->decreased(aCenter[i]))); - anArcAngle[i] = aEndArcDir->angle(aStartArcDir[i]); - } - - // get and filter possible centers - std::list< std::shared_ptr > aSuspectCenters; - possibleFilletCenterArcArc(aCenter[0], anArcRadius[0], aCenter[1], - anArcRadius[1], theRadius, aSuspectCenters); - double aDot = 0.0; - std::shared_ptr aLineTgPoint, anArcTgPoint; - std::list< std::shared_ptr >::iterator anIt = aSuspectCenters.begin(); - for (; anIt != aSuspectCenters.end(); anIt++) { - std::shared_ptr aCurDir = std::shared_ptr( - new GeomAPI_Dir2d((*anIt)->decreased(aCenter[0]))); - double aCurAngle = aCurDir->angle(aStartArcDir[0]); - if (anArcAngle[0] < 0.0) aCurAngle *= -1.0; - if (aCurAngle < 0.0 || aCurAngle > fabs(anArcAngle[0])) - continue; // incorrect position - theTangentA = aCenter[0]->added(aCurDir->xy()->multiplied(anArcRadius[0])); - - aCurDir = std::shared_ptr(new GeomAPI_Dir2d((*anIt)->decreased(aCenter[1]))); - aCurAngle = aCurDir->angle(aStartArcDir[1]); - if (anArcAngle[1] < 0.0) aCurAngle *= -1.0; - if (aCurAngle < 0.0 || aCurAngle > fabs(anArcAngle[1])) - continue; // incorrect position - theTangentB = aCenter[1]->added(aCurDir->xy()->multiplied(anArcRadius[1])); - - // the center is found, stop searching - theCenter = *anIt; - return; - } - } -} - -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; -} - -std::set getCoincides(const FeaturePtr& theConstraintCoincidence) -{ - std::set aCoincides; - - std::shared_ptr aFilletPnt = - SketchPlugin_Tools::getCoincidencePoint(theConstraintCoincidence); - - SketchPlugin_Tools::findCoincidences(theConstraintCoincidence, - SketchPlugin_ConstraintCoincidence::ENTITY_A(), - aCoincides); - SketchPlugin_Tools::findCoincidences(theConstraintCoincidence, - SketchPlugin_ConstraintCoincidence::ENTITY_B(), - aCoincides); - - // Remove points from set of coincides. - std::set aNewSetOfCoincides; - for(std::set::iterator anIt = aCoincides.begin(); anIt != aCoincides.end(); ++anIt) { - if((*anIt)->getKind() == SketchPlugin_Line::ID()) { - aNewSetOfCoincides.insert(*anIt); - } else if((*anIt)->getKind() == SketchPlugin_Arc::ID()) { - AttributePtr anAttrCenter = (*anIt)->attribute(SketchPlugin_Arc::CENTER_ID()); - std::shared_ptr aPointCenter2D = - std::dynamic_pointer_cast(anAttrCenter); - if(aPointCenter2D.get() && aFilletPnt->isEqual(aPointCenter2D->pnt())) { - continue; - } - aNewSetOfCoincides.insert(*anIt); - } - } - aCoincides = aNewSetOfCoincides; - - // If we still have more than two coincides remove auxilary entities from set of coincides. - if(aCoincides.size() > 2) { - aNewSetOfCoincides.clear(); - for(std::set::iterator - anIt = aCoincides.begin(); anIt != aCoincides.end(); ++anIt) { - if(!(*anIt)->boolean(SketchPlugin_SketchEntity::AUXILIARY_ID())->value()) { - aNewSetOfCoincides.insert(*anIt); - } - } - aCoincides = aNewSetOfCoincides; - } - - return aCoincides; -} diff --git a/src/SketchPlugin/SketchPlugin_ConstraintFillet.h b/src/SketchPlugin/SketchPlugin_ConstraintFillet.h deleted file mode 100644 index d860688dd..000000000 --- a/src/SketchPlugin/SketchPlugin_ConstraintFillet.h +++ /dev/null @@ -1,91 +0,0 @@ -// Copyright (C) 2014-20xx CEA/DEN, EDF R&D --> - -// File: SketchPlugin_ConstraintFillet.h -// Created: 19 Mar 2015 -// Author: Artem ZHIDKOV - -#ifndef SketchPlugin_ConstraintFillet_H_ -#define SketchPlugin_ConstraintFillet_H_ - -#include "SketchPlugin.h" -#include -#include "SketchPlugin_ConstraintBase.h" - -/** \class SketchPlugin_ConstraintFillet - * \ingroup Plugins - * \brief Feature for creation of a new constraint filleting two objects which have - * coincident point - * - * This constraint has three attributes: - * SketchPlugin_Constraint::ENTITY_A() and SketchPlugin_Constraint::ENTITY_B() - * for the filleting objects; - * SketchPlugin_Constraint::VALUE() contains radius of filleting circular arc - * - * Also the constraint has attribute SketchPlugin_Constraint::ENTITY_C() - * which contains created list objects forming the fillet - */ -class SketchPlugin_ConstraintFillet : public SketchPlugin_ConstraintBase -{ - public: - /// \struct Struct to store base edges with states, result edges and constraints. - struct FilletFeatures { - /// list of objects the fillet is based and its states - std::list> baseEdgesState; - std::list resultEdges; ///< list of result edges - std::list resultConstraints; ///< list of constraints provided by the fillet - }; - - /// Fillet constraint kind - inline static const std::string& ID() - { - static const std::string MY_CONSTRAINT_FILLET_ID("SketchConstraintFillet"); - return MY_CONSTRAINT_FILLET_ID; - } - /// \brief Returns the kind of a feature - SKETCHPLUGIN_EXPORT virtual const std::string& getKind() - { - static std::string MY_KIND = SketchPlugin_ConstraintFillet::ID(); - return MY_KIND; - } - - /// \brief Creates a new part document if needed - SKETCHPLUGIN_EXPORT virtual void execute(); - - /// \brief Request for initialization of data model of the feature: adding all attributes - SKETCHPLUGIN_EXPORT virtual void initAttributes(); - - /// Called on change of any argument-attribute of this object - /// \param theID identifier of changed attribute - SKETCHPLUGIN_EXPORT virtual void attributeChanged(const std::string& theID); - - /// Returns the AIS preview - SKETCHPLUGIN_EXPORT virtual AISObjectPtr getAISObject(AISObjectPtr thePrevious); - - /// Reimplemented from ModelAPI_Feature::isMacro(). - /// \returns true - SKETCHPLUGIN_EXPORT virtual bool isMacro() const; - - /// \brief Use plugin manager for features creation - SketchPlugin_ConstraintFillet(); - - /// \return map of base points and features; - SKETCHPLUGIN_EXPORT const std::map pointsFeaturesMap() const { - return myPointFeaturesMap; - }; - -private: - /// \ Removes all produced features and restore base edges. - void clearResults(); - -private: - std::set myNewPoints; ///< set of new points - - /// map of point and features for fillet - std::map myPointFeaturesMap; - bool myListOfPointsChangedInCode; ///< flag to track that list of points changed in code - bool myRadiusChangedByUser; ///< flag to track that radius changed by user - bool myRadiusChangedInCode; ///< flag to track that radius changed in code - bool myRadiusInitialized; /// < flag to track that radius initialized -}; - -#endif diff --git a/src/SketchPlugin/SketchPlugin_Fillet.cpp b/src/SketchPlugin/SketchPlugin_Fillet.cpp new file mode 100644 index 000000000..9a163403f --- /dev/null +++ b/src/SketchPlugin/SketchPlugin_Fillet.cpp @@ -0,0 +1,796 @@ +// Copyright (C) 2014-20xx CEA/DEN, EDF R&D --> + +// File: SketchPlugin_Fillet.cpp +// Created: 19 Mar 2015 +// Author: Artem ZHIDKOV + +#include "SketchPlugin_Fillet.h" + +#include "SketchPlugin_Arc.h" +#include "SketchPlugin_Line.h" +#include "SketchPlugin_Point.h" +#include "SketchPlugin_Sketch.h" +#include "SketchPlugin_ConstraintEqual.h" +#include "SketchPlugin_ConstraintCoincidence.h" +#include "SketchPlugin_ConstraintLength.h" +#include "SketchPlugin_ConstraintTangent.h" +#include "SketchPlugin_ConstraintRadius.h" +#include "SketchPlugin_Tools.h" + +#include +#include +#include +#include +#include +#include + +#include + +#include +#include +#include +#include +#include + +#include + +#include + +#include + +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); + +/// \brief Calculates center of fillet arc and coordinates of tangency points +static void calculateFilletCenter(FeaturePtr theFeatureA, FeaturePtr theFeatureB, + double theRadius, bool theNotInversed[2], + std::shared_ptr& theCenter, + 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); + +/// Get coincide edges for fillet +static std::set getCoincides(const FeaturePtr& theConstraintCoincidence); + +static std::set findFeaturesToRemove(const FeaturePtr theFeature, + const AttributePtr theAttribute); + +SketchPlugin_Fillet::SketchPlugin_Fillet() +: myFilletCreated(false) +{ +} + +void SketchPlugin_Fillet::initAttributes() +{ + data()->addAttribute(FILLET_POINT_ID(), ModelAPI_AttributeRefAttr::typeId()); +} + +void SketchPlugin_Fillet::execute() +{ + // Wait all constraints being created, then send update events + static Events_ID anUpdateEvent = Events_Loop::eventByName(EVENT_OBJECT_UPDATED); + bool isUpdateFlushed = Events_Loop::loop()->isFlushed(anUpdateEvent); + if (isUpdateFlushed) + Events_Loop::loop()->setFlushed(anUpdateEvent, false); + + // Create arc feature. + FeaturePtr aFilletArc = sketch()->addFeature(SketchPlugin_Arc::ID()); + + // Set arc attributes. + bool aWasBlocked = aFilletArc->data()->blockSendAttributeUpdated(true); + std::dynamic_pointer_cast( + aFilletArc->attribute(SketchPlugin_Arc::CENTER_ID()))->setValue(myCenterXY->x(), + myCenterXY->y()); + std::shared_ptr aStartPoint = + std::dynamic_pointer_cast( + aFilletArc->attribute(SketchPlugin_Arc::START_ID())); + std::shared_ptr aEndPoint = + std::dynamic_pointer_cast( + aFilletArc->attribute(SketchPlugin_Arc::END_ID())); + if(aStartPoint->isInitialized() && aEndPoint->isInitialized() + && (aStartPoint->pnt()->xy()->distance(myTangentXY1) > tolerance + || aEndPoint->pnt()->xy()->distance(myTangentXY2) > tolerance)) { + std::dynamic_pointer_cast(aFilletArc)->setReversed(false); + } + aStartPoint->setValue(myTangentXY1->x(), myTangentXY1->y()); + aEndPoint->setValue(myTangentXY2->x(), myTangentXY2->y()); + aFilletArc->data()->blockSendAttributeUpdated(aWasBlocked); + aFilletArc->execute(); + + // Delete features with refs to points of edges. + std::shared_ptr aStartPoint1; + int aFeatInd1 = myIsReversed ? 1 : 0; + int anAttrInd1 = (myIsReversed ? 2 : 0) + (myIsNotInversed[aFeatInd1] ? 0 : 1); + aStartPoint1 = std::dynamic_pointer_cast( + myBaseFeatures[aFeatInd1]->attribute(myFeatAttributes[anAttrInd1])); + std::set aFeaturesToBeRemoved1 = + findFeaturesToRemove(myBaseFeatures[aFeatInd1], aStartPoint1); + + std::shared_ptr aStartPoint2; + int aFeatInd2 = myIsReversed ? 0 : 1; + int anAttrInd2 = (myIsReversed ? 0 : 2) + (myIsNotInversed[aFeatInd2] ? 0 : 1); + aStartPoint2 = std::dynamic_pointer_cast( + myBaseFeatures[aFeatInd2]->attribute(myFeatAttributes[anAttrInd2])); + std::set aFeaturesToBeRemoved2 = + findFeaturesToRemove(myBaseFeatures[aFeatInd2], aStartPoint2); + + aFeaturesToBeRemoved1.insert(aFeaturesToBeRemoved2.begin(), aFeaturesToBeRemoved2.end()); + ModelAPI_Tools::removeFeaturesAndReferences(aFeaturesToBeRemoved1); + + // Update fillet edges. + recalculateAttributes(aFilletArc, SketchPlugin_Arc::START_ID(), + myBaseFeatures[aFeatInd1], myFeatAttributes[anAttrInd1]); + recalculateAttributes(aFilletArc, SketchPlugin_Arc::END_ID(), + myBaseFeatures[aFeatInd2], myFeatAttributes[anAttrInd2]); + + // Create coincidence features. + FeaturePtr aConstraint = sketch()->addFeature(SketchPlugin_ConstraintCoincidence::ID()); + AttributeRefAttrPtr aRefAttr = std::dynamic_pointer_cast( + aConstraint->attribute(SketchPlugin_Constraint::ENTITY_A())); + aRefAttr->setAttr(aFilletArc->attribute(SketchPlugin_Arc::START_ID())); + aRefAttr = std::dynamic_pointer_cast( + aConstraint->attribute(SketchPlugin_Constraint::ENTITY_B())); + aRefAttr->setAttr(myBaseFeatures[aFeatInd1]->attribute(myFeatAttributes[anAttrInd1])); + aConstraint->execute(); + ModelAPI_EventCreator::get()->sendUpdated(aConstraint, anUpdateEvent); + aConstraint = sketch()->addFeature(SketchPlugin_ConstraintCoincidence::ID()); + aRefAttr = std::dynamic_pointer_cast( + aConstraint->attribute(SketchPlugin_Constraint::ENTITY_A())); + aRefAttr->setAttr(aFilletArc->attribute(SketchPlugin_Arc::END_ID())); + aRefAttr = std::dynamic_pointer_cast( + aConstraint->attribute(SketchPlugin_Constraint::ENTITY_B())); + aRefAttr->setAttr(myBaseFeatures[aFeatInd2]->attribute(myFeatAttributes[anAttrInd2])); + aConstraint->execute(); + ModelAPI_EventCreator::get()->sendUpdated(aConstraint, anUpdateEvent); + + // Create tangent features. + for (int i = 0; i < 2; i++) { + aConstraint = sketch()->addFeature(SketchPlugin_ConstraintTangent::ID()); + aRefAttr = std::dynamic_pointer_cast( + aConstraint->attribute(SketchPlugin_Constraint::ENTITY_A())); + aRefAttr->setObject(aFilletArc->lastResult()); + aRefAttr = std::dynamic_pointer_cast( + aConstraint->attribute(SketchPlugin_Constraint::ENTITY_B())); + bool isArc = myBaseFeatures[i]->getKind() == SketchPlugin_Arc::ID(); + aRefAttr->setObject(isArc ? myBaseFeatures[i]->lastResult() : + myBaseFeatures[i]->firstResult()); + aConstraint->execute(); + ModelAPI_EventCreator::get()->sendUpdated(aConstraint, anUpdateEvent); + } + + // Send events to update the sub-features by the solver. + if(isUpdateFlushed) { + Events_Loop::loop()->setFlushed(anUpdateEvent, true); + } + + myFilletCreated = true; +} + +AISObjectPtr SketchPlugin_Fillet::getAISObject(AISObjectPtr thePrevious) +{ + if(myFilletCreated) { + return AISObjectPtr(); + } + + SketchPlugin_Sketch* aSketch = sketch(); + if(!aSketch) { + return AISObjectPtr(); + } + + // Get fillet point. + AttributeRefAttrPtr aPointRefAttr = refattr(FILLET_POINT_ID()); + if (!aPointRefAttr->isInitialized() || aPointRefAttr->isObject()) { + return AISObjectPtr(); + } + std::shared_ptr aFilletPoint2D = + std::dynamic_pointer_cast(aPointRefAttr->attr()); + if (!aFilletPoint2D.get()) { + return AISObjectPtr(); + } + + // Obtain constraint coincidence for the fillet point. + FeaturePtr aConstraintCoincidence; + const std::set& aRefsList = aFilletPoint2D->owner()->data()->refsToMe(); + for(std::set::const_iterator anIt = aRefsList.cbegin(); + anIt != aRefsList.cend(); + ++anIt) { + std::shared_ptr anAttr = (*anIt); + FeaturePtr aFeature = std::dynamic_pointer_cast(anAttr->owner()); + if(aFeature->getKind() == SketchPlugin_ConstraintCoincidence::ID()) { + AttributeRefAttrPtr anAttrRefA = std::dynamic_pointer_cast( + aFeature->attribute(SketchPlugin_ConstraintCoincidence::ENTITY_A())); + AttributeRefAttrPtr anAttrRefB = std::dynamic_pointer_cast( + aFeature->attribute(SketchPlugin_ConstraintCoincidence::ENTITY_B())); + if(anAttrRefA.get() && !anAttrRefA->isObject()) { + AttributePtr anAttrA = anAttrRefA->attr(); + if(aFilletPoint2D == anAttrA) { + aConstraintCoincidence = aFeature; + break; + } + } + if(anAttrRefB.get() && !anAttrRefB->isObject()) { + AttributePtr anAttrB = anAttrRefB->attr(); + if(aFilletPoint2D == anAttrB) { + aConstraintCoincidence = aFeature; + break; + } + } + } + } + + if(!aConstraintCoincidence.get()) { + setError("Error: No coincident edges at selected point."); + return AISObjectPtr(); + } + + // Get coincide edges. + std::set anEdgeFeatures = getCoincides(aConstraintCoincidence); + if(anEdgeFeatures.size() != 2) { + setError("Error: Selected point does not have two suitable edges for fillet."); + return AISObjectPtr(); + } + + FeaturePtr anEdgeFeature1, anEdgeFeature2; + std::set::iterator aLinesIt = anEdgeFeatures.begin(); + anEdgeFeature1 = *aLinesIt++; + anEdgeFeature2 = *aLinesIt; + + // Getting points located at 1/3 of edge length from fillet point. + std::shared_ptr aFilletPnt2d = aFilletPoint2D->pnt(); + std::shared_ptr aPnt1, aPnt2; + getPointOnEdge(anEdgeFeature1, aFilletPnt2d, aPnt1); + getPointOnEdge(anEdgeFeature2, aFilletPnt2d, aPnt2); + + /// Getting distances. + double aDistance1 = getProjectionDistance(anEdgeFeature2, aPnt1); + double aDistance2 = getProjectionDistance(anEdgeFeature1, aPnt2); + + // Calculate radius value for fillet. + double aRadius = aDistance1 < aDistance2 ? aDistance1 / 2.0 : aDistance2 / 2.0; + + // Calculate arc attributes. + static const int aNbFeatures = 2; + myBaseFeatures[0] = anEdgeFeature1; + myBaseFeatures[1] = anEdgeFeature2; + // First pair of points relate to first feature, second pair - to second. + std::shared_ptr aStartEndPnt[aNbFeatures * 2]; + for (int i = 0; i < aNbFeatures; i++) { + std::string aStartAttr, aEndAttr; + if (myBaseFeatures[i]->getKind() == SketchPlugin_Line::ID()) { + aStartAttr = SketchPlugin_Line::START_ID(); + aEndAttr = SketchPlugin_Line::END_ID(); + } else if (myBaseFeatures[i]->getKind() == SketchPlugin_Arc::ID()) { + aStartAttr = SketchPlugin_Arc::START_ID(); + aEndAttr = SketchPlugin_Arc::END_ID(); + } else { // Wrong argument. + setError("Error: One of the points has wrong coincide feature"); + return AISObjectPtr(); + } + myFeatAttributes[2*i] = aStartAttr; + aStartEndPnt[2*i] = std::dynamic_pointer_cast( + myBaseFeatures[i]->attribute(aStartAttr))->pnt(); + myFeatAttributes[2*i+1] = aEndAttr; + aStartEndPnt[2*i+1] = std::dynamic_pointer_cast( + myBaseFeatures[i]->attribute(aEndAttr))->pnt(); + } + 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(aFilletPnt2d) < 1.e-10) { + myIsNotInversed[aFeatInd] = (j==0); + break; + } + } + + calculateFilletCenter(anEdgeFeature1, anEdgeFeature2, aRadius, + myIsNotInversed, myCenterXY, myTangentXY1, myTangentXY2); + + // Tangent directions of the features in coincident point. + std::shared_ptr aTangentDir[aNbFeatures]; + for (int i = 0; i < aNbFeatures; i++) { + std::shared_ptr aDir; + if (myBaseFeatures[i]->getKind() == SketchPlugin_Line::ID()) { + aDir = aStartEndPnt[2*i+1]->xy()->decreased(aStartEndPnt[2*i]->xy()); + if (!myIsNotInversed[i]) + aDir = aDir->multiplied(-1.0); + } else if (myBaseFeatures[i]->getKind() == SketchPlugin_Arc::ID()) { + std::shared_ptr aCenterPoint = + std::dynamic_pointer_cast( + myBaseFeatures[i]->attribute(SketchPlugin_Arc::CENTER_ID()))->pnt(); + aDir = myIsNotInversed[i] ? aStartEndPnt[2*i]->xy() : aStartEndPnt[2*i+1]->xy(); + aDir = aDir->decreased(aCenterPoint->xy()); + + double x = aDir->x(); + double y = aDir->y(); + aDir->setX(-y); + aDir->setY(x); + if (myIsNotInversed[i] == + std::dynamic_pointer_cast(myBaseFeatures[i])->isReversed()) + aDir = aDir->multiplied(-1.0); + } + aTangentDir[i] = std::shared_ptr(new GeomAPI_Dir2d(aDir)); + } + + // By default, the start point of fillet arc is connected to FeatureA, + // and the end point - to FeatureB. But when the angle between TangentDirA and + // TangentDirB greater 180 degree, the sequaence of features need to be reversed. + double cosBA = aTangentDir[0]->cross(aTangentDir[1]); // cos(B-A), + // where A and B - angles between corresponding tanget direction and the X axis + myIsReversed = cosBA > 0.0; + + if(myIsReversed) { + std::shared_ptr aTmp = myTangentXY1; + myTangentXY1 = myTangentXY2; + myTangentXY2 = aTmp; + } + + // Create arc for presentation. + std::shared_ptr aCenterPnt(aSketch->to3D(myCenterXY->x(), myCenterXY->y())); + std::shared_ptr aTangentPnt1(aSketch->to3D(myTangentXY1->x(), + myTangentXY1->y())); + std::shared_ptr aTangentPnt2(aSketch->to3D(myTangentXY2->x(), + myTangentXY2->y())); + std::shared_ptr aNDir = std::dynamic_pointer_cast( + aSketch->data()->attribute(SketchPlugin_Sketch::NORM_ID())); + std::shared_ptr anArcShape = + GeomAlgoAPI_EdgeBuilder::lineCircleArc(aCenterPnt, aTangentPnt1, aTangentPnt2, aNDir->dir()); + + AISObjectPtr anAISObject = thePrevious; + if(!anAISObject.get()) { + anAISObject = AISObjectPtr(new GeomAPI_AISObject); + } + anAISObject->createShape(anArcShape); + return anAISObject; +} + +// ========= Auxiliary functions ================= +void recalculateAttributes(FeaturePtr theNewArc, const std::string& theNewArcAttribute, + FeaturePtr theFeature, const std::string& theFeatureAttribute) +{ + std::shared_ptr anArcPoint = std::dynamic_pointer_cast( + theNewArc->attribute(theNewArcAttribute))->pnt(); + std::dynamic_pointer_cast( + theFeature->attribute(theFeatureAttribute))->setValue(anArcPoint->x(), anArcPoint->y()); +} + +/// \brief Find intersections of lines shifted along normal direction +void possibleFilletCenterLineLine( + std::shared_ptr thePointA, std::shared_ptr theDirA, + std::shared_ptr thePointB, std::shared_ptr theDirB, + double theRadius, std::list< std::shared_ptr >& theCenters) +{ + std::shared_ptr aDirAT(new GeomAPI_Dir2d(-theDirA->y(), theDirA->x())); + std::shared_ptr aDirBT(new GeomAPI_Dir2d(-theDirB->y(), theDirB->x())); + std::shared_ptr aPntA, aPntB; + double aDet = theDirA->cross(theDirB); + for (double aStepA = -1.0; aStepA <= 1.0; aStepA += 2.0) { + aPntA = thePointA->added(aDirAT->xy()->multiplied(aStepA * theRadius)); + for (double aStepB = -1.0; aStepB <= 1.0; aStepB += 2.0) { + aPntB = thePointB->added(aDirBT->xy()->multiplied(aStepB * theRadius)); + double aVX = aDirAT->xy()->dot(aPntA); + double aVY = aDirBT->xy()->dot(aPntB); + std::shared_ptr aPoint(new GeomAPI_XY( + (theDirB->x() * aVX - theDirA->x() * aVY) / aDet, + (theDirB->y() * aVX - theDirA->y() * aVY) / aDet)); + theCenters.push_back(aPoint); + } + } +} + +/// \brief Find intersections of line shifted along normal direction in both sides +/// and a circle with extended radius +void possibleFilletCenterLineArc( + std::shared_ptr theStartLine, std::shared_ptr theDirLine, + std::shared_ptr theCenterArc, double theRadiusArc, + double theRadius, std::list< std::shared_ptr >& theCenters) +{ + std::shared_ptr aDirT(new GeomAPI_Dir2d(-theDirLine->y(), theDirLine->x())); + std::shared_ptr aPnt; + double aDirNorm2 = theDirLine->dot(theDirLine); + double aRad = 0.0; + double aDirX = theDirLine->x(); + double aDirX2 = theDirLine->x() * theDirLine->x(); + double aDirY2 = theDirLine->y() * theDirLine->y(); + double aDirXY = theDirLine->x() * theDirLine->y(); + for (double aStepA = -1.0; aStepA <= 1.0; aStepA += 2.0) { + aPnt = theStartLine->added(aDirT->xy()->multiplied(aStepA * theRadius)); + double aCoeff = aDirT->xy()->dot(aPnt->decreased(theCenterArc)); + double aCoeff2 = aCoeff * aCoeff; + for (double aStepB = -1.0; aStepB <= 1.0; aStepB += 2.0) { + aRad = theRadiusArc + aStepB * theRadius; + double aD = aRad * aRad * aDirNorm2 - aCoeff2; + if (aD < 0.0) + continue; + double aDs = sqrt(aD); + double x1 = theCenterArc->x() + (aCoeff * aDirT->x() - aDirT->y() * aDs) / aDirNorm2; + double x2 = theCenterArc->x() + (aCoeff * aDirT->x() + aDirT->y() * aDs) / aDirNorm2; + double y1 = (aDirX2 * aPnt->y() + aDirY2 * theCenterArc->y() - + aDirXY * (aPnt->x() - theCenterArc->x()) - theDirLine->y() * aDs) / aDirNorm2; + double y2 = (aDirX2 * aPnt->y() + aDirY2 * theCenterArc->y() - + aDirXY * (aPnt->x() - theCenterArc->x()) + theDirLine->y() * aDs) / aDirNorm2; + + std::shared_ptr aPoint1(new GeomAPI_XY(x1, y1)); + theCenters.push_back(aPoint1); + std::shared_ptr aPoint2(new GeomAPI_XY(x2, y2)); + theCenters.push_back(aPoint2); + } + } +} + +/// \brief Find intersections of two circles with extended radii +void possibleFilletCenterArcArc( + std::shared_ptr theCenterA, double theRadiusA, + std::shared_ptr theCenterB, double theRadiusB, + double theRadius, std::list< std::shared_ptr >& theCenters) +{ + std::shared_ptr aCenterDir = theCenterB->decreased(theCenterA); + double aCenterDist2 = aCenterDir->dot(aCenterDir); + double aCenterDist = sqrt(aCenterDist2); + + double aRadA, aRadB; + for (double aStepA = -1.0; aStepA <= 1.0; aStepA += 2.0) { + aRadA = theRadiusA + aStepA * theRadius; + for (double aStepB = -1.0; aStepB <= 1.0; aStepB += 2.0) { + aRadB = theRadiusB + aStepB * theRadius; + if (aRadA + aRadB < aCenterDist || fabs(aRadA - aRadB) > aCenterDist) + continue; // there is no intersections + + double aMedDist = (aRadA * aRadA - aRadB * aRadB + aCenterDist2) / (2.0 * aCenterDist); + double aHeight = sqrt(aRadA * aRadA - aMedDist * aMedDist); + + double x1 = theCenterA->x() + + (aMedDist * aCenterDir->x() + aCenterDir->y() * aHeight) / aCenterDist; + double y1 = theCenterA->y() + + (aMedDist * aCenterDir->y() - aCenterDir->x() * aHeight) / aCenterDist; + + double x2 = theCenterA->x() + + (aMedDist * aCenterDir->x() - aCenterDir->y() * aHeight) / aCenterDist; + double y2 = theCenterA->y() + + (aMedDist * aCenterDir->y() + aCenterDir->x() * aHeight) / aCenterDist; + + std::shared_ptr aPoint1(new GeomAPI_XY(x1, y1)); + theCenters.push_back(aPoint1); + std::shared_ptr aPoint2(new GeomAPI_XY(x2, y2)); + theCenters.push_back(aPoint2); + } + } +} + +void calculateFilletCenter(FeaturePtr theFeatureA, FeaturePtr theFeatureB, + double theRadius, bool theNotInversed[2], + std::shared_ptr& theCenter, + std::shared_ptr& theTangentA, + std::shared_ptr& theTangentB) +{ + static const int aNbFeatures = 2; + FeaturePtr aFeature[aNbFeatures] = {theFeatureA, theFeatureB}; + std::shared_ptr aStart[aNbFeatures], aEnd[aNbFeatures], aCenter[aNbFeatures]; + std::shared_ptr aStartPoint, aEndPoint; + + for (int i = 0; i < aNbFeatures; i++) { + if (aFeature[i]->getKind() == SketchPlugin_Line::ID()) { + aStartPoint = std::dynamic_pointer_cast( + aFeature[i]->attribute(SketchPlugin_Line::START_ID())); + aEndPoint = std::dynamic_pointer_cast( + aFeature[i]->attribute(SketchPlugin_Line::END_ID())); + } else if (aFeature[i]->getKind() == SketchPlugin_Arc::ID()) { + aStartPoint = std::dynamic_pointer_cast( + aFeature[i]->attribute(SketchPlugin_Arc::START_ID())); + aEndPoint = std::dynamic_pointer_cast( + aFeature[i]->attribute(SketchPlugin_Arc::END_ID())); + aCenter[i] = std::dynamic_pointer_cast( + aFeature[i]->attribute(SketchPlugin_Arc::CENTER_ID()))->pnt()->xy(); + } else + return; + aStart[i] = std::shared_ptr(theNotInversed[i] ? + new GeomAPI_XY(aStartPoint->x(), aStartPoint->y()) : + new GeomAPI_XY(aEndPoint->x(), aEndPoint->y())); + aEnd[i] = std::shared_ptr(theNotInversed[i] ? + new GeomAPI_XY(aEndPoint->x(), aEndPoint->y()) : + new GeomAPI_XY(aStartPoint->x(), aStartPoint->y())); + } + + if (theFeatureA->getKind() == SketchPlugin_Line::ID() && + theFeatureB->getKind() == SketchPlugin_Line::ID()) { + std::shared_ptr aDir[2]; + std::shared_ptr aDirT[2]; + for (int i = 0; i < aNbFeatures; i++) { + aDir[i] = std::shared_ptr(new GeomAPI_Dir2d(aEnd[i]->decreased(aStart[i]))); + aDirT[i] = std::shared_ptr(new GeomAPI_Dir2d(-aDir[i]->y(), aDir[i]->x())); + } + + // get and filter possible centers + std::list< std::shared_ptr > aSuspectCenters; + possibleFilletCenterLineLine(aStart[0], aDir[0], aStart[1], aDir[1], + theRadius, aSuspectCenters); + double aDot = 0.0; + std::list< std::shared_ptr >::iterator anIt = aSuspectCenters.begin(); + for (; anIt != aSuspectCenters.end(); anIt++) { + aDot = aDirT[0]->xy()->dot(aStart[0]->decreased(*anIt)); + theTangentA = (*anIt)->added(aDirT[0]->xy()->multiplied(aDot)); + if (theTangentA->decreased(aStart[0])->dot(aDir[0]->xy()) < 0.0) + continue; // incorrect position + aDot = aDirT[1]->xy()->dot(aStart[1]->decreased(*anIt)); + theTangentB = (*anIt)->added(aDirT[1]->xy()->multiplied(aDot)); + if (theTangentB->decreased(aStart[1])->dot(aDir[1]->xy()) < 0.0) + continue; // incorrect position + // the center is found, stop searching + theCenter = *anIt; + return; + } + } else if ((theFeatureA->getKind() == SketchPlugin_Arc::ID() && + theFeatureB->getKind() == SketchPlugin_Line::ID()) || + (theFeatureA->getKind() == SketchPlugin_Line::ID() && + theFeatureB->getKind() == SketchPlugin_Arc::ID())) { + int aLineInd = theFeatureA->getKind() == SketchPlugin_Line::ID() ? 0 : 1; + double anArcRadius = aStart[1-aLineInd]->distance(aCenter[1-aLineInd]); + std::shared_ptr aDirLine = std::shared_ptr( + new GeomAPI_Dir2d(aEnd[aLineInd]->decreased(aStart[aLineInd]))); + std::shared_ptr aDirT = std::shared_ptr( + new GeomAPI_Dir2d(-aDirLine->y(), aDirLine->x())); + + std::shared_ptr aStartArcDir = std::shared_ptr( + new GeomAPI_Dir2d(aStart[1-aLineInd]->decreased(aCenter[1-aLineInd]))); + std::shared_ptr aEndArcDir = std::shared_ptr( + new GeomAPI_Dir2d(aEnd[1-aLineInd]->decreased(aCenter[1-aLineInd]))); + double anArcAngle = aEndArcDir->angle(aStartArcDir); + + // 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)); + // 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; + 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)); + if (theFeatureA->getKind() == SketchPlugin_Line::ID()) { + theTangentA = aLineTgPoint; + theTangentB = anArcTgPoint; + } else { + theTangentA = anArcTgPoint; + theTangentB = aLineTgPoint; + } + //return; + } + } else if (theFeatureA->getKind() == SketchPlugin_Arc::ID() && + theFeatureB->getKind() == SketchPlugin_Arc::ID()) { + double anArcRadius[aNbFeatures]; + double anArcAngle[aNbFeatures]; + std::shared_ptr aStartArcDir[aNbFeatures]; + for (int i = 0; i < aNbFeatures; i++) { + anArcRadius[i] = aStart[i]->distance(aCenter[i]); + aStartArcDir[i] = std::shared_ptr( + new GeomAPI_Dir2d(aStart[i]->decreased(aCenter[i]))); + std::shared_ptr aEndArcDir = std::shared_ptr( + new GeomAPI_Dir2d(aEnd[i]->decreased(aCenter[i]))); + anArcAngle[i] = aEndArcDir->angle(aStartArcDir[i]); + } + + // get and filter possible centers + std::list< std::shared_ptr > aSuspectCenters; + possibleFilletCenterArcArc(aCenter[0], anArcRadius[0], aCenter[1], + anArcRadius[1], theRadius, aSuspectCenters); + double aDot = 0.0; + std::shared_ptr aLineTgPoint, anArcTgPoint; + std::list< std::shared_ptr >::iterator anIt = aSuspectCenters.begin(); + for (; anIt != aSuspectCenters.end(); anIt++) { + std::shared_ptr aCurDir = std::shared_ptr( + new GeomAPI_Dir2d((*anIt)->decreased(aCenter[0]))); + double aCurAngle = aCurDir->angle(aStartArcDir[0]); + if (anArcAngle[0] < 0.0) aCurAngle *= -1.0; + if (aCurAngle < 0.0 || aCurAngle > fabs(anArcAngle[0])) + continue; // incorrect position + theTangentA = aCenter[0]->added(aCurDir->xy()->multiplied(anArcRadius[0])); + + aCurDir = std::shared_ptr(new GeomAPI_Dir2d((*anIt)->decreased(aCenter[1]))); + aCurAngle = aCurDir->angle(aStartArcDir[1]); + if (anArcAngle[1] < 0.0) aCurAngle *= -1.0; + if (aCurAngle < 0.0 || aCurAngle > fabs(anArcAngle[1])) + continue; // incorrect position + theTangentB = aCenter[1]->added(aCurDir->xy()->multiplied(anArcRadius[1])); + + // the center is found, stop searching + theCenter = *anIt; + return; + } + } +} + +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; +} + +std::set getCoincides(const FeaturePtr& theConstraintCoincidence) +{ + std::set aCoincides; + + std::shared_ptr aFilletPnt = + SketchPlugin_Tools::getCoincidencePoint(theConstraintCoincidence); + + SketchPlugin_Tools::findCoincidences(theConstraintCoincidence, + SketchPlugin_ConstraintCoincidence::ENTITY_A(), + aCoincides); + SketchPlugin_Tools::findCoincidences(theConstraintCoincidence, + SketchPlugin_ConstraintCoincidence::ENTITY_B(), + aCoincides); + + // Remove points from set of coincides. + std::set aNewSetOfCoincides; + for(std::set::iterator anIt = aCoincides.begin(); anIt != aCoincides.end(); ++anIt) { + std::shared_ptr aSketchEntity = + std::dynamic_pointer_cast(*anIt); + if(aSketchEntity.get() && aSketchEntity->isCopy()) { + continue; + } + if((*anIt)->getKind() == SketchPlugin_Line::ID()) { + aNewSetOfCoincides.insert(*anIt); + } else if((*anIt)->getKind() == SketchPlugin_Arc::ID()) { + AttributePtr anAttrCenter = (*anIt)->attribute(SketchPlugin_Arc::CENTER_ID()); + std::shared_ptr aPointCenter2D = + std::dynamic_pointer_cast(anAttrCenter); + if(aPointCenter2D.get() && aFilletPnt->isEqual(aPointCenter2D->pnt())) { + continue; + } + aNewSetOfCoincides.insert(*anIt); + } + } + aCoincides = aNewSetOfCoincides; + + // If we still have more than two coincides remove auxilary entities from set of coincides. + if(aCoincides.size() > 2) { + aNewSetOfCoincides.clear(); + for(std::set::iterator + anIt = aCoincides.begin(); anIt != aCoincides.end(); ++anIt) { + if(!(*anIt)->boolean(SketchPlugin_SketchEntity::AUXILIARY_ID())->value()) { + aNewSetOfCoincides.insert(*anIt); + } + } + aCoincides = aNewSetOfCoincides; + } + + return aCoincides; +} + +std::set findFeaturesToRemove(const FeaturePtr theFeature, + const AttributePtr theAttribute) { + std::set aFeaturesToBeRemoved; + std::set aRefs = theFeature->data()->refsToMe(); + std::list aResults = theFeature->results(); + for(std::list::const_iterator aResultsIt = aResults.cbegin(); + aResultsIt != aResults.cend(); + ++aResultsIt) { + ResultPtr aResult = *aResultsIt; + std::set aResultRefs = aResult->data()->refsToMe(); + aRefs.insert(aResultRefs.begin(), aResultRefs.end()); + } + for(std::set::const_iterator anIt = aRefs.cbegin(); + anIt != aRefs.cend(); + ++anIt) { + std::shared_ptr anAttr = (*anIt); + FeaturePtr aFeature = std::dynamic_pointer_cast(anAttr->owner()); + if(aFeature->getKind() == SketchPlugin_Fillet::ID()) { + continue; + } + if(aFeature->getKind() == SketchPlugin_ConstraintLength::ID() + || aFeature->getKind() == SketchPlugin_ConstraintEqual::ID()) { + aFeaturesToBeRemoved.insert(aFeature); + } else { + std::list anAttrs = + aFeature->data()->attributes(ModelAPI_AttributeRefAttr::typeId()); + for(std::list::const_iterator aRefAttrsIt = anAttrs.cbegin(); + aRefAttrsIt != anAttrs.cend(); + ++aRefAttrsIt) { + AttributeRefAttrPtr anAttrRefAttr = + std::dynamic_pointer_cast(*aRefAttrsIt); + if(anAttrRefAttr.get() && anAttrRefAttr->attr() == theAttribute) { + aFeaturesToBeRemoved.insert(aFeature); + } + } + } + } + return aFeaturesToBeRemoved; +} diff --git a/src/SketchPlugin/SketchPlugin_Fillet.h b/src/SketchPlugin/SketchPlugin_Fillet.h new file mode 100644 index 000000000..b25e0257d --- /dev/null +++ b/src/SketchPlugin/SketchPlugin_Fillet.h @@ -0,0 +1,79 @@ +// Copyright (C) 2014-20xx CEA/DEN, EDF R&D --> + +// File: SketchPlugin_Fillet.h +// Created: 19 Mar 2015 +// Author: Artem ZHIDKOV + +#ifndef SketchPlugin_Fillet_H_ +#define SketchPlugin_Fillet_H_ + +#include "SketchPlugin.h" + +#include "SketchPlugin_SketchEntity.h" + +#include + +class GeomAPI_XY; + +/// \class SketchPlugin_Fillet +/// \ingroup Plugins +/// \brief Feature for creation of a new arc filleting two objects which have +/// coincident point. +class SketchPlugin_Fillet: public SketchPlugin_SketchEntity, public GeomAPI_IPresentable +{ + public: + /// Feature kind. + inline static const std::string& ID() + { + static const std::string MY_FEATURE_ID("SketchFillet"); + return MY_FEATURE_ID; + } + + /// Attribute name of fillet point. + inline static const std::string& FILLET_POINT_ID() + { + static const std::string ID("fillet_point"); + return ID; + } + + /// \return the kind of a feature. + SKETCHPLUGIN_EXPORT virtual const std::string& getKind() + { + static std::string MY_KIND = SketchPlugin_Fillet::ID(); + return MY_KIND; + } + + /// \brief Creates a new part document if needed. + SKETCHPLUGIN_EXPORT virtual void execute(); + + /// \brief Request for initialization of data model of the feature: adding all attributes. + SKETCHPLUGIN_EXPORT virtual void initAttributes(); + + /// Returns the AIS preview + SKETCHPLUGIN_EXPORT virtual AISObjectPtr getAISObject(AISObjectPtr thePrevious); + + /// Reimplemented from ModelAPI_Feature::isMacro(). + /// \returns true + SKETCHPLUGIN_EXPORT virtual bool isMacro() const {return true;}; + + SKETCHPLUGIN_EXPORT virtual bool isPreviewNeeded() const {return false;}; + + /// Reimplemented from SketchPlugin_Feature::move(). + /// Do nothing. + SKETCHPLUGIN_EXPORT virtual void move(const double theDeltaX, const double theDeltaY) {}; + + /// \brief Use plugin manager for features creation + SketchPlugin_Fillet(); + +private: + FeaturePtr myBaseFeatures[2]; + std::string myFeatAttributes[4]; // attributes of features + bool myIsReversed; + bool myIsNotInversed[2]; // indicates which point the features share + bool myFilletCreated; + std::shared_ptr myCenterXY; + std::shared_ptr myTangentXY1; + std::shared_ptr myTangentXY2; +}; + +#endif diff --git a/src/SketchPlugin/SketchPlugin_Plugin.cpp b/src/SketchPlugin/SketchPlugin_Plugin.cpp index e422ef436..87ef7b27a 100644 --- a/src/SketchPlugin/SketchPlugin_Plugin.cpp +++ b/src/SketchPlugin/SketchPlugin_Plugin.cpp @@ -13,7 +13,7 @@ #include #include #include -#include +#include #include #include #include @@ -165,8 +165,8 @@ FeaturePtr SketchPlugin_Plugin::createFeature(std::string theFeatureID) return FeaturePtr(new SketchPlugin_ConstraintMiddle); } else if (theFeatureID == SketchPlugin_ConstraintMirror::ID()) { return FeaturePtr(new SketchPlugin_ConstraintMirror); - } else if (theFeatureID == SketchPlugin_ConstraintFillet::ID()) { - return FeaturePtr(new SketchPlugin_ConstraintFillet); + } else if (theFeatureID == SketchPlugin_Fillet::ID()) { + return FeaturePtr(new SketchPlugin_Fillet); } else if (theFeatureID == SketchPlugin_ConstraintSplit::ID()) { return FeaturePtr(new SketchPlugin_ConstraintSplit); } else if (theFeatureID == SketchPlugin_MultiTranslation::ID()) { @@ -234,7 +234,7 @@ std::shared_ptr SketchPlugin_Plugin aMsg->setState(SketchPlugin_ConstraintTangent::ID(), aHasSketchPlane); aMsg->setState(SketchPlugin_ConstraintMiddle::ID(), aHasSketchPlane); aMsg->setState(SketchPlugin_ConstraintMirror::ID(), aHasSketchPlane); - aMsg->setState(SketchPlugin_ConstraintFillet::ID(), aHasSketchPlane); + aMsg->setState(SketchPlugin_Fillet::ID(), aHasSketchPlane); aMsg->setState(SketchPlugin_ConstraintSplit::ID(), aHasSketchPlane); aMsg->setState(SketchPlugin_ConstraintAngle::ID(), aHasSketchPlane); aMsg->setState(SketchPlugin_MultiRotation::ID(), aHasSketchPlane); diff --git a/src/SketchPlugin/SketchPlugin_Validators.cpp b/src/SketchPlugin/SketchPlugin_Validators.cpp index 641aaa0fd..d42c78360 100755 --- a/src/SketchPlugin/SketchPlugin_Validators.cpp +++ b/src/SketchPlugin/SketchPlugin_Validators.cpp @@ -10,7 +10,7 @@ #include "SketchPlugin_Circle.h" #include "SketchPlugin_ConstraintCoincidence.h" #include "SketchPlugin_ConstraintDistance.h" -#include "SketchPlugin_ConstraintFillet.h" +#include "SketchPlugin_Fillet.h" #include "SketchPlugin_ConstraintRigid.h" #include "SketchPlugin_ConstraintTangent.h" #include "SketchPlugin_Line.h" @@ -483,195 +483,159 @@ bool SketchPlugin_FilletVertexValidator::isValid(const AttributePtr& theAttribut const std::list& theArguments, Events_InfoMessage& theError) const { - std::shared_ptr aFilletFeature = - std::dynamic_pointer_cast(theAttribute->owner()); - AttributeRefAttrListPtr aPointsRefList = - std::dynamic_pointer_cast(theAttribute); - if(aPointsRefList->size() == 0) { - theError = "Error: List of points is empty."; + AttributeRefAttrPtr aPointRefAttr = + std::dynamic_pointer_cast(theAttribute); + if(!aPointRefAttr.get()) { + theError = "Error: Point not selected."; return false; } - std::map aPointsFeaturesMap = - aFilletFeature->pointsFeaturesMap(); - std::set aSetOfPointsOnResultEdges; - for(std::map::iterator - aPointsIter = aPointsFeaturesMap.begin(); - aPointsIter != aPointsFeaturesMap.end(); - ++aPointsIter) { - const SketchPlugin_ConstraintFillet::FilletFeatures& aFeatures = aPointsIter->second; - const std::list& aResultEdges = aFeatures.resultEdges; - for(std::list::const_iterator aResultIter = aResultEdges.cbegin(); - aResultIter != aResultEdges.cend(); - ++aResultIter) { - FeaturePtr aResultFeature = *aResultIter; - if(aResultFeature->getKind() == SketchPlugin_Line::ID()) { - aSetOfPointsOnResultEdges.insert(aResultFeature->attribute(SketchPlugin_Line::START_ID())); - aSetOfPointsOnResultEdges.insert(aResultFeature->attribute(SketchPlugin_Line::END_ID())); - } else if(aResultFeature->getKind() == SketchPlugin_Arc::ID()) { - aSetOfPointsOnResultEdges.insert(aResultFeature->attribute(SketchPlugin_Arc::START_ID())); - aSetOfPointsOnResultEdges.insert(aResultFeature->attribute(SketchPlugin_Arc::END_ID())); - } - } + AttributePtr aPointAttribute = aPointRefAttr->attr(); + if (!aPointAttribute.get()) { + theError = "Error: Bad point selected."; + return false; } + std::shared_ptr aSelectedPnt = + std::dynamic_pointer_cast(aPointAttribute)->pnt(); - std::list> aPointsList = aPointsRefList->list(); - for(std::list>::const_iterator - aPointsIt = aPointsList.cbegin(); aPointsIt != aPointsList.cend(); aPointsIt++) { - ObjectPtr anObject = (*aPointsIt).first; - AttributePtr aPointAttribute = (*aPointsIt).second; - if (!aPointAttribute.get()) - return false; - std::shared_ptr aSelectedPnt = - std::dynamic_pointer_cast(aPointAttribute)->pnt(); - - // If we alredy have some result then: - // - if it is the same point all ok, just skip it - // - if it is point on the fillet result edge then it is not valid - if(!aPointsFeaturesMap.empty()) { - if(aPointsFeaturesMap.find(aPointAttribute) != aPointsFeaturesMap.end()) { - continue; - } - - // Check that selected point not on the one of the fillet result edge. - if(aSetOfPointsOnResultEdges.find(aPointAttribute) != aSetOfPointsOnResultEdges.end()) { - return false; - } - } - - // Obtain constraint coincidence for the fillet point. - const std::set& aRefsList = aPointAttribute->owner()->data()->refsToMe(); - FeaturePtr aConstraintCoincidence; - for(std::set::const_iterator anIt = aRefsList.cbegin(); - anIt != aRefsList.cend(); ++anIt) { - std::shared_ptr aAttr = (*anIt); - 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(aPointAttribute == anAttrA) { - aConstraintCoincidence = aConstrFeature; - break; - } + // Obtain constraint coincidence for the fillet point. + const std::set& aRefsList = aPointAttribute->owner()->data()->refsToMe(); + FeaturePtr aConstraintCoincidence; + for(std::set::const_iterator anIt = aRefsList.cbegin(); + anIt != aRefsList.cend(); ++anIt) { + std::shared_ptr aAttr = (*anIt); + 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(aPointAttribute == anAttrA) { + aConstraintCoincidence = aConstrFeature; + break; } - if(anAttrRefB.get() && !anAttrRefB->isObject()) { - AttributePtr anAttrB = anAttrRefB->attr(); - if(aPointAttribute == anAttrB) { - aConstraintCoincidence = aConstrFeature; - break; - } + } + if(anAttrRefB.get() && !anAttrRefB->isObject()) { + AttributePtr anAttrB = anAttrRefB->attr(); + if(aPointAttribute == anAttrB) { + aConstraintCoincidence = aConstrFeature; + break; } } } + } - if(!aConstraintCoincidence.get()) { - theError = "Error: one of the selected point does not have coicidence."; - return false; + if(!aConstraintCoincidence.get()) { + theError = "Error: one of the selected point does not have coicidence."; + return false; + } + + // Get coincides from constraint. + std::set aCoinsides; + SketchPlugin_Tools::findCoincidences(aConstraintCoincidence, + SketchPlugin_ConstraintCoincidence::ENTITY_A(), + aCoinsides); + SketchPlugin_Tools::findCoincidences(aConstraintCoincidence, + SketchPlugin_ConstraintCoincidence::ENTITY_B(), + aCoinsides); + + // Remove points from set of coincides. + std::set aNewSetOfCoincides; + for(std::set::iterator anIt = aCoinsides.begin(); + anIt != aCoinsides.end(); ++anIt) { + std::shared_ptr aSketchEntity = + std::dynamic_pointer_cast(*anIt); + if(aSketchEntity.get() && aSketchEntity->isCopy()) { + continue; + } + if((*anIt)->getKind() != SketchPlugin_Line::ID() && + (*anIt)->getKind() != SketchPlugin_Arc::ID()) { + continue; } + if((*anIt)->getKind() == SketchPlugin_Arc::ID()) { + AttributePtr anArcCenter = (*anIt)->attribute(SketchPlugin_Arc::CENTER_ID()); + std::shared_ptr anArcCenterPnt = + std::dynamic_pointer_cast(anArcCenter)->pnt(); + double aDistSelectedArcCenter = aSelectedPnt->distance(anArcCenterPnt); + if(aDistSelectedArcCenter < tolerance) { + continue; + } + } + aNewSetOfCoincides.insert(*anIt); + } + aCoinsides = aNewSetOfCoincides; - // Get coincides from constraint. - std::set aCoinsides; - SketchPlugin_Tools::findCoincidences(aConstraintCoincidence, - SketchPlugin_ConstraintCoincidence::ENTITY_A(), - aCoinsides); - SketchPlugin_Tools::findCoincidences(aConstraintCoincidence, - SketchPlugin_ConstraintCoincidence::ENTITY_B(), - aCoinsides); - - // Remove points from set of coincides. - std::set aNewSetOfCoincides; + // If we still have more than two coincides remove auxilary entities from set of coincides. + if(aCoinsides.size() > 2) { + aNewSetOfCoincides.clear(); for(std::set::iterator anIt = aCoinsides.begin(); anIt != aCoinsides.end(); ++anIt) { - if((*anIt)->getKind() != SketchPlugin_Line::ID() && - (*anIt)->getKind() != SketchPlugin_Arc::ID()) { - continue; - } - if((*anIt)->getKind() == SketchPlugin_Arc::ID()) { - AttributePtr anArcCenter = (*anIt)->attribute(SketchPlugin_Arc::CENTER_ID()); - std::shared_ptr anArcCenterPnt = - std::dynamic_pointer_cast(anArcCenter)->pnt(); - double aDistSelectedArcCenter = aSelectedPnt->distance(anArcCenterPnt); - if(aDistSelectedArcCenter < tolerance) { - continue; - } + if(!(*anIt)->boolean(SketchPlugin_SketchEntity::AUXILIARY_ID())->value()) { + aNewSetOfCoincides.insert(*anIt); } - aNewSetOfCoincides.insert(*anIt); } aCoinsides = aNewSetOfCoincides; + } - // If we still have more than two coincides remove auxilary entities from set of coincides. - if(aCoinsides.size() > 2) { - aNewSetOfCoincides.clear(); - for(std::set::iterator anIt = aCoinsides.begin(); - anIt != aCoinsides.end(); ++anIt) { - if(!(*anIt)->boolean(SketchPlugin_SketchEntity::AUXILIARY_ID())->value()) { - aNewSetOfCoincides.insert(*anIt); - } - } - aCoinsides = aNewSetOfCoincides; - } + if(aCoinsides.size() != 2) { + theError = "Error: One of the selected points does not have two suitable edges for fillet."; + return false; + } - if(aCoinsides.size() != 2) { - theError = "Error: One of the selected points does not have two suitable edges for fillet."; - return false; - } + // Check that selected edges don't have tangent constraint. + std::set::iterator anIt = aCoinsides.begin(); + FeaturePtr aFirstFeature = *anIt++; + FeaturePtr aSecondFeature = *anIt; + const std::set& aFirstFeatureRefsList = aFirstFeature->data()->refsToMe(); + if(hasSameTangentFeature(aFirstFeatureRefsList, aSecondFeature)) { + theError = "Error: Edges in selected point has tangent constraint."; + return false; + } - // Check that selected edges don't have tangent constraint. - std::set::iterator anIt = aCoinsides.begin(); - FeaturePtr aFirstFeature = *anIt++; - FeaturePtr aSecondFeature = *anIt; - const std::set& aFirstFeatureRefsList = aFirstFeature->data()->refsToMe(); - if(hasSameTangentFeature(aFirstFeatureRefsList, aSecondFeature)) { + std::list aFirstResults = aFirstFeature->results(); + for(std::list::iterator aResIt = aFirstResults.begin(); + aResIt != aFirstResults.end(); ++aResIt) { + ResultPtr aRes = *aResIt; + const std::set& aResRefsList = aRes->data()->refsToMe(); + if(hasSameTangentFeature(aResRefsList, aSecondFeature)) { theError = "Error: Edges in selected point has tangent constraint."; return false; } + } - std::list aFirstResults = aFirstFeature->results(); - for(std::list::iterator aResIt = aFirstResults.begin(); - aResIt != aFirstResults.end(); ++aResIt) { - ResultPtr aRes = *aResIt; - const std::set& aResRefsList = aRes->data()->refsToMe(); - if(hasSameTangentFeature(aResRefsList, aSecondFeature)) { - theError = "Error: Edges in selected point has tangent constraint."; - return false; - } - } - - // Check that lines not collinear - if(aFirstFeature->getKind() == SketchPlugin_Line::ID() && - aSecondFeature->getKind() == SketchPlugin_Line::ID()) { - std::string aStartAttr = SketchPlugin_Line::START_ID(); - std::string anEndAttr = SketchPlugin_Line::END_ID(); - std::shared_ptr aFirstStartPnt, aFirstEndPnt, aSecondStartPnt, aSecondEndPnt; - aFirstStartPnt = - std::dynamic_pointer_cast( - aFirstFeature->attribute(aStartAttr))->pnt(); - aFirstEndPnt = - std::dynamic_pointer_cast(aFirstFeature->attribute(anEndAttr))->pnt(); - aSecondStartPnt = - std::dynamic_pointer_cast( - aSecondFeature->attribute(aStartAttr))->pnt(); - aSecondEndPnt = - std::dynamic_pointer_cast( - aSecondFeature->attribute(anEndAttr))->pnt(); - double aCheck1 = - fabs((aFirstEndPnt->x() - aFirstStartPnt->x()) * - (aSecondStartPnt->y() - aFirstStartPnt->y()) - - (aSecondStartPnt->x() - aFirstStartPnt->x()) * (aFirstEndPnt->y() - aFirstStartPnt->y())); - double aCheck2 = - fabs((aFirstEndPnt->x() - aFirstStartPnt->x()) * - (aSecondEndPnt->y() - aFirstStartPnt->y()) - - (aSecondEndPnt->x() - aFirstStartPnt->x()) * (aFirstEndPnt->y() - aFirstStartPnt->y())); - if(aCheck1 < 1.e-7 && aCheck2 < 1.e-7) { - return false; - } + // Check that lines not collinear + if(aFirstFeature->getKind() == SketchPlugin_Line::ID() && + aSecondFeature->getKind() == SketchPlugin_Line::ID()) { + std::string aStartAttr = SketchPlugin_Line::START_ID(); + std::string anEndAttr = SketchPlugin_Line::END_ID(); + std::shared_ptr aFirstStartPnt, aFirstEndPnt, aSecondStartPnt, aSecondEndPnt; + aFirstStartPnt = + std::dynamic_pointer_cast( + aFirstFeature->attribute(aStartAttr))->pnt(); + aFirstEndPnt = + std::dynamic_pointer_cast(aFirstFeature->attribute(anEndAttr))->pnt(); + aSecondStartPnt = + std::dynamic_pointer_cast( + aSecondFeature->attribute(aStartAttr))->pnt(); + aSecondEndPnt = + std::dynamic_pointer_cast( + aSecondFeature->attribute(anEndAttr))->pnt(); + double aCheck1 = + fabs((aFirstEndPnt->x() - aFirstStartPnt->x()) * + (aSecondStartPnt->y() - aFirstStartPnt->y()) - + (aSecondStartPnt->x() - aFirstStartPnt->x()) * (aFirstEndPnt->y() - aFirstStartPnt->y())); + double aCheck2 = + fabs((aFirstEndPnt->x() - aFirstStartPnt->x()) * + (aSecondEndPnt->y() - aFirstStartPnt->y()) - + (aSecondEndPnt->x() - aFirstStartPnt->x()) * (aFirstEndPnt->y() - aFirstStartPnt->y())); + if(aCheck1 < 1.e-7 && aCheck2 < 1.e-7) { + return false; } } + return true; } diff --git a/src/SketchPlugin/SketchPlugin_msg_en.ts b/src/SketchPlugin/SketchPlugin_msg_en.ts index de5c42990..f7d332f69 100755 --- a/src/SketchPlugin/SketchPlugin_msg_en.ts +++ b/src/SketchPlugin/SketchPlugin_msg_en.ts @@ -1938,77 +1938,77 @@ - SketchConstraintFillet:ConstraintValue:GeomValidators_Positive + SketchFillet:ConstraintValue:GeomValidators_Positive Double is not initialized. Set the fillet radius - SketchConstraintFillet:ConstraintValue:GeomValidators_Positive + SketchFillet:ConstraintValue:GeomValidators_Positive Double is not positive. The fillet radius must be positive - SketchConstraintFillet:ConstraintValue:GeomValidators_Positive + SketchFillet:ConstraintValue:GeomValidators_Positive Integer is not initialized. Set the integer fillet radius - SketchConstraintFillet:ConstraintValue:GeomValidators_Positive + SketchFillet:ConstraintValue:GeomValidators_Positive Integer is not positive. The integer fillet radius must be positive - SketchConstraintFillet:Model_FeatureValidator + SketchFillet:Model_FeatureValidator Attribute "ConstraintEntityA" is not initialized. Select one or several points for filet - SketchConstraintFillet:Model_FeatureValidator + SketchFillet:Model_FeatureValidator Attribute "ConstraintValue" is not initialized. Set the fillet radius - SketchConstraintFillet:ConstraintEntityA:SketchPlugin_FilletVertexValidator + SketchFillet:ConstraintEntityA:SketchPlugin_FilletVertexValidator Error: List of points is empty. List of points is empty - SketchConstraintFillet:ConstraintEntityA:SketchPlugin_FilletVertexValidator + SketchFillet:ConstraintEntityA:SketchPlugin_FilletVertexValidator Error: one of the selected point does not have coicidence. One of the selected point does not have coicidence - SketchConstraintFillet:ConstraintEntityA:SketchPlugin_FilletVertexValidator + SketchFillet:ConstraintEntityA:SketchPlugin_FilletVertexValidator Error: One of the selected points does not have two suitable edges for fillet. One of the selected points does not have two suitable edges for fillet - SketchConstraintFillet:ConstraintEntityA:SketchPlugin_FilletVertexValidator + SketchFillet:ConstraintEntityA:SketchPlugin_FilletVertexValidator Error: Edges in selected point has tangent constraint. Edges in selected point has tangent constraint - SketchConstraintFillet:ConstraintEntityA:SketchPlugin_FilletVertexValidator + SketchFillet:ConstraintEntityA:SketchPlugin_FilletVertexValidator Error: Edges in selected point has tangent constraint. Edges in selected point has tangent constraint diff --git a/src/SketchPlugin/plugin-Sketch.xml b/src/SketchPlugin/plugin-Sketch.xml index 50c1a6552..bf5db26b3 100644 --- a/src/SketchPlugin/plugin-Sketch.xml +++ b/src/SketchPlugin/plugin-Sketch.xml @@ -12,7 +12,7 @@ SketchConstraintParallel SketchConstraintPerpendicular SketchConstraintRigid SketchConstraintHorizontal SketchConstraintVertical SketchConstraintEqual SketchConstraintTangent - SketchConstraintFillet SketchConstraintSplit SketchTrim + SketchFillet SketchConstraintSplit SketchTrim SketchConstraintCoincidence SketchConstraintMirror SketchConstraintAngle SketchMultiRotation SketchMultiTranslation @@ -120,24 +120,17 @@ - - - - - - - - - + +