Creation fillet by one point.
#include <SketchPlugin_ConstraintEqual.h>
#include <SketchPlugin_ConstraintTangent.h>
#include <SketchPlugin_ConstraintCoincidence.h>
-#include <SketchPlugin_ConstraintFillet.h>
+#include <SketchPlugin_Fillet.h>
#include <SketchPlugin_ConstraintMirror.h>
#include <SketchPlugin_ConstraintAngle.h>
#include <SketchPlugin_ConstraintCollinear.h>
#include <SketchPlugin_ConstraintCollinear.h>
#include <SketchPlugin_ConstraintDistance.h>
#include <SketchPlugin_ConstraintEqual.h>
-#include <SketchPlugin_ConstraintFillet.h>
+#include <SketchPlugin_Fillet.h>
#include <SketchPlugin_ConstraintHorizontal.h>
#include <SketchPlugin_ConstraintLength.h>
#include <SketchPlugin_ConstraintMiddle.h>
const ModelHighAPI_Double & theRadius)
{
std::shared_ptr<ModelAPI_Feature> 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();
SketchPlugin_ConstraintCollinear.h
SketchPlugin_ConstraintDistance.h
SketchPlugin_ConstraintEqual.h
- SketchPlugin_ConstraintFillet.h
+ SketchPlugin_Fillet.h
SketchPlugin_ConstraintHorizontal.h
SketchPlugin_ConstraintLength.h
SketchPlugin_ConstraintMiddle.h
SketchPlugin_ConstraintCollinear.cpp
SketchPlugin_ConstraintDistance.cpp
SketchPlugin_ConstraintEqual.cpp
- SketchPlugin_ConstraintFillet.cpp
+ SketchPlugin_Fillet.cpp
SketchPlugin_ConstraintHorizontal.cpp
SketchPlugin_ConstraintLength.cpp
SketchPlugin_ConstraintMiddle.cpp
TestConstraintMiddlePoint.py
TestMultiRotation.py
TestMultiTranslation.py
- TestFillet.py
TestRectangle.py
TestProjection.py
TestSplit.py
+++ /dev/null
-// 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 <GeomAPI_Circ2d.h>
-#include <GeomAPI_Dir2d.h>
-#include <GeomAPI_Lin2d.h>
-#include <GeomAPI_Pnt2d.h>
-#include <GeomAPI_XY.h>
-#include <GeomDataAPI_Point2D.h>
-#include <ModelAPI_AttributeDouble.h>
-#include <ModelAPI_AttributeRefAttrList.h>
-#include <ModelAPI_Data.h>
-#include <ModelAPI_Events.h>
-#include <ModelAPI_Session.h>
-#include <ModelAPI_Validator.h>
-
-#include <SketchPlugin_Arc.h>
-#include <SketchPlugin_Line.h>
-#include <SketchPlugin_Point.h>
-#include <SketchPlugin_Sketch.h>
-#include <SketchPlugin_ConstraintCoincidence.h>
-#include <SketchPlugin_ConstraintTangent.h>
-#include <SketchPlugin_ConstraintRadius.h>
-#include <SketchPlugin_Tools.h>
-
-#include <Events_Loop.h>
-
-#include <math.h>
-
-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<GeomAPI_XY>& theCenter,
- std::shared_ptr<GeomAPI_XY>& theTangentA,
- std::shared_ptr<GeomAPI_XY>& theTangentB);
-
-/// Get point on 1/3 length of edge from fillet point
-static void getPointOnEdge(const FeaturePtr theFeature,
- const std::shared_ptr<GeomAPI_Pnt2d> theFilletPoint,
- std::shared_ptr<GeomAPI_Pnt2d>& thePoint);
-
-/// Get distance from point to feature
-static double getProjectionDistance(const FeaturePtr theFeature,
- const std::shared_ptr<GeomAPI_Pnt2d> thePoint);
-
-/// Get coincide edges for fillet
-static std::set<FeaturePtr> 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<ModelAPI_Data> aData = data();
-
- // Check the base objects are initialized.
- AttributeRefAttrListPtr aPointsRefList = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttrList>(
- 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<ModelAPI_AttributeDouble>(
- 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<AttributePtr>::iterator aPointsIter = myNewPoints.begin();
- aPointsIter != myNewPoints.end();
- ++aPointsIter) {
- AttributePtr aPointAttr = *aPointsIter;
- std::shared_ptr<GeomDataAPI_Point2D> aFilletPoint2d =
- std::dynamic_pointer_cast<GeomDataAPI_Point2D>(aPointAttr);
- if(!aFilletPoint2d.get()) {
- setError("Error: One of the selected points is empty.");
- return;
- }
- std::shared_ptr<GeomAPI_Pnt2d> aFilletPnt2d = aFilletPoint2d->pnt();
-
- // Obtain base lines for fillet.
- bool anIsNeedNewObjects = true;
- FilletFeatures aFilletFeatures;
- std::map<AttributePtr, FilletFeatures>::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<AttributePtr>& aRefsList = aFilletPoint2d->owner()->data()->refsToMe();
- for(std::set<AttributePtr>::const_iterator
- anIt = aRefsList.cbegin(); anIt != aRefsList.cend(); ++anIt) {
- std::shared_ptr<ModelAPI_Attribute> anAttr = (*anIt);
- FeaturePtr aConstrFeature = std::dynamic_pointer_cast<ModelAPI_Feature>(anAttr->owner());
- if(aConstrFeature->getKind() == SketchPlugin_ConstraintCoincidence::ID()) {
- AttributeRefAttrPtr anAttrRefA = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(
- aConstrFeature->attribute(SketchPlugin_ConstraintCoincidence::ENTITY_A()));
- AttributeRefAttrPtr anAttrRefB = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(
- 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<FeaturePtr> 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<FeaturePtr>::iterator aLinesIt = aCoincides.begin();
- aBaseEdgeA = *aLinesIt++;
- aBaseEdgeB = *aLinesIt;
-
- std::pair<FeaturePtr, bool> aBasePairA =
- std::make_pair(aBaseEdgeA,
- aBaseEdgeA->boolean(SketchPlugin_SketchEntity::AUXILIARY_ID())->value());
- std::pair<FeaturePtr, bool> 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<FeaturePtr>::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<GeomAPI_Dir2d> 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<GeomAPI_Pnt2d> 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<GeomDataAPI_Point2D>(
- aBaseFeatures[i]->attribute(aStartAttr))->pnt();
- aFeatAttributes[2*i+1] = aEndAttr;
- aStartEndPnt[2*i+1] = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
- 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<GeomAPI_XY> 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<GeomAPI_Pnt2d> aCenterPoint =
- std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
- 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<SketchPlugin_Arc>(aBaseFeatures[i])->isReversed())
- aDir = aDir->multiplied(-1.0);
- }
- aTangentDir[i] = std::shared_ptr<GeomAPI_Dir2d>(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<GeomAPI_XY> 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<GeomDataAPI_Point2D>(
- aResultEdgeA->attribute(aFeatAttributes[isStart[0] ? 0 : 1]))->
- setValue(aTangentPntA->x(), aTangentPntA->y());
- aResultEdgeA->execute();
- std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
- 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<GeomDataAPI_Point2D>(
- aResultArc->attribute(SketchPlugin_Arc::CENTER_ID()))->setValue(aCenter->x(), aCenter->y());
- if(isReversed) {
- std::shared_ptr<GeomAPI_XY> aTmp = aTangentPntA;
- aTangentPntA = aTangentPntB;
- aTangentPntB = aTmp;
- }
- std::shared_ptr<GeomDataAPI_Point2D> aStartPoint =
- std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
- aResultArc->attribute(SketchPlugin_Arc::START_ID()));
- std::shared_ptr<GeomDataAPI_Point2D> aEndPoint = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
- 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<SketchPlugin_Arc>(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<ModelAPI_AttributeRefAttr>(
- aConstraint->attribute(SketchPlugin_Constraint::ENTITY_A()));
- aRefAttr->setAttr(aResultArc->attribute(SketchPlugin_Arc::START_ID()));
- aRefAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(
- 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<ModelAPI_AttributeRefAttr>(
- aConstraint->attribute(SketchPlugin_Constraint::ENTITY_A()));
- aRefAttr->setAttr(aResultArc->attribute(SketchPlugin_Arc::END_ID()));
- aRefAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(
- 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<ModelAPI_AttributeRefAttr>(
- // aConstraint->attribute(SketchPlugin_Constraint::ENTITY_A()));
- //aRefAttr->setObject(aNewArc->lastResult());
- //std::dynamic_pointer_cast<ModelAPI_AttributeDouble>(
- // aConstraint->attribute(SketchPlugin_Constraint::VALUE()))->setValue(aFilletRadius);
- //std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
- // 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<ModelAPI_AttributeRefAttr>(
- aConstraint->attribute(SketchPlugin_Constraint::ENTITY_A()));
- aRefAttr->setObject(aResultArc->lastResult());
- aRefAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(
- 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<ModelAPI_AttributeRefAttr>(
- aConstraint->attribute(SketchPlugin_Constraint::ENTITY_A()));
- aRefAttr->setAttr(aBaseFeatures[i]->attribute(aFeatAttributes[anAttrInd]));
- aRefAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(
- 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<ModelAPI_AttributeRefAttr>(
- aConstraint->attribute(SketchPlugin_Constraint::ENTITY_A()));
- aRefAttr->setObject(aBaseFeatures[i]->lastResult());
- aRefAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(
- 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<ModelAPI_AttributeRefAttr>(
- aConstraint->attribute(SketchPlugin_Constraint::ENTITY_A()));
- aRefAttr->setAttr(aResultFeatures[i]->attribute(aFeatAttributes[anAttrInd]));
- aRefAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(
- 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<ModelAPI_AttributeRefAttr>(
- 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<ModelAPI_AttributeDouble>(
- 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<ModelAPI_AttributeRefAttrList>(
- 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<std::pair<ObjectPtr, AttributePtr>>
- aSelectedPointsList = aRefListOfFilletPoints->list();
- std::list<std::pair<ObjectPtr, AttributePtr>>::iterator anIter = aSelectedPointsList.begin();
- std::set<AttributePtr> aPointsToSkeep;
- for(int anIndex = 0; anIndex < aListSize; anIndex++, anIter++) {
- AttributePtr aFilletPointAttr = (*anIter).second;
- std::shared_ptr<GeomDataAPI_Point2D> aFilletPoint2D =
- std::dynamic_pointer_cast<GeomDataAPI_Point2D>(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<AttributePtr>& aRefsList = aFilletPointAttr->owner()->data()->refsToMe();
- for(std::set<AttributePtr>::const_iterator
- anIt = aRefsList.cbegin(); anIt != aRefsList.cend(); ++anIt) {
- std::shared_ptr<ModelAPI_Attribute> anAttr = (*anIt);
- FeaturePtr aConstrFeature = std::dynamic_pointer_cast<ModelAPI_Feature>(anAttr->owner());
- if(aConstrFeature->getKind() == SketchPlugin_ConstraintCoincidence::ID()) {
- AttributeRefAttrPtr anAttrRefA = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(
- aConstrFeature->attribute(SketchPlugin_ConstraintCoincidence::ENTITY_A()));
- AttributeRefAttrPtr anAttrRefB = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(
- 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<FeaturePtr> 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<GeomAPI_Pnt2d> aFilletPnt2d = aFilletPoint2D->pnt();
- std::set<FeaturePtr> aNewSetOfCoincides;
- for(std::set<FeaturePtr>::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<GeomDataAPI_Point2D> aPoint2D =
- std::dynamic_pointer_cast<GeomDataAPI_Point2D>(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<GeomDataAPI_Point2D> aPointStart2D =
- std::dynamic_pointer_cast<GeomDataAPI_Point2D>(anAttrStart);
- if(aPointStart2D.get() && aFilletPnt2d->isEqual(aPointStart2D->pnt())) {
- aPointsToSkeep.insert(anAttrStart);
- }
- AttributePtr anAttrEnd = (*anIt)->attribute(SketchPlugin_Line::END_ID());
- std::shared_ptr<GeomDataAPI_Point2D> aPointEnd2D =
- std::dynamic_pointer_cast<GeomDataAPI_Point2D>(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<GeomDataAPI_Point2D> aPointCenter2D =
- std::dynamic_pointer_cast<GeomDataAPI_Point2D>(anAttrCenter);
- if(aPointCenter2D.get() && aFilletPnt2d->isEqual(aPointCenter2D->pnt())) {
- aPointsToSkeep.insert(anAttrCenter);
- continue;
- }
- AttributePtr anAttrStart = (*anIt)->attribute(SketchPlugin_Arc::START_ID());
- std::shared_ptr<GeomDataAPI_Point2D> aPointStart2D =
- std::dynamic_pointer_cast<GeomDataAPI_Point2D>(anAttrStart);
- if(aPointStart2D.get() && aFilletPnt2d->isEqual(aPointStart2D->pnt())) {
- aPointsToSkeep.insert(anAttrStart);
- }
- AttributePtr anAttrEnd = (*anIt)->attribute(SketchPlugin_Arc::END_ID());
- std::shared_ptr<GeomDataAPI_Point2D> aPointEnd2D =
- std::dynamic_pointer_cast<GeomDataAPI_Point2D>(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<FeaturePtr>::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<FeaturePtr>::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<GeomAPI_Pnt2d> aFilletPnt2d = aFilletPoint2D->pnt();
- std::shared_ptr<GeomAPI_Pnt2d> 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<AttributePtr, FilletFeatures>::iterator aPointsIter = myPointFeaturesMap.begin();
- aPointsIter != myPointFeaturesMap.end();) {
- const FilletFeatures& aFilletFeatures = aPointsIter->second;
- std::list<std::pair<FeaturePtr, bool>>::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<AttributePtr, FilletFeatures>::iterator aPointsIter = myPointFeaturesMap.begin();
- aPointsIter != myPointFeaturesMap.end();) {
- // Remove all produced constraints.
- const FilletFeatures& aFilletFeatures = aPointsIter->second;
- std::list<FeaturePtr>::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<GeomAPI_Pnt2d> anArcPoint = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
- theNewArc->attribute(theNewArcAttribute))->pnt();
- std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
- theFeature->attribute(theFeatureAttribute))->setValue(anArcPoint->x(), anArcPoint->y());
-}
-
-/// \brief Find intersections of lines shifted along normal direction
-void possibleFilletCenterLineLine(
- std::shared_ptr<GeomAPI_XY> thePointA, std::shared_ptr<GeomAPI_Dir2d> theDirA,
- std::shared_ptr<GeomAPI_XY> thePointB, std::shared_ptr<GeomAPI_Dir2d> theDirB,
- double theRadius, std::list< std::shared_ptr<GeomAPI_XY> >& theCenters)
-{
- std::shared_ptr<GeomAPI_Dir2d> aDirAT(new GeomAPI_Dir2d(-theDirA->y(), theDirA->x()));
- std::shared_ptr<GeomAPI_Dir2d> aDirBT(new GeomAPI_Dir2d(-theDirB->y(), theDirB->x()));
- std::shared_ptr<GeomAPI_XY> 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<GeomAPI_XY> 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<GeomAPI_XY> theStartLine, std::shared_ptr<GeomAPI_Dir2d> theDirLine,
- std::shared_ptr<GeomAPI_XY> theCenterArc, double theRadiusArc,
- double theRadius, std::list< std::shared_ptr<GeomAPI_XY> >& theCenters)
-{
- std::shared_ptr<GeomAPI_Dir2d> aDirT(new GeomAPI_Dir2d(-theDirLine->y(), theDirLine->x()));
- std::shared_ptr<GeomAPI_XY> 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<GeomAPI_XY> aPoint1(new GeomAPI_XY(x1, y1));
- theCenters.push_back(aPoint1);
- std::shared_ptr<GeomAPI_XY> aPoint2(new GeomAPI_XY(x2, y2));
- theCenters.push_back(aPoint2);
- }
- }
-}
-
-/// \brief Find intersections of two circles with extended radii
-void possibleFilletCenterArcArc(
- std::shared_ptr<GeomAPI_XY> theCenterA, double theRadiusA,
- std::shared_ptr<GeomAPI_XY> theCenterB, double theRadiusB,
- double theRadius, std::list< std::shared_ptr<GeomAPI_XY> >& theCenters)
-{
- std::shared_ptr<GeomAPI_XY> 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<GeomAPI_XY> aPoint1(new GeomAPI_XY(x1, y1));
- theCenters.push_back(aPoint1);
- std::shared_ptr<GeomAPI_XY> aPoint2(new GeomAPI_XY(x2, y2));
- theCenters.push_back(aPoint2);
- }
- }
-}
-
-void calculateFilletCenter(FeaturePtr theFeatureA, FeaturePtr theFeatureB,
- double theRadius, bool theNotInversed[2],
- std::shared_ptr<GeomAPI_XY>& theCenter,
- std::shared_ptr<GeomAPI_XY>& theTangentA,
- std::shared_ptr<GeomAPI_XY>& theTangentB)
-{
- static const int aNbFeatures = 2;
- FeaturePtr aFeature[aNbFeatures] = {theFeatureA, theFeatureB};
- std::shared_ptr<GeomAPI_XY> aStart[aNbFeatures], aEnd[aNbFeatures], aCenter[aNbFeatures];
- std::shared_ptr<GeomDataAPI_Point2D> aStartPoint, aEndPoint;
-
- for (int i = 0; i < aNbFeatures; i++) {
- if (aFeature[i]->getKind() == SketchPlugin_Line::ID()) {
- aStartPoint = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
- aFeature[i]->attribute(SketchPlugin_Line::START_ID()));
- aEndPoint = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
- aFeature[i]->attribute(SketchPlugin_Line::END_ID()));
- } else if (aFeature[i]->getKind() == SketchPlugin_Arc::ID()) {
- aStartPoint = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
- aFeature[i]->attribute(SketchPlugin_Arc::START_ID()));
- aEndPoint = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
- aFeature[i]->attribute(SketchPlugin_Arc::END_ID()));
- aCenter[i] = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
- aFeature[i]->attribute(SketchPlugin_Arc::CENTER_ID()))->pnt()->xy();
- } else
- return;
- aStart[i] = std::shared_ptr<GeomAPI_XY>(theNotInversed[i] ?
- new GeomAPI_XY(aStartPoint->x(), aStartPoint->y()) :
- new GeomAPI_XY(aEndPoint->x(), aEndPoint->y()));
- aEnd[i] = std::shared_ptr<GeomAPI_XY>(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<GeomAPI_Dir2d> aDir[2];
- std::shared_ptr<GeomAPI_Dir2d> aDirT[2];
- for (int i = 0; i < aNbFeatures; i++) {
- aDir[i] = std::shared_ptr<GeomAPI_Dir2d>(new GeomAPI_Dir2d(aEnd[i]->decreased(aStart[i])));
- aDirT[i] = std::shared_ptr<GeomAPI_Dir2d>(new GeomAPI_Dir2d(-aDir[i]->y(), aDir[i]->x()));
- }
-
- // get and filter possible centers
- std::list< std::shared_ptr<GeomAPI_XY> > aSuspectCenters;
- possibleFilletCenterLineLine(aStart[0], aDir[0], aStart[1], aDir[1],
- theRadius, aSuspectCenters);
- double aDot = 0.0;
- std::list< std::shared_ptr<GeomAPI_XY> >::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<GeomAPI_Dir2d> aDirLine = std::shared_ptr<GeomAPI_Dir2d>(
- new GeomAPI_Dir2d(aEnd[aLineInd]->decreased(aStart[aLineInd])));
- std::shared_ptr<GeomAPI_Dir2d> aDirT = std::shared_ptr<GeomAPI_Dir2d>(
- new GeomAPI_Dir2d(-aDirLine->y(), aDirLine->x()));
-
- std::shared_ptr<GeomAPI_Dir2d> aStartArcDir = std::shared_ptr<GeomAPI_Dir2d>(
- new GeomAPI_Dir2d(aStart[1-aLineInd]->decreased(aCenter[1-aLineInd])));
- std::shared_ptr<GeomAPI_Dir2d> aEndArcDir = std::shared_ptr<GeomAPI_Dir2d>(
- 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<GeomAPI_XY> > 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<GeomAPI_XY> 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<GeomAPI_XY> >::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<GeomAPI_Dir2d> aCurDir = std::shared_ptr<GeomAPI_Dir2d>(
- 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<GeomAPI_Dir2d> aStartArcDir[aNbFeatures];
- for (int i = 0; i < aNbFeatures; i++) {
- anArcRadius[i] = aStart[i]->distance(aCenter[i]);
- aStartArcDir[i] = std::shared_ptr<GeomAPI_Dir2d>(
- new GeomAPI_Dir2d(aStart[i]->decreased(aCenter[i])));
- std::shared_ptr<GeomAPI_Dir2d> aEndArcDir = std::shared_ptr<GeomAPI_Dir2d>(
- new GeomAPI_Dir2d(aEnd[i]->decreased(aCenter[i])));
- anArcAngle[i] = aEndArcDir->angle(aStartArcDir[i]);
- }
-
- // get and filter possible centers
- std::list< std::shared_ptr<GeomAPI_XY> > aSuspectCenters;
- possibleFilletCenterArcArc(aCenter[0], anArcRadius[0], aCenter[1],
- anArcRadius[1], theRadius, aSuspectCenters);
- double aDot = 0.0;
- std::shared_ptr<GeomAPI_XY> aLineTgPoint, anArcTgPoint;
- std::list< std::shared_ptr<GeomAPI_XY> >::iterator anIt = aSuspectCenters.begin();
- for (; anIt != aSuspectCenters.end(); anIt++) {
- std::shared_ptr<GeomAPI_Dir2d> aCurDir = std::shared_ptr<GeomAPI_Dir2d>(
- 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<GeomAPI_Dir2d>(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<GeomAPI_Pnt2d> theFilletPoint,
- std::shared_ptr<GeomAPI_Pnt2d>& thePoint) {
- if(theFeature->getKind() == SketchPlugin_Line::ID()) {
- std::shared_ptr<GeomAPI_Pnt2d> aPntStart = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
- theFeature->attribute(SketchPlugin_Line::START_ID()))->pnt();
- std::shared_ptr<GeomAPI_Pnt2d> aPntEnd = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
- theFeature->attribute(SketchPlugin_Line::END_ID()))->pnt();
- if(aPntStart->distance(theFilletPoint) > 1.e-7) {
- aPntStart = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
- theFeature->attribute(SketchPlugin_Line::END_ID()))->pnt();
- aPntEnd = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
- 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<GeomAPI_Pnt2d> aPntTemp;
- std::shared_ptr<GeomAPI_Pnt2d> aPntStart = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
- theFeature->attribute(SketchPlugin_Arc::START_ID()))->pnt();
- std::shared_ptr<GeomAPI_Pnt2d> aPntEnd = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
- theFeature->attribute(SketchPlugin_Arc::END_ID()))->pnt();
- if(theFeature->attribute(SketchPlugin_Arc::INVERSED_ID())) {
- aPntTemp = aPntStart;
- aPntStart = aPntEnd;
- aPntEnd = aPntTemp;
- }
- std::shared_ptr<GeomAPI_Pnt2d> aCenterPnt = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
- theFeature->attribute(SketchPlugin_Arc::CENTER_ID()))->pnt();
- std::shared_ptr<GeomAPI_Circ2d> 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<GeomAPI_Pnt2d> thePoint)
-{
- std::shared_ptr<GeomAPI_Pnt2d> aProjectPnt;
- if(theFeature->getKind() == SketchPlugin_Line::ID()) {
- std::shared_ptr<GeomAPI_Pnt2d> aPntStart = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
- theFeature->attribute(SketchPlugin_Line::START_ID()))->pnt();
- std::shared_ptr<GeomAPI_Pnt2d> aPntEnd = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
- theFeature->attribute(SketchPlugin_Line::END_ID()))->pnt();
- std::shared_ptr<GeomAPI_Lin2d> aLin(new GeomAPI_Lin2d(aPntStart, aPntEnd));
- aProjectPnt = aLin->project(thePoint);
- } else {
- std::shared_ptr<GeomAPI_Pnt2d> aPntStart = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
- theFeature->attribute(SketchPlugin_Arc::START_ID()))->pnt();
- std::shared_ptr<GeomAPI_Pnt2d> aPntEnd = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
- theFeature->attribute(SketchPlugin_Arc::END_ID()))->pnt();
- std::shared_ptr<GeomAPI_Pnt2d> aCenterPnt = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
- theFeature->attribute(SketchPlugin_Arc::CENTER_ID()))->pnt();
- std::shared_ptr<GeomAPI_Circ2d> aCirc(new GeomAPI_Circ2d(aCenterPnt, aPntStart));
- aProjectPnt = aCirc->project(thePoint);
- }
- if(aProjectPnt.get()) {
- return aProjectPnt->distance(thePoint);
- }
- return -1;
-}
-
-std::set<FeaturePtr> getCoincides(const FeaturePtr& theConstraintCoincidence)
-{
- std::set<FeaturePtr> aCoincides;
-
- std::shared_ptr<GeomAPI_Pnt2d> 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<FeaturePtr> aNewSetOfCoincides;
- for(std::set<FeaturePtr>::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<GeomDataAPI_Point2D> aPointCenter2D =
- std::dynamic_pointer_cast<GeomDataAPI_Point2D>(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<FeaturePtr>::iterator
- anIt = aCoincides.begin(); anIt != aCoincides.end(); ++anIt) {
- if(!(*anIt)->boolean(SketchPlugin_SketchEntity::AUXILIARY_ID())->value()) {
- aNewSetOfCoincides.insert(*anIt);
- }
- }
- aCoincides = aNewSetOfCoincides;
- }
-
- return aCoincides;
-}
+++ /dev/null
-// 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 <SketchPlugin_Sketch.h>
-#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<std::pair<FeaturePtr, bool>> baseEdgesState;
- std::list<FeaturePtr> resultEdges; ///< list of result edges
- std::list<FeaturePtr> 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<AttributePtr, FilletFeatures> pointsFeaturesMap() const {
- return myPointFeaturesMap;
- };
-
-private:
- /// \ Removes all produced features and restore base edges.
- void clearResults();
-
-private:
- std::set<AttributePtr> myNewPoints; ///< set of new points
-
- /// map of point and features for fillet
- std::map<AttributePtr, FilletFeatures> 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
--- /dev/null
+// 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 <ModelAPI_AttributeRefAttr.h>
+#include <ModelAPI_Data.h>
+#include <ModelAPI_Events.h>
+#include <ModelAPI_Session.h>
+#include <ModelAPI_Tools.h>
+#include <ModelAPI_Validator.h>
+
+#include <GeomAlgoAPI_EdgeBuilder.h>
+
+#include <GeomAPI_Circ2d.h>
+#include <GeomAPI_Dir2d.h>
+#include <GeomAPI_Lin2d.h>
+#include <GeomAPI_Pnt2d.h>
+#include <GeomAPI_XY.h>
+
+#include <GeomDataAPI_Point2D.h>
+
+#include <Events_Loop.h>
+
+#include <math.h>
+
+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<GeomAPI_XY>& theCenter,
+ std::shared_ptr<GeomAPI_XY>& theTangentA,
+ std::shared_ptr<GeomAPI_XY>& theTangentB);
+
+/// Get point on 1/3 length of edge from fillet point
+static void getPointOnEdge(const FeaturePtr theFeature,
+ const std::shared_ptr<GeomAPI_Pnt2d> theFilletPoint,
+ std::shared_ptr<GeomAPI_Pnt2d>& thePoint);
+
+/// Get distance from point to feature
+static double getProjectionDistance(const FeaturePtr theFeature,
+ const std::shared_ptr<GeomAPI_Pnt2d> thePoint);
+
+/// Get coincide edges for fillet
+static std::set<FeaturePtr> getCoincides(const FeaturePtr& theConstraintCoincidence);
+
+static std::set<FeaturePtr> 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<GeomDataAPI_Point2D>(
+ aFilletArc->attribute(SketchPlugin_Arc::CENTER_ID()))->setValue(myCenterXY->x(),
+ myCenterXY->y());
+ std::shared_ptr<GeomDataAPI_Point2D> aStartPoint =
+ std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
+ aFilletArc->attribute(SketchPlugin_Arc::START_ID()));
+ std::shared_ptr<GeomDataAPI_Point2D> aEndPoint =
+ std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
+ 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<SketchPlugin_Arc>(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<GeomDataAPI_Point2D> aStartPoint1;
+ int aFeatInd1 = myIsReversed ? 1 : 0;
+ int anAttrInd1 = (myIsReversed ? 2 : 0) + (myIsNotInversed[aFeatInd1] ? 0 : 1);
+ aStartPoint1 = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
+ myBaseFeatures[aFeatInd1]->attribute(myFeatAttributes[anAttrInd1]));
+ std::set<FeaturePtr> aFeaturesToBeRemoved1 =
+ findFeaturesToRemove(myBaseFeatures[aFeatInd1], aStartPoint1);
+
+ std::shared_ptr<GeomDataAPI_Point2D> aStartPoint2;
+ int aFeatInd2 = myIsReversed ? 0 : 1;
+ int anAttrInd2 = (myIsReversed ? 0 : 2) + (myIsNotInversed[aFeatInd2] ? 0 : 1);
+ aStartPoint2 = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
+ myBaseFeatures[aFeatInd2]->attribute(myFeatAttributes[anAttrInd2]));
+ std::set<FeaturePtr> 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<ModelAPI_AttributeRefAttr>(
+ aConstraint->attribute(SketchPlugin_Constraint::ENTITY_A()));
+ aRefAttr->setAttr(aFilletArc->attribute(SketchPlugin_Arc::START_ID()));
+ aRefAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(
+ 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<ModelAPI_AttributeRefAttr>(
+ aConstraint->attribute(SketchPlugin_Constraint::ENTITY_A()));
+ aRefAttr->setAttr(aFilletArc->attribute(SketchPlugin_Arc::END_ID()));
+ aRefAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(
+ 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<ModelAPI_AttributeRefAttr>(
+ aConstraint->attribute(SketchPlugin_Constraint::ENTITY_A()));
+ aRefAttr->setObject(aFilletArc->lastResult());
+ aRefAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(
+ 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<GeomDataAPI_Point2D> aFilletPoint2D =
+ std::dynamic_pointer_cast<GeomDataAPI_Point2D>(aPointRefAttr->attr());
+ if (!aFilletPoint2D.get()) {
+ return AISObjectPtr();
+ }
+
+ // Obtain constraint coincidence for the fillet point.
+ FeaturePtr aConstraintCoincidence;
+ const std::set<AttributePtr>& aRefsList = aFilletPoint2D->owner()->data()->refsToMe();
+ for(std::set<AttributePtr>::const_iterator anIt = aRefsList.cbegin();
+ anIt != aRefsList.cend();
+ ++anIt) {
+ std::shared_ptr<ModelAPI_Attribute> anAttr = (*anIt);
+ FeaturePtr aFeature = std::dynamic_pointer_cast<ModelAPI_Feature>(anAttr->owner());
+ if(aFeature->getKind() == SketchPlugin_ConstraintCoincidence::ID()) {
+ AttributeRefAttrPtr anAttrRefA = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(
+ aFeature->attribute(SketchPlugin_ConstraintCoincidence::ENTITY_A()));
+ AttributeRefAttrPtr anAttrRefB = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(
+ 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<FeaturePtr> 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<FeaturePtr>::iterator aLinesIt = anEdgeFeatures.begin();
+ anEdgeFeature1 = *aLinesIt++;
+ anEdgeFeature2 = *aLinesIt;
+
+ // Getting points located at 1/3 of edge length from fillet point.
+ std::shared_ptr<GeomAPI_Pnt2d> aFilletPnt2d = aFilletPoint2D->pnt();
+ std::shared_ptr<GeomAPI_Pnt2d> 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<GeomAPI_Pnt2d> 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<GeomDataAPI_Point2D>(
+ myBaseFeatures[i]->attribute(aStartAttr))->pnt();
+ myFeatAttributes[2*i+1] = aEndAttr;
+ aStartEndPnt[2*i+1] = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
+ 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<GeomAPI_Dir2d> aTangentDir[aNbFeatures];
+ for (int i = 0; i < aNbFeatures; i++) {
+ std::shared_ptr<GeomAPI_XY> 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<GeomAPI_Pnt2d> aCenterPoint =
+ std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
+ 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<SketchPlugin_Arc>(myBaseFeatures[i])->isReversed())
+ aDir = aDir->multiplied(-1.0);
+ }
+ aTangentDir[i] = std::shared_ptr<GeomAPI_Dir2d>(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<GeomAPI_XY> aTmp = myTangentXY1;
+ myTangentXY1 = myTangentXY2;
+ myTangentXY2 = aTmp;
+ }
+
+ // Create arc for presentation.
+ std::shared_ptr<GeomAPI_Pnt> aCenterPnt(aSketch->to3D(myCenterXY->x(), myCenterXY->y()));
+ std::shared_ptr<GeomAPI_Pnt> aTangentPnt1(aSketch->to3D(myTangentXY1->x(),
+ myTangentXY1->y()));
+ std::shared_ptr<GeomAPI_Pnt> aTangentPnt2(aSketch->to3D(myTangentXY2->x(),
+ myTangentXY2->y()));
+ std::shared_ptr<GeomDataAPI_Dir> aNDir = std::dynamic_pointer_cast<GeomDataAPI_Dir>(
+ aSketch->data()->attribute(SketchPlugin_Sketch::NORM_ID()));
+ std::shared_ptr<GeomAPI_Shape> 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<GeomAPI_Pnt2d> anArcPoint = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
+ theNewArc->attribute(theNewArcAttribute))->pnt();
+ std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
+ theFeature->attribute(theFeatureAttribute))->setValue(anArcPoint->x(), anArcPoint->y());
+}
+
+/// \brief Find intersections of lines shifted along normal direction
+void possibleFilletCenterLineLine(
+ std::shared_ptr<GeomAPI_XY> thePointA, std::shared_ptr<GeomAPI_Dir2d> theDirA,
+ std::shared_ptr<GeomAPI_XY> thePointB, std::shared_ptr<GeomAPI_Dir2d> theDirB,
+ double theRadius, std::list< std::shared_ptr<GeomAPI_XY> >& theCenters)
+{
+ std::shared_ptr<GeomAPI_Dir2d> aDirAT(new GeomAPI_Dir2d(-theDirA->y(), theDirA->x()));
+ std::shared_ptr<GeomAPI_Dir2d> aDirBT(new GeomAPI_Dir2d(-theDirB->y(), theDirB->x()));
+ std::shared_ptr<GeomAPI_XY> 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<GeomAPI_XY> 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<GeomAPI_XY> theStartLine, std::shared_ptr<GeomAPI_Dir2d> theDirLine,
+ std::shared_ptr<GeomAPI_XY> theCenterArc, double theRadiusArc,
+ double theRadius, std::list< std::shared_ptr<GeomAPI_XY> >& theCenters)
+{
+ std::shared_ptr<GeomAPI_Dir2d> aDirT(new GeomAPI_Dir2d(-theDirLine->y(), theDirLine->x()));
+ std::shared_ptr<GeomAPI_XY> 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<GeomAPI_XY> aPoint1(new GeomAPI_XY(x1, y1));
+ theCenters.push_back(aPoint1);
+ std::shared_ptr<GeomAPI_XY> aPoint2(new GeomAPI_XY(x2, y2));
+ theCenters.push_back(aPoint2);
+ }
+ }
+}
+
+/// \brief Find intersections of two circles with extended radii
+void possibleFilletCenterArcArc(
+ std::shared_ptr<GeomAPI_XY> theCenterA, double theRadiusA,
+ std::shared_ptr<GeomAPI_XY> theCenterB, double theRadiusB,
+ double theRadius, std::list< std::shared_ptr<GeomAPI_XY> >& theCenters)
+{
+ std::shared_ptr<GeomAPI_XY> 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<GeomAPI_XY> aPoint1(new GeomAPI_XY(x1, y1));
+ theCenters.push_back(aPoint1);
+ std::shared_ptr<GeomAPI_XY> aPoint2(new GeomAPI_XY(x2, y2));
+ theCenters.push_back(aPoint2);
+ }
+ }
+}
+
+void calculateFilletCenter(FeaturePtr theFeatureA, FeaturePtr theFeatureB,
+ double theRadius, bool theNotInversed[2],
+ std::shared_ptr<GeomAPI_XY>& theCenter,
+ std::shared_ptr<GeomAPI_XY>& theTangentA,
+ std::shared_ptr<GeomAPI_XY>& theTangentB)
+{
+ static const int aNbFeatures = 2;
+ FeaturePtr aFeature[aNbFeatures] = {theFeatureA, theFeatureB};
+ std::shared_ptr<GeomAPI_XY> aStart[aNbFeatures], aEnd[aNbFeatures], aCenter[aNbFeatures];
+ std::shared_ptr<GeomDataAPI_Point2D> aStartPoint, aEndPoint;
+
+ for (int i = 0; i < aNbFeatures; i++) {
+ if (aFeature[i]->getKind() == SketchPlugin_Line::ID()) {
+ aStartPoint = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
+ aFeature[i]->attribute(SketchPlugin_Line::START_ID()));
+ aEndPoint = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
+ aFeature[i]->attribute(SketchPlugin_Line::END_ID()));
+ } else if (aFeature[i]->getKind() == SketchPlugin_Arc::ID()) {
+ aStartPoint = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
+ aFeature[i]->attribute(SketchPlugin_Arc::START_ID()));
+ aEndPoint = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
+ aFeature[i]->attribute(SketchPlugin_Arc::END_ID()));
+ aCenter[i] = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
+ aFeature[i]->attribute(SketchPlugin_Arc::CENTER_ID()))->pnt()->xy();
+ } else
+ return;
+ aStart[i] = std::shared_ptr<GeomAPI_XY>(theNotInversed[i] ?
+ new GeomAPI_XY(aStartPoint->x(), aStartPoint->y()) :
+ new GeomAPI_XY(aEndPoint->x(), aEndPoint->y()));
+ aEnd[i] = std::shared_ptr<GeomAPI_XY>(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<GeomAPI_Dir2d> aDir[2];
+ std::shared_ptr<GeomAPI_Dir2d> aDirT[2];
+ for (int i = 0; i < aNbFeatures; i++) {
+ aDir[i] = std::shared_ptr<GeomAPI_Dir2d>(new GeomAPI_Dir2d(aEnd[i]->decreased(aStart[i])));
+ aDirT[i] = std::shared_ptr<GeomAPI_Dir2d>(new GeomAPI_Dir2d(-aDir[i]->y(), aDir[i]->x()));
+ }
+
+ // get and filter possible centers
+ std::list< std::shared_ptr<GeomAPI_XY> > aSuspectCenters;
+ possibleFilletCenterLineLine(aStart[0], aDir[0], aStart[1], aDir[1],
+ theRadius, aSuspectCenters);
+ double aDot = 0.0;
+ std::list< std::shared_ptr<GeomAPI_XY> >::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<GeomAPI_Dir2d> aDirLine = std::shared_ptr<GeomAPI_Dir2d>(
+ new GeomAPI_Dir2d(aEnd[aLineInd]->decreased(aStart[aLineInd])));
+ std::shared_ptr<GeomAPI_Dir2d> aDirT = std::shared_ptr<GeomAPI_Dir2d>(
+ new GeomAPI_Dir2d(-aDirLine->y(), aDirLine->x()));
+
+ std::shared_ptr<GeomAPI_Dir2d> aStartArcDir = std::shared_ptr<GeomAPI_Dir2d>(
+ new GeomAPI_Dir2d(aStart[1-aLineInd]->decreased(aCenter[1-aLineInd])));
+ std::shared_ptr<GeomAPI_Dir2d> aEndArcDir = std::shared_ptr<GeomAPI_Dir2d>(
+ 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<GeomAPI_XY> > 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<GeomAPI_XY> 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<GeomAPI_XY> >::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<GeomAPI_Dir2d> aCurDir = std::shared_ptr<GeomAPI_Dir2d>(
+ 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<GeomAPI_Dir2d> aStartArcDir[aNbFeatures];
+ for (int i = 0; i < aNbFeatures; i++) {
+ anArcRadius[i] = aStart[i]->distance(aCenter[i]);
+ aStartArcDir[i] = std::shared_ptr<GeomAPI_Dir2d>(
+ new GeomAPI_Dir2d(aStart[i]->decreased(aCenter[i])));
+ std::shared_ptr<GeomAPI_Dir2d> aEndArcDir = std::shared_ptr<GeomAPI_Dir2d>(
+ new GeomAPI_Dir2d(aEnd[i]->decreased(aCenter[i])));
+ anArcAngle[i] = aEndArcDir->angle(aStartArcDir[i]);
+ }
+
+ // get and filter possible centers
+ std::list< std::shared_ptr<GeomAPI_XY> > aSuspectCenters;
+ possibleFilletCenterArcArc(aCenter[0], anArcRadius[0], aCenter[1],
+ anArcRadius[1], theRadius, aSuspectCenters);
+ double aDot = 0.0;
+ std::shared_ptr<GeomAPI_XY> aLineTgPoint, anArcTgPoint;
+ std::list< std::shared_ptr<GeomAPI_XY> >::iterator anIt = aSuspectCenters.begin();
+ for (; anIt != aSuspectCenters.end(); anIt++) {
+ std::shared_ptr<GeomAPI_Dir2d> aCurDir = std::shared_ptr<GeomAPI_Dir2d>(
+ 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<GeomAPI_Dir2d>(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<GeomAPI_Pnt2d> theFilletPoint,
+ std::shared_ptr<GeomAPI_Pnt2d>& thePoint) {
+ if(theFeature->getKind() == SketchPlugin_Line::ID()) {
+ std::shared_ptr<GeomAPI_Pnt2d> aPntStart = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
+ theFeature->attribute(SketchPlugin_Line::START_ID()))->pnt();
+ std::shared_ptr<GeomAPI_Pnt2d> aPntEnd = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
+ theFeature->attribute(SketchPlugin_Line::END_ID()))->pnt();
+ if(aPntStart->distance(theFilletPoint) > 1.e-7) {
+ aPntStart = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
+ theFeature->attribute(SketchPlugin_Line::END_ID()))->pnt();
+ aPntEnd = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
+ 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<GeomAPI_Pnt2d> aPntTemp;
+ std::shared_ptr<GeomAPI_Pnt2d> aPntStart = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
+ theFeature->attribute(SketchPlugin_Arc::START_ID()))->pnt();
+ std::shared_ptr<GeomAPI_Pnt2d> aPntEnd = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
+ theFeature->attribute(SketchPlugin_Arc::END_ID()))->pnt();
+ if(theFeature->attribute(SketchPlugin_Arc::INVERSED_ID())) {
+ aPntTemp = aPntStart;
+ aPntStart = aPntEnd;
+ aPntEnd = aPntTemp;
+ }
+ std::shared_ptr<GeomAPI_Pnt2d> aCenterPnt = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
+ theFeature->attribute(SketchPlugin_Arc::CENTER_ID()))->pnt();
+ std::shared_ptr<GeomAPI_Circ2d> 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<GeomAPI_Pnt2d> thePoint)
+{
+ std::shared_ptr<GeomAPI_Pnt2d> aProjectPnt;
+ if(theFeature->getKind() == SketchPlugin_Line::ID()) {
+ std::shared_ptr<GeomAPI_Pnt2d> aPntStart = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
+ theFeature->attribute(SketchPlugin_Line::START_ID()))->pnt();
+ std::shared_ptr<GeomAPI_Pnt2d> aPntEnd = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
+ theFeature->attribute(SketchPlugin_Line::END_ID()))->pnt();
+ std::shared_ptr<GeomAPI_Lin2d> aLin(new GeomAPI_Lin2d(aPntStart, aPntEnd));
+ aProjectPnt = aLin->project(thePoint);
+ } else {
+ std::shared_ptr<GeomAPI_Pnt2d> aPntStart = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
+ theFeature->attribute(SketchPlugin_Arc::START_ID()))->pnt();
+ std::shared_ptr<GeomAPI_Pnt2d> aPntEnd = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
+ theFeature->attribute(SketchPlugin_Arc::END_ID()))->pnt();
+ std::shared_ptr<GeomAPI_Pnt2d> aCenterPnt = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
+ theFeature->attribute(SketchPlugin_Arc::CENTER_ID()))->pnt();
+ std::shared_ptr<GeomAPI_Circ2d> aCirc(new GeomAPI_Circ2d(aCenterPnt, aPntStart));
+ aProjectPnt = aCirc->project(thePoint);
+ }
+ if(aProjectPnt.get()) {
+ return aProjectPnt->distance(thePoint);
+ }
+ return -1;
+}
+
+std::set<FeaturePtr> getCoincides(const FeaturePtr& theConstraintCoincidence)
+{
+ std::set<FeaturePtr> aCoincides;
+
+ std::shared_ptr<GeomAPI_Pnt2d> 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<FeaturePtr> aNewSetOfCoincides;
+ for(std::set<FeaturePtr>::iterator anIt = aCoincides.begin(); anIt != aCoincides.end(); ++anIt) {
+ std::shared_ptr<SketchPlugin_SketchEntity> aSketchEntity =
+ std::dynamic_pointer_cast<SketchPlugin_SketchEntity>(*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<GeomDataAPI_Point2D> aPointCenter2D =
+ std::dynamic_pointer_cast<GeomDataAPI_Point2D>(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<FeaturePtr>::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<FeaturePtr> findFeaturesToRemove(const FeaturePtr theFeature,
+ const AttributePtr theAttribute) {
+ std::set<FeaturePtr> aFeaturesToBeRemoved;
+ std::set<AttributePtr> aRefs = theFeature->data()->refsToMe();
+ std::list<ResultPtr> aResults = theFeature->results();
+ for(std::list<ResultPtr>::const_iterator aResultsIt = aResults.cbegin();
+ aResultsIt != aResults.cend();
+ ++aResultsIt) {
+ ResultPtr aResult = *aResultsIt;
+ std::set<AttributePtr> aResultRefs = aResult->data()->refsToMe();
+ aRefs.insert(aResultRefs.begin(), aResultRefs.end());
+ }
+ for(std::set<AttributePtr>::const_iterator anIt = aRefs.cbegin();
+ anIt != aRefs.cend();
+ ++anIt) {
+ std::shared_ptr<ModelAPI_Attribute> anAttr = (*anIt);
+ FeaturePtr aFeature = std::dynamic_pointer_cast<ModelAPI_Feature>(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<AttributePtr> anAttrs =
+ aFeature->data()->attributes(ModelAPI_AttributeRefAttr::typeId());
+ for(std::list<AttributePtr>::const_iterator aRefAttrsIt = anAttrs.cbegin();
+ aRefAttrsIt != anAttrs.cend();
+ ++aRefAttrsIt) {
+ AttributeRefAttrPtr anAttrRefAttr =
+ std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(*aRefAttrsIt);
+ if(anAttrRefAttr.get() && anAttrRefAttr->attr() == theAttribute) {
+ aFeaturesToBeRemoved.insert(aFeature);
+ }
+ }
+ }
+ }
+ return aFeaturesToBeRemoved;
+}
--- /dev/null
+// 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 <GeomAPI_IPresentable.h>
+
+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<GeomAPI_XY> myCenterXY;
+ std::shared_ptr<GeomAPI_XY> myTangentXY1;
+ std::shared_ptr<GeomAPI_XY> myTangentXY2;
+};
+
+#endif
#include <SketchPlugin_ConstraintCollinear.h>
#include <SketchPlugin_ConstraintDistance.h>
#include <SketchPlugin_ConstraintEqual.h>
-#include <SketchPlugin_ConstraintFillet.h>
+#include <SketchPlugin_Fillet.h>
#include <SketchPlugin_ConstraintSplit.h>
#include <SketchPlugin_ConstraintHorizontal.h>
#include <SketchPlugin_ConstraintLength.h>
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()) {
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);
#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"
const std::list<std::string>& theArguments,
Events_InfoMessage& theError) const
{
- std::shared_ptr<SketchPlugin_ConstraintFillet> aFilletFeature =
- std::dynamic_pointer_cast<SketchPlugin_ConstraintFillet>(theAttribute->owner());
- AttributeRefAttrListPtr aPointsRefList =
- std::dynamic_pointer_cast<ModelAPI_AttributeRefAttrList>(theAttribute);
- if(aPointsRefList->size() == 0) {
- theError = "Error: List of points is empty.";
+ AttributeRefAttrPtr aPointRefAttr =
+ std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(theAttribute);
+ if(!aPointRefAttr.get()) {
+ theError = "Error: Point not selected.";
return false;
}
- std::map<AttributePtr, SketchPlugin_ConstraintFillet::FilletFeatures> aPointsFeaturesMap =
- aFilletFeature->pointsFeaturesMap();
- std::set<AttributePtr> aSetOfPointsOnResultEdges;
- for(std::map<AttributePtr, SketchPlugin_ConstraintFillet::FilletFeatures>::iterator
- aPointsIter = aPointsFeaturesMap.begin();
- aPointsIter != aPointsFeaturesMap.end();
- ++aPointsIter) {
- const SketchPlugin_ConstraintFillet::FilletFeatures& aFeatures = aPointsIter->second;
- const std::list<FeaturePtr>& aResultEdges = aFeatures.resultEdges;
- for(std::list<FeaturePtr>::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<GeomAPI_Pnt2d> aSelectedPnt =
+ std::dynamic_pointer_cast<GeomDataAPI_Point2D>(aPointAttribute)->pnt();
- std::list<std::pair<ObjectPtr, AttributePtr>> aPointsList = aPointsRefList->list();
- for(std::list<std::pair<ObjectPtr, AttributePtr>>::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<GeomAPI_Pnt2d> aSelectedPnt =
- std::dynamic_pointer_cast<GeomDataAPI_Point2D>(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<AttributePtr>& aRefsList = aPointAttribute->owner()->data()->refsToMe();
- FeaturePtr aConstraintCoincidence;
- for(std::set<AttributePtr>::const_iterator anIt = aRefsList.cbegin();
- anIt != aRefsList.cend(); ++anIt) {
- std::shared_ptr<ModelAPI_Attribute> aAttr = (*anIt);
- FeaturePtr aConstrFeature = std::dynamic_pointer_cast<ModelAPI_Feature>(aAttr->owner());
- if (aConstrFeature->getKind() == SketchPlugin_ConstraintCoincidence::ID()) {
- AttributeRefAttrPtr anAttrRefA = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(
- aConstrFeature->attribute(SketchPlugin_ConstraintCoincidence::ENTITY_A()));
- AttributeRefAttrPtr anAttrRefB = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(
- 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<AttributePtr>& aRefsList = aPointAttribute->owner()->data()->refsToMe();
+ FeaturePtr aConstraintCoincidence;
+ for(std::set<AttributePtr>::const_iterator anIt = aRefsList.cbegin();
+ anIt != aRefsList.cend(); ++anIt) {
+ std::shared_ptr<ModelAPI_Attribute> aAttr = (*anIt);
+ FeaturePtr aConstrFeature = std::dynamic_pointer_cast<ModelAPI_Feature>(aAttr->owner());
+ if (aConstrFeature->getKind() == SketchPlugin_ConstraintCoincidence::ID()) {
+ AttributeRefAttrPtr anAttrRefA = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(
+ aConstrFeature->attribute(SketchPlugin_ConstraintCoincidence::ENTITY_A()));
+ AttributeRefAttrPtr anAttrRefB = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(
+ 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<FeaturePtr> 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<FeaturePtr> aNewSetOfCoincides;
+ for(std::set<FeaturePtr>::iterator anIt = aCoinsides.begin();
+ anIt != aCoinsides.end(); ++anIt) {
+ std::shared_ptr<SketchPlugin_SketchEntity> aSketchEntity =
+ std::dynamic_pointer_cast<SketchPlugin_SketchEntity>(*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<GeomAPI_Pnt2d> anArcCenterPnt =
+ std::dynamic_pointer_cast<GeomDataAPI_Point2D>(anArcCenter)->pnt();
+ double aDistSelectedArcCenter = aSelectedPnt->distance(anArcCenterPnt);
+ if(aDistSelectedArcCenter < tolerance) {
+ continue;
+ }
+ }
+ aNewSetOfCoincides.insert(*anIt);
+ }
+ aCoinsides = aNewSetOfCoincides;
- // Get coincides from constraint.
- std::set<FeaturePtr> 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<FeaturePtr> 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<FeaturePtr>::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<GeomAPI_Pnt2d> anArcCenterPnt =
- std::dynamic_pointer_cast<GeomDataAPI_Point2D>(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<FeaturePtr>::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<FeaturePtr>::iterator anIt = aCoinsides.begin();
+ FeaturePtr aFirstFeature = *anIt++;
+ FeaturePtr aSecondFeature = *anIt;
+ const std::set<AttributePtr>& 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<FeaturePtr>::iterator anIt = aCoinsides.begin();
- FeaturePtr aFirstFeature = *anIt++;
- FeaturePtr aSecondFeature = *anIt;
- const std::set<AttributePtr>& aFirstFeatureRefsList = aFirstFeature->data()->refsToMe();
- if(hasSameTangentFeature(aFirstFeatureRefsList, aSecondFeature)) {
+ std::list<ResultPtr> aFirstResults = aFirstFeature->results();
+ for(std::list<ResultPtr>::iterator aResIt = aFirstResults.begin();
+ aResIt != aFirstResults.end(); ++aResIt) {
+ ResultPtr aRes = *aResIt;
+ const std::set<AttributePtr>& aResRefsList = aRes->data()->refsToMe();
+ if(hasSameTangentFeature(aResRefsList, aSecondFeature)) {
theError = "Error: Edges in selected point has tangent constraint.";
return false;
}
+ }
- std::list<ResultPtr> aFirstResults = aFirstFeature->results();
- for(std::list<ResultPtr>::iterator aResIt = aFirstResults.begin();
- aResIt != aFirstResults.end(); ++aResIt) {
- ResultPtr aRes = *aResIt;
- const std::set<AttributePtr>& 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<GeomAPI_Pnt2d> aFirstStartPnt, aFirstEndPnt, aSecondStartPnt, aSecondEndPnt;
- aFirstStartPnt =
- std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
- aFirstFeature->attribute(aStartAttr))->pnt();
- aFirstEndPnt =
- std::dynamic_pointer_cast<GeomDataAPI_Point2D>(aFirstFeature->attribute(anEndAttr))->pnt();
- aSecondStartPnt =
- std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
- aSecondFeature->attribute(aStartAttr))->pnt();
- aSecondEndPnt =
- std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
- 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<GeomAPI_Pnt2d> aFirstStartPnt, aFirstEndPnt, aSecondStartPnt, aSecondEndPnt;
+ aFirstStartPnt =
+ std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
+ aFirstFeature->attribute(aStartAttr))->pnt();
+ aFirstEndPnt =
+ std::dynamic_pointer_cast<GeomDataAPI_Point2D>(aFirstFeature->attribute(anEndAttr))->pnt();
+ aSecondStartPnt =
+ std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
+ aSecondFeature->attribute(aStartAttr))->pnt();
+ aSecondEndPnt =
+ std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
+ 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;
}
</context>
<context>
- <name>SketchConstraintFillet:ConstraintValue:GeomValidators_Positive</name>
+ <name>SketchFillet:ConstraintValue:GeomValidators_Positive</name>
<message>
<source>Double is not initialized.</source>
<translation>Set the fillet radius</translation>
</message>
</context>
<context>
- <name>SketchConstraintFillet:ConstraintValue:GeomValidators_Positive</name>
+ <name>SketchFillet:ConstraintValue:GeomValidators_Positive</name>
<message>
<source>Double is not positive.</source>
<translation>The fillet radius must be positive</translation>
</message>
</context>
<context>
- <name>SketchConstraintFillet:ConstraintValue:GeomValidators_Positive</name>
+ <name>SketchFillet:ConstraintValue:GeomValidators_Positive</name>
<message>
<source>Integer is not initialized.</source>
<translation>Set the integer fillet radius</translation>
</message>
</context>
<context>
- <name>SketchConstraintFillet:ConstraintValue:GeomValidators_Positive</name>
+ <name>SketchFillet:ConstraintValue:GeomValidators_Positive</name>
<message>
<source>Integer is not positive.</source>
<translation>The integer fillet radius must be positive</translation>
</message>
</context>
<context>
- <name>SketchConstraintFillet:Model_FeatureValidator</name>
+ <name>SketchFillet:Model_FeatureValidator</name>
<message>
<source>Attribute "ConstraintEntityA" is not initialized.</source>
<translation>Select one or several points for filet</translation>
</message>
</context>
<context>
- <name>SketchConstraintFillet:Model_FeatureValidator</name>
+ <name>SketchFillet:Model_FeatureValidator</name>
<message>
<source>Attribute "ConstraintValue" is not initialized.</source>
<translation>Set the fillet radius</translation>
</message>
</context>
<context>
- <name>SketchConstraintFillet:ConstraintEntityA:SketchPlugin_FilletVertexValidator</name>
+ <name>SketchFillet:ConstraintEntityA:SketchPlugin_FilletVertexValidator</name>
<message>
<source>Error: List of points is empty.</source>
<translation>List of points is empty</translation>
</message>
</context>
<context>
- <name>SketchConstraintFillet:ConstraintEntityA:SketchPlugin_FilletVertexValidator</name>
+ <name>SketchFillet:ConstraintEntityA:SketchPlugin_FilletVertexValidator</name>
<message>
<source>Error: one of the selected point does not have coicidence.</source>
<translation>One of the selected point does not have coicidence</translation>
</message>
</context>
<context>
- <name>SketchConstraintFillet:ConstraintEntityA:SketchPlugin_FilletVertexValidator</name>
+ <name>SketchFillet:ConstraintEntityA:SketchPlugin_FilletVertexValidator</name>
<message>
<source>Error: One of the selected points does not have two suitable edges for fillet.</source>
<translation>One of the selected points does not have two suitable edges for fillet</translation>
</message>
</context>
<context>
- <name>SketchConstraintFillet:ConstraintEntityA:SketchPlugin_FilletVertexValidator</name>
+ <name>SketchFillet:ConstraintEntityA:SketchPlugin_FilletVertexValidator</name>
<message>
<source>Error: Edges in selected point has tangent constraint.</source>
<translation>Edges in selected point has tangent constraint</translation>
</message>
</context>
<context>
- <name>SketchConstraintFillet:ConstraintEntityA:SketchPlugin_FilletVertexValidator</name>
+ <name>SketchFillet:ConstraintEntityA:SketchPlugin_FilletVertexValidator</name>
<message>
<source>Error: Edges in selected point has tangent constraint.</source>
<translation>Edges in selected point has tangent constraint</translation>
SketchConstraintParallel SketchConstraintPerpendicular
SketchConstraintRigid SketchConstraintHorizontal SketchConstraintVertical
SketchConstraintEqual SketchConstraintTangent
- SketchConstraintFillet SketchConstraintSplit SketchTrim
+ SketchFillet SketchConstraintSplit SketchTrim
SketchConstraintCoincidence
SketchConstraintMirror SketchConstraintAngle
SketchMultiRotation SketchMultiTranslation
</feature>
<!-- SketchConstraintFillet -->
- <feature id="SketchConstraintFillet" title="Fillet" tooltip="Create constraint defining fillet between two objects" icon="icons/Sketch/fillet.png">
- <!--<sketch_shape_selector id="ConstraintEntityA"
- label="Point" tooltip="Select point for fillet (should be shared by two entities only)" shape_types="vertex">
+ <feature id="SketchFillet"
+ title="Fillet"
+ tooltip="Create constraint defining fillet between two objects"
+ icon="icons/Sketch/fillet.png">
+ <sketch_shape_selector id="fillet_point"
+ label="Point"
+ tooltip="Select point for fillet (should be shared by two entities only)"
+ shape_types="vertex">
<validator id="SketchPlugin_FilletVertexValidator"/>
- </sketch_shape_selector>-->
- <sketch_multi_selector id="ConstraintEntityA"
- label="Points:"
- tooltip="Select points for fillets"
- type_choice="Vertices"
- greed = "true"
- clear_in_neutral_point="false">
- <validator id="SketchPlugin_FilletVertexValidator"/>
- </sketch_multi_selector>
- <labelvalue label="Radius" tooltip="Fillet arc radius" id="ConstraintValue" accept_expressions="0" min="0" use_reset="false"
- enable_value="enable_by_preferences">
- <validator id="GeomValidators_Positive"/>
- </labelvalue>
- <validator id="PartSet_FilletSelection"/>
+ </sketch_shape_selector>
+ <!--<validator id="PartSet_FilletSelection"/>-->
</feature>
<!-- SketchConstraintSplit -->
<feature id="SketchConstraintSplit" title="Split"