Salome HOME
Migration to OCCT 7.0
[modules/geom.git] / src / GEOMAlgo / GEOMAlgo_GetInPlaceAPI.cxx
1 // Copyright (C) 2007-2016  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, or (at your option) any later version.
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 // File:     GEOMAlgo_GetInPlaceAPI.cxx
23 // Created:
24 // Author:   Sergey KHROMOV
25
26
27 #include <GEOMAlgo_GetInPlaceAPI.hxx>
28 #include <GEOMAlgo_GetInPlace.hxx>
29 #include <GEOM_Object.hxx>
30 #include <GEOMUtils.hxx>
31
32 #include <Bnd_Box.hxx>
33 #include <BRepAdaptor_Surface.hxx>
34 #include <BRepBndLib.hxx>
35 #include <BRepBuilderAPI_MakeVertex.hxx>
36 #include <BRepExtrema_DistShapeShape.hxx>
37 #include <BRepGProp.hxx>
38 #include <BRep_Tool.hxx>
39 #include <Geom2d_Curve.hxx>
40 #include <GProp_GProps.hxx>
41 #include <gp_Pnt.hxx>
42 #include <Precision.hxx>
43 #include <TDataStd_IntegerArray.hxx>
44 #include <TopExp.hxx>
45 #include <TopExp_Explorer.hxx>
46 #include <TopoDS.hxx>
47 #include <TopoDS_Vertex.hxx>
48
49 //=======================================================================
50 //function : GetInPlace
51 //purpose  : 
52 //=======================================================================
53 Standard_Boolean GEOMAlgo_GetInPlaceAPI::GetInPlace
54                       (const TopoDS_Shape        &theWhere,
55                        const TopoDS_Shape        &theWhat,
56                              GEOMAlgo_GetInPlace &theGIP)
57 {
58   if (theWhere.IsNull() || theWhat.IsNull()) {
59     return Standard_False;
60   }
61
62   // Compute confusion tolerance.
63   Standard_Real    aTolConf = Precision::Confusion();
64   Standard_Integer i;
65
66   for (i = 0; i < 2; ++i) {
67     TopExp_Explorer anExp(i == 0 ? theWhere : theWhat, TopAbs_VERTEX);
68
69     for (; anExp.More(); anExp.Next()) {
70       const TopoDS_Vertex aVtx = TopoDS::Vertex(anExp.Current());
71       const Standard_Real aTolVtx = BRep_Tool::Tolerance(aVtx);
72
73       if (aTolVtx > aTolConf) {
74         aTolConf = aTolVtx;
75       }
76     }
77   }
78
79   // Compute mass tolerance.
80   Bnd_Box       aBoundingBox;
81   Standard_Real aXmin, aYmin, aZmin, aXmax, aYmax, aZmax;
82   Standard_Real aMassTol;
83
84   BRepBndLib::Add(theWhere, aBoundingBox);
85   BRepBndLib::Add(theWhat,  aBoundingBox);
86   aBoundingBox.Get(aXmin, aYmin, aZmin, aXmax, aYmax, aZmax);
87   aMassTol = Max(aXmax - aXmin, aYmax - aYmin);
88   aMassTol = Max(aMassTol, aZmax - aZmin);
89   aMassTol *= aTolConf;
90
91   // Searching for the sub-shapes inside the ShapeWhere shape
92   theGIP.SetTolerance(aTolConf);
93   theGIP.SetTolMass(aMassTol);
94   theGIP.SetTolCG(aTolConf);
95
96   theGIP.SetArgument(theWhat);
97   theGIP.SetShapeWhere(theWhere);
98
99   theGIP.Perform();
100
101   int iErr = theGIP.ErrorStatus();
102
103   if (iErr) {
104     return Standard_False;
105   }
106
107   return Standard_True;
108 }
109
110 //=======================================================================
111 //function : GetInPlaceOld
112 //purpose  : 
113 //=======================================================================
114 Standard_Integer GEOMAlgo_GetInPlaceAPI::GetInPlaceOld
115             (const TopoDS_Shape         &theWhere,
116              const TopoDS_Shape         &theWhat,
117                    TopTools_ListOfShape &theShapesInPlace)
118 {
119   theShapesInPlace.Clear();
120
121   if (theWhere.IsNull() || theWhat.IsNull()) {
122     // Error: aWhere and aWhat TopoDS_Shape are Null.
123     return 1;
124   }
125
126   // Check shape type.
127   TopAbs_ShapeEnum iType = GEOMUtils::GetTypeOfSimplePart(theWhat);
128
129   if (iType == TopAbs_SHAPE) {
130     // Error: An attempt to extract a shape of not supported type.
131     return 2;
132   }
133
134   // Compute confusion tolerance.
135   Standard_Real    aTolConf = Precision::Confusion();
136   Standard_Integer i;
137
138   for (i = 0; i < 2; ++i) {
139     TopExp_Explorer anExp(i == 0 ? theWhere : theWhat, TopAbs_VERTEX);
140
141     for (; anExp.More(); anExp.Next()) {
142       const TopoDS_Vertex aVtx = TopoDS::Vertex(anExp.Current());
143       const Standard_Real aTolVtx = BRep_Tool::Tolerance(aVtx);
144
145       if (aTolVtx > aTolConf) {
146         aTolConf = aTolVtx;
147       }
148     }
149   }
150
151   // Compute mass tolerance.
152   Bnd_Box       aBoundingBox;
153   Standard_Real aXmin, aYmin, aZmin, aXmax, aYmax, aZmax;
154   Standard_Real aMassTol;
155
156   BRepBndLib::Add(theWhere, aBoundingBox);
157   BRepBndLib::Add(theWhat,  aBoundingBox);
158   aBoundingBox.Get(aXmin, aYmin, aZmin, aXmax, aYmax, aZmax);
159   aMassTol = Max(aXmax - aXmin, aYmax - aYmin);
160   aMassTol = Max(aMassTol, aZmax - aZmin);
161   aMassTol *= aTolConf;
162
163   // Compute the result.
164   TopExp_Explorer     Exp_aWhat  (theWhat,  iType);
165   TopExp_Explorer     Exp_aWhere (theWhere, iType);
166   Standard_Real       tab_aWhat[4], tab_aWhere[4];
167   gp_Pnt              aPnt, aPnt_aWhat;
168   TopoDS_Shape        aPntShape;
169   TopoDS_Vertex       aVertex;
170   bool                isFound = false;
171   TopTools_MapOfShape map_aWhere;
172
173   for (; Exp_aWhere.More(); Exp_aWhere.Next()) {
174     if (!map_aWhere.Add(Exp_aWhere.Current()))
175       continue; // skip repeated shape to avoid mass addition
176     GetShapeProperties( Exp_aWhere.Current(), tab_aWhere, aPnt );
177     for ( Exp_aWhat.ReInit(); Exp_aWhat.More(); Exp_aWhat.Next() ) {
178       GetShapeProperties( Exp_aWhat.Current(), tab_aWhat, aPnt_aWhat );
179       if (fabs(tab_aWhat[3] - tab_aWhere[3]) <= aMassTol && aPnt_aWhat.Distance(aPnt) <= aTolConf)
180         isFound = true;
181       else {
182         if (tab_aWhat[3] > tab_aWhere[3]) {
183           aPntShape = BRepBuilderAPI_MakeVertex( aPnt ).Shape();
184           aVertex   = TopoDS::Vertex( aPntShape );
185           BRepExtrema_DistShapeShape aWhereDistance ( aVertex, Exp_aWhere.Current() );
186           BRepExtrema_DistShapeShape aWhatDistance  ( aVertex, Exp_aWhat.Current() );
187           if (aWhereDistance.IsDone() && aWhatDistance.IsDone() &&
188               fabs(aWhereDistance.Value() - aWhatDistance.Value()) <= aTolConf)
189           {
190             // 0020162: "EDF 961 GEOM : Getinplace is getting additionnal orthogonal faces"
191             // aVertex must be projected to the same point on Where and on What
192             gp_Pnt pOnWhat  = aWhatDistance.PointOnShape2(1);
193             gp_Pnt pOnWhere = aWhereDistance.PointOnShape2(1);
194             isFound = (pOnWhat.Distance(pOnWhere) <= aTolConf);
195             if ( isFound && iType == TopAbs_FACE )
196             {
197               // check normals at pOnWhat and pOnWhere
198               const double angleTol = M_PI/180.;
199               gp_Vec normToWhat  = GetNormal( TopoDS::Face(Exp_aWhat.Current()), aWhatDistance);
200               gp_Vec normToWhere = GetNormal( TopoDS::Face(Exp_aWhere.Current()), aWhereDistance);
201               if ( normToWhat * normToWhere < 0 )
202                 normToWhat.Reverse();
203               isFound = ( normToWhat.Angle( normToWhere ) < angleTol );
204             }
205           }
206         }
207       }
208       if ( isFound ) {
209         theShapesInPlace.Append(Exp_aWhere.Current());
210         //aWhere_Mass += tab_aWhere[3];
211         isFound = false;
212         break;
213       }
214     }
215   }
216
217   if (theShapesInPlace.Extent() == 0) {
218     // Not found any Results
219     return 3;
220   }
221
222   return 0;
223 }
224
225 //=======================================================================
226 //function : GetNormal
227 //purpose  : 
228 //=======================================================================
229 gp_Vec GEOMAlgo_GetInPlaceAPI::GetNormal
230                          (const TopoDS_Face                &theFace,
231                           const BRepExtrema_DistShapeShape &theExtrema)
232 {
233   gp_Vec defaultNorm(1,0,0); // to have same normals on different faces
234   try {
235     // get UV at extrema point
236     Standard_Real u,v, f,l;
237     switch ( theExtrema.SupportTypeShape2(1) ) {
238     case BRepExtrema_IsInFace: {
239       theExtrema.ParOnFaceS2(1, u, v );
240       break;
241     }
242     case BRepExtrema_IsOnEdge: {
243       TopoDS_Edge edge = TopoDS::Edge( theExtrema.SupportOnShape2(1));
244       Handle(Geom2d_Curve) pcurve =
245         BRep_Tool::CurveOnSurface(edge, theFace, f,l);
246
247       theExtrema.ParOnEdgeS2( 1, u );
248       gp_Pnt2d uv = pcurve->Value( u );
249       u = uv.Coord(1);
250       v = uv.Coord(2);
251       break;
252     }
253     case BRepExtrema_IsVertex: return defaultNorm;
254     }
255     // get derivatives
256     BRepAdaptor_Surface surface( theFace, false );
257     gp_Vec du, dv; gp_Pnt p;
258     surface.D1( u, v, p, du, dv );
259
260     return du ^ dv;
261
262   } catch (Standard_Failure ) {
263   }
264   return defaultNorm;
265 }
266
267 //=======================================================================
268 //function : GetShapeProperties
269 //purpose  : 
270 //=======================================================================
271 void GEOMAlgo_GetInPlaceAPI::GetShapeProperties(const TopoDS_Shape  &theShape,
272                                                       Standard_Real  theTab[],
273                                                       gp_Pnt        &theVertex)
274 {
275   GProp_GProps  aProps;
276   gp_Pnt        aCenterMass;
277   Standard_Real aShapeSize;
278
279   if    (theShape.ShapeType() == TopAbs_VERTEX) {
280     aCenterMass = BRep_Tool::Pnt(TopoDS::Vertex(theShape));
281   } else if (theShape.ShapeType() == TopAbs_EDGE) {
282     BRepGProp::LinearProperties(theShape,  aProps);
283   } else if (theShape.ShapeType() == TopAbs_FACE) {
284     BRepGProp::SurfaceProperties(theShape, aProps);
285   } else {
286     BRepGProp::VolumeProperties(theShape,  aProps);
287   }
288
289   if (theShape.ShapeType() == TopAbs_VERTEX) {
290     aShapeSize = 1;
291   } else {
292     aCenterMass = aProps.CentreOfMass();
293     aShapeSize  = aProps.Mass();
294   }
295
296   theVertex = aCenterMass;
297   theTab[0] = theVertex.X();
298   theTab[1] = theVertex.Y();
299   theTab[2] = theVertex.Z();
300   theTab[3] = aShapeSize;
301 }
302
303 //=======================================================================
304 //function : GetInPlaceByHistory
305 //purpose  : 
306 //=======================================================================
307 Standard_Boolean GEOMAlgo_GetInPlaceAPI::GetInPlaceByHistory
308                       (const Handle(GEOM_Function)      &theWhereFunction,
309                        const TopTools_IndexedMapOfShape &theWhereIndices,
310                        const TopoDS_Shape               &theWhat,
311                              TopTools_ListOfShape       &theShapesInPlace)
312 {
313   if (theWhereFunction.IsNull() || theWhat.IsNull())
314     return Standard_False;
315
316   if (theWhereIndices.Contains(theWhat)) {
317     // entity was not changed by the operation
318     theShapesInPlace.Append(theWhat);
319
320     return Standard_True;
321   }
322
323   // try to find in history
324   TDF_Label aHistoryLabel = theWhereFunction->GetHistoryEntry(Standard_False);
325
326   // search in history for all argument shapes
327   Standard_Boolean isFound = Standard_False;
328   Standard_Boolean isGood = Standard_False;
329
330   TDF_LabelSequence aLabelSeq;
331   theWhereFunction->GetDependency(aLabelSeq);
332   Standard_Integer nbArg = aLabelSeq.Length();
333
334   for (Standard_Integer iarg = 1; iarg <= nbArg && !isFound; iarg++) {
335
336     TDF_Label anArgumentRefLabel = aLabelSeq.Value(iarg);
337
338     Handle(GEOM_Object) anArgumentObject = GEOM_Object::GetReferencedObject(anArgumentRefLabel);
339     TopoDS_Shape anArgumentShape = anArgumentObject->GetValue();
340
341     TopTools_IndexedMapOfShape anArgumentIndices;
342     TopExp::MapShapes(anArgumentShape, anArgumentIndices);
343
344     if (anArgumentIndices.Contains(theWhat)) {
345       isFound = Standard_True;
346       Standard_Integer aWhatIndex = anArgumentIndices.FindIndex(theWhat);
347
348       // Find corresponding label in history
349       TDF_Label anArgumentHistoryLabel =
350         theWhereFunction->GetArgumentHistoryEntry(anArgumentRefLabel, Standard_False);
351       if (anArgumentHistoryLabel.IsNull()) {
352         // Lost History of operation argument. Possibly, all its entities was removed.
353         isGood = Standard_True;
354       }
355       else {
356         TDF_Label aWhatHistoryLabel = anArgumentHistoryLabel.FindChild(aWhatIndex, Standard_False);
357
358         if (aWhatHistoryLabel.IsNull()) {
359           // Removed entity ? Compound ? Compsolid ? Shell ? Wire
360           isGood = Standard_False;
361         } else {
362           Handle(TDataStd_IntegerArray) anIntegerArray;
363           if (!aWhatHistoryLabel.FindAttribute(TDataStd_IntegerArray::GetID(), anIntegerArray)) {
364             //Error: Empty modifications history for the sought shape.
365             isGood = Standard_False;
366           }
367           else {
368             isGood = Standard_True;
369             Standard_Integer imod, aModifLen = anIntegerArray->Array()->Length();
370             for (imod = 1; imod <= aModifLen; imod++) {
371               const Standard_Integer anIndex =
372                 anIntegerArray->Array()->Value(imod);
373
374               theShapesInPlace.Append(theWhereIndices.FindKey(anIndex));
375             }
376           }
377         }
378       }
379     }
380   }
381
382   isFound = isGood;
383
384   if (!isFound) {
385     // try compound/compsolid/shell/wire element by element
386     Standard_Boolean isFoundAny = Standard_False;
387     TopTools_MapOfShape mapShape;
388
389     if (theWhat.ShapeType() == TopAbs_COMPOUND ||
390         theWhat.ShapeType() == TopAbs_COMPSOLID) {
391       // recursive processing of compound/compsolid
392       TopoDS_Iterator anIt (theWhat, Standard_True, Standard_True);
393       for (; anIt.More(); anIt.Next()) {
394         if (mapShape.Add(anIt.Value())) {
395           TopoDS_Shape curWhat = anIt.Value();
396           isFoundAny = GetInPlaceByHistory(theWhereFunction, theWhereIndices, curWhat, theShapesInPlace);
397           if (isFoundAny) isFound = Standard_True;
398         }
399       }
400     }
401     else if (theWhat.ShapeType() == TopAbs_SHELL) {
402       // try to replace a shell by its faces images
403       TopExp_Explorer anExp (theWhat, TopAbs_FACE);
404       for (; anExp.More(); anExp.Next()) {
405         if (mapShape.Add(anExp.Current())) {
406           TopoDS_Shape curWhat = anExp.Current();
407           isFoundAny = GetInPlaceByHistory(theWhereFunction, theWhereIndices, curWhat, theShapesInPlace);
408           if (isFoundAny) isFound = Standard_True;
409         }
410       }
411     }
412     else if (theWhat.ShapeType() == TopAbs_WIRE) {
413       // try to replace a wire by its edges images
414       TopExp_Explorer anExp (theWhat, TopAbs_EDGE);
415       for (; anExp.More(); anExp.Next()) {
416         if (mapShape.Add(anExp.Current())) {
417           TopoDS_Shape curWhat = anExp.Current();
418           isFoundAny = GetInPlaceByHistory(theWhereFunction, theWhereIndices, curWhat, theShapesInPlace);
419           if (isFoundAny) isFound = Standard_True;
420         }
421       }
422     }
423     else {
424       // Removed entity
425     }
426   }
427
428   return isFound;
429 }