%include "std_string.i"
%include "std_list.i"
%include "std_shared_ptr.i"
+%include "std_set.i"
// directors
%feature("director") ModelAPI_Plugin;
%template(ObjectList) std::list<std::shared_ptr<ModelAPI_Object> >;
%template(ResultList) std::list<std::shared_ptr<ModelAPI_Result> >;
%template(DocumentList) std::list<std::shared_ptr<ModelAPI_Document> >;
+// std::set -> []
+%template(AttributeSet) std::set<std::shared_ptr<ModelAPI_Attribute> >;
// std::dynamic_pointer_cast
template<class T1, class T2> std::shared_ptr<T1> shared_ptr_cast(std::shared_ptr<T2> theObject);
<file>icons/plane_view.png</file>
<file>icons/collinear.png</file>
<file>icons/middlepoint.png</file>
+ <file>icons/rectangle.png</file>
</qresource>
</RCC>
"""
import ModelAPI
-from macros.box.feature import BoxFeature
+from macros.box.feature import BoxFeature
+from macros.rectangle.feature import SketchPlugin_Rectangle
class PythonFeaturesPlugin(ModelAPI.ModelAPI_Plugin):
if theFeatureID == BoxFeature.ID():
aFeature = BoxFeature().__disown__()
+ elif theFeatureID == SketchPlugin_Rectangle.ID():
+ aFeature = SketchPlugin_Rectangle().__disown__()
+
else:
raise StandardError("No such feature %s" % theFeatureID)
<plugin>
<source path="../addons/macros/box/widget.xml"/>
+ <source path="../addons/macros/rectangle/widget.xml"/>
</plugin>
--- /dev/null
+"""
+Macro-feature to produce rectangle in the sketcher
+Author: Artem ZHIDKOV
+Copyright (C) 2016-20xx CEA/DEN, EDF R&D
+"""
+
+import model
+import ModelAPI
+import GeomDataAPI
+
+class SketchPlugin_Rectangle(model.Feature):
+ """
+ Implementation of rectangle creation.
+
+ It produced 2 horizontal lines and 2 vertical lines connected by coincidence constraints
+ """
+
+# Initializations
+
+ def __init__(self):
+ """x.__init__(...) initializes x; see x.__class__.__doc__ for signature"""
+ model.Feature.__init__(self)
+
+ @staticmethod
+ def ID():
+ """Rectangle feature kind."""
+ return "SketchRectangle"
+
+ @staticmethod
+ def START_ID():
+ """Returns ID of first corner."""
+ return "RectStartPoint"
+
+ @staticmethod
+ def END_ID():
+ """Returns ID of second corner."""
+ return "RectEndPoint"
+
+ @staticmethod
+ def AUXILIARY_ID():
+ """Returns whether the rectangle is accessory."""
+ return "Auxiliary"
+
+ @staticmethod
+ def LINES_LIST_ID():
+ """Returns ID of list containing lines created."""
+ return "RectangleList"
+
+ def getKind(self):
+ """Override Feature.getKind()"""
+ return SketchPlugin_Rectangle.ID()
+
+
+# Initialization of the rectangle
+
+ 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())
+ ModelAPI.ModelAPI_Session.get().validators().registerNotObligatory(self.getKind(), self.LINES_LIST_ID())
+
+ def isMacro(self):
+ """
+ Override Feature.isMacro().
+ Rectangle feature is macro: removes itself on the creation transaction finish.
+ """
+ return True
+
+# Edition of the rectangle
+
+ def execute(self):
+ # Retrieving list of already created lines
+ aLinesList = self.reflist(self.LINES_LIST_ID())
+ aNbLines = aLinesList.size()
+ if aNbLines == 0:
+ # Search the sketch containing this rectangle
+ self.__sketch = None
+ aRefs = self.data().refsToMe();
+ for iter in aRefs:
+ aFeature = ModelAPI.objectToFeature(iter.owner())
+ if aFeature.getKind() == "Sketch":
+ self.__sketch = ModelAPI.featureToCompositeFeature(aFeature)
+ break
+ # Create lines to compose the rectangle
+ for i in range (0, 4):
+ aLine = self.__sketch.addFeature("SketchLine")
+ aLinesList.append(aLine)
+ aNbLines = aLinesList.size()
+ # Create constraints to keep the rectangle
+ for i in range (0, aNbLines):
+ aLine = ModelAPI.objectToFeature(aLinesList.object(i))
+ # connect neighbor lines by coincidence
+ iPrev = i - 1
+ if iPrev < 0:
+ iPrev = aNbLines - 1
+ 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"))
+ # Flags which show horizontal or vertical constraint is build for correponding line
+ self.__isHV = [False, False, False, False]
+ # Update coordinates of created lines
+ self.updateLines()
+ # Add horizontal and vertical constraint for the lines which already have result
+ for i in range (0, aNbLines):
+ if self.__isHV[i]:
+ continue
+ aLine = ModelAPI.objectToFeature(aLinesList.object(i))
+ aLineResult = aLine.lastResult()
+ if aLineResult is None:
+ continue
+ aHVName = "SketchConstraintHorizontal"
+ if i % 2 == 1:
+ aHVName = "SketchConstraintVertical"
+ aHVConstraint = self.__sketch.addFeature(aHVName)
+ aRefAttrA = aHVConstraint.refattr("ConstraintEntityA")
+ aRefAttrA.setObject(aLine.lastResult())
+ self.__isHV[i] = True
+
+ def attributeChanged(self, theID):
+ if theID == self.START_ID() or theID == self.END_ID():
+ aStartPoint = GeomDataAPI.geomDataAPI_Point2D(self.attribute(self.START_ID()))
+ aEndPoint = GeomDataAPI.geomDataAPI_Point2D(self.attribute(self.END_ID()))
+ if aStartPoint.isInitialized() and aEndPoint.isInitialized:
+ self.updateLines()
+
+ def updateLines(self):
+ # Retrieving list of already created lines
+ aLinesList = self.reflist(self.LINES_LIST_ID())
+ aNbLines = aLinesList.size()
+
+ 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()]
+
+ # Update coordinates of rectangle lines
+ for i in range (0, aNbLines):
+ aLine = ModelAPI.objectToFeature(aLinesList.object(i))
+ aLineStart = GeomDataAPI.geomDataAPI_Point2D(aLine.attribute("StartPoint"))
+ aLineEnd = GeomDataAPI.geomDataAPI_Point2D(aLine.attribute("EndPoint"))
+ aLineStart.setValue(aX[i-1], aY[i-1])
+ aLineEnd.setValue(aX[i], aY[i])
--- /dev/null
+<source>
+ <workbench id="Sketch">
+ <group id="Macro">
+
+ <!-- SketchRectangle (python feature) -->
+ <feature
+ id="SketchRectangle"
+ title="Rectangle"
+ tooltip="Create rectangle"
+ icon=":icons/rectangle.png">
+ <sketch-2dpoint_selector id="RectStartPoint" accept_expressions="0" title="Start point" tooltip="Start point coordinates"/>
+ <sketch-2dpoint_selector id="RectEndPoint" accept_expressions="0" title="End point" tooltip="End point coordinates"/>
+ <boolvalue id="Auxiliary" label="Auxiliary" default="false" tooltip="Construction element" obligatory="0"/>
+ <validator id="GeomValidators_Different" parameters="RectStartPoint,RectEndPoint"/>
+ </feature>
+
+ </group>
+ </workbench>
+</source>
TestMultiRotation.py
TestMultiTranslation.py
TestFillet.py
+ TestRectangle.py
TestHighload.py
TestSnowflake.py)
aMsg->setState(SketchPlugin_ConstraintAngle::ID(), aHasSketchPlane);
aMsg->setState(SketchPlugin_MultiRotation::ID(), aHasSketchPlane);
aMsg->setState(SketchPlugin_MultiTranslation::ID(), aHasSketchPlane);
+ // SketchRectangle is a python feature, so its ID is passed just as a string
+ aMsg->setState("SketchRectangle", aHasSketchPlane);
}
}
return aMsg;
{
std::shared_ptr<ModelAPI_Feature> aNew = document()->addFeature(theID, false);
if (aNew) {
- std::dynamic_pointer_cast<SketchPlugin_Feature>(aNew)->setSketch(this);
+ // the sketch cannot be specified for the macro-features defined in python
+ // like SketchRectangle, so we need to check the type of new feature
+ std::shared_ptr<SketchPlugin_Feature> aSketchFeature =
+ std::dynamic_pointer_cast<SketchPlugin_Feature>(aNew);
+ if (aSketchFeature)
+ aSketchFeature->setSketch(this);
data()->reflist(SketchPlugin_Sketch::FEATURES_ID())->append(aNew);
}
// set as current also after it becomes sub to set correctly enabled for other sketch subs
--- /dev/null
+"""
+ TestRectangle.py
+ Unit test of SketchPlugin_Ractangle class
+
+"""
+from GeomDataAPI import *
+from ModelAPI import *
+import math
+#=========================================================================
+# Initialization of the test
+#=========================================================================
+
+__updated__ = "2016-02-05"
+
+
+#=========================================================================
+# 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()
+
+
+#=========================================================================
+# 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")
+aStartCorner = geomDataAPI_Point2D(aRectangle.attribute("RectStartPoint"))
+aEndCorner = geomDataAPI_Point2D(aRectangle.attribute("RectEndPoint"))
+aStartCorner.setValue(10., 10.)
+aEndCorner.setValue(40., 30.)
+aSession.finishOperation()
+#=========================================================================
+# Check the lines of rectangle are parallel to the axes
+#=========================================================================
+aNbSubs = aSketchFeature.numberOfSubs()
+aNbLines = 0
+for i in range (0, aNbSubs):
+ aFeature = objectToFeature(aSketchFeature.subFeature(i))
+ if aFeature.getKind() == "SketchLine":
+ aLastLine = aFeature
+ assert (isHorizontal(aLastLine) or isVertical(aLastLine))
+ aNbLines = aNbLines + 1
+assert (aNbLines == 4)
+#=========================================================================
+# Move one of lines
+#=========================================================================
+aSession.startOperation()
+aLineEnd = geomDataAPI_Point2D(aLastLine.attribute("EndPoint"))
+aLineEnd.setValue(50., 50.)
+aSession.finishOperation()
+#=========================================================================
+# Check the lines of rectangle are parallel to the axes
+#=========================================================================
+aNbSubs = aSketchFeature.numberOfSubs()
+aNbLines = 0
+for i in range (0, aNbSubs):
+ aFeature = objectToFeature(aSketchFeature.subFeature(i))
+ if aFeature.getKind() == "SketchLine":
+ aLastLine = aFeature
+ assert (isHorizontal(aLastLine) or isVertical(aLastLine))
+ aNbLines = aNbLines + 1
+assert (aNbLines == 4)
+#=========================================================================
+# End of test
+#=========================================================================
<group id="Basic">
<feature
id="Sketch"
- nested="SketchPoint SketchLine SketchCircle SketchArc SketchConstraintLength SketchConstraintRadius SketchConstraintDistance SketchConstraintParallel SketchConstraintPerpendicular SketchConstraintRigid SketchConstraintHorizontal SketchConstraintVertical SketchConstraintEqual SketchConstraintTangent SketchConstraintFillet SketchConstraintCoincidence SketchConstraintMirror SketchConstraintAngle SketchMultiRotation SketchMultiTranslation SketchConstraintCollinear SketchConstraintMiddle"
+ nested="SketchPoint SketchLine SketchCircle SketchArc SketchRectangle SketchConstraintLength SketchConstraintRadius SketchConstraintDistance SketchConstraintParallel SketchConstraintPerpendicular SketchConstraintRigid SketchConstraintHorizontal SketchConstraintVertical SketchConstraintEqual SketchConstraintTangent SketchConstraintFillet SketchConstraintCoincidence SketchConstraintMirror SketchConstraintAngle SketchMultiRotation SketchMultiTranslation SketchConstraintCollinear SketchConstraintMiddle"
when_nested="accept abort"
title="Sketch"
tooltip="Create sketch"
</box>
</toolbox>
</feature>
+ </group>
+ <group id="Macro">
<!-- SketchConstraintFillet -->
<feature id="SketchConstraintFillet" title="Fillet" tooltip="Create constraint defining fillet between two objects" icon=":icons/fillet.png">
<!--<sketch_shape_selector id="ConstraintEntityA"