#include "SketchPlugin_Line.h"
#include "SketchPlugin_Point.h"
#include "SketchPlugin_Sketch.h"
+#include "SketchPlugin_ConstraintDistance.h"
#include "SketchPlugin_ConstraintEqual.h"
#include "SketchPlugin_ConstraintCoincidence.h"
#include "SketchPlugin_ConstraintLength.h"
#include "SketchPlugin_ConstraintRadius.h"
#include "SketchPlugin_Tools.h"
+#include <ModelAPI_AttributeDouble.h>
+#include <ModelAPI_AttributeInteger.h>
#include <ModelAPI_AttributeRefAttr.h>
#include <ModelAPI_Data.h>
#include <ModelAPI_Events.h>
// create feature for fillet arc
FeaturePtr aFilletArc = createFilletArc();
- // 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);
- Events_Loop::loop()->flush(Events_Loop::eventByName(EVENT_OBJECT_DELETED));
+ // collect features referred to the edges participating in fillet
+ AttributePoint2DPtr aFilletPoints[2];
+ int aFeatInd[2];
+ int anAttrInd[2];
+ std::set<FeaturePtr> aFeaturesToBeRemoved;
+ for (int i = 0; i < 2; ++i) {
+ bool isFirstIndex = (i == 0);
+ aFeatInd[i] = myIsReversed == isFirstIndex ? 1 : 0;
+ anAttrInd[i] = (myIsReversed == isFirstIndex ? 2 : 0) + (myIsNotInversed[aFeatInd[i]] ? 0 : 1);
+ aFilletPoints[i] = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
+ myBaseFeatures[aFeatInd[i]]->attribute(myFeatAttributes[anAttrInd[i]]));
+ std::set<FeaturePtr> aRemove =
+ findFeaturesToRemove(myBaseFeatures[aFeatInd[i]], aFilletPoints[i]);
+ aFeaturesToBeRemoved.insert(aRemove.begin(), aRemove.end());
+ }
+
+ // keep "distance" constraints and remove all other references
+ removeReferencesButKeepDistances(aFeaturesToBeRemoved, aFilletPoints);
// Update fillet edges.
recalculateAttributes(aFilletArc, SketchPlugin_Arc::START_ID(),
- myBaseFeatures[aFeatInd1], myFeatAttributes[anAttrInd1]);
+ myBaseFeatures[aFeatInd[0]], myFeatAttributes[anAttrInd[0]]);
recalculateAttributes(aFilletArc, SketchPlugin_Arc::END_ID(),
- myBaseFeatures[aFeatInd2], myFeatAttributes[anAttrInd2]);
+ myBaseFeatures[aFeatInd[1]], myFeatAttributes[anAttrInd[1]]);
FeaturePtr aConstraint;
aConstraint = SketchPlugin_Tools::createConstraint(sketch(),
SketchPlugin_ConstraintCoincidence::ID(),
aFilletArc->attribute(SketchPlugin_Arc::START_ID()),
- myBaseFeatures[aFeatInd1]->attribute(myFeatAttributes[anAttrInd1]));
+ myBaseFeatures[aFeatInd[0]]->attribute(myFeatAttributes[anAttrInd[0]]));
ModelAPI_EventCreator::get()->sendUpdated(aConstraint, anUpdateEvent);
aConstraint = SketchPlugin_Tools::createConstraint(sketch(),
SketchPlugin_ConstraintCoincidence::ID(),
aFilletArc->attribute(SketchPlugin_Arc::END_ID()),
- myBaseFeatures[aFeatInd2]->attribute(myFeatAttributes[anAttrInd2]));
+ myBaseFeatures[aFeatInd[1]]->attribute(myFeatAttributes[anAttrInd[1]]));
ModelAPI_EventCreator::get()->sendUpdated(aConstraint, anUpdateEvent);
// Create tangent features.
}
// Send events to update the sub-features by the solver.
- if(isUpdateFlushed) {
+ if (isUpdateFlushed)
Events_Loop::loop()->setFlushed(anUpdateEvent, true);
- }
}
AISObjectPtr SketchPlugin_Fillet::getAISObject(AISObjectPtr thePrevious)
return aFilletArc;
}
+FeaturePtr SketchPlugin_Fillet::createFilletApex(const GeomPnt2dPtr& theCoordinates)
+{
+ FeaturePtr anApex = sketch()->addFeature(SketchPlugin_Point::ID());
+ AttributePoint2DPtr aCoord = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
+ anApex->attribute(SketchPlugin_Point::COORD_ID()));
+ aCoord->setValue(theCoordinates);
+
+ // additional coincidence constraints
+ static Events_ID anUpdateEvent = Events_Loop::eventByName(EVENT_OBJECT_UPDATED);
+ FeaturePtr aConstraint;
+ for (int i = 0; i < 2; i++) {
+ aConstraint = SketchPlugin_Tools::createConstraint(sketch(),
+ SketchPlugin_ConstraintCoincidence::ID(),
+ aCoord,
+ myBaseFeatures[i]->lastResult());
+ aConstraint->execute();
+ ModelAPI_EventCreator::get()->sendUpdated(aConstraint, anUpdateEvent);
+ }
+
+ return anApex;
+}
+
+void SketchPlugin_Fillet::removeReferencesButKeepDistances(
+ std::set<FeaturePtr>& theFeaturesToRemove,
+ const AttributePoint2DPtr theFilletPoints[2])
+{
+ FeaturePtr aFilletApex;
+ struct Length {
+ AttributePtr myPoints[2];
+ std::string myValueText;
+ double myValueDouble;
+ GeomPnt2dPtr myFlyoutPoint;
+ int myLocationType;
+ };
+ std::list<Length> aLengthToDistance;
+
+ std::set<FeaturePtr>::iterator aFeat = theFeaturesToRemove.begin();
+ while (aFeat != theFeaturesToRemove.end()) {
+ std::shared_ptr<SketchPlugin_ConstraintDistance> aDistance =
+ std::dynamic_pointer_cast<SketchPlugin_ConstraintDistance>(*aFeat);
+ if (aDistance) {
+ if (!aFilletApex)
+ aFilletApex = createFilletApex(theFilletPoints[0]->pnt());
+ // update attributes of distance constraints
+ bool isUpdated = false;
+ for (int attrInd = 0; attrInd < CONSTRAINT_ATTR_SIZE && !isUpdated; ++attrInd) {
+ AttributeRefAttrPtr aRefAttr =
+ aDistance->refattr(SketchPlugin_Constraint::ATTRIBUTE(attrInd));
+ if (aRefAttr && !aRefAttr->isObject() &&
+ (aRefAttr->attr() == theFilletPoints[0] || aRefAttr->attr() == theFilletPoints[1])) {
+ aRefAttr->setAttr(aFilletApex->attribute(SketchPlugin_Point::COORD_ID()));
+ isUpdated = true;
+ }
+ }
+ // avoid distance from removing if it is updated
+ std::set<FeaturePtr>::iterator aKeepIt = aFeat++;
+ if (isUpdated)
+ theFeaturesToRemove.erase(aKeepIt);
+
+ } else {
+ std::shared_ptr<SketchPlugin_ConstraintLength> aLength =
+ std::dynamic_pointer_cast<SketchPlugin_ConstraintLength>(*aFeat);
+ if (aLength) {
+ if (!aFilletApex)
+ aFilletApex = createFilletApex(theFilletPoints[0]->pnt());
+ // remove Length, but create new distance constraint
+ AttributeRefAttrPtr aRefAttr =
+ aLength->refattr(SketchPlugin_Constraint::ENTITY_A());
+ FeaturePtr aLine = ModelAPI_Feature::feature(aRefAttr->object());
+ if (aLine) {
+ aLengthToDistance.push_back(Length());
+ Length& aNewLength = aLengthToDistance.back();
+ // main attrbutes
+ for (int i = 0; i < 2; ++i) {
+ AttributePtr anAttr = aLine->attribute(
+ i == 0 ? SketchPlugin_Line::START_ID() : SketchPlugin_Line::END_ID());
+ if (anAttr == theFilletPoints[0] || anAttr == theFilletPoints[1])
+ aNewLength.myPoints[i] = aFilletApex->attribute(SketchPlugin_Point::COORD_ID());
+ else
+ aNewLength.myPoints[i] = anAttr;
+ }
+ // value
+ AttributeDoublePtr aValue = aLength->real(SketchPlugin_Constraint::VALUE());
+ aNewLength.myValueDouble = aValue->value();
+ aNewLength.myValueText = aValue->text();
+ // auxiliary attributes
+ AttributePoint2DPtr aFlyoutAttr = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
+ aLength->attribute(SketchPlugin_ConstraintLength::FLYOUT_VALUE_PNT()));
+ if (aFlyoutAttr && aFlyoutAttr->isInitialized())
+ aNewLength.myFlyoutPoint = aFlyoutAttr->pnt();
+ AttributeIntegerPtr aLocationAttr =
+ aLength->integer(SketchPlugin_ConstraintLength::LOCATION_TYPE_ID());
+ if (aLocationAttr && aLocationAttr->isInitialized())
+ aNewLength.myLocationType = aLocationAttr->value();
+ else
+ aNewLength.myLocationType = -1;
+ }
+ }
+
+ ++aFeat;
+ }
+ }
+
+ // remove references
+ ModelAPI_Tools::removeFeaturesAndReferences(theFeaturesToRemove);
+ Events_Loop::loop()->flush(Events_Loop::eventByName(EVENT_OBJECT_DELETED));
+
+ // restore Length constraints as point-point distances
+ FeaturePtr aConstraint;
+ std::list<Length>::iterator anIt = aLengthToDistance.begin();
+ for (; anIt != aLengthToDistance.end(); ++anIt) {
+ aConstraint = SketchPlugin_Tools::createConstraint(sketch(),
+ SketchPlugin_ConstraintDistance::ID(), anIt->myPoints[0], anIt->myPoints[1]);
+ // set value
+ AttributeDoublePtr aValue = aConstraint->real(SketchPlugin_Constraint::VALUE());
+ if (anIt->myValueText.empty())
+ aValue->setValue(anIt->myValueDouble);
+ else
+ aValue->setText(anIt->myValueText);
+ // set flyout point if exists
+ if (anIt->myFlyoutPoint) {
+ AttributePoint2DPtr aFlyoutAttr = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
+ aConstraint->attribute(SketchPlugin_ConstraintDistance::FLYOUT_VALUE_PNT()));
+ aFlyoutAttr->setValue(anIt->myFlyoutPoint);
+ }
+ // set location type if initialized
+ if (anIt->myLocationType >= 0) {
+ AttributeIntegerPtr aLocationType =
+ aConstraint->integer(SketchPlugin_ConstraintDistance::LOCATION_TYPE_ID());
+ aLocationType->setValue(anIt->myLocationType);
+ }
+ aConstraint->execute();
+ ModelAPI_EventCreator::get()->sendUpdated(aConstraint,
+ Events_Loop::eventByName(EVENT_OBJECT_UPDATED));
+ }
+}
+
// ========= Auxiliary functions =================
void recalculateAttributes(FeaturePtr theNewArc, const std::string& theNewArcAttribute,
FeaturePtr theFeature, const std::string& theFeatureAttribute)
from GeomAPI import *
from GeomDataAPI import *
from ModelAPI import *
+from SketchAPI import *
import math
import unittest
from salome.shaper import model
model.do()
self.checkDOF()
self.mySketch.setFillet(aSketchLineA.startPoint())
- self.myDOF += 2
+ self.myDOF += 1
model.do()
self.checkFillet()
self.checkDOF()
self.collectFeatures()
self.checkNbFeatures("SketchLine", 2)
self.checkNbFeatures("SketchArc", 1)
- self.checkNbFeatures("SketchConstraintCoincidence", 2)
+ self.checkNbFeatures("SketchConstraintCoincidence", 4) # Additionally 2 coincidences for apex with fillet objects
self.checkNbFeatures("SketchConstraintTangent", 2)
self.checkNbFeatures("SketchConstraintLength", 0) # Length constraint expected to be removed
+ self.checkNbFeatures("SketchConstraintDistance", 1) # Distance constraint should appear instead of Length
self.checkNbFeatures("SketchFillet", 0)
model.testNbSubShapes(self.mySketch, GeomAPI_Shape.FACE, [0])
def test_fillet_with_distance(self):
""" Test 12. Fillet on two connected lines in case of Distance constraint applied
"""
- aSketchLineA = self.mySketch.addLine(10., 10., 20., 10.)
- aSketchLineB = self.mySketch.addLine(10., 10., 10., 20.)
- self.myDOF += 8
+ aSketchLineA = self.mySketch.addLine(20, 20, 70, 20)
+ aSketchLineB = self.mySketch.addLine(70, 20, 70, 53.16624790355412)
+ aSketchLineC = self.mySketch.addLine(70, 53.16624790355412, 20, 20)
+ self.myDOF += 12
+ model.do()
self.checkDOF()
- self.mySketch.setCoincident(aSketchLineA.startPoint(), aSketchLineB.startPoint())
- self.myDOF -= 2
+ # coincidences
+ self.mySketch.setCoincident(aSketchLineA.endPoint(), aSketchLineB.startPoint())
+ self.mySketch.setCoincident(aSketchLineB.endPoint(), aSketchLineC.startPoint())
+ self.mySketch.setCoincident(aSketchLineA.startPoint(), aSketchLineC.endPoint())
+ self.myDOF -= 6
model.do()
self.checkDOF()
- # third line to apply Distance constraints
- aSketchLineC = self.mySketch.addLine(10., 0., 20., 5.)
- self.myDOF += 4
- self.mySketch.setDistance(aSketchLineB.startPoint(), aSketchLineC.result(), 10.)
- self.mySketch.setDistance(aSketchLineB.endPoint(), aSketchLineC.result(), 5.)
+ # other constraints
+ self.mySketch.setHorizontal(aSketchLineA.result())
+ self.mySketch.setVertical(aSketchLineB.result())
self.myDOF -= 2
model.do()
self.checkDOF()
+ # construction point
+ aProjection = self.mySketch.addProjection(model.selection("VERTEX", "Origin"), False)
+ aSketchPoint = SketchAPI_Point(aProjection.createdFeature())
+ model.do()
+ # distances
+ self.mySketch.setLength(aSketchLineA.result(), 50)
+ self.mySketch.setDistance(aSketchLineA.startPoint(), aSketchLineC.startPoint(), 60, True)
+ self.mySketch.setHorizontalDistance(aSketchPoint.coordinates(), aSketchLineA.startPoint(), 20)
+ self.mySketch.setVerticalDistance(aSketchPoint.coordinates(), aSketchLineC.endPoint(), 20)
+ self.myDOF -= 4
+ model.do()
+ self.checkDOF()
+
self.mySketch.setFillet(aSketchLineA.startPoint())
- self.myDOF += 2 # Distance has been removed
+ self.myDOF += 1
model.do()
self.checkFillet()
self.checkDOF()
self.collectFeatures()
self.checkNbFeatures("SketchLine", 3)
self.checkNbFeatures("SketchArc", 1)
- self.checkNbFeatures("SketchConstraintCoincidence", 2)
+ self.checkNbFeatures("SketchConstraintCoincidence", 6) # Additionally 2 coincidences for apex with fillet objects
+ self.checkNbFeatures("SketchConstraintHorizontal", 1)
+ self.checkNbFeatures("SketchConstraintVertical", 1)
self.checkNbFeatures("SketchConstraintTangent", 2)
- self.checkNbFeatures("SketchConstraintDistance", 1) # only one Distance should be left
+ self.checkNbFeatures("SketchConstraintLength", 0) # Length translated to Distance
+ self.checkNbFeatures("SketchConstraintDistance", 2) # Length translated to Distance
+ self.checkNbFeatures("SketchConstraintDistanceHorizontal", 1)
+ self.checkNbFeatures("SketchConstraintDistanceVertical", 1)
self.checkNbFeatures("SketchFillet", 0)
model.testNbSubShapes(self.mySketch, GeomAPI_Shape.FACE, [0])