1. Implemented SketchPlugin entities related to Horizontal and Vertical Distance constraints.
2. Add processing of new constraints in the solver.
3. Special Python commands for new constraints in SketchAPI
4. Unit tests
#include <SketchPlugin_ConstraintCoincidence.h>
#include <SketchPlugin_ConstraintCollinear.h>
#include <SketchPlugin_ConstraintDistance.h>
+#include <SketchPlugin_ConstraintDistanceHorizontal.h>
+#include <SketchPlugin_ConstraintDistanceVertical.h>
#include <SketchPlugin_ConstraintEqual.h>
#include <SketchPlugin_ConstraintHorizontal.h>
#include <SketchPlugin_ConstraintLength.h>
static const std::string DISTANCE_SETTER("setDistance");
return DISTANCE_SETTER;
}
+ if (theType == SketchPlugin_ConstraintDistanceHorizontal::ID()) {
+ static const std::string DISTANCE_SETTER("setHorizontalDistance");
+ return DISTANCE_SETTER;
+ }
+ if (theType == SketchPlugin_ConstraintDistanceVertical::ID()) {
+ static const std::string DISTANCE_SETTER("setVerticalDistance");
+ return DISTANCE_SETTER;
+ }
if (theType == SketchPlugin_ConstraintEqual::ID()) {
static const std::string EQUAL_SETTER("setEqual");
return EQUAL_SETTER;
//--------------------------------------------------------------------------------------
+std::list<std::shared_ptr<SketchAPI_SketchEntity> > SketchAPI_Rectangle::lines() const
+{
+ std::list<FeaturePtr> aFeatures;
+ std::list<ObjectPtr> aList = linesList()->list();
+ std::list<ObjectPtr>::const_iterator anIt = aList.begin();
+ for (; anIt != aList.end(); ++anIt)
+ aFeatures.push_back(ModelAPI_Feature::feature(*anIt));
+ return SketchAPI_SketchEntity::wrap(aFeatures);
+}
SKETCHAPI_EXPORT
void setByPoints(const std::shared_ptr<GeomAPI_Pnt2d> & theStartPoint,
const std::shared_ptr<GeomAPI_Pnt2d> & theEndPoint);
+
+ /// List of lines composing rectangle
+ SKETCHAPI_EXPORT std::list<std::shared_ptr<SketchAPI_SketchEntity> > lines() const;
};
//! Pointer on Rectangle object
#include <SketchPlugin_ConstraintCoincidence.h>
#include <SketchPlugin_ConstraintCollinear.h>
#include <SketchPlugin_ConstraintDistance.h>
+#include <SketchPlugin_ConstraintDistanceHorizontal.h>
+#include <SketchPlugin_ConstraintDistanceVertical.h>
#include <SketchPlugin_ConstraintEqual.h>
#include <SketchPlugin_Fillet.h>
#include <SketchPlugin_ConstraintHorizontal.h>
return InterfacePtr(new ModelHighAPI_Interface(aFeature));
}
+std::shared_ptr<ModelHighAPI_Interface> SketchAPI_Sketch::setHorizontalDistance(
+ const ModelHighAPI_RefAttr & thePoint1,
+ const ModelHighAPI_RefAttr & thePoint2,
+ const ModelHighAPI_Double & theValue)
+{
+ std::shared_ptr<ModelAPI_Feature> aFeature =
+ compositeFeature()->addFeature(SketchPlugin_ConstraintDistanceHorizontal::ID());
+ fillAttribute(thePoint1, aFeature->refattr(SketchPlugin_Constraint::ENTITY_A()));
+ fillAttribute(thePoint2, aFeature->refattr(SketchPlugin_Constraint::ENTITY_B()));
+ fillAttribute(theValue, aFeature->real(SketchPlugin_Constraint::VALUE()));
+ aFeature->execute();
+ return InterfacePtr(new ModelHighAPI_Interface(aFeature));
+}
+
+std::shared_ptr<ModelHighAPI_Interface> SketchAPI_Sketch::setVerticalDistance(
+ const ModelHighAPI_RefAttr & thePoint1,
+ const ModelHighAPI_RefAttr & thePoint2,
+ const ModelHighAPI_Double & theValue)
+{
+ std::shared_ptr<ModelAPI_Feature> aFeature =
+ compositeFeature()->addFeature(SketchPlugin_ConstraintDistanceVertical::ID());
+ fillAttribute(thePoint1, aFeature->refattr(SketchPlugin_Constraint::ENTITY_A()));
+ fillAttribute(thePoint2, aFeature->refattr(SketchPlugin_Constraint::ENTITY_B()));
+ fillAttribute(theValue, aFeature->real(SketchPlugin_Constraint::VALUE()));
+ aFeature->execute();
+ return InterfacePtr(new ModelHighAPI_Interface(aFeature));
+}
+
std::shared_ptr<ModelHighAPI_Interface> SketchAPI_Sketch::setEqual(
const ModelHighAPI_RefAttr & theObject1,
const ModelHighAPI_RefAttr & theObject2)
const ModelHighAPI_RefAttr & thePointOrLine,
const ModelHighAPI_Double & theValue);
+ /// Set horizontal distance
+ SKETCHAPI_EXPORT
+ std::shared_ptr<ModelHighAPI_Interface> setHorizontalDistance(
+ const ModelHighAPI_RefAttr & thePoint1,
+ const ModelHighAPI_RefAttr & thePoint2,
+ const ModelHighAPI_Double & theValue);
+
+ /// Set vertical distance
+ SKETCHAPI_EXPORT
+ std::shared_ptr<ModelHighAPI_Interface> setVerticalDistance(
+ const ModelHighAPI_RefAttr & thePoint1,
+ const ModelHighAPI_RefAttr & thePoint2,
+ const ModelHighAPI_Double & theValue);
+
/// Set equal
SKETCHAPI_EXPORT
std::shared_ptr<ModelHighAPI_Interface> setEqual(
SketchPlugin_ConstraintCoincidence.h
SketchPlugin_ConstraintCollinear.h
SketchPlugin_ConstraintDistance.h
+ SketchPlugin_ConstraintDistanceHorizontal.h
+ SketchPlugin_ConstraintDistanceVertical.h
SketchPlugin_ConstraintEqual.h
SketchPlugin_ConstraintHorizontal.h
SketchPlugin_ConstraintLength.h
SketchPlugin_ConstraintCoincidence.cpp
SketchPlugin_ConstraintCollinear.cpp
SketchPlugin_ConstraintDistance.cpp
+ SketchPlugin_ConstraintDistanceHorizontal.cpp
+ SketchPlugin_ConstraintDistanceVertical.cpp
SketchPlugin_ConstraintEqual.cpp
SketchPlugin_ConstraintHorizontal.cpp
SketchPlugin_ConstraintLength.cpp
TestConstraintCollinear.py
TestConstraintLength.py
TestConstraintDistance.py
+ TestConstraintDistanceHorizontal.py
+ TestConstraintDistanceVertical.py
+ TestConstraintDistanceBehavior.py
TestConstraintParallel.py
TestConstraintPerpendicular.py
TestConstraintRadius.py
return aDistance;
}
+bool SketchPlugin_ConstraintDistance::areAttributesInitialized()
+{
+ std::shared_ptr<ModelAPI_Data> aData = data();
+ std::shared_ptr<GeomAPI_Ax3> aPlane = SketchPlugin_Sketch::plane(sketch());
+ std::shared_ptr<GeomDataAPI_Point2D> aPointA =
+ SketcherPrs_Tools::getFeaturePoint(aData, SketchPlugin_Constraint::ENTITY_A(), aPlane);
+ std::shared_ptr<GeomDataAPI_Point2D> aPointB =
+ SketcherPrs_Tools::getFeaturePoint(aData, SketchPlugin_Constraint::ENTITY_B(), aPlane);
+
+ if (!aPointA && !aPointB)
+ return false;
+ else if (aPointA || aPointB) {
+ FeaturePtr aLine;
+ if (!aPointA)
+ aLine = SketcherPrs_Tools::getFeatureLine(aData, SketchPlugin_Constraint::ENTITY_A());
+ else if (!aPointB)
+ aLine = SketcherPrs_Tools::getFeatureLine(aData, SketchPlugin_Constraint::ENTITY_B());
+ else // both points are initialized
+ return true;
+
+ if (!aLine || aLine->getKind() != SketchPlugin_Line::ID())
+ return false;
+ }
+ return true;
+}
+
void SketchPlugin_ConstraintDistance::attributeChanged(const std::string& theID)
{
if (theID == SketchPlugin_Constraint::ENTITY_A() ||
protected:
/// Returns the current distance between the feature attributes
- double calculateCurrentDistance();
+ virtual double calculateCurrentDistance();
+
+ /// Check the attributes related to distanced points/features are initialized
+ bool areAttributesInitialized();
private:
bool myFlyoutUpdate; ///< to avoid cyclic dependencies on automatic updates of flyout point
--- /dev/null
+// Copyright (C) 2014-20xx CEA/DEN, EDF R&D -->
+
+// File: SketchPlugin_ConstraintDistanceHorizontal.cpp
+// Created: 2 May 2017
+// Author: Artem ZHIDKOV
+
+#include <SketchPlugin_ConstraintDistanceHorizontal.h>
+
+#include <SketcherPrs_Tools.h>
+#include <SketcherPrs_Factory.h>
+
+#include <GeomAPI_Dir2d.h>
+#include <GeomAPI_XY.h>
+#include <GeomDataAPI_Point2D.h>
+
+#include <ModelAPI_AttributeDouble.h>
+
+const double tolerance = 1e-7;
+
+
+SketchPlugin_ConstraintDistanceHorizontal::SketchPlugin_ConstraintDistanceHorizontal()
+ : SketchPlugin_ConstraintDistance()
+{
+}
+
+//*************************************************************************************
+void SketchPlugin_ConstraintDistanceHorizontal::initAttributes()
+{
+ data()->addAttribute(SketchPlugin_Constraint::VALUE(), ModelAPI_AttributeDouble::typeId());
+ data()->addAttribute(SketchPlugin_Constraint::FLYOUT_VALUE_PNT(), GeomDataAPI_Point2D::typeId());
+ data()->addAttribute(SketchPlugin_Constraint::ENTITY_A(), ModelAPI_AttributeRefAttr::typeId());
+ data()->addAttribute(SketchPlugin_Constraint::ENTITY_B(), ModelAPI_AttributeRefAttr::typeId());
+}
+
+//*************************************************************************************
+void SketchPlugin_ConstraintDistanceHorizontal::execute()
+{
+ AttributeDoublePtr anAttrValue = real(SketchPlugin_Constraint::VALUE());
+ if (anAttrValue->isInitialized() || !areAttributesInitialized())
+ return;
+
+ double aDistance = calculateCurrentDistance();
+ anAttrValue->setValue(aDistance);
+}
+
+//*************************************************************************************
+AISObjectPtr SketchPlugin_ConstraintDistanceHorizontal::getAISObject(AISObjectPtr thePrevious)
+{
+ if (!sketch())
+ return thePrevious;
+
+ AISObjectPtr anAIS = SketcherPrs_Factory::lengthDimensionConstraint(this,
+ sketch()->coordinatePlane(),
+ thePrevious);
+ return anAIS;
+}
+
+//*************************************************************************************
+void SketchPlugin_ConstraintDistanceHorizontal::move(double theDeltaX, double theDeltaY)
+{
+ std::shared_ptr<ModelAPI_Data> aData = data();
+ if (!aData->isValid())
+ return;
+
+ // Recalculate a shift of flyout point in terms of local coordinates
+ std::shared_ptr<GeomAPI_XY> aDir(new GeomAPI_XY(theDeltaX, theDeltaY));
+ std::shared_ptr<GeomAPI_Ax3> aPlane = SketchPlugin_Sketch::plane(sketch());
+ std::shared_ptr<GeomDataAPI_Point2D> aPointA = SketcherPrs_Tools::getFeaturePoint(
+ data(), SketchPlugin_Constraint::ENTITY_A(), aPlane);
+ std::shared_ptr<GeomDataAPI_Point2D> aPointB = SketcherPrs_Tools::getFeaturePoint(
+ data(), SketchPlugin_Constraint::ENTITY_B(), aPlane);
+
+ if (!aPointA || !aPointB)
+ return;
+
+ std::shared_ptr<GeomAPI_XY> aStartPnt = aPointA->pnt()->xy();
+ std::shared_ptr<GeomAPI_XY> aEndPnt = aPointB->pnt()->xy();
+
+ std::shared_ptr<GeomAPI_Dir2d> aLineDir(new GeomAPI_Dir2d(aEndPnt->decreased(aStartPnt)));
+ double dX = aDir->dot(aLineDir->xy());
+ double dY = -aDir->cross(aLineDir->xy());
+
+ std::shared_ptr<GeomDataAPI_Point2D> aPoint = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
+ aData->attribute(SketchPlugin_Constraint::FLYOUT_VALUE_PNT()));
+ myFlyoutUpdate = true;
+ if (aPoint->isInitialized()) {
+ aPoint->setValue(aPoint->x() + dX, aPoint->y() + dY);
+ } else {
+ aPoint->setValue(dX, dY);
+ }
+ myFlyoutUpdate = false;
+}
+
+double SketchPlugin_ConstraintDistanceHorizontal::calculateCurrentDistance()
+{
+ std::shared_ptr<ModelAPI_Data> aData = data();
+ std::shared_ptr<GeomAPI_Ax3> aPlane = SketchPlugin_Sketch::plane(sketch());
+ std::shared_ptr<GeomDataAPI_Point2D> aPointA =
+ SketcherPrs_Tools::getFeaturePoint(aData, SketchPlugin_Constraint::ENTITY_A(), aPlane);
+ std::shared_ptr<GeomDataAPI_Point2D> aPointB =
+ SketcherPrs_Tools::getFeaturePoint(aData, SketchPlugin_Constraint::ENTITY_B(), aPlane);
+
+ return aPointB->x() - aPointA->x();
+}
+
+void SketchPlugin_ConstraintDistanceHorizontal::attributeChanged(const std::string& theID)
+{
+ if (theID == SketchPlugin_Constraint::ENTITY_A() ||
+ theID == SketchPlugin_Constraint::ENTITY_B())
+ {
+ AttributeDoublePtr aValueAttr = real(SketchPlugin_Constraint::VALUE());
+ if (!aValueAttr->isInitialized() && areAttributesInitialized()) {
+ // only if it is not initialized, try to compute the current value
+ double aDistance = calculateCurrentDistance();
+ aValueAttr->setValue(aDistance);
+ }
+ } else if (theID == SketchPlugin_Constraint::FLYOUT_VALUE_PNT() && !myFlyoutUpdate) {
+ myFlyoutUpdate = true;
+ // Recalculate flyout point in local coordinates of the distance constraint:
+ // the X coordinate is a length of projection of the flyout point on the
+ // line binding two distanced points
+ // or a line of projection of the distanced point onto the distanced segment
+ // the Y coordinate is a distance from the flyout point to the line
+ std::shared_ptr<GeomDataAPI_Point2D> aFlyoutAttr =
+ std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
+ attribute(SketchPlugin_Constraint::FLYOUT_VALUE_PNT()));
+ std::shared_ptr<GeomAPI_Pnt2d> aFlyoutPnt = aFlyoutAttr->pnt();
+
+ std::shared_ptr<GeomAPI_Ax3> aPlane = SketchPlugin_Sketch::plane(sketch());
+ std::shared_ptr<GeomDataAPI_Point2D> aPointA = SketcherPrs_Tools::getFeaturePoint(
+ data(), SketchPlugin_Constraint::ENTITY_A(), aPlane);
+ std::shared_ptr<GeomDataAPI_Point2D> aPointB = SketcherPrs_Tools::getFeaturePoint(
+ data(), SketchPlugin_Constraint::ENTITY_B(), aPlane);
+
+ std::shared_ptr<GeomAPI_XY> aStartPnt = aPointA->pnt()->xy();
+ std::shared_ptr<GeomAPI_XY> aEndPnt = aPointB->pnt()->xy();
+
+ if (aEndPnt->distance(aStartPnt) < tolerance)
+ return;
+
+ std::shared_ptr<GeomAPI_Dir2d> aLineDir(new GeomAPI_Dir2d(aEndPnt->decreased(aStartPnt)));
+ std::shared_ptr<GeomAPI_XY> aFlyoutDir = aFlyoutPnt->xy()->decreased(aStartPnt);
+
+ double X = aFlyoutDir->dot(aLineDir->xy());
+ double Y = -aFlyoutDir->cross(aLineDir->xy());
+ aFlyoutAttr->setValue(X, Y);
+ myFlyoutUpdate = false;
+ }
+}
--- /dev/null
+// Copyright (C) 2014-20xx CEA/DEN, EDF R&D -->
+
+// File: SketchPlugin_ConstraintDistanceHorizontal.h
+// Created: 2 May 2017
+// Author: Artem ZHIDKOV
+
+#ifndef SketchPlugin_ConstraintDistanceHorizontal_H_
+#define SketchPlugin_ConstraintDistanceHorizontal_H_
+
+#include <SketchPlugin.h>
+#include <SketchPlugin_ConstraintDistance.h>
+
+/** \class SketchPlugin_ConstraintDistanceHorizontal
+ * \ingroup Plugins
+ * \brief Feature for creation of a new constraint which defines a horizontal distance between two points.
+ *
+ * This constraint has three attributes:
+ * SketchPlugin_Constraint::VALUE(), SketchPlugin_Constraint::ENTITY_A() and SketchPlugin_Constraint::ENTITY_B()
+ */
+class SketchPlugin_ConstraintDistanceHorizontal : public SketchPlugin_ConstraintDistance
+{
+public:
+ /// Distance constraint kind
+ inline static const std::string& ID()
+ {
+ static const std::string MY_CONSTRAINT_DISTANCE_ID("SketchConstraintDistanceHorizontal");
+ return MY_CONSTRAINT_DISTANCE_ID;
+ }
+
+ /// \brief Returns the kind of a feature
+ SKETCHPLUGIN_EXPORT virtual const std::string& getKind()
+ {
+ static std::string MY_KIND = SketchPlugin_ConstraintDistanceHorizontal::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);
+
+ /// Moves the feature
+ /// \param theDeltaX the delta for X coordinate is moved
+ /// \param theDeltaY the delta for Y coordinate is moved
+ SKETCHPLUGIN_EXPORT virtual void move(const double theDeltaX, const double theDeltaY);
+
+ /// 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);
+
+ /// \brief Use plugin manager for features creation
+ SketchPlugin_ConstraintDistanceHorizontal();
+
+protected:
+ /// Returns the current distance between the feature attributes
+ virtual double calculateCurrentDistance();
+
+private:
+ bool myFlyoutUpdate; ///< to avoid cyclic dependencies on automatic updates of flyout point
+};
+
+#endif
--- /dev/null
+// Copyright (C) 2014-20xx CEA/DEN, EDF R&D -->
+
+// File: SketchPlugin_ConstraintDistanceVertical.cpp
+// Created: 10 May 2017
+// Author: Artem ZHIDKOV
+
+#include <SketchPlugin_ConstraintDistanceVertical.h>
+
+#include <SketcherPrs_Tools.h>
+#include <SketcherPrs_Factory.h>
+
+#include <GeomAPI_Dir2d.h>
+#include <GeomAPI_XY.h>
+#include <GeomDataAPI_Point2D.h>
+
+#include <ModelAPI_AttributeDouble.h>
+
+const double tolerance = 1e-7;
+
+
+SketchPlugin_ConstraintDistanceVertical::SketchPlugin_ConstraintDistanceVertical()
+ : SketchPlugin_ConstraintDistance()
+{
+}
+
+//*************************************************************************************
+void SketchPlugin_ConstraintDistanceVertical::initAttributes()
+{
+ data()->addAttribute(SketchPlugin_Constraint::VALUE(), ModelAPI_AttributeDouble::typeId());
+ data()->addAttribute(SketchPlugin_Constraint::FLYOUT_VALUE_PNT(), GeomDataAPI_Point2D::typeId());
+ data()->addAttribute(SketchPlugin_Constraint::ENTITY_A(), ModelAPI_AttributeRefAttr::typeId());
+ data()->addAttribute(SketchPlugin_Constraint::ENTITY_B(), ModelAPI_AttributeRefAttr::typeId());
+}
+
+//*************************************************************************************
+void SketchPlugin_ConstraintDistanceVertical::execute()
+{
+ AttributeDoublePtr anAttrValue = real(SketchPlugin_Constraint::VALUE());
+ if (anAttrValue->isInitialized() || !areAttributesInitialized())
+ return;
+
+ double aDistance = calculateCurrentDistance();
+ anAttrValue->setValue(aDistance);
+}
+
+//*************************************************************************************
+AISObjectPtr SketchPlugin_ConstraintDistanceVertical::getAISObject(AISObjectPtr thePrevious)
+{
+ if (!sketch())
+ return thePrevious;
+
+ AISObjectPtr anAIS = SketcherPrs_Factory::lengthDimensionConstraint(this,
+ sketch()->coordinatePlane(),
+ thePrevious);
+ return anAIS;
+}
+
+//*************************************************************************************
+void SketchPlugin_ConstraintDistanceVertical::move(double theDeltaX, double theDeltaY)
+{
+ std::shared_ptr<ModelAPI_Data> aData = data();
+ if (!aData->isValid())
+ return;
+
+ // Recalculate a shift of flyout point in terms of local coordinates
+ std::shared_ptr<GeomAPI_XY> aDir(new GeomAPI_XY(theDeltaX, theDeltaY));
+ std::shared_ptr<GeomAPI_Ax3> aPlane = SketchPlugin_Sketch::plane(sketch());
+ std::shared_ptr<GeomDataAPI_Point2D> aPointA = SketcherPrs_Tools::getFeaturePoint(
+ data(), SketchPlugin_Constraint::ENTITY_A(), aPlane);
+ std::shared_ptr<GeomDataAPI_Point2D> aPointB = SketcherPrs_Tools::getFeaturePoint(
+ data(), SketchPlugin_Constraint::ENTITY_B(), aPlane);
+
+ if (!aPointA || !aPointB)
+ return;
+
+ std::shared_ptr<GeomAPI_XY> aStartPnt = aPointA->pnt()->xy();
+ std::shared_ptr<GeomAPI_XY> aEndPnt = aPointB->pnt()->xy();
+
+ std::shared_ptr<GeomAPI_Dir2d> aLineDir(new GeomAPI_Dir2d(aEndPnt->decreased(aStartPnt)));
+ double dX = aDir->dot(aLineDir->xy());
+ double dY = -aDir->cross(aLineDir->xy());
+
+ std::shared_ptr<GeomDataAPI_Point2D> aPoint = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
+ aData->attribute(SketchPlugin_Constraint::FLYOUT_VALUE_PNT()));
+ myFlyoutUpdate = true;
+ if (aPoint->isInitialized()) {
+ aPoint->setValue(aPoint->x() + dX, aPoint->y() + dY);
+ } else {
+ aPoint->setValue(dX, dY);
+ }
+ myFlyoutUpdate = false;
+}
+
+double SketchPlugin_ConstraintDistanceVertical::calculateCurrentDistance()
+{
+ std::shared_ptr<ModelAPI_Data> aData = data();
+ std::shared_ptr<GeomAPI_Ax3> aPlane = SketchPlugin_Sketch::plane(sketch());
+ std::shared_ptr<GeomDataAPI_Point2D> aPointA =
+ SketcherPrs_Tools::getFeaturePoint(aData, SketchPlugin_Constraint::ENTITY_A(), aPlane);
+ std::shared_ptr<GeomDataAPI_Point2D> aPointB =
+ SketcherPrs_Tools::getFeaturePoint(aData, SketchPlugin_Constraint::ENTITY_B(), aPlane);
+
+ return aPointB->y() - aPointA->y();
+}
+
+void SketchPlugin_ConstraintDistanceVertical::attributeChanged(const std::string& theID)
+{
+ if (theID == SketchPlugin_Constraint::ENTITY_A() ||
+ theID == SketchPlugin_Constraint::ENTITY_B())
+ {
+ AttributeDoublePtr aValueAttr = real(SketchPlugin_Constraint::VALUE());
+ if (!aValueAttr->isInitialized() && areAttributesInitialized()) {
+ // only if it is not initialized, try to compute the current value
+ double aDistance = calculateCurrentDistance();
+ aValueAttr->setValue(aDistance);
+ }
+ } else if (theID == SketchPlugin_Constraint::FLYOUT_VALUE_PNT() && !myFlyoutUpdate) {
+ myFlyoutUpdate = true;
+ // Recalculate flyout point in local coordinates of the distance constraint:
+ // the X coordinate is a length of projection of the flyout point on the
+ // line binding two distanced points
+ // or a line of projection of the distanced point onto the distanced segment
+ // the Y coordinate is a distance from the flyout point to the line
+ std::shared_ptr<GeomDataAPI_Point2D> aFlyoutAttr =
+ std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
+ attribute(SketchPlugin_Constraint::FLYOUT_VALUE_PNT()));
+ std::shared_ptr<GeomAPI_Pnt2d> aFlyoutPnt = aFlyoutAttr->pnt();
+
+ std::shared_ptr<GeomAPI_Ax3> aPlane = SketchPlugin_Sketch::plane(sketch());
+ std::shared_ptr<GeomDataAPI_Point2D> aPointA = SketcherPrs_Tools::getFeaturePoint(
+ data(), SketchPlugin_Constraint::ENTITY_A(), aPlane);
+ std::shared_ptr<GeomDataAPI_Point2D> aPointB = SketcherPrs_Tools::getFeaturePoint(
+ data(), SketchPlugin_Constraint::ENTITY_B(), aPlane);
+
+ std::shared_ptr<GeomAPI_XY> aStartPnt = aPointA->pnt()->xy();
+ std::shared_ptr<GeomAPI_XY> aEndPnt = aPointB->pnt()->xy();
+
+ if (aEndPnt->distance(aStartPnt) < tolerance)
+ return;
+
+ std::shared_ptr<GeomAPI_Dir2d> aLineDir(new GeomAPI_Dir2d(aEndPnt->decreased(aStartPnt)));
+ std::shared_ptr<GeomAPI_XY> aFlyoutDir = aFlyoutPnt->xy()->decreased(aStartPnt);
+
+ double X = aFlyoutDir->dot(aLineDir->xy());
+ double Y = -aFlyoutDir->cross(aLineDir->xy());
+ aFlyoutAttr->setValue(X, Y);
+ myFlyoutUpdate = false;
+ }
+}
--- /dev/null
+// Copyright (C) 2014-20xx CEA/DEN, EDF R&D -->
+
+// File: SketchPlugin_ConstraintDistanceVertical.h
+// Created: 10 May 2017
+// Author: Artem ZHIDKOV
+
+#ifndef SketchPlugin_ConstraintDistanceVertical_H_
+#define SketchPlugin_ConstraintDistanceVertical_H_
+
+#include <SketchPlugin.h>
+#include <SketchPlugin_ConstraintDistance.h>
+
+/** \class SketchPlugin_ConstraintDistanceVertical
+ * \ingroup Plugins
+ * \brief Feature for creation of a new constraint which defines a vertical distance between two points.
+ *
+ * This constraint has three attributes:
+ * SketchPlugin_Constraint::VALUE(), SketchPlugin_Constraint::ENTITY_A() and SketchPlugin_Constraint::ENTITY_B()
+ */
+class SketchPlugin_ConstraintDistanceVertical : public SketchPlugin_ConstraintDistance
+{
+public:
+ /// Distance constraint kind
+ inline static const std::string& ID()
+ {
+ static const std::string MY_CONSTRAINT_DISTANCE_ID("SketchConstraintDistanceVertical");
+ return MY_CONSTRAINT_DISTANCE_ID;
+ }
+
+ /// \brief Returns the kind of a feature
+ SKETCHPLUGIN_EXPORT virtual const std::string& getKind()
+ {
+ static std::string MY_KIND = SketchPlugin_ConstraintDistanceVertical::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);
+
+ /// Moves the feature
+ /// \param theDeltaX the delta for X coordinate is moved
+ /// \param theDeltaY the delta for Y coordinate is moved
+ SKETCHPLUGIN_EXPORT virtual void move(const double theDeltaX, const double theDeltaY);
+
+ /// 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);
+
+ /// \brief Use plugin manager for features creation
+ SketchPlugin_ConstraintDistanceVertical();
+
+protected:
+ /// Returns the current distance between the feature attributes
+ virtual double calculateCurrentDistance();
+
+private:
+ bool myFlyoutUpdate; ///< to avoid cyclic dependencies on automatic updates of flyout point
+};
+
+#endif
#include <SketchPlugin_ConstraintCoincidence.h>
#include <SketchPlugin_ConstraintCollinear.h>
#include <SketchPlugin_ConstraintDistance.h>
+#include <SketchPlugin_ConstraintDistanceHorizontal.h>
+#include <SketchPlugin_ConstraintDistanceVertical.h>
#include <SketchPlugin_ConstraintEqual.h>
#include <SketchPlugin_Fillet.h>
#include <SketchPlugin_ConstraintSplit.h>
return FeaturePtr(new SketchPlugin_ConstraintCollinear);
} else if (theFeatureID == SketchPlugin_ConstraintDistance::ID()) {
return FeaturePtr(new SketchPlugin_ConstraintDistance);
+ } else if (theFeatureID == SketchPlugin_ConstraintDistanceHorizontal::ID()) {
+ return FeaturePtr(new SketchPlugin_ConstraintDistanceHorizontal);
+ } else if (theFeatureID == SketchPlugin_ConstraintDistanceVertical::ID()) {
+ return FeaturePtr(new SketchPlugin_ConstraintDistanceVertical);
} else if (theFeatureID == SketchPlugin_ConstraintLength::ID()) {
return FeaturePtr(new SketchPlugin_ConstraintLength);
} else if (theFeatureID == SketchPlugin_ConstraintParallel::ID()) {
aMsg->setState(SketchPlugin_Line::ID(), aHasSketchPlane);
aMsg->setState(SketchPlugin_Circle::ID(), aHasSketchPlane);
aMsg->setState(SketchPlugin_Arc::ID(), aHasSketchPlane);
+ aMsg->setState(SketchPlugin_Ellipse::ID(), aHasSketchPlane);
aMsg->setState(SketchPlugin_Projection::ID(), aHasSketchPlane);
aMsg->setState(SketchPlugin_ConstraintCoincidence::ID(), aHasSketchPlane);
aMsg->setState(SketchPlugin_ConstraintCollinear::ID(), aHasSketchPlane);
aMsg->setState(SketchPlugin_Trim::ID(), aHasSketchPlane);
aMsg->setState(SketchPlugin_MacroArc::ID(), aHasSketchPlane);
aMsg->setState(SketchPlugin_MacroCircle::ID(), aHasSketchPlane);
+ aMsg->setState(SketchPlugin_ConstraintDistanceHorizontal::ID(), aHasSketchPlane);
+ aMsg->setState(SketchPlugin_ConstraintDistanceVertical::ID(), aHasSketchPlane);
// SketchRectangle is a python feature, so its ID is passed just as a string
aMsg->setState("SketchRectangle", aHasSketchPlane);
}
--- /dev/null
+from salome.shaper import model
+from SketchAPI import *
+import math
+
+TOLERANCE = 1.e-7
+
+model.begin()
+partSet = model.moduleDocument()
+Part_1 = model.addPart(partSet)
+Part_1_doc = Part_1.document()
+DistanceParam = model.addParameter(Part_1_doc, "distance", "10.")
+Sketch_1 = model.addSketch(Part_1_doc, model.defaultPlane("XOY"))
+SketchRectangle_1 = Sketch_1.addRectangle(20., 20., 70., 50.)
+[SketchLine_1, SketchLine_2, SketchLine_3, SketchLine_4] = SketchRectangle_1.lines()
+firstPoint = SketchAPI_Line(SketchLine_2).startPoint()
+secondPoint = SketchAPI_Line(SketchLine_3).endPoint()
+model.do()
+
+# =============================================================================
+# Test 1.
+# =============================================================================
+# horizontal distance constraint
+SketchConstraintDistanceHorizontal_1 = Sketch_1.setHorizontalDistance(firstPoint, secondPoint, "distance")
+model.do()
+
+# changing the parameter
+for param in range(-30, 31, 2):
+ DistanceParam.setValue(param)
+ model.do()
+ dist = secondPoint.x() - firstPoint.x()
+ assert math.fabs(dist - param) < TOLERANCE, "Incorrect horizontal distance {}, expected {}".format(dist, param)
+
+model.testNbSubFeatures(Sketch_1, "SketchLine", 4)
+model.testNbSubFeatures(Sketch_1, "SketchConstraintDistanceHorizontal", 1)
+
+# remove horizontal distance constraint
+Part_1_doc.removeFeature(SketchConstraintDistanceHorizontal_1.feature())
+model.do()
+
+# =============================================================================
+# Test 2.
+# =============================================================================
+# Vertical distance constraint
+SketchConstraintDistanceVertical_1 = Sketch_1.setVerticalDistance(firstPoint, secondPoint, "distance")
+model.do()
+
+# changing the parameter
+for param in range(-30, 31, 2):
+ DistanceParam.setValue(param)
+ model.do()
+ dist = secondPoint.y() - firstPoint.y()
+ assert math.fabs(dist - param) < TOLERANCE, "Incorrect vertical distance {}, expected {}".format(dist, param)
+
+model.testNbSubFeatures(Sketch_1, "SketchLine", 4)
+model.testNbSubFeatures(Sketch_1, "SketchConstraintDistanceVertical", 1)
+
+# remove verticel distance constraint
+Part_1_doc.removeFeature(SketchConstraintDistanceVertical_1.feature())
+model.do()
+
+# =============================================================================
+# Test 3.
+# =============================================================================
+# distance constraint
+SketchConstraintDistance_1 = Sketch_1.setDistance(firstPoint, secondPoint, "distance")
+model.do()
+
+# changing the parameter
+for param in range(-30, 31, 2):
+ DistanceParam.setValue(param)
+ model.do()
+ if param <= 0:
+ assert SketchConstraintDistance_1.feature().error() != '', "ERROR: Sketch should not be valid due to negative distance value"
+ else:
+ dist = model.distancePointPoint(firstPoint, secondPoint)
+ assert math.fabs(dist - math.fabs(param)) < TOLERANCE, "Incorrect distance {}, expected {}".format(dist, math.fabs(param))
+
+model.testNbSubFeatures(Sketch_1, "SketchLine", 4)
+model.testNbSubFeatures(Sketch_1, "SketchConstraintDistance", 1)
+# leave distance constraint alive
+
+model.end()
--- /dev/null
+"""
+ TestConstraintDistanceHorizontal.py
+ Unit test of SketchPlugin_ConstraintDistanceHorizontal class
+
+ SketchPlugin_ConstraintDistanceHorizontal
+ static const std::string MY_CONSTRAINT_DISTANCE_ID("SketchConstraintDistance");
+ data()->addAttribute(SketchPlugin_Constraint::VALUE(), ModelAPI_AttributeDouble::typeId());
+ data()->addAttribute(SketchPlugin_Constraint::FLYOUT_VALUE_PNT(), GeomDataAPI_Point2D::typeId());
+ data()->addAttribute(SketchPlugin_Constraint::ENTITY_A(), ModelAPI_AttributeRefAttr::typeId());
+ data()->addAttribute(SketchPlugin_Constraint::ENTITY_B(), ModelAPI_AttributeRefAttr::typeId());
+"""
+
+from GeomDataAPI import *
+from ModelAPI import *
+import math
+from salome.shaper import model
+
+#=========================================================================
+# Initialization of the test
+#=========================================================================
+
+__updated__ = "2017-05-10"
+
+
+def horizontalDistance(point1, point2):
+ """
+ subroutine to calculate signed distance between two points
+ """
+ return point2.x() - point1.x()
+
+aSession = ModelAPI_Session.get()
+aDocument = aSession.moduleDocument()
+#=========================================================================
+# Creation of a sketch
+#=========================================================================
+aSession.startOperation()
+aSketchCommonFeature = aDocument.addFeature("Sketch")
+aSketchFeature = featureToCompositeFeature(aSketchCommonFeature)
+origin = geomDataAPI_Point(aSketchFeature.attribute("Origin"))
+origin.setValue(0, 0, 0)
+dirx = geomDataAPI_Dir(aSketchFeature.attribute("DirX"))
+dirx.setValue(1, 0, 0)
+norm = geomDataAPI_Dir(aSketchFeature.attribute("Norm"))
+norm.setValue(0, 0, 1)
+aSession.finishOperation()
+#=========================================================================
+# Create two movable and one fixed point
+#=========================================================================
+aSession.startOperation()
+aPoint1 = aSketchFeature.addFeature("SketchPoint")
+aPoint1Coords = geomDataAPI_Point2D(aPoint1.attribute("PointCoordinates"))
+aPoint1Coords.setValue(50., 50.)
+aSession.finishOperation()
+aSession.startOperation()
+aPoint2 = aSketchFeature.addFeature("SketchPoint")
+aPoint2Coords = geomDataAPI_Point2D(aPoint2.attribute("PointCoordinates"))
+aPoint2Coords.setValue(70., 70.)
+aSession.finishOperation()
+aSession.startOperation()
+anOriginResult = modelAPI_Result(aDocument.objectByName("Construction", "Origin"))
+anOriginShape = anOriginResult.shape()
+anExtPoint = aSketchFeature.addFeature("SketchPoint")
+anExtCoords = geomDataAPI_Point2D(anExtPoint.attribute("PointCoordinates"))
+anExtCoords.setValue(0., 0.)
+anExtPoint.selection("External").setValue(anOriginResult, anOriginShape)
+aSession.finishOperation()
+assert (model.dof(aSketchFeature) == 4)
+
+#=========================================================================
+# Create a constraint to keep horizontal distance between movable points
+#=========================================================================
+DISTANCE1 = 25.
+aSession.startOperation()
+aHDist1 = aSketchFeature.addFeature("SketchConstraintDistanceHorizontal")
+aDistance = aHDist1.real("ConstraintValue")
+refattrA = aHDist1.refattr("ConstraintEntityA")
+refattrB = aHDist1.refattr("ConstraintEntityB")
+assert (not aDistance.isInitialized())
+assert (not refattrA.isInitialized())
+assert (not refattrB.isInitialized())
+refattrA.setObject(aPoint1.lastResult())
+refattrB.setObject(aPoint2.lastResult())
+aSession.finishOperation()
+assert (model.dof(aSketchFeature) == 3)
+# set flyout point then abort operation, after that check the Distance is correct
+aSession.startOperation()
+aFlyoutPoint = geomDataAPI_Point2D(aHDist1.attribute("ConstraintFlyoutValuePnt"))
+aFlyoutPoint.setValue(50.0, 100.0)
+aSession.abortOperation()
+assert (refattrA.isInitialized())
+assert (refattrB.isInitialized())
+assert (aDistance.isInitialized())
+aSession.startOperation()
+aDistance.setValue(DISTANCE1)
+aSession.finishOperation()
+assert math.fabs(horizontalDistance(aPoint1Coords, aPoint2Coords) - DISTANCE1) < 1.e-5, "Distance values are different: {0} != {1}".format(horizontalDistance(aPoint1Coords, aPoint2Coords), DISTANCE1)
+assert (model.dof(aSketchFeature) == 3)
+#=========================================================================
+# Change a distance value
+#=========================================================================
+d = DISTANCE1 + 20.
+dStep = -5.
+while d >= -30.:
+ aSession.startOperation()
+ DISTANCE1 = d
+ aDistance.setValue(DISTANCE1)
+ aSession.finishOperation()
+ assert math.fabs(horizontalDistance(aPoint1Coords, aPoint2Coords) - DISTANCE1) < 1.e-5, "Distance values are different: {0} != {1}".format(horizontalDistance(aPoint1Coords, aPoint2Coords), DISTANCE1)
+ d += dStep
+assert (model.dof(aSketchFeature) == 3)
+
+#=========================================================================
+# Create a constraint to keep horizontal distance between fixed and movable points
+#=========================================================================
+DISTANCE2 = 50.
+aSession.startOperation()
+aHDist2 = aSketchFeature.addFeature("SketchConstraintDistanceHorizontal")
+aDistance = aHDist2.real("ConstraintValue")
+refattrA = aHDist2.refattr("ConstraintEntityA")
+refattrB = aHDist2.refattr("ConstraintEntityB")
+assert (not aDistance.isInitialized())
+assert (not refattrA.isInitialized())
+assert (not refattrB.isInitialized())
+refattrA.setObject(anExtPoint.lastResult())
+refattrB.setAttr(aPoint1Coords)
+aDistance.setValue(DISTANCE2)
+aSession.finishOperation()
+assert math.fabs(horizontalDistance(anExtCoords, aPoint1Coords) - DISTANCE2) < 1.e-5, "Distance values are different: {0} != {1}".format(horizontalDistance(anExtCoords, aPoint1Coords), DISTANCE2)
+assert math.fabs(aPoint1Coords.x() - DISTANCE2) < 1.e-5, "Wrong point coordinates ({}, {}), expected x = {}".format(aPoint1Coords.x(), aPoint1Coords.y(), DISTANCE2)
+assert (model.dof(aSketchFeature) == 2)
+#=========================================================================
+# Change a distance value (check previous constraint is applied too)
+#=========================================================================
+d = DISTANCE2
+dStep = -5.
+while d >= -50.:
+ aSession.startOperation()
+ DISTANCE2 = d
+ aDistance.setValue(DISTANCE2)
+ aSession.finishOperation()
+ assert math.fabs(horizontalDistance(anExtCoords, aPoint1Coords) - DISTANCE2) < 1.e-5, "Distance values are different: {0} != {1}".format(horizontalDistance(anExtCoords, aPoint1Coords), DISTANCE2)
+ assert math.fabs(aPoint1Coords.x() - DISTANCE2) < 1.e-5, "Wrong point coordinates ({}, {}), expected x = {}".format(aPoint1Coords.x(), aPoint1Coords.y(), DISTANCE2)
+ assert math.fabs(horizontalDistance(aPoint1Coords, aPoint2Coords) - DISTANCE1) < 1.e-5, "Distance values are different: {0} != {1}".format(horizontalDistance(aPoint1Coords, aPoint2Coords), DISTANCE1)
+ d += dStep
+assert (model.dof(aSketchFeature) == 2)
+
+#=========================================================================
+# Remove first distance
+#=========================================================================
+aStoredCoords = [aPoint2Coords.x(), aPoint2Coords.y()]
+aSession.startOperation()
+aDocument.removeFeature(aHDist1)
+aSession.finishOperation()
+assert (model.dof(aSketchFeature) == 3)
+aSession.startOperation()
+DISTANCE2 = 20.
+aDistance.setValue(DISTANCE2)
+aSession.finishOperation()
+assert math.fabs(horizontalDistance(anExtCoords, aPoint1Coords) - DISTANCE2) < 1.e-5, "Distance values are different: {0} != {1}".format(horizontalDistance(anExtCoords, aPoint1Coords), DISTANCE2)
+assert math.fabs(aPoint1Coords.x() - DISTANCE2) < 1.e-5, "Wrong point coordinates ({}, {}), expected x = {}".format(aPoint1Coords.x(), aPoint1Coords.y(), DISTANCE2)
+assert aPoint2Coords.x() == aStoredCoords[0] and aPoint2Coords.y() == aStoredCoords[1]
+
+#=========================================================================
+# Create line and set horizontal distance between line boundaries
+#=========================================================================
+aSession.startOperation()
+aLine = aSketchFeature.addFeature("SketchLine")
+aStartPoint = geomDataAPI_Point2D(aLine.attribute("StartPoint"))
+aEndPoint = geomDataAPI_Point2D(aLine.attribute("EndPoint"))
+aStartPoint.setValue(50., 0.)
+aEndPoint.setValue(100., 20.)
+aSession.finishOperation()
+assert (model.dof(aSketchFeature) == 7)
+
+DISTANCE3 = 50.
+aSession.startOperation()
+aHDist3 = aSketchFeature.addFeature("SketchConstraintDistanceHorizontal")
+aDistance = aHDist3.real("ConstraintValue")
+refattrA = aHDist3.refattr("ConstraintEntityA")
+refattrB = aHDist3.refattr("ConstraintEntityB")
+assert (not aDistance.isInitialized())
+assert (not refattrA.isInitialized())
+assert (not refattrB.isInitialized())
+refattrA.setAttr(aStartPoint)
+refattrB.setAttr(aEndPoint)
+aDistance.setValue(DISTANCE3)
+aSession.finishOperation()
+assert math.fabs(horizontalDistance(aStartPoint, aEndPoint) - DISTANCE3) < 1.e-5, "Distance values are different: {0} != {1}".format(horizontalDistance(aStartPoint, aEndPoint), DISTANCE3)
+assert (model.dof(aSketchFeature) == 6)
+#=========================================================================
+# Change a distance value
+#=========================================================================
+d = DISTANCE3
+dStep = -5.
+while d >= -50.:
+ aSession.startOperation()
+ DISTANCE3 = d
+ aDistance.setValue(DISTANCE3)
+ aSession.finishOperation()
+ assert math.fabs(horizontalDistance(aStartPoint, aEndPoint) - DISTANCE3) < 1.e-5, "Distance values are different: {0} != {1}".format(horizontalDistance(aStartPoint, aEndPoint), DISTANCE3)
+ d += dStep
+assert (model.dof(aSketchFeature) == 6)
+
+#=========================================================================
+# End of test
+#=========================================================================
+
+assert(model.checkPythonDump())
--- /dev/null
+"""
+ TestConstraintDistanceVertical.py
+ Unit test of SketchPlugin_ConstraintDistanceVertical class
+
+ SketchPlugin_ConstraintDistanceVertical
+ static const std::string MY_CONSTRAINT_DISTANCE_ID("SketchConstraintDistance");
+ data()->addAttribute(SketchPlugin_Constraint::VALUE(), ModelAPI_AttributeDouble::typeId());
+ data()->addAttribute(SketchPlugin_Constraint::FLYOUT_VALUE_PNT(), GeomDataAPI_Point2D::typeId());
+ data()->addAttribute(SketchPlugin_Constraint::ENTITY_A(), ModelAPI_AttributeRefAttr::typeId());
+ data()->addAttribute(SketchPlugin_Constraint::ENTITY_B(), ModelAPI_AttributeRefAttr::typeId());
+"""
+
+from GeomDataAPI import *
+from ModelAPI import *
+import math
+from salome.shaper import model
+
+#=========================================================================
+# Initialization of the test
+#=========================================================================
+
+__updated__ = "2017-05-10"
+
+
+def verticalDistance(point1, point2):
+ """
+ subroutine to calculate signed distance between two points
+ """
+ return point2.y() - point1.y()
+
+aSession = ModelAPI_Session.get()
+aDocument = aSession.moduleDocument()
+#=========================================================================
+# Creation of a sketch
+#=========================================================================
+aSession.startOperation()
+aSketchCommonFeature = aDocument.addFeature("Sketch")
+aSketchFeature = featureToCompositeFeature(aSketchCommonFeature)
+origin = geomDataAPI_Point(aSketchFeature.attribute("Origin"))
+origin.setValue(0, 0, 0)
+dirx = geomDataAPI_Dir(aSketchFeature.attribute("DirX"))
+dirx.setValue(1, 0, 0)
+norm = geomDataAPI_Dir(aSketchFeature.attribute("Norm"))
+norm.setValue(0, 0, 1)
+aSession.finishOperation()
+#=========================================================================
+# Create two movable and one fixed point
+#=========================================================================
+aSession.startOperation()
+aPoint1 = aSketchFeature.addFeature("SketchPoint")
+aPoint1Coords = geomDataAPI_Point2D(aPoint1.attribute("PointCoordinates"))
+aPoint1Coords.setValue(50., 50.)
+aSession.finishOperation()
+aSession.startOperation()
+aPoint2 = aSketchFeature.addFeature("SketchPoint")
+aPoint2Coords = geomDataAPI_Point2D(aPoint2.attribute("PointCoordinates"))
+aPoint2Coords.setValue(70., 70.)
+aSession.finishOperation()
+aSession.startOperation()
+anOriginResult = modelAPI_Result(aDocument.objectByName("Construction", "Origin"))
+anOriginShape = anOriginResult.shape()
+anExtPoint = aSketchFeature.addFeature("SketchPoint")
+anExtCoords = geomDataAPI_Point2D(anExtPoint.attribute("PointCoordinates"))
+anExtCoords.setValue(0., 0.)
+anExtPoint.selection("External").setValue(anOriginResult, anOriginShape)
+aSession.finishOperation()
+assert (model.dof(aSketchFeature) == 4)
+
+#=========================================================================
+# Create a constraint to keep vertical distance between movable points
+#=========================================================================
+DISTANCE1 = 25.
+aSession.startOperation()
+aVDist1 = aSketchFeature.addFeature("SketchConstraintDistanceVertical")
+aDistance = aVDist1.real("ConstraintValue")
+refattrA = aVDist1.refattr("ConstraintEntityA")
+refattrB = aVDist1.refattr("ConstraintEntityB")
+assert (not aDistance.isInitialized())
+assert (not refattrA.isInitialized())
+assert (not refattrB.isInitialized())
+refattrA.setObject(aPoint1.lastResult())
+refattrB.setObject(aPoint2.lastResult())
+aSession.finishOperation()
+assert (model.dof(aSketchFeature) == 3)
+# set flyout point then abort operation, after that check the Distance is correct
+aSession.startOperation()
+aFlyoutPoint = geomDataAPI_Point2D(aVDist1.attribute("ConstraintFlyoutValuePnt"))
+aFlyoutPoint.setValue(50.0, 100.0)
+aSession.abortOperation()
+assert (refattrA.isInitialized())
+assert (refattrB.isInitialized())
+assert (aDistance.isInitialized())
+aSession.startOperation()
+aDistance.setValue(DISTANCE1)
+aSession.finishOperation()
+assert math.fabs(verticalDistance(aPoint1Coords, aPoint2Coords) - DISTANCE1) < 1.e-5, "Distance values are different: {0} != {1}".format(verticalDistance(aPoint1Coords, aPoint2Coords), DISTANCE1)
+assert (model.dof(aSketchFeature) == 3)
+#=========================================================================
+# Change a distance value
+#=========================================================================
+d = DISTANCE1 + 20.
+dStep = -5.
+while d >= -30.:
+ aSession.startOperation()
+ DISTANCE1 = d
+ aDistance.setValue(DISTANCE1)
+ aSession.finishOperation()
+ assert math.fabs(verticalDistance(aPoint1Coords, aPoint2Coords) - DISTANCE1) < 1.e-5, "Distance values are different: {0} != {1}".format(verticalDistance(aPoint1Coords, aPoint2Coords), DISTANCE1)
+ d += dStep
+assert (model.dof(aSketchFeature) == 3)
+
+#=========================================================================
+# Create a constraint to keep vertical distance between fixed and movable points
+#=========================================================================
+DISTANCE2 = 50.
+aSession.startOperation()
+aVDist2 = aSketchFeature.addFeature("SketchConstraintDistanceVertical")
+aDistance = aVDist2.real("ConstraintValue")
+refattrA = aVDist2.refattr("ConstraintEntityA")
+refattrB = aVDist2.refattr("ConstraintEntityB")
+assert (not aDistance.isInitialized())
+assert (not refattrA.isInitialized())
+assert (not refattrB.isInitialized())
+refattrA.setObject(anExtPoint.lastResult())
+refattrB.setAttr(aPoint1Coords)
+aDistance.setValue(DISTANCE2)
+aSession.finishOperation()
+assert math.fabs(verticalDistance(anExtCoords, aPoint1Coords) - DISTANCE2) < 1.e-5, "Distance values are different: {0} != {1}".format(verticalDistance(anExtCoords, aPoint1Coords), DISTANCE2)
+assert math.fabs(aPoint1Coords.y() - DISTANCE2) < 1.e-5, "Wrong point coordinates ({}, {}), expected y = {}".format(aPoint1Coords.x(), aPoint1Coords.y(), DISTANCE2)
+assert (model.dof(aSketchFeature) == 2)
+#=========================================================================
+# Change a distance value (check previous constraint is applied too)
+#=========================================================================
+d = DISTANCE2
+dStep = -5.
+while d >= -50.:
+ aSession.startOperation()
+ DISTANCE2 = d
+ aDistance.setValue(DISTANCE2)
+ aSession.finishOperation()
+ assert math.fabs(verticalDistance(anExtCoords, aPoint1Coords) - DISTANCE2) < 1.e-5, "Distance values are different: {0} != {1}".format(verticalDistance(anExtCoords, aPoint1Coords), DISTANCE2)
+ assert math.fabs(aPoint1Coords.y() - DISTANCE2) < 1.e-5, "Wrong point coordinates ({}, {}), expected y = {}".format(aPoint1Coords.x(), aPoint1Coords.y(), DISTANCE2)
+ assert math.fabs(verticalDistance(aPoint1Coords, aPoint2Coords) - DISTANCE1) < 1.e-5, "Distance values are different: {0} != {1}".format(verticalDistance(aPoint1Coords, aPoint2Coords), DISTANCE1)
+ d += dStep
+assert (model.dof(aSketchFeature) == 2)
+
+#=========================================================================
+# Remove first distance
+#=========================================================================
+aStoredCoords = [aPoint2Coords.x(), aPoint2Coords.y()]
+aSession.startOperation()
+aDocument.removeFeature(aVDist1)
+aSession.finishOperation()
+assert (model.dof(aSketchFeature) == 3)
+aSession.startOperation()
+DISTANCE2 = 20.
+aDistance.setValue(DISTANCE2)
+aSession.finishOperation()
+assert math.fabs(verticalDistance(anExtCoords, aPoint1Coords) - DISTANCE2) < 1.e-5, "Distance values are different: {0} != {1}".format(verticalDistance(anExtCoords, aPoint1Coords), DISTANCE2)
+assert math.fabs(aPoint1Coords.y() - DISTANCE2) < 1.e-5, "Wrong point coordinates ({}, {}), expected y = {}".format(aPoint1Coords.x(), aPoint1Coords.y(), DISTANCE2)
+assert aPoint2Coords.x() == aStoredCoords[0] and aPoint2Coords.y() == aStoredCoords[1]
+
+#=========================================================================
+# Create line and set vertical distance between line boundaries
+#=========================================================================
+aSession.startOperation()
+aLine = aSketchFeature.addFeature("SketchLine")
+aStartPoint = geomDataAPI_Point2D(aLine.attribute("StartPoint"))
+aEndPoint = geomDataAPI_Point2D(aLine.attribute("EndPoint"))
+aStartPoint.setValue(50., 0.)
+aEndPoint.setValue(100., 20.)
+aSession.finishOperation()
+assert (model.dof(aSketchFeature) == 7)
+
+DISTANCE3 = 50.
+aSession.startOperation()
+aVDist3 = aSketchFeature.addFeature("SketchConstraintDistanceVertical")
+aDistance = aVDist3.real("ConstraintValue")
+refattrA = aVDist3.refattr("ConstraintEntityA")
+refattrB = aVDist3.refattr("ConstraintEntityB")
+assert (not aDistance.isInitialized())
+assert (not refattrA.isInitialized())
+assert (not refattrB.isInitialized())
+refattrA.setAttr(aStartPoint)
+refattrB.setAttr(aEndPoint)
+aDistance.setValue(DISTANCE3)
+aSession.finishOperation()
+assert math.fabs(verticalDistance(aStartPoint, aEndPoint) - DISTANCE3) < 1.e-5, "Distance values are different: {0} != {1}".format(verticalDistance(aStartPoint, aEndPoint), DISTANCE3)
+assert (model.dof(aSketchFeature) == 6)
+#=========================================================================
+# Change a distance value
+#=========================================================================
+d = DISTANCE3
+dStep = -5.
+while d >= -50.:
+ aSession.startOperation()
+ DISTANCE3 = d
+ aDistance.setValue(DISTANCE3)
+ aSession.finishOperation()
+ assert math.fabs(verticalDistance(aStartPoint, aEndPoint) - DISTANCE3) < 1.e-5, "Distance values are different: {0} != {1}".format(verticalDistance(aStartPoint, aEndPoint), DISTANCE3)
+ d += dStep
+assert (model.dof(aSketchFeature) == 6)
+
+#=========================================================================
+# End of test
+#=========================================================================
+
+assert(model.checkPythonDump())
SketchEllipse SketchMacroEllipse
SketchRectangle
SketchProjection
- SketchConstraintLength SketchConstraintRadius SketchConstraintDistance
+ SketchConstraintLength SketchConstraintRadius SketchConstraintDistance SketchConstraintDistanceHorizontal SketchConstraintDistanceVertical
SketchConstraintParallel SketchConstraintPerpendicular
SketchConstraintRigid SketchConstraintHorizontal SketchConstraintVertical
SketchConstraintEqual SketchConstraintTangent
<validator id="PartSet_DistanceSelection"/>
</feature>
- <!-- SketchConstraintLength -->
+ <!-- SketchConstraintDistanceHorizontal -->
+ <feature
+ id="SketchConstraintDistanceHorizontal"
+ title="Horizontal Distance"
+ tooltip="Set horizontal distance between two points"
+ icon="icons/Sketch/distance_h.png">
+ <label title="Select points for distance definition."/>
+ <sketch_shape_selector
+ id="ConstraintEntityA"
+ label="First point"
+ tooltip="Select point."
+ shape_types="vertex">
+ <validator id="SketchPlugin_ExternalValidator" parameters="ConstraintEntityB"/>
+ <validator id="PartSet_DifferentObjects"/>
+ <validator id="GeomValidators_ShapeType" parameters="vertex"/>
+ </sketch_shape_selector>
+ <sketch_shape_selector
+ id="ConstraintEntityB"
+ label="Second point"
+ tooltip="Select point."
+ shape_types="vertex">
+ <validator id="PartSet_DifferentObjects"/>
+ <validator id="SketchPlugin_ExternalValidator" parameters="ConstraintEntityA"/>
+ <validator id="GeomValidators_ShapeType" parameters="vertex"/>
+ </sketch_shape_selector>
+ <sketch-2dpoint_flyout_selector id="ConstraintFlyoutValuePnt" default="computed" internal="1" obligatory="0"/>
+
+ <doublevalue_editor label="Value" tooltip="Distance" id="ConstraintValue" default="computed"/>
+
+ <validator id="PartSet_DistanceSelection"/>
+ </feature>
+
+ <!-- SketchConstraintDistanceVertical -->
+ <feature
+ id="SketchConstraintDistanceVertical"
+ title="Vertical Distance"
+ tooltip="Set vertical distance between two points"
+ icon="icons/Sketch/distance_v.png">
+ <label title="Select points for distance definition."/>
+ <sketch_shape_selector
+ id="ConstraintEntityA"
+ label="First point"
+ tooltip="Select point."
+ shape_types="vertex">
+ <validator id="SketchPlugin_ExternalValidator" parameters="ConstraintEntityB"/>
+ <validator id="PartSet_DifferentObjects"/>
+ <validator id="GeomValidators_ShapeType" parameters="vertex"/>
+ </sketch_shape_selector>
+ <sketch_shape_selector
+ id="ConstraintEntityB"
+ label="Second point"
+ tooltip="Select point."
+ shape_types="vertex">
+ <validator id="PartSet_DifferentObjects"/>
+ <validator id="SketchPlugin_ExternalValidator" parameters="ConstraintEntityA"/>
+ <validator id="GeomValidators_ShapeType" parameters="vertex"/>
+ </sketch_shape_selector>
+ <sketch-2dpoint_flyout_selector id="ConstraintFlyoutValuePnt" default="computed" internal="1" obligatory="0"/>
+
+ <doublevalue_editor label="Value" tooltip="Distance" id="ConstraintValue" default="computed"/>
+
+ <validator id="PartSet_DistanceSelection"/>
+ </feature>
+
+ <!-- SketchConstraintLength -->
<feature id="SketchConstraintLength" title="Length" tooltip="Set fixed length of a line segment" icon="icons/Sketch/length.png">
<label title="Select a line on which to calculate length" tooltip="Select a line on which to calculate length"/>
<shape_selector id="ConstraintEntityA" label="Line" tooltip="Select a line" shape_types="edge" >
CONSTRAINT_DISTANCE, // base distance if we don't know the measured objects yet
CONSTRAINT_PT_PT_DISTANCE,
CONSTRAINT_PT_LINE_DISTANCE,
+ CONSTRAINT_HORIZONTAL_DISTANCE,
+ CONSTRAINT_VERTICAL_DISTANCE,
CONSTRAINT_RADIUS,
CONSTRAINT_ANGLE,
CONSTRAINT_FIXED,
#include <SketchPlugin_ConstraintCoincidence.h>
#include <SketchPlugin_ConstraintCollinear.h>
#include <SketchPlugin_ConstraintDistance.h>
+#include <SketchPlugin_ConstraintDistanceHorizontal.h>
+#include <SketchPlugin_ConstraintDistanceVertical.h>
#include <SketchPlugin_ConstraintEqual.h>
#include <SketchPlugin_ConstraintLength.h>
#include <SketchPlugin_ConstraintMiddle.h>
createConstraintDistancePointLine(std::shared_ptr<PlaneGCSSolver_ScalarWrapper> theValue,
std::shared_ptr<PlaneGCSSolver_PointWrapper> thePoint,
std::shared_ptr<PlaneGCSSolver_EdgeWrapper> theEntity);
+static ConstraintWrapperPtr
+ createConstraintHVDistance(const SketchSolver_ConstraintType& theType,
+ std::shared_ptr<PlaneGCSSolver_ScalarWrapper> theValue,
+ std::shared_ptr<PlaneGCSSolver_PointWrapper> thePoint1,
+ std::shared_ptr<PlaneGCSSolver_PointWrapper> thePoint2);
static ConstraintWrapperPtr
createConstraintRadius(std::shared_ptr<PlaneGCSSolver_ScalarWrapper> theValue,
std::shared_ptr<PlaneGCSSolver_EdgeWrapper> theEntity);
return SolverConstraintPtr(new SketchSolver_ConstraintCoincidence(theConstraint));
} else if (theConstraint->getKind() == SketchPlugin_ConstraintCollinear::ID()) {
return SolverConstraintPtr(new SketchSolver_ConstraintCollinear(theConstraint));
- } else if (theConstraint->getKind() == SketchPlugin_ConstraintDistance::ID()) {
+ } else if (theConstraint->getKind() == SketchPlugin_ConstraintDistance::ID() ||
+ theConstraint->getKind() == SketchPlugin_ConstraintDistanceHorizontal::ID() ||
+ theConstraint->getKind() == SketchPlugin_ConstraintDistanceVertical::ID()) {
return SolverConstraintPtr(new SketchSolver_ConstraintDistance(theConstraint));
} else if (theConstraint->getKind() == SketchPlugin_ConstraintEqual::ID()) {
return SolverConstraintPtr(new SketchSolver_ConstraintEqual(theConstraint));
aPoint1,
GCS_EDGE_WRAPPER(theEntity1));
break;
+ case CONSTRAINT_HORIZONTAL_DISTANCE:
+ case CONSTRAINT_VERTICAL_DISTANCE:
+ aResult = createConstraintHVDistance(theType, GCS_SCALAR_WRAPPER(theValue), aPoint1, aPoint2);
+ break;
case CONSTRAINT_RADIUS:
aResult = createConstraintRadius(GCS_SCALAR_WRAPPER(theValue),
GCS_EDGE_WRAPPER(theEntity1));
return aResult;
}
+ConstraintWrapperPtr createConstraintHVDistance(
+ const SketchSolver_ConstraintType& theType,
+ std::shared_ptr<PlaneGCSSolver_ScalarWrapper> theValue,
+ std::shared_ptr<PlaneGCSSolver_PointWrapper> thePoint1,
+ std::shared_ptr<PlaneGCSSolver_PointWrapper> thePoint2)
+{
+ GCSPointPtr aPoint1 = thePoint1->point();
+ GCSPointPtr aPoint2 = thePoint2->point();
+
+ double *aParam1, *aParam2;
+ if (theType == CONSTRAINT_HORIZONTAL_DISTANCE) {
+ aParam1 = aPoint1->x;
+ aParam2 = aPoint2->x;
+ } else if (theType == CONSTRAINT_VERTICAL_DISTANCE) {
+ aParam1 = aPoint1->y;
+ aParam2 = aPoint2->y;
+ }
+
+ GCSConstraintPtr aNewConstr(new GCS::ConstraintDifference(aParam1, aParam2, theValue->scalar()));
+
+ std::shared_ptr<PlaneGCSSolver_ConstraintWrapper> aResult(
+ new PlaneGCSSolver_ConstraintWrapper(aNewConstr, theType));
+ aResult->setValueParameter(theValue);
+ return aResult;
+}
+
ConstraintWrapperPtr createConstraintRadius(
std::shared_ptr<PlaneGCSSolver_ScalarWrapper> theValue,
std::shared_ptr<PlaneGCSSolver_EdgeWrapper> theEntity)
ConstraintWrapperPtr aNewConstraint = PlaneGCSSolver_Tools::createConstraint(
myBaseConstraint, aConstrType,
aValue, anAttributes[0], anAttributes[1], anAttributes[2], anAttributes[3]);
+ if (!aNewConstraint) {
+ myErrorMsg = SketchSolver_Error::WRONG_CONSTRAINT_TYPE();
+ return;
+ }
myStorage->addConstraint(myBaseConstraint, aNewConstraint);
adjustConstraint();
#include <SketchSolver_Error.h>
#include <SketchSolver_Manager.h>
+#include <SketchPlugin_ConstraintDistanceHorizontal.h>
+#include <SketchPlugin_ConstraintDistanceVertical.h>
+
#include <GeomAPI_Dir2d.h>
#include <GeomAPI_Lin2d.h>
#include <GeomAPI_Pnt2d.h>
return;
}
- if (theAttributes[1])
- myType = CONSTRAINT_PT_PT_DISTANCE;
- else if (theAttributes[2] && theAttributes[2]->type() == ENTITY_LINE)
+ 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;
+ } else if (theAttributes[2] && theAttributes[2]->type() == ENTITY_LINE)
myType = CONSTRAINT_PT_LINE_DISTANCE;
else
theAttributes.clear();
static const std::string MY_ERROR_VALUE("Caution: SolveSpace crash! Constraints are wrong");
return MY_ERROR_VALUE;
}
+ /// Constraint has wrong type
+ inline static const std::string& WRONG_CONSTRAINT_TYPE()
+ {
+ static const std::string MY_ERROR_VALUE("Unsupported type of constraint");
+ return MY_ERROR_VALUE;
+ }
};
#endif
#include <SketchPlugin_Constraint.h>
#include <SketchPlugin_ConstraintLength.h>
#include <SketchPlugin_ConstraintDistance.h>
+#include <SketchPlugin_ConstraintDistanceHorizontal.h>
+#include <SketchPlugin_ConstraintDistanceVertical.h>
#include <SketchPlugin_Line.h>
#include <SketchPlugin_Point.h>
#include <SketchPlugin_Circle.h>
thePnt2 = thePlane->to3D(aEndPoint->x(), aEndPoint->y())->impl<gp_Pnt>();
return true;
- } else if (theConstraint->getKind() == SketchPlugin_ConstraintDistance::ID()) {
+ } else if (theConstraint->getKind() == SketchPlugin_ConstraintDistance::ID() ||
+ theConstraint->getKind() == SketchPlugin_ConstraintDistanceHorizontal::ID() ||
+ theConstraint->getKind() == SketchPlugin_ConstraintDistanceVertical::ID()) {
// The constraint is distance
std::shared_ptr<GeomDataAPI_Point2D> aPoint_A = SketcherPrs_Tools::getFeaturePoint(
aData, SketchPlugin_Constraint::ENTITY_A(), thePlane);