X-Git-Url: http://git.salome-platform.org/gitweb/?a=blobdiff_plain;f=src%2FSketchSolver%2FSketchSolver_ConstraintDistance.cpp;h=590681a8681d3341f7e59d50c45541c01ce33c6e;hb=9afbc5fb015e5ff91689e1ef3f4da286347fbda5;hp=901053c6d7a90d70d09cefaad4169ce0efea0f39;hpb=a94fc319f2aa64b43c9a73b5ff7063923648faec;p=modules%2Fshaper.git diff --git a/src/SketchSolver/SketchSolver_ConstraintDistance.cpp b/src/SketchSolver/SketchSolver_ConstraintDistance.cpp index 901053c6d..590681a86 100644 --- a/src/SketchSolver/SketchSolver_ConstraintDistance.cpp +++ b/src/SketchSolver/SketchSolver_ConstraintDistance.cpp @@ -1,4 +1,4 @@ -// Copyright (C) 2014-2017 CEA/DEN, EDF R&D +// Copyright (C) 2014-2023 CEA, EDF // // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public @@ -12,16 +12,21 @@ // // You should have received a copy of the GNU Lesser General Public // License along with this library; if not, write to the Free Software -// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // -// See http://www.salome-platform.org/ or -// email : webmaster.salome@opencascade.com +// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com // #include #include #include +#include +#include +#include +#include +#include + #include #include @@ -33,6 +38,121 @@ #include +static void getPointAndLine(const ConstraintPtr& theConstraint, const StoragePtr& theStorage, + EntityWrapperPtr& thePoint, EntityWrapperPtr& theLine) +{ + for (int i = 0; i < 2; ++i) { + AttributePtr anAttr = theConstraint->attribute(SketchPlugin_Constraint::ATTRIBUTE(i)); + EntityWrapperPtr anEntity = theStorage->entity(anAttr); + if (anEntity->type() == ENTITY_POINT) + thePoint = anEntity; + else if (anEntity->type() == ENTITY_LINE) + theLine = anEntity; + } +} + +static void adjustOddPoint(const EntityWrapperPtr& theDistPoint, + const EntityWrapperPtr& theDistLine, + GCSPointPtr& theOddPoint) +{ + if (!theOddPoint) + return; + + std::shared_ptr aLine = PlaneGCSSolver_Tools::line(theDistLine); + std::shared_ptr aPoint = PlaneGCSSolver_Tools::point(theDistPoint); + + std::shared_ptr aLineVec = aLine->direction()->xy(); + std::shared_ptr aPtLineVec = aPoint->xy()->decreased(aLine->location()->xy()); + + double aDot = aPtLineVec->dot(aLineVec); + std::shared_ptr aProjectedPnt = + aLine->location()->xy()->added(aLineVec->multiplied(aDot)); + + *(theOddPoint->x) = aProjectedPnt->x(); + *(theOddPoint->y) = aProjectedPnt->y(); +} + +static FeaturePtr getFeature(AttributeRefAttrPtr theRefAttr) +{ + ObjectPtr anObj; + if (theRefAttr->isObject()) + anObj = theRefAttr->object(); + else + anObj = theRefAttr->attr()->owner(); + return ModelAPI_Feature::feature(anObj); +} + +static void calculateDistanceDirection(const ConstraintPtr& theConstraint, + const StoragePtr& theStorage, + double& theDirX, double& theDirY) +{ + std::shared_ptr aDistDir = std::dynamic_pointer_cast( + theConstraint->attribute(SketchPlugin_ConstraintDistance::DIRECTION_ID())); + if (aDistDir && aDistDir->isInitialized()) { + theDirX = aDistDir->x(); + theDirY = aDistDir->y(); + if (fabs(theDirX) > tolerance || fabs(theDirY) > tolerance) + return; + } + + AttributeRefAttrPtr aRefAttrA = theConstraint->refattr(SketchPlugin_Constraint::ENTITY_A()); + AttributeRefAttrPtr aRefAttrB = theConstraint->refattr(SketchPlugin_Constraint::ENTITY_B()); + + EntityWrapperPtr aEntityA = theStorage->entity(aRefAttrA); + EntityWrapperPtr aEntityB = theStorage->entity(aRefAttrB); + + GCSPointPtr aPoint; + if (aEntityA->type() != ENTITY_LINE && aEntityB->type() != ENTITY_LINE) { + aPoint = std::dynamic_pointer_cast(aEntityA)->point(); + theDirX = 1.0; + theDirY = 0.0; + + EdgeWrapperPtr anEdgeA = std::dynamic_pointer_cast( + theStorage->entity(getFeature(aRefAttrA))); + EdgeWrapperPtr anEdgeB = std::dynamic_pointer_cast( + theStorage->entity(getFeature(aRefAttrB))); + + if (anEdgeA && anEdgeB) { + GCS::DeriVector2 aDirA = anEdgeA->entity()->CalculateNormal(*aPoint); + GCS::DeriVector2 aDirB = anEdgeB->entity()->CalculateNormal(*aPoint); + double x = -aDirA.x + aDirB.x; + double y = -aDirA.y + aDirB.y; + double norm = sqrt(x*x + y*y); + if (norm > tolerance) { + theDirX = x / norm; + theDirY = y / norm; + } + } + } +} + +static void moveEntity(const ConstraintPtr& theConstraint, + const StoragePtr& theStorage, + const double theDX, const double theDY) +{ + static const double THE_SHIFT = 1.e-4; + + AttributeRefAttrPtr aRefAttrA = theConstraint->refattr(SketchPlugin_Constraint::ENTITY_A()); + AttributeRefAttrPtr aRefAttrB = theConstraint->refattr(SketchPlugin_Constraint::ENTITY_B()); + + EntityWrapperPtr aEntityA = theStorage->entity(aRefAttrA); + EntityWrapperPtr aEntityB = theStorage->entity(aRefAttrB); + + PointWrapperPtr aPointA = std::dynamic_pointer_cast(aEntityA); + PointWrapperPtr aPointB = std::dynamic_pointer_cast(aEntityB); + + if (aPointA) { + *aPointA->point()->x -= THE_SHIFT * theDX; + *aPointA->point()->y -= THE_SHIFT * theDY; + } + else if (aPointB) { + *aPointB->point()->x += THE_SHIFT * theDX; + *aPointB->point()->y += THE_SHIFT * theDY; + } +} + + + void SketchSolver_ConstraintDistance::getAttributes( EntityWrapperPtr& theValue, std::vector& theAttributes) @@ -43,76 +163,187 @@ void SketchSolver_ConstraintDistance::getAttributes( return; } + ScalarWrapperPtr aValue = std::dynamic_pointer_cast(theValue); + bool isCoincidence = fabs(aValue->value()) < tolerance; + if (theAttributes[1]) { if (myBaseConstraint->getKind() == SketchPlugin_ConstraintDistanceHorizontal::ID()) myType = CONSTRAINT_HORIZONTAL_DISTANCE; else if (myBaseConstraint->getKind() == SketchPlugin_ConstraintDistanceVertical::ID()) myType = CONSTRAINT_VERTICAL_DISTANCE; else - myType = CONSTRAINT_PT_PT_DISTANCE; + myType = isCoincidence ? CONSTRAINT_PT_PT_COINCIDENT : CONSTRAINT_PT_PT_DISTANCE; } else if (theAttributes[2] && theAttributes[2]->type() == ENTITY_LINE) - myType = CONSTRAINT_PT_LINE_DISTANCE; + myType = isCoincidence ? CONSTRAINT_PT_ON_CURVE : CONSTRAINT_PT_LINE_DISTANCE; else theAttributes.clear(); + if (myType == CONSTRAINT_HORIZONTAL_DISTANCE || myType == CONSTRAINT_VERTICAL_DISTANCE) + mySignValue = aValue->value() < 0.0 ? -1.0 : 1.0; + myPrevValue = 0.0; + + if (isCoincidence) + myStorage->subscribeUpdates(this, PlaneGCSSolver_UpdateCoincidence::GROUP()); + else + myStorage->subscribeUpdates(this, PlaneGCSSolver_UpdateFeature::GROUP()); } void SketchSolver_ConstraintDistance::adjustConstraint() +{ + if (getType() == CONSTRAINT_PT_LINE_DISTANCE) { + bool isSigned = myBaseConstraint->boolean(SketchPlugin_ConstraintDistance::SIGNED())->value(); + if (myIsSigned == isSigned) { + // adjust auxiliary point for sign-keeping + if (isSigned) { + EntityWrapperPtr aDistPoint, aDistLine; + getPointAndLine(myBaseConstraint, myStorage, aDistPoint, aDistLine); + adjustOddPoint(aDistPoint, aDistLine, myOddPoint); + } + } + else { + // Adjust point-line distance by setting/removing additional constraints + if (isSigned) + addConstraintsToKeepSign(); + else + removeConstraintsKeepingSign(); + } + myIsSigned = isSigned; + } +} + +void SketchSolver_ConstraintDistance::update() { ConstraintWrapperPtr aConstraint = myStorage->constraint(myBaseConstraint); + myPrevValue = aConstraint->value(); - // Adjust point-point distance if the points are equal - if (getType() == CONSTRAINT_PT_PT_DISTANCE) { -//// AttributePtr aPt1 = myBaseConstraint->attribute(SketchPlugin_Constraint::ENTITY_A()); -//// AttributePtr aPt2 = myBaseConstraint->attribute(SketchPlugin_Constraint::ENTITY_B()); -//// -//// BuilderPtr aBuilder = SketchSolver_Manager::instance()->builder(); -//// std::shared_ptr aPoint1 = aBuilder->point(myStorage->entity(aPt1)); -//// EntityWrapperPtr anEntity2 = myStorage->entity(aPt2); -//// std::shared_ptr aPoint2 = aBuilder->point(anEntity2); -//// -//////// if (aPoint1->distance(aPoint2) < tolerance) { -//////// // Change X coordinate of second point to eliminate coincidence -//////// ParameterWrapperPtr aX = aSubs.back()->parameters().front(); -//////// aX->setValue(aX->value() + 1.0); -//////// myStorage->update(aX); -//////// } - return; - } + bool isDistanceAlognDir = + myBaseConstraint->getKind() == SketchPlugin_ConstraintDistanceHorizontal::ID() || + myBaseConstraint->getKind() == SketchPlugin_ConstraintDistanceVertical::ID(); - // Adjust point-line distance - if (fabs(myPrevValue) == fabs(aConstraint->value())) { - // sign of distance is not changed -//// aConstraint->setValue(myPrevValue); -//// myStorage->addConstraint(myBaseConstraint, aConstraint); - return; + AttributeDoublePtr aCurValue = myBaseConstraint->real(SketchPlugin_Constraint::VALUE()); + bool isZeroSwitch = fabs(myPrevValue) < tolerance && fabs(aCurValue->value()) > tolerance; + bool isNonZeroSwitch = fabs(myPrevValue) > tolerance && fabs(aCurValue->value()) < tolerance; + + if (!isDistanceAlognDir && (isZeroSwitch || isNonZeroSwitch)) { + // the value is changed from non-zero to zero or vice versa + remove(); + process(); + + // move entities to avoid conflicting constraints + if (isZeroSwitch) { + double aDirX, aDirY; + // calculate the direction basing on the distanced objects + calculateDistanceDirection(myBaseConstraint, myStorage, aDirX, aDirY); + moveEntity(myBaseConstraint, myStorage, aDirX, aDirY); + + if (myOddPoint) { + removeConstraintsKeepingSign(); + addConstraintsToKeepSign(); + } + } } + else { + SketchSolver_Constraint::update(); + if (isDistanceAlognDir && mySignValue * aConstraint->value() < 0.0) { + if (isZeroSwitch) + aConstraint->setValue(-aConstraint->value()); + else + mySignValue *= -1.0; + } + } +} -//// // Adjust the sign of constraint value -//// BuilderPtr aBuilder = SketchSolver_Manager::instance()->builder(); -//// -//// std::shared_ptr aLine; -//// std::shared_ptr aPoint; -//// for (int i = 0; i < 2; ++i) { -//// AttributePtr anAttr = myBaseConstraint->attribute(SketchPlugin_Constraint::ATTRIBUTE(i)); -//// EntityWrapperPtr anEntity = myStorage->entity(anAttr); -//// if (anEntity->type() == ENTITY_POINT) -//// aPoint = aBuilder->point(anEntity); -//// else if (anEntity->type() == ENTITY_LINE) -//// aLine = aBuilder->line(anEntity); -//// } -//// -//// std::shared_ptr aLineVec = aLine->direction()->xy(); -//// std::shared_ptr aPtLineVec = aPoint->xy()->decreased(aLine->location()->xy()); -//// if (aLineVec->cross(aPtLineVec) * aConstraint->value() < 0.0) -//// aConstraint->setValue(aConstraint->value() * (-1.0)); +bool SketchSolver_ConstraintDistance::remove() +{ + removeConstraintsKeepingSign(); + return SketchSolver_Constraint::remove(); } -void SketchSolver_ConstraintDistance::update() +void SketchSolver_ConstraintDistance::addConstraintsToKeepSign() { - ConstraintWrapperPtr aConstraint = myStorage->constraint(myBaseConstraint); - myPrevValue = aConstraint->value(); + std::shared_ptr aStorage = + std::dynamic_pointer_cast(myStorage); + + ConstraintWrapperPtr aConstraint = aStorage->constraint(myBaseConstraint); + std::list aGCSConstraints = aConstraint->constraints(); - SketchSolver_Constraint::update(); + // calculate projection of the point on the line and find a sign of a distance + EntityWrapperPtr aDistPoint, aDistLine; + getPointAndLine(myBaseConstraint, myStorage, aDistPoint, aDistLine); + + std::shared_ptr aLine = PlaneGCSSolver_Tools::line(aDistLine); + std::shared_ptr aPoint = PlaneGCSSolver_Tools::point(aDistPoint); + + std::shared_ptr aLineVec = aLine->direction()->xy(); + std::shared_ptr aPtLineVec = aPoint->xy()->decreased(aLine->location()->xy()); + if (aLineVec->cross(aPtLineVec) >= 0.) + mySignValue = PI/2.0; + else + mySignValue = - PI/2.0; + + // create auxiliary point on the line and set auxiliary constraints + myOddPoint = GCSPointPtr(new GCS::Point); + myOddPoint->x = aStorage->createParameter(); + myOddPoint->y = aStorage->createParameter(); + adjustOddPoint(aDistPoint, aDistLine, myOddPoint); + + PointWrapperPtr aPointWr = std::dynamic_pointer_cast(aDistPoint); + EdgeWrapperPtr anEdgeWr = std::dynamic_pointer_cast(aDistLine); + std::shared_ptr aGCSLine = std::dynamic_pointer_cast(anEdgeWr->entity()); + // point-on-line + GCSConstraintPtr aNewConstraint(new GCS::ConstraintPointOnLine(*myOddPoint, *aGCSLine)); + aGCSConstraints.push_back(aNewConstraint); + // angle which keep orientation + aNewConstraint = GCSConstraintPtr(new GCS::ConstraintL2LAngle( + aGCSLine->p1, aGCSLine->p2, *myOddPoint, *(aPointWr->point()), &mySignValue)); + aGCSConstraints.push_back(aNewConstraint); + + aConstraint->setConstraints(aGCSConstraints); + + aStorage->removeConstraint(myBaseConstraint); + aStorage->addConstraint(myBaseConstraint, aConstraint); +} + +void SketchSolver_ConstraintDistance::removeConstraintsKeepingSign() +{ + if (!myOddPoint) + return; // no sign kept => nothing to remove + + std::shared_ptr aStorage = + std::dynamic_pointer_cast(myStorage); + + ConstraintWrapperPtr aConstraint = aStorage->constraint(myBaseConstraint); + std::list aGCSConstraints = aConstraint->constraints(); + + aStorage->removeConstraint(myBaseConstraint); + + // remove parameters related to auxiliary point + GCS::SET_pD aParams; + aParams.insert(myOddPoint->x); + aParams.insert(myOddPoint->y); + aStorage->removeParameters(aParams); + + // remove constraints keeping sign of point-line distance, + // not more than 2 additional constraints is possible + if (!aGCSConstraints.empty()) + aGCSConstraints.pop_back(); + if (!aGCSConstraints.empty()) + aGCSConstraints.pop_back(); + aConstraint->setConstraints(aGCSConstraints); + aStorage->addConstraint(myBaseConstraint, aConstraint); + + myIsSigned = false; +} + +void SketchSolver_ConstraintDistance::notify(const FeaturePtr& theFeature, + PlaneGCSSolver_Update*) +{ + if (getType() == CONSTRAINT_PT_LINE_DISTANCE && myIsSigned && + theFeature->getKind() == SketchPlugin_Sketch::ID()) { + // the sketch plane was updated, recalculate auxiliary constraints + removeConstraintsKeepingSign(); + addConstraintsToKeepSign(); + myIsSigned = true; // reset it, due to changing by removeConstraintsKeepingSign() + } }