Central point is added to a sketch along with edges rectangle.
ep_ref = points[i]
assert(ep.distance(ep_ref) <= tolerance)
-def checkRectangleL(lines, valref, tolerance = 1.e-5):
- for i in range(0, 4):
- line = SketchAPI_Line(lines[i])
- #print (line.defaultResult().shape().edge().length())
- #print (valref[i%2])
- #print (abs(line.defaultResult().shape().edge().length()-valref[i%2]))
- assert(abs(line.defaultResult().shape().edge().length()-valref[i%2]) <= tolerance)
+def areCounterDirectedAndOfEqualLength(theLineA, theLineB):
+ tolerance = 1.e-5
+
+ aStartA = theLineA.startPoint().pnt()
+ aEndA = theLineA.endPoint().pnt()
+ aDirA_X = aEndA.x() - aStartA.x()
+ aDirA_Y = aEndA.y() - aStartA.y()
+
+ aStartB = theLineB.startPoint().pnt()
+ aEndB = theLineB.endPoint().pnt()
+ aDirB_X = aEndB.x() - aStartB.x()
+ aDirB_Y = aEndB.y() - aStartB.y()
+
+ return abs(aDirA_X + aDirB_X) < tolerance and abs(aDirA_Y + aDirB_Y) < tolerance
+
+def arePerpendicular(theLineA, theLineB):
+ tolerance = 1.e-5
+
+ aStartA = theLineA.startPoint().pnt()
+ aEndA = theLineA.endPoint().pnt()
+ aDirA_X = aEndA.x() - aStartA.x()
+ aDirA_Y = aEndA.y() - aStartA.y()
+ aLengthA = theLineA.defaultResult().shape().edge().length()
+
+ aStartB = theLineB.startPoint().pnt()
+ aEndB = theLineB.startPoint().pnt()
+ aDirB_X = aEndB.x() - aStartB.x()
+ aDirB_Y = aEndB.y() - aStartB.y()
+ aLengthB = theLineB.defaultResult().shape().edge().length()
+
+ if (aLengthA < tolerance or aLengthB < tolerance):
+ return True
+
+ return (aDirA_X * aDirB_X + aDirA_Y * aDirB_Y) / (aLengthA * aLengthB) < tolerance
+
+def areConnected(theLineA, theLineB):
+ aEndA = theLineA.endPoint().pnt()
+ aStartB = theLineB.startPoint().pnt()
+ return aEndA.x() == aStartB.x() and aEndA.y() == aStartB.y()
+
+def checkIfArbitraryAlignedRectangle(theEdgeLines):
+ aLine0 = SketchAPI_Line(theEdgeLines[0])
+ aLine1 = SketchAPI_Line(theEdgeLines[1])
+ aLine2 = SketchAPI_Line(theEdgeLines[2])
+ aLine3 = SketchAPI_Line(theEdgeLines[3])
+
+ assert (areCounterDirectedAndOfEqualLength(aLine0, aLine2))
+ assert (areCounterDirectedAndOfEqualLength(aLine1, aLine3))
+ assert (arePerpendicular(aLine0, aLine1))
+ assert (arePerpendicular(aLine2, aLine3))
+ assert (areConnected(aLine0, aLine1))
+ assert (areConnected(aLine1, aLine2))
+ assert (areConnected(aLine2, aLine3))
+ assert (areConnected(aLine3, aLine0))
+
+
model.begin()
partSet = model.moduleDocument()
# move center of rectangle
SHIFT = 1.0
center = SketchAPI_Line(lines_1[0]).startPoint().pnt()
-valref = [ \
-400.86931 , 200.78509 , \
-401.73886 , 201.57021 , \
-402.60865 , 202.35537 , \
-403.47866 , 203.14056 , \
-404.34890 , 203.92580 ]
for i in range(0, 5):
center.setX(center.x() + SHIFT)
center.setY(center.y() + SHIFT)
model.begin()
sketch.move(SketchAPI_Line(lines_1[0]).startPoint(), center)
model.end()
- checkRectangleL(lines_3, valref[2*i:])
+ checkIfArbitraryAlignedRectangle(lines_3)
# move corner of rectangle
corner = SketchAPI_Line(lines_2[0]).endPoint().pnt()
-valref = [ \
-403.11209 , 202.95437 , \
-401.87551 , 201.98300 , \
-400.63915 , 201.01169 , \
-399.40301 , 200.04043 , \
-398.16710 , 199.06922 ]
for i in range(0, 5):
corner.setX(corner.x() + SHIFT)
corner.setY(corner.y() + SHIFT)
model.begin()
sketch.move(SketchAPI_Line(lines_2[0]).endPoint(), corner)
model.end()
- checkRectangleL(lines_3, valref[2*i:])
+ checkIfArbitraryAlignedRectangle(lines_3)
assert(model.checkPythonDump())
"""Override Feature.initAttributes()"""
# Flag whether the rectangle is accessory
self.data().addAttribute(self.AUXILIARY_ID(), ModelAPI.ModelAPI_AttributeBoolean.typeId())
- # Creating corners of the rectangle
+ # Corners of the rectangle (being defined by opposite corners)
self.data().addAttribute(self.START_ID(), GeomDataAPI.GeomDataAPI_Point2D.typeId())
self.data().addAttribute(self.END_ID(), GeomDataAPI.GeomDataAPI_Point2D.typeId())
- # Creating list to store lines
+ # List with both contour and diagonal lines
self.data().addAttribute(self.LINES_LIST_ID(), ModelAPI.ModelAPI_AttributeRefList.typeId())
ModelAPI.ModelAPI_Session.get().validators().registerNotObligatory(self.getKind(), self.LINES_LIST_ID())
# Type of rectangle
self.data().addAttribute(self.RECTANGLE_TYPE_ID(), ModelAPI.ModelAPI_AttributeString.typeId())
- # Center and corner of the rectangle
+ # Center and corner of centered rectangle (being defined by center and corner)
self.data().addAttribute(self.CENTER_ID(), GeomDataAPI.GeomDataAPI_Point2D.typeId())
self.data().addAttribute(self.CORNER_ID(), GeomDataAPI.GeomDataAPI_Point2D.typeId())
"""
return True
-# Edition of the rectangle
+
+# Editing of a rectangle. It is called on select of the first generative point
+# and on hover of the second generative point. Generative point is either corner or center,
+# depending on rectangle type. And also it is called on call of Sketch.addRectangleCentered(...) in TUI.
def execute(self):
- # Retrieving list of already created lines
- aLinesList = self.reflist(self.LINES_LIST_ID())
- aNbLines = aLinesList.size()
- if aNbLines == 1:
- # Create 1-4 lines to compose the rectangle
- for i in range (0, 3):
+ # Retrieve list of already created lines
+ aLinesList = self.reflist(self.LINES_LIST_ID())
+ if aLinesList.size() == 1:
+ # Create remaining rectangle contour lines
+ for i in range (1, 4):
aLine = self.__sketch.addFeature("SketchLine")
aLinesList.append(aLine)
- self.updateLines()
- aNbLines = aLinesList.size()
+ self.__updateLines()
+
+ # Connect rectangle contour lines
aStartPoints = []
- # Create constraints to keep the rectangle
- for i in range (0, aNbLines):
+ for i in range (0, 4):
aLine = ModelAPI.objectToFeature(aLinesList.object(i))
- # connect neighbor lines by coincidence
- iPrev = i - 1
- if iPrev < 0:
- iPrev = aNbLines - 1
+ iPrev = i - 1 if i != 0 else 3
aPrevLine = ModelAPI.objectToFeature(aLinesList.object(iPrev))
aCoincidence = self.__sketch.addFeature("SketchConstraintCoincidence")
- aRefAttrA = aCoincidence.refattr("ConstraintEntityA")
- aRefAttrB = aCoincidence.refattr("ConstraintEntityB")
- aRefAttrA.setAttr(aPrevLine.attribute("EndPoint"))
- aRefAttrB.setAttr(aLine.attribute("StartPoint"))
+ aCoincidence.refattr("ConstraintEntityA").setAttr(aPrevLine.attribute("EndPoint"))
+ aCoincidence.refattr("ConstraintEntityB").setAttr(aLine.attribute("StartPoint"))
aStartPoints.append(aLine.attribute("StartPoint"))
- # Flags which show perpendicular constraint is build for correponding line
- self.__isPERP = [False, False, False]
+
# Update coordinates of created lines
- self.updateLines()
+ self.__updateLines()
+
+ # Flags, indicating perpendicular constraint is imposed on contour lines i and i+1.
+ self.__isPERP = [False, False, False]
+
# Create auxiliary diagonals in case of centered rectangle
if self.string(self.RECTANGLE_TYPE_ID()).value() == self.RECTANGLE_CENTERED_ID():
aDiag1 = self.__sketch.addFeature("SketchLine")
aLinesList.append(aDiag1)
aDiag2 = self.__sketch.addFeature("SketchLine")
aLinesList.append(aDiag2)
- # coincidences in corners
+
+ # Add coincidences between diagonals' endpoints and rectangle vertices
aPoints = [aDiag1.attribute("StartPoint"), aDiag2.attribute("StartPoint"),
aDiag1.attribute("EndPoint"), aDiag2.attribute("EndPoint")]
+
for i in range (0, len(aPoints)):
aCoincidence = self.__sketch.addFeature("SketchConstraintCoincidence")
- aRefAttrA = aCoincidence.refattr("ConstraintEntityA")
- aRefAttrB = aCoincidence.refattr("ConstraintEntityB")
- aRefAttrA.setAttr(aStartPoints[i])
- aRefAttrB.setAttr(aPoints[i])
+ aCoincidence.refattr("ConstraintEntityA").setAttr(aStartPoints[i])
+ aCoincidence.refattr("ConstraintEntityB").setAttr(aPoints[i])
+
# Update coordinates of created lines
- self.updateLines()
+ self.__updateLines()
aDiag1.execute()
aDiag2.execute()
+
# coincidences between center point and diagonals
- refPnt = self.getReferencePoint(self.refattr(self.CENTER_REF_ID()))
- if refPnt is not None:
+ attr = self.__getPoint2DAttrOfSketchPoint(self.refattr(self.CENTER_REF_ID()))
+ if attr is not None:
for line in [aDiag1.lastResult(), aDiag2.lastResult()]:
aCoincidence = self.__sketch.addFeature("SketchConstraintCoincidence")
- aCoincidence.refattr("ConstraintEntityA").setAttr(refPnt)
+ aCoincidence.refattr("ConstraintEntityA").setAttr(attr)
aCoincidence.refattr("ConstraintEntityB").setObject(line)
- # Perpendicular for the lines which already have result
+
+ # Add perpendicular constraints to the contour lines, which already have result
for i in range (0, 3):
if self.__isPERP[i]:
continue
+
aLine_A = ModelAPI.objectToFeature(aLinesList.object(i))
aLineResult_A = aLine_A.lastResult()
if aLineResult_A is None:
continue
+
aLine_B = ModelAPI.objectToFeature(aLinesList.object(i+1))
aLineResult_B = aLine_B.lastResult()
if aLineResult_B is None:
continue
- aHVConstraint = self.__sketch.addFeature("SketchConstraintPerpendicular")
- refattrA = aHVConstraint.refattr("ConstraintEntityA")
- refattrA.setObject(aLine_A.lastResult())
- refattrB = aHVConstraint.refattr("ConstraintEntityB")
- refattrB.setObject(aLine_B.lastResult())
+
+ aConstraintPerp = self.__sketch.addFeature("SketchConstraintPerpendicular")
+ aConstraintPerp.refattr("ConstraintEntityA").setObject(aLine_A.lastResult())
+ aConstraintPerp.refattr("ConstraintEntityB").setObject(aLine_B.lastResult())
self.__isPERP[i] = True
+
def attributeChanged(self, theID):
if theID == self.START_ID() or theID == self.END_ID() or theID == self.CENTER_ID() or theID == self.CENTER_REF_ID() or theID == self.CORNER_ID():
- # Search the sketch containing this rectangle
+ # Find the sketch containing this rectangle
self.__sketch = None
- aRefs = self.data().refsToMe();
- for iter in aRefs:
- aFeature = ModelAPI.objectToFeature(iter.owner())
+ aRefsToMe = self.data().refsToMe()
+ for aRefToMe in aRefsToMe:
+ aFeature = ModelAPI.objectToFeature(aRefToMe.owner())
if aFeature.getKind() == "Sketch":
self.__sketch = ModelAPI.featureToCompositeFeature(aFeature)
break
+ if theID == self.CENTER_ID():
+ aCenter = GeomDataAPI.geomDataAPI_Point2D(self.attribute(self.CENTER_ID())) # shared_ptr to Point2D
+ aCenterSketchPointAttr = self.refattr(self.CENTER_REF_ID())
+ if (not aCenterSketchPointAttr.isInitialized()):
+ # Create SketchPoint. In .execute() it will be constrained to keep center.
+ aCenterSketchPoint = self.__sketch.addFeature("SketchPoint")
+ aCenterSketchPoint.data().boolean("Auxiliary").setValue(True)
+ aCenterSketchPointCoords = GeomDataAPI.geomDataAPI_Point2D(aCenterSketchPoint.attribute("PointCoordinates")) # shared_ptr to Point2D
+ aCenterSketchPointCoords.setValue(aCenter.x(), aCenter.y())
+ aCenterSketchPointAttr.setObject(aCenterSketchPoint)
+ else:
+ # Maintain consistency between center SketchPoint and center Point2D.
+ aCenterSketchPointCoordsAttr = self.__getPoint2DAttrOfSketchPoint(aCenterSketchPointAttr)
+ if (aCenterSketchPointCoordsAttr == None):
+ Warning("Faulty logic")
+ else:
+ aCenterSketchPointCoords = GeomDataAPI.geomDataAPI_Point2D(aCenterSketchPointCoordsAttr) # shared_ptr to Point2D
+ aCenterSketchPointCoords.setValue(aCenter.x(), aCenter.y())
+ elif theID == self.CENTER_REF_ID():
+ aCenterSketchPointAttr = self.refattr(self.CENTER_REF_ID())
+ aCenterSketchPointCoordsAttr = self.__getPoint2DAttrOfSketchPoint(aCenterSketchPointAttr) # shared_ptr to Point2D
+ if (aCenterSketchPointCoordsAttr == None):
+ Warning("Faulty logic. Attempt to set rectangle's attribute " + self.CENTER_REF_ID() + " not with refattr to SketchPoint.")
+ return
+
+ # Maintain consistency between center SketchPoint and center Point2D.
+ aCenterSketchPointCoords = GeomDataAPI.geomDataAPI_Point2D(aCenterSketchPointCoordsAttr) # shared_ptr to Point2D
+ aCenter = GeomDataAPI.geomDataAPI_Point2D(self.attribute(self.CENTER_ID())) # shared_ptr to Point2D
+ aCenter.setValue(aCenterSketchPointCoords.x(), aCenterSketchPointCoords.y())
+
aLinesList = self.reflist(self.LINES_LIST_ID())
aNbLines = aLinesList.size()
if aNbLines == 0:
- # Create first line to be able to create a coincidence with selected point/feature
- for i in range (0, 1):
- aLine = self.__sketch.addFeature("SketchLine")
- aLinesList.append(aLine)
+ # If only one generative point is iniialized,
+ # do not create the full set of contour lines to not clutter
+ # UI with icons of constraints near the mouse pointer.
+ aLine = self.__sketch.addFeature("SketchLine")
+ aLinesList.append(aLine)
aStartPoint = GeomDataAPI.geomDataAPI_Point2D(self.attribute(self.START_ID()))
aEndPoint = GeomDataAPI.geomDataAPI_Point2D(self.attribute(self.END_ID()))
- aCenter = self.getPointByRef(self.attribute(self.CENTER_ID()), self.refattr(self.CENTER_REF_ID()))
+ aCenter = self.__getPoint2D(self.attribute(self.CENTER_ID()), self.refattr(self.CENTER_REF_ID()))
aCorner = GeomDataAPI.geomDataAPI_Point2D(self.attribute(self.CORNER_ID()))
+
if (aStartPoint.isInitialized() and aEndPoint.isInitialized()) or (aCenter is not None and aCorner.isInitialized()):
- self.updateLines()
+ self.__updateLines()
else:
- self.updateStartPoint()
- if theID == self.AUXILIARY_ID():
+ self.__updateLinesWithOnlyGenerativePoint()
+ elif theID == self.AUXILIARY_ID():
+ # Change aux attribute of contour lines
anAuxiliary = self.data().boolean(self.AUXILIARY_ID()).value()
- aLinesList = self.reflist(self.LINES_LIST_ID())
- aNbLines = aLinesList.size()
- # Update coordinates of rectangle lines
- for i in range (0, aNbLines):
+ aLinesList = self.reflist(self.LINES_LIST_ID())
+ for i in range (0, min(aLinesList.size(), 4)):
aLine = ModelAPI.objectToFeature(aLinesList.object(i))
aLine.data().boolean("Auxiliary").setValue(anAuxiliary)
-
- def getReferencePoint(self, theRef):
- if theRef.isObject() and theRef.object() is not None:
- feature = ModelAPI.ModelAPI_Feature.feature(theRef.object())
+ elif theID == self.RECTANGLE_TYPE_ID():
+ # TODO Find a way to distinguish "attribute changed" events on hover and on click.
+ # Now, if both generative points are selected, but the rectangle is not applied,
+ # and then rectangle type is changed, the unapplied rectangle is erased.
+ # It should be applied instead.
+ aLinesList = self.reflist(self.LINES_LIST_ID()).clear()
+ aCenterSketchPointAttr = self.refattr(self.CENTER_REF_ID())
+ aCenterSketchPointAttr.reset()
+ self.attribute(self.START_ID()).reset()
+ self.attribute(self.END_ID()).reset()
+ self.attribute(self.CENTER_ID()).reset()
+ self.attribute(self.CORNER_ID()).reset()
+
+
+ def __getPoint2DAttrOfSketchPoint(self, theSketchPointRefAttr):
+ if theSketchPointRefAttr.isObject() and theSketchPointRefAttr.object() is not None:
+ feature = ModelAPI.ModelAPI_Feature.feature(theSketchPointRefAttr.object())
if feature.getKind() == "SketchPoint":
return feature.attribute("PointCoordinates")
else:
- return theRef.attr()
- return None
-
- def getPointByRef(self, thePoint, theRef):
- attr = thePoint
- if theRef.isInitialized():
- refPnt = self.getReferencePoint(theRef)
- if refPnt is not None:
- attr = refPnt
+ return theSketchPointRefAttr.attr()
+
+
+ def __getPoint2D(self, thePoint2DAttr, theSketchPointRefAttr):
+ attr = thePoint2DAttr
+ if theSketchPointRefAttr.isInitialized():
+ aPoint2DAttr = self.__getPoint2DAttrOfSketchPoint(theSketchPointRefAttr)
+ if aPoint2DAttr is not None:
+ attr = aPoint2DAttr
if attr is None or not attr.isInitialized():
return None
return GeomDataAPI.geomDataAPI_Point2D(attr).pnt()
- def updateLines(self):
- # Retrieving list of already created lines
- aLinesList = self.reflist(self.LINES_LIST_ID())
- aNbLines = min(aLinesList.size(), 4)
+
+ def __updateLines(self):
if self.string(self.RECTANGLE_TYPE_ID()).value() == self.RECTANGLE_CENTERED_ID():
- aCenter = self.getPointByRef(self.attribute(self.CENTER_ID()), self.refattr(self.CENTER_REF_ID()))
+ aCenter = self.__getPoint2D(self.attribute(self.CENTER_ID()), self.refattr(self.CENTER_REF_ID()))
aCorner = GeomDataAPI.geomDataAPI_Point2D(self.attribute(self.CORNER_ID()))
aStartX = 2.0 * aCenter.x() - aCorner.x()
aStartY = 2.0 * aCenter.y() - aCorner.y()
aStartPoint = GeomDataAPI.geomDataAPI_Point2D(self.attribute(self.START_ID()))
aEndPoint = GeomDataAPI.geomDataAPI_Point2D(self.attribute(self.END_ID()))
aX = [aStartPoint.x(), aStartPoint.x(), aEndPoint.x(), aEndPoint.x()]
- aY = [aStartPoint.y(), aEndPoint.y(), aEndPoint.y(), aStartPoint.y()]
- anAuxiliary = self.data().boolean(self.AUXILIARY_ID()).value()
+ aY = [aStartPoint.y(), aEndPoint.y(), aEndPoint.y(), aStartPoint.y()]
+
+ # Retrieve list of already created lines
+ aLinesList = self.reflist(self.LINES_LIST_ID())
+ aNumOfContourLines = min(aLinesList.size(), 4)
- # do not recalculate the rectrangle after each update
+ # Do not update lines during update of coordinates
wasBlocked = []
for i in range (0, aLinesList.size()):
wasBlocked.append(aLinesList.object(i).data().blockSendAttributeUpdated(True))
# Update coordinates of rectangle lines
- for i in range (0, aNbLines):
+ anAuxiliary = self.data().boolean(self.AUXILIARY_ID()).value()
+ for i in range (0, aNumOfContourLines):
aLine = ModelAPI.objectToFeature(aLinesList.object(i))
aLineStart = GeomDataAPI.geomDataAPI_Point2D(aLine.attribute("StartPoint"))
aLineEnd = GeomDataAPI.geomDataAPI_Point2D(aLine.attribute("EndPoint"))
# Update auxiliary diagonals
if self.string(self.RECTANGLE_TYPE_ID()).value() == self.RECTANGLE_CENTERED_ID():
- for i in range (aNbLines, aLinesList.size()):
+ for i in range (aNumOfContourLines, aLinesList.size()):
aLine = ModelAPI.objectToFeature(aLinesList.object(i))
aLineStart = GeomDataAPI.geomDataAPI_Point2D(aLine.attribute("StartPoint"))
aLineEnd = GeomDataAPI.geomDataAPI_Point2D(aLine.attribute("EndPoint"))
- aLineStart.setValue(aX[i-aNbLines-1], aY[i-aNbLines-1])
- aLineEnd.setValue(aX[i-aNbLines+1], aY[i-aNbLines+1])
+ aLineStart.setValue(aX[i-aNumOfContourLines-1], aY[i-aNumOfContourLines-1])
+ aLineEnd.setValue(aX[i-aNumOfContourLines+1], aY[i-aNumOfContourLines+1])
aLine.data().boolean("Auxiliary").setValue(True)
- # update the rectangle
+ # Update the rectangle
for i in range (0, aLinesList.size()):
aLinesList.object(i).data().blockSendAttributeUpdated(wasBlocked[i], True)
- def updateStartPoint(self):
- # Retrieving list of already created lines
+
+ def __updateLinesWithOnlyGenerativePoint(self):
+ # Retrieve list of already created lines
aLinesList = self.reflist(self.LINES_LIST_ID())
aNbLines = aLinesList.size()
aX = aStartPoint.x()
aY = aStartPoint.y()
else:
- aCenter = self.getPointByRef(self.attribute(self.CENTER_ID()), self.refattr(self.CENTER_REF_ID()))
+ aCenter = self.__getPoint2D(self.attribute(self.CENTER_ID()), self.refattr(self.CENTER_REF_ID()))
aX = aCenter.x()
aY = aCenter.y()
}
SketchAPI_Rectangle::SketchAPI_Rectangle(const std::shared_ptr<ModelAPI_Feature> & theFeature,
- double theX1, double theY1, double theX2, double theY2)
+ double theX1, double theY1,
+ double theX2, double theY2,
+ bool theCreateByCenterAndCorner)
: SketchAPI_SketchEntity(theFeature)
{
if (initialize()) {
- setByCoordinates(theX1, theY1, theX2, theY2);
+ theCreateByCenterAndCorner ? setByCenterAndCornerCoords(theX1, theY1, theX2, theY2) : setByCoordinates(theX1, theY1, theX2, theY2);
}
}
SketchAPI_Rectangle::SketchAPI_Rectangle(const std::shared_ptr<ModelAPI_Feature> & theFeature,
- const std::shared_ptr<GeomAPI_Pnt2d> & theFirstPoint,
- const std::shared_ptr<GeomAPI_Pnt2d> & theEndPoint)
+ const std::shared_ptr<GeomAPI_Pnt2d> & thePoint1,
+ const std::shared_ptr<GeomAPI_Pnt2d> & thePoint2,
+ bool theCreateByCenterAndCorner)
: SketchAPI_SketchEntity(theFeature)
{
if (initialize()) {
- setByPoints(theFirstPoint, theEndPoint);
+ theCreateByCenterAndCorner ? setByCenterAndCornerPoints(thePoint1, thePoint2) : setByPoints(thePoint1, thePoint2);
}
}
execute();
}
+void SketchAPI_Rectangle::setByCenterAndCornerCoords(
+ double theCenterX, double theCenterY,
+ double theCornerX, double theCornerY
+) {
+ fillAttribute("RectangleTypeCentered", type());
+ fillAttribute(centerPoint(), theCenterX, theCenterY);
+ fillAttribute(cornerPoint(), theCornerX, theCornerY);
+ execute();
+}
+
+void SketchAPI_Rectangle::setByCenterAndCornerPoints(
+ const std::shared_ptr<GeomAPI_Pnt2d> & theCenterPoint,
+ const std::shared_ptr<GeomAPI_Pnt2d> & theCornerPoint
+) {
+ fillAttribute("RectangleTypeCentered", type());
+ fillAttribute(theCenterPoint, centerPoint());
+ fillAttribute(theCornerPoint, cornerPoint());
+ execute();
+}
+
//--------------------------------------------------------------------------------------
std::list<std::shared_ptr<SketchAPI_SketchEntity> > SketchAPI_Rectangle::lines() const
/// Constructor with values
SKETCHAPI_EXPORT
SketchAPI_Rectangle(const std::shared_ptr<ModelAPI_Feature> & theFeature,
- double theX1, double theY1, double theX2, double theY2);
+ double theX1, double theY1,
+ double theX2, double theY2,
+ bool theCreateByCenterAndCorner = false);
/// Constructor with values
SKETCHAPI_EXPORT
SketchAPI_Rectangle(const std::shared_ptr<ModelAPI_Feature> & theFeature,
- const std::shared_ptr<GeomAPI_Pnt2d> & theFirstPoint,
- const std::shared_ptr<GeomAPI_Pnt2d> & theEndPoint);
+ const std::shared_ptr<GeomAPI_Pnt2d> & thePoint1,
+ const std::shared_ptr<GeomAPI_Pnt2d> & thePoint2,
+ bool theCreateByCenterAndCorner = false);
+
+
+
/// Destructor
SKETCHAPI_EXPORT
virtual ~SketchAPI_Rectangle();
void setByPoints(const std::shared_ptr<GeomAPI_Pnt2d> & theFirstPoint,
const std::shared_ptr<GeomAPI_Pnt2d> & theSecondPoint);
+ /// Set by coordinates
+ SKETCHAPI_EXPORT
+ void setByCenterAndCornerCoords(
+ double theCenterX, double theCenterY,
+ double theCornerX, double theCornerY
+ );
+
+ /// Set by points
+ SKETCHAPI_EXPORT
+ void setByCenterAndCornerPoints(
+ const std::shared_ptr<GeomAPI_Pnt2d> & theCenterPoint,
+ const std::shared_ptr<GeomAPI_Pnt2d> & theCornerPoint
+ );
+
/// List of lines composing rectangle
SKETCHAPI_EXPORT std::list<std::shared_ptr<SketchAPI_SketchEntity> > lines() const;
};
std::shared_ptr<SketchAPI_Rectangle> SketchAPI_Sketch::addRectangle(double theX1, double theY1,
double theX2, double theY2)
{
- std::shared_ptr<ModelAPI_Feature> aFeature =
- compositeFeature()->addFeature(SketchAPI_Rectangle::ID());
+ std::shared_ptr<ModelAPI_Feature> aFeature = compositeFeature()->addFeature(SketchAPI_Rectangle::ID());
return RectanglePtr(new SketchAPI_Rectangle(aFeature, theX1, theY1, theX2, theY2));
}
-std::shared_ptr<SketchAPI_Rectangle> SketchAPI_Sketch::addRectangle(
- const std::shared_ptr<GeomAPI_Pnt2d> & theStartPoint,
- const std::shared_ptr<GeomAPI_Pnt2d> & theEndPoint)
-{
- std::shared_ptr<ModelAPI_Feature> aFeature =
- compositeFeature()->addFeature(SketchAPI_Rectangle::ID());
- return RectanglePtr(new SketchAPI_Rectangle(aFeature, theStartPoint, theEndPoint));
-}
static std::shared_ptr<GeomAPI_Pnt2d> pointCoordinates(
const std::pair<std::shared_ptr<GeomAPI_Pnt2d>, ModelHighAPI_RefAttr> & thePoint)
anAttr = aFeature->attribute(SketchPlugin_Point::COORD_ID());
}
- std::shared_ptr<GeomDataAPI_Point2D> aPntAttr =
- std::dynamic_pointer_cast<GeomDataAPI_Point2D>(anAttr);
+ std::shared_ptr<GeomDataAPI_Point2D> aPntAttr = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(anAttr);
if (aPntAttr)
return aPntAttr->pnt();
return std::shared_ptr<GeomAPI_Pnt2d>();
}
+std::shared_ptr<SketchAPI_Rectangle> SketchAPI_Sketch::addRectangle(
+ const std::pair<std::shared_ptr<GeomAPI_Pnt2d>, ModelHighAPI_RefAttr> & theStartPoint,
+ const std::pair<std::shared_ptr<GeomAPI_Pnt2d>, ModelHighAPI_RefAttr> & theEndPoint)
+{
+ std::shared_ptr<ModelAPI_Feature> aFeature = compositeFeature()->addFeature(SketchAPI_Rectangle::ID());
+ RectanglePtr aRect(new SketchAPI_Rectangle(aFeature));
+ fillAttribute("RectangleTypeByCorners", aRect->type());
+ fillAttribute(pointCoordinates(theStartPoint), aRect->startPoint());
+ fillAttribute(pointCoordinates(theEndPoint), aRect->endPoint());
+ aRect->execute();
+
+ if (!theStartPoint.second.isEmpty() && aRect->linesList()->size() >= 1) {
+ // Get end point of the first line in rectangle and apply coincidence constraint
+ FeaturePtr aLine = ModelAPI_Feature::feature(aRect->linesList()->object(0));
+ AttributePtr aLinePnt = aLine->attribute(SketchPlugin_Line::END_ID());
+ setCoincident(ModelHighAPI_RefAttr(aLinePnt), theStartPoint.second);
+ }
+
+ if (!theEndPoint.second.isEmpty() && aRect->linesList()->size() >= 4) {
+ // Get start point of the last line in rectangle and apply coincidence constraint
+ FeaturePtr aLine = ModelAPI_Feature::feature(aRect->linesList()->object(3));
+ AttributePtr aLinePnt = aLine->attribute(SketchPlugin_Line::START_ID());
+ setCoincident(ModelHighAPI_RefAttr(aLinePnt), theEndPoint.second);
+ }
+ return aRect;
+}
+
std::shared_ptr<SketchAPI_Rectangle> SketchAPI_Sketch::addRectangleCentered(
const std::pair<std::shared_ptr<GeomAPI_Pnt2d>, ModelHighAPI_RefAttr> & theCenter,
const std::pair<std::shared_ptr<GeomAPI_Pnt2d>, ModelHighAPI_RefAttr> & theCorner)
{
- std::shared_ptr<ModelAPI_Feature> aFeature =
- compositeFeature()->addFeature(SketchAPI_Rectangle::ID());
+ std::shared_ptr<ModelAPI_Feature> aFeature = compositeFeature()->addFeature(SketchAPI_Rectangle::ID());
RectanglePtr aRect(new SketchAPI_Rectangle(aFeature));
fillAttribute("RectangleTypeCentered", aRect->type());
+
if (!theCenter.second.isEmpty())
fillAttribute(theCenter.second, aRect->centerPointRef());
- fillAttribute(pointCoordinates(theCenter), aRect->centerPoint());
+ else
+ fillAttribute(pointCoordinates(theCenter), aRect->centerPoint());
+
fillAttribute(pointCoordinates(theCorner), aRect->cornerPoint());
aRect->execute();
- if (!theCorner.second.isEmpty() && aRect->linesList()->size() > 1) {
- // get start point of the last line in rectangle and apply coindidence constraint
+ if (!theCorner.second.isEmpty() && aRect->linesList()->size() >= 4) {
+ // get start point of the last line in rectangle and apply coincidence constraint
FeaturePtr aLine = ModelAPI_Feature::feature(aRect->linesList()->object(3));
AttributePtr aEndPnt = aLine->attribute(SketchPlugin_Line::START_ID());
setCoincident(ModelHighAPI_RefAttr(aEndPnt), theCorner.second);
return aRect;
}
+std::shared_ptr<SketchAPI_Rectangle> SketchAPI_Sketch::addRectangleCentered(
+ double theCenterX, double theCenterY,
+ double theCornerX, double theCornerY
+) {
+ std::shared_ptr<ModelAPI_Feature> aFeature = compositeFeature()->addFeature(SketchAPI_Rectangle::ID());
+ return RectanglePtr(new SketchAPI_Rectangle(aFeature, theCenterX, theCenterY, theCornerX, theCornerY, true));
+}
+
//--------------------------------------------------------------------------------------
std::shared_ptr<SketchAPI_Circle> SketchAPI_Sketch::addCircle(double theCenterX,
double theCenterY,
/// Add rectangle
SKETCHAPI_EXPORT
std::shared_ptr<SketchAPI_Rectangle> addRectangle(
- const std::shared_ptr<GeomAPI_Pnt2d> & theStartPoint,
- const std::shared_ptr<GeomAPI_Pnt2d> & theEndPoint);
+ const std::pair<std::shared_ptr<GeomAPI_Pnt2d>, ModelHighAPI_RefAttr> & theStartPoint,
+ const std::pair<std::shared_ptr<GeomAPI_Pnt2d>, ModelHighAPI_RefAttr> & theEndPoint);
/// Add rectangle
SKETCHAPI_EXPORT
std::shared_ptr<SketchAPI_Rectangle> addRectangleCentered(
const std::pair<std::shared_ptr<GeomAPI_Pnt2d>, ModelHighAPI_RefAttr> & theCenter,
const std::pair<std::shared_ptr<GeomAPI_Pnt2d>, ModelHighAPI_RefAttr> & theCorner);
+ /// Add rectangle
+ SKETCHAPI_EXPORT
+ std::shared_ptr<SketchAPI_Rectangle> addRectangleCentered(
+ double theCenterX, double theCenterY,
+ double theCornerX, double theCornerY
+ );
/// Add circle
SKETCHAPI_EXPORT
--- /dev/null
+# Copyright (C) 2014-2023 CEA, EDF
+#
+# This library is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public
+# 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
+#
+
+"""
+ TestRectangle.py
+ Unit test of SketchPlugin_Rectangle class (centered rectangle case)
+
+"""
+from GeomDataAPI import *
+from ModelAPI import *
+import math
+from salome.shaper import model
+
+#=========================================================================
+# Initialization of the test
+#=========================================================================
+
+__updated__ = "2023-08-07"
+
+
+#=========================================================================
+# Auxiliary functions
+#=========================================================================
+def isHorizontal(line):
+ aStart = geomDataAPI_Point2D(line.attribute("StartPoint"))
+ aEnd = geomDataAPI_Point2D(line.attribute("EndPoint"))
+ return aStart.y() == aEnd.y()
+
+def isVertical(line):
+ aStart = geomDataAPI_Point2D(line.attribute("StartPoint"))
+ aEnd = geomDataAPI_Point2D(line.attribute("EndPoint"))
+ return aStart.x() == aEnd.x()
+
+def areCounterDirectedAndOfEqualLength(theLineA, theLineB):
+ tolerance = 1.e-5
+
+ aStartA = geomDataAPI_Point2D(theLineA.attribute("StartPoint"))
+ aEndA = geomDataAPI_Point2D(theLineA.attribute("EndPoint"))
+ aDirA_X = aEndA.x() - aStartA.x()
+ aDirA_Y = aEndA.y() - aStartA.y()
+
+ aStartB = geomDataAPI_Point2D(theLineB.attribute("StartPoint"))
+ aEndB = geomDataAPI_Point2D(theLineB.attribute("EndPoint"))
+ aDirB_X = aEndB.x() - aStartB.x()
+ aDirB_Y = aEndB.y() - aStartB.y()
+
+ return abs(aDirA_X + aDirB_X) < tolerance and abs(aDirA_Y + aDirB_Y) < tolerance
+
+def arePerpendicular(theLineA, theLineB):
+ tolerance = 1.e-5
+
+ aStartA = geomDataAPI_Point2D(theLineA.attribute("StartPoint"))
+ aEndA = geomDataAPI_Point2D(theLineA.attribute("EndPoint"))
+ aDirA_X = aEndA.x() - aStartA.x()
+ aDirA_Y = aEndA.y() - aStartA.y()
+ aLengthA = theLineA.lastResult().shape().edge().length()
+
+ aStartB = geomDataAPI_Point2D(theLineB.attribute("StartPoint"))
+ aEndB = geomDataAPI_Point2D(theLineB.attribute("EndPoint"))
+ aDirB_X = aEndB.x() - aStartB.x()
+ aDirB_Y = aEndB.y() - aStartB.y()
+ aLengthB = theLineB.lastResult().shape().edge().length()
+
+ if (aLengthA < tolerance or aLengthB < tolerance):
+ return True
+
+ return (aDirA_X * aDirB_X + aDirA_Y * aDirB_Y) / (aLengthA * aLengthB) < tolerance
+
+def areConnected(theLineA, theLineB):
+ aEndA = geomDataAPI_Point2D(theLineA.attribute("EndPoint"))
+ aStartB = geomDataAPI_Point2D(theLineB.attribute("StartPoint"))
+ return aEndA.x() == aStartB.x() and aEndA.y() == aStartB.y()
+
+
+#=========================================================================
+# Start of test
+#=========================================================================
+aSession = ModelAPI_Session.get()
+aDocument = aSession.moduleDocument()
+#=========================================================================
+# Creation of a sketch
+#=========================================================================
+aSession.startOperation()
+aSketchFeature = featureToCompositeFeature(aDocument.addFeature("Sketch"))
+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 a rectangle
+#=========================================================================
+aSession.startOperation()
+aRectangle = aSketchFeature.addFeature("SketchRectangle")
+aRectangle.string("RectangleType").setValue("RectangleTypeCentered")
+aCenter = geomDataAPI_Point2D(aRectangle.attribute("RectCenterPoint"))
+aCorner = geomDataAPI_Point2D(aRectangle.attribute("RectCornerPoint"))
+aCenter.setValue(10., 10.)
+aCorner.setValue(40., 30.)
+aSession.finishOperation()
+#=========================================================================
+# Check the lines of rectangle are parallel to the axes
+#=========================================================================
+aNbSubs = aSketchFeature.numberOfSubs()
+assert (aNbSubs >= 5) # The first feature on the sketch is center SketchPoint.
+aNbLines = 0
+for i in range (1, 5):
+ aFeature = objectToFeature(aSketchFeature.subFeature(i))
+ if aFeature.getKind() == "SketchLine":
+ aLastLine = aFeature
+ assert (isHorizontal(aLastLine) or isVertical(aLastLine))
+ aNbLines = aNbLines + 1
+assert (aNbLines == 4)
+assert (model.dof(aSketchFeature) == 5)
+#=========================================================================
+# Move one of lines
+#=========================================================================
+aSession.startOperation()
+aLineEnd = geomDataAPI_Point2D(aLastLine.attribute("EndPoint"))
+aLineEnd.setValue(41., 30.)
+aSession.finishOperation()
+
+#=========================================================================
+# Check the opposites lines of rectangle are parallel, and neighboring
+# ones are perpendicular
+#=========================================================================
+aLine0 = objectToFeature(aSketchFeature.subFeature(1))
+assert (aLine0.getKind() == "SketchLine")
+
+aLine1 = objectToFeature(aSketchFeature.subFeature(2))
+assert (aLine1.getKind() == "SketchLine")
+
+aLine2 = objectToFeature(aSketchFeature.subFeature(3))
+assert (aLine2.getKind() == "SketchLine")
+
+aLine3 = objectToFeature(aSketchFeature.subFeature(4))
+assert (aLine3.getKind() == "SketchLine")
+
+assert (areCounterDirectedAndOfEqualLength(aLine0, aLine2))
+assert (areCounterDirectedAndOfEqualLength(aLine1, aLine3))
+assert (arePerpendicular(aLine0, aLine1))
+assert (arePerpendicular(aLine2, aLine3))
+
+#=========================================================================
+# Check the contour is closed
+#=========================================================================
+assert (areConnected(aLine0, aLine1))
+assert (areConnected(aLine1, aLine2))
+assert (areConnected(aLine2, aLine3))
+assert (areConnected(aLine3, aLine0))
+
+#=========================================================================
+# End of test
+#=========================================================================
+
+assert(model.checkPythonDump())
+#!/usr/bin/env python
+"""Un exemple de création d'un rectangle"""
+
from salome.shaper import model
from salome.shaper import geom
+
model.begin()
partSet = model.moduleDocument()
+
+### Create Part
Part_1 = model.addPart(partSet)
Part_1_doc = Part_1.document()
+
+### Create Sketch
Sketch_1 = model.addSketch(Part_1_doc, model.defaultPlane("XOY"))
-Rectangle_1 = Sketch_1.addRectangle(5.5, 8.5, 31.3, 78.9)
-# rectangle from center and end points
-center = geom.Pnt2d(10, 5)
-corner = geom.Pnt2d(25, 75)
-rectangle_2 = sketch.addRectangleCentered(center, corner)
+
+
+### Rectangle by corners defined with doubles.
+rectWithFloats = Sketch_1.addRectangle(-8, -8, -5, -3)
+############################################################
+
+
+### Rectangle by corners defined with SketchPoints.
+SP_corner1 = Sketch_1.addPoint(-8, 8)
+SP_corner2 = Sketch_1.addPoint(-5, 3)
+
+rectWithSPs = Sketch_1.addRectangle(SP_corner1, SP_corner2)
+############################################################
+
+
+### Rectangle by corners defined with Pnt2Ds.
+Pnt2D_corner1 = geom.Pnt2d(-8 - 5, 8)
+Pnt2D_corner2 = geom.Pnt2d(-5 - 5, 3)
+
+rectWithPnt2Ds = Sketch_1.addRectangle(Pnt2D_corner1, Pnt2D_corner2)
+############################################################
+
+
+############################################################
+############################################################
+### Rectangle by center and corner defined with Pnt2Ds.
+Pnt2D_center = geom.Pnt2d(6.5 + 5, 5.5)
+Pnt2D_corner = geom.Pnt2d(8.0 + 5, 8.0)
+
+rectCenteredWithPnt2Ds = Sketch_1.addRectangleCentered(Pnt2D_center, Pnt2D_corner)
+############################################################
+
+
+### Rectangle by center and corner defined with SketchPoints.
+SP_center = Sketch_1.addPoint(6.5, 5.5)
+SP_corner = Sketch_1.addPoint(8.0, 8.0)
+
+rectCenteredWithPnt2Ds = Sketch_1.addRectangleCentered(SP_center, SP_corner)
+############################################################
+
+
+### Rectangle by center and corner defined with doubles.
+rectCenteredWithDoubles = Sketch_1.addRectangleCentered(6.5, -5.5, 8.0, -8.0)
+############################################################
model.do()
-model.end()
+model.end()
\ No newline at end of file
TestProjectionUpdate.py
TestProjectionWithoutReference.py
TestRectangle1.py
+ TestRectangleCentered1.py
TestRemainingDoF.py
TestRemoveBSpline.py
TestRemoveBSplinePeriodic.py