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