From 0c2de986ec02a958f2b58f51a0b43b339d4a6b61 Mon Sep 17 00:00:00 2001 From: azv Date: Tue, 17 Mar 2015 12:18:34 +0300 Subject: [PATCH] Constraint Tangent is added --- src/GeomAPI/GeomAPI_Edge.cpp | 16 ++- src/SketchPlugin/CMakeLists.txt | 6 +- .../SketchPlugin_ConstraintTangent.cpp | 44 +++++++++ .../SketchPlugin_ConstraintTangent.h | 51 ++++++++++ src/SketchPlugin/SketchPlugin_Plugin.cpp | 4 + .../Test/TestConstraintTangent.py | 97 +++++++++++++++++++ src/SketchPlugin/plugin-Sketch.xml | 12 ++- src/SketchSolver/SketchSolver_Constraint.cpp | 24 ++++- .../SketchSolver_ConstraintGroup.cpp | 50 +++++++++- 9 files changed, 292 insertions(+), 12 deletions(-) create mode 100644 src/SketchPlugin/SketchPlugin_ConstraintTangent.cpp create mode 100644 src/SketchPlugin/SketchPlugin_ConstraintTangent.h create mode 100644 src/SketchPlugin/Test/TestConstraintTangent.py diff --git a/src/GeomAPI/GeomAPI_Edge.cpp b/src/GeomAPI/GeomAPI_Edge.cpp index 759b0b323..4b758eb90 100644 --- a/src/GeomAPI/GeomAPI_Edge.cpp +++ b/src/GeomAPI/GeomAPI_Edge.cpp @@ -46,8 +46,12 @@ bool GeomAPI_Edge::isCircle() const const TopoDS_Shape& aShape = const_cast(this)->impl(); double aFirst, aLast; Handle(Geom_Curve) aCurve = BRep_Tool::Curve((const TopoDS_Edge&)aShape, aFirst, aLast); - if (aCurve->IsKind(STANDARD_TYPE(Geom_Circle)) && aCurve->IsClosed()) - return true; + if (aCurve->IsKind(STANDARD_TYPE(Geom_Circle))) + { + // Check the difference of first and last parameters to be equal to the curve period + if (Abs(aLast - aFirst - aCurve->Period()) < Precision::PConfusion()) + return true; + } return false; } @@ -56,8 +60,12 @@ bool GeomAPI_Edge::isArc() const const TopoDS_Shape& aShape = const_cast(this)->impl(); double aFirst, aLast; Handle(Geom_Curve) aCurve = BRep_Tool::Curve((const TopoDS_Edge&)aShape, aFirst, aLast); - if (aCurve->IsKind(STANDARD_TYPE(Geom_Circle)) && !aCurve->IsClosed()) - return true; + if (aCurve->IsKind(STANDARD_TYPE(Geom_Circle))) + { + // Check the difference of first and last parameters is not equal the curve period + if (Abs(aLast - aFirst - aCurve->Period()) >= Precision::PConfusion()) + return true; + } return false; } diff --git a/src/SketchPlugin/CMakeLists.txt b/src/SketchPlugin/CMakeLists.txt index c34904df2..d1499da27 100644 --- a/src/SketchPlugin/CMakeLists.txt +++ b/src/SketchPlugin/CMakeLists.txt @@ -25,6 +25,7 @@ SET(PROJECT_HEADERS SketchPlugin_ConstraintHorizontal.h SketchPlugin_ConstraintVertical.h SketchPlugin_ConstraintEqual.h + SketchPlugin_ConstraintTangent.h SketchPlugin_ShapeValidator.h SketchPlugin_Validators.h SketchPlugin_ResultValidators.h @@ -50,6 +51,7 @@ SET(PROJECT_SOURCES SketchPlugin_ConstraintHorizontal.cpp SketchPlugin_ConstraintVertical.cpp SketchPlugin_ConstraintEqual.cpp + SketchPlugin_ConstraintTangent.cpp SketchPlugin_ShapeValidator.cpp SketchPlugin_Validators.cpp SketchPlugin_ResultValidators.cpp @@ -91,12 +93,14 @@ ADD_UNIT_TESTS(TestSketchPointLine.py TestConstraintConcidence.py TestConstraintLength.py TestConstraintDistance.py - TestConstraintParallel.py +# TestConstraintParallel.py TestConstraintPerpendicular.py TestConstraintRadius.py TestConstraintRigid.py TestConstraintHorizontal.py TestConstraintVertical.py TestConstraintEqual.py + TestConstraintTangent.py + TestConstraintParallel.py TestHighload.py TestSnowflake.py) diff --git a/src/SketchPlugin/SketchPlugin_ConstraintTangent.cpp b/src/SketchPlugin/SketchPlugin_ConstraintTangent.cpp new file mode 100644 index 000000000..f2cf4a307 --- /dev/null +++ b/src/SketchPlugin/SketchPlugin_ConstraintTangent.cpp @@ -0,0 +1,44 @@ +// Copyright (C) 2014-20xx CEA/DEN, EDF R&D --> + +// File: SketchPlugin_ConstraintTangent.cpp +// Created: 16 Mar 2015 +// Author: Artem ZHIDKOV + +#include "SketchPlugin_ConstraintTangent.h" + +#include +#include +#include + +#include +#include + +#include + +#include + +SketchPlugin_ConstraintTangent::SketchPlugin_ConstraintTangent() +{ +} + +void SketchPlugin_ConstraintTangent::initAttributes() +{ + data()->addAttribute(SketchPlugin_Constraint::ENTITY_A(), ModelAPI_AttributeRefAttr::type()); + data()->addAttribute(SketchPlugin_Constraint::ENTITY_B(), ModelAPI_AttributeRefAttr::type()); +} + +void SketchPlugin_ConstraintTangent::execute() +{ +} + +AISObjectPtr SketchPlugin_ConstraintTangent::getAISObject(AISObjectPtr thePrevious) +{ + if (!sketch()) + return thePrevious; + + AISObjectPtr anAIS = thePrevious; + /// TODO: Tangency constraint presentation should be put here + return anAIS; +} + + diff --git a/src/SketchPlugin/SketchPlugin_ConstraintTangent.h b/src/SketchPlugin/SketchPlugin_ConstraintTangent.h new file mode 100644 index 000000000..cb7edd51e --- /dev/null +++ b/src/SketchPlugin/SketchPlugin_ConstraintTangent.h @@ -0,0 +1,51 @@ +// Copyright (C) 2014-20xx CEA/DEN, EDF R&D --> + +// File: SketchPlugin_ConstraintTangent.h +// Created: 16 Mar 2015 +// Author: Artem ZHIDKOV + +#ifndef SketchPlugin_ConstraintTangent_H_ +#define SketchPlugin_ConstraintTangent_H_ + +#include "SketchPlugin.h" +#include +#include "SketchPlugin_ConstraintBase.h" + +/** \class SketchPlugin_ConstraintTangent + * \ingroup Plugins + * \brief Feature for creation of a new constraint tangency between line and arc + * or between two circular arcs. The used features must have shared vertex + * + * This constraint has two attributes: + * SketchPlugin_Constraint::ENTITY_A() and SketchPlugin_Constraint::ENTITY_B() + */ +class SketchPlugin_ConstraintTangent : public SketchPlugin_ConstraintBase +{ + public: + /// Equal constraint kind + inline static const std::string& ID() + { + static const std::string MY_CONSTRAINT_TANGENT_ID("SketchConstraintTangent"); + return MY_CONSTRAINT_TANGENT_ID; + } + /// \brief Returns the kind of a feature + SKETCHPLUGIN_EXPORT virtual const std::string& getKind() + { + static std::string MY_KIND = SketchPlugin_ConstraintTangent::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); + + /// \brief Use plugin manager for features creation + SketchPlugin_ConstraintTangent(); +}; + +#endif diff --git a/src/SketchPlugin/SketchPlugin_Plugin.cpp b/src/SketchPlugin/SketchPlugin_Plugin.cpp index 5e1ac512c..fd9b04f8a 100644 --- a/src/SketchPlugin/SketchPlugin_Plugin.cpp +++ b/src/SketchPlugin/SketchPlugin_Plugin.cpp @@ -15,6 +15,7 @@ #include #include #include +#include #include #include #include @@ -118,6 +119,8 @@ FeaturePtr SketchPlugin_Plugin::createFeature(string theFeatureID) return FeaturePtr(new SketchPlugin_ConstraintVertical); } else if (theFeatureID == SketchPlugin_ConstraintEqual::ID()) { return FeaturePtr(new SketchPlugin_ConstraintEqual); + } else if (theFeatureID == SketchPlugin_ConstraintTangent::ID()) { + return FeaturePtr(new SketchPlugin_ConstraintTangent); } // feature of such kind is not found return FeaturePtr(); @@ -165,6 +168,7 @@ std::shared_ptr SketchPlugin_Plugin aMsg->setState(SketchPlugin_ConstraintHorizontal::ID(), aHasSketchPlane); aMsg->setState(SketchPlugin_ConstraintVertical::ID(), aHasSketchPlane); aMsg->setState(SketchPlugin_ConstraintEqual::ID(), aHasSketchPlane); + aMsg->setState(SketchPlugin_ConstraintTangent::ID(), aHasSketchPlane); } } return aMsg; diff --git a/src/SketchPlugin/Test/TestConstraintTangent.py b/src/SketchPlugin/Test/TestConstraintTangent.py new file mode 100644 index 000000000..2eeb02514 --- /dev/null +++ b/src/SketchPlugin/Test/TestConstraintTangent.py @@ -0,0 +1,97 @@ +""" + TestConstraintTangent.py + Unit test of SketchPlugin_ConstraintTangent class + + SketchPlugin_ConstraintTangent + static const std::string MY_CONSTRAINT_TANGENT_ID("SketchConstraintTangent"); + data()->addAttribute(SketchPlugin_Constraint::ENTITY_A(), ModelAPI_AttributeRefAttr::type()); + data()->addAttribute(SketchPlugin_Constraint::ENTITY_B(), ModelAPI_AttributeRefAttr::type()); + +""" +from GeomDataAPI import * +from GeomAPI import * +from ModelAPI import * +import math +#========================================================================= +# Initialization of the test +#========================================================================= + +__updated__ = "2015-03-17" + +aSession = ModelAPI_Session.get() +aDocument = aSession.moduleDocument() +#========================================================================= +# Creation of a sketch +#========================================================================= +aSession.startOperation() +aSketchCommonFeature = aDocument.addFeature("Sketch") +aSketchFeature = modelAPI_CompositeFeature(aSketchCommonFeature) +origin = geomDataAPI_Point(aSketchFeature.attribute("Origin")) +origin.setValue(0, 0, 0) +dirx = geomDataAPI_Dir(aSketchFeature.attribute("DirX")) +dirx.setValue(1, 0, 0) +diry = geomDataAPI_Dir(aSketchFeature.attribute("DirY")) +diry.setValue(0, 1, 0) +norm = geomDataAPI_Dir(aSketchFeature.attribute("Norm")) +norm.setValue(0, 0, 1) +aSession.finishOperation() +#========================================================================= +# Creation of an arc and a line +#========================================================================= +# Arc +aSession.startOperation() +aSketchArc1 = aSketchFeature.addFeature("SketchArc") +anArcCentr = geomDataAPI_Point2D(aSketchArc1.attribute("ArcCenter")) +anArcCentr.setValue(10., 10.) +anArcStartPoint = geomDataAPI_Point2D(aSketchArc1.attribute("ArcStartPoint")) +anArcStartPoint.setValue(0., 50.) +anArcEndPoint = geomDataAPI_Point2D(aSketchArc1.attribute("ArcEndPoint")) +anArcEndPoint.setValue(50., 0.) +aSession.finishOperation() +# Line +aSession.startOperation() +aSketchLine1 = aSketchFeature.addFeature("SketchLine") +aLineStartPoint = geomDataAPI_Point2D(aSketchLine1.attribute("StartPoint")) +aLineEndPoint = geomDataAPI_Point2D(aSketchLine1.attribute("EndPoint")) +aLineStartPoint.setValue(0., 50.) +aLineEndPoint.setValue(0., 100.) +aSession.finishOperation() +#========================================================================= +# Link arc start point and line's point by the coincidence constraint +#========================================================================= +aSession.startOperation() +aConstraint = aSketchFeature.addFeature("SketchConstraintCoincidence") +reflistA = aConstraint.refattr("ConstraintEntityA") +reflistB = aConstraint.refattr("ConstraintEntityB") +reflistA.setAttr(anArcStartPoint) +reflistB.setAttr(aLineStartPoint) +aConstraint.execute() +aSession.finishOperation() +#========================================================================= +# Add tangency constraint and check correctness +#========================================================================= +aSession.startOperation() +aTangency = aSketchFeature.addFeature("SketchConstraintTangent") +aRefObjectA = aTangency.refattr("ConstraintEntityA") +aRefObjectB = aTangency.refattr("ConstraintEntityB") +anObjectA = modelAPI_ResultConstruction(aSketchArc1.firstResult()) +anObjectB = modelAPI_ResultConstruction(aSketchLine1.firstResult()) +assert (anObjectA is not None) +assert (anObjectB is not None) +aRefObjectA.setObject(anObjectA) +aRefObjectB.setObject(anObjectB) +aTangency.execute() +aSession.finishOperation() +anArcVecX = anArcStartPoint.x() - anArcCentr.x() +anArcVecY = anArcStartPoint.y() - anArcCentr.y() +aLineVecX = aLineEndPoint.x() - aLineStartPoint.x() +aLineVecY = aLineEndPoint.y() - aLineStartPoint.y() +aDot = anArcVecX * aLineVecX + anArcVecY * aLineVecY +print anArcVecX, anArcVecY +print aLineVecX, aLineVecY +print aDot +print aLineStartPoint.x(), aLineStartPoint.y(), aLineEndPoint.x(), aLineEndPoint.y() +assert(aDot == 0.) +#========================================================================= +# End of test +#========================================================================= diff --git a/src/SketchPlugin/plugin-Sketch.xml b/src/SketchPlugin/plugin-Sketch.xml index b33c14891..8e8803758 100644 --- a/src/SketchPlugin/plugin-Sketch.xml +++ b/src/SketchPlugin/plugin-Sketch.xml @@ -5,7 +5,7 @@ + + + + + + + + diff --git a/src/SketchSolver/SketchSolver_Constraint.cpp b/src/SketchSolver/SketchSolver_Constraint.cpp index 980c51879..e4af2a064 100644 --- a/src/SketchSolver/SketchSolver_Constraint.cpp +++ b/src/SketchSolver/SketchSolver_Constraint.cpp @@ -20,6 +20,7 @@ #include #include #include +#include #include #include @@ -229,8 +230,7 @@ const int& SketchSolver_Constraint::getType( std::shared_ptr anAttr = aConstrData->attribute(SketchPlugin_Constraint::ATTRIBUTE(indAttr)); AttrType aType = typeOfAttribute(anAttr); - if (aType == LINE) - { + if (aType == LINE) { myAttributesList[aNbEntities++] = SketchPlugin_Constraint::ATTRIBUTE(indAttr); aNbLines++; } @@ -242,6 +242,26 @@ const int& SketchSolver_Constraint::getType( return getType(); } + if (aConstraintKind.compare(SketchPlugin_ConstraintTangent::ID()) == 0) + { + static const int anArcPosDefault = 2; + static const int aLinePosDefault = 3; + int anArcPos = anArcPosDefault; // arc in tangency constraint should be placed before line + int aLinePos = aLinePosDefault; + for (unsigned int indAttr = 0; indAttr < CONSTRAINT_ATTR_SIZE; indAttr++) { + std::shared_ptr anAttr = + aConstrData->attribute(SketchPlugin_Constraint::ATTRIBUTE(indAttr)); + AttrType aType = typeOfAttribute(anAttr); + if (aType == LINE && aLinePos < CONSTRAINT_ATTR_SIZE) + myAttributesList[aLinePos++] = SketchPlugin_Constraint::ATTRIBUTE(indAttr); + else if (aType == ARC) + myAttributesList[anArcPos++] = SketchPlugin_Constraint::ATTRIBUTE(indAttr); + } + if (anArcPos - anArcPosDefault + aLinePos - aLinePosDefault == 2) + myType = aLinePos > 3 ? SLVS_C_ARC_LINE_TANGENT : SLVS_C_CURVE_CURVE_TANGENT; + return getType(); + } + /// \todo Implement other kind of constraints return getType(); diff --git a/src/SketchSolver/SketchSolver_ConstraintGroup.cpp b/src/SketchSolver/SketchSolver_ConstraintGroup.cpp index 3cb517247..61299f8a7 100644 --- a/src/SketchSolver/SketchSolver_ConstraintGroup.cpp +++ b/src/SketchSolver/SketchSolver_ConstraintGroup.cpp @@ -52,6 +52,12 @@ class SketchSolver_Error static const std::string MY_ERROR_VALUE("Conflicting constraints"); return MY_ERROR_VALUE; } + /// The entities need to have shared point, but they have not + inline static const std::string& NO_COINCIDENT_POINTS() + { + static const std::string MY_ERROR_VALUE("Objects should have coincident point"); + return MY_ERROR_VALUE; + } }; /// This value is used to give unique index to the groups @@ -351,14 +357,50 @@ bool SketchSolver_ConstraintGroup::changeConstraint( removeTemporaryConstraints(aTmpConstrToDelete); } } + // For the tangency constraints it is necessary to identify which points of entities are coincident + int aSlvsOtherFlag = 0; + int aSlvsOther2Flag = 0; + if (aConstrType == SLVS_C_ARC_LINE_TANGENT || aConstrType == SLVS_C_CURVE_CURVE_TANGENT) { + // Search entities used by constraint + int anEnt1Pos = Search(aConstrEnt[2], myEntities); + int anEnt2Pos = Search(aConstrEnt[3], myEntities); + // Obtain start and end points of entities + Slvs_hEntity aPointsToFind[4]; + aPointsToFind[0] = myEntities[anEnt1Pos].point[1]; + aPointsToFind[1]= myEntities[anEnt1Pos].point[2]; + bool hasLine = (myEntities[anEnt2Pos].type == SLVS_E_LINE_SEGMENT); + aPointsToFind[2]= myEntities[anEnt2Pos].point[hasLine ? 0 : 1]; + aPointsToFind[3]= myEntities[anEnt2Pos].point[hasLine ? 1 : 2]; + // Search coincident points + bool isPointFound[4]; + std::vector >::const_iterator aCPIter = myCoincidentPoints.begin(); + for ( ; aCPIter != myCoincidentPoints.end(); aCPIter++) { + for (int i = 0; i < 4; i++) + isPointFound[i] = (aCPIter->find(aPointsToFind[i]) != aCPIter->end()); + if ((isPointFound[0] || isPointFound[1]) && (isPointFound[2] || isPointFound[3])) { + // the arc is tangent by end point + if (isPointFound[1]) aSlvsOtherFlag = 1; + // the second item is an arc and it is tangent by end point too + if (!hasLine && isPointFound[3]) aSlvsOther2Flag = 1; + break; + } + } + if (aCPIter == myCoincidentPoints.end()) { + // There is no coincident points between tangential objects. Generate error message + Events_Error::send(SketchSolver_Error::NO_COINCIDENT_POINTS(), this); + return false; + } + } // Create SolveSpace constraint structure - Slvs_Constraint aConstraint = Slvs_MakeConstraint(++myConstrMaxID, myID, aConstrType, + Slvs_Constraint aSlvsConstr = Slvs_MakeConstraint(++myConstrMaxID, myID, aConstrType, myWorkplane.h, aDistance, aConstrEnt[0], aConstrEnt[1], aConstrEnt[2], aConstrEnt[3]); - myConstraints.push_back(aConstraint); - myConstraintMap[theConstraint] = std::vector(1, aConstraint.h); - int aConstrPos = Search(aConstraint.h, myConstraints); + if (aSlvsOtherFlag != 0) aSlvsConstr.other = aSlvsOtherFlag; + if (aSlvsOther2Flag != 0) aSlvsConstr.other2 = aSlvsOther2Flag; + myConstraints.push_back(aSlvsConstr); + myConstraintMap[theConstraint] = std::vector(1, aSlvsConstr.h); + int aConstrPos = Search(aSlvsConstr.h, myConstraints); aConstrIter = myConstraints.begin() + aConstrPos; myNeedToSolve = true; } else { // Attributes of constraint may be changed => update constraint -- 2.39.2