ca3990e931c03e626fd3a90fe1f68796d9b2289a
[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 #ifdef WNT
27 #define _CRT_SECURE_NO_DEPRECATE
28 #pragma warning (disable:4996)
29 #endif
30
31 IMPLEMENT_STANDARD_HANDLE  (VrmlData_Group, VrmlData_Node)
32 IMPLEMENT_STANDARD_RTTIEXT (VrmlData_Group, VrmlData_Node)
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, "Separator") ||
207              VRMLDATA_LCOMPARE (theBuffer.LinePtr, "Switch")) {
208       Standard_Boolean isBracketed (Standard_False);
209       // Read the opening bracket for the list of children
210       if (!OK(aStatus, VrmlData_Scene::ReadLine(theBuffer)))
211         break;
212       
213       if (theBuffer.LinePtr[0] == '{') {
214         theBuffer.LinePtr++;
215         if (!OK(aStatus, VrmlData_Scene::ReadLine(theBuffer)))
216           break;
217         isBracketed = Standard_True;
218       }
219
220       // Read the child nodes
221       Handle(VrmlData_Node) aChildNode;
222       while (OK(aStatus, VrmlData_Scene::ReadLine(theBuffer))) {
223         // read the end-of-list bracket
224         if (isBracketed && theBuffer.LinePtr[0] == '}') {
225           theBuffer.LinePtr++;
226           break;
227         }
228         
229         // otherwise read a node
230         if (!OK(aStatus, ReadNode (theBuffer, aChildNode)))
231           break;
232         
233         AddNode (aChildNode);
234         if (isBracketed == Standard_False)
235           break;
236       }
237     }
238     else if (VRMLDATA_LCOMPARE (theBuffer.LinePtr, "ShapeHints")) {
239       // Skip this tag
240       if (!OK(aStatus, VrmlData_Scene::ReadLine(theBuffer)))
241         break;
242       
243       if (theBuffer.LinePtr[0] == '{') {
244         theBuffer.LinePtr++;
245         if (!OK(aStatus, VrmlData_Scene::ReadLine(theBuffer)))
246           break;
247         
248         while (OK(aStatus, VrmlData_Scene::ReadLine(theBuffer))) {
249           // read the end-of-list bracket
250           if (theBuffer.LinePtr[0] == '}') {
251             theBuffer.LinePtr++;
252             break;
253           }
254           theBuffer.LinePtr++;
255         }
256       }
257     } else if (VRMLDATA_LCOMPARE (theBuffer.LinePtr, "center"))
258       if (myIsTransform)
259         aStatus = Scene().ReadXYZ (theBuffer, aCenter,
260                                    Standard_True, Standard_False);
261       else {
262         aStatus = VrmlData_VrmlFormatError;
263         break;
264       }
265     else if (VRMLDATA_LCOMPARE (theBuffer.LinePtr, "rotation"))
266       if (myIsTransform) {
267         if (OK(aStatus, Scene().ReadXYZ (theBuffer, aRotAxis,
268                                          Standard_False, Standard_False)))
269         {
270           if (aRotAxis.SquareModulus() < Precision::Confusion())
271             aRotAxis.SetZ (1.0);
272           aStatus = Scene().ReadReal (theBuffer, aRotAngle,
273                                       Standard_False, Standard_False);
274         }
275       } else {
276         aStatus = VrmlData_VrmlFormatError;
277         break;
278       }
279     else if (VRMLDATA_LCOMPARE (theBuffer.LinePtr, "scale")) {
280       if (myIsTransform)
281         aStatus = Scene().ReadXYZ (theBuffer, aScale,
282                                    Standard_False, Standard_True);
283       else {
284         aStatus = VrmlData_VrmlFormatError;
285         break;
286       }
287     } else if (VRMLDATA_LCOMPARE (theBuffer.LinePtr, "scaleOrientation"))
288       if (myIsTransform) {
289         if (OK(aStatus, Scene().ReadXYZ (theBuffer, aScaleAxis,
290                                          Standard_False, Standard_False)))
291           aStatus = Scene().ReadReal (theBuffer, aScaleAngle,
292                                       Standard_False, Standard_False);
293       } else {
294         aStatus = VrmlData_VrmlFormatError;
295         break;
296       }
297     else if (VRMLDATA_LCOMPARE (theBuffer.LinePtr, "translation"))
298       if (myIsTransform)
299         aStatus = Scene().ReadXYZ (theBuffer, aTrans,
300                                    Standard_True, Standard_False);
301       else {
302         aStatus = VrmlData_VrmlFormatError;
303         break;
304       }
305     else if (VRMLDATA_LCOMPARE (theBuffer.LinePtr, "url")) {
306       NCollection_List<TCollection_AsciiString> lstURL;
307       if (OK(aStatus, ReadMultiString (theBuffer, lstURL))) {
308         NCollection_List<TCollection_AsciiString>::Iterator anIter (lstURL);
309         for (; anIter.More(); anIter.Next()) {
310           ifstream aStream;
311           const TCollection_AsciiString& aFileName = anIter.Value();
312           if (!OK(aStatus, openFile (aStream, aFileName)))
313             break;
314           VrmlData_Scene aScene (Scene().Allocator());
315           aScene.myLinearScale = Scene().myLinearScale;
316           aScene.myVrmlDir = Scene().myVrmlDir;
317           aScene << aStream;
318           if (!OK(aStatus, aScene.Status()))
319             break;
320           VrmlData_Scene::Iterator anIterN = aScene.GetIterator();
321           for (; anIterN.More(); anIterN.Next())
322             if (!anIterN.Value()->IsKind(STANDARD_TYPE(VrmlData_WorldInfo)))
323               AddNode (anIterN.Value());
324           VrmlData_Scene::Iterator anAllIter(aScene.myAllNodes);
325           for (; anAllIter.More(); anAllIter.Next()) {
326             const Handle(VrmlData_Node)& aNode = anAllIter.Value();
327             if (aNode->IsKind(STANDARD_TYPE(VrmlData_WorldInfo)))
328               continue;
329             const_cast <VrmlData_Scene&> (Scene()).myAllNodes.Append (aNode);
330             aNode->myScene = &Scene();
331             // The name of the imported node should be prefixed by the URL
332             // because each name must remain unique in the global scene.
333             if (aNode->Name())
334               if (* aNode->Name() != '\0') {
335                 TCollection_AsciiString buf;
336                 buf += aFileName;
337                 Standard_Integer aCharLocation = buf.Location (1, '.', 1, buf.Length());
338                 if (aCharLocation != 0)
339                 {
340                   buf.Remove (aCharLocation, buf.Length() - aCharLocation + 1);
341                 }
342                 buf += '_';
343                 buf += aNode->Name();
344                 const size_t len = buf.Length();
345                 char * aNewName =
346                   static_cast<char *> (Scene().Allocator()->Allocate (len));
347                 if (aNewName) {
348                   aNode->myName = aNewName;
349                   memcpy (aNewName, buf.ToCString(), len);
350                 }
351               }
352           }
353         }
354       }
355     } else
356       break;
357
358     if (!OK(aStatus))
359       break;
360   }
361
362   // Read the terminating (closing) brace
363   if (OK(aStatus))
364     aStatus = readBrace (theBuffer);
365   if (OK(aStatus)) {
366     // Check if the Bounding Box has been imported
367     if (aBoxSize.X() > -Precision::Confusion() &&
368         aBoxSize.Y() > -Precision::Confusion() &&
369         aBoxSize.Z() > -Precision::Confusion())
370     {
371       myBox.SetCenter (aBoxCenter);
372       myBox.SetHSize  (aBoxSize*0.5);
373     }
374     if (myIsTransform) {
375       // Create the corresponding transformation.
376       gp_Trsf tRot, tCentInv;
377       myTrsf.SetTranslation(aTrans+aCenter);
378       gp_Ax1 aRotation (gp::Origin(), aRotAxis);
379       tRot.SetRotation(gp_Ax1 (gp::Origin(), aRotAxis), aRotAngle);
380       myTrsf.Multiply (tRot);
381       // Check that the scale is uniform (the same value in all 3 directions.
382       // Only in this case the scaling is applied.
383       const Standard_Real aScaleDiff[2] = {
384         aScale.X()-aScale.Y(),
385         aScale.X()-aScale.Z()
386       };
387       if (aScaleDiff[0]*aScaleDiff[0] + aScaleDiff[1]*aScaleDiff[1]
388           < Precision::Confusion())
389       {
390         gp_Trsf tScale;
391         tScale.SetScale (gp::Origin(), (aScale.X()+aScale.Y()+aScale.Z())/3.);
392         myTrsf.Multiply (tScale);
393       }
394       tCentInv.SetTranslation (aCenter.Reversed());
395       myTrsf.Multiply (tCentInv);
396     }
397   }
398   return aStatus;
399 }
400
401 //=======================================================================
402 //function : Shape
403 //purpose  : 
404 //=======================================================================
405
406 void VrmlData_Group::Shape (TopoDS_Shape&                       theShape,
407                             VrmlData_DataMapOfShapeAppearance * pMapApp)
408 {
409   VrmlData_Scene::createShape (theShape, myNodes, pMapApp);
410   theShape.Location(myTrsf);
411 }
412
413 //=======================================================================
414 //function : openFile
415 //purpose  : 
416 //=======================================================================
417
418 VrmlData_ErrorStatus VrmlData_Group::openFile
419                                 (Standard_IStream&              theStream,
420                                  const TCollection_AsciiString& theFilename)
421 {
422   ifstream& aStream = static_cast<ifstream&> (theStream);
423   VrmlData_ErrorStatus aStatus (VrmlData_EmptyData);
424   NCollection_List<TCollection_ExtendedString>::Iterator aDirIter =
425     Scene().VrmlDirIterator();
426   for (; aDirIter.More(); aDirIter.Next()) {
427     if (!aDirIter.Value().IsAscii())
428       continue;
429     const TCollection_AsciiString aFullName =
430       TCollection_AsciiString (aDirIter.Value()) + theFilename;
431     aStream.open (aFullName.ToCString(), ios::in);
432     if (aStream.fail())
433       aStream.clear();
434     else {
435       aStatus = VrmlData_StatusOK;
436       break;
437     }
438   }
439   if (aStatus == VrmlData_EmptyData) {
440     aStream.open (theFilename.ToCString(), ios::in);
441     if (!aStream.fail())
442       aStatus = VrmlData_StatusOK;
443   }
444   if (aStatus == VrmlData_EmptyData)
445     aStatus = VrmlData_CannotOpenFile;
446   return aStatus;
447 }
448
449 //=======================================================================
450 //function : Write
451 //purpose  : 
452 //=======================================================================
453
454 VrmlData_ErrorStatus VrmlData_Group::Write (const char * thePrefix) const
455 {
456   VrmlData_ErrorStatus aStatus (VrmlData_StatusOK);
457   if (myNodes.IsEmpty() == Standard_False) {
458     const VrmlData_Scene& aScene = Scene();
459     Standard_Boolean isTransform = myIsTransform;
460     if (isTransform && myTrsf.Form() == gp_Identity)
461       isTransform = Standard_False;
462     static const char * header[2] = { "Group {" , "Transform {" };
463     if (OK (aStatus, aScene.WriteLine (thePrefix, header[isTransform ? 1 : 0],
464                                        GlobalIndent())))
465     {
466       char buf[240];
467       if (OK(aStatus) && aScene.IsDummyWrite() == Standard_False)
468       {
469         const gp_XYZ aBoxCorner[2] = {
470           myBox.CornerMin(),
471           myBox.CornerMax()
472         };
473         // Check that the box is not void
474         if (aBoxCorner[0].X() < aBoxCorner[1].X() + Precision::Confusion()) {
475           Sprintf (buf, "bboxCenter  %.9g %.9g %.9g",
476                    0.5 * (aBoxCorner[0].X() + aBoxCorner[1].X()),
477                    0.5 * (aBoxCorner[0].Y() + aBoxCorner[1].Y()),
478                    0.5 * (aBoxCorner[0].Z() + aBoxCorner[1].Z()));
479           aStatus = aScene.WriteLine (buf);
480           if (OK(aStatus)) {
481             Sprintf (buf, "bboxSize    %.9g %.9g %.9g",
482                      aBoxCorner[1].X() - aBoxCorner[0].X(),
483                      aBoxCorner[1].Y() - aBoxCorner[0].Y(),
484                      aBoxCorner[1].Z() - aBoxCorner[0].Z());
485             aStatus = aScene.WriteLine (buf);
486           }
487         }
488       }
489       if (OK(aStatus) && isTransform && aScene.IsDummyWrite() == Standard_False)
490       {
491         // Output the Scale
492         const Standard_Real aScaleFactor = myTrsf.ScaleFactor();
493         if ((aScaleFactor - 1.)*(aScaleFactor - 1.) >
494             0.0001*Precision::Confusion())
495         {
496           Sprintf (buf, "scale       %.12g %.12g %.12g",
497                    aScaleFactor, aScaleFactor, aScaleFactor);
498           aStatus = aScene.WriteLine (buf);
499         }
500
501         // Output the Translation
502         const gp_XYZ& aTrans = myTrsf.TranslationPart();
503         if (aTrans.SquareModulus() > 0.0001*Precision::Confusion()) {
504           Sprintf (buf, "translation %.12g %.12g %.12g",
505                    aTrans.X(), aTrans.Y(), aTrans.Z());
506           aStatus = aScene.WriteLine (buf);
507         }
508
509         // Output the Rotation
510         gp_XYZ anAxis;
511         Standard_Real anAngle;
512         if (myTrsf.GetRotation (anAxis, anAngle)) {
513           // output the Rotation
514           Sprintf (buf, "rotation    %.12g %.12g %.12g %.9g",
515                    anAxis.X(), anAxis.Y(), anAxis.Z(), anAngle);
516           aStatus = aScene.WriteLine (buf);
517         }
518       }
519
520       if (OK(aStatus)) {
521
522         aStatus = aScene.WriteLine ("children [", 0L, GlobalIndent());
523
524         VrmlData_ListOfNode::Iterator anIterChild (myNodes);
525         for (; anIterChild.More() && OK(aStatus); anIterChild.Next()) {
526           const Handle(VrmlData_Node)& aNode = anIterChild.Value();
527           aScene.WriteNode (0L, aNode);
528         }
529
530         if (OK(aStatus)) {
531           aStatus = aScene.WriteLine ("]", 0L, -GlobalIndent());
532         }
533       }
534       aStatus = WriteClosing();
535     }
536   }
537   return aStatus;
538 }