Salome HOME
Merge from BR_siman_phase1 14/02/2013
[modules/geom.git] / src / GEOMImpl / GEOMImpl_MeasureDriver.cxx
1 // Copyright (C) 2007-2012  CEA/DEN, EDF R&D, OPEN CASCADE
2 //
3 // Copyright (C) 2003-2007  OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN,
4 // CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS
5 //
6 // This library is free software; you can redistribute it and/or
7 // modify it under the terms of the GNU Lesser General Public
8 // License as published by the Free Software Foundation; either
9 // version 2.1 of the License.
10 //
11 // This library is distributed in the hope that it will be useful,
12 // but WITHOUT ANY WARRANTY; without even the implied warranty of
13 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14 // Lesser General Public License for more details.
15 //
16 // You should have received a copy of the GNU Lesser General Public
17 // License along with this library; if not, write to the Free Software
18 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
19 //
20 // See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
21
22 #include <Standard_Stream.hxx>
23
24 #include <GEOMImpl_MeasureDriver.hxx>
25 #include <GEOMImpl_IMeasure.hxx>
26 #include <GEOMImpl_Types.hxx>
27
28 #include <GEOM_Function.hxx>
29
30 #include <GEOMUtils.hxx>
31
32 #include <BRep_Tool.hxx>
33 #include <BRepTools.hxx>
34 #include <BRepGProp.hxx>
35 #include <BRepBuilderAPI_Copy.hxx>
36 #include <BRepBuilderAPI_MakeEdge.hxx>
37 #include <BRepBuilderAPI_MakeVertex.hxx>
38 #include <BRepPrimAPI_MakeBox.hxx>
39
40 #include <TopAbs.hxx>
41 #include <TopoDS.hxx>
42 #include <TopoDS_Shape.hxx>
43 #include <TopoDS_Edge.hxx>
44 #include <TopoDS_Wire.hxx>
45 #include <TopExp.hxx>
46 #include <TopExp_Explorer.hxx>
47 #include <TopTools_IndexedMapOfShape.hxx>
48
49 #include <GProp_GProps.hxx>
50 #include <GeomLProp_SLProps.hxx>
51 #include <Geom_Surface.hxx>
52
53 #include <Bnd_Box.hxx>
54 #include <BRepBndLib.hxx>
55 #include <BRepAdaptor_Surface.hxx>
56 #include <ShapeAnalysis_Surface.hxx>
57
58 #include <gp_Pnt.hxx>
59 #include <Precision.hxx>
60 #include <Standard_NullObject.hxx>
61 #include <StdFail_NotDone.hxx>
62
63 //=======================================================================
64 //function : GetID
65 //purpose  :
66 //======================================================================= 
67 const Standard_GUID& GEOMImpl_MeasureDriver::GetID()
68 {
69   static Standard_GUID aMeasureDriver("FF1BBB65-5D14-4df2-980B-3A668264EA16");
70   return aMeasureDriver; 
71 }
72
73
74 //=======================================================================
75 //function : GEOMImpl_MeasureDriver
76 //purpose  : 
77 //=======================================================================
78 GEOMImpl_MeasureDriver::GEOMImpl_MeasureDriver() 
79 {
80 }
81
82 //=======================================================================
83 //function : Execute
84 //purpose  :
85 //======================================================================= 
86 Standard_Integer GEOMImpl_MeasureDriver::Execute(TFunction_Logbook& log) const
87 {
88   if (Label().IsNull()) return 0;    
89   Handle(GEOM_Function) aFunction = GEOM_Function::GetFunction(Label());
90
91   GEOMImpl_IMeasure aCI (aFunction);
92   Standard_Integer aType = aFunction->GetType();
93
94   TopoDS_Shape aShape;
95
96   if (aType == CDG_MEASURE)
97   {
98     Handle(GEOM_Function) aRefBase = aCI.GetBase();
99     TopoDS_Shape aShapeBase = aRefBase->GetValue();
100     if (aShapeBase.IsNull())
101       Standard_NullObject::Raise("Shape for centre of mass calculation is null");
102
103     gp_Ax3 aPos = GEOMUtils::GetPosition(aShapeBase);
104     gp_Pnt aCenterMass = aPos.Location();
105     aShape = BRepBuilderAPI_MakeVertex(aCenterMass).Shape();
106   }
107   else if (aType == BND_BOX_MEASURE)
108   {
109     Handle(GEOM_Function) aRefBase = aCI.GetBase();
110     TopoDS_Shape aShapeBase = aRefBase->GetValue();
111     if (aShapeBase.IsNull())
112       Standard_NullObject::Raise("Shape for bounding box calculation is null");
113
114     BRepBuilderAPI_Copy aCopyTool (aShapeBase);
115     if (!aCopyTool.IsDone())
116       Standard_NullObject::Raise("Shape for bounding box calculation is bad");
117
118     aShapeBase = aCopyTool.Shape();
119
120     // remove triangulation to obtain more exact boundaries
121     BRepTools::Clean(aShapeBase);
122
123     Bnd_Box B;
124     BRepBndLib::Add(aShapeBase, B);
125
126     Standard_Real Xmin, Ymin, Zmin, Xmax, Ymax, Zmax;
127     B.Get(Xmin, Ymin, Zmin, Xmax, Ymax, Zmax);
128
129     if (Xmax - Xmin < Precision::Confusion()) Xmax += Precision::Confusion();
130     if (Ymax - Ymin < Precision::Confusion()) Ymax += Precision::Confusion();
131     if (Zmax - Zmin < Precision::Confusion()) Zmax += Precision::Confusion();
132
133     gp_Pnt P1 (Xmin, Ymin, Zmin);
134     gp_Pnt P2 (Xmax, Ymax, Zmax);
135
136     BRepPrimAPI_MakeBox MB (P1, P2);
137     MB.Build();
138     if (!MB.IsDone()) StdFail_NotDone::Raise("Bounding box cannot be computed from the given shape");
139     aShape = MB.Shape();
140   }
141   else if (aType == VERTEX_BY_INDEX)
142   {
143     Handle(GEOM_Function) aRefBase = aCI.GetBase();
144     TopoDS_Shape aShapeBase = aRefBase->GetValue();
145     if (aShapeBase.IsNull()) {
146       Standard_NullObject::Raise("Shape for centre of mass calculation is null");
147     }
148
149     int index = aCI.GetIndex();
150     gp_Pnt aVertex;
151
152     if (aShapeBase.ShapeType() == TopAbs_VERTEX) {
153       if ( index != 1 )
154         Standard_NullObject::Raise("Vertex index is out of range");
155       else
156         aVertex = BRep_Tool::Pnt(TopoDS::Vertex(aShapeBase));
157     } else if (aShapeBase.ShapeType() == TopAbs_EDGE) {
158       TopoDS_Vertex aV1, aV2;
159       TopoDS_Edge anEdgeE = TopoDS::Edge(aShapeBase);
160       
161       TopExp::Vertices(anEdgeE, aV1, aV2);
162       gp_Pnt aP1 = BRep_Tool::Pnt(aV1);
163       gp_Pnt aP2 = BRep_Tool::Pnt(aV2);
164
165       if (index < 0 || index > 1)
166         Standard_NullObject::Raise("Vertex index is out of range");
167
168       if ( ( anEdgeE.Orientation() == TopAbs_FORWARD && index == 0 ) ||
169            ( anEdgeE.Orientation() == TopAbs_REVERSED && index == 1 ) )
170         aVertex = aP1;
171       else
172       aVertex = aP2;
173     } else if (aShapeBase.ShapeType() == TopAbs_WIRE) {
174       TopTools_IndexedMapOfShape anEdgeShapes;
175       TopTools_IndexedMapOfShape aVertexShapes;
176       TopoDS_Vertex aV1, aV2;
177       TopoDS_Wire aWire = TopoDS::Wire(aShapeBase);
178       TopExp_Explorer exp (aWire, TopAbs_EDGE);
179       for (; exp.More(); exp.Next()) {
180         anEdgeShapes.Add(exp.Current());
181         TopoDS_Edge E = TopoDS::Edge(exp.Current());
182         TopExp::Vertices(E, aV1, aV2);
183         if ( aVertexShapes.Extent() == 0)
184           aVertexShapes.Add(aV1);
185         if ( !aV1.IsSame( aVertexShapes(aVertexShapes.Extent()) ) )
186           aVertexShapes.Add(aV1);
187         if ( !aV2.IsSame( aVertexShapes(aVertexShapes.Extent()) ) )
188           aVertexShapes.Add(aV2);
189       }
190
191       if (index < 0 || index > aVertexShapes.Extent())
192         Standard_NullObject::Raise("Vertex index is out of range");
193
194       if (aWire.Orientation() == TopAbs_FORWARD)
195         aVertex = BRep_Tool::Pnt(TopoDS::Vertex(aVertexShapes(index+1)));
196       else
197         aVertex = BRep_Tool::Pnt(TopoDS::Vertex(aVertexShapes(aVertexShapes.Extent() - index)));
198     } else {
199       Standard_NullObject::Raise("Shape for vertex calculation is not an edge or wire");
200     }
201
202     aShape = BRepBuilderAPI_MakeVertex(aVertex).Shape();
203   }
204   else if (aType == VECTOR_FACE_NORMALE)
205   {
206     // Face
207     Handle(GEOM_Function) aRefBase = aCI.GetBase();
208     TopoDS_Shape aShapeBase = aRefBase->GetValue();
209     if (aShapeBase.IsNull()) {
210       Standard_NullObject::Raise("Face for normale calculation is null");
211     }
212     if (aShapeBase.ShapeType() != TopAbs_FACE) {
213       Standard_NullObject::Raise("Shape for normale calculation is not a face");
214     }
215     TopoDS_Face aFace = TopoDS::Face(aShapeBase);
216
217     // Point
218     gp_Pnt p1 (0,0,0);
219
220     Handle(GEOM_Function) aPntFunc = aCI.GetPoint();
221     if (!aPntFunc.IsNull())
222     {
223       TopoDS_Shape anOptPnt = aPntFunc->GetValue();
224       if (anOptPnt.IsNull())
225         Standard_NullObject::Raise("Invalid shape given for point argument");
226       p1 = BRep_Tool::Pnt(TopoDS::Vertex(anOptPnt));
227     }
228     else
229     {
230       gp_Ax3 aPos = GEOMUtils::GetPosition(aFace);
231       p1 = aPos.Location();
232     }
233
234     // Point parameters on surface
235     Handle(Geom_Surface) aSurf = BRep_Tool::Surface(aFace);
236     Handle(ShapeAnalysis_Surface) aSurfAna = new ShapeAnalysis_Surface (aSurf);
237     gp_Pnt2d pUV = aSurfAna->ValueOfUV(p1, Precision::Confusion());
238
239     // Normal direction
240     gp_Vec Vec1,Vec2;
241     BRepAdaptor_Surface SF (aFace);
242     SF.D1(pUV.X(), pUV.Y(), p1, Vec1, Vec2);
243     if (Vec1.Magnitude() < Precision::Confusion()) {
244       gp_Vec tmpV;
245       gp_Pnt tmpP;
246       SF.D1(pUV.X(), pUV.Y()-0.1, tmpP, Vec1, tmpV);
247     }
248     else if (Vec2.Magnitude() < Precision::Confusion()) {
249       gp_Vec tmpV;
250       gp_Pnt tmpP;
251       SF.D1(pUV.X()-0.1, pUV.Y(), tmpP, tmpV, Vec2);
252     }
253
254     gp_Vec V = Vec1.Crossed(Vec2);
255     Standard_Real mod = V.Magnitude();
256     if (mod < Precision::Confusion())
257       Standard_NullObject::Raise("Normal vector of a face has null magnitude");
258
259     // Set length of normal vector to average radius of curvature
260     Standard_Real radius = 0.0;
261     GeomLProp_SLProps aProperties (aSurf, pUV.X(), pUV.Y(), 2, Precision::Confusion());
262     if (aProperties.IsCurvatureDefined()) {
263       Standard_Real radius1 = Abs(aProperties.MinCurvature());
264       Standard_Real radius2 = Abs(aProperties.MaxCurvature());
265       if (Abs(radius1) > Precision::Confusion()) {
266         radius = 1.0 / radius1;
267         if (Abs(radius2) > Precision::Confusion()) {
268           radius = (radius + 1.0 / radius2) / 2.0;
269         }
270       }
271       else {
272         if (Abs(radius2) > Precision::Confusion()) {
273           radius = 1.0 / radius2;
274         }
275       }
276     }
277
278     // Set length of normal vector to average dimension of the face
279     // (only if average radius of curvature is not appropriate)
280     if (radius < Precision::Confusion()) {
281         Bnd_Box B;
282         Standard_Real Xmin, Xmax, Ymin, Ymax, Zmin, Zmax;
283         BRepBndLib::Add(aFace, B);
284         B.Get(Xmin, Ymin, Zmin, Xmax, Ymax, Zmax);
285         radius = ((Xmax - Xmin) + (Ymax - Ymin) + (Zmax - Zmin)) / 3.0;
286     }
287
288     if (radius < Precision::Confusion())
289       radius = 1.0;
290
291     V *= radius / mod;
292
293     // consider the face orientation
294     if (aFace.Orientation() == TopAbs_REVERSED ||
295         aFace.Orientation() == TopAbs_INTERNAL) {
296       V = - V;
297     }
298
299     // Edge
300     gp_Pnt p2 = p1.Translated(V);
301     BRepBuilderAPI_MakeEdge aBuilder (p1, p2);
302     if (!aBuilder.IsDone())
303       Standard_NullObject::Raise("Vector construction failed");
304     aShape = aBuilder.Shape();
305   }
306   else {
307   }
308
309   if (aShape.IsNull()) return 0;
310
311   aFunction->SetValue(aShape);
312
313   log.SetTouched(Label()); 
314
315   return 1;
316 }
317
318
319 //=======================================================================
320 //function :  GEOMImpl_MeasureDriver_Type_
321 //purpose  :
322 //======================================================================= 
323 Standard_EXPORT Handle_Standard_Type& GEOMImpl_MeasureDriver_Type_()
324 {
325
326   static Handle_Standard_Type aType1 = STANDARD_TYPE(TFunction_Driver);
327   if ( aType1.IsNull()) aType1 = STANDARD_TYPE(TFunction_Driver);
328   static Handle_Standard_Type aType2 = STANDARD_TYPE(MMgt_TShared);
329   if ( aType2.IsNull()) aType2 = STANDARD_TYPE(MMgt_TShared); 
330   static Handle_Standard_Type aType3 = STANDARD_TYPE(Standard_Transient);
331   if ( aType3.IsNull()) aType3 = STANDARD_TYPE(Standard_Transient);
332  
333
334   static Handle_Standard_Transient _Ancestors[]= {aType1,aType2,aType3,NULL};
335   static Handle_Standard_Type _aType = new Standard_Type("GEOMImpl_MeasureDriver",
336                                                          sizeof(GEOMImpl_MeasureDriver),
337                                                          1,
338                                                          (Standard_Address)_Ancestors,
339                                                          (Standard_Address)NULL);
340
341   return _aType;
342 }
343
344 //=======================================================================
345 //function : DownCast
346 //purpose  :
347 //======================================================================= 
348 const Handle(GEOMImpl_MeasureDriver) Handle(GEOMImpl_MeasureDriver)::DownCast(const Handle(Standard_Transient)& AnObject)
349 {
350   Handle(GEOMImpl_MeasureDriver) _anOtherObject;
351
352   if (!AnObject.IsNull()) {
353      if (AnObject->IsKind(STANDARD_TYPE(GEOMImpl_MeasureDriver))) {
354        _anOtherObject = Handle(GEOMImpl_MeasureDriver)((Handle(GEOMImpl_MeasureDriver)&)AnObject);
355      }
356   }
357
358   return _anOtherObject ;
359 }