Salome HOME
39762ed778d19ded02d0327425bad2adb1d5d321
[modules/shaper.git] / src / SketchPlugin / Test / TestFillet.py
1 """
2     TestFillet.py
3     Unit test of SketchPlugin_Fillet class
4
5     SketchPlugin_Fillet
6         static const std::string MY_CONSTRAINT_FILLET_ID("SketchFillet");
7         data()->addAttribute(SketchPlugin_Constraint::VALUE(), ModelAPI_AttributeDouble::typeId());
8         data()->addAttribute(SketchPlugin_Constraint::ENTITY_A(), ModelAPI_AttributeRefAttrList::typeId());
9         data()->addAttribute(SketchPlugin_Constraint::ENTITY_B(), ModelAPI_AttributeRefList::typeId());
10         data()->addAttribute(SketchPlugin_Constraint::ENTITY_C(), ModelAPI_AttributeRefAttrList::typeId());
11
12 """
13 from GeomDataAPI import *
14 from ModelAPI import *
15 import math
16 from salome.shaper import model
17
18 #=========================================================================
19 # Auxiliary functions
20 #=========================================================================
21 TOLERANCE = 1.e-7
22
23 def createSketch1(theSketch):
24     global aEndPoint1, aEndPoint2
25     # Initialize sketch by three lines with coincident boundaries
26     allFeatures = []
27
28     aSession.startOperation()
29     # Line1
30     aSketchLine1 = theSketch.addFeature("SketchLine")
31     aStartPoint1 = geomDataAPI_Point2D(aSketchLine1.attribute("StartPoint"))
32     aEndPoint1   = geomDataAPI_Point2D(aSketchLine1.attribute("EndPoint"))
33     aStartPoint1.setValue(-10., -10.)
34     aEndPoint1.setValue(-10., 10.)
35     allFeatures.append(aSketchLine1)
36     # Line2
37     aSketchLine2 = theSketch.addFeature("SketchLine")
38     aStartPoint2 = geomDataAPI_Point2D(aSketchLine2.attribute("StartPoint"))
39     aEndPoint2   = geomDataAPI_Point2D(aSketchLine2.attribute("EndPoint"))
40     aStartPoint2.setValue(-10., 10.)
41     aEndPoint2.setValue(10., 10.)
42     allFeatures.append(aSketchLine2)
43     # Line3
44     aSketchLine3 = theSketch.addFeature("SketchLine")
45     aStartPoint3 = geomDataAPI_Point2D(aSketchLine3.attribute("StartPoint"))
46     aEndPoint3   = geomDataAPI_Point2D(aSketchLine3.attribute("EndPoint"))
47     aStartPoint3.setValue(10., 10.)
48     aEndPoint3.setValue(10., -10.)
49     allFeatures.append(aSketchLine3)
50     # Coincidence1
51     aCoincidence1 = theSketch.addFeature("SketchConstraintCoincidence")
52     aCoincidence1.refattr("ConstraintEntityA").setAttr(aEndPoint1)
53     aCoincidence1.refattr("ConstraintEntityB").setAttr(aStartPoint2)
54     # Coincidence2
55     aCoincidence2 = theSketch.addFeature("SketchConstraintCoincidence")
56     aCoincidence2.refattr("ConstraintEntityA").setAttr(aEndPoint2)
57     aCoincidence2.refattr("ConstraintEntityB").setAttr(aStartPoint3)
58
59     aSession.finishOperation()
60     return allFeatures
61
62
63 def createSketch2(theSketch):
64     global aStartPoint1
65     # Initialize sketch by line and arc with coincident boundary
66     allFeatures = []
67
68     aSession.startOperation()
69     # Line
70     aSketchLine = theSketch.addFeature("SketchLine")
71     aStartPoint1 = geomDataAPI_Point2D(aSketchLine.attribute("StartPoint"))
72     aEndPoint1   = geomDataAPI_Point2D(aSketchLine.attribute("EndPoint"))
73     aStartPoint1.setValue(10., 10.)
74     aEndPoint1.setValue(30., 15.)
75     allFeatures.append(aSketchLine)
76     # Arc
77     aSketchArc = theSketch.addFeature("SketchArc")
78     aStartPoint2 = geomDataAPI_Point2D(aSketchArc.attribute("ArcStartPoint"))
79     aEndPoint2   = geomDataAPI_Point2D(aSketchArc.attribute("ArcEndPoint"))
80     aCenterPoint = geomDataAPI_Point2D(aSketchArc.attribute("ArcCenter"))
81     aCenterPoint.setValue(20., 10.)
82     aStartPoint2.setValue(10., 10.)
83     aEndPoint2.setValue(20., 0.)
84     allFeatures.append(aSketchArc)
85     # Coincidence
86     aCoincidence = theSketch.addFeature("SketchConstraintCoincidence")
87     aCoincidence.refattr("ConstraintEntityA").setAttr(aStartPoint1)
88     aCoincidence.refattr("ConstraintEntityB").setAttr(aStartPoint2)
89
90     aSession.finishOperation()
91     return allFeatures
92
93 def checkSmoothness(theSketch):
94     aPtPtCoincidences = getCoincidences(theSketch)
95     for coinc in aPtPtCoincidences:
96         aConnectedFeatures = connectedFeatures(coinc)
97         assert(len(aConnectedFeatures) == 2)
98         if aConnectedFeatures[0].getKind() == "SketchArc":
99             if aConnectedFeatures[1].getKind() == "SketchArc":
100                 checkArcArcSmoothness(aConnectedFeatures[0], aConnectedFeatures[1])
101             elif aConnectedFeatures[1].getKind() == "SketchLine":
102                 checkArcLineSmoothness(aConnectedFeatures[0], aConnectedFeatures[1])
103         elif aConnectedFeatures[0].getKind() == "SketchLine" and aConnectedFeatures[1].getKind() == "SketchArc":
104             checkArcLineSmoothness(aConnectedFeatures[1], aConnectedFeatures[0])
105
106 def checkArcLineSmoothness(theArc, theLine):
107     aCenter = geomDataAPI_Point2D(theArc.attribute("ArcCenter"))
108     aDistance = distancePointLine(aCenter, theLine)
109     aRadius = arcRadius(theArc)
110     assert(math.fabs(aRadius - aDistance) < TOLERANCE)
111
112 def checkArcArcSmoothness(theArc1, theArc2):
113     aCenter1 = geomDataAPI_Point2D(theArc1.attribute("ArcCenter"))
114     aCenter2 = geomDataAPI_Point2D(theArc2.attribute("ArcCenter"))
115     aDistance = distancePointPoint(aCenter1, aCenter2)
116     aRadius1 = arcRadius(theArc1)
117     aRadius2 = arcRadius(theArc2)
118     aRadSum = aRadius1 + aRadius2
119     aRadDiff = math.fabs(aRadius1 - aRadius2)
120     assert(math.fabs(aDistance - aRadSum) < TOLERANCE or math.fabs(aDistance - aRadDiff) < TOLERANCE)
121
122 def getCoincidences(theSketch):
123     aCoincidences = []
124     for anIndex in range(0, theSketch.numberOfSubs()):
125         aSubFeature = theSketch.subFeature(anIndex)
126         if aSubFeature.getKind() == "SketchConstraintCoincidence":
127             anEntityA = aSubFeature.refattr("ConstraintEntityA")
128             anEntityB = aSubFeature.refattr("ConstraintEntityB")
129             if not anEntityA.isObject() and not anEntityB.isObject():
130                 aCoincidences.append(aSubFeature)
131     return aCoincidences
132
133 def connectedFeatures(theCoincidence):
134     anEntityA = theCoincidence.refattr("ConstraintEntityA")
135     anEntityB = theCoincidence.refattr("ConstraintEntityB")
136     aFeatureA = ModelAPI.ModelAPI_Feature.feature(anEntityA.attr().owner())
137     aFeatureB = ModelAPI.ModelAPI_Feature.feature(anEntityB.attr().owner())
138     return [aFeatureA, aFeatureB]
139
140 def arcRadius(theArc):
141     aCenter = geomDataAPI_Point2D(theArc.attribute("ArcCenter"))
142     aStart = geomDataAPI_Point2D(theArc.attribute("ArcStartPoint"))
143     return distancePointPoint(aCenter, aStart)
144
145 def distancePointPoint(thePoint1, thePoint2):
146     return math.hypot(thePoint1.x() - thePoint2.x(), thePoint1.y() - thePoint2.y())
147
148 def distancePointLine(thePoint, theLine):
149     aLineStart = geomDataAPI_Point2D(theLine.attribute("StartPoint"))
150     aLineEnd = geomDataAPI_Point2D(theLine.attribute("EndPoint"))
151     aLength = distancePointPoint(aLineStart, aLineEnd)
152
153     aDir1x, aDir1y = aLineEnd.x() - aLineStart.x(), aLineEnd.y() - aLineStart.y()
154     aDir2x, aDir2y = thePoint.x() - aLineStart.x(), thePoint.y() - aLineStart.y()
155     aCross = aDir1x * aDir2y - aDir1y * aDir2x
156     return math.fabs(aCross) / aLength
157
158
159 #=========================================================================
160 # Initialization of the test
161 #=========================================================================
162
163 __updated__ = "2015-09-18"
164
165 aSession = ModelAPI_Session.get()
166 aDocument = aSession.moduleDocument()
167 #=========================================================================
168 # Creation of a sketch
169 #=========================================================================
170 aSession.startOperation()
171 aSketchCommonFeature = aDocument.addFeature("Sketch")
172 aSketchFeature = featureToCompositeFeature(aSketchCommonFeature)
173 origin = geomDataAPI_Point(aSketchFeature.attribute("Origin"))
174 origin.setValue(0, 0, 0)
175 dirx = geomDataAPI_Dir(aSketchFeature.attribute("DirX"))
176 dirx.setValue(1, 0, 0)
177 norm = geomDataAPI_Dir(aSketchFeature.attribute("Norm"))
178 norm.setValue(0, 0, 1)
179 aSession.finishOperation()
180 #=========================================================================
181 # Initialize sketch by three connected lines
182 #=========================================================================
183 createSketch1(aSketchFeature)
184 assert (model.dof(aSketchFeature) == 8)
185 #=========================================================================
186 # Create the Fillet
187 #=========================================================================
188 aSession.startOperation()
189 aFillet = aSketchFeature.addFeature("SketchFillet")
190 aFillet.refattr("fillet_point").setAttr(aEndPoint1);
191 aSession.finishOperation()
192 aSession.startOperation()
193 aFillet = aSketchFeature.addFeature("SketchFillet")
194 aFillet.refattr("fillet_point").setAttr(aEndPoint2);
195 aSession.finishOperation()
196 #=========================================================================
197 # Verify the objects of fillet are created
198 #=========================================================================
199 checkSmoothness(aSketchFeature)
200 assert model.dof(aSketchFeature) == 14, "PlaneGCS limitation: if you see this message, then maybe PlaneGCS has solved DoF for sketch with fillet correctly (expected DoF = 10, observed = {0}".format(model.dof(aSketchFeature))
201
202 #=========================================================================
203 # Create another sketch
204 #=========================================================================
205 aSession.startOperation()
206 aSketchCommonFeature = aDocument.addFeature("Sketch")
207 aSketchFeature = featureToCompositeFeature(aSketchCommonFeature)
208 origin = geomDataAPI_Point(aSketchFeature.attribute("Origin"))
209 origin.setValue(0, 0, 0)
210 dirx = geomDataAPI_Dir(aSketchFeature.attribute("DirX"))
211 dirx.setValue(1, 0, 0)
212 norm = geomDataAPI_Dir(aSketchFeature.attribute("Norm"))
213 norm.setValue(0, 1, 0)
214 aSession.finishOperation()
215 #=========================================================================
216 # Initialize sketch by line and arc
217 #=========================================================================
218 createSketch2(aSketchFeature)
219 assert (model.dof(aSketchFeature) == 7)
220 #=========================================================================
221 # Create the Fillet
222 #=========================================================================
223 aSession.startOperation()
224 aFillet = aSketchFeature.addFeature("SketchFillet")
225 aFillet.refattr("fillet_point").setAttr(aStartPoint1)
226 aSession.finishOperation()
227 #=========================================================================
228 # Verify the objects of fillet are created
229 #=========================================================================
230 checkSmoothness(aSketchFeature)
231 assert model.dof(aSketchFeature) == 10, "PlaneGCS limitation: if you see this message, then maybe PlaneGCS has solved DoF for sketch with fillet correctly (expected DoF = 8, observed = {0}".format(model.dof(aSketchFeature))
232 #=========================================================================
233 # End of test
234 #=========================================================================
235
236 # TODO: Improve Fillet test case by moving one of filleted objectes and check coincidence and tangency are correct
237
238 # TODO: Checking of Python dump has been disabled until the Fillet redesigned.
239 #assert(model.checkPythonDump())