if (!myIsInitialized) {
// create attribute: not initialized by value yet, just zero
myCoords = TDataStd_RealArray::Set(myLab, 0, 2);
+ myIsInitialized = true;
}
}
double aValues[3] = {anAttr->x(), anAttr->y(), anAttr->z()};
dumpArray(aResult, aValues, 3);
} else if (aType == GeomDataAPI_Dir::typeId()) {
+ if (theAttr->id() == "DistanceDirection")
+ return "__notcase__";
AttributeDirPtr anAttr = std::dynamic_pointer_cast<GeomDataAPI_Dir>(theAttr);
double aValues[3] = {anAttr->x(), anAttr->y(), anAttr->z()};
dumpArray(aResult, aValues, 3);
void setSpinValue(ModuleBase_ParamSpinBox* theSpin, double theValue)
{
- if (fabs(theSpin->value() - theValue) < tolerance)
+ if (!theSpin->text().isEmpty() && fabs(theSpin->value() - theValue) < tolerance)
return;
bool isBlocked = theSpin->blockSignals(true);
theSpin->setValue(theValue);
TestConstraintDistanceBehavior.py
TestConstraintDistanceHorizontal.py
TestConstraintDistanceVertical.py
+ TestConstraintDistanceZero.py
+ TestConstraintDistanceHorizontalZero.py
+ TestConstraintDistanceVerticalZero.py
TestConstraintEqual.py
TestConstraintEqualEllipse.py
TestConstraintFixed.py
#include <GeomAPI_Pnt2d.h>
#include <GeomAPI_XY.h>
#include <GeomDataAPI_Point2D.h>
+#include <GeomDataAPI_Dir.h>
#include <ModelAPI_AttributeDouble.h>
#include <ModelAPI_AttributeInteger.h>
data()->addAttribute(SketchPlugin_ConstraintDistance::LOCATION_TYPE_ID(),
ModelAPI_AttributeInteger::typeId());
ModelAPI_Session::get()->validators()->registerNotObligatory(getKind(), LOCATION_TYPE_ID());
+
+ AttributePtr anAttr = data()->addAttribute(SketchPlugin_ConstraintDistance::DIRECTION_ID(),
+ GeomDataAPI_Dir::typeId());
+ anAttr->setIsArgument(false);
+ ModelAPI_Session::get()->validators()->registerNotObligatory(getKind(), DIRECTION_ID());
}
void SketchPlugin_ConstraintDistance::colorConfigInfo(std::string& theSection, std::string& theName,
return anAIS;
}
+static std::shared_ptr<GeomAPI_Lin2d> getLine(DataPtr theData, const std::string& theAttrName)
+{
+ FeaturePtr aLineFeature = SketcherPrs_Tools::getFeatureLine(theData, theAttrName);
+ if (!aLineFeature)
+ return GeomLine2dPtr();
+
+ std::shared_ptr<GeomDataAPI_Point2D> aStart = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
+ aLineFeature->attribute(SketchPlugin_Line::START_ID()));
+ std::shared_ptr<GeomDataAPI_Point2D> aEnd = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
+ aLineFeature->attribute(SketchPlugin_Line::END_ID()));
+
+ return GeomLine2dPtr(new GeomAPI_Lin2d(aStart->x(), aStart->y(), aEnd->x(), aEnd->y()));
+}
+
double SketchPlugin_ConstraintDistance::calculateCurrentDistance()
{
double aDistance = -1.;
std::shared_ptr<GeomDataAPI_Point2D> aPointB =
SketcherPrs_Tools::getFeaturePoint(aData, SketchPlugin_Constraint::ENTITY_B(), aPlane);
+ GeomPnt2dPtr aGeomPntA, aGeomPntB;
+ GeomLine2dPtr aLine;
if (aPointA.get() && aPointB.get()) { // both points
- aDistance = aPointA->pnt()->distance(aPointB->pnt());
+ aGeomPntA = aPointA->pnt();
+ aGeomPntB = aPointB->pnt();
} else {
- FeaturePtr aLineFeature;
- std::shared_ptr<SketchPlugin_Line> aLine;
if (!aPointA.get() && aPointB.get()) { //Line and point
- aLineFeature = SketcherPrs_Tools::getFeatureLine(aData, SketchPlugin_Constraint::ENTITY_A());
- aLine = std::dynamic_pointer_cast<SketchPlugin_Line>(aLineFeature);
- if (aLine.get()) {
- aDistance = aLine->distanceToPoint(aPointB->pnt());
- }
+ aLine = getLine(aData, SketchPlugin_Constraint::ENTITY_A());
+ aGeomPntB = aPointB->pnt();
+ aGeomPntA = aLine ? aLine->project(aGeomPntB) : GeomPnt2dPtr();
} else if (aPointA.get() && !aPointB.get()) { // Point and line
- aLineFeature = SketcherPrs_Tools::getFeatureLine(aData, SketchPlugin_Constraint::ENTITY_B());
- aLine = std::dynamic_pointer_cast<SketchPlugin_Line>(aLineFeature);
- if (aLine.get()) {
- aDistance = aLine->distanceToPoint(aPointA->pnt());
- }
+ aLine = getLine(aData, SketchPlugin_Constraint::ENTITY_B());
+ aGeomPntA = aPointA->pnt();
+ aGeomPntB = aLine ? aLine->project(aGeomPntA) : GeomPnt2dPtr();
}
}
+
+ if (aGeomPntA.get() && aGeomPntB.get()) {
+ aDistance = aGeomPntA->distance(aGeomPntB);
+ if (aDistance < tolerance)
+ aDistance = 0.0;
+ }
+
+ // keep the direction between arguments for processing of the zero distance
+ std::shared_ptr<GeomDataAPI_Dir> aPointPointDir =
+ std::dynamic_pointer_cast<GeomDataAPI_Dir>(attribute(DIRECTION_ID()));
+ if (aDistance > tolerance)
+ aPointPointDir->setValue(aGeomPntB->x() - aGeomPntA->x(), aGeomPntB->y() - aGeomPntA->y(), 0.0);
+ else if (aLine) {
+ GeomDir2dPtr aLineDir = aLine->direction();
+ aPointPointDir->setValue(-aLineDir->y(), aLineDir->x(), 0.0);
+ }
+
return aDistance;
}
if (!aValueAttr->isInitialized()) {
// only if it is not initialized, try to compute the current value
double aDistance = calculateCurrentDistance();
- if (aDistance > 0) { // set as value the length of updated references
+ if (aDistance >= 0) { // set as value the length of updated references
aValueAttr->setValue(aDistance);
}
}
return MY_SIGNED;
}
+ /// \brief The direction from the first object to the second.
+ /// To change distance value from zero to non-zero correctly.
+ inline static const std::string& DIRECTION_ID()
+ {
+ static const std::string MY_DIRECTION_ID("DistanceDirection");
+ return MY_DIRECTION_ID;
+ }
+
/// attribute name of dimension location type
inline static const std::string& LOCATION_TYPE_ID()
{
}
// LCOV_EXCL_STOP
-double SketchPlugin_Line::distanceToPoint(const std::shared_ptr<GeomAPI_Pnt2d>& thePoint)
-{
- double aDelta = 0;
-
- std::shared_ptr<ModelAPI_Data> aData = data();
- std::shared_ptr<GeomDataAPI_Point2D> aPoint1 =
- std::dynamic_pointer_cast<GeomDataAPI_Point2D>(aData->attribute(START_ID()));
- std::shared_ptr<GeomDataAPI_Point2D> aPoint2 =
- std::dynamic_pointer_cast<GeomDataAPI_Point2D>(aData->attribute(END_ID()));
-
- GeomAPI_Lin2d aLin2d(aPoint1->x(), aPoint1->y(), aPoint2->x(), aPoint2->y());
-
- if (false/*projection*/) { // TODO: if it has not been necessary, remove this block
- std::shared_ptr<GeomAPI_Pnt2d> aResult = aLin2d.project(thePoint);
- aDelta = aResult->distance(thePoint);
- } else { // distance
- aDelta = aLin2d.distance(thePoint);
- }
-
- return aDelta;
-}
-
const std::string& SketchPlugin_Line::getKind()
{
static std::string MY_KIND = SketchPlugin_Line::ID();
/// if message has selected object
virtual std::string processEvent(const std::shared_ptr<Events_Message>& theMessage);
- /// Return the distance between the feature and the point
- /// \param thePoint the point
- double distanceToPoint(const std::shared_ptr<GeomAPI_Pnt2d>& thePoint);
-
/// Called on change of any argument-attribute of this object
SKETCHPLUGIN_EXPORT virtual void attributeChanged(const std::string& theID);
model.do()
# changing the parameter
-for param in range(-30, 31, 2):
+for param in range(-31, 30, 2):
if param == 0:
continue
DistanceParam.setValue(param)
model.do()
# changing the parameter
-for param in range(-30, 31, 2):
+for param in range(-31, 30, 2):
if param == 0:
continue
DistanceParam.setValue(param)
for param in range(-30, 31, 2):
DistanceParam.setValue(param)
model.do()
- if param <= 0:
+ if param < 0:
assert SketchConstraintDistance_1.feature().error() != '', "ERROR: Sketch should not be valid due to negative distance value"
+ elif param == 0: # constraint is valid, but lead to degenerated geometry
+ assert Sketch_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))
#=========================================================================
# Change a distance value
#=========================================================================
-d = DISTANCE1 + 20.
+d = DISTANCE1 + 21.
dStep = -5.
while d >= -30.:
aSession.startOperation()
DISTANCE1 = d
aDistance.setValue(DISTANCE1)
aSession.finishOperation()
- if DISTANCE1 == 0:
- assert(aHDist1.error() != "")
- else:
- assert math.fabs(horizontalDistance(aPoint1Coords, aPoint2Coords) - DISTANCE1) < 1.e-5, "Distance values are different: {0} != {1}".format(horizontalDistance(aPoint1Coords, aPoint2Coords), DISTANCE1)
+ 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)
# Change a distance value (check previous constraint is applied too)
#=========================================================================
d = DISTANCE2
-dStep = -5.
+dStep = -7.
while d >= -50.:
aSession.startOperation()
DISTANCE2 = d
aDistance.setValue(DISTANCE2)
aSession.finishOperation()
- if DISTANCE2 == 0:
- assert(aHDist2.error() != "")
- else:
- 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)
+ 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)
# Change a distance value
#=========================================================================
d = DISTANCE3
-dStep = -5.
+dStep = -7.
while d >= -50.:
aSession.startOperation()
DISTANCE3 = d
aDistance.setValue(DISTANCE3)
aSession.finishOperation()
- if DISTANCE3 == 0:
- assert(aHDist3.error() != "")
- else:
- assert math.fabs(horizontalDistance(aStartPoint, aEndPoint) - DISTANCE3) < 1.e-5, "Distance values are different: {0} != {1}".format(horizontalDistance(aStartPoint, aEndPoint), DISTANCE3)
+ 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)
--- /dev/null
+# Copyright (C) 2019 CEA/DEN, EDF R&D
+#
+# This library is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public
+# License as published by the Free Software Foundation; either
+# version 2.1 of the License, or (at your option) any later version.
+#
+# This library is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# Lesser General Public License for more details.
+#
+# 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
+#
+# See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
+#
+
+"""
+ Test the zero value of the constraint "DistanceHorizontal"
+"""
+
+import unittest
+import math
+
+from salome.shaper import model
+from SketchAPI import *
+
+__updated__ = "2019-10-22"
+TOLERANCE = 1.e-6
+
+class TestZeroDistanceHorizontal(unittest.TestCase):
+ def setUp(self):
+ model.begin()
+ self.myDocument = model.moduleDocument()
+ self.mySketch = model.addSketch(self.myDocument, model.defaultPlane("XOY"))
+ self.myLine1 = self.mySketch.addLine(10, 10, 45, 27.5)
+ self.myLine2 = self.mySketch.addLine(20, 15, 30, 40)
+ self.myLine3 = self.mySketch.addLine(10, 0, 10, 10)
+ model.do()
+ self.myDOF = 12
+
+ def tearDown(self):
+ model.end()
+ model.checkSketch(self.mySketch, self.myDOF)
+
+ def assertDistanceHorizontal(self, theObject1, theObject2, theDistance):
+ dist = theObject2.x() - theObject1.x()
+ self.assertTrue(math.fabs(dist - theDistance) < TOLERANCE, "Current distance = {}, reference = {}".format(dist, theDistance))
+ model.checkSketch(self.mySketch, self.myDOF)
+
+
+ def test_distance_positive_nzznz(self):
+ """ Test 1. Change distance from non-zero to zero and back to non-zero
+ """
+ dist = self.mySketch.setHorizontalDistance(self.myLine1.startPoint(), self.myLine2.startPoint(), 10)
+ self.myDOF -= 1
+ model.do()
+ self.assertDistanceHorizontal(self.myLine1.startPoint(), self.myLine2.startPoint(), 10)
+
+ SketchAPI_Constraint(dist).setValue(0)
+ model.do()
+ self.assertDistanceHorizontal(self.myLine1.startPoint(), self.myLine2.startPoint(), 0)
+
+ SketchAPI_Constraint(dist).setValue(10)
+ model.do()
+ self.assertDistanceHorizontal(self.myLine1.startPoint(), self.myLine2.startPoint(), 10)
+
+ def test_distance_negative_nzznz(self):
+ """ Test 2. Change distance from non-zero to zero and back to non-zero
+ """
+ dist = self.mySketch.setHorizontalDistance(self.myLine1.endPoint(), self.myLine2.endPoint(), 15)
+ self.myDOF -= 1
+ model.do()
+ self.assertDistanceHorizontal(self.myLine1.endPoint(), self.myLine2.endPoint(), -15)
+
+ SketchAPI_Constraint(dist).setValue(0)
+ model.do()
+ self.assertDistanceHorizontal(self.myLine1.endPoint(), self.myLine2.endPoint(), 0)
+
+ SketchAPI_Constraint(dist).setValue(10)
+ model.do()
+ self.assertDistanceHorizontal(self.myLine1.endPoint(), self.myLine2.endPoint(), -10)
+
+ def test_distance_equal_znzz(self):
+ """ Test 3. Change distance from zero to non-zero and back to zero
+ """
+ dist = self.mySketch.setHorizontalDistance(self.myLine1.startPoint(), self.myLine3.endPoint(), 0)
+ self.myDOF -= 1
+ model.do()
+ self.assertDistanceHorizontal(self.myLine1.startPoint(), self.myLine3.endPoint(), 0)
+
+ SketchAPI_Constraint(dist).setValue(10)
+ model.do()
+ self.assertDistanceHorizontal(self.myLine1.startPoint(), self.myLine3.endPoint(), 10)
+
+ SketchAPI_Constraint(dist).setValue(0)
+ model.do()
+ self.assertDistanceHorizontal(self.myLine1.startPoint(), self.myLine3.endPoint(), 0)
+
+ def test_distance_notequal_znzz(self):
+ """ Test 4. Change distance from zero to non-zero and back to zero
+ """
+ dist = self.mySketch.setHorizontalDistance(self.myLine1.startPoint(), self.myLine3.startPoint(), 0)
+ self.myDOF -= 1
+ model.do()
+ self.assertDistanceHorizontal(self.myLine1.startPoint(), self.myLine3.startPoint(), 0)
+
+ SketchAPI_Constraint(dist).setValue(10)
+ model.do()
+ self.assertDistanceHorizontal(self.myLine1.startPoint(), self.myLine3.startPoint(), 10)
+
+ SketchAPI_Constraint(dist).setValue(0)
+ model.do()
+ self.assertDistanceHorizontal(self.myLine1.startPoint(), self.myLine3.startPoint(), 0)
+
+
+if __name__ == "__main__":
+ test_program = unittest.main(exit=False)
+ assert test_program.result.wasSuccessful(), "Test failed"
+ assert model.checkPythonDump()
#=========================================================================
# Change a distance value
#=========================================================================
-d = DISTANCE1 + 20.
+d = DISTANCE1 + 21.
dStep = -5.
while d >= -30.:
aSession.startOperation()
DISTANCE1 = d
aDistance.setValue(DISTANCE1)
aSession.finishOperation()
- if DISTANCE1 == 0:
- assert(aVDist1.error() != "")
- else:
- assert math.fabs(verticalDistance(aPoint1Coords, aPoint2Coords) - DISTANCE1) < 1.e-5, "Distance values are different: {0} != {1}".format(verticalDistance(aPoint1Coords, aPoint2Coords), DISTANCE1)
+ 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)
# Change a distance value (check previous constraint is applied too)
#=========================================================================
d = DISTANCE2
-dStep = -5.
+dStep = -7.
while d >= -50.:
aSession.startOperation()
DISTANCE2 = d
aDistance.setValue(DISTANCE2)
aSession.finishOperation()
- if DISTANCE2 == 0:
- assert(aVDist2.error() != "")
- else:
- 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)
+ 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)
# Change a distance value
#=========================================================================
d = DISTANCE3
-dStep = -5.
+dStep = -7.
while d >= -50.:
aSession.startOperation()
DISTANCE3 = d
aDistance.setValue(DISTANCE3)
aSession.finishOperation()
- if DISTANCE3 == 0:
- assert(aVDist3.error() != "")
- else:
- assert math.fabs(verticalDistance(aStartPoint, aEndPoint) - DISTANCE3) < 1.e-5, "Distance values are different: {0} != {1}".format(verticalDistance(aStartPoint, aEndPoint), DISTANCE3)
+ 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)
--- /dev/null
+# Copyright (C) 2019 CEA/DEN, EDF R&D
+#
+# This library is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public
+# License as published by the Free Software Foundation; either
+# version 2.1 of the License, or (at your option) any later version.
+#
+# This library is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# Lesser General Public License for more details.
+#
+# 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
+#
+# See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
+#
+
+"""
+ Test the zero value of the constraint "DistanceVertical"
+"""
+
+import unittest
+import math
+
+from salome.shaper import model
+from SketchAPI import *
+
+__updated__ = "2019-10-22"
+TOLERANCE = 1.e-6
+
+class TestZeroDistanceVertical(unittest.TestCase):
+ def setUp(self):
+ model.begin()
+ self.myDocument = model.moduleDocument()
+ self.mySketch = model.addSketch(self.myDocument, model.defaultPlane("XOY"))
+ self.myLine1 = self.mySketch.addLine(10, 10, 45, 27.5)
+ self.myLine2 = self.mySketch.addLine(20, 15, 30, 40)
+ self.myLine3 = self.mySketch.addLine(0, 10, 10, 10)
+ model.do()
+ self.myDOF = 12
+
+ def tearDown(self):
+ model.end()
+ model.checkSketch(self.mySketch, self.myDOF)
+
+ def assertDistanceVertical(self, theObject1, theObject2, theDistance):
+ dist = theObject2.y() - theObject1.y()
+ self.assertTrue(math.fabs(dist - theDistance) < TOLERANCE, "Current distance = {}, reference = {}".format(dist, theDistance))
+ model.checkSketch(self.mySketch, self.myDOF)
+
+
+ def test_distance_positive_nzznz(self):
+ """ Test 1. Change distance from non-zero to zero and back to non-zero
+ """
+ dist = self.mySketch.setVerticalDistance(self.myLine1.startPoint(), self.myLine2.startPoint(), 5)
+ self.myDOF -= 1
+ model.do()
+ self.assertDistanceVertical(self.myLine1.startPoint(), self.myLine2.startPoint(), 5)
+
+ SketchAPI_Constraint(dist).setValue(0)
+ model.do()
+ self.assertDistanceVertical(self.myLine1.startPoint(), self.myLine2.startPoint(), 0)
+
+ SketchAPI_Constraint(dist).setValue(10)
+ model.do()
+ self.assertDistanceVertical(self.myLine1.startPoint(), self.myLine2.startPoint(), 10)
+
+ def test_distance_negative_nzznz(self):
+ """ Test 2. Change distance from non-zero to zero and back to non-zero
+ """
+ dist = self.mySketch.setVerticalDistance(self.myLine1.endPoint(), self.myLine2.startPoint(), 12.5)
+ self.myDOF -= 1
+ model.do()
+ self.assertDistanceVertical(self.myLine1.endPoint(), self.myLine2.startPoint(), -12.5)
+
+ SketchAPI_Constraint(dist).setValue(0)
+ model.do()
+ self.assertDistanceVertical(self.myLine1.endPoint(), self.myLine2.startPoint(), 0)
+
+ SketchAPI_Constraint(dist).setValue(12.5)
+ model.do()
+ self.assertDistanceVertical(self.myLine1.endPoint(), self.myLine2.startPoint(), -12.5)
+
+ def test_distance_equal_znzz(self):
+ """ Test 3. Change distance from zero to non-zero and back to zero
+ """
+ dist = self.mySketch.setVerticalDistance(self.myLine1.startPoint(), self.myLine3.endPoint(), 0)
+ self.myDOF -= 1
+ model.do()
+ self.assertDistanceVertical(self.myLine1.startPoint(), self.myLine3.endPoint(), 0)
+
+ SketchAPI_Constraint(dist).setValue(10)
+ model.do()
+ self.assertDistanceVertical(self.myLine1.startPoint(), self.myLine3.endPoint(), 10)
+
+ SketchAPI_Constraint(dist).setValue(0)
+ model.do()
+ self.assertDistanceVertical(self.myLine1.startPoint(), self.myLine3.endPoint(), 0)
+
+ def test_distance_notequal_znzz(self):
+ """ Test 4. Change distance from zero to non-zero and back to zero
+ """
+ dist = self.mySketch.setVerticalDistance(self.myLine1.startPoint(), self.myLine3.startPoint(), 0)
+ self.myDOF -= 1
+ model.do()
+ self.assertDistanceVertical(self.myLine1.startPoint(), self.myLine3.startPoint(), 0)
+
+ SketchAPI_Constraint(dist).setValue(10)
+ model.do()
+ self.assertDistanceVertical(self.myLine1.startPoint(), self.myLine3.startPoint(), 10)
+
+ SketchAPI_Constraint(dist).setValue(0)
+ model.do()
+ self.assertDistanceVertical(self.myLine1.startPoint(), self.myLine3.startPoint(), 0)
+
+
+if __name__ == "__main__":
+ test_program = unittest.main(exit=False)
+ assert test_program.result.wasSuccessful(), "Test failed"
+ assert model.checkPythonDump()
--- /dev/null
+# Copyright (C) 2019 CEA/DEN, EDF R&D
+#
+# This library is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public
+# License as published by the Free Software Foundation; either
+# version 2.1 of the License, or (at your option) any later version.
+#
+# This library is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# Lesser General Public License for more details.
+#
+# 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
+#
+# See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
+#
+
+"""
+ Test the zero value of the constraint "Distance"
+"""
+
+import unittest
+import math
+
+from salome.shaper import model
+from SketchAPI import *
+
+__updated__ = "2019-10-22"
+TOLERANCE = 1.e-6
+
+class TestZeroDistance(unittest.TestCase):
+ def setUp(self):
+ model.begin()
+ self.myDocument = model.moduleDocument()
+ self.mySketch = model.addSketch(self.myDocument, model.defaultPlane("XOY"))
+ self.myLine1 = self.mySketch.addLine(10, 10, 45, 27.5)
+ self.myLine2 = self.mySketch.addLine(20, 15, 30, 40)
+ self.myLine3 = self.mySketch.addLine(10, 0, 10, 10)
+ model.do()
+ self.myDOF = 12
+
+ def tearDown(self):
+ model.end()
+ model.checkSketch(self.mySketch, self.myDOF)
+
+ def assertDistance(self, theObject1, theObject2, theDistance, isSigned = False):
+ dist = -1.
+ if issubclass(type(theObject1), SketchAPI_SketchEntity):
+ if isSigned:
+ dist = model.signedDistancePointLine(theObject2, theObject1)
+ else:
+ dist = model.distancePointLine(theObject2, theObject1)
+ elif issubclass(type(theObject2), SketchAPI_SketchEntity):
+ if isSigned:
+ dist = model.signedDistancePointLine(theObject1, theObject2)
+ else:
+ dist = model.distancePointLine(theObject1, theObject2)
+ else:
+ dist = model.distancePointPoint(theObject1, theObject2)
+ self.assertTrue(math.fabs(dist - theDistance) < TOLERANCE, "Current distance = {}, reference = {}".format(dist, theDistance))
+ model.checkSketch(self.mySketch, self.myDOF)
+
+
+ def test_distance_points_nzznz(self):
+ """ Test 1. Change point-point distance from non-zero to zero and back to non-zero
+ """
+ dist = self.mySketch.setDistance(self.myLine1.endPoint(), self.myLine2.endPoint(), 20)
+ self.myDOF -= 1
+ model.do()
+ self.assertDistance(self.myLine1.endPoint(), self.myLine2.endPoint(), 20)
+
+ SketchAPI_Constraint(dist).setValue(0)
+ self.myDOF -= 1
+ model.do()
+ self.assertDistance(self.myLine1.endPoint(), self.myLine2.endPoint(), 0)
+
+ SketchAPI_Constraint(dist).setValue(20)
+ self.myDOF += 1
+ model.do()
+ self.assertDistance(self.myLine1.endPoint(), self.myLine2.endPoint(), 20)
+
+ def test_distance_points_znzz(self):
+ """ Test 2. Change point-point distance from zero to non-zero and back to zero
+ """
+ dist = self.mySketch.setDistance(self.myLine1.startPoint(), self.myLine3.endPoint(), 0)
+ self.myDOF -= 2
+ model.do()
+ self.assertDistance(self.myLine1.startPoint(), self.myLine3.endPoint(), 0)
+
+ SketchAPI_Constraint(dist).setValue(10)
+ self.myDOF += 1
+ model.do()
+ self.assertDistance(self.myLine1.startPoint(), self.myLine3.endPoint(), 10)
+
+ SketchAPI_Constraint(dist).setValue(0)
+ self.myDOF -= 1
+ model.do()
+ self.assertDistance(self.myLine1.startPoint(), self.myLine3.endPoint(), 0)
+
+
+ def test_unsigned_distance_nzznz(self):
+ """ Test 3. Change unsigned point-line distance from non-zero to zero and back to non-zero
+ """
+ dist = self.mySketch.setDistance(self.myLine1.result(), self.myLine2.endPoint(), 20)
+ self.myDOF -= 1
+ model.do()
+ self.assertDistance(self.myLine1, self.myLine2.endPoint(), 20)
+
+ SketchAPI_Constraint(dist).setValue(0)
+ model.do()
+ self.assertDistance(self.myLine1, self.myLine2.endPoint(), 0)
+
+ SketchAPI_Constraint(dist).setValue(20)
+ model.do()
+ self.assertDistance(self.myLine1, self.myLine2.endPoint(), 20)
+
+ def test_unsigned_distance_znzz(self):
+ """ Test 4. Change unsigned point-line distance from zero to non-zero and back to zero
+ """
+ dist = self.mySketch.setDistance(self.myLine2.startPoint(), self.myLine1.result(), 0)
+ self.myDOF -= 1
+ model.do()
+ self.assertDistance(self.myLine2.startPoint(), self.myLine1, 0)
+
+ SketchAPI_Constraint(dist).setValue(10)
+ model.do()
+ self.assertDistance(self.myLine2.startPoint(), self.myLine1, 10)
+
+ SketchAPI_Constraint(dist).setValue(0)
+ model.do()
+ self.assertDistance(self.myLine2.startPoint(), self.myLine1, 0)
+
+
+ def test_signed_distance_nzznz(self):
+ """ Test 5. Change signed point-line distance from non-zero to zero and back to non-zero
+ """
+ dist = self.mySketch.setDistance(self.myLine1.result(), self.myLine2.endPoint(), 20, True)
+ self.myDOF -= 1
+ model.do()
+ self.assertDistance(self.myLine1, self.myLine2.endPoint(), -20, True)
+
+ SketchAPI_Constraint(dist).setValue(0)
+ model.do()
+ self.assertDistance(self.myLine1, self.myLine2.endPoint(), 0, True)
+
+ SketchAPI_Constraint(dist).setValue(20)
+ model.do()
+ self.assertDistance(self.myLine1, self.myLine2.endPoint(), -20, True)
+
+ def test_signed_distance_nzznz_2(self):
+ """ Test 6. Change signed point-line distance from non-zero to zero and back to non-zero
+ """
+ dist = self.mySketch.setDistance(self.myLine3.startPoint(), self.myLine1.result(), 10, True)
+ self.myDOF -= 1
+ model.do()
+ self.assertDistance(self.myLine1, self.myLine3.startPoint(), 10, True)
+
+ SketchAPI_Constraint(dist).setValue(0)
+ model.do()
+ self.assertDistance(self.myLine1, self.myLine3.startPoint(), 0, True)
+
+ SketchAPI_Constraint(dist).setValue(20)
+ model.do()
+ self.assertDistance(self.myLine1, self.myLine3.startPoint(), 20, True)
+
+ def test_signed_distance_znzz(self):
+ """ Test 7. Change signed point-line distance from zero to non-zero and back to zero
+ """
+ dist = self.mySketch.setDistance(self.myLine2.startPoint(), self.myLine1.result(), 0, True)
+ self.myDOF -= 1
+ model.do()
+ self.assertDistance(self.myLine2.startPoint(), self.myLine1, 0)
+
+ SketchAPI_Constraint(dist).setValue(10)
+ model.do()
+ self.assertDistance(self.myLine2.startPoint(), self.myLine1, 10)
+
+ SketchAPI_Constraint(dist).setValue(0)
+ model.do()
+ self.assertDistance(self.myLine2.startPoint(), self.myLine1, 0)
+
+
+if __name__ == "__main__":
+ test_program = unittest.main(exit=False)
+ assert test_program.result.wasSuccessful(), "Test failed"
+ assert model.checkPythonDump()
<validator id="SketchPlugin_ExternalValidator" parameters="ConstraintEntityB"/>
<validator id="PartSet_DifferentObjects"/>
<validator id="GeomValidators_ShapeType" parameters="vertex,line"/>
- <validator id="PartSet_DifferentPoints" parameters="ConstraintEntityB"/>
</sketch_shape_selector>
<sketch_shape_selector
id="ConstraintEntityB"
<validator id="SketchPlugin_DistanceAttr" parameters="ConstraintEntityA"/>
<validator id="SketchPlugin_ExternalValidator" parameters="ConstraintEntityA"/>
<validator id="GeomValidators_ShapeType" parameters="vertex,line"/>
- <validator id="PartSet_DifferentPoints" parameters="ConstraintEntityA"/>
</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" min="0">
- <validator id="GeomValidators_Positive"/>
+ <validator id="GeomValidators_Positive" parameters="-1.e-10"/>
</doublevalue_editor>
<module_choice id="LocationType"
<sketch-2dpoint_flyout_selector id="ConstraintFlyoutValuePnt" default="computed" internal="1" obligatory="0"/>
<doublevalue_editor label="Value" tooltip="Distance" id="DistanceValue" default="computed" min="0">
- <validator id="GeomValidators_Positive"/>
+ <validator id="GeomValidators_Positive" parameters="-1.e-10"/>
</doublevalue_editor>
<module_choice id="LocationType"
<sketch-2dpoint_flyout_selector id="ConstraintFlyoutValuePnt" default="computed" internal="1" obligatory="0"/>
<doublevalue_editor label="Value" tooltip="Distance" id="DistanceValue" default="computed" min="0">
- <validator id="GeomValidators_Positive"/>
+ <validator id="GeomValidators_Positive" parameters="-1.e-10"/>
</doublevalue_editor>
<module_choice id="LocationType"
double PlaneGCSSolver_ConstraintWrapper::value() const
{
- return myValueParam->value();
+ return myValueParam ? myValueParam->value() : 0.0;
}
#include <PlaneGCSSolver_PointWrapper.h>
#include <PlaneGCSSolver_Storage.h>
#include <PlaneGCSSolver_Tools.h>
+#include <PlaneGCSSolver_UpdateCoincidence.h>
#include <SketchPlugin_ConstraintDistanceHorizontal.h>
#include <SketchPlugin_ConstraintDistanceVertical.h>
*(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<GeomDataAPI_Dir> aDistDir = std::dynamic_pointer_cast<GeomDataAPI_Dir>(
+ 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<PlaneGCSSolver_PointWrapper>(aEntityA)->point();
+ theDirX = 1.0;
+ theDirY = 0.0;
+
+ EdgeWrapperPtr anEdgeA = std::dynamic_pointer_cast<PlaneGCSSolver_EdgeWrapper>(
+ theStorage->entity(getFeature(aRefAttrA)));
+ EdgeWrapperPtr anEdgeB = std::dynamic_pointer_cast<PlaneGCSSolver_EdgeWrapper>(
+ 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<PlaneGCSSolver_PointWrapper>(aEntityA);
+ PointWrapperPtr aPointB = std::dynamic_pointer_cast<PlaneGCSSolver_PointWrapper>(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,
return;
}
+ ScalarWrapperPtr aValue = std::dynamic_pointer_cast<PlaneGCSSolver_ScalarWrapper>(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;
- myStorage->subscribeUpdates(this, PlaneGCSSolver_UpdateFeature::GROUP());
+ if (isCoincidence)
+ myStorage->subscribeUpdates(this, PlaneGCSSolver_UpdateCoincidence::GROUP());
+ else
+ myStorage->subscribeUpdates(this, PlaneGCSSolver_UpdateFeature::GROUP());
}
void SketchSolver_ConstraintDistance::adjustConstraint()
ConstraintWrapperPtr aConstraint = myStorage->constraint(myBaseConstraint);
myPrevValue = aConstraint->value();
- SketchSolver_Constraint::update();
+ bool isDistanceAlognDir =
+ myBaseConstraint->getKind() == SketchPlugin_ConstraintDistanceHorizontal::ID() ||
+ myBaseConstraint->getKind() == SketchPlugin_ConstraintDistanceVertical::ID();
+
+ 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;
+ }
+ }
}
bool SketchSolver_ConstraintDistance::remove()
return readyToDisplay(theConstraint, thePlane, aPnt1, aPnt2);
}
+static bool isEqualPoints(ModelAPI_Feature* theConstraint,
+ const gp_Pnt& thePoint1,
+ const gp_Pnt& thePoint2)
+{
+ bool isEqual = false;
+ if (theConstraint->getKind() == SketchPlugin_ConstraintDistanceHorizontal::ID())
+ isEqual = Abs(thePoint1.X() - thePoint2.X()) < Precision::Confusion();
+ else if (theConstraint->getKind() == SketchPlugin_ConstraintDistanceVertical::ID())
+ isEqual = Abs(thePoint1.Y() - thePoint2.Y()) < Precision::Confusion();
+ else
+ isEqual = thePoint1.SquareDistance(thePoint2) < Precision::SquareConfusion();
+ return isEqual;
+}
+
void SketcherPrs_LengthDimension::Compute(
const Handle(PrsMgr_PresentationManager3d)& thePresentationManager,
const Handle(Prs3d_Presentation)& thePresentation,
gp_Pnt aPnt1, aPnt2;
bool aReadyToDisplay = readyToDisplay(myConstraint, plane(), aPnt1, aPnt2);
if (aReadyToDisplay) {
+ if (isEqualPoints(myConstraint, aPnt1, aPnt2)) {
+ // adjust points to draw the dimension presentation
+ std::shared_ptr<GeomDataAPI_Dir> aDirAttr = std::dynamic_pointer_cast<GeomDataAPI_Dir>(
+ myConstraint->attribute(SketchPlugin_ConstraintDistance::DIRECTION_ID()));
+ double x = 0.0, y = 0.0;
+ if (aDirAttr && aDirAttr->isInitialized()) {
+ x = aDirAttr->x();
+ y = aDirAttr->y();
+ if (x == 0.0 && y == 0.0)
+ x = 1.0;
+ }
+ else if (myConstraint->getKind() == SketchPlugin_ConstraintDistanceVertical::ID())
+ y = 1.0;
+ else
+ x = 1.0;
+ GeomPointPtr aCoord = plane()->to3D(x, y);
+
+ gp_XYZ aDir(aCoord->x(), aCoord->y(), aCoord->z());
+ aPnt1.ChangeCoord().Add(aDir * (-Precision::Confusion()));
+ aPnt2.ChangeCoord().Add(aDir * Precision::Confusion());
+ }
+
myFirstPoint = aPnt1;
mySecondPoint = aPnt2;
if (!aPnt_A || !aPnt_B) // Objects not found
return false;
- if (theConstraint->getKind() == SketchPlugin_ConstraintDistanceHorizontal::ID()) {
+ /*if (theConstraint->getKind() == SketchPlugin_ConstraintDistanceHorizontal::ID()) {
if (fabs(aPnt_A->x() - aPnt_B->x()) < Precision::Confusion())
return false;
}
else if (theConstraint->getKind() == SketchPlugin_ConstraintDistanceVertical::ID()) {
if (fabs(aPnt_A->y() - aPnt_B->y()) < Precision::Confusion())
return false;
- }
+ }*/
// Get points from these object
std::shared_ptr<GeomAPI_Pnt> aPoint1 = thePlane->to3D(aPnt_A->x(), aPnt_A->y());