1 // Copyright (C) 2005 OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN,
2 // CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS
4 // This library is free software; you can redistribute it and/or
5 // modify it under the terms of the GNU Lesser General Public
6 // License as published by the Free Software Foundation; either
7 // version 2.1 of the License.
9 // This library is distributed in the hope that it will be useful
10 // but WITHOUT ANY WARRANTY; without even the implied warranty of
11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 // Lesser General Public License for more details.
14 // You should have received a copy of the GNU Lesser General Public
15 // License along with this library; if not, write to the Free Software
16 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18 // See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
20 // File: GEOMAlgo_BuilderSolid.cxx
22 // Author: Peter KURNEV
25 #include <GEOMAlgo_BuilderSolid.ixx>
27 #include <gp_Pnt2d.hxx>
33 #include <Geom_Curve.hxx>
34 #include <Geom_Surface.hxx>
35 #include <Geom2d_Curve.hxx>
39 #include <TopoDS_Iterator.hxx>
40 #include <TopoDS_Face.hxx>
42 #include <TopoDS_Shape.hxx>
43 #include <TopoDS_Shell.hxx>
44 #include <TopoDS_Edge.hxx>
45 #include <TopoDS_Solid.hxx>
46 #include <TopoDS_Vertex.hxx>
47 #include <TopoDS_Compound.hxx>
49 #include <BRep_Builder.hxx>
50 #include <BRep_Tool.hxx>
51 #include <BRepTools.hxx>
52 #include <BRepClass3d_SolidClassifier.hxx>
55 #include <TopExp_Explorer.hxx>
57 #include <TopTools_MapOfShape.hxx>
58 #include <TopTools_MapIteratorOfMapOfShape.hxx>
59 #include <TopTools_MapOfOrientedShape.hxx>
60 #include <TopTools_MapIteratorOfMapOfOrientedShape.hxx>
61 #include <TopTools_ListOfShape.hxx>
62 #include <TopTools_ListIteratorOfListOfShape.hxx>
63 #include <TopTools_DataMapOfShapeShape.hxx>
64 #include <TopTools_IndexedMapOfShape.hxx>
65 #include <TopTools_IndexedDataMapOfShapeListOfShape.hxx>
66 #include <TopTools_DataMapOfShapeListOfShape.hxx>
67 #include <TopTools_DataMapIteratorOfDataMapOfShapeListOfShape.hxx>
69 #include <IntTools_Context.hxx>
71 #include <BOPTools_Tools2D.hxx>
72 #include <BOPTools_Tools3D.hxx>
74 #include <NMTTools_ListOfCoupleOfShape.hxx>
75 #include <NMTTools_CoupleOfShape.hxx>
76 #include <NMTTools_ListIteratorOfListOfCoupleOfShape.hxx>
78 #include <GEOMAlgo_Tools3D.hxx>
79 #include <GEOMAlgo_BuilderTools.hxx>
83 Standard_Boolean IsGrowthShell(const TopoDS_Shape& ,
84 const TopTools_IndexedMapOfShape& );
86 Standard_Boolean IsHole(const TopoDS_Shape& ,
89 Standard_Boolean IsInside(const TopoDS_Shape& ,
93 void MakeInternalShells(const TopTools_MapOfShape& ,
94 TopTools_ListOfShape& );
96 //modified by NIZNHY-PKV Tue Aug 5 15:06:50 2008f
98 Standard_Boolean IsClosedShell(const TopoDS_Shell& theShell);
99 //modified by NIZNHY-PKV Tue Aug 5 15:06:57 2008t
101 //=======================================================================
104 //=======================================================================
105 GEOMAlgo_BuilderSolid::GEOMAlgo_BuilderSolid()
107 GEOMAlgo_BuilderArea()
110 //=======================================================================
113 //=======================================================================
114 GEOMAlgo_BuilderSolid::~GEOMAlgo_BuilderSolid()
117 //=======================================================================
120 //=======================================================================
121 void GEOMAlgo_BuilderSolid::Perform()
128 TopTools_ListIteratorOfListOfShape aIt;
130 aBB.MakeCompound(aC);
131 aIt.Initialize(myShapes);
132 for(; aIt.More(); aIt.Next()) {
133 const TopoDS_Shape& aF=aIt.Value();
138 if (myContext==NULL) {
139 myErrorStatus=11;// Null Context
143 PerformShapesToAvoid();
156 PerformInternalShapes();
161 //=======================================================================
162 //function :PerformShapesToAvoid
164 //=======================================================================
165 void GEOMAlgo_BuilderSolid::PerformShapesToAvoid()
167 Standard_Boolean bFound;
168 Standard_Integer i, iCnt, aNbE, aNbF;
169 TopAbs_Orientation aOrE;
170 TopTools_IndexedDataMapOfShapeListOfShape aMEF;
171 TopTools_ListIteratorOfListOfShape aIt;
173 myShapesToAvoid.Clear();
178 bFound=Standard_False;
182 aIt.Initialize (myShapes);
183 for (; aIt.More(); aIt.Next()) {
184 const TopoDS_Shape& aF=aIt.Value();
185 if (!myShapesToAvoid.Contains(aF)) {
186 TopExp::MapShapesAndAncestors(aF, TopAbs_EDGE, TopAbs_FACE, aMEF);
195 for (i=1; i<=aNbE; ++i) {
196 const TopoDS_Edge& aE=TopoDS::Edge(aMEF.FindKey(i));
197 if (BRep_Tool::Degenerated(aE)) {
201 TopTools_ListOfShape& aLF=aMEF.ChangeFromKey(aE);
208 aOrE=aE.Orientation();
210 const TopoDS_Face& aF1=TopoDS::Face(aLF.First());
212 if (aOrE==TopAbs_INTERNAL) {
215 bFound=Standard_True;
216 myShapesToAvoid.Add(aF1);
219 const TopoDS_Face& aF2=TopoDS::Face(aLF.Last());
220 if (aF2.IsSame(aF1)) {
221 if (BRep_Tool::IsClosed(aE, aF1)) {
225 if (aOrE==TopAbs_INTERNAL) {
229 bFound=Standard_True;
230 myShapesToAvoid.Add(aF1);
231 myShapesToAvoid.Add(aF2);
236 TopTools_ListIteratorOfListOfShape aItLF;
238 aItLF.Initialize (aLF);
239 for (; aItLF.More(); aItLF.Next()) {
240 const TopoDS_Shape& aFx=aItLF.Value();
245 }// for (i=1; i<=aNbE; ++i) {
253 //=======================================================================
254 //function : PerformLoops
256 //=======================================================================
257 void GEOMAlgo_BuilderSolid::PerformLoops()
263 Standard_Integer aNbLF, aNbOff, aNbFP, aNbFA;
264 TopAbs_Orientation anOr;
267 NMTTools_CoupleOfShape aCSOff;
268 TopTools_MapOfOrientedShape AddedFacesMap;//, aMFP;
269 TopTools_IndexedDataMapOfShapeListOfShape aEFMap, aMEFP;
270 TopTools_ListIteratorOfListOfShape aItF, aIt;
271 TopTools_MapIteratorOfMapOfOrientedShape aItM;
272 TopoDS_Iterator aItS;
274 //=================================================
278 aItF.Initialize (myShapes);
279 for (; aItF.More(); aItF.Next()) {
280 const TopoDS_Shape& aFF = aItF.Value();
281 TopExp::MapShapesAndAncestors(aFF, TopAbs_EDGE, TopAbs_FACE, aEFMap);
284 aItF.Initialize (myShapes);
285 for (; aItF.More(); aItF.Next()) {
286 const TopoDS_Shape& aFF = aItF.Value();
287 if (myShapesToAvoid.Contains(aFF)) {
290 if (!AddedFacesMap.Add(aFF)) {
296 aBB.MakeShell(aShell);
297 aBB.Add(aShell, aFF);
300 TopExp::MapShapesAndAncestors(aFF, TopAbs_EDGE, TopAbs_FACE, aMEFP);
302 // loop on faces added to Shell; add their neighbor faces to Shell and so on
303 TopoDS_Iterator aItAddedF (aShell);
304 for (; aItAddedF.More(); aItAddedF.Next()) {
305 const TopoDS_Face& aF = TopoDS::Face(aItAddedF.Value());
307 // loop on edges of aF; find a good neighbor face of aF by aE
308 TopExp_Explorer aEdgeExp(aF, TopAbs_EDGE);
309 for (; aEdgeExp.More(); aEdgeExp.Next()) {
310 const TopoDS_Edge& aE = TopoDS::Edge(aEdgeExp.Current());
313 if (aMEFP.Contains(aE)) {
314 const TopTools_ListOfShape& aLFP=aMEFP.FindFromKey(aE);
321 anOr=aE.Orientation();
322 if (anOr==TopAbs_INTERNAL) {
326 if (BRep_Tool::Degenerated(aE)) {
330 // candidate faces list
331 const TopTools_ListOfShape& aLF=aEFMap.FindFromKey(aE);
337 // try to select one of neighbors
338 // check if a face already added to Shell shares E
339 Standard_Boolean bFound;
340 TopTools_ListIteratorOfListOfShape aItLF;
341 NMTTools_ListOfCoupleOfShape aLCSOff;
343 aItLF.Initialize(aLF);
344 for (; aItLF.More(); aItLF.Next()) {
345 const TopoDS_Face& aFL=TopoDS::Face(aItLF.Value());
346 if (myShapesToAvoid.Contains(aFL)) {
349 if (aF.IsSame(aFL)) {
352 if (AddedFacesMap.Contains(aFL)){
356 bFound=GEOMAlgo_Tools3D::GetEdgeOff(aE, aFL, aEL);
361 aCSOff.SetShape1(aEL);
362 aCSOff.SetShape2(aFL);
363 aLCSOff.Append(aCSOff);
364 }//for (; aItLF.More(); aItLF.Next()) {
366 aNbOff=aLCSOff.Extent();
373 aSelF=TopoDS::Face(aLCSOff.First().Shape2());
376 GEOMAlgo_Tools3D::GetFaceOff(aE, aF, aLCSOff, aSelF);
379 if (!aSelF.IsNull() && AddedFacesMap.Add(aSelF)) {
380 aBB.Add(aShell, aSelF);
381 TopExp::MapShapesAndAncestors(aSelF, TopAbs_EDGE, TopAbs_FACE, aMEFP);
383 } // for (; aEdgeExp.More(); aEdgeExp.Next()) {
384 } //for (; aItAddedF.More(); aItAddedF.Next()) {
385 //modified by NIZNHY-PKV Tue Aug 5 15:07:08 2008f
386 //myLoops.Append(aShell);
387 if (IsClosedShell(aShell)) {
388 myLoops.Append(aShell);
392 TopoDS_Iterator aItS;
393 aItS.Initialize(aShell);
394 for (; aItS.More(); aItS.Next()) {
395 const TopoDS_Shape& aFs=aItS.Value();
400 //modified by NIZNHY-PKV Tue Aug 5 15:07:30 2008t
401 } // for (; aItF.More(); aItF.Next()) {
402 //modified by NIZNHY-PKV Tue Aug 5 15:07:35 2008f
405 TopTools_MapOfOrientedShape aMP;
407 // a. collect all edges that are in loops
408 aIt.Initialize (myLoops);
409 for (; aIt.More(); aIt.Next()) {
410 const TopoDS_Shape& aS=aIt.Value();
412 for (; aItS.More(); aItS.Next()) {
413 const TopoDS_Shape& aF=aItS.Value();
418 // b. collect all edges that are to avoid
419 aItM.Initialize(myShapesToAvoid);
420 for (; aItM.More(); aItM.Next()) {
421 const TopoDS_Shape& aF=aItM.Key();
425 // c. add all edges that are not processed to myShapesToAvoid
426 aIt.Initialize (myShapes);
427 for (; aIt.More(); aIt.Next()) {
428 const TopoDS_Shape& aF=aIt.Value();
429 if (!aMP.Contains(aF)) {
430 myShapesToAvoid.Add(aF);
433 //modified by NIZNHY-PKV Tue Aug 5 15:07:44 2008t
434 //=================================================
438 myLoopsInternal.Clear();
441 AddedFacesMap.Clear();
443 aNbFA=myShapesToAvoid.Extent();
445 aItM.Initialize(myShapesToAvoid);
446 for (; aItM.More(); aItM.Next()) {
447 const TopoDS_Shape& aFF=aItM.Key();
448 TopExp::MapShapesAndAncestors(aFF, TopAbs_EDGE, TopAbs_FACE, aEFMap);
451 aItM.Initialize(myShapesToAvoid);
452 for (; aItM.More(); aItM.Next()) {
453 const TopoDS_Shape& aFF=aItM.Key();
454 if (!AddedFacesMap.Add(aFF)) {
460 aBB.MakeShell(aShell);
461 aBB.Add(aShell, aFF);
463 TopoDS_Iterator aItAddedF (aShell);
464 for (; aItAddedF.More(); aItAddedF.Next()) {
465 const TopoDS_Face& aF = TopoDS::Face(aItAddedF.Value());
467 TopExp_Explorer aEdgeExp(aF, TopAbs_EDGE);
468 for (; aEdgeExp.More(); aEdgeExp.Next()) {
469 const TopoDS_Edge& aE = TopoDS::Edge(aEdgeExp.Current());
470 const TopTools_ListOfShape& aLF=aEFMap.FindFromKey(aE);
471 aItF.Initialize(aLF);
472 for (; aItF.More(); aItF.Next()) {
473 const TopoDS_Face& aFL=TopoDS::Face(aItF.Value());
474 if (AddedFacesMap.Add(aFL)){
475 aBB.Add(aShell, aFL);
480 myLoopsInternal.Append(aShell);
483 //=======================================================================
484 //function : PerformAreas
486 //=======================================================================
487 void GEOMAlgo_BuilderSolid::PerformAreas()
491 Standard_Boolean bIsGrowthShell, bIsHole;
492 TopTools_ListOfShape aNewSolids, aHoleShells;
493 TopoDS_Shape anInfinitePointShape;
494 TopTools_DataMapOfShapeShape aInOutMap;
495 TopTools_DataMapOfShapeListOfShape aMSH;
496 TopTools_DataMapIteratorOfDataMapOfShapeListOfShape aItMSH;
497 TopTools_ListIteratorOfListOfShape aShellIt, aSolidIt;
498 TopTools_IndexedMapOfShape aMHF;
503 // Draft solids [aNewSolids]
504 aShellIt.Initialize(myLoops);
505 for ( ; aShellIt.More(); aShellIt.Next()) {
506 const TopoDS_Shape& aShell = aShellIt.Value();
508 bIsGrowthShell=IsGrowthShell(aShell, aMHF);
509 if (bIsGrowthShell) {
510 // make a growth solid from a shell
512 aBB.MakeSolid(Solid);
513 aBB.Add (Solid, aShell);
515 aNewSolids.Append (Solid);
518 // check if a shell is a hole
520 bIsHole=IsHole(aShell, myContext);
521 //bIsHole=GEOMAlgo_BuilderTools::IsHole(aShell);
524 aHoleShells.Append(aShell);
525 TopExp::MapShapes(aShell, TopAbs_FACE, aMHF);
528 // make a growth solid from a shell
530 aBB.MakeSolid(Solid);
531 aBB.Add (Solid, aShell);
533 aNewSolids.Append (Solid);
538 // 2. Find outer growth shell that is most close to each hole shell
539 aShellIt.Initialize(aHoleShells);
540 for (; aShellIt.More(); aShellIt.Next()) {
541 const TopoDS_Shape& aHole = aShellIt.Value();
543 aSolidIt.Initialize(aNewSolids);
544 for ( ; aSolidIt.More(); aSolidIt.Next()) {
545 const TopoDS_Shape& aSolid = aSolidIt.Value();
547 if (!IsInside(aHole, aSolid, myContext)){
551 if ( aInOutMap.IsBound (aHole)){
552 const TopoDS_Shape& aSolid2 = aInOutMap(aHole);
553 if (IsInside(aSolid, aSolid2, myContext)) {
554 aInOutMap.UnBind(aHole);
555 aInOutMap.Bind (aHole, aSolid);
559 aInOutMap.Bind (aHole, aSolid);
563 // Add aHole to a map Solid/ListOfHoles [aMSH]
564 if (aInOutMap.IsBound(aHole)){
565 const TopoDS_Shape& aSolid=aInOutMap(aHole);
566 if (aMSH.IsBound(aSolid)) {
567 TopTools_ListOfShape& aLH=aMSH.ChangeFind(aSolid);
571 TopTools_ListOfShape aLH;
573 aMSH.Bind(aSolid, aLH);
575 //aBB.Add (aSolid, aHole);
577 }// for (; aShellIt.More(); aShellIt.Next()) {
579 // 3. Add aHoles to Solids
580 aItMSH.Initialize(aMSH);
581 for (; aItMSH.More(); aItMSH.Next()) {
582 TopoDS_Solid aSolid=TopoDS::Solid(aItMSH.Key());
584 const TopTools_ListOfShape& aLH=aItMSH.Value();
585 aShellIt.Initialize(aLH);
586 for (; aShellIt.More(); aShellIt.Next()) {
587 const TopoDS_Shape& aHole = aShellIt.Value();
588 aBB.Add (aSolid, aHole);
592 BRepClass3d_SolidClassifier& aSC=myContext->SolidClassifier(aSolid);
597 // These aNewSolids are draft solids that
598 // do not contain any internal shapes
600 myAreas.Append(aNewSolids);
602 //=======================================================================
603 //function : PerformInternalShapes
605 //=======================================================================
606 void GEOMAlgo_BuilderSolid::PerformInternalShapes()
610 Standard_Integer aNbFI=myLoopsInternal.Extent();
611 if (!aNbFI) {// nothing to do
616 TopTools_ListIteratorOfListOfShape aShellIt, aSolidIt;
618 TopTools_MapOfShape aMF, aMFP;
619 TopTools_MapIteratorOfMapOfShape aItMF;
620 TopTools_IndexedDataMapOfShapeListOfShape aMEF;
621 TopTools_ListOfShape aLSI;
623 // 1. All internal faces
624 aShellIt.Initialize(myLoopsInternal);
625 for (; aShellIt.More(); aShellIt.Next()) {
626 const TopoDS_Shape& aShell=aShellIt.Value();
627 aIt.Initialize(aShell);
628 for (; aIt.More(); aIt.Next()) {
629 const TopoDS_Shape& aF=aIt.Value();
636 aSolidIt.Initialize(myAreas);
637 for ( ; aSolidIt.More(); aSolidIt.Next()) {
638 TopoDS_Solid& aSolid=TopoDS::Solid(aSolidIt.Value());
641 TopExp::MapShapesAndAncestors(aSolid, TopAbs_EDGE, TopAbs_FACE, aMEF);
643 // 2.1 Separate faces to process aMFP
645 aItMF.Initialize(aMF);
646 for (; aItMF.More(); aItMF.Next()) {
647 const TopoDS_Face& aF=TopoDS::Face(aItMF.Key());
648 if (GEOMAlgo_Tools3D::IsInternalFace(aF, aSolid, aMEF, 1.e-14, *myContext)) {
653 // 2.2 Make Internal Shells
655 MakeInternalShells(aMFP, aLSI);
657 // 2.3 Add them to aSolid
658 aShellIt.Initialize(aLSI);
659 for (; aShellIt.More(); aShellIt.Next()) {
660 const TopoDS_Shape& aSI=aShellIt.Value();
661 aBB.Add (aSolid, aSI);
664 // 2.4 Remove faces aMFP from aMF
665 aItMF.Initialize(aMFP);
666 for (; aItMF.More(); aItMF.Next()) {
667 const TopoDS_Shape& aF=aItMF.Key();
675 } //for ( ; aSolidIt.More(); aSolidIt.Next()) {
678 //=======================================================================
679 //function : MakeInternalShells
681 //=======================================================================
682 void MakeInternalShells(const TopTools_MapOfShape& theMF,
683 TopTools_ListOfShape& theShells)
685 TopTools_MapIteratorOfMapOfShape aItM;
686 TopTools_MapOfShape aAddedFacesMap;
687 TopTools_ListIteratorOfListOfShape aItF;
688 TopTools_IndexedDataMapOfShapeListOfShape aMEF;
691 aItM.Initialize(theMF);
692 for (; aItM.More(); aItM.Next()) {
693 const TopoDS_Shape& aF=aItM.Key();
694 TopExp::MapShapesAndAncestors(aF, TopAbs_EDGE, TopAbs_FACE, aMEF);
697 aItM.Initialize(theMF);
698 for (; aItM.More(); aItM.Next()) {
699 TopoDS_Shape aFF=aItM.Key();
700 if (!aAddedFacesMap.Add(aFF)) {
706 aBB.MakeShell(aShell);
707 aFF.Orientation(TopAbs_INTERNAL);
708 aBB.Add(aShell, aFF);
710 TopoDS_Iterator aItAddedF (aShell);
711 for (; aItAddedF.More(); aItAddedF.Next()) {
712 const TopoDS_Shape& aF =aItAddedF.Value();
714 TopExp_Explorer aEdgeExp(aF, TopAbs_EDGE);
715 for (; aEdgeExp.More(); aEdgeExp.Next()) {
716 const TopoDS_Shape& aE =aEdgeExp.Current();
717 const TopTools_ListOfShape& aLF=aMEF.FindFromKey(aE);
718 aItF.Initialize(aLF);
719 for (; aItF.More(); aItF.Next()) {
720 TopoDS_Shape aFL=aItF.Value();
721 if (aAddedFacesMap.Add(aFL)){
722 aFL.Orientation(TopAbs_INTERNAL);
723 aBB.Add(aShell, aFL);
728 theShells.Append(aShell);
731 //=======================================================================
734 //=======================================================================
735 Standard_Boolean IsHole(const TopoDS_Shape& theS2,
736 IntTools_PContext& theContext)
738 TopoDS_Solid *pS2=(TopoDS_Solid *)&theS2;
739 BRepClass3d_SolidClassifier& aClsf=theContext->SolidClassifier(*pS2);
741 aClsf.PerformInfinitePoint(::RealSmall());
743 return (aClsf.State()==TopAbs_IN);
745 //=======================================================================
746 //function : IsInside
748 //=======================================================================
749 Standard_Boolean IsInside(const TopoDS_Shape& theS1,
750 const TopoDS_Shape& theS2,
751 IntTools_PContext& theContext)
753 TopExp_Explorer aExp;
756 TopoDS_Solid *pS2=(TopoDS_Solid *)&theS2;
758 aExp.Init(theS1, TopAbs_FACE);
760 BRepClass3d_SolidClassifier& aClsf=theContext->SolidClassifier(*pS2);
761 aClsf.PerformInfinitePoint(::RealSmall());
762 aState=aClsf.State();
765 TopTools_IndexedMapOfShape aBounds;
766 const TopoDS_Face& aF = TopoDS::Face(aExp.Current());
767 aState=GEOMAlgo_Tools3D::ComputeState(aF, *pS2, 1.e-14, aBounds, *theContext);
769 return (aState==TopAbs_IN);
771 //=======================================================================
772 //function : IsGrowthShell
774 //=======================================================================
775 Standard_Boolean IsGrowthShell(const TopoDS_Shape& theShell,
776 const TopTools_IndexedMapOfShape& theMHF)
778 Standard_Boolean bRet;
782 if (theMHF.Extent()) {
783 aIt.Initialize(theShell);
784 for(; aIt.More(); aIt.Next()) {
785 const TopoDS_Shape& aF=aIt.Value();
786 if (theMHF.Contains(aF)) {
793 //modified by NIZNHY-PKV Tue Aug 5 15:07:50 2008f
794 //=======================================================================
795 //function : IsClosedShell
797 //=======================================================================
798 Standard_Boolean IsClosedShell(const TopoDS_Shell& theShell)
800 Standard_Integer aNbE;
801 Standard_Boolean bRet;
803 TopExp_Explorer aExp;
804 TopTools_MapOfShape aM;
807 aIt.Initialize(theShell);
808 for(; aIt.More(); aIt.Next()) {
809 const TopoDS_Face& aF=TopoDS::Face(aIt.Value());
810 aExp.Init(aF, TopAbs_EDGE);
811 for (; aExp.More(); aExp.Next()) {
812 const TopoDS_Edge& aE=TopoDS::Edge(aExp.Current());
813 if (BRep_Tool::Degenerated(aE)) {
817 if (BRep_Tool::IsClosed(aE, aF)) {
821 if (aE.Orientation()==TopAbs_INTERNAL) {
836 //modified by NIZNHY-PKV Tue Aug 5 15:08:07 2008t
837 //BRepTools::Write(aFF, "ff");