0031918: Application Framework - New binary format for fast reading part of OCAF...
[occt.git] / src / BinTools / BinTools_ShapeWriter.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_ShapeWriter.hxx>
15 #include <BinTools_LocationSet.hxx>
16
17 #include <TopoDS.hxx>
18 #include <BRep_TEdge.hxx>
19 #include <BRep_GCurve.hxx>
20 #include <BRep_Polygon3D.hxx>
21 #include <BRep_PolygonOnTriangulation.hxx>
22 #include <TopoDS_Iterator.hxx>
23 #include <TopoDS_Vertex.hxx>
24 #include <BRep_Tool.hxx>
25 #include <BRep_TVertex.hxx>
26 #include <BRep_PointRepresentation.hxx>
27 #include <BRep_TFace.hxx>
28 #include <BinTools_CurveSet.hxx>
29 #include <BinTools_Curve2dSet.hxx>
30 #include <BinTools_SurfaceSet.hxx>
31 #include <BinTools_OStream.hxx>
32
33 //=======================================================================
34 //function : BinTools_ShapeWriter
35 //purpose  : 
36 //=======================================================================
37 BinTools_ShapeWriter::BinTools_ShapeWriter()
38   : BinTools_ShapeSetBase()
39 {}
40   
41 //=======================================================================
42 //function : ~BinTools_ShapeWriter
43 //purpose  : 
44 //=======================================================================
45 BinTools_ShapeWriter::~BinTools_ShapeWriter()
46 {}
47
48 //=======================================================================
49 //function : Clear
50 //purpose  : 
51 //=======================================================================
52 void BinTools_ShapeWriter::Clear()
53 {
54   BinTools_ShapeSetBase::Clear();
55   myShapePos.Clear();
56   myLocationPos.Clear();
57   myCurvePos.Clear();
58   myCurve2dPos.Clear();
59   mySurfacePos.Clear();
60   myPolygon3dPos.Clear();
61   myPolygonPos.Clear();
62   myTriangulationPos.Clear();
63 }
64   
65 //=======================================================================
66 //function : Write
67 //purpose  : 
68 //=======================================================================
69 void BinTools_ShapeWriter::Write (const TopoDS_Shape& theShape, Standard_OStream& theStream)
70 {
71   BinTools_OStream anOStream(theStream);
72   WriteShape (anOStream, theShape);
73 }
74
75 //=======================================================================
76 //function : WriteShape
77 //purpose  : 
78 //=======================================================================
79 void BinTools_ShapeWriter::WriteShape (BinTools_OStream& theStream, const TopoDS_Shape& theShape)
80 {
81   if (theShape.IsNull())
82   {
83     theStream << BinTools_ObjectType_EmptyShape;
84     return;
85   }
86   TopoDS_Shape aShape = theShape.Located (TopLoc_Location());
87   const uint64_t* anExisting = myShapePos.Seek (aShape);
88   if (anExisting) // shape is already there, so, write reference to it
89   {
90     theStream.WriteReference(*anExisting);
91     WriteLocation (theStream, theShape.Location());
92     theStream << Standard_Byte (theShape.Orientation ());
93     return;
94   }
95   uint64_t aNewPos = theStream.Position();
96   myShapePos.Bind (aShape, aNewPos);
97   theStream.WriteShape (aShape.ShapeType(), aShape.Orientation());
98   WriteLocation (theStream, theShape.Location());
99
100   try {
101     OCC_CATCH_SIGNALS
102     switch (aShape.ShapeType())
103     {
104     case TopAbs_VERTEX:
105     {
106       TopoDS_Vertex aV = TopoDS::Vertex (aShape);
107       theStream << BRep_Tool::Tolerance (aV);
108       gp_Pnt aP = BRep_Tool::Pnt (aV);
109       theStream << aP;
110       Handle(BRep_TVertex) aTV = Handle(BRep_TVertex)::DownCast (aShape.TShape());
111       for(BRep_ListIteratorOfListOfPointRepresentation anIter (aTV->Points()); anIter.More(); anIter.Next())
112       {
113         const Handle(BRep_PointRepresentation)& aPR = anIter.Value();
114         if (aPR->IsPointOnCurve())
115         {
116           theStream << (Standard_Byte)1; // 1
117           theStream << aPR->Parameter();
118           WriteCurve (theStream, aPR->Curve());
119         }
120         else if (aPR->IsPointOnCurveOnSurface())
121         {
122           theStream << (Standard_Byte)2;// 2
123           theStream << aPR->Parameter();
124           WriteCurve (theStream, aPR->PCurve());
125           WriteSurface (theStream, aPR->Surface());
126         }
127         else if (aPR->IsPointOnSurface())
128         {
129           theStream << (Standard_Byte)3;// 3
130           theStream << aPR->Parameter2() << aPR->Parameter();
131           WriteSurface (theStream, aPR->Surface());
132         }
133         WriteLocation (theStream, aPR->Location());
134       }
135       theStream << (Standard_Byte)0;
136     }
137     break;
138     case TopAbs_EDGE:
139     {
140       Handle(BRep_TEdge) aTE = Handle(BRep_TEdge)::DownCast (aShape.TShape());
141       theStream << aTE->Tolerance();
142       theStream.PutBools (aTE->SameParameter(), aTE->SameRange(), aTE->Degenerated());
143       Standard_Real aFirst, aLast;
144       for(BRep_ListIteratorOfListOfCurveRepresentation anIter = aTE->Curves(); anIter.More(); anIter.Next())
145       {
146         const Handle(BRep_CurveRepresentation)& aCR = anIter.Value();
147         if (aCR->IsCurve3D())
148         {
149           if (!aCR->Curve3D().IsNull())
150           {
151             Handle(BRep_GCurve) aGC = Handle(BRep_GCurve)::DownCast (aCR);
152             aGC->Range (aFirst, aLast);
153             theStream << (Standard_Byte)1; // -1- CURVE_3D;
154             WriteCurve (theStream, aCR->Curve3D());
155             WriteLocation (theStream, aCR->Location());
156             theStream << aFirst << aLast;
157           }
158         }
159         else if (aCR->IsCurveOnSurface()) {
160           Handle(BRep_GCurve) GC = Handle(BRep_GCurve)::DownCast (aCR);
161           GC->Range (aFirst, aLast);
162           if (!aCR->IsCurveOnClosedSurface())
163             theStream << (Standard_Byte)2; // -2- Curve on surf
164           else
165             theStream << (Standard_Byte)3; // -3- Curve on closed surf
166           WriteCurve (theStream, aCR->PCurve());
167
168           if (aCR->IsCurveOnClosedSurface()) { //+ int|char
169             WriteCurve (theStream, aCR->PCurve2());
170             theStream << (Standard_Byte)aCR->Continuity();
171           }
172           WriteSurface (theStream, aCR->Surface());
173           WriteLocation (theStream, aCR->Location());
174           theStream << aFirst << aLast;
175         }
176         else if (aCR->IsRegularity())
177         {
178           theStream << (Standard_Byte)4; // -4- Regularity
179           theStream << (Standard_Byte)aCR->Continuity();
180           WriteSurface (theStream, aCR->Surface());
181           WriteLocation (theStream, aCR->Location());
182           WriteSurface (theStream, aCR->Surface2());
183           WriteLocation (theStream, aCR->Location2());
184         }
185         else if (IsWithTriangles())
186         {
187           if (aCR->IsPolygon3D())
188           {
189             Handle(BRep_Polygon3D) aGC = Handle(BRep_Polygon3D)::DownCast (aCR);
190             if (!aGC->Polygon3D().IsNull())
191             {
192               theStream << (Standard_Byte)5; // -5- Polygon3D
193               WritePolygon (theStream, aCR->Polygon3D());
194               WriteLocation (theStream, aCR->Location());
195             }
196           }
197           else if (aCR->IsPolygonOnTriangulation())
198           {
199             Handle(BRep_PolygonOnTriangulation) aPT = Handle(BRep_PolygonOnTriangulation)::DownCast (aCR);
200             if (!aCR->IsPolygonOnClosedTriangulation())
201               theStream << (Standard_Byte)6; // -6- Polygon on triangulation
202             else
203               theStream << (Standard_Byte)7; // -7- Polygon on closed triangulation
204             WritePolygon (theStream, aPT->PolygonOnTriangulation());
205
206             if (aCR->IsPolygonOnClosedTriangulation())
207               WritePolygon (theStream, aPT->PolygonOnTriangulation2());
208             // edge triangulation does not need normals
209             WriteTriangulation (theStream, aPT->Triangulation(), Standard_False);
210             WriteLocation (theStream, aCR->Location());
211           }
212         }
213       }
214       theStream << (Standard_Byte)0;
215     }
216     break;
217     case TopAbs_FACE:
218     {
219
220       Handle(BRep_TFace) aTF = Handle(BRep_TFace)::DownCast (aShape.TShape());
221       const TopoDS_Face& aF = TopoDS::Face (aShape);
222
223       // Write the surface geometry
224       theStream << BRep_Tool::NaturalRestriction (aF) << aTF->Tolerance();
225       WriteSurface (theStream, aTF->Surface());
226       WriteLocation (theStream, aTF->Location());
227
228       if (IsWithTriangles() || aTF->Surface().IsNull())
229       {
230         if (!(aTF->Triangulation()).IsNull())
231         {
232           theStream << (Standard_Byte)2;
233           WriteTriangulation (theStream, aTF->Triangulation(),
234             aTF->Triangulation()->HasNormals() && (IsWithNormals() || aTF->Surface().IsNull()));
235         }
236         else
237           theStream << (Standard_Byte)1;
238       }
239       else
240         theStream << (Standard_Byte)0; //without triangulation
241     }
242     break;
243     default:
244     {}
245   }
246   }
247   catch (Standard_Failure const& anException)
248   {
249     Standard_SStream aMsg;
250     aMsg << "EXCEPTION in BinTools_ShapeWriter::WriteShape" << std::endl;
251     aMsg << anException << std::endl;
252     throw Standard_Failure(aMsg.str().c_str());
253   }
254   theStream.PutBools (aShape.Free(), aShape.Modified(), aShape.Checked(),
255     aShape.Orientable(), aShape.Closed(), aShape.Infinite(), aShape.Convex());
256   // process sub-shapes
257   for (TopoDS_Iterator aSub (aShape, Standard_False, Standard_False); aSub.More(); aSub.Next())
258     WriteShape (theStream, aSub.Value());
259
260   theStream << BinTools_ObjectType_EndShape;
261 }
262
263 //=======================================================================
264 //function : WriteLocation
265 //purpose  : 
266 //=======================================================================
267 void BinTools_ShapeWriter::WriteLocation (BinTools_OStream& theStream, const TopLoc_Location& theLocation)
268 {
269   if (theLocation.IsIdentity())
270   {
271     theStream << BinTools_ObjectType_EmptyLocation;
272     return;
273   }
274   const uint64_t* aLoc = myLocationPos.Seek (theLocation);
275   if (aLoc)
276   {
277     theStream.WriteReference (*aLoc);
278     return;
279   }
280   uint64_t aNewLoc = theStream.Position();
281   try
282   {
283     OCC_CATCH_SIGNALS
284     TopLoc_Location aL2 = theLocation.NextLocation();
285     Standard_Boolean isSimple = aL2.IsIdentity();
286     Standard_Integer aPower = theLocation.FirstPower();
287     TopLoc_Location aL1 = theLocation.FirstDatum();
288     Standard_Boolean elementary = (isSimple && aPower == 1);
289     if (elementary)
290     {
291       theStream << BinTools_ObjectType_SimpleLocation << theLocation.Transformation();
292     }
293     else
294     {
295       theStream << BinTools_ObjectType_Location;
296       WriteLocation (theStream, aL1);
297       theStream << aPower;
298       while (!aL2.IsIdentity()) {
299         aL1 = aL2.FirstDatum();
300         aPower = aL2.FirstPower();
301         aL2 = aL2.NextLocation();
302         WriteLocation (theStream, aL1);
303         theStream << aPower;
304       }
305       theStream << BinTools_ObjectType_LocationEnd;
306     }
307     myLocationPos.Bind (theLocation, aNewLoc);
308   }
309   catch (Standard_Failure const& anException) {
310     Standard_SStream aMsg;
311     aMsg << "EXCEPTION in BinTools_ShapeWriter::WriteLocation" << std::endl;
312     aMsg << anException << std::endl;
313     throw Standard_Failure (aMsg.str().c_str());
314   }
315 }
316
317 //=======================================================================
318 //function : WriteCurve
319 //purpose  : 
320 //=======================================================================
321 void BinTools_ShapeWriter::WriteCurve (BinTools_OStream& theStream, const Handle(Geom_Curve)& theCurve)
322 {
323   if (theCurve.IsNull())
324   {
325     theStream << BinTools_ObjectType_EmptyCurve;
326     return;
327   }
328   const uint64_t* aCurve = myCurvePos.Seek (theCurve);
329   if (aCurve)
330   {
331     theStream.WriteReference (*aCurve);
332     return;
333   }
334   myCurvePos.Bind (theCurve, theStream.Position());
335   theStream << BinTools_ObjectType_Curve;
336   BinTools_CurveSet::WriteCurve (theCurve, theStream);
337 }
338
339 //=======================================================================
340 //function : WriteCurve
341 //purpose  : 
342 //=======================================================================
343 void BinTools_ShapeWriter::WriteCurve (BinTools_OStream& theStream, const Handle(Geom2d_Curve)& theCurve)
344 {
345   if (theCurve.IsNull())
346   {
347     theStream << BinTools_ObjectType_EmptyCurve2d;
348     return;
349   }
350   const uint64_t* aCurve = myCurve2dPos.Seek (theCurve);
351   if (aCurve)
352   {
353     theStream.WriteReference (*aCurve);
354     return;
355   }
356   myCurve2dPos.Bind (theCurve, theStream.Position());
357   theStream << BinTools_ObjectType_Curve2d;
358   BinTools_Curve2dSet::WriteCurve2d (theCurve, theStream);
359 }
360
361 //=======================================================================
362 //function : WriteSurface
363 //purpose  : 
364 //=======================================================================
365 void BinTools_ShapeWriter::WriteSurface (BinTools_OStream& theStream, const Handle(Geom_Surface)& theSurface)
366 {
367   if (theSurface.IsNull())
368   {
369     theStream << BinTools_ObjectType_EmptySurface;
370     return;
371   }
372   const uint64_t* aSurface = mySurfacePos.Seek (theSurface);
373   if (aSurface)
374   {
375     theStream.WriteReference (*aSurface);
376     return;
377   }
378   mySurfacePos.Bind (theSurface, theStream.Position());
379   theStream << BinTools_ObjectType_Surface;
380   BinTools_SurfaceSet::WriteSurface (theSurface, theStream);
381 }
382
383 //=======================================================================
384 //function : WritePolygon
385 //purpose  : 
386 //=======================================================================
387 void BinTools_ShapeWriter::WritePolygon (BinTools_OStream& theStream, const Handle(Poly_Polygon3D)& thePolygon)
388 {
389   if (thePolygon.IsNull())
390   {
391     theStream << BinTools_ObjectType_EmptyPolygon3d;
392     return;
393   }
394   const uint64_t* aPolygon = myPolygon3dPos.Seek (thePolygon);
395   if (aPolygon)
396   {
397     theStream.WriteReference (*aPolygon);
398     return;
399   }
400   myPolygon3dPos.Bind (thePolygon, theStream.Position());
401   theStream << BinTools_ObjectType_Polygon3d;
402
403   const Standard_Integer aNbNodes = thePolygon->NbNodes();
404   theStream << aNbNodes << thePolygon->HasParameters() << thePolygon->Deflection();
405   const TColgp_Array1OfPnt& aNodes = thePolygon->Nodes();
406   for (Standard_Integer aNodeIter = 1; aNodeIter <= aNbNodes; ++aNodeIter)
407     theStream << aNodes.Value (aNodeIter);
408   if (thePolygon->HasParameters())
409   {
410     const TColStd_Array1OfReal& aParam = thePolygon->Parameters();
411     for (Standard_Integer aNodeIter = 1; aNodeIter <= aNbNodes; ++aNodeIter)
412       theStream << aParam.Value (aNodeIter);
413   }
414 }
415
416 //=======================================================================
417 //function : WritePolygon
418 //purpose  : 
419 //=======================================================================
420 void BinTools_ShapeWriter::WritePolygon (BinTools_OStream& theStream,
421                                          const Handle(Poly_PolygonOnTriangulation)& thePolygon)
422 {
423   if (thePolygon.IsNull())
424   {
425     theStream << BinTools_ObjectType_EmptyPolygonOnTriangulation;
426     return;
427   }
428   const uint64_t* aPolygon = myPolygonPos.Seek (thePolygon);
429   if (aPolygon)
430   {
431     theStream.WriteReference (*aPolygon);
432     return;
433   }
434   myPolygonPos.Bind (thePolygon, theStream.Position());
435   theStream << BinTools_ObjectType_PolygonOnTriangulation;
436
437   const TColStd_Array1OfInteger& aNodes = thePolygon->Nodes();
438   theStream << aNodes.Length();
439   for (Standard_Integer aNodeIter = 1; aNodeIter <= aNodes.Length(); ++aNodeIter)
440     theStream << aNodes.Value(aNodeIter);
441   theStream << thePolygon->Deflection();
442   if (const Handle(TColStd_HArray1OfReal)& aParam = thePolygon->Parameters())
443   {
444     theStream << Standard_True;
445     for (Standard_Integer aNodeIter = 1; aNodeIter <= aParam->Length(); ++aNodeIter)
446       theStream << aParam->Value(aNodeIter);
447   }
448   else
449     theStream << Standard_False;
450 }
451
452 void BinTools_ShapeWriter::WriteTriangulation (BinTools_OStream& theStream,
453                                                const Handle(Poly_Triangulation)& theTriangulation,
454                                                const Standard_Boolean theNeedToWriteNormals)
455 {
456   if (theTriangulation.IsNull())
457   {
458     theStream << BinTools_ObjectType_EmptyTriangulation;
459     return;
460   }
461   const uint64_t* aTriangulation = myTriangulationPos.Seek (theTriangulation);
462   if (aTriangulation)
463   {
464     theStream.WriteReference (*aTriangulation);
465     return;
466   }
467   myTriangulationPos.Bind (theTriangulation, theStream.Position());
468   theStream << BinTools_ObjectType_Triangulation;
469
470   const Standard_Integer aNbNodes = theTriangulation->NbNodes();
471   const Standard_Integer aNbTriangles = theTriangulation->NbTriangles();
472   theStream << aNbNodes << aNbTriangles << theTriangulation->HasUVNodes();
473   theStream << theNeedToWriteNormals << theTriangulation->Deflection();
474   // write the 3d nodes
475   for (Standard_Integer aNodeIter = 1; aNodeIter <= aNbNodes; ++aNodeIter)
476     theStream << theTriangulation->Node (aNodeIter);
477   //theStream.write ((char*)(theTriangulation->InternalNodes().value(0)) , sizeof (gp_Pnt) * aNbNodes);  
478
479   if (theTriangulation->HasUVNodes())
480   {
481     for (Standard_Integer aNodeIter = 1; aNodeIter <= aNbNodes; ++aNodeIter)
482       theStream << theTriangulation->UVNode (aNodeIter);
483   }
484   for (Standard_Integer aTriIter = 1; aTriIter <= aNbTriangles; ++aTriIter)
485     theStream << theTriangulation->Triangle (aTriIter);
486
487   if (theNeedToWriteNormals)
488   {
489     gp_Vec3f aNormal;
490     for (Standard_Integer aNormalIter = 1; aNormalIter <= aNbNodes; ++aNormalIter)
491     {
492       theTriangulation->Normal (aNormalIter, aNormal);
493       theStream << aNormal;
494     }
495   }
496 }