0029597: Data Exchange - unable to read VRML2 file
[occt.git] / src / VrmlData / VrmlData_Group.cxx
1 // Created on: 2006-11-06
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_Group.hxx>
17 #include <VrmlData_Geometry.hxx>
18 #include <VrmlData_Scene.hxx>
19 #include <VrmlData_WorldInfo.hxx>
20 #include <VrmlData_InBuffer.hxx>
21 #include <VrmlData_ListOfNode.hxx>
22 #include <VrmlData_UnknownNode.hxx>
23 #include <Precision.hxx>
24 #include <gp_Ax1.hxx>
25
26 IMPLEMENT_STANDARD_RTTIEXT(VrmlData_Group,VrmlData_Node)
27
28 #ifdef _MSC_VER
29 #define _CRT_SECURE_NO_DEPRECATE
30 #pragma warning (disable:4996)
31 #endif
32
33
34 //=======================================================================
35 //function : VrmlData_Group
36 //purpose  : Constructor
37 //=======================================================================
38
39 VrmlData_Group::VrmlData_Group (const VrmlData_Scene&   theScene,
40                                 const char              * theName,
41                                 const Standard_Boolean  isTransform)
42   : VrmlData_Node     (theScene, theName),
43     myIsTransform     (isTransform),
44     myNodes           (theScene.Allocator())
45 {}
46
47 //=======================================================================
48 //function : RemoveNode
49 //purpose  : 
50 //=======================================================================
51
52 Standard_Boolean VrmlData_Group::RemoveNode
53                         (const Handle(VrmlData_Node)& theNode)
54 {
55   Standard_Boolean aResult (Standard_False);
56   for (Iterator anIter = NodeIterator(); anIter.More(); anIter.Next())
57     if (anIter.Value() == theNode) {
58       aResult = Standard_True;
59       myNodes.Remove (anIter);
60       break;
61     }
62   return aResult;
63 }
64
65 //=======================================================================
66 //function : SetTransform
67 //purpose  : 
68 //=======================================================================
69
70 Standard_Boolean VrmlData_Group::SetTransform (const gp_Trsf& theTrsf)
71 {
72   Standard_Boolean aResult (Standard_False);
73   if (myIsTransform) {
74     myTrsf = theTrsf;
75     aResult = Standard_True;
76   }
77   return aResult;
78 }
79
80 //=======================================================================
81 //function : VrmlData_Group::Clone
82 //purpose  : 
83 //=======================================================================
84
85 Handle(VrmlData_Node) VrmlData_Group::Clone
86                                 (const Handle(VrmlData_Node)& theOther) const
87 {
88   Handle(VrmlData_Group) aResult =
89     Handle(VrmlData_Group)::DownCast (VrmlData_Node::Clone(theOther));
90   if (aResult.IsNull())
91     aResult =
92       new VrmlData_Group (theOther.IsNull() ? Scene() : theOther->Scene(),
93                           Name(), myIsTransform);
94
95   aResult->myIsTransform = myIsTransform;
96   if (&aResult->Scene() == &Scene())
97     aResult->myNodes = myNodes;
98   else {
99     // Create a dummy node to pass the different Scene instance to methods Clone
100     const Handle(VrmlData_UnknownNode) aDummyNode =
101       new VrmlData_UnknownNode (aResult->Scene());
102     Iterator anIter (myNodes);
103     for (; anIter.More(); anIter.Next()) {
104       const Handle(VrmlData_Node)& aNode = anIter.Value();
105       if (aNode.IsNull() == Standard_False)
106         aResult->myNodes.Append(aNode->Clone (aDummyNode));
107     }
108   }
109   if (myIsTransform)
110     aResult->SetTransform (myTrsf);
111   aResult->SetBox (myBox);
112
113   return aResult;
114 }
115
116 //=======================================================================
117 //function : FindNode
118 //purpose  : 
119 //=======================================================================
120
121 Handle(VrmlData_Node) VrmlData_Group::FindNode
122                                         (const char * theName,
123                                          gp_Trsf&     theLocation) const
124 {
125   Handle(VrmlData_Node) aResult;
126   Iterator anIter (myNodes);
127   for (; anIter.More(); anIter.Next()) {
128     const Handle(VrmlData_Node)& aNode = anIter.Value();
129     if (aNode.IsNull() == Standard_False) {
130       if (strcmp(aNode->Name(), theName) == 0)
131       {
132         aResult = aNode;
133         theLocation = myTrsf;
134         break;
135       }
136       // Try a Group type of node
137       if (aNode->IsKind(STANDARD_TYPE(VrmlData_Group)))
138       {
139         const Handle(VrmlData_Group) aGroup =
140           Handle(VrmlData_Group)::DownCast (aNode);
141         if (aGroup.IsNull() == Standard_False) {
142           aResult = aGroup->FindNode(theName, theLocation);
143           if (aResult.IsNull() == Standard_False) {
144             //theLocation *= myTrsf;
145             theLocation.PreMultiply(myTrsf);
146             break;
147           }
148         }
149       }
150     }
151   }
152   return aResult;
153 }
154
155 //=======================================================================
156 //function : VrmlData_Group::Read
157 //purpose  : 
158 //=======================================================================
159
160 VrmlData_ErrorStatus VrmlData_Group::Read (VrmlData_InBuffer& theBuffer)
161 {
162   VrmlData_ErrorStatus aStatus;
163   gp_XYZ aBoxCenter(0., 0., 0.), aBoxSize(-1., -1., -1.);
164   gp_XYZ aCenter  (0., 0., 0.), aScale (1., 1., 1.), aTrans (0., 0., 0.);
165   gp_XYZ aRotAxis (0., 0., 1.), aScaleAxis (0., 0., 1.);
166   Standard_Real aRotAngle (0.), aScaleAngle(0.);
167
168   while (OK(aStatus, VrmlData_Scene::ReadLine(theBuffer)))
169   {
170     if (VRMLDATA_LCOMPARE (theBuffer.LinePtr, "bboxCenter"))
171       aStatus = Scene().ReadXYZ (theBuffer, aBoxCenter,
172                                  Standard_True, Standard_False);
173
174     else if (VRMLDATA_LCOMPARE (theBuffer.LinePtr, "bboxSize"))
175       aStatus = Scene().ReadXYZ (theBuffer, aBoxSize,
176                                  Standard_True, Standard_False);
177
178     else if (VRMLDATA_LCOMPARE (theBuffer.LinePtr, "children")) {
179       Standard_Boolean isBracketed (Standard_False);
180       // Read the opening bracket for the list of children
181       if (!OK(aStatus, VrmlData_Scene::ReadLine(theBuffer)))
182         break;
183       if (theBuffer.LinePtr[0] == '[') {
184         theBuffer.LinePtr++;
185         if (!OK(aStatus, VrmlData_Scene::ReadLine(theBuffer)))
186           break;
187         isBracketed = Standard_True;
188       }
189
190       // Read the child nodes
191       Handle(VrmlData_Node) aChildNode;
192       while (OK(aStatus, VrmlData_Scene::ReadLine(theBuffer))) {
193         // read the end-of-list bracket
194         if (isBracketed && theBuffer.LinePtr[0] == ']') {
195           theBuffer.LinePtr++;
196           break;
197         }
198         // otherwise read a node
199         if (!OK(aStatus, ReadNode (theBuffer, aChildNode)))
200           break;
201         AddNode (aChildNode);
202         if (isBracketed == Standard_False)
203           break;
204       }
205     }
206     else if (VRMLDATA_LCOMPARE(theBuffer.LinePtr, "collide")) {
207       TCollection_AsciiString aDummy;
208       aStatus = Scene().ReadWord (theBuffer, aDummy);
209     }
210     else if (VRMLDATA_LCOMPARE (theBuffer.LinePtr, "Separator") ||
211              VRMLDATA_LCOMPARE (theBuffer.LinePtr, "Switch")) {
212       Standard_Boolean isBracketed (Standard_False);
213       // Read the opening bracket for the list of children
214       if (!OK(aStatus, VrmlData_Scene::ReadLine(theBuffer)))
215         break;
216       
217       if (theBuffer.LinePtr[0] == '{') {
218         theBuffer.LinePtr++;
219         if (!OK(aStatus, VrmlData_Scene::ReadLine(theBuffer)))
220           break;
221         isBracketed = Standard_True;
222       }
223
224       // Read the child nodes
225       Handle(VrmlData_Node) aChildNode;
226       while (OK(aStatus, VrmlData_Scene::ReadLine(theBuffer))) {
227         // read the end-of-list bracket
228         if (isBracketed && theBuffer.LinePtr[0] == '}') {
229           theBuffer.LinePtr++;
230           break;
231         }
232         
233         // otherwise read a node
234         if (!OK(aStatus, ReadNode (theBuffer, aChildNode)))
235           break;
236         
237         AddNode (aChildNode);
238         if (isBracketed == Standard_False)
239           break;
240       }
241     }
242     else if (VRMLDATA_LCOMPARE (theBuffer.LinePtr, "ShapeHints")) {
243       // Skip this tag
244       if (!OK(aStatus, VrmlData_Scene::ReadLine(theBuffer)))
245         break;
246       
247       if (theBuffer.LinePtr[0] == '{') {
248         theBuffer.LinePtr++;
249         if (!OK(aStatus, VrmlData_Scene::ReadLine(theBuffer)))
250           break;
251         
252         while (OK(aStatus, VrmlData_Scene::ReadLine(theBuffer))) {
253           // read the end-of-list bracket
254           if (theBuffer.LinePtr[0] == '}') {
255             theBuffer.LinePtr++;
256             break;
257           }
258           theBuffer.LinePtr++;
259         }
260       }
261     } else if (VRMLDATA_LCOMPARE (theBuffer.LinePtr, "center"))
262       if (myIsTransform)
263         aStatus = Scene().ReadXYZ (theBuffer, aCenter,
264                                    Standard_True, Standard_False);
265       else {
266         aStatus = VrmlData_VrmlFormatError;
267         break;
268       }
269     else if (VRMLDATA_LCOMPARE (theBuffer.LinePtr, "rotation"))
270       if (myIsTransform) {
271         if (OK(aStatus, Scene().ReadXYZ (theBuffer, aRotAxis,
272                                          Standard_False, Standard_False)))
273         {
274           if (aRotAxis.SquareModulus() < Precision::Confusion())
275             aRotAxis.SetZ (1.0);
276           aStatus = Scene().ReadReal (theBuffer, aRotAngle,
277                                       Standard_False, Standard_False);
278         }
279       } else {
280         aStatus = VrmlData_VrmlFormatError;
281         break;
282       }
283     else if (VRMLDATA_LCOMPARE (theBuffer.LinePtr, "scaleOrientation"))
284       if (myIsTransform) {
285         if (OK(aStatus, Scene().ReadXYZ (theBuffer, aScaleAxis,
286                                          Standard_False, Standard_False)))
287           aStatus = Scene().ReadReal (theBuffer, aScaleAngle,
288                                       Standard_False, Standard_False);
289       } else {
290         aStatus = VrmlData_VrmlFormatError;
291         break;
292       }
293     else if (VRMLDATA_LCOMPARE (theBuffer.LinePtr, "scale"))
294       if (myIsTransform)
295         aStatus = Scene().ReadXYZ (theBuffer, aScale,
296                                    Standard_False, Standard_True);
297       else {
298         aStatus = VrmlData_VrmlFormatError;
299         break;
300       }
301     else if (VRMLDATA_LCOMPARE (theBuffer.LinePtr, "translation"))
302       if (myIsTransform)
303         aStatus = Scene().ReadXYZ (theBuffer, aTrans,
304                                    Standard_True, Standard_False);
305       else {
306         aStatus = VrmlData_VrmlFormatError;
307         break;
308       }
309     else if (VRMLDATA_LCOMPARE (theBuffer.LinePtr, "url")) {
310       NCollection_List<TCollection_AsciiString> lstURL;
311       if (OK(aStatus, ReadMultiString (theBuffer, lstURL))) {
312         NCollection_List<TCollection_AsciiString>::Iterator anIter (lstURL);
313         for (; anIter.More(); anIter.Next()) {
314           ifstream aStream;
315           const TCollection_AsciiString& aFileName = anIter.Value();
316           if (!OK(aStatus, openFile (aStream, aFileName)))
317             break;
318           VrmlData_Scene aScene (Scene().Allocator());
319           aScene.myLinearScale = Scene().myLinearScale;
320           aScene.myVrmlDir = Scene().myVrmlDir;
321           aScene << aStream;
322           if (!OK(aStatus, aScene.Status()))
323             break;
324           VrmlData_Scene::Iterator anIterN = aScene.GetIterator();
325           for (; anIterN.More(); anIterN.Next())
326             if (!anIterN.Value()->IsKind(STANDARD_TYPE(VrmlData_WorldInfo)))
327               AddNode (anIterN.Value());
328           VrmlData_Scene::Iterator anAllIter(aScene.myAllNodes);
329           for (; anAllIter.More(); anAllIter.Next()) {
330             const Handle(VrmlData_Node)& aNode = anAllIter.Value();
331             if (aNode->IsKind(STANDARD_TYPE(VrmlData_WorldInfo)))
332               continue;
333             const_cast <VrmlData_Scene&> (Scene()).myAllNodes.Append (aNode);
334             aNode->myScene = &Scene();
335             // The name of the imported node should be prefixed by the URL
336             // because each name must remain unique in the global scene.
337             if (aNode->Name())
338               if (* aNode->Name() != '\0') {
339                 TCollection_AsciiString buf;
340                 buf += aFileName;
341                 Standard_Integer aCharLocation = buf.Location (1, '.', 1, buf.Length());
342                 if (aCharLocation != 0)
343                 {
344                   buf.Remove (aCharLocation, buf.Length() - aCharLocation + 1);
345                 }
346                 buf += '_';
347                 buf += aNode->Name();
348                 const size_t len = buf.Length();
349                 char * aNewName =
350                   static_cast<char *> (Scene().Allocator()->Allocate (len));
351                 if (aNewName) {
352                   aNode->myName = aNewName;
353                   memcpy (aNewName, buf.ToCString(), len);
354                 }
355               }
356           }
357         }
358       }
359     } else
360       break;
361
362     if (!OK(aStatus))
363       break;
364   }
365
366   // Read the terminating (closing) brace
367   if (OK(aStatus))
368     aStatus = readBrace (theBuffer);
369   if (OK(aStatus)) {
370     // Check if the Bounding Box has been imported
371     if (aBoxSize.X() > -Precision::Confusion() &&
372         aBoxSize.Y() > -Precision::Confusion() &&
373         aBoxSize.Z() > -Precision::Confusion())
374     {
375       myBox.SetCenter (aBoxCenter);
376       myBox.SetHSize  (aBoxSize*0.5);
377     }
378     if (myIsTransform) {
379       // Create the corresponding transformation.
380       gp_Trsf tRot, tCentInv;
381       myTrsf.SetTranslation(aTrans+aCenter);
382       gp_Ax1 aRotation (gp::Origin(), aRotAxis);
383       tRot.SetRotation(gp_Ax1 (gp::Origin(), aRotAxis), aRotAngle);
384       myTrsf.Multiply (tRot);
385       // Check that the scale is uniform (the same value in all 3 directions.
386       // Only in this case the scaling is applied.
387       const Standard_Real aScaleDiff[2] = {
388         aScale.X()-aScale.Y(),
389         aScale.X()-aScale.Z()
390       };
391       if (aScaleDiff[0]*aScaleDiff[0] + aScaleDiff[1]*aScaleDiff[1]
392           < Precision::Confusion())
393       {
394         gp_Trsf tScale;
395         tScale.SetScale (gp::Origin(), (aScale.X()+aScale.Y()+aScale.Z())/3.);
396         myTrsf.Multiply (tScale);
397       }
398       tCentInv.SetTranslation (aCenter.Reversed());
399       myTrsf.Multiply (tCentInv);
400     }
401   }
402   return aStatus;
403 }
404
405 //=======================================================================
406 //function : Shape
407 //purpose  : 
408 //=======================================================================
409
410 void VrmlData_Group::Shape (TopoDS_Shape&                       theShape,
411                             VrmlData_DataMapOfShapeAppearance * pMapApp)
412 {
413   VrmlData_Scene::createShape (theShape, myNodes, pMapApp);
414   theShape.Location(myTrsf);
415 }
416
417 //=======================================================================
418 //function : openFile
419 //purpose  : 
420 //=======================================================================
421
422 VrmlData_ErrorStatus VrmlData_Group::openFile
423                                 (Standard_IStream&              theStream,
424                                  const TCollection_AsciiString& theFilename)
425 {
426   ifstream& aStream = static_cast<ifstream&> (theStream);
427   VrmlData_ErrorStatus aStatus (VrmlData_EmptyData);
428   NCollection_List<TCollection_ExtendedString>::Iterator aDirIter =
429     Scene().VrmlDirIterator();
430   for (; aDirIter.More(); aDirIter.Next()) {
431     if (!aDirIter.Value().IsAscii())
432       continue;
433     const TCollection_AsciiString aFullName =
434       TCollection_AsciiString (aDirIter.Value()) + theFilename;
435     aStream.open (aFullName.ToCString(), ios::in);
436     if (aStream.fail())
437       aStream.clear();
438     else {
439       aStatus = VrmlData_StatusOK;
440       break;
441     }
442   }
443   if (aStatus == VrmlData_EmptyData) {
444     aStream.open (theFilename.ToCString(), ios::in);
445     if (!aStream.fail())
446       aStatus = VrmlData_StatusOK;
447   }
448   if (aStatus == VrmlData_EmptyData)
449     aStatus = VrmlData_CannotOpenFile;
450   return aStatus;
451 }
452
453 //=======================================================================
454 //function : Write
455 //purpose  : 
456 //=======================================================================
457
458 VrmlData_ErrorStatus VrmlData_Group::Write (const char * thePrefix) const
459 {
460   VrmlData_ErrorStatus aStatus (VrmlData_StatusOK);
461   if (myNodes.IsEmpty() == Standard_False) {
462     const VrmlData_Scene& aScene = Scene();
463     Standard_Boolean isTransform = myIsTransform;
464     if (isTransform && myTrsf.Form() == gp_Identity)
465       isTransform = Standard_False;
466     static const char * header[2] = { "Group {" , "Transform {" };
467     if (OK (aStatus, aScene.WriteLine (thePrefix, header[isTransform ? 1 : 0],
468                                        GlobalIndent())))
469     {
470       char buf[240];
471       if (OK(aStatus) && aScene.IsDummyWrite() == Standard_False)
472       {
473         const gp_XYZ aBoxCorner[2] = {
474           myBox.CornerMin(),
475           myBox.CornerMax()
476         };
477         // Check that the box is not void
478         if (aBoxCorner[0].X() < aBoxCorner[1].X() + Precision::Confusion()) {
479           Sprintf (buf, "bboxCenter  %.9g %.9g %.9g",
480                    0.5 * (aBoxCorner[0].X() + aBoxCorner[1].X()),
481                    0.5 * (aBoxCorner[0].Y() + aBoxCorner[1].Y()),
482                    0.5 * (aBoxCorner[0].Z() + aBoxCorner[1].Z()));
483           aStatus = aScene.WriteLine (buf);
484           if (OK(aStatus)) {
485             Sprintf (buf, "bboxSize    %.9g %.9g %.9g",
486                      aBoxCorner[1].X() - aBoxCorner[0].X(),
487                      aBoxCorner[1].Y() - aBoxCorner[0].Y(),
488                      aBoxCorner[1].Z() - aBoxCorner[0].Z());
489             aStatus = aScene.WriteLine (buf);
490           }
491         }
492       }
493       if (OK(aStatus) && isTransform && aScene.IsDummyWrite() == Standard_False)
494       {
495         // Output the Scale
496         const Standard_Real aScaleFactor = myTrsf.ScaleFactor();
497         if ((aScaleFactor - 1.)*(aScaleFactor - 1.) >
498             0.0001*Precision::Confusion())
499         {
500           Sprintf (buf, "scale       %.12g %.12g %.12g",
501                    aScaleFactor, aScaleFactor, aScaleFactor);
502           aStatus = aScene.WriteLine (buf);
503         }
504
505         // Output the Translation
506         const gp_XYZ& aTrans = myTrsf.TranslationPart();
507         if (aTrans.SquareModulus() > 0.0001*Precision::Confusion()) {
508           Sprintf (buf, "translation %.12g %.12g %.12g",
509                    aTrans.X(), aTrans.Y(), aTrans.Z());
510           aStatus = aScene.WriteLine (buf);
511         }
512
513         // Output the Rotation
514         gp_XYZ anAxis;
515         Standard_Real anAngle;
516         if (myTrsf.GetRotation (anAxis, anAngle)) {
517           // output the Rotation
518           Sprintf (buf, "rotation    %.12g %.12g %.12g %.9g",
519                    anAxis.X(), anAxis.Y(), anAxis.Z(), anAngle);
520           aStatus = aScene.WriteLine (buf);
521         }
522       }
523
524       if (OK(aStatus)) {
525
526         aStatus = aScene.WriteLine ("children [", 0L, GlobalIndent());
527
528         VrmlData_ListOfNode::Iterator anIterChild (myNodes);
529         for (; anIterChild.More() && OK(aStatus); anIterChild.Next()) {
530           const Handle(VrmlData_Node)& aNode = anIterChild.Value();
531           aScene.WriteNode (0L, aNode);
532         }
533
534         if (OK(aStatus)) {
535           aStatus = aScene.WriteLine ("]", 0L, -GlobalIndent());
536         }
537       }
538       aStatus = WriteClosing();
539     }
540   }
541   return aStatus;
542 }