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