Salome HOME
lot 15:: protection against corrupted polylines/objects
[modules/hydro.git] / src / HYDROData / HYDROData_CompleteCalcCase.cxx
1 // Copyright (C) 2014-2018  EDF-R&D
2 // This library is free software; you can redistribute it and/or
3 // modify it under the terms of the GNU Lesser General Public
4 // License as published by the Free Software Foundation; either
5 // version 2.1 of the License, or (at your option) any later version.
6 //
7 // This library is distributed in the hope that it will be useful,
8 // but WITHOUT ANY WARRANTY; without even the implied warranty of
9 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
10 // Lesser General Public License for more details.
11 //
12 // You should have received a copy of the GNU Lesser General Public
13 // License along with this library; if not, write to the Free Software
14 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
15 //
16 // See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
17 //
18
19 // File:     HYDROData_CompleteCalcCase.cxx
20 // Author:   Ilya SHCHEKIN
21
22 #include <HYDROData_CompleteCalcCase.h>
23
24 #include <gp_Pnt.hxx>
25 #include <HYDROData_SplitToZonesTool.h>
26 #include <HYDROData_SplitShapesGroup.h>
27 #include <BOPTools_AlgoTools3D.hxx>
28 #include <IntTools_Context.hxx>
29 #include <BRepBuilderAPI_MakeFace.hxx>
30 #include <TopTools_HSequenceOfShape.hxx>
31 #include <HYDROData_PolylineXY.h>
32 #include <TopoDS.hxx>
33 #include <HYDROData_Region.h>
34 #include <TopTools_IndexedMapOfShape.hxx>
35 #include <TopExp.hxx>
36 #include <HYDROData_Document.h>
37 #include <HYDROData_Tool.h>
38
39 static void GetModifToOrigHistory(BOPAlgo_Builder& theAlgo, TopTools_IndexedDataMapOfShapeListOfShape& theModifToOrigMap)
40 {
41   const TopTools_ListOfShape& args = theAlgo.Arguments();
42   TopTools_IndexedMapOfShape argsAllSh;
43   TopTools_ListOfShape::Iterator it(args);
44   for (;it.More();it.Next())
45   {
46     const TopoDS_Shape& aSh = it.Value();
47     if (aSh.IsNull())
48       continue;
49     TopExp::MapShapes(it.Value(), argsAllSh);
50   }
51   for (int i=1;i<=argsAllSh.Extent();i++)
52   {
53     const TopoDS_Shape& arg_sh = argsAllSh(i);
54     const TopTools_ListOfShape& modif_ls = theAlgo.Modified(arg_sh);
55     for (TopTools_ListIteratorOfListOfShape itLS(modif_ls); itLS.More(); itLS.Next())
56     {
57       const TopoDS_Shape& val = itLS.Value();
58       TopTools_ListOfShape* LS = theModifToOrigMap.ChangeSeek(val);
59       if (LS)
60         LS->Append(arg_sh);
61       else
62       {
63         TopTools_ListOfShape newLS;
64         newLS.Append(arg_sh);
65         theModifToOrigMap.Add(val, newLS);
66       }
67     }
68   }
69 }
70
71
72 static bool CheckIntersection(BOPAlgo_Builder& theAlgo, const std::vector<TopoDS_Shape>& SHM,
73   const TopTools_MapOfShape& ShapesToAvoid)
74 {
75   TopTools_MapOfShape gmodif_m;
76   int calc_ext = 0;
77   for (int i=0; i<SHM.size();i++)
78   {
79     TopTools_MapOfShape modif_m;
80     const TopTools_ListOfShape& modif_ls = theAlgo.Modified(SHM[i]);
81     for (TopTools_ListIteratorOfListOfShape itLS(modif_ls); itLS.More(); itLS.Next())
82     {
83       const TopoDS_Shape& val = itLS.Value();
84       if (!ShapesToAvoid.Contains(val))
85         modif_m.Add(val);
86     }
87     calc_ext+=modif_m.Extent();
88     gmodif_m.Unite(modif_m);
89     if (gmodif_m.Extent() < calc_ext)
90       return true; //there is an intersection
91   }
92   return false;
93 }
94
95 bool HYDROData_CompleteCalcCase::AddObjects( const Handle(HYDROData_Document)& doc,
96                                              Handle(HYDROData_CalculationCase)& theCalcCase, 
97                                              NCollection_Sequence<Handle(HYDROData_Entity)> theNewObjects,
98                                              bool IsUseOrigNamingOfNewRegions,
99                                              bool& IsIntersectionOfNewObj,
100                                              NCollection_Sequence<Handle(HYDROData_Region)>& theNewRegions)
101 {
102   Handle(HYDROData_PolylineXY) aBndPolyline = theCalcCase->GetBoundaryPolyline();        
103   TopoDS_Wire aBndWire;
104   TopoDS_Face aLimFace;
105   bool UseBndPolyline = false;
106   QString CaseName = theCalcCase->GetName();
107   if (!aBndPolyline.IsNull())
108   {
109     Handle(TopTools_HSequenceOfShape) aConnectedWires = new TopTools_HSequenceOfShape;
110     int nbWires = aBndPolyline->GetNbConnectedWires(aConnectedWires);
111     if (nbWires > 0)
112     {
113       aBndWire = TopoDS::Wire(aConnectedWires->Value(1));
114       if(!aBndWire.IsNull()) 
115       {      
116         if(HYDROData_SplitToZonesTool::buildLimFace(aBndWire, aLimFace)) 
117         {
118           theNewObjects.Append(theCalcCase->GetBoundaryPolyline());
119           UseBndPolyline = true;
120         }
121       }
122     }
123   }
124
125   BOPAlgo_Builder anAlgo;
126   std::vector<TopoDS_Shape> newShapes;
127   std::vector<Handle(HYDROData_ShapesGroup)> newshapesGroups;
128   NCollection_DataMap<TopoDS_Shape, QStringList, TopTools_ShapeMapHasher> aShToRefObjects;
129   for (int i=1; i<= theNewObjects.Size();i++)
130   {
131     Handle(HYDROData_PolylineXY) aPolyXY = Handle(HYDROData_PolylineXY)::DownCast( theNewObjects(i) );
132     if (!aPolyXY.IsNull())
133     {
134       TopoDS_Shape aSh = aPolyXY->GetShape();
135       if (!aSh.IsNull())
136       {
137         newShapes.push_back(aSh);
138         anAlgo.AddArgument(aSh);
139         QStringList aLS(aPolyXY->GetName());
140         aShToRefObjects.Bind(aSh, aLS);
141       }
142     }
143     else 
144     {
145       Handle(HYDROData_Object ) anObj = Handle(HYDROData_Object)::DownCast( theNewObjects(i) );
146       if (!anObj.IsNull())
147       {
148         TopoDS_Shape aSh = anObj->GetTopShape();
149         //
150         HYDROData_SequenceOfObjects groups = anObj->GetGroups();
151         for ( int k=1; k<=groups.Size(); k++ )
152         {
153           Handle(HYDROData_ShapesGroup) aGroup = Handle(HYDROData_ShapesGroup)::DownCast(groups(k));
154           if ( aGroup.IsNull() )
155             continue;
156           newshapesGroups.push_back(aGroup);
157         }
158         //
159         if (!aSh.IsNull())
160         {
161           newShapes.push_back(aSh);
162           anAlgo.AddArgument(aSh);
163           QStringList aLS(anObj->GetName());
164           aShToRefObjects.Bind(aSh, aLS);
165         }
166       }
167     }
168   }
169
170   HYDROData_SequenceOfObjects aRegions = theCalcCase->GetRegions();
171   for ( int i = 1; i <= aRegions.Size(); i++ )
172   {
173     Handle(HYDROData_Region) aRegion = Handle(HYDROData_Region)::DownCast( aRegions(i) );
174     if ( !aRegion.IsNull() )
175     {
176       HYDROData_SequenceOfObjects aZones = aRegion->GetZones();
177       for ( int j = 1; j <= aZones.Size(); j++ )
178       {
179         Handle(HYDROData_Zone) aZone = Handle(HYDROData_Zone)::DownCast( aZones(j) );
180         TopoDS_Shape aSh = aZone->GetShape();
181         anAlgo.AddArgument(aSh);
182         HYDROData_SequenceOfObjects aRefObjects = aZone->GetObjects();
183         QStringList aRefObjList;
184         for (int k=1;k<=aRefObjects.Size();k++)
185           aRefObjList << aRefObjects(k)->GetName();
186         aShToRefObjects.Bind(aSh, aRefObjList);
187       }
188     }
189   }
190
191   anAlgo.Perform(); 
192 #if OCC_VERSION_LARGE > 0x07020000
193   if (anAlgo.HasErrors())
194     return false;
195 #endif
196   TopoDS_Shape aRes = anAlgo.Shape();        
197   TopTools_MapOfShape UsedFaces;
198   ///
199   TopTools_IndexedDataMapOfShapeListOfShape theModifToOrigMap;
200   GetModifToOrigHistory(anAlgo, theModifToOrigMap);
201
202   //
203   if (UseBndPolyline)
204   {
205     TopTools_IndexedMapOfShape aResFaces;
206     TopExp::MapShapes(aRes, TopAbs_FACE, aResFaces);
207     Handle(IntTools_Context) aContext = new IntTools_Context();
208     for (int i=1; i<= aResFaces.Extent();i++)
209     {
210       gp_Pnt aP3D;
211       gp_Pnt2d aP2D;
212       TopoDS_Face aF = TopoDS::Face(aResFaces(i));
213       int err = BOPTools_AlgoTools3D::PointInFace(aF, aP3D, aP2D, aContext);
214       if (err)
215         continue;
216
217       TopAbs_State aState = HYDROData_Tool::ComputePointState(gp_XY(aP3D.X(), aP3D.Y()), aLimFace);
218       if (aState == TopAbs_OUT)
219       {
220         UsedFaces.Add(aF); //filter out the faces which is out of boundary polyline
221       }
222     }
223   }
224
225   ///
226   //check intersection between new objects => if it's present, the combining of zones into region will be depend on ordering
227   IsIntersectionOfNewObj = CheckIntersection(anAlgo, newShapes, UsedFaces);
228   //
229   std::vector<std::vector<TopoDS_Shape>> NREGV; //new regions vector (each vector is a region, subvector == zones) 
230   for (int i=0;i<newShapes.size();i++)
231   {
232     TopoDS_Shape aSh = newShapes[i];
233     if (aSh.ShapeType() != TopAbs_FACE)
234       continue;
235     TopTools_ListOfShape newShL = anAlgo.Modified(aSh);
236     if (newShL.IsEmpty()) //non-modified
237     {
238       if (!UsedFaces.Contains(aSh))
239       {
240         std::vector<TopoDS_Shape> vect;
241         vect.push_back(aSh);
242         NREGV.push_back(vect);
243         UsedFaces.Add(aSh);
244       }
245     }
246     else //was modified
247     {
248       std::vector<TopoDS_Shape> vect;
249       for (TopTools_ListIteratorOfListOfShape it(newShL); it.More(); it.Next())
250       {
251         TopoDS_Face nF = TopoDS::Face(it.Value());
252         if (!nF.IsNull() && !UsedFaces.Contains(nF))
253         {                                         
254           vect.push_back(nF);
255           UsedFaces.Add(nF);
256         }
257       }    
258       NREGV.push_back(vect);
259     }
260   }
261
262   //iter through already existing zone
263   //substract new zones (NREGV) from old zones
264   for ( int i = 1; i <= aRegions.Size(); i++ )
265   {
266     Handle(HYDROData_Region) aRegion = Handle(HYDROData_Region)::DownCast( aRegions(i) );
267     if ( !aRegion.IsNull() )
268     {
269       HYDROData_SequenceOfObjects aZones = aRegion->GetZones();
270       for ( int j = 1; j <= aZones.Size(); j++ )
271       {
272         Handle(HYDROData_Zone) aZone = Handle(HYDROData_Zone)::DownCast(aZones(j));
273         TopoDS_Shape aSh = aZone->GetShape();
274         TopTools_ListOfShape newShL = anAlgo.Modified(aSh);
275         if (newShL.IsEmpty() )
276           newShL.Append(aSh);
277         TopTools_MapOfShape newShM;
278         for (TopTools_ListIteratorOfListOfShape it(newShL); it.More(); it.Next())
279           newShM.Add(it.Value());
280         //
281         newShM.Subtract(UsedFaces); ///substract UsedFaces from newShM (since they have been taken by regions/object with higher priority)
282         //
283
284         if (newShM.Size() == 0)
285         {
286           //remove zone
287           aRegion->RemoveZone(aZone, true);
288         }
289         else if (newShM.Size() == 1)
290         {
291           TopoDS_Shape newS = *newShM.cbegin();
292           if (!newS.IsEqual(aSh))
293             aZone->SetShape(newS);
294         }
295         else ///newShM > 1
296         {
297           QString anOldZoneName = aZone->GetName();                
298           HYDROData_SequenceOfObjects aRefObjects = aZone->GetObjects();
299           aRegion->RemoveZone(aZone, false);
300           QStringList aRefObjList;
301           for (int k=1;k<=aRefObjects.Size();k++)
302             aRefObjList << aRefObjects(k)->GetName();
303           for (TopTools_MapIteratorOfMapOfShape it(newShM); it.More(); it.Next())
304           {
305             if (it.Value().ShapeType() == TopAbs_FACE)
306             {
307               TopoDS_Face F = TopoDS::Face(it.Value());
308               aRegion->addNewZone( doc, anOldZoneName, F, aRefObjList );
309             }
310           }
311         }
312       }
313     }
314   }
315
316   //create new regions/zones based on NREGV
317   QString aRegsPref = CaseName + "_Reg_";
318   QString aZonesPref = CaseName + "_Zone";
319   for ( int k=0;k<NREGV.size();k++ )
320   {
321     const std::vector<TopoDS_Shape>& sh_vec = NREGV[k];
322     Handle(HYDROData_Region) aRegion = theCalcCase->addNewRegion( doc, aRegsPref );
323     theNewRegions.Append(aRegion);
324     QString OrigNameOfRegion = "";
325     for (int i=0;i<sh_vec.size();i++)
326     {
327       TopoDS_Face nF = TopoDS::Face(sh_vec[i]);
328       //QString zoneName = aZonesPref;
329       QStringList refObjList;
330       //
331       const TopTools_ListOfShape* origLS = theModifToOrigMap.Seek(nF);
332       if (origLS)
333       {
334         for (TopTools_ListIteratorOfListOfShape itLS1(*origLS); itLS1.More(); itLS1.Next())
335         {
336           const TopoDS_Shape& OrSh = itLS1.Value();
337           const QStringList* names = aShToRefObjects.Seek(OrSh);
338           if (names)
339             refObjList.append(*names);
340         }
341       }
342       //
343       Handle(HYDROData_Zone) aRegionZone = aRegion->addNewZone( doc, aZonesPref, nF, refObjList);
344
345       //try to get an origial name region (obtained from origin object)
346       if (IsUseOrigNamingOfNewRegions && !refObjList.empty() && OrigNameOfRegion == "") 
347         OrigNameOfRegion = refObjList.first();
348     }
349     if (OrigNameOfRegion != "")
350       aRegion->SetName(OrigNameOfRegion + "_reg");
351   }
352
353   //GROUPS
354   HYDROData_SequenceOfObjects aSplitGroups = theCalcCase->GetSplitGroups();
355
356   ///process boundary polyline group (if present)
357   Handle(HYDROData_ShapesGroup) aBndWireGroup;
358   QString BndWireGroupName;
359   TopTools_ListOfShape aNewGroupForBndWireLS;
360   if (UseBndPolyline)
361   {
362     TopTools_IndexedMapOfShape aBndWireEdges;
363     TopTools_IndexedDataMapOfShapeListOfShape aResEdgesToFaces;
364     TopExp::MapShapes(aBndWire, TopAbs_EDGE, aBndWireEdges);
365     TopExp::MapShapesAndAncestors(aRes, TopAbs_EDGE, TopAbs_FACE, aResEdgesToFaces);
366     TopTools_IndexedMapOfShape aNewGroupForBndWire;
367     for (int i=1;i<=aBndWireEdges.Extent();i++)
368     {
369       TopoDS_Shape E = aBndWireEdges(i);
370       TopTools_ListOfShape aMLS = anAlgo.Modified(E);
371       if (aMLS.IsEmpty())
372         aMLS.Append(E);
373       TopTools_ListIteratorOfListOfShape itLS(aMLS);
374       for (;itLS.More();itLS.Next())
375       {
376         TopoDS_Edge E1 = TopoDS::Edge(itLS.Value());
377         if (E1.IsNull())
378           continue;
379         if (!aResEdgesToFaces.Contains(E1)) //should contains E since it's a part of aRes
380           continue;
381         //skip free edges
382         if (aResEdgesToFaces.FindFromKey(E1).Extent() > 0) 
383           aNewGroupForBndWire.Add(E1);
384       }
385     }
386     //
387     BndWireGroupName = CaseName + "_" + aBndPolyline->GetName();
388     for (int i=1;i<=aNewGroupForBndWire.Extent();i++)
389       aNewGroupForBndWireLS.Append(aNewGroupForBndWire(i));
390   }
391
392   // UPDATE SPLIT GROUPS       
393   for ( int k=1; k<=aSplitGroups.Size(); k++ )
394   {
395     Handle(HYDROData_ShapesGroup) aGroup = Handle(HYDROData_ShapesGroup)::DownCast(aSplitGroups(k));
396     if ( aGroup.IsNull() )
397       continue;
398
399     TopTools_SequenceOfShape GDefSeq, ModifedGDefSeq;
400
401     if (UseBndPolyline && aGroup->GetName() == BndWireGroupName)
402     {
403       aBndWireGroup = aGroup;
404       continue;
405     }
406
407     aGroup->GetShapes( GDefSeq );
408     for (int i=1;i<=GDefSeq.Length();i++)
409     {
410       const TopoDS_Shape& CSH = GDefSeq(i); 
411       TopTools_ListOfShape aMLS = anAlgo.Modified(CSH);
412       if (aMLS.IsEmpty())
413         aMLS.Append(CSH);
414       TopTools_ListIteratorOfListOfShape itLS(aMLS);
415       for (;itLS.More();itLS.Next())
416         ModifedGDefSeq.Append(itLS.Value());                     
417     }
418     aGroup->SetShapes(ModifedGDefSeq);
419   }
420
421   if (UseBndPolyline)
422   {
423     if (!aBndWireGroup.IsNull()) //modify group
424     {
425       aBndWireGroup->SetShapes(aNewGroupForBndWireLS);
426     }
427     else //add new group
428     {
429       Handle(HYDROData_SplitShapesGroup) aSplitGroup = theCalcCase->addNewSplitGroup( BndWireGroupName );
430       aSplitGroup->SetShapes(aNewGroupForBndWireLS);
431     }
432   }
433
434   ///Add new groups from newly added objects
435   for ( int k=0; k<newshapesGroups.size(); k++ )
436   {
437     Handle(HYDROData_ShapesGroup) aGroup = newshapesGroups[k];
438     QString aName = aGroup->GetName();
439     TopTools_SequenceOfShape aSeqSh, ModifedGDefSeq;
440     aGroup->GetShapes(aSeqSh);
441     Handle(HYDROData_SplitShapesGroup) aSplitGroup = theCalcCase->addNewSplitGroup( aName );
442     theCalcCase->AddGeometryGroup( aSplitGroup );
443
444     for (int i=1;i<=aSeqSh.Length();i++)
445     {
446       const TopoDS_Shape& CSH = aSeqSh(i); 
447       TopTools_ListOfShape aMLS = anAlgo.Modified(CSH);
448       if (aMLS.IsEmpty())
449         aMLS.Append(CSH);
450       TopTools_ListIteratorOfListOfShape itLS(aMLS);
451       for (;itLS.More();itLS.Next())
452         ModifedGDefSeq.Append(itLS.Value());                     
453     }
454     aSplitGroup->SetShapes(ModifedGDefSeq);
455   }
456
457   return true;
458 }