0028709: Extend type 'BRepTools_ReShape' to support 'BRepTools_History' history
[occt.git] / src / BRepTools / BRepTools_ReShape.cxx
1 // Copyright (c) 1999-2014 OPEN CASCADE SAS
2 //
3 // This file is part of Open CASCADE Technology software library.
4 //
5 // This library is free software; you can redistribute it and/or modify it under
6 // the terms of the GNU Lesser General Public License version 2.1 as published
7 // by the Free Software Foundation, with special exception defined in the file
8 // OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
9 // distribution for complete text of the license and disclaimer of any warranty.
10 //
11 // Alternatively, this file may be used under the terms of Open CASCADE
12 // commercial license or contractual agreement.
13
14 //    abv 28.04.99 S4137: ading method Apply for work on all types of shapes
15 //    sln 29.11.01 Bug24: correction iteration through map in method 'Status'
16 //    sln 29.11.01 Bug22: correction of methods Replace and Value for case when mode myConsiderLocation is on
17
18 #include <BRep_Builder.hxx>
19 #include <BRep_GCurve.hxx>
20 #include <BRep_ListIteratorOfListOfCurveRepresentation.hxx>
21 #include <BRep_ListOfCurveRepresentation.hxx>
22 #include <BRep_TEdge.hxx>
23 #include <BRep_Tool.hxx>
24 #include <BRepTools_ReShape.hxx>
25 #include <Geom_Surface.hxx>
26 #include <NCollection_IndexedMap.hxx>
27 #include <Standard_Type.hxx>
28 #include <TopExp_Explorer.hxx>
29 #include <TopLoc_Location.hxx>
30 #include <TopoDS.hxx>
31 #include <TopoDS_Compound.hxx>
32 #include <TopoDS_Edge.hxx>
33 #include <TopoDS_Face.hxx>
34 #include <TopoDS_Iterator.hxx>
35 #include <TopoDS_Shape.hxx>
36 #include <TopoDS_Shell.hxx>
37 #include <TopoDS_Solid.hxx>
38
39 IMPLEMENT_STANDARD_RTTIEXT(BRepTools_ReShape,MMgt_TShared)
40
41 namespace
42 {
43
44 //! Adds the shape to the map.
45 //! If the shape is a wire, shell or solid then
46 //! adds the sub-shapes of the shape instead.
47 //! Returns 'true' if the sub-shapes were added.
48 template<typename TMap>
49 void Add(TMap& theMap, const TopoDS_Shape& theShape)
50 {
51   const TopAbs_ShapeEnum aType = theShape.ShapeType();
52   if (aType != TopAbs_WIRE && aType != TopAbs_SHELL &&
53     aType != TopAbs_COMPSOLID)
54   {
55     theMap.Add(theShape);
56     return;
57   }
58
59   for (TopoDS_Iterator aIt(theShape); aIt.More(); aIt.Next())
60   {
61     theMap.Add(aIt.Value());
62   }
63 }
64
65 }
66
67 //include <ShapeExtend.hxx>
68 //#include <BRepTools_Edge.hxx>
69 static void CopyRanges (const TopoDS_Shape& toedge, const TopoDS_Shape& fromedge,
70                         const Standard_Real alpha, const Standard_Real beta) 
71 {
72   Handle(BRep_TEdge) aTEdgeFrom = Handle(BRep_TEdge)::DownCast(fromedge.TShape());
73   Handle(BRep_TEdge) aTEdgeTo   = Handle(BRep_TEdge)::DownCast(toedge.TShape());
74   BRep_ListOfCurveRepresentation& tolist = aTEdgeTo->ChangeCurves();
75   BRep_ListIteratorOfListOfCurveRepresentation fromitcr (aTEdgeFrom->ChangeCurves());
76   for (; fromitcr.More(); fromitcr.Next()) {
77     Handle(BRep_GCurve) fromGC = Handle(BRep_GCurve)::DownCast(fromitcr.Value());
78     if ( fromGC.IsNull() ) continue;
79     Standard_Boolean isC3d = fromGC->IsCurve3D();
80     if(isC3d) {
81       if(fromGC->Curve3D().IsNull()) continue; }
82     else {
83        if(fromGC->PCurve().IsNull()) continue; }
84       
85     if ( ! isC3d && ! fromGC->IsCurveOnSurface()) continue; // only 3d curves and pcurves are treated
86
87     Handle(Geom_Surface) surface;
88     TopLoc_Location L;
89     if ( ! isC3d ) {
90       surface = fromGC->Surface();
91       L = fromGC->Location();
92     } 
93
94     Handle(BRep_GCurve) toGC;
95     for (BRep_ListIteratorOfListOfCurveRepresentation toitcr (tolist); toitcr.More(); toitcr.Next()) {
96       toGC = Handle(BRep_GCurve)::DownCast(toitcr.Value());
97       if ( toGC.IsNull() ) continue;
98       if ( isC3d ) {
99         if ( ! toGC->IsCurve3D() ) continue;
100       }
101       else if ( ! toGC->IsCurveOnSurface() || 
102                surface != toGC->Surface() || L != toGC->Location() ) continue;
103       Standard_Real first = fromGC->First();
104       Standard_Real last = fromGC->Last();
105       Standard_Real len = last - first;
106       toGC->SetRange ( first+alpha*len, first+beta*len );
107       break;
108     }
109   }
110 }
111
112
113 //=======================================================================
114 //function : BRepTools_ReShape
115 //purpose  : 
116 //=======================================================================
117
118 BRepTools_ReShape::BRepTools_ReShape()
119 {
120   myConsiderLocation = Standard_False;
121 }
122
123
124 //=======================================================================
125 //function : Clear
126 //purpose  : 
127 //=======================================================================
128
129 void BRepTools_ReShape::Clear() 
130 {
131   myShapeToReplacement.Clear();
132   myNewShapes.Clear();
133 }
134
135
136 //=======================================================================
137 //function : Remove
138 //purpose  : 
139 //=======================================================================
140
141 void BRepTools_ReShape::Remove (const TopoDS_Shape& shape)
142 {
143   TopoDS_Shape nulshape;
144   replace(shape, nulshape, TReplacementKind_Remove);
145 }
146
147 //=======================================================================
148 //function : replace
149 //purpose  : 
150 //=======================================================================
151
152 void BRepTools_ReShape::replace (const TopoDS_Shape& ashape,
153                                  const TopoDS_Shape& anewshape,
154                                  const TReplacementKind theKind)
155 {
156   TopoDS_Shape shape = ashape;
157   TopoDS_Shape newshape = anewshape;
158   if ( shape.IsNull() || shape == newshape ) return;
159
160   if (shape.Orientation() == TopAbs_REVERSED)
161   {
162     shape.Reverse();
163     newshape.Reverse();
164   }
165   // protect against INTERNAL or EXTERNAL shape
166   else if (shape.Orientation() == TopAbs_INTERNAL
167     || shape.Orientation() == TopAbs_EXTERNAL)
168   {
169     newshape.Orientation((newshape.Orientation() == shape.Orientation()) ?
170       TopAbs_FORWARD : TopAbs_REVERSED);
171     shape.Orientation(TopAbs_FORWARD);
172   }
173
174   if (myConsiderLocation) {
175     //sln 29.11.01 Bug22: Change location of 'newshape' in accordance with location of 'shape'
176     newshape.Location(newshape.Location().Multiplied(shape.Location().Inverted()));
177     TopLoc_Location nullLoc; 
178     shape.Location ( nullLoc );
179   }
180
181 #ifdef OCCT_DEBUG
182   if ( IsRecorded ( shape ) && ((myConsiderLocation && ! Value ( shape ).IsPartner ( newshape )) ||
183                                  (!myConsiderLocation && ! Value ( shape ).IsSame ( newshape )))) 
184     cout << "Warning: BRepTools_ReShape::Replace: shape already recorded" << endl;
185 #endif
186
187   myShapeToReplacement.Bind(shape, TReplacement(newshape, theKind));
188   myNewShapes.Add (newshape);
189 }
190
191 //=======================================================================
192 //function : IsRecorded
193 //purpose  : 
194 //=======================================================================
195
196 Standard_Boolean BRepTools_ReShape::IsRecorded (const TopoDS_Shape& ashape) const
197 {
198   TopoDS_Shape shape = ashape;
199   if (myConsiderLocation) {
200     TopLoc_Location nullLoc;
201     shape.Location ( nullLoc );
202   }
203   if (shape.IsNull()) return Standard_False;
204   return myShapeToReplacement.IsBound (shape);
205 }
206
207
208 //=======================================================================
209 //function : Value
210 //purpose  : 
211 //=======================================================================
212
213 TopoDS_Shape BRepTools_ReShape::Value (const TopoDS_Shape& ashape) const
214 {
215   TopoDS_Shape res;
216   if (ashape.IsNull()) return res;
217   TopoDS_Shape shape = ashape;
218   if (myConsiderLocation) {
219     TopLoc_Location nullLoc;
220     shape.Location ( nullLoc );
221   }
222   
223   Standard_Boolean fromMap = Standard_False;
224   if (!myShapeToReplacement.IsBound(shape))
225   {
226     res = shape;
227   }
228   else
229   {
230     res = myShapeToReplacement(shape).Result();
231     if (shape.Orientation() == TopAbs_REVERSED)
232     {
233       res.Reverse();
234     }
235     fromMap = Standard_True;
236   }
237   // for INTERNAL/EXTERNAL, since they are not fully supported, keep orientation
238   if ( shape.Orientation() == TopAbs_INTERNAL ||
239        shape.Orientation() == TopAbs_EXTERNAL ) 
240     res.Orientation ( shape.Orientation() );
241
242   if (myConsiderLocation) {
243     //sln 29.11.01 Bug22: Recalculate location of resulting shape in accordance with
244     //whether result is from map or not
245     if(fromMap) res.Location(ashape.Location()*res.Location());
246     else res.Location(ashape.Location());
247   }
248
249   return res;
250 }
251
252
253 //=======================================================================
254 //function : Status
255 //purpose  : 
256 //=======================================================================
257
258 Standard_Integer BRepTools_ReShape::Status(const TopoDS_Shape& ashape,
259                                             TopoDS_Shape& newsh,
260                                             const Standard_Boolean last) 
261 {
262   Standard_Integer res = 0;
263   if (ashape.IsNull())  {  newsh.Nullify();  return res;  }
264
265   TopoDS_Shape shape = ashape;
266   TopLoc_Location aLocSh = shape.Location();
267   if (myConsiderLocation) {
268     TopLoc_Location nullLoc;
269     shape.Location ( nullLoc );
270   }
271
272   if (!myShapeToReplacement.IsBound(shape))
273   {
274     newsh = shape;
275     res = 0;
276   }
277   else
278   {
279     newsh = myShapeToReplacement(shape).Result();
280     res = 1;
281   }
282   if (res > 0) {
283     if (newsh.IsNull()) res = -1;
284     else if (newsh.IsEqual (shape)) res = 0;
285     else if ( last && ((myConsiderLocation && ! newsh.IsPartner (shape)) ||
286                        (!myConsiderLocation && ! newsh.IsSame (shape)))) {
287       //TopoDS_Shape newnewsh;
288       //Standard_Integer newres = Status (newsh, newnewsh, last);
289       //newsh = newnewsh;
290       //if (newres) res = newres;
291       // sln 29.11.01 Bug24: Correction iteration through maps. Way of iteration used early does not
292       // correspond to way of storing information in the maps.
293       newsh = Apply(shape, TopAbs_SHAPE);
294       if (newsh.IsNull()) res = -1; 
295       if (newsh.IsEqual (shape)) res = 0;
296     }
297   }
298   if(myConsiderLocation && !newsh.IsNull()) 
299   {
300     TopLoc_Location aResLoc = (res >0 && !newsh.Location().IsIdentity() ? 
301       aLocSh * newsh.Location() : aLocSh);
302     newsh.Location(aResLoc);
303   }
304   return res;
305 }
306
307 //=======================================================================
308 //function : EncodeStatus
309 //purpose  : static
310 //=======================================================================
311 static Standard_Integer EncodeStatus (const Standard_Integer status)
312 {
313   switch ( status ) {
314   case 0   : return 0x0000; //ShapeExtend_OK
315   case 1: return 0x0001;    //ShapeExtend_DONE1
316   case 2: return 0x0002;    //....
317   case 3: return 0x0004;
318   case 4: return 0x0008;
319   case 5: return 0x0010;
320   case 6: return 0x0020;
321   case 7: return 0x0040;
322   case 8: return 0x0080;    //....
323   case 9 : return 0x00ff;   //ShapeExtend_DONE
324   case 10: return 0x0100;   //ShapeExtend_FAIL1
325   case 11: return 0x0200;   //...
326   case 12: return 0x0400;
327   case 13: return 0x0800;
328   case 14: return 0x1000;
329   case 15: return 0x2000;
330   case 16: return 0x4000;
331   case 17: return 0x8000;   //....
332   case 18 : return 0xff00;  //ShapeExtend_FAIL
333   }
334   return 0;
335 }
336
337
338 //=======================================================================
339 //function : Apply
340 //purpose  : 
341 //=======================================================================
342
343 TopoDS_Shape BRepTools_ReShape::Apply (const TopoDS_Shape& shape,
344                                        const TopAbs_ShapeEnum until) 
345 {
346   myStatus = EncodeStatus(0); //ShapeExtend::EncodeStatus ( ShapeExtend_OK );
347   if ( shape.IsNull() ) return shape;
348
349   // apply direct replacement
350   TopoDS_Shape newsh = Value ( shape );
351   
352   // if shape removed, return NULL
353   if ( newsh.IsNull() ) {
354     myStatus = EncodeStatus (2); //ShapeExtend_DONE2
355     return newsh;
356   }
357   
358   // if shape replaced, apply modifications to the result recursively 
359   if ( (myConsiderLocation && ! newsh.IsPartner (shape)) || 
360       (!myConsiderLocation &&! newsh.IsSame ( shape )) ) {
361     TopoDS_Shape res = Apply ( newsh, until );
362     myStatus |= EncodeStatus(1); //ShapeExtend::EncodeStatus ( ShapeExtend_DONE1 );
363     return res;
364   }
365
366   TopAbs_ShapeEnum st = shape.ShapeType(); //, subt;
367   if ( st >= until ) return newsh;    // critere d arret
368   if(st == TopAbs_VERTEX || st == TopAbs_SHAPE)
369     return shape;
370   // define allowed types of components
371   //fix for SAMTECH bug OCC322 about abcense internal vertices after sewing. 
372   /*
373   switch ( st ) {
374   case TopAbs_COMPOUND:  subt = TopAbs_SHAPE;  break;
375   case TopAbs_COMPSOLID: subt = TopAbs_SOLID;  break;
376   case TopAbs_SOLID:     subt = TopAbs_SHELL;  break;
377   case TopAbs_SHELL:     subt = TopAbs_FACE;   break;
378   case TopAbs_FACE:      subt = TopAbs_WIRE;   break;
379   case TopAbs_WIRE:      subt = TopAbs_EDGE;   break;
380   case TopAbs_EDGE:      subt = TopAbs_VERTEX; break;
381   case TopAbs_VERTEX:
382   case TopAbs_SHAPE:
383   default:               return shape;
384   }
385   */
386   BRep_Builder B;
387   
388   TopoDS_Shape result = shape.EmptyCopied();
389   TopAbs_Orientation orien = shape.Orientation();
390   result.Orientation(TopAbs_FORWARD); // protect against INTERNAL or EXTERNAL shapes
391   Standard_Boolean modif = Standard_False;
392   Standard_Integer locStatus = myStatus;
393   
394   // apply recorded modifications to subshapes
395   Standard_Boolean isEmpty = Standard_True;
396   for ( TopoDS_Iterator it(shape,Standard_False); it.More(); it.Next() ) {
397     TopoDS_Shape sh = it.Value();
398     newsh = Apply ( sh, until );
399     if ( newsh != sh ) {
400       if ( myStatus & EncodeStatus(4)) //ShapeExtend::DecodeStatus ( myStatus, ShapeExtend_DONE4 ) )
401         locStatus |= EncodeStatus(4); //|= ShapeExtend::EncodeStatus ( ShapeExtend_DONE4 );
402       modif = 1;
403     }
404     if ( newsh.IsNull() ) {
405       locStatus |= EncodeStatus(4); //ShapeExtend::EncodeStatus ( ShapeExtend_DONE4 );
406       continue;
407     }
408     if ( isEmpty )
409       isEmpty = Standard_False;
410     locStatus |= EncodeStatus(3);//ShapeExtend::EncodeStatus ( ShapeExtend_DONE3 );
411     if ( st == TopAbs_COMPOUND || newsh.ShapeType() == sh.ShapeType()) { //fix for SAMTECH bug OCC322 about abcense internal vertices after sewing.
412       B.Add ( result, newsh );
413       continue;
414     }
415     Standard_Integer nitems = 0;
416     for ( TopoDS_Iterator subit(newsh); subit.More(); subit.Next(), nitems++ ) {
417       TopoDS_Shape subsh = subit.Value();
418       if ( subsh.ShapeType() == sh.ShapeType() ) B.Add ( result, subsh );//fix for SAMTECH bug OCC322 about abcense internal vertices after sewing.
419       else locStatus |= EncodeStatus(10);//ShapeExtend::EncodeStatus ( ShapeExtend_FAIL1 );
420     }
421     if ( ! nitems ) locStatus |= EncodeStatus(10);//ShapeExtend::EncodeStatus ( ShapeExtend_FAIL1 );
422   }
423   if ( ! modif ) return shape;
424
425   // For empty topological containers (any kind of shape except vertex, edge
426   // and face) we have to produce an empty result
427   if ( isEmpty && st != TopAbs_VERTEX && st != TopAbs_EDGE && st != TopAbs_FACE )
428   {
429     result = TopoDS_Shape();
430   }
431   else
432   {
433     // restore Range on edge broken by EmptyCopied()
434     if ( st == TopAbs_EDGE ) {
435       CopyRanges (result, shape, 0, 1);
436     }
437     else if (st == TopAbs_FACE)  {
438       TopoDS_Face face = TopoDS::Face ( shape );
439       if( BRep_Tool::NaturalRestriction( face ) ) {
440         BRep_Builder aB;
441         aB.NaturalRestriction( TopoDS::Face (  result ), Standard_True );
442       }
443     }
444     else if (st == TopAbs_WIRE || st == TopAbs_SHELL)
445       result.Closed (BRep_Tool::IsClosed (result));
446
447     result.Orientation(orien);
448   }
449
450   replace(shape, result,
451     result.IsNull() ? TReplacementKind_Remove : TReplacementKind_Modify);
452   myStatus = locStatus;
453
454   return result;
455 }
456
457
458 //=======================================================================
459 //function : Status
460 //purpose  : 
461 //=======================================================================
462
463 /*Standard_Boolean BRepTools_ReShape::Status (const ShapeExtend_Status status) const
464 {
465   return ShapeExtend::DecodeStatus ( myStatus, status );
466 }*/
467
468 //=======================================================================
469 //function : CopyVertex
470 //purpose  : 
471 //=======================================================================
472
473 TopoDS_Vertex BRepTools_ReShape::CopyVertex(const TopoDS_Vertex& theV,
474                                             const Standard_Real theTol)
475 {
476   return CopyVertex(theV, BRep_Tool::Pnt(theV), theTol);
477 }
478
479 //=======================================================================
480 //function : CopyVertex
481 //purpose  : 
482 //=======================================================================
483
484 TopoDS_Vertex BRepTools_ReShape::CopyVertex(const TopoDS_Vertex& theV,
485                                             const gp_Pnt& theNewPos,
486                                             const Standard_Real theTol)
487 {
488   TopoDS_Vertex aVertexCopy;
489   Standard_Boolean isRecorded = IsRecorded(theV);
490   aVertexCopy = isRecorded ? TopoDS::Vertex(Apply(theV)) : TopoDS::Vertex(theV.EmptyCopied());
491
492   BRep_Builder B;
493   Standard_Real aNewTol = theTol > 0.0 ? theTol : BRep_Tool::Tolerance(theV);
494   B.UpdateVertex(aVertexCopy, theNewPos, aNewTol);
495
496   if (!isRecorded)
497     Replace(theV, aVertexCopy);
498
499   return aVertexCopy;
500 }
501
502 Standard_Boolean BRepTools_ReShape::IsNewShape(const TopoDS_Shape& theShape) const
503 {
504   return myNewShapes.Contains(theShape);
505 }
506
507 //=======================================================================
508 //function : History
509 //purpose  :
510 //=======================================================================
511
512 Handle(BRepTools_History) BRepTools_ReShape::History() const
513 {
514   Handle(BRepTools_History) aHistory = new BRepTools_History;
515
516   // Fill the history.
517   for (TShapeToReplacement::Iterator aRIt(myShapeToReplacement);
518     aRIt.More(); aRIt.Next())
519   {
520     const TopoDS_Shape& aShape = aRIt.Key();
521     if (!BRepTools_History::IsSupportedType(aShape) ||
522       myNewShapes.Contains(aShape))
523     {
524       continue;
525     }
526
527     NCollection_IndexedMap<TopoDS_Shape> aIntermediates;
528     NCollection_Map<TopoDS_Shape> aModified;
529     aIntermediates.Add(aShape);
530     for (Standard_Integer aI = 1; aI <= aIntermediates.Size(); ++aI)
531     {
532       const TopoDS_Shape& aIntermediate = aIntermediates(aI);
533       const TReplacement* aReplacement =
534         myShapeToReplacement.Seek(aIntermediate);
535       if (aReplacement == NULL)
536       {
537         Add(aModified, aIntermediate);
538       }
539       else if (aReplacement->RelationKind() !=
540         BRepTools_History::TRelationType_Removed)
541       {
542         const TopoDS_Shape aResult = aReplacement->RelationResult();
543         if (!aResult.IsNull())
544         {
545           Add(aIntermediates, aResult);
546         }
547       }
548     }
549
550     if (aModified.IsEmpty())
551     {
552       aHistory->Remove(aShape);
553     }
554     else
555     {
556       for (NCollection_Map<TopoDS_Shape>::Iterator aIt(aModified);
557         aIt.More(); aIt.Next())
558       {
559         aHistory->AddModified(aShape, aIt.Value());
560       }
561     }
562   }
563
564   return aHistory;
565 }