From: azv Date: Fri, 6 Dec 2019 12:23:41 +0000 (+0300) Subject: Task 5.1.3 Sketcher: angle dimension (issue #3061) X-Git-Tag: V9_5_0a1~119 X-Git-Url: http://git.salome-platform.org/gitweb/?a=commitdiff_plain;h=190904ad404bab6bd70b2c86ac1ea12f94abec21;p=modules%2Fshaper.git Task 5.1.3 Sketcher: angle dimension (issue #3061) Rework Angle constraint to avoid dependency of the order of selected edges, but implement the dependency of the selected points on the lines. --- diff --git a/src/FeaturesPlugin/Test/TestMeasurementAngle3Points.py b/src/FeaturesPlugin/Test/TestMeasurementAngle3Points.py index 399717906..5fa0b85fb 100644 --- a/src/FeaturesPlugin/Test/TestMeasurementAngle3Points.py +++ b/src/FeaturesPlugin/Test/TestMeasurementAngle3Points.py @@ -45,9 +45,9 @@ SketchConstraintEqual_2 = Sketch_1.setEqual(SketchLine_3.result(), SketchLine_1. SketchConstraintEqual_3 = Sketch_1.setEqual(SketchLine_4.result(), SketchLine_1.result()) SketchConstraintEqual_4 = Sketch_1.setEqual(SketchLine_5.result(), SketchLine_1.result()) SketchConstraintEqual_5 = Sketch_1.setEqual(SketchLine_6.result(), SketchLine_1.result()) -SketchConstraintAngle_1 = Sketch_1.setAngleBackward(SketchLine_1.result(), SketchLine_2.result(), 120) +SketchConstraintAngle_1 = Sketch_1.setAngle(SketchLine_1.result(), SketchLine_2.result(), 120) SketchConstraintAngle_2 = Sketch_1.setAngle(SketchLine_3.result(), SketchLine_2.result(), 120) -SketchConstraintAngle_3 = Sketch_1.setAngleBackward(SketchLine_3.result(), SketchLine_4.result(), 120) +SketchConstraintAngle_3 = Sketch_1.setAngle(SketchLine_3.result(), SketchLine_4.result(), 120) SketchConstraintHorizontal_1 = Sketch_1.setHorizontal(SketchLine_2.result()) SketchConstraintLength_1 = Sketch_1.setLength(SketchLine_5.result(), 60) SketchProjection_1 = Sketch_1.addProjection(model.selection("VERTEX", "PartSet/Origin"), False) diff --git a/src/GeomAPI/GeomAPI_Angle2d.cpp b/src/GeomAPI/GeomAPI_Angle2d.cpp index bb093cb0c..f3ef3d9ae 100644 --- a/src/GeomAPI/GeomAPI_Angle2d.cpp +++ b/src/GeomAPI/GeomAPI_Angle2d.cpp @@ -144,9 +144,7 @@ double GeomAPI_Angle2d::angleRadian() ThreePoints2d* anAngle = MY_ANGLE; gp_Dir2d aDir1(anAngle->myFirst.XY() - anAngle->myCenter.XY()); gp_Dir2d aDir2(anAngle->mySecond.XY() - anAngle->myCenter.XY()); - double aRes = aDir1.Angle(aDir2); - if (aRes < 0.0) aRes += 2 * PI; - return aRes; + return aDir1.Angle(aDir2); } bool GeomAPI_Angle2d::isReversed(int theIndex) diff --git a/src/PartSet/PartSet_WidgetFeaturePointSelector.cpp b/src/PartSet/PartSet_WidgetFeaturePointSelector.cpp index f44ca0209..7b5aff07d 100644 --- a/src/PartSet/PartSet_WidgetFeaturePointSelector.cpp +++ b/src/PartSet/PartSet_WidgetFeaturePointSelector.cpp @@ -30,6 +30,7 @@ #include #include +#include #include #include #include @@ -66,10 +67,14 @@ PartSet_WidgetFeaturePointSelector::PartSet_WidgetFeaturePointSelector(QWidget* std::string anAttributes = theData->getProperty("selection_attributes"); QStringList anAttributesList = QString(anAttributes.c_str()).split(' ', QString::SkipEmptyParts); + myHasPreview = anAttributesList.size() >= 4; + mySelectedObjectAttribute = anAttributesList[0].toStdString(); mySelectedPointAttribute = anAttributesList[1].toStdString(); - myPreviewObjectAttribute = anAttributesList[2].toStdString(); - myPreviewPointAttribute = anAttributesList[3].toStdString(); + if (myHasPreview) { + myPreviewObjectAttribute = anAttributesList[2].toStdString(); + myPreviewPointAttribute = anAttributesList[3].toStdString(); + } } PartSet_WidgetFeaturePointSelector::~PartSet_WidgetFeaturePointSelector() @@ -150,27 +155,42 @@ void PartSet_WidgetFeaturePointSelector::mouseReleased(ModuleBase_IViewWindow* t if (theEvent->button() != Qt::LeftButton) return; - std::shared_ptr aRefPreviewAttr = - std::dynamic_pointer_cast( - feature()->data()->attribute(myPreviewObjectAttribute)); - ObjectPtr aPreviewObject = aRefPreviewAttr->value(); + ObjectPtr aPreviewObject; + GeomPnt2dPtr aPreviewPoint; + if (myHasPreview) { + std::shared_ptr aRefPreviewAttr = + std::dynamic_pointer_cast( + feature()->data()->attribute(myPreviewObjectAttribute)); + aPreviewObject = aRefPreviewAttr->value(); + + std::shared_ptr aPointPreviewAttr = + std::dynamic_pointer_cast( + feature()->data()->attribute(myPreviewPointAttribute)); + aPreviewPoint = aPointPreviewAttr->pnt(); + } + else { + aPreviewObject = myPreviewObject; + aPreviewPoint = myPreviewPoint; + } + // do not move focus from the current widget if the object is not highlighted/selected if (!aPreviewObject.get()) return; // set parameters of preview into parameters of selection in the feature - std::shared_ptr aRefSelectedAttr = - std::dynamic_pointer_cast( - feature()->data()->attribute(mySelectedObjectAttribute)); - aRefSelectedAttr->setValue(aRefPreviewAttr->value()); - std::shared_ptr aPointSelectedAttr = std::dynamic_pointer_cast( feature()->data()->attribute(mySelectedPointAttribute)); - std::shared_ptr aPointPreviewAttr = - std::dynamic_pointer_cast( - feature()->data()->attribute(myPreviewPointAttribute)); - aPointSelectedAttr->setValue(aPointPreviewAttr->x(), aPointPreviewAttr->y()); + aPointSelectedAttr->setValue(aPreviewPoint); + + AttributeReferencePtr aRefSelectedAttr = feature()->reference(mySelectedObjectAttribute); + if (aRefSelectedAttr) + aRefSelectedAttr->setValue(aPreviewObject); + else { + AttributeRefAttrPtr aRefAttrSelectedAttr = feature()->refattr(mySelectedObjectAttribute); + if (aRefAttrSelectedAttr) + aRefAttrSelectedAttr->setObject(aPreviewObject); + } updateObject(feature()); @@ -189,20 +209,21 @@ bool PartSet_WidgetFeaturePointSelector::fillFeature( QMouseEvent* theEvent) { bool aFilled = false; - ObjectPtr anObject; if (theSelectedPrs.get() && theSelectedPrs->object().get()) - anObject = theSelectedPrs->object(); - - std::shared_ptr aRef = - std::dynamic_pointer_cast( - feature()->data()->attribute(myPreviewObjectAttribute)); - aRef->setValue(anObject); - - std::shared_ptr anAttributePoint = - std::dynamic_pointer_cast( - feature()->data()->attribute(myPreviewPointAttribute)); - std::shared_ptr aPoint = PartSet_Tools::getPnt2d(theEvent, theWindow, mySketch); - anAttributePoint->setValue(aPoint); + myPreviewObject = theSelectedPrs->object(); + myPreviewPoint = PartSet_Tools::getPnt2d(theEvent, theWindow, mySketch); + + if (myHasPreview) { + std::shared_ptr aRef = + std::dynamic_pointer_cast( + feature()->data()->attribute(myPreviewObjectAttribute)); + aRef->setValue(myPreviewObject); + + std::shared_ptr anAttributePoint = + std::dynamic_pointer_cast( + feature()->data()->attribute(myPreviewPointAttribute)); + anAttributePoint->setValue(myPreviewPoint); + } // redisplay AIS presentation in viewer #ifndef HIGHLIGHT_STAYS_PROBLEM // an attempt to clear highlighted item in the viewer: but of OCCT diff --git a/src/PartSet/PartSet_WidgetFeaturePointSelector.h b/src/PartSet/PartSet_WidgetFeaturePointSelector.h index 818253f4e..972b30ede 100644 --- a/src/PartSet/PartSet_WidgetFeaturePointSelector.h +++ b/src/PartSet/PartSet_WidgetFeaturePointSelector.h @@ -38,6 +38,7 @@ class ModuleBase_IViewWindow; class ModuleBase_ViewerPrs; class GeomAPI_Pnt; +class GeomAPI_Pnt2d; class GeomDataAPI_Point2D; class QWidget; @@ -132,6 +133,10 @@ protected: std::string mySelectedPointAttribute; std::string myPreviewObjectAttribute; std::string myPreviewPointAttribute; + + bool myHasPreview; + std::shared_ptr myPreviewObject; + std::shared_ptr myPreviewPoint; }; #endif \ No newline at end of file diff --git a/src/SketchPlugin/SketchPlugin_ConstraintAngle.cpp b/src/SketchPlugin/SketchPlugin_ConstraintAngle.cpp index 137acd0cd..bf2f211d9 100644 --- a/src/SketchPlugin/SketchPlugin_ConstraintAngle.cpp +++ b/src/SketchPlugin/SketchPlugin_ConstraintAngle.cpp @@ -38,7 +38,9 @@ #include #include -#include +#include +#include +#include const double tolerance = 1.e-7; #define PI 3.1415926535897932 @@ -54,24 +56,34 @@ SketchPlugin_ConstraintAngle::SketchPlugin_ConstraintAngle() void SketchPlugin_ConstraintAngle::initAttributes() { + ModelAPI_ValidatorsFactory* aValidators = ModelAPI_Session::get()->validators(); + data()->addAttribute(SketchPlugin_Constraint::VALUE(), ModelAPI_AttributeDouble::typeId()); data()->addAttribute(SketchPlugin_Constraint::ENTITY_A(), ModelAPI_AttributeRefAttr::typeId()); data()->addAttribute(SketchPlugin_Constraint::ENTITY_B(), ModelAPI_AttributeRefAttr::typeId()); data()->addAttribute(SketchPlugin_Constraint::FLYOUT_VALUE_PNT(), GeomDataAPI_Point2D::typeId()); - data()->addAttribute(SketchPlugin_ConstraintAngle::ANGLE_VALUE_ID(), - ModelAPI_AttributeDouble::typeId()); - data()->addAttribute(SketchPlugin_ConstraintAngle::TYPE_ID(), - ModelAPI_AttributeInteger::typeId()); + data()->addAttribute(ANGLE_VALUE_ID(), ModelAPI_AttributeDouble::typeId()); + data()->addAttribute(TYPE_ID(), ModelAPI_AttributeInteger::typeId()); + + data()->addAttribute(ANGLE_REVERSED_FIRST_LINE_ID(), ModelAPI_AttributeBoolean::typeId()); + data()->addAttribute(ANGLE_REVERSED_SECOND_LINE_ID(), ModelAPI_AttributeBoolean::typeId()); + + data()->addAttribute(LOCATION_TYPE_ID(), ModelAPI_AttributeInteger::typeId()); + aValidators->registerNotObligatory(getKind(), LOCATION_TYPE_ID()); + + data()->addAttribute(SELECTED_FIRST_POINT_ID(), GeomDataAPI_Point2D::typeId()); + data()->attribute(SELECTED_FIRST_POINT_ID())->setIsArgument(false); + aValidators->registerNotObligatory(getKind(), SELECTED_FIRST_POINT_ID()); - data()->addAttribute(SketchPlugin_ConstraintAngle::ANGLE_REVERSED_FIRST_LINE_ID(), - ModelAPI_AttributeBoolean::typeId()); - data()->addAttribute(SketchPlugin_ConstraintAngle::ANGLE_REVERSED_SECOND_LINE_ID(), - ModelAPI_AttributeBoolean::typeId()); + data()->addAttribute(SELECTED_SECOND_POINT_ID(), GeomDataAPI_Point2D::typeId()); + data()->attribute(SELECTED_SECOND_POINT_ID())->setIsArgument(false); + aValidators->registerNotObligatory(getKind(), SELECTED_SECOND_POINT_ID()); - data()->addAttribute(SketchPlugin_ConstraintAngle::LOCATION_TYPE_ID(), - ModelAPI_AttributeInteger::typeId()); - ModelAPI_Session::get()->validators()->registerNotObligatory(getKind(), LOCATION_TYPE_ID()); + if (attribute(TYPE_ID())->isInitialized()) + myPrevAngleType = integer(TYPE_ID())->value(); + else + myPrevAngleType = (int)SketcherPrs_Tools::ANGLE_DIRECT; } void SketchPlugin_ConstraintAngle::colorConfigInfo(std::string& theSection, std::string& theName, @@ -86,21 +98,15 @@ void SketchPlugin_ConstraintAngle::execute() { std::shared_ptr aData = data(); - std::shared_ptr anAttrA = - aData->refattr(SketchPlugin_Constraint::ENTITY_A()); - std::shared_ptr anAttrB = - aData->refattr(SketchPlugin_Constraint::ENTITY_B()); + AttributeRefAttrPtr anAttrA = aData->refattr(SketchPlugin_Constraint::ENTITY_A()); + AttributeRefAttrPtr anAttrB = aData->refattr(SketchPlugin_Constraint::ENTITY_B()); if (!anAttrA->isInitialized() || !anAttrB->isInitialized()) return; - AttributeDoublePtr anAttrValue = std::dynamic_pointer_cast( - aData->attribute(SketchPlugin_ConstraintAngle::ANGLE_VALUE_ID())); + AttributeDoublePtr anAttrValue = real(ANGLE_VALUE_ID()); + if (!anAttrValue->isInitialized()) + calculateAngle(); - if (!anAttrValue->isInitialized()) { - double anAngle = calculateAngle(); - anAttrValue->setValue(anAngle); - updateConstraintValueByAngleValue(); - } // the value should to be computed here, not in the // getAISObject in order to change the model value // inside the object transaction. This is important for creating a constraint by preselection. @@ -128,37 +134,26 @@ void SketchPlugin_ConstraintAngle::attributeChanged(const std::string& theID) std::shared_ptr aData = data(); if (!aData) return; - FeaturePtr aLineA = SketcherPrs_Tools::getFeatureLine(aData, SketchPlugin_Constraint::ENTITY_A()); - FeaturePtr aLineB = SketcherPrs_Tools::getFeatureLine(aData, SketchPlugin_Constraint::ENTITY_B()); + + if (theID == TYPE_ID()) + updateAngleValue(); + + FeaturePtr aLineA = SketcherPrs_Tools::getFeatureLine(aData, ENTITY_A()); + FeaturePtr aLineB = SketcherPrs_Tools::getFeatureLine(aData, ENTITY_B()); if (!aLineA || !aLineB) return; - if (theID == SketchPlugin_Constraint::ENTITY_A() || - theID == SketchPlugin_Constraint::ENTITY_B()) { - AttributeDoublePtr aValueAttr = real(SketchPlugin_ConstraintAngle::ANGLE_VALUE_ID()); - AttributeDoublePtr aConstrValueAttr = real(SketchPlugin_Constraint::VALUE()); - // only if one of attributes is not initialized, try to compute the current value - if (!aValueAttr->isInitialized() || !aConstrValueAttr->isInitialized()) { - if (aValueAttr->isInitialized() && !aConstrValueAttr->isInitialized()) - // initialize base value of constraint - updateConstraintValueByAngleValue(); - double anAngle = calculateAngle(); - aValueAttr->setValue(anAngle); - updateConstraintValueByAngleValue(); - } - } else if (theID == SketchPlugin_Constraint::FLYOUT_VALUE_PNT() && !myFlyoutUpdate) { + if (theID == ENTITY_A() || theID == ENTITY_B() || + theID == TYPE_ID() || theID == ANGLE_VALUE_ID()) { + calculateAngle(); + } else if (theID == FLYOUT_VALUE_PNT() && !myFlyoutUpdate) { // Recalculate flyout point in local coordinates // coordinates are calculated according to the center of shapes intersection std::shared_ptr aFlyoutAttr = - std::dynamic_pointer_cast( - attribute(SketchPlugin_Constraint::FLYOUT_VALUE_PNT())); + std::dynamic_pointer_cast(attribute(FLYOUT_VALUE_PNT())); std::shared_ptr aData = data(); std::shared_ptr aPlane = SketchPlugin_Sketch::plane(sketch()); - FeaturePtr aLineA = - SketcherPrs_Tools::getFeatureLine(aData, SketchPlugin_Constraint::ENTITY_A()); - FeaturePtr aLineB = - SketcherPrs_Tools::getFeatureLine(aData, SketchPlugin_Constraint::ENTITY_B()); // Intersection of lines std::shared_ptr anInter = intersect(aLineA, aLineB); @@ -171,111 +166,167 @@ void SketchPlugin_ConstraintAngle::attributeChanged(const std::string& theID) aFlyoutAttr->setValue(aFlyoutAttr->x() + tolerance, aFlyoutAttr->y()); myFlyoutUpdate = false; } - else if (theID == SketchPlugin_ConstraintAngle::TYPE_ID()) { - std::shared_ptr aValueAttr = std::dynamic_pointer_cast< - ModelAPI_AttributeDouble>(data()->attribute(SketchPlugin_ConstraintAngle::ANGLE_VALUE_ID())); - double anAngle = calculateAngle(); - if (aValueAttr->text().empty()) - aValueAttr->setValue(anAngle); - else { - aValueAttr = std::dynamic_pointer_cast< - ModelAPI_AttributeDouble>(data()->attribute(SketchPlugin_ConstraintAngle::VALUE())); - aValueAttr->setValue(anAngle); - } - } - else if (theID == SketchPlugin_ConstraintAngle::ANGLE_VALUE_ID()) { - updateConstraintValueByAngleValue(); - } } -double SketchPlugin_ConstraintAngle::calculateAngle() +void SketchPlugin_ConstraintAngle::calculateAngle() { + // update *_REVERSED_* flags + calculateAnglePosition(); + std::shared_ptr aData = data(); std::shared_ptr aPlane = SketchPlugin_Sketch::plane(sketch()); - FeaturePtr aLineA = SketcherPrs_Tools::getFeatureLine(aData, SketchPlugin_Constraint::ENTITY_A()); - FeaturePtr aLineB = SketcherPrs_Tools::getFeatureLine(aData, SketchPlugin_Constraint::ENTITY_B()); + FeaturePtr aLineA = SketcherPrs_Tools::getFeatureLine(aData, ENTITY_A()); + FeaturePtr aLineB = SketcherPrs_Tools::getFeatureLine(aData, ENTITY_B()); - std::shared_ptr aStartA = std::dynamic_pointer_cast( - aLineA->attribute(SketchPlugin_Line::START_ID())); - std::shared_ptr aEndA = std::dynamic_pointer_cast( - aLineA->attribute(SketchPlugin_Line::END_ID())); - std::shared_ptr aStartB = std::dynamic_pointer_cast( - aLineB->attribute(SketchPlugin_Line::START_ID())); - std::shared_ptr aEndB = std::dynamic_pointer_cast( - aLineB->attribute(SketchPlugin_Line::END_ID())); - - std::shared_ptr anAng; - if (!attribute(ANGLE_REVERSED_FIRST_LINE_ID())->isInitialized() || - !attribute(ANGLE_REVERSED_SECOND_LINE_ID())->isInitialized()) - anAng = std::shared_ptr(new GeomAPI_Angle2d( - aStartA->pnt(), aEndA->pnt(), aStartB->pnt(), aEndB->pnt())); - else { - std::shared_ptr aLine1(new GeomAPI_Lin2d(aStartA->pnt(), aEndA->pnt())); - bool isReversed1 = boolean(ANGLE_REVERSED_FIRST_LINE_ID())->value(); - std::shared_ptr aLine2(new GeomAPI_Lin2d(aStartB->pnt(), aEndB->pnt())); - bool isReversed2 = boolean(ANGLE_REVERSED_SECOND_LINE_ID())->value(); - anAng = std::shared_ptr( + GeomPnt2dPtr aStartA = SketcherPrs_Tools::getPoint(aLineA.get(), SketchPlugin_Line::START_ID()); + GeomPnt2dPtr aEndA = SketcherPrs_Tools::getPoint(aLineA.get(), SketchPlugin_Line::END_ID()); + GeomPnt2dPtr aStartB = SketcherPrs_Tools::getPoint(aLineB.get(), SketchPlugin_Line::START_ID()); + GeomPnt2dPtr aEndB = SketcherPrs_Tools::getPoint(aLineB.get(), SketchPlugin_Line::END_ID()); + + std::shared_ptr aLine1(new GeomAPI_Lin2d(aStartA, aEndA)); + std::shared_ptr aLine2(new GeomAPI_Lin2d(aStartB, aEndB)); + + bool isReversed1 = boolean(ANGLE_REVERSED_FIRST_LINE_ID())->value(); + bool isReversed2 = boolean(ANGLE_REVERSED_SECOND_LINE_ID())->value(); + + std::shared_ptr anAng( new GeomAPI_Angle2d(aLine1, isReversed1, aLine2, isReversed2)); - } double anAngle = anAng->angleDegree(); - std::shared_ptr aValueAttr = std::dynamic_pointer_cast< - ModelAPI_AttributeDouble>(data()->attribute(VALUE())); - std::shared_ptr anAngleValueAttr = std::dynamic_pointer_cast< - ModelAPI_AttributeDouble>(data()->attribute(ANGLE_VALUE_ID())); - if (!aValueAttr->isInitialized()) - aValueAttr->setValue(anAngle); - /// an angle value should be corrected by the current angle type - anAngle = getAngleForType(anAngleValueAttr->text().empty() ? - anAngle : anAngleValueAttr->value()); - boolean(ANGLE_REVERSED_FIRST_LINE_ID())->setValue(anAng->isReversed(0)); - boolean(ANGLE_REVERSED_SECOND_LINE_ID())->setValue(anAng->isReversed(1)); - return anAngle; + + AttributeDoublePtr anAngleValueAttr = real(ANGLE_VALUE_ID()); + if (!anAngleValueAttr->isInitialized()) + anAngleValueAttr->setValue(getAngleForType(fabs(anAngle))); + + anAngle /= fabs(anAngle); + anAngle *= getAngleForType(anAngleValueAttr->value()); + + // update value of the constraint to be passed to the solver + real(SketchPlugin_Constraint::VALUE())->setValue(anAngle); } -double SketchPlugin_ConstraintAngle::getAngleForType(double theAngle, bool isPreviousValueObtuse) +void SketchPlugin_ConstraintAngle::calculateAnglePosition() { - double anAngle = theAngle; + if (attribute(ANGLE_REVERSED_FIRST_LINE_ID())->isInitialized() && + attribute(ANGLE_REVERSED_SECOND_LINE_ID())->isInitialized()) + return; // already calculated - std::shared_ptr aData = data(); - std::shared_ptr aTypeAttr = std::dynamic_pointer_cast< - ModelAPI_AttributeInteger>(aData->attribute(SketchPlugin_ConstraintAngle::TYPE_ID())); - SketcherPrs_Tools::AngleType anAngleType = (SketcherPrs_Tools::AngleType)(aTypeAttr->value()); - switch (anAngleType) { + DataPtr aData = data(); + FeaturePtr aLineA = SketcherPrs_Tools::getFeatureLine(aData, ENTITY_A()); + FeaturePtr aLineB = SketcherPrs_Tools::getFeatureLine(aData, ENTITY_B()); + + GeomPnt2dPtr aStartA = SketcherPrs_Tools::getPoint(aLineA.get(), SketchPlugin_Line::START_ID()); + GeomPnt2dPtr aEndA = SketcherPrs_Tools::getPoint(aLineA.get(), SketchPlugin_Line::END_ID()); + GeomPnt2dPtr aStartB = SketcherPrs_Tools::getPoint(aLineB.get(), SketchPlugin_Line::START_ID()); + GeomPnt2dPtr aEndB = SketcherPrs_Tools::getPoint(aLineB.get(), SketchPlugin_Line::END_ID()); + + bool isReversed1 = false; + bool isReversed2 = false; + + GeomPnt2dPtr aSelected1 = SketcherPrs_Tools::getPoint(this, SELECTED_FIRST_POINT_ID()); + GeomPnt2dPtr aSelected2 = SketcherPrs_Tools::getPoint(this, SELECTED_SECOND_POINT_ID()); + if (aSelected1 && aSelected2) { + GeomPnt2dPtr anInterPnt = intersect(aLineA, aLineB); + if (!anInterPnt) + return; + std::shared_ptr anInterXY = anInterPnt->xy(); + isReversed1 = aSelected1->xy()->decreased(anInterXY)->dot( + aEndA->xy()->decreased(aStartA->xy())) < -tolerance; + isReversed2 = aSelected2->xy()->decreased(anInterXY)->dot( + aEndB->xy()->decreased(aStartB->xy())) < -tolerance; + } + else { + // no point is selected (document opened or Python script is loaded), + // calculate basing on the value + std::shared_ptr anAng(new GeomAPI_Angle2d(aStartA, aEndA, aStartB, aEndB)); + isReversed1 = anAng->isReversed(0); + isReversed2 = anAng->isReversed(1); + } + + // adjust reversed flags according to the angle type + AttributeIntegerPtr aTypeAttr = integer(TYPE_ID()); + if (aTypeAttr && aTypeAttr->isInitialized() && + (SketcherPrs_Tools::AngleType)(aTypeAttr->value()) == SketcherPrs_Tools::ANGLE_COMPLEMENTARY) + isReversed1 = !isReversed1; + + boolean(ANGLE_REVERSED_FIRST_LINE_ID())->setValue(isReversed1); + boolean(ANGLE_REVERSED_SECOND_LINE_ID())->setValue(isReversed2); +} + +static double angleForType(const double theAngle, const int theType) +{ + double anAngle = theAngle; + switch ((SketcherPrs_Tools::AngleType)theType) { case SketcherPrs_Tools::ANGLE_DIRECT: anAngle = theAngle; - break; - case SketcherPrs_Tools::ANGLE_COMPLEMENTARY: { - if (theAngle > 180 || isPreviousValueObtuse) - anAngle = theAngle - 180.0; - else - anAngle = 180.0 - theAngle; - - if (anAngle < 0.0) - anAngle += 360.0; - } - break; + break; + case SketcherPrs_Tools::ANGLE_COMPLEMENTARY: + anAngle = 180.0 - theAngle; + break; case SketcherPrs_Tools::ANGLE_BACKWARD: anAngle = 360.0 - theAngle; - break; + break; default: break; } return anAngle; } -void SketchPlugin_ConstraintAngle::updateConstraintValueByAngleValue() +double SketchPlugin_ConstraintAngle::getAngleForType(double theAngle) { - std::shared_ptr aValueAttr = std::dynamic_pointer_cast< - ModelAPI_AttributeDouble>(data()->attribute(SketchPlugin_ConstraintAngle::ANGLE_VALUE_ID())); - double anAngle = aValueAttr->value(); - - /// an angle value should be corrected by the current angle type - aValueAttr = std::dynamic_pointer_cast< - ModelAPI_AttributeDouble>(data()->attribute(SketchPlugin_Constraint::VALUE())); - if (!aValueAttr->isInitialized()) - calculateAngle(); - anAngle = getAngleForType(anAngle, aValueAttr->value() > 180.0); - aValueAttr->setValue(anAngle); + return angleForType(theAngle, integer(TYPE_ID())->value()); +} + +void SketchPlugin_ConstraintAngle::updateAngleValue() +{ + AttributeIntegerPtr anAngleType = integer(TYPE_ID()); + AttributeDoublePtr anAngleValueAttr = real(ANGLE_VALUE_ID()); + if (anAngleValueAttr->isInitialized()) { + if (anAngleValueAttr->text().empty()) { + // calculate value related to the type twice: + // the first time - to return to direct angle, + // the second time - to apply new type + double aValue = angleForType(anAngleValueAttr->value(), myPrevAngleType); + aValue = angleForType(aValue, anAngleType->value()); + anAngleValueAttr->setValue(aValue); + } + else { + // process the parametric value + std::string anAngleText = anAngleValueAttr->text(); + std::regex anAngleRegex("\\s*([-+]?[0-9]*\\.?[0-9]*)\\s*([-+])\\s*\\((.*)\\)", + std::regex_constants::ECMAScript); + + double anAnglePrefix = 0.0; + static const char aSignPrefix[2] = { '-', '+' }; + int aSignInd = 1; + + std::smatch aResult; + if (std::regex_search(anAngleText, aResult, anAngleRegex)) { + anAnglePrefix = std::atof(aResult[1].str().c_str()); + aSignInd = aResult[2].str()[0] == aSignPrefix[0] ? 0 : 1; + anAngleText = aResult[3].str(); + } + + if (myPrevAngleType != SketcherPrs_Tools::ANGLE_DIRECT) + aSignInd = 1 - aSignInd; + anAnglePrefix = angleForType(anAnglePrefix, myPrevAngleType); + + if (anAngleType->value() != SketcherPrs_Tools::ANGLE_DIRECT) + aSignInd = 1 - aSignInd; + anAnglePrefix = angleForType(anAnglePrefix, anAngleType->value()); + + std::ostringstream aText; + bool isPrintSign = true; + if (fabs(anAnglePrefix) > tolerance) + aText << anAnglePrefix; + else + isPrintSign = aSignInd == 0; + if (isPrintSign) + aText << " " << aSignPrefix[aSignInd] << " ("; + aText << anAngleText << (isPrintSign ? ")" : ""); + anAngleValueAttr->setText(aText.str()); + } + } + myPrevAngleType = anAngleType->value(); } bool SketchPlugin_ConstraintAngle::compute(const std::string& theAttributeId) @@ -300,23 +351,13 @@ bool SketchPlugin_ConstraintAngle::compute(const std::string& theAttributeId) return false; // Start and end points of lines - std::shared_ptr aPointA1 = std::dynamic_pointer_cast( - aLineA->attribute(SketchPlugin_Line::START_ID())); - std::shared_ptr aPointA2 = std::dynamic_pointer_cast( - aLineA->attribute(SketchPlugin_Line::END_ID())); - - std::shared_ptr aStartA = aPointA1->pnt(); - std::shared_ptr aEndA = aPointA2->pnt(); + GeomPnt2dPtr aStartA = SketcherPrs_Tools::getPoint(aLineA.get(), SketchPlugin_Line::START_ID()); + GeomPnt2dPtr aEndA = SketcherPrs_Tools::getPoint(aLineA.get(), SketchPlugin_Line::END_ID()); if (aStartA->distance(aEndA) < tolerance) return false; - std::shared_ptr aPointB1 = std::dynamic_pointer_cast( - aLineB->attribute(SketchPlugin_Line::START_ID())); - std::shared_ptr aPointB2 = std::dynamic_pointer_cast( - aLineB->attribute(SketchPlugin_Line::END_ID())); - - std::shared_ptr aStartB = aPointB1->pnt(); - std::shared_ptr aEndB = aPointB2->pnt(); + GeomPnt2dPtr aStartB = SketcherPrs_Tools::getPoint(aLineB.get(), SketchPlugin_Line::START_ID()); + GeomPnt2dPtr aEndB = SketcherPrs_Tools::getPoint(aLineB.get(), SketchPlugin_Line::END_ID()); if (aStartB->distance(aEndB) < tolerance) return false; @@ -335,20 +376,12 @@ bool SketchPlugin_ConstraintAngle::compute(const std::string& theAttributeId) std::shared_ptr intersect(FeaturePtr theLine1, FeaturePtr theLine2) { // Start and end points of lines - std::shared_ptr aPointA1 = std::dynamic_pointer_cast( - theLine1->attribute(SketchPlugin_Line::START_ID())); - std::shared_ptr aPointA2 = std::dynamic_pointer_cast( - theLine1->attribute(SketchPlugin_Line::END_ID())); - - std::shared_ptr aPointB1 = std::dynamic_pointer_cast( - theLine2->attribute(SketchPlugin_Line::START_ID())); - std::shared_ptr aPointB2 = std::dynamic_pointer_cast( - theLine2->attribute(SketchPlugin_Line::END_ID())); - - std::shared_ptr aStartA = aPointA1->pnt(); - std::shared_ptr aEndA = aPointA2->pnt(); - std::shared_ptr aStartB = aPointB1->pnt(); - std::shared_ptr aEndB = aPointB2->pnt(); + const std::string& aLineStartAttr = SketchPlugin_Line::START_ID(); + const std::string& aLineEndAttr = SketchPlugin_Line::END_ID(); + GeomPnt2dPtr aStartA = SketcherPrs_Tools::getPoint(theLine1.get(), aLineStartAttr); + GeomPnt2dPtr aEndA = SketcherPrs_Tools::getPoint(theLine1.get(), aLineEndAttr); + GeomPnt2dPtr aStartB = SketcherPrs_Tools::getPoint(theLine2.get(), aLineStartAttr); + GeomPnt2dPtr aEndB = SketcherPrs_Tools::getPoint(theLine2.get(), aLineEndAttr); if (aStartA->distance(aEndA) < tolerance || aStartB->distance(aEndB) < tolerance) std::shared_ptr(); diff --git a/src/SketchPlugin/SketchPlugin_ConstraintAngle.h b/src/SketchPlugin/SketchPlugin_ConstraintAngle.h index 39caab384..3983acff6 100644 --- a/src/SketchPlugin/SketchPlugin_ConstraintAngle.h +++ b/src/SketchPlugin/SketchPlugin_ConstraintAngle.h @@ -81,6 +81,19 @@ class SketchPlugin_ConstraintAngle : public SketchPlugin_ConstraintBase return MY_LOCATION_TYPE_ID; } + /// attribute name indicating the first point selected + inline static const std::string& SELECTED_FIRST_POINT_ID() + { + static const std::string MY_SELECTED_FIRST_POINT_ID("SelectedPointA"); + return MY_SELECTED_FIRST_POINT_ID; + } + + /// attribute name indicating the second point selected + inline static const std::string& SELECTED_SECOND_POINT_ID() + { + static const std::string MY_SELECTED_SECOND_POINT_ID("SelectedPointB"); + return MY_SELECTED_SECOND_POINT_ID; + } /// \brief Creates a new part document if needed SKETCHPLUGIN_EXPORT virtual void execute(); @@ -104,24 +117,28 @@ class SketchPlugin_ConstraintAngle : public SketchPlugin_ConstraintBase /// Returns the AIS preview SKETCHPLUGIN_EXPORT virtual AISObjectPtr getAISObject(AISObjectPtr thePrevious); + /// \brief Use plugin manager for features creation + SketchPlugin_ConstraintAngle(); + +protected: /// Calculate current value of the angle - double calculateAngle(); + void calculateAngle(); + + /// Compute the position of the angle presentation (the quarter selected by the user) + void calculateAnglePosition(); /// Converts the angle value according to the current angle type and sketch plane normal. /// The in/out angle is in degree. /// \param theAngle a source for the calculated angle - /// \param isPreviousValueObtuse a flag if obtuse should be processed /// \param a double angle value - double getAngleForType(double theAngle, bool isPreviousValueObtuse = false); + double getAngleForType(double theAngle); - /// Update value of VALUE attribute by the combination of the current angle type and angle value - void updateConstraintValueByAngleValue(); - - /// \brief Use plugin manager for features creation - SketchPlugin_ConstraintAngle(); + /// Update value of ANGLE_VALUE attribute according to the current type + void updateAngleValue(); private: bool myFlyoutUpdate; ///< to avoid cyclic dependencies on automatic updates of flyout point + int myPrevAngleType; }; #endif diff --git a/src/SketchPlugin/plugin-Sketch.xml b/src/SketchPlugin/plugin-Sketch.xml index d2253d9ac..0c77223de 100644 --- a/src/SketchPlugin/plugin-Sketch.xml +++ b/src/SketchPlugin/plugin-Sketch.xml @@ -998,16 +998,28 @@ - + - - + + - + diff --git a/src/SketcherPrs/SketcherPrs_Angle.cpp b/src/SketcherPrs/SketcherPrs_Angle.cpp index f5bcf8e3d..1696fc7e1 100644 --- a/src/SketcherPrs/SketcherPrs_Angle.cpp +++ b/src/SketcherPrs/SketcherPrs_Angle.cpp @@ -145,15 +145,24 @@ bool SketcherPrs_Angle::readyToDisplay(ModelAPI_Feature* theConstraint, new GeomAPI_Angle2d(aLine1, isReversed1, aLine2, isReversed2)); } - gp_Pnt2d aFirstPoint = anAng->firstPoint()->impl(); + gp_Pnt2d aCenterPoint = anAng->center()->impl(); + gp_Pnt2d aFirstPoint, aSecondPoint; + if (anAng->angleRadian() > 0.0) { + aFirstPoint = anAng->firstPoint()->impl(); + aSecondPoint = anAng->secondPoint()->impl(); + } + else { + aFirstPoint = anAng->secondPoint()->impl(); + aSecondPoint = anAng->firstPoint()->impl(); + } + + std::shared_ptr aPoint = thePlane->to3D(aFirstPoint.X(), aFirstPoint.Y()); theFirstPoint = aPoint->impl(); - gp_Pnt2d aCenterPoint = anAng->center()->impl(); aPoint = thePlane->to3D(aCenterPoint.X(), aCenterPoint.Y()); theCenterPoint = aPoint->impl(); - gp_Pnt2d aSecondPoint = anAng->secondPoint()->impl(); aPoint = thePlane->to3D(aSecondPoint.X(), aSecondPoint.Y()); theSecondPoint = aPoint->impl(); @@ -167,6 +176,9 @@ void SketcherPrs_Angle::Compute(const Handle(PrsMgr_PresentationManager3d)& theP { if (!plane().get()) return; + + DataPtr aData = myConstraint->data(); + gp_Pnt aFirstPoint, aSecondPoint, aCenterPoint; bool aReadyToDisplay = readyToDisplay(myConstraint, plane(), aFirstPoint, aSecondPoint, aCenterPoint); @@ -175,7 +187,6 @@ void SketcherPrs_Angle::Compute(const Handle(PrsMgr_PresentationManager3d)& theP mySecondPoint = aSecondPoint; myCenterPoint = aCenterPoint; - DataPtr aData = myConstraint->data(); AttributeDoublePtr anAttributeValue = aData->real(SketchPlugin_ConstraintAngle::ANGLE_VALUE_ID()); myValue.init(anAttributeValue); @@ -188,7 +199,6 @@ void SketcherPrs_Angle::Compute(const Handle(PrsMgr_PresentationManager3d)& theP myFlyOutPoint = aFlyoutPnt->impl(); } - DataPtr aData = myConstraint->data(); std::shared_ptr aTypeAttr = std::dynamic_pointer_cast< ModelAPI_AttributeInteger>(aData->attribute(SketchPlugin_ConstraintAngle::TYPE_ID())); SketcherPrs_Tools::AngleType anAngleType = (SketcherPrs_Tools::AngleType)(aTypeAttr->value()); @@ -197,7 +207,7 @@ void SketcherPrs_Angle::Compute(const Handle(PrsMgr_PresentationManager3d)& theP switch (anAngleType) { case SketcherPrs_Tools::ANGLE_DIRECT: { #ifndef COMPILATION_CORRECTION - SetArrowsVisibility(AIS_TOAV_Second); + SetArrowsVisibility(AIS_TOAV_Both); #endif SetMeasuredGeometry(myFirstPoint, myCenterPoint, mySecondPoint); #ifndef COMPILATION_CORRECTION @@ -219,7 +229,7 @@ void SketcherPrs_Angle::Compute(const Handle(PrsMgr_PresentationManager3d)& theP break; case SketcherPrs_Tools::ANGLE_BACKWARD: { #ifndef COMPILATION_CORRECTION - SetArrowsVisibility(AIS_TOAV_Second); + SetArrowsVisibility(AIS_TOAV_Both); #endif SetMeasuredGeometry(myFirstPoint, myCenterPoint, mySecondPoint); bool isReversedPlanes = isAnglePlaneReversedToSketchPlane(); diff --git a/src/SketcherPrs/SketcherPrs_Tools.cpp b/src/SketcherPrs/SketcherPrs_Tools.cpp index 4e9522fd1..8b32e6944 100644 --- a/src/SketcherPrs/SketcherPrs_Tools.cpp +++ b/src/SketcherPrs/SketcherPrs_Tools.cpp @@ -94,8 +94,12 @@ std::shared_ptr getShape(ObjectPtr theObject) std::shared_ptr getPoint(ModelAPI_Feature* theFeature, const std::string& theAttribute) { - std::shared_ptr aPointAttr = ModelGeomAlgo_Point2D::getPointOfRefAttr( + std::shared_ptr aPointAttr = + std::dynamic_pointer_cast(theFeature->attribute(theAttribute)); + if (!aPointAttr.get() || !aPointAttr->isInitialized()) { + aPointAttr = ModelGeomAlgo_Point2D::getPointOfRefAttr( theFeature, theAttribute, SketchPlugin_Point::ID(), SketchPlugin_Point::COORD_ID()); + } if (aPointAttr.get() != NULL) return aPointAttr->pnt(); return std::shared_ptr();