X-Git-Url: http://git.salome-platform.org/gitweb/?a=blobdiff_plain;f=src%2FPythonAddons%2Fmacros%2Frectangle%2Ffeature.py;h=d2df5435642ab693c5be44bba2a62f0647b692f5;hb=e466624749375b6ead3e8a8ded26bf29ea9325ae;hp=747664f0b6fc1447c5d312f55364f7d6f39f577d;hpb=f063806a5a0ccea75f7d2f9aa032be4270afd557;p=modules%2Fshaper.git diff --git a/src/PythonAddons/macros/rectangle/feature.py b/src/PythonAddons/macros/rectangle/feature.py index 747664f0b..d2df54356 100755 --- a/src/PythonAddons/macros/rectangle/feature.py +++ b/src/PythonAddons/macros/rectangle/feature.py @@ -1,4 +1,4 @@ -# Copyright (C) 2014-2022 CEA/DEN, EDF R&D +# Copyright (C) 2014-2024 CEA, EDF # # This library is free software; you can redistribute it and/or # modify it under the terms of the GNU Lesser General Public @@ -105,20 +105,20 @@ class SketchPlugin_Rectangle(model.Feature): def initAttributes(self): """Override Feature.initAttributes()""" # Flag whether the rectangle is accessory - self.data().addAttribute(self.AUXILIARY_ID(), ModelAPI.ModelAPI_AttributeBoolean_typeId()) - # Creating corners of the rectangle - 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 - self.data().addAttribute(self.LINES_LIST_ID(), ModelAPI.ModelAPI_AttributeRefList_typeId()) + self.data().addAttribute(self.AUXILIARY_ID(), ModelAPI.ModelAPI_AttributeBoolean.typeId()) + # 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()) + # 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 - self.data().addAttribute(self.CENTER_ID(), GeomDataAPI.GeomDataAPI_Point2D_typeId()) - self.data().addAttribute(self.CORNER_ID(), GeomDataAPI.GeomDataAPI_Point2D_typeId()) + self.data().addAttribute(self.RECTANGLE_TYPE_ID(), ModelAPI.ModelAPI_AttributeString.typeId()) + # 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()) - self.data().addAttribute(self.CENTER_REF_ID(), ModelAPI.ModelAPI_AttributeRefAttr_typeId()) + self.data().addAttribute(self.CENTER_REF_ID(), ModelAPI.ModelAPI_AttributeRefAttr.typeId()) ModelAPI.ModelAPI_Session.get().validators().registerNotObligatory(self.getKind(), self.CENTER_REF_ID()) def isMacro(self): @@ -128,144 +128,191 @@ class SketchPlugin_Rectangle(model.Feature): """ 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() @@ -275,16 +322,20 @@ class SketchPlugin_Rectangle(model.Feature): 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")) @@ -294,20 +345,21 @@ class SketchPlugin_Rectangle(model.Feature): # 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() @@ -316,7 +368,7 @@ class SketchPlugin_Rectangle(model.Feature): 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()