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