0033041: Coding - get rid of unused headers [TopTools to Xw]
[occt.git] / src / VrmlData / VrmlData_Scene.cxx
1 // Created on: 2006-05-25
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_Scene.hxx>
17 #include <VrmlData_Appearance.hxx>
18 #include <VrmlData_Box.hxx>
19 #include <VrmlData_Cone.hxx>
20 #include <VrmlData_Cylinder.hxx>
21 #include <VrmlData_DataMapOfShapeAppearance.hxx>
22 #include <VrmlData_Group.hxx>
23 #include <VrmlData_ImageTexture.hxx>
24 #include <VrmlData_InBuffer.hxx>
25 #include <VrmlData_IndexedFaceSet.hxx>
26 #include <VrmlData_IndexedLineSet.hxx>
27 #include <VrmlData_Material.hxx>
28 #include <VrmlData_Normal.hxx>
29 #include <VrmlData_Scene.hxx>
30 #include <VrmlData_ShapeNode.hxx>
31 #include <VrmlData_Sphere.hxx>
32 #include <VrmlData_TextureCoordinate.hxx>
33 #include <VrmlData_UnknownNode.hxx>
34 //#include <VrmlData_WorldInfo.hxx>
35 #include <NCollection_Vector.hxx>
36 #include <TopoDS.hxx>
37 #include <TopExp_Explorer.hxx>
38 #include <BRep_Builder.hxx>
39 #include <Precision.hxx>
40 #include <Standard_Version.hxx>
41 #include <VrmlData_WorldInfo.hxx>
42 #include <VrmlData_Geometry.hxx>
43
44 #ifdef _MSC_VER
45 #define _CRT_SECURE_NO_DEPRECATE
46 #pragma warning (disable:4996)
47 #endif
48
49 static void     dumpNode        (Standard_OStream&              theStream,
50                                  const Handle(VrmlData_Node)&   theNode,
51                                  const TCollection_AsciiString& theIndent);
52
53 static void     dumpNodeHeader  (Standard_OStream&              theStream,
54                                  const TCollection_AsciiString& theIndent,
55                                  const char *                   theType,
56                                  const char *                   theName);
57
58 //=======================================================================
59 //function : VrmlData_Scene
60 //purpose  : Constructor
61 //=======================================================================
62
63 VrmlData_Scene::VrmlData_Scene
64         (const Handle(NCollection_IncAllocator)& theAlloc)
65   : myLinearScale     (1.),
66     myStatus          (VrmlData_StatusOK),
67     myAllocator       (theAlloc.IsNull() ?
68                        new NCollection_IncAllocator : theAlloc.operator->()),
69     myLineError       (0),
70     myOutput          (0L),
71     myIndent          (2),
72     myCurrentIndent   (0),
73     myAutoNameCounter (0)
74 {
75   myWorldInfo = new VrmlData_WorldInfo (* this);
76   Standard_CString anInfo = "Generated by Open CASCADE Technology " OCC_VERSION_STRING;
77   myWorldInfo->AddInfo (anInfo);
78   myLstNodes.Append (myWorldInfo);
79   myAllNodes.Append (myWorldInfo);
80 }
81
82 //=======================================================================
83 //function : AddNode
84 //purpose  : 
85 //=======================================================================
86
87 const Handle(VrmlData_Node)& VrmlData_Scene::AddNode
88                                 (const Handle(VrmlData_Node)& theN,
89                                  const Standard_Boolean       isTopLevel)
90 {
91   if (theN.IsNull() == Standard_False)
92     if (theN->IsKind (STANDARD_TYPE(VrmlData_WorldInfo)) == Standard_False) {
93       myMutex.Lock();
94       const Handle(VrmlData_Node)& aNode =
95         myAllNodes.Append ((&theN->Scene()== this) ? theN : theN->Clone (NULL));
96       // Name is checked for uniqueness. If not, letter 'D' is appended until
97       // the name proves to be unique.
98       if (aNode->Name()[0] != '\0')
99         while (myNamedNodes.Add (aNode) == Standard_False)
100           aNode->setName (aNode->Name(), "D");
101       if (isTopLevel)
102         myLstNodes.Append (aNode);
103       myMutex.Unlock();
104       return aNode;
105     }
106   static Handle(VrmlData_Node) aNullNode;
107   aNullNode.Nullify();
108   return aNullNode;
109 }
110
111 //=======================================================================
112 //function : operator <<
113 //purpose  : Export to text stream (file or else)
114 //=======================================================================
115
116 Standard_OStream& operator << (Standard_OStream&     theOutput,
117                                const VrmlData_Scene& theScene)
118 {
119   VrmlData_Scene& aScene = const_cast <VrmlData_Scene&> (theScene);
120   aScene.myMutex.Lock();
121   aScene.myCurrentIndent = 0;
122   aScene.myLineError = 0;
123   aScene.myOutput = 0L;
124   aScene.myNamedNodesOut.Clear();
125   aScene.myUnnamedNodesOut.Clear();
126   aScene.myAutoNameCounter = 0;
127
128   // Dummy write
129
130   VrmlData_Scene::Iterator anIterD(aScene.myLstNodes);
131   for (; anIterD.More(); anIterD.Next()) {
132     const Handle(VrmlData_Node)& aNode = anIterD.Value();
133     if (aNode.IsNull() == Standard_False) {
134       const VrmlData_ErrorStatus aStatus = aScene.WriteNode (0L, aNode);
135       if (aStatus != VrmlData_StatusOK &&
136           aStatus != VrmlData_NotImplemented)
137         break;
138     }
139   }
140
141   aScene.myOutput = &theOutput;
142   aScene.myNamedNodesOut.Clear();
143   theOutput << "#VRML V2.0 utf8\n\n";
144
145   // Real write
146
147   VrmlData_Scene::Iterator anIter(aScene.myLstNodes);
148   for (; anIter.More(); anIter.Next()) {
149     const Handle(VrmlData_Node)& aNode = anIter.Value();
150     if (aNode.IsNull() == Standard_False) {
151       const VrmlData_ErrorStatus aStatus = aScene.WriteNode (0L, aNode);
152       if (aStatus != VrmlData_StatusOK &&
153           aStatus != VrmlData_NotImplemented)
154         break;
155     }
156   }
157   aScene.myOutput = 0L;
158   aScene.myNamedNodesOut.Clear();
159   aScene.myUnnamedNodesOut.Clear();
160   aScene.myMutex.Unlock();
161   return theOutput;
162 }
163
164 //=======================================================================
165 //function : SetVrmlDir
166 //purpose  : 
167 //=======================================================================
168
169 void VrmlData_Scene::SetVrmlDir (const TCollection_ExtendedString& theDir)
170 {
171   TCollection_ExtendedString& aDir = myVrmlDir.Append (theDir);
172   const Standard_ExtCharacter aTerminator = aDir.Value(aDir.Length());
173   if (aTerminator != Standard_ExtCharacter('\\') &&
174       aTerminator != Standard_ExtCharacter('/'))
175 #ifdef _WIN32
176     aDir += TCollection_ExtendedString ("\\");
177 #else
178     aDir += TCollection_ExtendedString ("/");
179 #endif
180 }
181
182 //=======================================================================
183 //function : WorldInfo
184 //purpose  : 
185 //=======================================================================
186
187 const Handle(VrmlData_WorldInfo)& VrmlData_Scene::WorldInfo() const
188 {
189   return myWorldInfo;
190 }
191
192 //=======================================================================
193 //function : readLine
194 //purpose  : 
195 //=======================================================================
196
197 VrmlData_ErrorStatus VrmlData_Scene::readLine (VrmlData_InBuffer& theBuffer)
198 {
199   VrmlData_ErrorStatus aStatus = VrmlData_StatusOK;
200   if (theBuffer.Input.eof())
201     aStatus = VrmlData_EndOfFile;
202   else {
203     theBuffer.Input.getline (theBuffer.Line, sizeof(theBuffer.Line));
204     theBuffer.LineCount++;
205     const int stat = theBuffer.Input.rdstate();
206     if (stat & std::ios::badbit) {
207       aStatus = VrmlData_UnrecoverableError;
208     }
209     else if (stat & std::ios::failbit) {
210       if (stat & std::ios::eofbit) {
211         aStatus = VrmlData_EndOfFile;
212       }
213       else {
214         aStatus = VrmlData_GeneralError;
215       }
216     }
217     theBuffer.LinePtr = &theBuffer.Line[0];
218     theBuffer.IsProcessed = Standard_False;
219   }
220   return aStatus;
221 }
222
223 //=======================================================================
224 //function : ReadLine
225 //purpose  : 
226 //=======================================================================
227
228 VrmlData_ErrorStatus VrmlData_Scene::ReadLine (VrmlData_InBuffer& theBuffer)
229 {
230   VrmlData_ErrorStatus aStatus (VrmlData_StatusOK); 
231
232   while (aStatus == VrmlData_StatusOK) {
233     // Find the first significant character of the line
234     for (; * theBuffer.LinePtr != '\0'; theBuffer.LinePtr++) {
235       if (* theBuffer.LinePtr != ' ' && * theBuffer.LinePtr != '\t'
236           && * theBuffer.LinePtr != ',')
237       {
238         if (* theBuffer.LinePtr == '\n' || * theBuffer.LinePtr == '\r' ||
239             * theBuffer.LinePtr == '#')
240           // go requesting the next line
241           break;
242         goto nonempty_line;
243       }
244     }
245     // the line is empty here (no significant characters). Read the next one.
246     aStatus = readLine (theBuffer);
247   }
248
249   // error or EOF detected
250   return aStatus;
251
252  nonempty_line:
253   // Try to detect comment
254   if (theBuffer.IsProcessed == Standard_False) {
255     Standard_Boolean isQuoted (Standard_False);
256     Standard_Integer anOffset (0);
257     char * ptr = theBuffer.LinePtr;
258     for (; * ptr != '\0'; ptr++) {
259       if (anOffset)
260         * ptr = ptr[anOffset];
261       if (* ptr == '\n' || * ptr == '\r' || * ptr == '#') {
262         if (isQuoted == Standard_False) {
263           * ptr = '\0';
264           break;
265         }
266       } else if (* ptr == '\\' && isQuoted)
267         ptr[0] = ptr[++anOffset];
268       else if (* ptr == '\"')
269         isQuoted = !isQuoted;
270     }
271     theBuffer.IsProcessed = Standard_True;
272   }
273   return aStatus;
274 }
275
276 //=======================================================================
277 //function : readHeader
278 //purpose  : 
279 //=======================================================================
280
281 VrmlData_ErrorStatus VrmlData_Scene::readHeader (VrmlData_InBuffer& theBuffer)
282 {
283   VrmlData_ErrorStatus aStat = readLine (theBuffer);
284   if (aStat == VrmlData_StatusOK &&
285       !VRMLDATA_LCOMPARE(theBuffer.LinePtr, "#VRML V2.0"))
286     aStat = VrmlData_NotVrmlFile;
287   else 
288     aStat = readLine(theBuffer);
289   return aStat;
290 }
291
292 //=======================================================================
293 //function : operator <<
294 //purpose  : Import from text stream (file or else)
295 //=======================================================================
296
297 VrmlData_Scene& VrmlData_Scene::operator << (Standard_IStream& theInput)
298 {
299   VrmlData_InBuffer aBuffer (theInput);
300   myMutex.Lock();
301   // Read the VRML header
302   myStatus = readHeader (aBuffer);
303   const Handle(VrmlData_UnknownNode) aNullNode= new VrmlData_UnknownNode(*this);
304 //   if (myStatus == StatusOK)
305 //     myStatus = ReadLine (aBuffer);
306   // Read VRML data by nodes
307   for(;;) {
308     if (!VrmlData_Node::OK(myStatus, ReadLine(aBuffer))) {
309       if (myStatus == VrmlData_EndOfFile)
310         myStatus = VrmlData_StatusOK;
311       break;
312     }
313     // this line provides the method ReadNode in the present context
314     Handle(VrmlData_Node) aNode;
315     myStatus = aNullNode->ReadNode (aBuffer, aNode);
316     // Unknown nodes are not stored however they do not generate error
317     if (myStatus != VrmlData_StatusOK)
318       break;
319     if (aNode.IsNull() == Standard_False /*&&
320         !aNode->IsKind (STANDARD_TYPE(VrmlData_UnknownNode))*/)
321     {
322       if (aNode->IsKind (STANDARD_TYPE(VrmlData_WorldInfo)) == Standard_False)
323         myLstNodes.Append (aNode);
324       else if (aNode->IsDefault() == Standard_False) {
325         const Handle(VrmlData_WorldInfo) aInfo =
326           Handle(VrmlData_WorldInfo)::DownCast (aNode);
327         myWorldInfo->SetTitle (aInfo->Title());
328         NCollection_List <const char *>::Iterator anIterInfo =
329           aInfo->InfoIterator();
330         for (; anIterInfo.More(); anIterInfo.Next())
331           myWorldInfo->AddInfo (anIterInfo.Value());
332       }
333     }
334   }
335   if (myStatus != VrmlData_StatusOK)
336     myLineError = aBuffer.LineCount;
337   myMutex.Unlock();
338   return * this;
339 }
340
341 //=======================================================================
342 //function : FindNode
343 //purpose  : 
344 //=======================================================================
345
346 Handle(VrmlData_Node) VrmlData_Scene::FindNode
347                                 (const char                   * theName,
348                                  const Handle(Standard_Type)& /*theType*/) const
349 {
350   Handle(VrmlData_Node) aResult;
351 #ifdef USE_LIST_API
352   Iterator anIter (myAllNodes);
353   for (; anIter.More(); anIter.Next())
354     if (!strcmp (anIter.Value()->Name(), theName)) {
355       aResult = anIter.Value();
356       if (theType.IsNull())
357         break;
358       if (aResult->IsKind(theType))
359         break;
360       aResult.Nullify();
361     }
362 #else
363   const Handle(VrmlData_UnknownNode) aDummyNode = new VrmlData_UnknownNode;
364   aDummyNode->myName = theName;
365   if (myNamedNodes.Contains (aDummyNode))
366     aResult = const_cast<VrmlData_MapOfNode&>(myNamedNodes).Added(aDummyNode);
367 #endif
368   return aResult;
369 }
370
371 //=======================================================================
372 //function : FindNode
373 //purpose  : 
374 //=======================================================================
375
376 Handle(VrmlData_Node) VrmlData_Scene::FindNode
377                                         (const char *   theName,
378                                          gp_Trsf&       theLocation) const
379 {
380   gp_Trsf aLoc;
381   Handle(VrmlData_Node) aResult;
382   Iterator anIter (myLstNodes);
383   for (; anIter.More(); anIter.Next()) {
384     const Handle(VrmlData_Node)& aNode = anIter.Value();
385     if (aNode.IsNull())
386       continue;
387     // Match a top-level node name
388     if (strcmp(aNode->Name(), theName) == 0) {
389       aResult = aNode;
390       theLocation = aLoc;
391       break;
392     }
393     // Try a Group type of node
394     if (aNode->IsKind(STANDARD_TYPE(VrmlData_Group)))
395     {
396       const Handle(VrmlData_Group) aGroup =
397         Handle(VrmlData_Group)::DownCast (aNode);
398       if (aGroup.IsNull() == Standard_False) {
399         aResult = aGroup->FindNode(theName, theLocation);
400         if (aResult.IsNull() == Standard_False)
401           break;
402       }
403     }
404   }
405   return aResult;
406 }
407
408 //=======================================================================
409 //function : ReadWord
410 //purpose  : 
411 //=======================================================================
412
413 VrmlData_ErrorStatus VrmlData_Scene::ReadWord
414                                       (VrmlData_InBuffer&           theBuffer,
415                                        TCollection_AsciiString&     theWord)
416 {
417   VrmlData_ErrorStatus aStatus = ReadLine(theBuffer);
418   if (aStatus == VrmlData_StatusOK) {
419     char * ptr = theBuffer.LinePtr;
420     while (* ptr != '\0' && * ptr != '\n' && * ptr != '\r' &&
421            * ptr != ' '  && * ptr != '\t' && * ptr != '{' && * ptr != '}' &&
422            * ptr != ','  && * ptr != '['  && * ptr != ']')
423       ptr++;
424     const Standard_Integer aLen = Standard_Integer(ptr - theBuffer.LinePtr);
425     if (aLen <= 0)
426       aStatus = VrmlData_StringInputError;
427     else {
428       theWord = TCollection_AsciiString ((Standard_CString)theBuffer.LinePtr,
429                                          aLen);
430       theBuffer.LinePtr = ptr;
431     }
432   }
433   return aStatus;
434 }
435
436 //=======================================================================
437 //function : createNode
438 //purpose  : 
439 //=======================================================================
440
441 VrmlData_ErrorStatus VrmlData_Scene::createNode
442                                       (VrmlData_InBuffer&           theBuffer,
443                                        Handle(VrmlData_Node)&       theNode,
444                                        const Handle(Standard_Type)& theType)
445 {
446   VrmlData_ErrorStatus    aStatus;
447   Handle(VrmlData_Node)   aNode;
448   TCollection_AsciiString aName;
449
450   // Read the DEF token to assign the node name
451   if (VrmlData_Node::OK(aStatus, ReadLine(theBuffer))) {
452     if (VRMLDATA_LCOMPARE(theBuffer.LinePtr, "DEF")) {
453       if (VrmlData_Node::OK(aStatus, ReadWord (theBuffer, aName)))
454         aStatus = ReadLine(theBuffer);
455     } else if (VRMLDATA_LCOMPARE(theBuffer.LinePtr, "NULL")) {
456       theNode.Nullify();
457       return aStatus;
458     }
459   }
460
461   const char * strName = aName.ToCString();
462   if (aStatus == VrmlData_StatusOK) {
463     // create the new node
464     if (VRMLDATA_LCOMPARE(theBuffer.LinePtr, "Appearance"))
465       aNode = new VrmlData_Appearance     (* this, strName);
466     else if (VRMLDATA_LCOMPARE(theBuffer.LinePtr, "Shape"))
467       aNode = new VrmlData_ShapeNode      (* this, strName);
468     else if (VRMLDATA_LCOMPARE(theBuffer.LinePtr, "Box"))
469       aNode = new VrmlData_Box            (* this, strName);
470     else if (VRMLDATA_LCOMPARE(theBuffer.LinePtr, "Color"))
471       aNode = new VrmlData_Color          (* this, strName);
472     else if (VRMLDATA_LCOMPARE(theBuffer.LinePtr, "Cone"))
473       aNode = new VrmlData_Cone           (* this, strName);
474     else if (VRMLDATA_LCOMPARE(theBuffer.LinePtr, "Coordinate")) {
475       aNode = new VrmlData_Coordinate     (* this, strName);
476       
477       // Check for "Coordinate3"
478       if (VRMLDATA_LCOMPARE (theBuffer.LinePtr, "3"))
479         theBuffer.LinePtr++;
480     }
481     else if (VRMLDATA_LCOMPARE(theBuffer.LinePtr, "Cylinder"))
482       aNode = new VrmlData_Cylinder       (* this, strName);
483     else if (VRMLDATA_LCOMPARE(theBuffer.LinePtr, "Group"))
484       aNode = new VrmlData_Group          (* this, strName,
485                                            Standard_False);
486     else if (VRMLDATA_LCOMPARE(theBuffer.LinePtr, "Transform"))
487       aNode = new VrmlData_Group          (* this, strName,
488                                            Standard_True);
489     else if (VRMLDATA_LCOMPARE(theBuffer.LinePtr, "Inline"))
490       aNode = new VrmlData_Group          (* this, strName,
491                                            Standard_False);
492     else if (VRMLDATA_LCOMPARE(theBuffer.LinePtr, "Separator"))
493       aNode = new VrmlData_Group          (* this, strName,
494                                            Standard_False);
495     else if (VRMLDATA_LCOMPARE(theBuffer.LinePtr, "Collision"))
496       aNode = new VrmlData_Group          (* this, strName,
497                                            Standard_False);
498     else if (VRMLDATA_LCOMPARE(theBuffer.LinePtr, "Switch"))
499       aNode = new VrmlData_Group          (* this, strName,
500                                            Standard_False);
501     else if (VRMLDATA_LCOMPARE(theBuffer.LinePtr, "ImageTexture"))
502       aNode = new VrmlData_ImageTexture   (* this, strName);
503     else if (VRMLDATA_LCOMPARE(theBuffer.LinePtr, "IndexedFaceSet"))
504       aNode = new VrmlData_IndexedFaceSet (* this, strName);
505     else if (VRMLDATA_LCOMPARE(theBuffer.LinePtr, "IndexedLineSet"))
506       aNode = new VrmlData_IndexedLineSet (* this, strName);
507     else if (VRMLDATA_LCOMPARE(theBuffer.LinePtr, "Material"))
508       aNode = new VrmlData_Material       (* this, strName);
509     else if (VRMLDATA_LCOMPARE(theBuffer.LinePtr, "Normal"))
510       aNode = new VrmlData_Normal         (* this, strName);
511     else if (VRMLDATA_LCOMPARE(theBuffer.LinePtr, "Sphere"))
512       aNode = new VrmlData_Sphere         (* this, strName);
513     else if (VRMLDATA_LCOMPARE(theBuffer.LinePtr, "TextureCoordinate"))
514       aNode = new VrmlData_TextureCoordinate(* this, strName);
515     else if (VRMLDATA_LCOMPARE(theBuffer.LinePtr, "WorldInfo"))
516       aNode = new VrmlData_WorldInfo      (* this, strName);
517     else {
518       void * isProto = VRMLDATA_LCOMPARE(theBuffer.LinePtr, "PROTO");
519       TCollection_AsciiString aTitle;
520       aStatus = ReadWord (theBuffer, aTitle);
521       if (isProto) {
522         aStatus = ReadLine(theBuffer);
523         if (aStatus == VrmlData_StatusOK) {
524           if (theBuffer.LinePtr[0] != '[')
525             aStatus = VrmlData_VrmlFormatError;
526           else {
527             theBuffer.LinePtr++;
528             Standard_Integer aLevelCounter(0);
529    // This loop searches for any opening bracket '['.
530    // Such bracket increments the level counter. A closing bracket decrements
531    // the counter. The loop terminates when the counter becomes negative.
532             while (aLevelCounter >= 0 &&
533                    (aStatus = ReadLine(theBuffer)) == VrmlData_StatusOK) {
534               int aChar;
535               while ((aChar = theBuffer.LinePtr[0]) != '\0') {
536                 theBuffer.LinePtr++;
537                 if        (aChar == '[') {
538                   aLevelCounter++;
539                   break;
540                 } else if (aChar == ']') {
541                   aLevelCounter--;
542                   break;
543                 }
544               }
545             }
546           }
547         }
548       }
549       if (aStatus == VrmlData_StatusOK)
550         aNode = new VrmlData_UnknownNode(* this,
551                                          strName,
552                                          aTitle.ToCString());
553     }
554   }
555   aStatus = ReadLine(theBuffer);
556   if (aNode.IsNull() == Standard_False) {
557     if (aNode->Name()[0] != '\0') 
558       myNamedNodes.Add (aNode);
559     if (theType.IsNull() == Standard_False)
560       if (aNode->IsKind(theType) == Standard_False)
561         aStatus = VrmlData_VrmlFormatError;
562   }
563   if (aStatus == VrmlData_StatusOK) {
564     if (theBuffer.LinePtr[0] == '{') {
565       theBuffer.LinePtr++;
566       theNode = aNode;
567       myAllNodes.Append(aNode);
568     } else {
569       aStatus = VrmlData_VrmlFormatError;
570     }
571   }
572   return aStatus;
573 }
574
575 //=======================================================================
576 //function : operator TopoDS_Shape
577 //purpose  : 
578 //=======================================================================
579
580 VrmlData_Scene::operator TopoDS_Shape () const
581 {
582   TopoDS_Shape aShape;
583   VrmlData_Scene::createShape (aShape, myLstNodes, 0L);
584   return aShape;
585 }
586
587 //=======================================================================
588 //function : GetShape
589 //purpose  : 
590 //=======================================================================
591
592 TopoDS_Shape VrmlData_Scene::GetShape (VrmlData_DataMapOfShapeAppearance& aMap)
593 {
594   TopoDS_Shape aShape;
595   VrmlData_Scene::createShape (aShape, myLstNodes, &aMap);
596   return aShape;
597 }
598
599 //=======================================================================
600 //function : createShape
601 //purpose  : 
602 //=======================================================================
603
604 void VrmlData_Scene::createShape
605                 (TopoDS_Shape&                      outShape,
606                  const VrmlData_ListOfNode&         lstNodes,
607                  VrmlData_DataMapOfShapeAppearance* pMapShapeApp)
608 {
609   TopoDS_Shape aSingleShape;  // used when there is a single ShapeNode
610   Standard_Boolean isSingleShape (Standard_True);
611   BRep_Builder aBuilder;
612   outShape.Nullify();
613   aBuilder.MakeCompound(TopoDS::Compound(outShape));
614   aSingleShape.Orientation(TopAbs_FORWARD);
615
616   Iterator anIter (lstNodes);
617   for (; anIter.More(); anIter.Next()) {
618     // Try a Shape type of node
619     const Handle(VrmlData_ShapeNode) aNodeShape =
620       Handle(VrmlData_ShapeNode)::DownCast (anIter.Value());
621     if (aNodeShape.IsNull() == Standard_False) {
622       const Handle(VrmlData_Geometry) aNodeGeom = aNodeShape->Geometry();
623       if (aNodeGeom.IsNull() == Standard_False) {
624         if (aSingleShape.IsNull() == Standard_False)
625           isSingleShape = Standard_False;
626         const Handle(TopoDS_TShape) aTShape = aNodeGeom->TShape();
627         aSingleShape.TShape(aTShape);
628         if (aSingleShape.IsNull() == Standard_False) {
629           aBuilder.Add (outShape, aSingleShape);
630           if (pMapShapeApp != 0L) {
631             const Handle(VrmlData_Appearance)& anAppearance =
632               aNodeShape->Appearance();
633             if (anAppearance.IsNull() == Standard_False) {
634               // Check if the current topology is a single face
635               if (aTShape->IsKind(STANDARD_TYPE(TopoDS_TFace)))
636                 pMapShapeApp->Bind(aTShape, anAppearance);
637               else {
638                 // This is not a face, explode it in faces and bind each face
639                 TopoDS_Shape aCurShape;
640                 aCurShape.TShape(aTShape);
641                 TopExp_Explorer anExp(aCurShape, TopAbs_FACE);
642                 for (; anExp.More(); anExp.Next()) {
643                   const TopoDS_Face& aFace = TopoDS::Face(anExp.Current());
644                   pMapShapeApp->Bind(aFace.TShape(), anAppearance);
645                 }
646               }
647             }
648           }
649         }
650       }
651       continue;
652     }
653     // Try a Group type of node
654     const Handle(VrmlData_Group) aNodeGroup =
655       Handle(VrmlData_Group)::DownCast (anIter.Value());
656     if (aNodeGroup.IsNull() == Standard_False) {
657       TopoDS_Shape aShape;
658       aNodeGroup->Shape(aShape, pMapShapeApp);
659       if (aShape.IsNull() == Standard_False) {
660         aBuilder.Add (outShape, aShape);
661         isSingleShape = Standard_False;
662       }
663     }
664   }
665   if (isSingleShape)
666     outShape = aSingleShape;
667 }
668
669 //=======================================================================
670 //function : ReadReal
671 //purpose  : 
672 //=======================================================================
673
674 VrmlData_ErrorStatus VrmlData_Scene::ReadReal
675                                 (VrmlData_InBuffer& theBuffer,
676                                  Standard_Real&     theResult,
677                                  Standard_Boolean   isScale,
678                                  Standard_Boolean   isOnlyPositive) const
679 {
680   Standard_Real aResult(0.);
681   VrmlData_ErrorStatus aStatus;
682   if (VrmlData_Node::OK(aStatus, VrmlData_Scene::ReadLine(theBuffer))) {
683     char * endptr;
684     aResult = Strtod (theBuffer.LinePtr, &endptr);
685     if (endptr == theBuffer.LinePtr)
686       aStatus = VrmlData_NumericInputError;
687     else if (isOnlyPositive && aResult < 0.001*Precision::Confusion())
688       aStatus = VrmlData_IrrelevantNumber;
689     else {
690       theResult = isScale ? (aResult * myLinearScale) : aResult;
691       theBuffer.LinePtr = endptr;
692     }
693   }
694   return aStatus;
695 }
696
697 //=======================================================================
698 //function : ReadXYZ
699 //purpose  : 
700 //=======================================================================
701
702 VrmlData_ErrorStatus VrmlData_Scene::ReadXYZ
703                                 (VrmlData_InBuffer&     theBuffer,
704                                  gp_XYZ&                theXYZ,
705                                  Standard_Boolean       isScale,
706                                  Standard_Boolean       isOnlyPos) const
707 {
708   Standard_Real aVal[3] = {0., 0., 0.};
709   VrmlData_ErrorStatus aStatus = VrmlData_StatusOK;
710   for (Standard_Integer i = 0; i < 3; i++) {
711     if (!VrmlData_Node::OK(aStatus, VrmlData_Scene::ReadLine(theBuffer)))
712       break;
713     char * endptr;
714     aVal[i] = Strtod (theBuffer.LinePtr, &endptr);
715     if (endptr == theBuffer.LinePtr) {
716       aStatus = VrmlData_NumericInputError;
717       break;
718     } else {
719       if (isOnlyPos && aVal[i] < 0.001*Precision::Confusion()) {
720         aStatus = VrmlData_IrrelevantNumber;
721         break;
722       }
723       theBuffer.LinePtr = endptr;
724     }
725   }
726   if (aStatus == VrmlData_StatusOK) {
727     if (isScale) {
728       theXYZ.SetCoord (aVal[0] * myLinearScale,
729                        aVal[1] * myLinearScale,
730                        aVal[2] * myLinearScale);
731     }
732     else {
733       theXYZ.SetCoord (aVal[0], aVal[1], aVal[2]);
734     }
735   }
736   return aStatus;
737 }
738
739 //=======================================================================
740 //function : ReadXY
741 //purpose  : 
742 //=======================================================================
743
744 VrmlData_ErrorStatus VrmlData_Scene::ReadXY
745                                 (VrmlData_InBuffer&     theBuffer,
746                                  gp_XY&                 theXY,
747                                  Standard_Boolean       isScale,
748                                  Standard_Boolean       isOnlyPos) const
749 {
750   Standard_Real aVal[2] = {0., 0.};
751   VrmlData_ErrorStatus aStatus = VrmlData_StatusOK;
752   for (Standard_Integer i = 0; i < 2; i++) {
753     if (!VrmlData_Node::OK(aStatus, VrmlData_Scene::ReadLine(theBuffer)))
754       break;
755     char * endptr;
756     aVal[i] = Strtod (theBuffer.LinePtr, &endptr);
757     if (endptr == theBuffer.LinePtr) {
758       aStatus = VrmlData_NumericInputError;
759       break;
760     } else {
761       if (isOnlyPos && aVal[i] < 0.001*Precision::Confusion()) {
762         aStatus = VrmlData_IrrelevantNumber;
763         break;
764       }
765       theBuffer.LinePtr = endptr;
766     }
767   }
768   if (aStatus == VrmlData_StatusOK) {
769     if (isScale)
770       theXY.SetCoord (aVal[0] * myLinearScale, aVal[1] * myLinearScale);
771     else
772       theXY.SetCoord (aVal[0], aVal[1]);
773   }
774   return aStatus;
775 }
776
777 //=======================================================================
778 //function : ReadArrIndex
779 //purpose  : Read the body of the data node (comma-separated list of int
780 //           multiplets)
781 //=======================================================================
782
783 VrmlData_ErrorStatus VrmlData_Scene::ReadArrIndex
784                                   (VrmlData_InBuffer&         theBuffer,
785                                    const Standard_Integer **& theArray,
786                                    Standard_Size&             theNBlocks) const
787 {
788   VrmlData_ErrorStatus aStatus;
789   theNBlocks = 0;
790   if (VrmlData_Node::OK(aStatus, ReadLine(theBuffer))) {
791     if (theBuffer.LinePtr[0] != '[')  // opening bracket
792       aStatus = VrmlData_VrmlFormatError;
793     else {
794       theBuffer.LinePtr++;
795       NCollection_Vector<const Standard_Integer *> vecIndice;
796       NCollection_Vector<Standard_Integer>         vecInt;
797       Standard_Boolean isMore (Standard_True);
798       long             anIntValue;
799
800       // Loop reading integers from the stream
801       while (isMore && VrmlData_Node::OK(aStatus, ReadLine(theBuffer)))
802       {
803         // closing bracket, in case that it follows a comma
804         if (theBuffer.LinePtr[0] == ']') {
805           theBuffer.LinePtr++;
806           break;
807         }
808         if (!VrmlData_Node::OK(aStatus, VrmlData_Node::ReadInteger(theBuffer,
809                                                                    anIntValue)))
810           break;
811         // Check for valid delimiter (']' or ',') 
812         if (!VrmlData_Node::OK(aStatus, ReadLine(theBuffer)))
813           break;
814         if (theBuffer.LinePtr[0] == ']') {
815           theBuffer.LinePtr++;
816           isMore = Standard_False;
817         }
818         if (anIntValue >= 0)
819         {
820           if (vecInt.Length() > 2)
821           {
822             // additional check for redundant point:
823             // ignore last point which is a dublicate of first point
824             if (anIntValue == vecInt[0])
825             {
826               continue;
827             }
828           }
829           // The input value is a node index, store it in the buffer vector
830           vecInt.Append(static_cast<Standard_Integer> (anIntValue));
831         }
832         if ((anIntValue < 0 || isMore == Standard_False)
833             && vecInt.Length() > 0)
834         {
835           const Standard_Integer aLen = vecInt.Length();
836           // The input is the end-of-face, store and close this face
837           Standard_Integer * bufFace = static_cast <Standard_Integer *>
838             (myAllocator->Allocate((aLen+1) * sizeof(Standard_Integer)));
839           if (bufFace == 0L) {
840             aStatus = VrmlData_UnrecoverableError;
841             break;
842           }
843           bufFace[0] = aLen;
844           for (Standard_Integer i = 0; i < aLen; i++)
845             bufFace[i+1] = vecInt(i);
846           vecInt.Clear();
847           vecIndice.Append(bufFace);
848         }
849       }
850       if (aStatus == VrmlData_StatusOK) {
851         const Standard_Size aNbBlocks =
852           static_cast <Standard_Size> (vecIndice.Length());
853         if (aNbBlocks) {
854           const Standard_Integer ** anArray =
855             static_cast <const Standard_Integer **>
856             (myAllocator->Allocate (aNbBlocks * sizeof(Standard_Integer *)));
857           if (anArray == 0L)
858             aStatus = VrmlData_UnrecoverableError;
859           else {
860             for (size_t i = 0; i < aNbBlocks; i++)
861               anArray[i] = vecIndice((Standard_Integer)i);
862             theNBlocks = aNbBlocks;
863             theArray = anArray;
864           } 
865         }
866       }
867     }
868   }
869   return aStatus;
870 }
871
872 //=======================================================================
873 //function : writeArrIndex
874 //purpose  : 
875 //=======================================================================
876
877 VrmlData_ErrorStatus VrmlData_Scene::WriteArrIndex
878                                 (const char *              thePrefix,
879                                  const Standard_Integer ** theArrIndex,
880                                  const Standard_Size       theNbBlocks) const
881 {
882   VrmlData_ErrorStatus aStatus (VrmlData_StatusOK);
883   if (theNbBlocks && (IsDummyWrite() == Standard_False)) {
884     if (VrmlData_Node::OK (aStatus,
885                            WriteLine (thePrefix, "[", 1)))
886     {
887       const size_t aLineLimit = (myCurrentIndent < 41) ? 36 : 100;
888       char buf[256];
889       for (Standard_Size iBlock = 0; iBlock < theNbBlocks; iBlock++) {
890         const Standard_Integer nVal (* theArrIndex[iBlock]);
891         const Standard_Integer * arrVal = theArrIndex[iBlock]+1;
892         switch (nVal) {
893         case 1:
894           Sprintf (buf, "%d,", arrVal[0]);
895           break;
896         case 2:
897           Sprintf (buf, "%d,%d,", arrVal[0], arrVal[1]);
898           break;
899         case 3:
900           Sprintf (buf, "%d,%d,%d,", arrVal[0], arrVal[1], arrVal[2]);
901           break;
902         case 4:
903           Sprintf (buf, "%d,%d,%d,%d,",
904                    arrVal[0], arrVal[1], arrVal[2], arrVal[3]);
905           break;
906         default:
907           if (nVal > 0) {
908             char * ptr = &buf[0];
909             for (Standard_Integer i = 0; i < nVal; i++) {
910               Sprintf (ptr, "%d,", arrVal[i]);
911               if (i == nVal - 1)
912                 break;
913               ptr = strchr (ptr, ',') + 1;
914               if ((ptr - &buf[0]) > (ptrdiff_t)aLineLimit) {
915                 WriteLine(buf);
916                 ptr = &buf[0];
917               }
918             }
919           }
920         }
921         WriteLine (buf, iBlock < theNbBlocks-1 ? "-1," : "-1");
922       }
923       if (aStatus == VrmlData_StatusOK)
924         aStatus = WriteLine ("]", 0L, -1);
925     }
926   }
927   return aStatus;
928 }
929
930 //=======================================================================
931 //function : WriteXYZ
932 //purpose  : 
933 //=======================================================================
934
935 VrmlData_ErrorStatus VrmlData_Scene::WriteXYZ
936                                 (const gp_XYZ&          theXYZ,
937                                  const Standard_Boolean isApplyScale,
938                                  const char             * thePostfix) const
939 {
940   char buf[240];
941   if (IsDummyWrite() == Standard_False) {
942     if (isApplyScale && myLinearScale > Precision::Confusion())
943       Sprintf (buf, "%.12g %.12g %.12g%s", theXYZ.X() / myLinearScale,
944                theXYZ.Y() / myLinearScale, theXYZ.Z() / myLinearScale,
945                thePostfix ? thePostfix : "");
946     else
947       Sprintf (buf, "%.12g %.12g %.12g%s", theXYZ.X(), theXYZ.Y(), theXYZ.Z(),
948                thePostfix ? thePostfix : "");
949   }
950   return WriteLine (buf);
951 }
952
953 //=======================================================================
954 //function : WriteLine
955 //purpose  : write the given string prepending the current indentation
956 //=======================================================================
957
958 VrmlData_ErrorStatus VrmlData_Scene::WriteLine
959                                         (const char             * theLin0,
960                                          const char             * theLin1,
961                                          const Standard_Integer theIndent) const
962 {
963   static const char spaces[] = "                                        "
964                                "                                        ";
965   VrmlData_ErrorStatus& aStatus =
966     const_cast <VrmlData_ErrorStatus&> (myStatus);
967   if (IsDummyWrite())
968     aStatus = VrmlData_StatusOK;
969   else {
970     Standard_Integer& aCurrentIndent =
971       const_cast <Standard_Integer&> (myCurrentIndent);
972     if (theIndent < 0)
973       aCurrentIndent -= myIndent;
974     if (aCurrentIndent < 0)
975       aCurrentIndent = 0;
976     if (theLin0 == 0L && theLin1 == 0L)
977       (* myOutput) << "\n";
978     else {
979       const Standard_Integer nSpaces = Min (aCurrentIndent, sizeof(spaces)-1);
980       (* myOutput) << &spaces[sizeof(spaces)-1 - nSpaces];
981       if (theLin0) {
982         (* myOutput) << theLin0;
983         if (theLin1)
984           (* myOutput) << " " << theLin1;
985       } else
986         (* myOutput) << theLin1;
987       (* myOutput) << "\n";
988     }
989     const int stat = myOutput->rdstate();
990     if (stat & std::ios::badbit)
991       aStatus = VrmlData_UnrecoverableError;
992     else if (stat & std::ios::failbit)
993 //       if (stat & std::ios::eofbit)
994 //         aStatus = VrmlData_EndOfFile;
995 //       else
996       aStatus = VrmlData_GeneralError;
997     if (theIndent > 0)
998       aCurrentIndent += myIndent;
999   }
1000   return myStatus;
1001 }
1002
1003 //=======================================================================
1004 //function : WriteNode
1005 //purpose  : 
1006 //=======================================================================
1007
1008 VrmlData_ErrorStatus VrmlData_Scene::WriteNode
1009                                 (const char *                 thePrefix,
1010                                  const Handle(VrmlData_Node)& theNode) const
1011 {
1012   VrmlData_ErrorStatus aStatus (VrmlData_StatusOK);
1013   Standard_Boolean isNoName (Standard_False);
1014   if (theNode->Name() == 0L)
1015     isNoName = Standard_True;
1016   else if (theNode->Name()[0] == '\0')
1017     isNoName = Standard_True;
1018
1019   if (theNode.IsNull() == Standard_False)
1020     if (theNode->IsDefault() == Standard_False) {
1021       if (isNoName && IsDummyWrite()) {
1022         // We are in a tentative 'write' session (nothing is written).
1023         // The goal is to identify multiply referred nodes.
1024         Standard_Address addrNode = theNode.operator->();
1025         if (!const_cast<NCollection_Map<Standard_Address>&>(myUnnamedNodesOut)
1026             .Add (addrNode))
1027         {
1028           Handle(VrmlData_UnknownNode) bidNode = new VrmlData_UnknownNode;
1029           char buf[32];
1030           do {
1031             Sprintf (buf, "_%d",
1032                      ++const_cast<Standard_Integer&>(myAutoNameCounter));
1033             bidNode->myName = &buf[0];
1034           } while (myNamedNodes.Contains (bidNode));
1035           // We found the vacant automatic name, let us assign to it.
1036           theNode->setName (&buf[0]);
1037           const_cast<VrmlData_MapOfNode&>(myNamedNodes).Add (theNode);
1038           return aStatus; // do not search under already duplicated node
1039         }
1040       }
1041       if (isNoName)
1042         aStatus = theNode->Write (thePrefix);
1043       else {
1044         // If the node name consists of blank characters, we do not write it
1045         const char * nptr = theNode->Name();
1046         for (; * nptr != '\0'; nptr++)
1047           if (* nptr != ' ' && * nptr != '\t')
1048             break;
1049         if (* nptr == '\0')
1050           aStatus = theNode->Write (thePrefix);
1051         else {
1052           // Name is written under DEF clause
1053           TCollection_AsciiString buf;
1054           if (myNamedNodesOut.Contains (theNode))
1055           {
1056             buf += "USE ";
1057             buf += theNode->Name();
1058             aStatus = WriteLine (thePrefix, buf.ToCString());
1059           } 
1060           else 
1061           {
1062             if (thePrefix)
1063             {
1064               buf += thePrefix;
1065               buf += ' ';
1066             }
1067             buf += "DEF ";
1068             buf += theNode->Name();
1069             aStatus = theNode->Write (buf.ToCString());
1070             const_cast<VrmlData_MapOfNode&>(myNamedNodesOut).Add (theNode);
1071           }
1072         }
1073       }
1074     }
1075   return aStatus;
1076 }
1077
1078 //=======================================================================
1079 //function : Dump
1080 //purpose  : 
1081 //=======================================================================
1082
1083 void VrmlData_Scene::Dump (Standard_OStream& theStream) const
1084 {
1085   theStream << " ===== Diagnostic Dump of a Scene (" << myAllNodes.Extent()
1086             << " nodes)\n";
1087
1088   /*
1089   Iterator anIterA(myAllNodes);
1090   for (; anIterA.More(); anIterA.Next())
1091     dumpNode(theStream, anIterA.Value(), "");
1092   */
1093   Iterator anIter(myLstNodes);
1094   for (; anIter.More(); anIter.Next())
1095     dumpNode(theStream, anIter.Value(), "  ");
1096 }
1097
1098 //=======================================================================
1099 //function : dumpNode
1100 //purpose  : static (local) function
1101 //=======================================================================
1102
1103 void dumpNode (Standard_OStream&                theStream,
1104                const Handle(VrmlData_Node)&     theNode,
1105                const TCollection_AsciiString&   theIndent)
1106 {
1107   if (theNode.IsNull())
1108     return;
1109   TCollection_AsciiString aNewIndent = 
1110     theIndent.IsEmpty() ? theIndent : theIndent + "  "; 
1111   if (theNode->IsKind(STANDARD_TYPE(VrmlData_Appearance))) {
1112     const Handle(VrmlData_Appearance) anAppearance = 
1113       Handle(VrmlData_Appearance)::DownCast (theNode);
1114     dumpNodeHeader (theStream, theIndent, "Appearance", theNode->Name());
1115     if (theIndent.IsEmpty() == Standard_False) {
1116       dumpNode (theStream, anAppearance->Material(), aNewIndent);
1117       dumpNode (theStream, anAppearance->Texture(), aNewIndent);
1118       dumpNode (theStream, anAppearance->TextureTransform(), aNewIndent);
1119     }
1120   } else if (theNode->IsKind(STANDARD_TYPE(VrmlData_ShapeNode))) {
1121     const Handle(VrmlData_ShapeNode) aShape = 
1122       Handle(VrmlData_ShapeNode)::DownCast (theNode);
1123     dumpNodeHeader (theStream, theIndent, "Shape", theNode->Name());
1124     if (theIndent.IsEmpty() == Standard_False) {
1125       dumpNode (theStream, aShape->Appearance(), aNewIndent);
1126       dumpNode (theStream, aShape->Geometry(), aNewIndent);
1127     }
1128   } else if (theNode->IsKind(STANDARD_TYPE(VrmlData_Box)))
1129     dumpNodeHeader (theStream, theIndent, "Box", theNode->Name());
1130   else if (theNode->IsKind(STANDARD_TYPE(VrmlData_Cylinder)))
1131     dumpNodeHeader (theStream, theIndent, "Cylinder", theNode->Name());
1132   else if (theNode->IsKind(STANDARD_TYPE(VrmlData_Sphere)))
1133     dumpNodeHeader (theStream, theIndent, "Sphere", theNode->Name());
1134   else if (theNode->IsKind(STANDARD_TYPE(VrmlData_Cone)))
1135     dumpNodeHeader (theStream, theIndent, "Cone", theNode->Name());
1136   else if (theNode->IsKind(STANDARD_TYPE(VrmlData_Coordinate)))
1137     dumpNodeHeader (theStream, theIndent, "Coordinate", theNode->Name());
1138   else if (theNode->IsKind(STANDARD_TYPE(VrmlData_Group))) {
1139     const Handle(VrmlData_Group) aGroup = 
1140       Handle(VrmlData_Group)::DownCast (theNode);
1141     char buf[64];
1142     Sprintf (buf, "Group (%s)",
1143              aGroup->IsTransform() ? "Transform" : "Group");
1144     dumpNodeHeader (theStream, theIndent, buf, theNode->Name());
1145     if (theIndent.IsEmpty() == Standard_False) {
1146       VrmlData_ListOfNode::Iterator anIter = aGroup->NodeIterator();
1147       for (; anIter.More(); anIter.Next())
1148         dumpNode (theStream, anIter.Value(), aNewIndent);
1149     }
1150   } else if (theNode->IsKind(STANDARD_TYPE(VrmlData_ImageTexture)))
1151     dumpNodeHeader (theStream, theIndent, "ImageTexture", theNode->Name());
1152   else if (theNode->IsKind(STANDARD_TYPE(VrmlData_IndexedFaceSet))) {
1153     const Handle(VrmlData_IndexedFaceSet) aNode =
1154       Handle(VrmlData_IndexedFaceSet)::DownCast(theNode);
1155     const Standard_Integer ** ppDummy; 
1156     const Standard_Size nCoord = aNode->Coordinates()->Length();
1157     const Standard_Size nPoly  = aNode->Polygons (ppDummy);
1158     char buf[80];
1159     Sprintf (buf, "IndexedFaceSet (%" PRIuPTR " vertices, %" PRIuPTR " polygons)",
1160              nCoord, nPoly);
1161
1162     dumpNodeHeader (theStream, theIndent, buf, theNode->Name());
1163   } else if (theNode->IsKind(STANDARD_TYPE(VrmlData_IndexedLineSet))) {
1164     const Handle(VrmlData_IndexedLineSet) aNode =
1165       Handle(VrmlData_IndexedLineSet)::DownCast(theNode);
1166     const Standard_Integer ** ppDummy; 
1167     const Standard_Size nCoord = aNode->Coordinates()->Length();
1168     const Standard_Size nPoly  = aNode->Polygons (ppDummy);
1169
1170     char buf[80];
1171     Sprintf(buf, "IndexedLineSet (%" PRIuPTR " vertices, %" PRIuPTR " polygons)",
1172             nCoord, nPoly);
1173
1174     dumpNodeHeader (theStream, theIndent, buf, theNode->Name());
1175   } else if (theNode->IsKind(STANDARD_TYPE(VrmlData_Material))) {
1176 //     const Handle(VrmlData_Material) aMaterial = 
1177 //       Handle(VrmlData_Material)::DownCast (theNode);
1178     dumpNodeHeader (theStream, theIndent, "Material", theNode->Name());
1179   }
1180   else if (theNode->IsKind(STANDARD_TYPE(VrmlData_Normal)))
1181     dumpNodeHeader (theStream, theIndent, "Normal", theNode->Name());
1182   else if (theNode->IsKind(STANDARD_TYPE(VrmlData_TextureCoordinate)))
1183     dumpNodeHeader (theStream, theIndent, "TextureCoordinate", theNode->Name());
1184   else if (theNode->IsKind(STANDARD_TYPE(VrmlData_WorldInfo)))
1185     dumpNodeHeader (theStream, theIndent, "WorldInfo", theNode->Name());
1186   else if (theNode->IsKind(STANDARD_TYPE(VrmlData_UnknownNode))) {
1187     const Handle(VrmlData_UnknownNode) anUnknown = 
1188       Handle(VrmlData_UnknownNode)::DownCast (theNode);
1189     char buf[64];
1190     Sprintf (buf, "Unknown (%s)", anUnknown->GetTitle().ToCString());
1191     dumpNodeHeader (theStream, theIndent, buf, theNode->Name());
1192   }
1193 }
1194
1195 //=======================================================================
1196 //function : dumpNodeHeader
1197 //purpose  : 
1198 //=======================================================================
1199
1200 void dumpNodeHeader (Standard_OStream&                  theStream,
1201                      const TCollection_AsciiString&     theIndent,
1202                      const char *                       theType,
1203                      const char *                       theName)
1204 {
1205   theStream << theIndent << theType << " node";
1206   if (theName[0] == '\0')
1207     theStream << "\n";
1208   else
1209     theStream << ": \"" << theName << "\"\n";
1210 }