0031918: Application Framework - New binary format for fast reading part of OCAF...
[occt.git] / src / BinTools / BinTools_ShapeReader.cxx
1 // Copyright (c) 2021 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 #include <BinTools_ShapeReader.hxx>
15 #include <TopoDS.hxx>
16 #include <BRep_PointOnCurve.hxx>
17 #include <BRep_PointOnCurveOnSurface.hxx>
18 #include <BRep_PointOnSurface.hxx>
19 #include <BRep_Polygon3D.hxx>
20 #include <BRep_Builder.hxx>
21 #include <BinTools_CurveSet.hxx>
22 #include <BinTools_Curve2dSet.hxx>
23 #include <BinTools_SurfaceSet.hxx>
24
25 //=======================================================================
26 //function : BinTools_ShapeReader
27 //purpose  : 
28 //=======================================================================
29 BinTools_ShapeReader::BinTools_ShapeReader()
30 {}
31   
32 //=======================================================================
33 //function : ~BinTools_ShapeReader
34 //purpose  : 
35 //=======================================================================
36 BinTools_ShapeReader::~BinTools_ShapeReader()
37 {}
38
39 //=======================================================================
40 //function : Clear
41 //purpose  : 
42 //=======================================================================
43 void BinTools_ShapeReader::Clear()
44 {
45   BinTools_ShapeSetBase::Clear();
46   myShapePos.Clear();
47   myLocationPos.Clear();
48   myCurvePos.Clear();
49   myCurve2dPos.Clear();
50   mySurfacePos.Clear();
51   myPolygon3dPos.Clear();
52   myPolygonPos.Clear();
53   myTriangulationPos.Clear();
54 }
55
56 //=======================================================================
57 //function : Read
58 //purpose  : 
59 //=======================================================================
60 void BinTools_ShapeReader::Read (Standard_IStream& theStream, TopoDS_Shape& theShape)
61 {
62   BinTools_IStream aStream(theStream);
63   theShape = ReadShape(aStream);
64 }
65
66 //=======================================================================
67 //function : ReadShape
68 //purpose  : 
69 //=======================================================================
70 TopoDS_Shape BinTools_ShapeReader::ReadShape (BinTools_IStream& theStream)
71 {
72   TopoDS_Shape aResult;
73   uint64_t aPosition = theStream.Position();
74   const BinTools_ObjectType& aType = theStream.ReadType();
75   if (aType == BinTools_ObjectType_EmptyShape || aType == BinTools_ObjectType_EndShape)
76     return aResult;
77
78   if (theStream.IsReference())
79   {
80     uint64_t aRef = theStream.ReadReference();
81     const TopoDS_Shape* aFound = myShapePos.Seek(aRef);
82     if (aFound) // the shape is already retrieved, just add location
83     {
84       aResult = *aFound;
85     }
86     else
87     {
88       uint64_t aCurrent = theStream.Position();
89       theStream.GoTo (aRef); // go to the referenced position
90       aResult = ReadShape (theStream);
91       theStream.GoTo (aCurrent); // returns to the current position
92     }
93     aResult.Location (*ReadLocation (theStream));
94     aResult.Orientation (TopAbs_Orientation (theStream.ReadByte()));
95     return aResult;
96   }
97   // read the shape
98   TopAbs_ShapeEnum aShapeType = theStream.ShapeType();
99   TopAbs_Orientation aShapeOrientation = theStream.ShapeOrientation();
100   const TopLoc_Location* aShapeLocation = ReadLocation (theStream);
101   Standard_Real aTol;
102   static BRep_Builder aBuilder;
103   try {
104     OCC_CATCH_SIGNALS
105       switch (aShapeType) {
106       case TopAbs_VERTEX:
107       {
108         TopoDS_Vertex& aV = TopoDS::Vertex (aResult);
109         // Read the point geometry
110         theStream >> aTol;
111         gp_Pnt aPnt = theStream.ReadPnt();
112         aBuilder.MakeVertex (aV, aPnt, aTol);
113         Handle(BRep_TVertex) aTV = Handle(BRep_TVertex)::DownCast (aV.TShape());
114         BRep_ListOfPointRepresentation& aLpr = aTV->ChangePoints();
115         static TopLoc_Location anEmptyLoc;
116         while (theStream) {
117           Standard_Byte aPrsType = theStream.ReadByte();
118           if (aPrsType == 0) // end of the cycle
119             break;
120           Standard_Real aParam = theStream.ReadReal();
121           Handle(BRep_PointRepresentation) aPR;
122           switch (aPrsType) {
123           case 1:
124           {
125             Handle(Geom_Curve) aCurve = ReadCurve (theStream);
126             if (!aCurve.IsNull())
127               aPR = new BRep_PointOnCurve (aParam, aCurve, anEmptyLoc);
128             break;
129           }
130           case 2:
131           {
132             Handle(Geom2d_Curve) aCurve2d = ReadCurve2d (theStream);
133             Handle(Geom_Surface) aSurface = ReadSurface (theStream);
134             if (!aCurve2d.IsNull() && aSurface.IsNull())
135               aPR = new BRep_PointOnCurveOnSurface (aParam, aCurve2d, aSurface, anEmptyLoc);
136             break;
137           }
138           case 3:
139           {
140             Standard_Real aParam2 = theStream.ReadReal();
141             Handle(Geom_Surface) aSurface = ReadSurface (theStream);
142             if (!aSurface.IsNull())
143               aPR = new BRep_PointOnSurface (aParam, aParam2, aSurface, anEmptyLoc);
144             break;
145           }
146           default:
147           {
148             Standard_SStream aMsg;
149             aMsg << "BinTools_ShapeReader::Read: UnExpected BRep_PointRepresentation = " << aPrsType << std::endl;
150             throw Standard_Failure (aMsg.str().c_str());
151           }
152           }
153           const TopLoc_Location* aPRLoc = ReadLocation (theStream);
154           if (!aPR.IsNull())
155           {
156             aPR->Location (*aPRLoc);
157             aLpr.Append (aPR);
158           }
159         }
160         break;
161       }
162       case TopAbs_EDGE:
163       {
164         TopoDS_Edge& aE = TopoDS::Edge (aResult);
165         aBuilder.MakeEdge(aE);
166         // Read the curve geometry 
167         theStream >> aTol;
168         Standard_Boolean aSameParameter, aSameRange, aDegenerated;
169         theStream.ReadBools (aSameParameter, aSameRange, aDegenerated);
170         aBuilder.SameParameter (aE, aSameParameter);
171         aBuilder.SameRange (aE, aSameRange);
172         aBuilder.Degenerated (aE, aDegenerated);
173         Standard_Real aFirst, aLast;
174         while (theStream) {
175           Standard_Byte aPrsType = theStream.ReadByte(); //{0|1|2|3|4|5|6|7}
176           if (aPrsType == 0)
177             break;
178           switch (aPrsType)
179           {
180           case 1: // -1- Curve 3D
181           {
182             Handle(Geom_Curve) aCurve = ReadCurve (theStream);
183             const TopLoc_Location* aLoc = ReadLocation (theStream);
184             theStream >> aFirst;
185             theStream >> aLast;
186             if (!aCurve.IsNull())
187             {
188               aBuilder.UpdateEdge (aE, aCurve, *aLoc, aTol);
189               aBuilder.Range (aE, aFirst, aLast, Standard_True);
190             }
191             break;
192           }
193           case 2: // -2- Curve on surf
194           case 3: // -3- Curve on closed surf
195           {
196             Standard_Boolean aClosed = (aPrsType == 3);
197             Handle(Geom2d_Curve) aCurve2d_2, aCurve2d_1 = ReadCurve2d (theStream);
198             GeomAbs_Shape aReg = GeomAbs_C0;
199             if (aClosed) {
200               aCurve2d_2 = ReadCurve2d (theStream);
201               aReg = (GeomAbs_Shape)theStream.ReadByte();
202             }
203             Handle(Geom_Surface) aSurface = ReadSurface (theStream);
204             const TopLoc_Location* aLoc = ReadLocation (theStream);
205             // range
206             theStream >> aFirst;
207             theStream >> aLast;
208             if (!aCurve2d_1.IsNull() && (!aClosed || !aCurve2d_2.IsNull()) && !aSurface.IsNull())
209             {
210               if (aClosed)
211               {
212                 aBuilder.UpdateEdge (aE, aCurve2d_1, aCurve2d_2, aSurface, *aLoc, aTol);
213                 aBuilder.Continuity (aE, aSurface, aSurface, *aLoc, *aLoc, aReg);
214               }
215               else
216                 aBuilder.UpdateEdge (aE, aCurve2d_1, aSurface, *aLoc, aTol);
217               aBuilder.Range (aE, aSurface, *aLoc, aFirst, aLast);
218             }
219             break;
220           }
221           case 4: // -4- Regularity
222           {
223             GeomAbs_Shape aReg = (GeomAbs_Shape)theStream.ReadByte();
224             Handle(Geom_Surface) aSurface1 = ReadSurface (theStream);
225             const TopLoc_Location* aLoc1 = ReadLocation (theStream);
226             Handle(Geom_Surface) aSurface2 = ReadSurface (theStream);
227             const TopLoc_Location* aLoc2 = ReadLocation (theStream);
228             if (!aSurface1.IsNull() && !aSurface2.IsNull())
229               aBuilder.Continuity (aE, aSurface1, aSurface2, *aLoc1, *aLoc2, aReg);
230             break;
231           }
232           case 5: // -5- Polygon3D                     
233           {
234             Handle(Poly_Polygon3D) aPolygon = ReadPolygon3d (theStream);
235             const TopLoc_Location* aLoc = ReadLocation (theStream);
236             aBuilder.UpdateEdge (aE, aPolygon, *aLoc);
237             break;
238           }
239           case 6: // -6- Polygon on triangulation
240           case 7: // -7- Polygon on closed triangulation
241           {
242             Standard_Boolean aClosed = (aPrsType == 7);
243             Handle(Poly_PolygonOnTriangulation) aPoly2, aPoly1 = ReadPolygon (theStream);
244             if (aClosed)
245               aPoly2 = ReadPolygon (theStream);
246             Handle(Poly_Triangulation) aTriangulation = ReadTriangulation (theStream);
247             const TopLoc_Location* aLoc = ReadLocation (theStream);
248             if (aClosed)
249               aBuilder.UpdateEdge (aE, aPoly1, aPoly2, aTriangulation, *aLoc);
250             else
251               aBuilder.UpdateEdge (aE, aPoly1, aTriangulation, *aLoc);
252             // range            
253             break;
254           }
255           default:
256           {
257             Standard_SStream aMsg;
258             aMsg << "Unexpected Curve Representation =" << aPrsType << std::endl;
259             throw Standard_Failure (aMsg.str().c_str());
260           }
261
262           }
263         }
264         break;
265       }
266       case TopAbs_WIRE:
267         aBuilder.MakeWire (TopoDS::Wire (aResult));
268         break;
269       case TopAbs_FACE:
270       {
271         TopoDS_Face& aF = TopoDS::Face (aResult);
272         aBuilder.MakeFace (aF);
273         Standard_Boolean aNatRes = theStream.ReadBool();
274         theStream >> aTol;
275         Handle(Geom_Surface) aSurface = ReadSurface (theStream);
276         const TopLoc_Location* aLoc = ReadLocation (theStream);
277         aBuilder.UpdateFace (aF, aSurface, *aLoc, aTol);
278         aBuilder.NaturalRestriction (aF, aNatRes);
279         if (theStream.ReadByte() == 2) // triangulation
280           aBuilder.UpdateFace (aF, ReadTriangulation (theStream));
281         break;
282       }
283       case TopAbs_SHELL:
284         aBuilder.MakeShell (TopoDS::Shell (aResult));
285         break;
286       case TopAbs_SOLID:
287         aBuilder.MakeSolid (TopoDS::Solid (aResult));
288         break;
289       case TopAbs_COMPSOLID:
290         aBuilder.MakeCompSolid (TopoDS::CompSolid (aResult));
291         break;
292       case TopAbs_COMPOUND:
293         aBuilder.MakeCompound (TopoDS::Compound (aResult));
294         break;
295       default:
296       {
297         Standard_SStream aMsg;
298         aMsg << "Unexpected topology type = " << aShapeType << std::endl;
299         throw Standard_Failure (aMsg.str().c_str());
300         break;
301       }
302       }
303   }
304   catch (Standard_Failure const& anException)
305   {
306     Standard_SStream aMsg;
307     aMsg << "EXCEPTION in BinTools_ShapeReader::Read" << std::endl;
308     aMsg << anException << std::endl;
309     throw Standard_Failure (aMsg.str().c_str());
310   }
311   // read flags and subs
312   Standard_Boolean aFree, aMod, aChecked, anOrient, aClosed, anInf, aConv;
313   theStream.ReadBools (aFree, aMod, aChecked, anOrient, aClosed, anInf, aConv);
314   // sub-shapes
315   for(TopoDS_Shape aSub = ReadShape (theStream); !aSub.IsNull(); aSub = ReadShape (theStream))
316     aBuilder.Add (aResult, aSub);
317   aResult.Free (aFree);
318   aResult.Modified (aMod);
319   aResult.Checked (aChecked);
320   aResult.Orientable (anOrient);
321   aResult.Closed (aClosed);
322   aResult.Infinite (anInf);
323   aResult.Convex (aConv);
324   myShapePos.Bind (aPosition, aResult);
325   aResult.Orientation (aShapeOrientation);
326   aResult.Location (*aShapeLocation);
327   return aResult;
328 }
329
330 //=======================================================================
331 //function : ReadLocation
332 //purpose  : 
333 //=======================================================================
334 const TopLoc_Location* BinTools_ShapeReader::ReadLocation (BinTools_IStream& theStream)
335 {
336   static const TopLoc_Location* anEmptyLoc = new TopLoc_Location;
337
338   uint64_t aPosition = theStream.Position();
339   const BinTools_ObjectType& aType = theStream.ReadType();
340   if (aType == BinTools_ObjectType_EmptyLocation || aType == BinTools_ObjectType_LocationEnd)
341     return anEmptyLoc;
342   if (theStream.IsReference())
343   {
344     uint64_t aRef = theStream.ReadReference();
345     const TopLoc_Location* aFound = myLocationPos.Seek (aRef);
346     if (aFound) // the location is already retrieved
347       return aFound;
348     uint64_t aCurrent = theStream.Position();
349     theStream.GoTo (aRef); // go to the referenced position
350     const TopLoc_Location* aResult = ReadLocation (theStream);
351     theStream.GoTo (aCurrent); // returns to the current position
352     return aResult;
353   }
354   // read the location directly from the stream
355   TopLoc_Location aLoc;
356   if (aType == BinTools_ObjectType_SimpleLocation)
357   {
358     gp_Trsf aTrsf;
359     theStream >> aTrsf;
360     aLoc = aTrsf;
361   }
362   else if (aType == BinTools_ObjectType_Location)
363   {
364     for(const TopLoc_Location* aNextLoc = ReadLocation (theStream); !aNextLoc->IsIdentity();
365                                aNextLoc = ReadLocation (theStream))
366       aLoc = aNextLoc->Powered (theStream.ReadInteger()) * aLoc;
367   }
368   myLocationPos.Bind (aPosition, aLoc);
369   return myLocationPos.Seek (aPosition);
370 }
371
372 //=======================================================================
373 //function : ReadCurve
374 //purpose  : 
375 //=======================================================================
376 Handle(Geom_Curve) BinTools_ShapeReader::ReadCurve (BinTools_IStream& theStream)
377 {
378   Handle(Geom_Curve) aResult;
379   uint64_t aPosition = theStream.Position();
380   theStream.ReadType();
381   if (theStream.IsReference())
382   { // get by reference
383     uint64_t aRef = theStream.ReadReference();
384     const Handle(Geom_Curve)* aFound = myCurvePos.Seek (aRef);
385     if (aFound) // the location is already retrieved
386       return *aFound;
387     uint64_t aCurrent = theStream.Position();
388     theStream.GoTo (aRef); // go to the referenced position
389     aResult = ReadCurve (theStream);
390     theStream.GoTo (aCurrent); // returns to the current position
391   }
392   else if (theStream.LastType() == BinTools_ObjectType_Curve)
393   { // read from the stream
394     BinTools_CurveSet::ReadCurve (theStream.Stream(), aResult);
395     theStream.UpdatePosition();
396     myCurvePos.Bind (aPosition, aResult);
397   }
398   return aResult;
399 }
400
401 //=======================================================================
402 //function : ReadCurve2d
403 //purpose  : 
404 //=======================================================================
405 Handle(Geom2d_Curve) BinTools_ShapeReader::ReadCurve2d (BinTools_IStream& theStream)
406 {
407   Handle(Geom2d_Curve) aResult;
408   uint64_t aPosition = theStream.Position();
409   theStream.ReadType();
410   if (theStream.IsReference())
411   { // get by reference
412     uint64_t aRef = theStream.ReadReference();
413     const Handle(Geom2d_Curve)* aFound = myCurve2dPos.Seek (aRef);
414     if (aFound) // the location is already retrieved
415       return *aFound;
416     uint64_t aCurrent = theStream.Position();
417     theStream.GoTo (aRef); // go to the referenced position
418     aResult = ReadCurve2d (theStream);
419     theStream.GoTo (aCurrent); // returns to the current position
420   }
421   else if (theStream.LastType() == BinTools_ObjectType_Curve2d)
422   { // read from the stream
423     BinTools_Curve2dSet::ReadCurve2d (theStream.Stream(), aResult);
424     theStream.UpdatePosition();
425     myCurve2dPos.Bind (aPosition, aResult);
426   }
427   return aResult;
428 }
429
430 //=======================================================================
431 //function : ReadSurface
432 //purpose  : 
433 //=======================================================================
434 Handle(Geom_Surface) BinTools_ShapeReader::ReadSurface (BinTools_IStream& theStream)
435 {
436   Handle(Geom_Surface) aResult;
437   uint64_t aPosition = theStream.Position();
438   theStream.ReadType();
439   if (theStream.IsReference())
440   { // get by reference
441     uint64_t aRef = theStream.ReadReference();
442     const Handle(Geom_Surface)* aFound = mySurfacePos.Seek (aRef);
443     if (aFound) // the location is already retrieved
444       return *aFound;
445     uint64_t aCurrent = theStream.Position();
446     theStream.GoTo (aRef); // go to the referenced position
447     aResult = ReadSurface (theStream);
448     theStream.GoTo (aCurrent); // returns to the current position
449   }
450   else if (theStream.LastType() == BinTools_ObjectType_Surface)
451   { // read from the stream
452     BinTools_SurfaceSet::ReadSurface (theStream.Stream(), aResult);
453     theStream.UpdatePosition();
454     mySurfacePos.Bind (aPosition, aResult);
455   }
456   return aResult;
457 }
458
459 //=======================================================================
460 //function : ReadPolygon3d
461 //purpose  : 
462 //=======================================================================
463 Handle(Poly_Polygon3D) BinTools_ShapeReader::ReadPolygon3d (BinTools_IStream& theStream)
464 {
465   Handle(Poly_Polygon3D) aResult;
466   uint64_t aPosition = theStream.Position();
467   theStream.ReadType();
468   if (theStream.IsReference())
469   { // get by reference
470     uint64_t aRef = theStream.ReadReference();
471     const Handle(Poly_Polygon3D)* aFound = myPolygon3dPos.Seek (aRef);
472     if (aFound) // the location is already retrieved
473       return *aFound;
474     uint64_t aCurrent = theStream.Position();
475     theStream.GoTo (aRef); // go to the referenced position
476     aResult = ReadPolygon3d (theStream);
477     theStream.GoTo (aCurrent); // returns to the current position
478   }
479   else if (theStream.LastType() == BinTools_ObjectType_Polygon3d)
480   { // read from the stream
481     Standard_Integer aNbNodes = theStream.ReadInteger();
482     Standard_Boolean aHasParameters = theStream.ReadBool();
483     aResult = new Poly_Polygon3D (aNbNodes, aHasParameters);
484     aResult->Deflection (theStream.ReadReal());
485     TColgp_Array1OfPnt& aNodes = aResult->ChangeNodes();
486     for (Standard_Integer aNodeIter = 1; aNodeIter <= aNbNodes; ++aNodeIter)
487       theStream >> aNodes.ChangeValue (aNodeIter);
488     if (aHasParameters)
489     {
490       TColStd_Array1OfReal& aParam = aResult->ChangeParameters();
491       for (Standard_Integer aNodeIter = 1; aNodeIter <= aNbNodes; ++aNodeIter)
492         theStream >> aParam.ChangeValue (aNodeIter);
493     }
494     myPolygon3dPos.Bind (aPosition, aResult);
495   }
496   return aResult;
497 }
498
499 //=======================================================================
500 //function : ReadPolygon
501 //purpose  : 
502 //=======================================================================
503 Handle(Poly_PolygonOnTriangulation) BinTools_ShapeReader::ReadPolygon (BinTools_IStream& theStream)
504 {
505   Handle(Poly_PolygonOnTriangulation) aResult;
506   uint64_t aPosition = theStream.Position();
507   theStream.ReadType();
508   if (theStream.IsReference())
509   { // get by reference
510     uint64_t aRef = theStream.ReadReference();
511     const Handle(Poly_PolygonOnTriangulation)* aFound = myPolygonPos.Seek (aRef);
512     if (aFound) // the location is already retrieved
513       return *aFound;
514     uint64_t aCurrent = theStream.Position();
515     theStream.GoTo (aRef); // go to the referenced position
516     aResult = ReadPolygon (theStream);
517     theStream.GoTo (aCurrent); // returns to the current position
518   }
519   else if (theStream.LastType() == BinTools_ObjectType_PolygonOnTriangulation)
520   { // read from the stream
521     Standard_Integer aNbNodes = theStream.ReadInteger();
522     aResult = new Poly_PolygonOnTriangulation (aNbNodes, Standard_False);
523     for (Standard_Integer aNodeIter = 1; aNodeIter <= aNbNodes; ++aNodeIter)
524       aResult->SetNode(aNodeIter, theStream.ReadInteger());
525     aResult->Deflection (theStream.ReadReal());
526     if (theStream.ReadBool())
527     {
528       Handle(TColStd_HArray1OfReal) aParams = new TColStd_HArray1OfReal (1, aNbNodes);
529       for (Standard_Integer aNodeIter = 1; aNodeIter <= aNbNodes; ++aNodeIter)
530         theStream >> aParams->ChangeValue (aNodeIter);
531       aResult->SetParameters (aParams);
532     }
533     myPolygonPos.Bind (aPosition, aResult);
534   }
535   return aResult;
536 }
537
538 //=======================================================================
539 //function : ReadTriangulation
540 //purpose  : 
541 //=======================================================================
542 Handle(Poly_Triangulation) BinTools_ShapeReader::ReadTriangulation (BinTools_IStream& theStream)
543 {
544   Handle(Poly_Triangulation) aResult;
545   uint64_t aPosition = theStream.Position();
546   const BinTools_ObjectType& aType = theStream.ReadType();
547   if (theStream.IsReference())
548   { // get by reference
549     uint64_t aRef = theStream.ReadReference();
550     const Handle(Poly_Triangulation)* aFound = myTriangulationPos.Seek (aRef);
551     if (aFound) // the location is already retrieved
552       return *aFound;
553     uint64_t aCurrent = theStream.Position();
554     theStream.GoTo (aRef); // go to the referenced position
555     aResult = ReadTriangulation (theStream);
556     theStream.GoTo (aCurrent); // returns to the current position
557   }
558   else if (aType == BinTools_ObjectType_Triangulation)
559   { // read from the stream
560     Standard_Integer aNbNodes = theStream.ReadInteger();
561     Standard_Integer aNbTriangles = theStream.ReadInteger();
562     Standard_Boolean aHasUV = theStream.ReadBool();
563     Standard_Boolean aHasNormals = theStream.ReadBool();
564     aResult = new Poly_Triangulation (aNbNodes, aNbTriangles, aHasUV, aHasNormals);
565     aResult->Deflection (theStream.ReadReal());
566     for (Standard_Integer aNodeIter = 1; aNodeIter <= aNbNodes; ++aNodeIter)
567       aResult->SetNode(aNodeIter, theStream.ReadPnt());
568     if (aHasUV)
569     {
570       gp_Pnt2d anUV;
571       for (Standard_Integer aNodeIter = 1; aNodeIter <= aNbNodes; ++aNodeIter)
572       {
573         theStream >> anUV.ChangeCoord().ChangeCoord (1);
574         theStream >> anUV.ChangeCoord().ChangeCoord (2);
575         aResult->SetUVNode(aNodeIter, anUV);
576       }
577     }
578     // read the triangles
579     Poly_Triangle aTriangle;
580     for (Standard_Integer aTriIter = 1; aTriIter <= aNbTriangles; ++aTriIter)
581     {
582       theStream >> aTriangle.ChangeValue (1);
583       theStream >> aTriangle.ChangeValue (2);
584       theStream >> aTriangle.ChangeValue (3);
585       aResult->SetTriangle(aTriIter, aTriangle);
586     }
587     if (aHasNormals)
588     {
589       gp_Vec3f aNormal;
590       for (Standard_Integer aNormalIter = 1; aNormalIter <= aNbNodes; ++aNormalIter)
591       {
592         theStream >> aNormal.x();
593         theStream >> aNormal.y();
594         theStream >> aNormal.z();
595         aResult->SetNormal (aNormalIter, aNormal);
596       }
597     }
598
599     myTriangulationPos.Bind (aPosition, aResult);
600   }
601   return aResult;
602 }