0024675: Crash reading a VRML file
[occt.git] / src / VrmlData / VrmlData_IndexedFaceSet.cxx
1 // Created on: 2006-11-04
2 // Created by: Alexander GRIGORIEV
3 // Copyright (c) 2006-2014 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 <VrmlData_IndexedFaceSet.hxx>
17 #include <VrmlData_InBuffer.hxx>
18 #include <VrmlData_UnknownNode.hxx>
19 #include <Poly_Triangulation.hxx>
20 #include <BRep_TFace.hxx>
21 #include <VrmlData_Coordinate.hxx>
22 #include <VrmlData_Color.hxx>
23 #include <VrmlData_Normal.hxx>
24 #include <VrmlData_TextureCoordinate.hxx>
25 #include <VrmlData_Scene.hxx>
26 #include <Precision.hxx>
27 #include <NCollection_Vector.hxx>
28 #include <NCollection_DataMap.hxx>
29 #include <Poly.hxx>
30 #include <TShort_HArray1OfShortReal.hxx>
31
32 #ifdef WNT
33 #define _CRT_SECURE_NO_DEPRECATE
34 #pragma warning (disable:4996)
35 #endif
36
37 IMPLEMENT_STANDARD_HANDLE  (VrmlData_Faceted, VrmlData_Geometry)
38 IMPLEMENT_STANDARD_RTTIEXT (VrmlData_Faceted, VrmlData_Geometry)
39 IMPLEMENT_STANDARD_HANDLE  (VrmlData_IndexedFaceSet, VrmlData_Faceted)
40 IMPLEMENT_STANDARD_RTTIEXT (VrmlData_IndexedFaceSet, VrmlData_Faceted)
41
42 //=======================================================================
43 //function : readData
44 //purpose  : 
45 //=======================================================================
46
47 VrmlData_ErrorStatus VrmlData_Faceted::readData (VrmlData_InBuffer& theBuffer)
48 {
49   VrmlData_ErrorStatus aStatus (VrmlData_EmptyData);
50   Standard_Boolean aBool;
51   if        (VRMLDATA_LCOMPARE (theBuffer.LinePtr, "ccw")) {
52     if (OK(aStatus, ReadBoolean (theBuffer, aBool)))
53       myIsCCW = aBool;
54   } else if (VRMLDATA_LCOMPARE (theBuffer.LinePtr, "convex")) {
55     if (OK(aStatus, ReadBoolean (theBuffer, aBool)))
56       myIsConvex = aBool;
57   } else if (VRMLDATA_LCOMPARE (theBuffer.LinePtr, "solid")) {
58     if (OK(aStatus, ReadBoolean (theBuffer, aBool)))
59       myIsSolid = aBool;
60   } else if (VRMLDATA_LCOMPARE (theBuffer.LinePtr, "creaseAngle")) {
61     Standard_Real anAngle;
62     if (OK(aStatus, Scene().ReadReal (theBuffer, anAngle,
63                                       Standard_False, Standard_False))) {
64       if (anAngle < -Precision::Confusion()*0.001)
65         aStatus = VrmlData_IrrelevantNumber;
66       else
67         myCreaseAngle = anAngle;
68     }
69   }
70   return aStatus;
71 }
72
73 //=======================================================================
74 //function : VrmlData_IndexedFaceSet::TShape
75 //purpose  : 
76 //=======================================================================
77
78 const Handle(TopoDS_TShape)& VrmlData_IndexedFaceSet::TShape ()
79 {
80   if (myNbPolygons == 0)
81     myTShape.Nullify();
82   else if (myIsModified) {
83     // Create an empty topological Face
84     const gp_XYZ * arrNodes = myCoords->Values();
85     Standard_Integer i, nTri(0);
86
87     NCollection_DataMap <int, int> mapNodeId;
88
89     // Count non-degenerated triangles
90     const int nNodes = (int)myCoords->Length();
91     for (i = 0; i < (int)myNbPolygons; i++) {
92       const Standard_Integer * arrIndice;
93       if (Polygon(i, arrIndice) == 3) {
94         //Check indices for out of bound
95         if (arrIndice[0] < 0 ||
96             arrIndice[0] >= nNodes ||
97             arrIndice[1] >= nNodes ||
98             arrIndice[2] >= nNodes)
99         {
100             continue;
101         }
102         const gp_XYZ aVec[2] = {
103           arrNodes[arrIndice[1]] - arrNodes[arrIndice[0]],
104           arrNodes[arrIndice[2]] - arrNodes[arrIndice[0]]
105         };
106         if ((aVec[0] ^ aVec[1]).SquareModulus() >
107             Precision::SquareConfusion())
108           ++nTri;
109         else {
110           const_cast<Standard_Integer&> (arrIndice[0]) = -1;
111           continue;
112         }
113       }
114       if (mapNodeId.IsBound (arrIndice[0]) == Standard_False)
115         mapNodeId.Bind (arrIndice[0], 0);
116       if (mapNodeId.IsBound (arrIndice[1]) == Standard_False)
117         mapNodeId.Bind (arrIndice[1], 0);
118       if (mapNodeId.IsBound (arrIndice[2]) == Standard_False)
119         mapNodeId.Bind (arrIndice[2], 0);
120     }
121     const Standard_Integer nbNodes (mapNodeId.Extent());
122     if (!nbNodes)
123     {
124         myIsModified = Standard_False;
125         myTShape.Nullify();
126         return myTShape;
127     }
128
129     Handle(Poly_Triangulation) aTriangulation =
130       new Poly_Triangulation (nbNodes, nTri, Standard_False);
131     Handle(BRep_TFace) aFace = new BRep_TFace();
132     aFace->Triangulation (aTriangulation);
133     myTShape = aFace;
134
135     // Copy the triangulation vertices
136     TColgp_Array1OfPnt& aNodes = aTriangulation->ChangeNodes();
137     NCollection_DataMap <int, int>::Iterator anIterN(mapNodeId);
138     for (i = 1; anIterN.More(); anIterN.Next()) {
139       const int aKey = anIterN.Key();
140       const gp_XYZ& aNodePnt = arrNodes[aKey];
141       aNodes(i) = gp_Pnt (aNodePnt);
142       anIterN.ChangeValue() = i++;
143     }
144
145     // Copy the triangles. Only the triangle-type polygons are supported.
146     // In this loop we also get rid of any possible degenerated triangles.
147     Poly_Array1OfTriangle& aTriangles = aTriangulation->ChangeTriangles();
148     nTri = 0;
149     for (i = 0; i < (int)myNbPolygons; i++) {
150       const Standard_Integer * arrIndice;
151       if (Polygon (i, arrIndice) == 3)
152         if (arrIndice[0] >= 0 &&
153             arrIndice[0] < nNodes &&
154             arrIndice[1] < nNodes &&
155             arrIndice[2] < nNodes)  // check to avoid previously skipped faces
156           aTriangles(++nTri).Set (mapNodeId(arrIndice[0]),
157                                   mapNodeId(arrIndice[1]),
158                                   mapNodeId(arrIndice[2]));
159     }
160
161     // Normals should be defined; if they are not, compute them
162     if (myNormals.IsNull ()) {
163       //aTriangulation->ComputeNormals();
164       Poly::ComputeNormals(aTriangulation);
165     }
166     else {
167       // Copy the normals. Currently only normals-per-vertex are supported.
168       Handle(TShort_HArray1OfShortReal) Normals =
169         new TShort_HArray1OfShortReal (1, 3*nbNodes);
170       if (myNormalPerVertex) {
171         if (myArrNormalInd == 0L) {
172           NCollection_DataMap <int, int>::Iterator anIterNN (mapNodeId);
173           for (; anIterNN.More (); anIterNN.Next ()) {
174             Standard_Integer anIdx = (anIterNN.Value() - 1) * 3 + 1;
175             const gp_XYZ& aNormal = myNormals->Normal (anIterNN.Key ());
176             Normals->SetValue (anIdx + 0, Standard_ShortReal (aNormal.X ()));
177             Normals->SetValue (anIdx + 1, Standard_ShortReal (aNormal.Y ()));
178             Normals->SetValue (anIdx + 2, Standard_ShortReal (aNormal.Z ()));
179           }
180         }
181         else
182         {
183           for (i = 0; i < (int)myNbPolygons; i++) 
184           {
185             const Standard_Integer * arrNodes;
186             if (Polygon(i, arrNodes) == 3 && 
187                 arrNodes[0] >= 0 &&
188                 arrNodes[0] < nNodes &&
189                 arrNodes[1] < nNodes &&
190                 arrNodes[2] < nNodes)  // check to avoid previously skipped faces
191             {
192               const Standard_Integer * arrIndice;
193               if (IndiceNormals(i, arrIndice) == 3) {
194                 for (Standard_Integer j = 0; j < 3; j++) {
195                   const gp_XYZ& aNormal = myNormals->Normal (arrIndice[j]);
196                   Standard_Integer anInd = (mapNodeId(arrNodes[j]) - 1) * 3 + 1;
197                   Normals->SetValue (anInd + 0, Standard_ShortReal (aNormal.X()));
198                   Normals->SetValue (anInd + 1, Standard_ShortReal (aNormal.Y()));
199                   Normals->SetValue (anInd + 2, Standard_ShortReal (aNormal.Z()));
200                 }
201               }
202             }
203           }
204         }
205       } else {
206         //TODO ..
207       }
208       aTriangulation->SetNormals(Normals);
209     }
210
211     myIsModified = Standard_False;
212   }
213   return myTShape;
214 }
215
216 //=======================================================================
217 //function : VrmlData_IndexedFaceSet::Clone
218 //purpose  : 
219 //=======================================================================
220
221 Handle(VrmlData_Node) VrmlData_IndexedFaceSet::Clone
222                                 (const Handle(VrmlData_Node)& theOther) const
223 {
224   Handle(VrmlData_IndexedFaceSet) aResult =
225     Handle(VrmlData_IndexedFaceSet)::DownCast (VrmlData_Node::Clone(theOther));
226   if (aResult.IsNull())
227     aResult =
228       new VrmlData_IndexedFaceSet(theOther.IsNull()? Scene(): theOther->Scene(),
229                                   Name());
230
231   if (&aResult->Scene() == &Scene()) {
232     aResult->SetCoordinates     (myCoords);
233     aResult->SetNormals         (myNormals);
234     aResult->SetColors          (myColors);
235     aResult->SetPolygons        (myNbPolygons, myArrPolygons);
236     aResult->SetNormalInd       (myNbNormals, myArrNormalInd);
237     aResult->SetColorInd        (myNbColors, myArrColorInd);
238     aResult->SetTextureCoordInd (myNbTextures, myArrTextureInd);
239   } else {
240     // Create a dummy node to pass the different Scene instance to methods Clone
241     const Handle(VrmlData_UnknownNode) aDummyNode =
242       new VrmlData_UnknownNode (aResult->Scene());
243     if (myCoords.IsNull() == Standard_False)
244       aResult->SetCoordinates (Handle(VrmlData_Coordinate)::DownCast
245                                (myCoords->Clone (aDummyNode)));
246     if (myNormals.IsNull() == Standard_False)
247       aResult->SetNormals (Handle(VrmlData_Normal)::DownCast
248                            (myNormals->Clone (aDummyNode)));
249     if (myColors.IsNull() == Standard_False)
250       aResult->SetColors (Handle(VrmlData_Color)::DownCast
251                           (myColors->Clone (aDummyNode)));
252     //TODO: Replace the following lines with the relevant copying
253     aResult->SetPolygons        (myNbPolygons, myArrPolygons);
254     aResult->SetNormalInd       (myNbNormals, myArrNormalInd);
255     aResult->SetColorInd        (myNbColors, myArrColorInd);
256     aResult->SetTextureCoordInd (myNbTextures, myArrTextureInd);
257   }
258   aResult->SetNormalPerVertex (myNormalPerVertex);
259   aResult->SetColorPerVertex  (myColorPerVertex);
260   return aResult;
261 }
262
263 //=======================================================================
264 //function : VrmlData_IndexedFaceSet::Read
265 //purpose  : 
266 //=======================================================================
267
268 VrmlData_ErrorStatus VrmlData_IndexedFaceSet::Read(VrmlData_InBuffer& theBuffer)
269 {
270   VrmlData_ErrorStatus aStatus;
271   const VrmlData_Scene& aScene = Scene();
272   while (OK(aStatus, VrmlData_Scene::ReadLine(theBuffer)))
273   {
274     if (OK(aStatus, VrmlData_Faceted::readData (theBuffer)))
275       continue;
276     if (aStatus != VrmlData_EmptyData)
277       break;
278     else if (VRMLDATA_LCOMPARE (theBuffer.LinePtr, "colorPerVertex"))
279       aStatus = ReadBoolean (theBuffer, myColorPerVertex);
280     else if (VRMLDATA_LCOMPARE (theBuffer.LinePtr, "normalPerVertex"))
281       aStatus = ReadBoolean (theBuffer, myNormalPerVertex);
282     else if (VRMLDATA_LCOMPARE (theBuffer.LinePtr, "coordIndex"))
283       aStatus = aScene.ReadArrIndex (theBuffer, myArrPolygons, myNbPolygons);
284     else if (VRMLDATA_LCOMPARE (theBuffer.LinePtr, "colorIndex"))
285       aStatus = aScene.ReadArrIndex (theBuffer, myArrColorInd, myNbColors);
286     else if (VRMLDATA_LCOMPARE (theBuffer.LinePtr, "normalIndex"))
287       aStatus = aScene.ReadArrIndex (theBuffer, myArrNormalInd, myNbNormals);
288     else if (VRMLDATA_LCOMPARE (theBuffer.LinePtr, "texCoordIndex"))
289       aStatus = aScene.ReadArrIndex (theBuffer, myArrTextureInd, myNbTextures);
290     // These four checks should be the last one to avoid their interference
291     // with the other tokens (e.g., coordIndex)
292     else if (VRMLDATA_LCOMPARE (theBuffer.LinePtr, "texCoord"))
293       aStatus = ReadNode (theBuffer, myTxCoords,
294                           STANDARD_TYPE(VrmlData_TextureCoordinate));
295     else if (VRMLDATA_LCOMPARE (theBuffer.LinePtr, "color"))
296       aStatus = ReadNode (theBuffer, myColors,
297                           STANDARD_TYPE(VrmlData_Color));
298     else if (VRMLDATA_LCOMPARE (theBuffer.LinePtr, "coord"))
299       aStatus = ReadNode (theBuffer, myCoords,
300                           STANDARD_TYPE(VrmlData_Coordinate));
301     else if (VRMLDATA_LCOMPARE (theBuffer.LinePtr, "normal"))
302       aStatus = ReadNode (theBuffer, myNormals,
303                           STANDARD_TYPE(VrmlData_Normal));
304     if (!OK(aStatus))
305       break;
306   }
307   // Read the terminating (closing) brace
308   if (OK(aStatus) || aStatus == VrmlData_EmptyData)
309     if (OK(aStatus, readBrace (theBuffer))) {
310       // Post-processing
311       ;
312     }
313   return aStatus;
314 }
315
316 // //=======================================================================
317 // //function : dummyReadBrackets
318 // //purpose  : static (local) function
319 // //=======================================================================
320
321 // VrmlData_ErrorStatus dummyReadBrackets (VrmlData_InBuffer& theBuffer)
322 // {
323 //   VrmlData_ErrorStatus aStatus;
324 //   Standard_Integer aLevelCounter (0);
325 //   // This loop searches for any opening bracket.
326 //   // Such bracket increments the level counter. A closing bracket decrements
327 //   // the counter. The loop terminates when the counter becomes zero.
328 //   while ((aStatus = VrmlData_Scene::ReadLine(theBuffer)) == VrmlData_StatusOK)
329 //   {
330 //     int aChar;
331 //     while ((aChar = theBuffer.LinePtr[0]) != '\0') {
332 //       theBuffer.LinePtr++;
333 //       if        (aChar == '[') {
334 //         aLevelCounter++;
335 //         break;
336 //       } else if (aChar == ']') {
337 //         aLevelCounter--;
338 //         break;
339 //       }
340 //     }
341 //     if (aLevelCounter <= 0)
342 //       break;
343 //   }
344 //   return aStatus;
345 // }
346
347 //=======================================================================
348 //function : IsDefault
349 //purpose  : 
350 //=======================================================================
351
352 Standard_Boolean VrmlData_IndexedFaceSet::IsDefault () const
353 {
354   Standard_Boolean aResult (Standard_True);
355   if (myNbPolygons)
356     aResult = Standard_False;
357   else if (myCoords.IsNull() == Standard_False)
358     aResult = myCoords->IsDefault();
359   return aResult;
360 }
361
362 //=======================================================================
363 //function : Write
364 //purpose  : 
365 //=======================================================================
366
367 VrmlData_ErrorStatus VrmlData_IndexedFaceSet::Write
368                                                 (const char * thePrefix) const
369 {
370   static char header[] = "IndexedFaceSet {";
371   const VrmlData_Scene& aScene = Scene();
372   VrmlData_ErrorStatus aStatus;
373   if (OK (aStatus, aScene.WriteLine (thePrefix, header, GlobalIndent()))) {
374
375     // Write the attributes of interface "VrmlData_Faceted"
376     if (IsCCW() == Standard_False)
377       aStatus = aScene.WriteLine ("ccw         FALSE");
378     if (OK(aStatus) && IsSolid() == Standard_False)
379       aStatus = aScene.WriteLine ("solid       FALSE");
380     if (OK(aStatus) && IsConvex() == Standard_False)
381       aStatus = aScene.WriteLine ("convex      FALSE");
382     if (OK(aStatus) && CreaseAngle() > Precision::Confusion()) {
383       char buf[64];
384       Sprintf (buf, "%.9g", CreaseAngle());
385       aStatus = aScene.WriteLine ("creaseAngle", buf);
386     }
387
388     if (OK(aStatus) && myCoords.IsNull() == Standard_False)
389       aStatus = aScene.WriteNode ("coord", myCoords);
390     if (OK(aStatus))
391       aStatus = aScene.WriteArrIndex ("coordIndex", myArrPolygons,myNbPolygons);
392
393     if (OK(aStatus) && myNormalPerVertex == Standard_False)
394       aStatus = aScene.WriteLine ("normalPerVertex FALSE");
395     if (OK(aStatus) && myNormals.IsNull() == Standard_False)
396       aStatus = aScene.WriteNode ("normal", myNormals);
397     if (OK(aStatus))
398       aStatus = aScene.WriteArrIndex ("normalIndex",myArrNormalInd,myNbNormals);
399
400     if (OK(aStatus) && myColorPerVertex == Standard_False)
401       aStatus = aScene.WriteLine ("colorPerVertex  FALSE");
402     if (OK(aStatus) && myColors.IsNull() == Standard_False)
403       aStatus = aScene.WriteNode ("color", myColors);
404     if (OK(aStatus))
405       aStatus = aScene.WriteArrIndex ("colorIndex", myArrColorInd, myNbColors);
406
407     if (OK(aStatus) && myTxCoords.IsNull() == Standard_False)
408       aStatus = aScene.WriteNode ("texCoord", myTxCoords);
409     if (OK(aStatus))
410       aStatus = aScene.WriteArrIndex ("texCoordIndex", myArrTextureInd,
411                                       myNbTextures);
412
413     aStatus = WriteClosing();
414   }
415   return aStatus;
416 }
417
418 //=======================================================================
419 //function : GetColor
420 //purpose  : 
421 //=======================================================================
422
423 Quantity_Color VrmlData_IndexedFaceSet::GetColor
424                                         (const Standard_Integer /*iFace*/,
425                                          const Standard_Integer /*iVertex*/)
426 {
427   //TODO
428   return Quantity_NOC_BLACK;
429 }
430