0030386: Modeling Algorithms - Unable to perform Cut operation
[occt.git] / src / BOPAlgo / BOPAlgo_MakeConnected.cxx
1 // Created on: 2018-03-29
2 // Created by: Eugeny MALTCHIKOV
3 // Copyright (c) 2018 OPEN CASCADE SAS
4 //
5 // This file is part of Open CASCADE Technology software library.
6 //
7 // This library is free software; you can redistribute it and/or modify it under
8 // the terms of the GNU Lesser General Public License version 2.1 as published
9 // by the Free Software Foundation, with special exception defined in the file
10 // OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
11 // distribution for complete text of the license and disclaimer of any warranty.
12 //
13 // Alternatively, this file may be used under the terms of Open CASCADE
14 // commercial license or contractual agreement.
15
16 #include <BOPAlgo_MakeConnected.hxx>
17
18 #include <BOPAlgo_Alerts.hxx>
19 #include <BOPAlgo_Builder.hxx>
20 #include <BOPAlgo_Tools.hxx>
21
22 #include <BOPTools_AlgoTools.hxx>
23
24 #include <BRep_Builder.hxx>
25
26 #include <TopExp_Explorer.hxx>
27
28 #include <TopoDS_Iterator.hxx>
29
30 //=======================================================================
31 //function : Perform
32 //purpose  : Makes the shapes connected
33 //=======================================================================
34 void BOPAlgo_MakeConnected::Perform()
35 {
36   // Check the input data
37   CheckData();
38   if (HasErrors())
39     return;
40
41   if (myHistory.IsNull())
42     myHistory = new BRepTools_History;
43
44   // Glue the arguments
45   MakeConnected();
46   if (HasErrors())
47     return;
48
49   // Perform material associations for the faces
50   AssociateMaterials();
51   if (HasErrors())
52     return;
53 }
54
55 //=======================================================================
56 //function : CheckData
57 //purpose  : Check the validity of input data
58 //=======================================================================
59 void BOPAlgo_MakeConnected::CheckData()
60 {
61   // Check the number of arguments
62   if (myArguments.IsEmpty())
63   {
64     // Not enough arguments
65     AddError(new BOPAlgo_AlertTooFewArguments());
66     return;
67   }
68
69   // Check that all shapes in arguments are of the same type
70
71   // Extract the shapes from the compound arguments
72   TopTools_ListOfShape aLA;
73   // Fence map
74   TopTools_MapOfShape aMFence;
75
76   TopTools_ListIteratorOfListOfShape itLA(myArguments);
77   for (; itLA.More(); itLA.Next())
78     BOPTools_AlgoTools::TreatCompound(itLA.Value(), aLA, &aMFence);
79
80   if (aLA.IsEmpty())
81   {
82     // It seems that all argument shapes are empty compounds
83     AddError(new BOPAlgo_AlertTooFewArguments());
84     return;
85   }
86
87   // Check dimensions of the extracted non-compound shapes
88   itLA.Initialize(aLA);
89   Standard_Integer iDim = BOPTools_AlgoTools::Dimension(itLA.Value());
90   for (itLA.Next(); itLA.More(); itLA.Next())
91   {
92     if (iDim != BOPTools_AlgoTools::Dimension(itLA.Value()))
93     {
94       // The arguments are of different type
95       AddError(new BOPAlgo_AlertMultiDimensionalArguments());
96       return;
97     }
98   }
99 }
100
101 //=======================================================================
102 //function : MakeConnected
103 //purpose  : Glues the argument shapes
104 //=======================================================================
105 void BOPAlgo_MakeConnected::MakeConnected()
106 {
107   // Initialize the history
108   if (myGlueHistory.IsNull())
109     myGlueHistory = new BRepTools_History;
110
111   if (myArguments.Extent() == 1)
112   {
113     // No need to glue the single shape
114     myShape = myArguments.First();
115   }
116   else
117   {
118     // Glue the shapes
119     BOPAlgo_Builder aGluer;
120     aGluer.SetArguments(myArguments);
121     aGluer.SetGlue(BOPAlgo_GlueShift);
122     aGluer.SetRunParallel(myRunParallel);
123     aGluer.SetNonDestructive(Standard_True);
124     aGluer.Perform();
125     if (aGluer.HasErrors())
126     {
127       // Unable to glue the shapes
128       TopoDS_Compound aCW;
129       BRep_Builder().MakeCompound(aCW);
130       for (TopTools_ListIteratorOfListOfShape it(myArguments); it.More(); it.Next())
131         BRep_Builder().Add(aCW, it.Value());
132       AddError(new BOPAlgo_AlertUnableToGlue(aCW));
133       return;
134     }
135     myShape = aGluer.Shape();
136     // Save the gluing history
137     myGlueHistory->Merge(aGluer.Arguments(), aGluer);
138     myHistory->Merge(myGlueHistory);
139   }
140
141   // Keep the glued shape
142   myGlued = myShape;
143
144   // Fill the map of origins
145   FillOrigins();
146 }
147
148 //=======================================================================
149 //function : FillOrigins
150 //purpose  : Fills the map of origins
151 //=======================================================================
152 void BOPAlgo_MakeConnected::FillOrigins()
153 {
154   myOrigins.Clear();
155
156   // Map the history shapes of the arguments
157   if (myAllInputsMap.IsEmpty())
158   {
159     TopTools_ListIteratorOfListOfShape itLA(myArguments);
160     for (; itLA.More(); itLA.Next())
161       TopExp::MapShapes(itLA.Value(), myAllInputsMap);
162   }
163
164   const Standard_Integer aNbS = myAllInputsMap.Extent();
165   for (Standard_Integer i = 1; i <= aNbS; ++i)
166   {
167     const TopoDS_Shape& aS = myAllInputsMap(i);
168     if (!BRepTools_History::IsSupportedType(aS))
169       continue;
170
171     // Get Modified & Generated shapes
172     for (Standard_Integer j = 0; j < 2; ++j)
173     {
174       const TopTools_ListOfShape& aLH = !j ? myHistory->Modified(aS) : myHistory->Generated(aS);
175       TopTools_ListIteratorOfListOfShape itLH(aLH);
176       for (; itLH.More(); itLH.Next())
177       {
178         const TopoDS_Shape& aHS = itLH.Value();
179         TopTools_ListOfShape* pLOr = myOrigins.ChangeSeek(aHS);
180         if (!pLOr)
181           pLOr = myOrigins.Bound(aHS, TopTools_ListOfShape());
182         if (!pLOr->Contains(aS))
183           pLOr->Append(aS);
184       }
185     }
186   }
187 }
188
189 //=======================================================================
190 //function : AssociateMaterials
191 //purpose  : Associates the materials for the border elements
192 //=======================================================================
193 void BOPAlgo_MakeConnected::AssociateMaterials()
194 {
195   myMaterials.Clear();
196
197   // Extract all non-compound shapes from the result
198   TopTools_ListOfShape aLShapes;
199   TopTools_MapOfShape aMFence;
200   BOPTools_AlgoTools::TreatCompound(myShape, aLShapes, &aMFence);
201
202   if (aLShapes.IsEmpty())
203     return;
204
205   // Define the element type and the material type
206   TopAbs_ShapeEnum anElemType;
207   const TopAbs_ShapeEnum aMaterialType = aLShapes.First().ShapeType();
208   if (aMaterialType == TopAbs_SOLID || aMaterialType == TopAbs_COMPSOLID)
209     anElemType = TopAbs_FACE;
210   else if (aMaterialType == TopAbs_FACE || aMaterialType == TopAbs_SHELL)
211     anElemType = TopAbs_EDGE;
212   else if (aMaterialType == TopAbs_EDGE || aMaterialType == TopAbs_WIRE)
213     anElemType = TopAbs_VERTEX;
214   else
215     return;
216
217   TopTools_ListIteratorOfListOfShape itLS(aLShapes);
218   for (; itLS.More(); itLS.Next())
219   {
220     const TopoDS_Shape& aS = itLS.Value();
221     const TopTools_ListOfShape& aLOr = GetOrigins(aS);
222     const TopoDS_Shape& aSOr = aLOr.IsEmpty() ? aS : aLOr.First();
223
224     TopExp_Explorer anExp(aS, anElemType);
225     for (; anExp.More(); anExp.Next())
226     {
227       const TopoDS_Shape& anElement = anExp.Current();
228       TopTools_ListOfShape* pLM = myMaterials.ChangeSeek(anElement);
229       if (!pLM)
230         pLM = myMaterials.Bound(anElement, TopTools_ListOfShape());
231       pLM->Append(aSOr);
232     }
233   }
234 }
235
236 //=======================================================================
237 //function : Update
238 //purpose  : Updates the history, material associations and origins map
239 //           after periodicity operations
240 //=======================================================================
241 void BOPAlgo_MakeConnected::Update()
242 {
243   // Update history
244   myHistory->Clear();
245   if (!myGlueHistory.IsNull())
246     myHistory->Merge(myGlueHistory);
247   if (!myPeriodicityMaker.History().IsNull())
248     myHistory->Merge(myPeriodicityMaker.History());
249
250   // Fill the map of origins
251   FillOrigins();
252
253   // Update the material associations after making the shape periodic
254   AssociateMaterials();
255 }
256
257 //=======================================================================
258 //function : MakePeriodic
259 //purpose  : Makes the shape periodic according to the given parameters
260 //=======================================================================
261 void BOPAlgo_MakeConnected::MakePeriodic(const BOPAlgo_MakePeriodic::PeriodicityParams& theParams)
262 {
263   if (HasErrors())
264     return;
265
266   // Make the shape periodic
267   myPeriodicityMaker.Clear();
268   myPeriodicityMaker.SetShape(myGlued);
269   myPeriodicityMaker.SetPeriodicityParameters(theParams);
270   myPeriodicityMaker.SetRunParallel(myRunParallel);
271   myPeriodicityMaker.Perform();
272   if (myPeriodicityMaker.HasErrors())
273   {
274     // Add warning informing the user that periodicity with
275     // given parameters is not possible
276     AddWarning(new BOPAlgo_AlertUnableToMakePeriodic(myShape));
277     return;
278   }
279
280   myShape = myPeriodicityMaker.Shape();
281
282   // Update history, materials, origins
283   Update();
284 }
285
286 //=======================================================================
287 //function : RepeatShape
288 //purpose  : Repeats the shape in the given direction given number of times
289 //=======================================================================
290 void BOPAlgo_MakeConnected::RepeatShape(const Standard_Integer theDirectionID,
291                                         const Standard_Integer theTimes)
292 {
293   if (HasErrors())
294     return;
295
296   if (myPeriodicityMaker.Shape().IsNull() || myPeriodicityMaker.HasErrors())
297   {
298     // The shape has not been made periodic yet
299     AddWarning(new BOPAlgo_AlertShapeIsNotPeriodic(myShape));
300     return;
301   }
302
303   // Repeat the shape
304   myShape = myPeriodicityMaker.RepeatShape(theDirectionID, theTimes);
305
306   // Update history, materials, origins
307   Update();
308 }
309
310 //=======================================================================
311 //function : ClearRepetitions
312 //purpose  : Clears the repetitions performed on the periodic shape
313 //           keeping the shape periodic
314 //=======================================================================
315 void BOPAlgo_MakeConnected::ClearRepetitions()
316 {
317   if (HasErrors())
318     return;
319
320   if (myPeriodicityMaker.Shape().IsNull() || myPeriodicityMaker.HasErrors())
321   {
322     // The shape has not been made periodic yet
323     AddWarning(new BOPAlgo_AlertShapeIsNotPeriodic(myShape));
324     return;
325   }
326
327   // Clear repetitions
328   myPeriodicityMaker.ClearRepetitions();
329   myShape = myPeriodicityMaker.Shape();
330
331   // Update history, materials, origins
332   Update();
333 }