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