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