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