1 // Created on: 2006-05-25
2 // Created by: Alexander GRIGORIEV
3 // Copyright (c) 2006-2014 OPEN CASCADE SAS
5 // This file is part of Open CASCADE Technology software library.
7 // This library is free software; you can redistribute it and/or modify it under
8 // the terms of the GNU Lesser General Public License version 2.1 as published
9 // by the Free Software Foundation, with special exception defined in the file
10 // OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
11 // distribution for complete text of the license and disclaimer of any warranty.
13 // Alternatively, this file may be used under the terms of Open CASCADE
14 // commercial license or contractual agreement.
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>
41 #include <TopoDS_Face.hxx>
42 #include <TopExp_Explorer.hxx>
43 #include <BRep_Builder.hxx>
44 #include <Precision.hxx>
47 #define _CRT_SECURE_NO_DEPRECATE
48 #pragma warning (disable:4996)
51 static void dumpNode (Standard_OStream& theStream,
52 const Handle(VrmlData_Node)& theNode,
53 const TCollection_AsciiString& theIndent);
55 static void dumpNodeHeader (Standard_OStream& theStream,
56 const TCollection_AsciiString& theIndent,
58 const char * theName);
60 //=======================================================================
61 //function : VrmlData_Scene
62 //purpose : Constructor
63 //=======================================================================
65 VrmlData_Scene::VrmlData_Scene
66 (const Handle(NCollection_IncAllocator)& theAlloc)
68 myStatus (VrmlData_StatusOK),
69 myAllocator (theAlloc.IsNull() ?
70 new NCollection_IncAllocator : theAlloc.operator->()),
77 myWorldInfo = new VrmlData_WorldInfo (* this);
78 myWorldInfo->AddInfo ("Created by OPEN CASCADE (tm) VrmlData API");
79 myLstNodes.Append (myWorldInfo);
80 myAllNodes.Append (myWorldInfo);
83 //=======================================================================
86 //=======================================================================
88 const Handle(VrmlData_Node)& VrmlData_Scene::AddNode
89 (const Handle(VrmlData_Node)& theN,
90 const Standard_Boolean isTopLevel)
92 if (theN.IsNull() == Standard_False)
93 if (theN->IsKind (STANDARD_TYPE(VrmlData_WorldInfo)) == Standard_False) {
95 const Handle(VrmlData_Node)& aNode =
96 myAllNodes.Append ((&theN->Scene()== this) ? theN : theN->Clone (NULL));
97 // Name is checked for uniqueness. If not, letter 'D' is appended until
98 // the name proves to be unique.
99 if (aNode->Name()[0] != '\0')
100 while (myNamedNodes.Add (aNode) == Standard_False)
101 aNode->setName (aNode->Name(), "D");
103 myLstNodes.Append (aNode);
107 static Handle(VrmlData_Node) aNullNode;
112 //=======================================================================
113 //function : operator <<
114 //purpose : Export to text stream (file or else)
115 //=======================================================================
117 Standard_OStream& operator << (Standard_OStream& theOutput,
118 const VrmlData_Scene& theScene)
120 VrmlData_Scene& aScene = const_cast <VrmlData_Scene&> (theScene);
121 aScene.myMutex.Lock();
122 aScene.myCurrentIndent = 0;
123 aScene.myLineError = 0;
124 aScene.myOutput = 0L;
125 aScene.myNamedNodesOut.Clear();
126 aScene.myUnnamedNodesOut.Clear();
127 aScene.myAutoNameCounter = 0;
131 VrmlData_Scene::Iterator anIterD(aScene.myLstNodes);
132 for (; anIterD.More(); anIterD.Next()) {
133 const Handle(VrmlData_Node)& aNode = anIterD.Value();
134 if (aNode.IsNull() == Standard_False) {
135 const VrmlData_ErrorStatus aStatus = aScene.WriteNode (0L, aNode);
136 if (aStatus != VrmlData_StatusOK &&
137 aStatus != VrmlData_NotImplemented)
142 aScene.myOutput = &theOutput;
143 aScene.myNamedNodesOut.Clear();
144 theOutput << "#VRML V2.0 utf8" << endl << endl;
148 VrmlData_Scene::Iterator anIter(aScene.myLstNodes);
149 for (; anIter.More(); anIter.Next()) {
150 const Handle(VrmlData_Node)& aNode = anIter.Value();
151 if (aNode.IsNull() == Standard_False) {
152 const VrmlData_ErrorStatus aStatus = aScene.WriteNode (0L, aNode);
153 if (aStatus != VrmlData_StatusOK &&
154 aStatus != VrmlData_NotImplemented)
158 aScene.myOutput = 0L;
159 aScene.myNamedNodesOut.Clear();
160 aScene.myUnnamedNodesOut.Clear();
161 aScene.myMutex.Unlock();
165 //=======================================================================
166 //function : SetVrmlDir
168 //=======================================================================
170 void VrmlData_Scene::SetVrmlDir (const TCollection_ExtendedString& theDir)
172 TCollection_ExtendedString& aDir = myVrmlDir.Append (theDir);
173 const Standard_ExtCharacter aTerminator = aDir.Value(aDir.Length());
174 if (aTerminator != Standard_ExtCharacter('\\') &&
175 aTerminator != Standard_ExtCharacter('/'))
177 aDir += TCollection_ExtendedString ("\\");
179 aDir += TCollection_ExtendedString ("/");
183 //=======================================================================
184 //function : WorldInfo
186 //=======================================================================
188 const Handle(VrmlData_WorldInfo)& VrmlData_Scene::WorldInfo() const
193 //=======================================================================
194 //function : readLine
196 //=======================================================================
198 VrmlData_ErrorStatus VrmlData_Scene::readLine (VrmlData_InBuffer& theBuffer)
200 VrmlData_ErrorStatus aStatus = VrmlData_StatusOK;
201 if (theBuffer.Input.eof())
202 aStatus = VrmlData_EndOfFile;
204 theBuffer.Input.getline (theBuffer.Line, sizeof(theBuffer.Line));
205 theBuffer.LineCount++;
206 const int stat = theBuffer.Input.rdstate();
207 if (stat & ios::badbit) {
208 aStatus = VrmlData_UnrecoverableError;
210 else if (stat & ios::failbit) {
211 if (stat & ios::eofbit) {
212 aStatus = VrmlData_EndOfFile;
215 aStatus = VrmlData_GeneralError;
218 theBuffer.LinePtr = &theBuffer.Line[0];
219 theBuffer.IsProcessed = Standard_False;
224 //=======================================================================
225 //function : ReadLine
227 //=======================================================================
229 VrmlData_ErrorStatus VrmlData_Scene::ReadLine (VrmlData_InBuffer& theBuffer)
231 VrmlData_ErrorStatus aStatus (VrmlData_StatusOK);
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 != ',')
239 if (* theBuffer.LinePtr == '\n' || * theBuffer.LinePtr == '\r' ||
240 * theBuffer.LinePtr == '#')
241 // go requesting the next line
246 // the line is empty here (no significant characters). Read the next one.
247 aStatus = readLine (theBuffer);
250 // error or EOF detected
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++) {
261 * ptr = ptr[anOffset];
262 if (* ptr == '\n' || * ptr == '\r' || * ptr == '#') {
263 if (isQuoted == Standard_False) {
267 } else if (* ptr == '\\' && isQuoted)
268 ptr[0] = ptr[++anOffset];
269 else if (* ptr == '\"')
270 isQuoted = !isQuoted;
272 theBuffer.IsProcessed = Standard_True;
277 //=======================================================================
278 //function : readHeader
280 //=======================================================================
282 VrmlData_ErrorStatus VrmlData_Scene::readHeader (VrmlData_InBuffer& theBuffer)
284 VrmlData_ErrorStatus aStat = readLine (theBuffer);
285 if (aStat == VrmlData_StatusOK &&
286 !VRMLDATA_LCOMPARE(theBuffer.LinePtr, "#VRML V2.0"))
287 aStat = VrmlData_NotVrmlFile;
289 aStat = readLine(theBuffer);
293 //=======================================================================
294 //function : operator <<
295 //purpose : Import from text stream (file or else)
296 //=======================================================================
298 VrmlData_Scene& VrmlData_Scene::operator << (Standard_IStream& theInput)
300 VrmlData_InBuffer aBuffer (theInput);
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
309 if (!VrmlData_Node::OK(myStatus, ReadLine(aBuffer))) {
310 if (myStatus == VrmlData_EndOfFile)
311 myStatus = VrmlData_StatusOK;
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)
320 if (aNode.IsNull() == Standard_False /*&&
321 !aNode->IsKind (STANDARD_TYPE(VrmlData_UnknownNode))*/)
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());
336 if (myStatus != VrmlData_StatusOK)
337 myLineError = aBuffer.LineCount;
342 //=======================================================================
343 //function : FindNode
345 //=======================================================================
347 Handle(VrmlData_Node) VrmlData_Scene::FindNode
348 (const char * theName,
349 const Handle(Standard_Type)& /*theType*/) const
351 Handle(VrmlData_Node) aResult;
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())
359 if (aResult->IsKind(theType))
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);
372 //=======================================================================
373 //function : FindNode
375 //=======================================================================
377 Handle(VrmlData_Node) VrmlData_Scene::FindNode
378 (const char * theName,
379 gp_Trsf& theLocation) const
382 Handle(VrmlData_Node) aResult;
383 Iterator anIter (myLstNodes);
384 for (; anIter.More(); anIter.Next()) {
385 const Handle(VrmlData_Node)& aNode = anIter.Value();
388 // Match a top-level node name
389 if (strcmp(aNode->Name(), theName) == 0) {
394 // Try a Group type of node
395 if (aNode->IsKind(STANDARD_TYPE(VrmlData_Group)))
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)
409 //=======================================================================
410 //function : ReadWord
412 //=======================================================================
414 VrmlData_ErrorStatus VrmlData_Scene::ReadWord
415 (VrmlData_InBuffer& theBuffer,
416 TCollection_AsciiString& theWord)
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 != ']')
425 const Standard_Integer aLen = Standard_Integer(ptr - theBuffer.LinePtr);
427 aStatus = VrmlData_StringInputError;
429 theWord = TCollection_AsciiString ((Standard_CString)theBuffer.LinePtr,
431 theBuffer.LinePtr = ptr;
437 //=======================================================================
438 //function : createNode
440 //=======================================================================
442 VrmlData_ErrorStatus VrmlData_Scene::createNode
443 (VrmlData_InBuffer& theBuffer,
444 Handle(VrmlData_Node)& theNode,
445 const Handle(Standard_Type)& theType)
447 VrmlData_ErrorStatus aStatus;
448 Handle(VrmlData_Node) aNode;
449 TCollection_AsciiString aName;
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")) {
462 const char * strName = aName.ToCString();
463 if (aStatus == VrmlData_StatusOK) {
464 // create the new node
465 if (VRMLDATA_LCOMPARE(theBuffer.LinePtr, "Appearance"))
466 aNode = new VrmlData_Appearance (* this, strName);
467 else if (VRMLDATA_LCOMPARE(theBuffer.LinePtr, "Shape"))
468 aNode = new VrmlData_ShapeNode (* this, strName);
469 else if (VRMLDATA_LCOMPARE(theBuffer.LinePtr, "Box"))
470 aNode = new VrmlData_Box (* this, strName);
471 else if (VRMLDATA_LCOMPARE(theBuffer.LinePtr, "Color"))
472 aNode = new VrmlData_Color (* this, strName);
473 else if (VRMLDATA_LCOMPARE(theBuffer.LinePtr, "Cone"))
474 aNode = new VrmlData_Cone (* this, strName);
475 else if (VRMLDATA_LCOMPARE(theBuffer.LinePtr, "Coordinate")) {
476 aNode = new VrmlData_Coordinate (* this, strName);
478 // Check for "Coordinate3"
479 if (VRMLDATA_LCOMPARE (theBuffer.LinePtr, "3"))
482 else if (VRMLDATA_LCOMPARE(theBuffer.LinePtr, "Cylinder"))
483 aNode = new VrmlData_Cylinder (* this, strName);
484 else if (VRMLDATA_LCOMPARE(theBuffer.LinePtr, "Group"))
485 aNode = new VrmlData_Group (* this, strName,
487 else if (VRMLDATA_LCOMPARE(theBuffer.LinePtr, "Transform"))
488 aNode = new VrmlData_Group (* this, strName,
490 else if (VRMLDATA_LCOMPARE(theBuffer.LinePtr, "Inline"))
491 aNode = new VrmlData_Group (* this, strName,
493 else if (VRMLDATA_LCOMPARE(theBuffer.LinePtr, "Separator"))
494 aNode = new VrmlData_Group (* this, strName,
496 else if (VRMLDATA_LCOMPARE(theBuffer.LinePtr, "Switch"))
497 aNode = new VrmlData_Group (* this, strName,
499 else if (VRMLDATA_LCOMPARE(theBuffer.LinePtr, "ImageTexture"))
500 aNode = new VrmlData_ImageTexture (* this, strName);
501 else if (VRMLDATA_LCOMPARE(theBuffer.LinePtr, "IndexedFaceSet"))
502 aNode = new VrmlData_IndexedFaceSet (* this, strName);
503 else if (VRMLDATA_LCOMPARE(theBuffer.LinePtr, "IndexedLineSet"))
504 aNode = new VrmlData_IndexedLineSet (* this, strName);
505 else if (VRMLDATA_LCOMPARE(theBuffer.LinePtr, "Material"))
506 aNode = new VrmlData_Material (* this, strName);
507 else if (VRMLDATA_LCOMPARE(theBuffer.LinePtr, "Normal"))
508 aNode = new VrmlData_Normal (* this, strName);
509 else if (VRMLDATA_LCOMPARE(theBuffer.LinePtr, "Sphere"))
510 aNode = new VrmlData_Sphere (* this, strName);
511 else if (VRMLDATA_LCOMPARE(theBuffer.LinePtr, "TextureCoordinate"))
512 aNode = new VrmlData_TextureCoordinate(* this, strName);
513 else if (VRMLDATA_LCOMPARE(theBuffer.LinePtr, "WorldInfo"))
514 aNode = new VrmlData_WorldInfo (* this, strName);
516 void * isProto = VRMLDATA_LCOMPARE(theBuffer.LinePtr, "PROTO");
517 TCollection_AsciiString aTitle;
518 aStatus = ReadWord (theBuffer, aTitle);
520 aStatus = ReadLine(theBuffer);
521 if (aStatus == VrmlData_StatusOK) {
522 if (theBuffer.LinePtr[0] != '[')
523 aStatus = VrmlData_VrmlFormatError;
526 Standard_Integer aLevelCounter(0);
527 // This loop searches for any opening bracket '['.
528 // Such bracket increments the level counter. A closing bracket decrements
529 // the counter. The loop terminates when the counter becomes negative.
530 while (aLevelCounter >= 0 &&
531 (aStatus = ReadLine(theBuffer)) == VrmlData_StatusOK) {
533 while ((aChar = theBuffer.LinePtr[0]) != '\0') {
538 } else if (aChar == ']') {
547 if (aStatus == VrmlData_StatusOK)
548 aNode = new VrmlData_UnknownNode(* this,
553 aStatus = ReadLine(theBuffer);
554 if (aNode.IsNull() == Standard_False) {
555 if (aNode->Name()[0] != '\0')
556 myNamedNodes.Add (aNode);
557 if (theType.IsNull() == Standard_False)
558 if (aNode->IsKind(theType) == Standard_False)
559 aStatus = VrmlData_VrmlFormatError;
561 if (aStatus == VrmlData_StatusOK) {
562 if (theBuffer.LinePtr[0] == '{') {
565 myAllNodes.Append(aNode);
567 aStatus = VrmlData_VrmlFormatError;
573 //=======================================================================
574 //function : operator TopoDS_Shape
576 //=======================================================================
578 VrmlData_Scene::operator TopoDS_Shape () const
581 VrmlData_Scene::createShape (aShape, myLstNodes, 0L);
585 //=======================================================================
586 //function : GetShape
588 //=======================================================================
590 TopoDS_Shape VrmlData_Scene::GetShape (VrmlData_DataMapOfShapeAppearance& aMap)
593 VrmlData_Scene::createShape (aShape, myLstNodes, &aMap);
597 //=======================================================================
598 //function : createShape
600 //=======================================================================
602 void VrmlData_Scene::createShape
603 (TopoDS_Shape& outShape,
604 const VrmlData_ListOfNode& lstNodes,
605 VrmlData_DataMapOfShapeAppearance* pMapShapeApp)
607 TopoDS_Shape aSingleShape; // used when there is a single ShapeNode
608 Standard_Boolean isSingleShape (Standard_True);
609 BRep_Builder aBuilder;
611 aBuilder.MakeCompound(TopoDS::Compound(outShape));
612 aSingleShape.Orientation(TopAbs_FORWARD);
614 Iterator anIter (lstNodes);
615 for (; anIter.More(); anIter.Next()) {
616 // Try a Shape type of node
617 const Handle(VrmlData_ShapeNode) aNodeShape =
618 Handle(VrmlData_ShapeNode)::DownCast (anIter.Value());
619 if (aNodeShape.IsNull() == Standard_False) {
620 const Handle(VrmlData_Geometry) aNodeGeom =
621 Handle(VrmlData_Geometry)::DownCast(aNodeShape->Geometry());
622 if (aNodeGeom.IsNull() == Standard_False) {
623 if (aSingleShape.IsNull() == Standard_False)
624 isSingleShape = Standard_False;
625 const Handle(TopoDS_TShape) aTShape = aNodeGeom->TShape();
626 aSingleShape.TShape(aTShape);
627 if (aSingleShape.IsNull() == Standard_False) {
628 aBuilder.Add (outShape, aSingleShape);
629 if (pMapShapeApp != 0L) {
630 const Handle(VrmlData_Appearance)& anAppearance =
631 aNodeShape->Appearance();
632 if (anAppearance.IsNull() == Standard_False) {
633 // Check if the current topology is a single face
634 if (aTShape->IsKind(STANDARD_TYPE(TopoDS_TFace)))
635 pMapShapeApp->Bind(aTShape, anAppearance);
637 // This is not a face, explode it in faces and bind each face
638 TopoDS_Shape aCurShape;
639 aCurShape.TShape(aTShape);
640 TopExp_Explorer anExp(aCurShape, TopAbs_FACE);
641 for (; anExp.More(); anExp.Next()) {
642 const TopoDS_Face& aFace = TopoDS::Face(anExp.Current());
643 pMapShapeApp->Bind(aFace.TShape(), anAppearance);
652 // Try a Group type of node
653 const Handle(VrmlData_Group) aNodeGroup =
654 Handle(VrmlData_Group)::DownCast (anIter.Value());
655 if (aNodeGroup.IsNull() == Standard_False) {
657 aNodeGroup->Shape(aShape, pMapShapeApp);
658 if (aShape.IsNull() == Standard_False) {
659 aBuilder.Add (outShape, aShape);
660 isSingleShape = Standard_False;
665 outShape = aSingleShape;
668 //=======================================================================
669 //function : ReadReal
671 //=======================================================================
673 VrmlData_ErrorStatus VrmlData_Scene::ReadReal
674 (VrmlData_InBuffer& theBuffer,
675 Standard_Real& theResult,
676 Standard_Boolean isScale,
677 Standard_Boolean isOnlyPositive) const
679 Standard_Real aResult(0.);
680 VrmlData_ErrorStatus aStatus;
681 if (VrmlData_Node::OK(aStatus, VrmlData_Scene::ReadLine(theBuffer))) {
683 aResult = Strtod (theBuffer.LinePtr, &endptr);
684 if (endptr == theBuffer.LinePtr)
685 aStatus = VrmlData_NumericInputError;
686 else if (isOnlyPositive && aResult < 0.001*Precision::Confusion())
687 aStatus = VrmlData_IrrelevantNumber;
689 theResult = isScale ? (aResult * myLinearScale) : aResult;
690 theBuffer.LinePtr = endptr;
696 //=======================================================================
699 //=======================================================================
701 VrmlData_ErrorStatus VrmlData_Scene::ReadXYZ
702 (VrmlData_InBuffer& theBuffer,
704 Standard_Boolean isScale,
705 Standard_Boolean isOnlyPos) const
707 Standard_Real aVal[3] = {0., 0., 0.};
708 VrmlData_ErrorStatus aStatus = VrmlData_StatusOK;
709 for (Standard_Integer i = 0; i < 3; i++) {
710 if (!VrmlData_Node::OK(aStatus, VrmlData_Scene::ReadLine(theBuffer)))
713 aVal[i] = Strtod (theBuffer.LinePtr, &endptr);
714 if (endptr == theBuffer.LinePtr) {
715 aStatus = VrmlData_NumericInputError;
718 if (isOnlyPos && aVal[i] < 0.001*Precision::Confusion()) {
719 aStatus = VrmlData_IrrelevantNumber;
722 theBuffer.LinePtr = endptr;
725 if (aStatus == VrmlData_StatusOK) {
727 theXYZ.SetCoord (aVal[0] * myLinearScale,
728 aVal[1] * myLinearScale,
729 aVal[2] * myLinearScale);
732 theXYZ.SetCoord (aVal[0], aVal[1], aVal[2]);
738 //=======================================================================
741 //=======================================================================
743 VrmlData_ErrorStatus VrmlData_Scene::ReadXY
744 (VrmlData_InBuffer& theBuffer,
746 Standard_Boolean isScale,
747 Standard_Boolean isOnlyPos) const
749 Standard_Real aVal[2] = {0., 0.};
750 VrmlData_ErrorStatus aStatus = VrmlData_StatusOK;
751 for (Standard_Integer i = 0; i < 2; i++) {
752 if (!VrmlData_Node::OK(aStatus, VrmlData_Scene::ReadLine(theBuffer)))
755 aVal[i] = Strtod (theBuffer.LinePtr, &endptr);
756 if (endptr == theBuffer.LinePtr) {
757 aStatus = VrmlData_NumericInputError;
760 if (isOnlyPos && aVal[i] < 0.001*Precision::Confusion()) {
761 aStatus = VrmlData_IrrelevantNumber;
764 theBuffer.LinePtr = endptr;
767 if (aStatus == VrmlData_StatusOK) {
769 theXY.SetCoord (aVal[0] * myLinearScale, aVal[1] * myLinearScale);
771 theXY.SetCoord (aVal[0], aVal[1]);
776 //=======================================================================
777 //function : ReadArrIndex
778 //purpose : Read the body of the data node (comma-separated list of int
780 //=======================================================================
782 VrmlData_ErrorStatus VrmlData_Scene::ReadArrIndex
783 (VrmlData_InBuffer& theBuffer,
784 const Standard_Integer **& theArray,
785 Standard_Size& theNBlocks) const
787 VrmlData_ErrorStatus aStatus;
789 if (VrmlData_Node::OK(aStatus, ReadLine(theBuffer))) {
790 if (theBuffer.LinePtr[0] != '[') // opening bracket
791 aStatus = VrmlData_VrmlFormatError;
794 NCollection_Vector<const Standard_Integer *> vecIndice;
795 NCollection_Vector<Standard_Integer> vecInt;
796 Standard_Boolean isMore (Standard_True);
799 // Loop reading integers from the stream
800 while (isMore && VrmlData_Node::OK(aStatus, ReadLine(theBuffer)))
802 // closing bracket, in case that it follows a comma
803 if (theBuffer.LinePtr[0] == ']') {
807 if (!VrmlData_Node::OK(aStatus, VrmlData_Node::ReadInteger(theBuffer,
810 // Check for valid delimiter (']' or ',')
811 if (!VrmlData_Node::OK(aStatus, ReadLine(theBuffer)))
813 if (theBuffer.LinePtr[0] == ']') {
815 isMore = Standard_False;
818 // The input value is a node index, store it in the buffer vector
819 vecInt.Append (static_cast<Standard_Integer> (anIntValue));
820 if ((anIntValue < 0 || isMore == Standard_False)
821 && vecInt.Length() > 0)
823 const Standard_Integer aLen = vecInt.Length();
824 // The input is the end-of-face, store and close this face
825 Standard_Integer * bufFace = static_cast <Standard_Integer *>
826 (myAllocator->Allocate((aLen+1) * sizeof(Standard_Integer)));
828 aStatus = VrmlData_UnrecoverableError;
832 for (Standard_Integer i = 0; i < aLen; i++)
833 bufFace[i+1] = vecInt(i);
835 vecIndice.Append(bufFace);
838 if (aStatus == VrmlData_StatusOK) {
839 const Standard_Size aNbBlocks =
840 static_cast <Standard_Size> (vecIndice.Length());
842 const Standard_Integer ** anArray =
843 static_cast <const Standard_Integer **>
844 (myAllocator->Allocate (aNbBlocks * sizeof(Standard_Integer *)));
846 aStatus = VrmlData_UnrecoverableError;
848 for (size_t i = 0; i < aNbBlocks; i++)
849 anArray[i] = vecIndice((Standard_Integer)i);
850 theNBlocks = aNbBlocks;
860 //=======================================================================
861 //function : writeArrIndex
863 //=======================================================================
865 VrmlData_ErrorStatus VrmlData_Scene::WriteArrIndex
866 (const char * thePrefix,
867 const Standard_Integer ** theArrIndex,
868 const Standard_Size theNbBlocks) const
870 VrmlData_ErrorStatus aStatus (VrmlData_StatusOK);
871 if (theNbBlocks && (IsDummyWrite() == Standard_False)) {
872 if (VrmlData_Node::OK (aStatus,
873 WriteLine (thePrefix, "[", 1)))
875 const size_t aLineLimit = (myCurrentIndent < 41) ? 36 : 100;
877 for (Standard_Size iBlock = 0; iBlock < theNbBlocks; iBlock++) {
878 const Standard_Integer nVal (* theArrIndex[iBlock]);
879 const Standard_Integer * arrVal = theArrIndex[iBlock]+1;
882 Sprintf (buf, "%d,", arrVal[0]);
885 Sprintf (buf, "%d,%d,", arrVal[0], arrVal[1]);
888 Sprintf (buf, "%d,%d,%d,", arrVal[0], arrVal[1], arrVal[2]);
891 Sprintf (buf, "%d,%d,%d,%d,",
892 arrVal[0], arrVal[1], arrVal[2], arrVal[3]);
896 char * ptr = &buf[0];
897 for (Standard_Integer i = 0; i < nVal; i++) {
898 Sprintf (ptr, "%d,", arrVal[i]);
899 ptr = strchr (ptr, ',') + 1;
900 if ((ptr - &buf[0]) > (ptrdiff_t)aLineLimit) {
907 WriteLine (buf, iBlock < theNbBlocks-1 ? "-1," : "-1");
909 if (aStatus == VrmlData_StatusOK)
910 aStatus = WriteLine ("]", 0L, -1);
916 //=======================================================================
917 //function : WriteXYZ
919 //=======================================================================
921 VrmlData_ErrorStatus VrmlData_Scene::WriteXYZ
922 (const gp_XYZ& theXYZ,
923 const Standard_Boolean isApplyScale,
924 const char * thePostfix) const
927 if (IsDummyWrite() == Standard_False) {
928 if (isApplyScale && myLinearScale > Precision::Confusion())
929 Sprintf (buf, "%.12g %.12g %.12g%s", theXYZ.X() / myLinearScale,
930 theXYZ.Y() / myLinearScale, theXYZ.Z() / myLinearScale,
931 thePostfix ? thePostfix : "");
933 Sprintf (buf, "%.12g %.12g %.12g%s", theXYZ.X(), theXYZ.Y(), theXYZ.Z(),
934 thePostfix ? thePostfix : "");
936 return WriteLine (buf);
939 //=======================================================================
940 //function : WriteLine
941 //purpose : write the given string prepending the current indentation
942 //=======================================================================
944 VrmlData_ErrorStatus VrmlData_Scene::WriteLine
945 (const char * theLin0,
946 const char * theLin1,
947 const Standard_Integer theIndent) const
949 static const char spaces[] = " "
951 VrmlData_ErrorStatus& aStatus =
952 const_cast <VrmlData_ErrorStatus&> (myStatus);
954 aStatus = VrmlData_StatusOK;
956 Standard_Integer& aCurrentIndent =
957 const_cast <Standard_Integer&> (myCurrentIndent);
959 aCurrentIndent -= myIndent;
960 if (aCurrentIndent < 0)
962 if (theLin0 == 0L && theLin1 == 0L)
963 (* myOutput) << endl;
965 const Standard_Integer nSpaces = Min (aCurrentIndent, sizeof(spaces)-1);
966 (* myOutput) << &spaces[sizeof(spaces)-1 - nSpaces];
968 (* myOutput) << theLin0;
970 (* myOutput) << ' ' << theLin1;
972 (* myOutput) << theLin1;
973 (* myOutput) << endl;
975 const int stat = myOutput->rdstate();
976 if (stat & ios::badbit)
977 aStatus = VrmlData_UnrecoverableError;
978 else if (stat & ios::failbit)
979 // if (stat & ios::eofbit)
980 // aStatus = VrmlData_EndOfFile;
982 aStatus = VrmlData_GeneralError;
984 aCurrentIndent += myIndent;
989 //=======================================================================
990 //function : WriteNode
992 //=======================================================================
994 VrmlData_ErrorStatus VrmlData_Scene::WriteNode
995 (const char * thePrefix,
996 const Handle(VrmlData_Node)& theNode) const
998 VrmlData_ErrorStatus aStatus (VrmlData_StatusOK);
999 Standard_Boolean isNoName (Standard_False);
1000 if (theNode->Name() == 0L)
1001 isNoName = Standard_True;
1002 else if (theNode->Name()[0] == '\0')
1003 isNoName = Standard_True;
1005 if (theNode.IsNull() == Standard_False)
1006 if (theNode->IsDefault() == Standard_False) {
1007 if (isNoName && IsDummyWrite()) {
1008 // We are in a tentative 'write' session (nothing is written).
1009 // The goal is to identify multiply referred nodes.
1010 Standard_Address addrNode = theNode.operator->();
1011 if (!const_cast<NCollection_Map<Standard_Address>&>(myUnnamedNodesOut)
1014 Handle(VrmlData_UnknownNode) bidNode = new VrmlData_UnknownNode;
1017 Sprintf (buf, "_%d",
1018 ++const_cast<Standard_Integer&>(myAutoNameCounter));
1019 bidNode->myName = &buf[0];
1020 } while (myNamedNodes.Contains (bidNode));
1021 // We found the vacant automatic name, let us assign to it.
1022 theNode->setName (&buf[0]);
1023 const_cast<VrmlData_MapOfNode&>(myNamedNodes).Add (theNode);
1024 return aStatus; // do not search under already duplicated node
1028 aStatus = theNode->Write (thePrefix);
1030 // If the node name consists of blank characters, we do not write it
1031 const char * nptr = theNode->Name();
1032 for (; * nptr != '\0'; nptr++)
1033 if (* nptr != ' ' && * nptr != '\t')
1036 aStatus = theNode->Write (thePrefix);
1038 // Name is written under DEF clause
1039 TCollection_AsciiString buf;
1040 if (myNamedNodesOut.Contains (theNode))
1043 buf += theNode->Name();
1044 aStatus = WriteLine (thePrefix, buf.ToCString());
1054 buf += theNode->Name();
1055 aStatus = theNode->Write (buf.ToCString());
1056 const_cast<VrmlData_MapOfNode&>(myNamedNodesOut).Add (theNode);
1064 //=======================================================================
1067 //=======================================================================
1069 void VrmlData_Scene::Dump (Standard_OStream& theStream) const
1071 theStream << " ===== Diagnostic Dump of a Scene (" << myAllNodes.Extent()
1072 << " nodes)" << endl;
1075 Iterator anIterA(myAllNodes);
1076 for (; anIterA.More(); anIterA.Next())
1077 dumpNode(theStream, anIterA.Value(), "");
1079 Iterator anIter(myLstNodes);
1080 for (; anIter.More(); anIter.Next())
1081 dumpNode(theStream, anIter.Value(), " ");
1084 //=======================================================================
1085 //function : dumpNode
1086 //purpose : static (local) function
1087 //=======================================================================
1089 void dumpNode (Standard_OStream& theStream,
1090 const Handle(VrmlData_Node)& theNode,
1091 const TCollection_AsciiString& theIndent)
1093 if (theNode.IsNull())
1095 TCollection_AsciiString aNewIndent =
1096 theIndent.IsEmpty() ? theIndent : theIndent + " ";
1097 if (theNode->IsKind(STANDARD_TYPE(VrmlData_Appearance))) {
1098 const Handle(VrmlData_Appearance) anAppearance =
1099 Handle(VrmlData_Appearance)::DownCast (theNode);
1100 dumpNodeHeader (theStream, theIndent, "Appearance", theNode->Name());
1101 if (theIndent.IsEmpty() == Standard_False) {
1102 dumpNode (theStream, anAppearance->Material(), aNewIndent);
1103 dumpNode (theStream, anAppearance->Texture(), aNewIndent);
1104 dumpNode (theStream, anAppearance->TextureTransform(), aNewIndent);
1106 } else if (theNode->IsKind(STANDARD_TYPE(VrmlData_ShapeNode))) {
1107 const Handle(VrmlData_ShapeNode) aShape =
1108 Handle(VrmlData_ShapeNode)::DownCast (theNode);
1109 dumpNodeHeader (theStream, theIndent, "Shape", theNode->Name());
1110 if (theIndent.IsEmpty() == Standard_False) {
1111 dumpNode (theStream, aShape->Appearance(), aNewIndent);
1112 dumpNode (theStream, aShape->Geometry(), aNewIndent);
1114 } else if (theNode->IsKind(STANDARD_TYPE(VrmlData_Box)))
1115 dumpNodeHeader (theStream, theIndent, "Box", theNode->Name());
1116 else if (theNode->IsKind(STANDARD_TYPE(VrmlData_Cylinder)))
1117 dumpNodeHeader (theStream, theIndent, "Cylinder", theNode->Name());
1118 else if (theNode->IsKind(STANDARD_TYPE(VrmlData_Sphere)))
1119 dumpNodeHeader (theStream, theIndent, "Sphere", theNode->Name());
1120 else if (theNode->IsKind(STANDARD_TYPE(VrmlData_Cone)))
1121 dumpNodeHeader (theStream, theIndent, "Cone", theNode->Name());
1122 else if (theNode->IsKind(STANDARD_TYPE(VrmlData_Coordinate)))
1123 dumpNodeHeader (theStream, theIndent, "Coordinate", theNode->Name());
1124 else if (theNode->IsKind(STANDARD_TYPE(VrmlData_Group))) {
1125 const Handle(VrmlData_Group) aGroup =
1126 Handle(VrmlData_Group)::DownCast (theNode);
1128 Sprintf (buf, "Group (%s)",
1129 aGroup->IsTransform() ? "Transform" : "Group");
1130 dumpNodeHeader (theStream, theIndent, buf, theNode->Name());
1131 if (theIndent.IsEmpty() == Standard_False) {
1132 VrmlData_ListOfNode::Iterator anIter = aGroup->NodeIterator();
1133 for (; anIter.More(); anIter.Next())
1134 dumpNode (theStream, anIter.Value(), aNewIndent);
1136 } else if (theNode->IsKind(STANDARD_TYPE(VrmlData_ImageTexture)))
1137 dumpNodeHeader (theStream, theIndent, "ImageTexture", theNode->Name());
1138 else if (theNode->IsKind(STANDARD_TYPE(VrmlData_IndexedFaceSet))) {
1139 const Handle(VrmlData_IndexedFaceSet) aNode =
1140 Handle(VrmlData_IndexedFaceSet)::DownCast(theNode);
1141 const Standard_Integer ** ppDummy;
1142 const Standard_Size nCoord = aNode->Coordinates()->Length();
1143 const Standard_Size nPoly = aNode->Polygons (ppDummy);
1145 Sprintf (buf, "IndexedFaceSet (%" PRIuPTR " vertices, %" PRIuPTR " polygons)",
1148 dumpNodeHeader (theStream, theIndent, buf, theNode->Name());
1149 } else if (theNode->IsKind(STANDARD_TYPE(VrmlData_IndexedLineSet))) {
1150 const Handle(VrmlData_IndexedLineSet) aNode =
1151 Handle(VrmlData_IndexedLineSet)::DownCast(theNode);
1152 const Standard_Integer ** ppDummy;
1153 const Standard_Size nCoord = aNode->Coordinates()->Length();
1154 const Standard_Size nPoly = aNode->Polygons (ppDummy);
1157 Sprintf(buf, "IndexedLineSet (%" PRIuPTR " vertices, %" PRIuPTR " polygons)",
1160 dumpNodeHeader (theStream, theIndent, buf, theNode->Name());
1161 } else if (theNode->IsKind(STANDARD_TYPE(VrmlData_Material))) {
1162 // const Handle(VrmlData_Material) aMaterial =
1163 // Handle(VrmlData_Material)::DownCast (theNode);
1164 dumpNodeHeader (theStream, theIndent, "Material", theNode->Name());
1166 else if (theNode->IsKind(STANDARD_TYPE(VrmlData_Normal)))
1167 dumpNodeHeader (theStream, theIndent, "Normal", theNode->Name());
1168 else if (theNode->IsKind(STANDARD_TYPE(VrmlData_TextureCoordinate)))
1169 dumpNodeHeader (theStream, theIndent, "TextureCoordinate", theNode->Name());
1170 else if (theNode->IsKind(STANDARD_TYPE(VrmlData_WorldInfo)))
1171 dumpNodeHeader (theStream, theIndent, "WorldInfo", theNode->Name());
1172 else if (theNode->IsKind(STANDARD_TYPE(VrmlData_UnknownNode))) {
1173 const Handle(VrmlData_UnknownNode) anUnknown =
1174 Handle(VrmlData_UnknownNode)::DownCast (theNode);
1176 Sprintf (buf, "Unknown (%s)", anUnknown->GetTitle().ToCString());
1177 dumpNodeHeader (theStream, theIndent, buf, theNode->Name());
1181 //=======================================================================
1182 //function : dumpNodeHeader
1184 //=======================================================================
1186 void dumpNodeHeader (Standard_OStream& theStream,
1187 const TCollection_AsciiString& theIndent,
1188 const char * theType,
1189 const char * theName)
1191 theStream << theIndent << theType <<" node";
1192 if (theName[0] == '\0')
1195 theStream << ": \"" << theName << '\"' << endl;