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>
45 #include <Standard_Version.hxx>
46 #include <VrmlData_WorldInfo.hxx>
47 #include <VrmlData_Geometry.hxx>
50 #define _CRT_SECURE_NO_DEPRECATE
51 #pragma warning (disable:4996)
54 static void dumpNode (Standard_OStream& theStream,
55 const Handle(VrmlData_Node)& theNode,
56 const TCollection_AsciiString& theIndent);
58 static void dumpNodeHeader (Standard_OStream& theStream,
59 const TCollection_AsciiString& theIndent,
61 const char * theName);
63 //=======================================================================
64 //function : VrmlData_Scene
65 //purpose : Constructor
66 //=======================================================================
68 VrmlData_Scene::VrmlData_Scene
69 (const Handle(NCollection_IncAllocator)& theAlloc)
71 myStatus (VrmlData_StatusOK),
72 myAllocator (theAlloc.IsNull() ?
73 new NCollection_IncAllocator : theAlloc.operator->()),
80 myWorldInfo = new VrmlData_WorldInfo (* this);
81 Standard_CString anInfo = "Generated by Open CASCADE Technology " OCC_VERSION_STRING;
82 myWorldInfo->AddInfo (anInfo);
83 myLstNodes.Append (myWorldInfo);
84 myAllNodes.Append (myWorldInfo);
87 //=======================================================================
90 //=======================================================================
92 const Handle(VrmlData_Node)& VrmlData_Scene::AddNode
93 (const Handle(VrmlData_Node)& theN,
94 const Standard_Boolean isTopLevel)
96 if (theN.IsNull() == Standard_False)
97 if (theN->IsKind (STANDARD_TYPE(VrmlData_WorldInfo)) == Standard_False) {
99 const Handle(VrmlData_Node)& aNode =
100 myAllNodes.Append ((&theN->Scene()== this) ? theN : theN->Clone (NULL));
101 // Name is checked for uniqueness. If not, letter 'D' is appended until
102 // the name proves to be unique.
103 if (aNode->Name()[0] != '\0')
104 while (myNamedNodes.Add (aNode) == Standard_False)
105 aNode->setName (aNode->Name(), "D");
107 myLstNodes.Append (aNode);
111 static Handle(VrmlData_Node) aNullNode;
116 //=======================================================================
117 //function : operator <<
118 //purpose : Export to text stream (file or else)
119 //=======================================================================
121 Standard_OStream& operator << (Standard_OStream& theOutput,
122 const VrmlData_Scene& theScene)
124 VrmlData_Scene& aScene = const_cast <VrmlData_Scene&> (theScene);
125 aScene.myMutex.Lock();
126 aScene.myCurrentIndent = 0;
127 aScene.myLineError = 0;
128 aScene.myOutput = 0L;
129 aScene.myNamedNodesOut.Clear();
130 aScene.myUnnamedNodesOut.Clear();
131 aScene.myAutoNameCounter = 0;
135 VrmlData_Scene::Iterator anIterD(aScene.myLstNodes);
136 for (; anIterD.More(); anIterD.Next()) {
137 const Handle(VrmlData_Node)& aNode = anIterD.Value();
138 if (aNode.IsNull() == Standard_False) {
139 const VrmlData_ErrorStatus aStatus = aScene.WriteNode (0L, aNode);
140 if (aStatus != VrmlData_StatusOK &&
141 aStatus != VrmlData_NotImplemented)
146 aScene.myOutput = &theOutput;
147 aScene.myNamedNodesOut.Clear();
148 theOutput << "#VRML V2.0 utf8\n\n";
152 VrmlData_Scene::Iterator anIter(aScene.myLstNodes);
153 for (; anIter.More(); anIter.Next()) {
154 const Handle(VrmlData_Node)& aNode = anIter.Value();
155 if (aNode.IsNull() == Standard_False) {
156 const VrmlData_ErrorStatus aStatus = aScene.WriteNode (0L, aNode);
157 if (aStatus != VrmlData_StatusOK &&
158 aStatus != VrmlData_NotImplemented)
162 aScene.myOutput = 0L;
163 aScene.myNamedNodesOut.Clear();
164 aScene.myUnnamedNodesOut.Clear();
165 aScene.myMutex.Unlock();
169 //=======================================================================
170 //function : SetVrmlDir
172 //=======================================================================
174 void VrmlData_Scene::SetVrmlDir (const TCollection_ExtendedString& theDir)
176 TCollection_ExtendedString& aDir = myVrmlDir.Append (theDir);
177 const Standard_ExtCharacter aTerminator = aDir.Value(aDir.Length());
178 if (aTerminator != Standard_ExtCharacter('\\') &&
179 aTerminator != Standard_ExtCharacter('/'))
181 aDir += TCollection_ExtendedString ("\\");
183 aDir += TCollection_ExtendedString ("/");
187 //=======================================================================
188 //function : WorldInfo
190 //=======================================================================
192 const Handle(VrmlData_WorldInfo)& VrmlData_Scene::WorldInfo() const
197 //=======================================================================
198 //function : readLine
200 //=======================================================================
202 VrmlData_ErrorStatus VrmlData_Scene::readLine (VrmlData_InBuffer& theBuffer)
204 VrmlData_ErrorStatus aStatus = VrmlData_StatusOK;
205 if (theBuffer.Input.eof())
206 aStatus = VrmlData_EndOfFile;
208 theBuffer.Input.getline (theBuffer.Line, sizeof(theBuffer.Line));
209 theBuffer.LineCount++;
210 const int stat = theBuffer.Input.rdstate();
211 if (stat & ios::badbit) {
212 aStatus = VrmlData_UnrecoverableError;
214 else if (stat & ios::failbit) {
215 if (stat & ios::eofbit) {
216 aStatus = VrmlData_EndOfFile;
219 aStatus = VrmlData_GeneralError;
222 theBuffer.LinePtr = &theBuffer.Line[0];
223 theBuffer.IsProcessed = Standard_False;
228 //=======================================================================
229 //function : ReadLine
231 //=======================================================================
233 VrmlData_ErrorStatus VrmlData_Scene::ReadLine (VrmlData_InBuffer& theBuffer)
235 VrmlData_ErrorStatus aStatus (VrmlData_StatusOK);
237 while (aStatus == VrmlData_StatusOK) {
238 // Find the first significant character of the line
239 for (; * theBuffer.LinePtr != '\0'; theBuffer.LinePtr++) {
240 if (* theBuffer.LinePtr != ' ' && * theBuffer.LinePtr != '\t'
241 && * theBuffer.LinePtr != ',')
243 if (* theBuffer.LinePtr == '\n' || * theBuffer.LinePtr == '\r' ||
244 * theBuffer.LinePtr == '#')
245 // go requesting the next line
250 // the line is empty here (no significant characters). Read the next one.
251 aStatus = readLine (theBuffer);
254 // error or EOF detected
258 // Try to detect comment
259 if (theBuffer.IsProcessed == Standard_False) {
260 Standard_Boolean isQuoted (Standard_False);
261 Standard_Integer anOffset (0);
262 char * ptr = theBuffer.LinePtr;
263 for (; * ptr != '\0'; ptr++) {
265 * ptr = ptr[anOffset];
266 if (* ptr == '\n' || * ptr == '\r' || * ptr == '#') {
267 if (isQuoted == Standard_False) {
271 } else if (* ptr == '\\' && isQuoted)
272 ptr[0] = ptr[++anOffset];
273 else if (* ptr == '\"')
274 isQuoted = !isQuoted;
276 theBuffer.IsProcessed = Standard_True;
281 //=======================================================================
282 //function : readHeader
284 //=======================================================================
286 VrmlData_ErrorStatus VrmlData_Scene::readHeader (VrmlData_InBuffer& theBuffer)
288 VrmlData_ErrorStatus aStat = readLine (theBuffer);
289 if (aStat == VrmlData_StatusOK &&
290 !VRMLDATA_LCOMPARE(theBuffer.LinePtr, "#VRML V2.0"))
291 aStat = VrmlData_NotVrmlFile;
293 aStat = readLine(theBuffer);
297 //=======================================================================
298 //function : operator <<
299 //purpose : Import from text stream (file or else)
300 //=======================================================================
302 VrmlData_Scene& VrmlData_Scene::operator << (Standard_IStream& theInput)
304 VrmlData_InBuffer aBuffer (theInput);
306 // Read the VRML header
307 myStatus = readHeader (aBuffer);
308 const Handle(VrmlData_UnknownNode) aNullNode= new VrmlData_UnknownNode(*this);
309 // if (myStatus == StatusOK)
310 // myStatus = ReadLine (aBuffer);
311 // Read VRML data by nodes
313 if (!VrmlData_Node::OK(myStatus, ReadLine(aBuffer))) {
314 if (myStatus == VrmlData_EndOfFile)
315 myStatus = VrmlData_StatusOK;
318 // this line provides the method ReadNode in the present context
319 Handle(VrmlData_Node) aNode;
320 myStatus = aNullNode->ReadNode (aBuffer, aNode);
321 // Unknown nodes are not stored however they do not generate error
322 if (myStatus != VrmlData_StatusOK)
324 if (aNode.IsNull() == Standard_False /*&&
325 !aNode->IsKind (STANDARD_TYPE(VrmlData_UnknownNode))*/)
327 if (aNode->IsKind (STANDARD_TYPE(VrmlData_WorldInfo)) == Standard_False)
328 myLstNodes.Append (aNode);
329 else if (aNode->IsDefault() == Standard_False) {
330 const Handle(VrmlData_WorldInfo) aInfo =
331 Handle(VrmlData_WorldInfo)::DownCast (aNode);
332 myWorldInfo->SetTitle (aInfo->Title());
333 NCollection_List <const char *>::Iterator anIterInfo =
334 aInfo->InfoIterator();
335 for (; anIterInfo.More(); anIterInfo.Next())
336 myWorldInfo->AddInfo (anIterInfo.Value());
340 if (myStatus != VrmlData_StatusOK)
341 myLineError = aBuffer.LineCount;
346 //=======================================================================
347 //function : FindNode
349 //=======================================================================
351 Handle(VrmlData_Node) VrmlData_Scene::FindNode
352 (const char * theName,
353 const Handle(Standard_Type)& /*theType*/) const
355 Handle(VrmlData_Node) aResult;
357 Iterator anIter (myAllNodes);
358 for (; anIter.More(); anIter.Next())
359 if (!strcmp (anIter.Value()->Name(), theName)) {
360 aResult = anIter.Value();
361 if (theType.IsNull())
363 if (aResult->IsKind(theType))
368 const Handle(VrmlData_UnknownNode) aDummyNode = new VrmlData_UnknownNode;
369 aDummyNode->myName = theName;
370 if (myNamedNodes.Contains (aDummyNode))
371 aResult = const_cast<VrmlData_MapOfNode&>(myNamedNodes).Added(aDummyNode);
376 //=======================================================================
377 //function : FindNode
379 //=======================================================================
381 Handle(VrmlData_Node) VrmlData_Scene::FindNode
382 (const char * theName,
383 gp_Trsf& theLocation) const
386 Handle(VrmlData_Node) aResult;
387 Iterator anIter (myLstNodes);
388 for (; anIter.More(); anIter.Next()) {
389 const Handle(VrmlData_Node)& aNode = anIter.Value();
392 // Match a top-level node name
393 if (strcmp(aNode->Name(), theName) == 0) {
398 // Try a Group type of node
399 if (aNode->IsKind(STANDARD_TYPE(VrmlData_Group)))
401 const Handle(VrmlData_Group) aGroup =
402 Handle(VrmlData_Group)::DownCast (aNode);
403 if (aGroup.IsNull() == Standard_False) {
404 aResult = aGroup->FindNode(theName, theLocation);
405 if (aResult.IsNull() == Standard_False)
413 //=======================================================================
414 //function : ReadWord
416 //=======================================================================
418 VrmlData_ErrorStatus VrmlData_Scene::ReadWord
419 (VrmlData_InBuffer& theBuffer,
420 TCollection_AsciiString& theWord)
422 VrmlData_ErrorStatus aStatus = ReadLine(theBuffer);
423 if (aStatus == VrmlData_StatusOK) {
424 char * ptr = theBuffer.LinePtr;
425 while (* ptr != '\0' && * ptr != '\n' && * ptr != '\r' &&
426 * ptr != ' ' && * ptr != '\t' && * ptr != '{' && * ptr != '}' &&
427 * ptr != ',' && * ptr != '[' && * ptr != ']')
429 const Standard_Integer aLen = Standard_Integer(ptr - theBuffer.LinePtr);
431 aStatus = VrmlData_StringInputError;
433 theWord = TCollection_AsciiString ((Standard_CString)theBuffer.LinePtr,
435 theBuffer.LinePtr = ptr;
441 //=======================================================================
442 //function : createNode
444 //=======================================================================
446 VrmlData_ErrorStatus VrmlData_Scene::createNode
447 (VrmlData_InBuffer& theBuffer,
448 Handle(VrmlData_Node)& theNode,
449 const Handle(Standard_Type)& theType)
451 VrmlData_ErrorStatus aStatus;
452 Handle(VrmlData_Node) aNode;
453 TCollection_AsciiString aName;
455 // Read the DEF token to assign the node name
456 if (VrmlData_Node::OK(aStatus, ReadLine(theBuffer))) {
457 if (VRMLDATA_LCOMPARE(theBuffer.LinePtr, "DEF")) {
458 if (VrmlData_Node::OK(aStatus, ReadWord (theBuffer, aName)))
459 aStatus = ReadLine(theBuffer);
460 } else if (VRMLDATA_LCOMPARE(theBuffer.LinePtr, "NULL")) {
466 const char * strName = aName.ToCString();
467 if (aStatus == VrmlData_StatusOK) {
468 // create the new node
469 if (VRMLDATA_LCOMPARE(theBuffer.LinePtr, "Appearance"))
470 aNode = new VrmlData_Appearance (* this, strName);
471 else if (VRMLDATA_LCOMPARE(theBuffer.LinePtr, "Shape"))
472 aNode = new VrmlData_ShapeNode (* this, strName);
473 else if (VRMLDATA_LCOMPARE(theBuffer.LinePtr, "Box"))
474 aNode = new VrmlData_Box (* this, strName);
475 else if (VRMLDATA_LCOMPARE(theBuffer.LinePtr, "Color"))
476 aNode = new VrmlData_Color (* this, strName);
477 else if (VRMLDATA_LCOMPARE(theBuffer.LinePtr, "Cone"))
478 aNode = new VrmlData_Cone (* this, strName);
479 else if (VRMLDATA_LCOMPARE(theBuffer.LinePtr, "Coordinate")) {
480 aNode = new VrmlData_Coordinate (* this, strName);
482 // Check for "Coordinate3"
483 if (VRMLDATA_LCOMPARE (theBuffer.LinePtr, "3"))
486 else if (VRMLDATA_LCOMPARE(theBuffer.LinePtr, "Cylinder"))
487 aNode = new VrmlData_Cylinder (* this, strName);
488 else if (VRMLDATA_LCOMPARE(theBuffer.LinePtr, "Group"))
489 aNode = new VrmlData_Group (* this, strName,
491 else if (VRMLDATA_LCOMPARE(theBuffer.LinePtr, "Transform"))
492 aNode = new VrmlData_Group (* this, strName,
494 else if (VRMLDATA_LCOMPARE(theBuffer.LinePtr, "Inline"))
495 aNode = new VrmlData_Group (* this, strName,
497 else if (VRMLDATA_LCOMPARE(theBuffer.LinePtr, "Separator"))
498 aNode = new VrmlData_Group (* this, strName,
500 else if (VRMLDATA_LCOMPARE(theBuffer.LinePtr, "Collision"))
501 aNode = new VrmlData_Group (* this, strName,
503 else if (VRMLDATA_LCOMPARE(theBuffer.LinePtr, "Switch"))
504 aNode = new VrmlData_Group (* this, strName,
506 else if (VRMLDATA_LCOMPARE(theBuffer.LinePtr, "ImageTexture"))
507 aNode = new VrmlData_ImageTexture (* this, strName);
508 else if (VRMLDATA_LCOMPARE(theBuffer.LinePtr, "IndexedFaceSet"))
509 aNode = new VrmlData_IndexedFaceSet (* this, strName);
510 else if (VRMLDATA_LCOMPARE(theBuffer.LinePtr, "IndexedLineSet"))
511 aNode = new VrmlData_IndexedLineSet (* this, strName);
512 else if (VRMLDATA_LCOMPARE(theBuffer.LinePtr, "Material"))
513 aNode = new VrmlData_Material (* this, strName);
514 else if (VRMLDATA_LCOMPARE(theBuffer.LinePtr, "Normal"))
515 aNode = new VrmlData_Normal (* this, strName);
516 else if (VRMLDATA_LCOMPARE(theBuffer.LinePtr, "Sphere"))
517 aNode = new VrmlData_Sphere (* this, strName);
518 else if (VRMLDATA_LCOMPARE(theBuffer.LinePtr, "TextureCoordinate"))
519 aNode = new VrmlData_TextureCoordinate(* this, strName);
520 else if (VRMLDATA_LCOMPARE(theBuffer.LinePtr, "WorldInfo"))
521 aNode = new VrmlData_WorldInfo (* this, strName);
523 void * isProto = VRMLDATA_LCOMPARE(theBuffer.LinePtr, "PROTO");
524 TCollection_AsciiString aTitle;
525 aStatus = ReadWord (theBuffer, aTitle);
527 aStatus = ReadLine(theBuffer);
528 if (aStatus == VrmlData_StatusOK) {
529 if (theBuffer.LinePtr[0] != '[')
530 aStatus = VrmlData_VrmlFormatError;
533 Standard_Integer aLevelCounter(0);
534 // This loop searches for any opening bracket '['.
535 // Such bracket increments the level counter. A closing bracket decrements
536 // the counter. The loop terminates when the counter becomes negative.
537 while (aLevelCounter >= 0 &&
538 (aStatus = ReadLine(theBuffer)) == VrmlData_StatusOK) {
540 while ((aChar = theBuffer.LinePtr[0]) != '\0') {
545 } else if (aChar == ']') {
554 if (aStatus == VrmlData_StatusOK)
555 aNode = new VrmlData_UnknownNode(* this,
560 aStatus = ReadLine(theBuffer);
561 if (aNode.IsNull() == Standard_False) {
562 if (aNode->Name()[0] != '\0')
563 myNamedNodes.Add (aNode);
564 if (theType.IsNull() == Standard_False)
565 if (aNode->IsKind(theType) == Standard_False)
566 aStatus = VrmlData_VrmlFormatError;
568 if (aStatus == VrmlData_StatusOK) {
569 if (theBuffer.LinePtr[0] == '{') {
572 myAllNodes.Append(aNode);
574 aStatus = VrmlData_VrmlFormatError;
580 //=======================================================================
581 //function : operator TopoDS_Shape
583 //=======================================================================
585 VrmlData_Scene::operator TopoDS_Shape () const
588 VrmlData_Scene::createShape (aShape, myLstNodes, 0L);
592 //=======================================================================
593 //function : GetShape
595 //=======================================================================
597 TopoDS_Shape VrmlData_Scene::GetShape (VrmlData_DataMapOfShapeAppearance& aMap)
600 VrmlData_Scene::createShape (aShape, myLstNodes, &aMap);
604 //=======================================================================
605 //function : createShape
607 //=======================================================================
609 void VrmlData_Scene::createShape
610 (TopoDS_Shape& outShape,
611 const VrmlData_ListOfNode& lstNodes,
612 VrmlData_DataMapOfShapeAppearance* pMapShapeApp)
614 TopoDS_Shape aSingleShape; // used when there is a single ShapeNode
615 Standard_Boolean isSingleShape (Standard_True);
616 BRep_Builder aBuilder;
618 aBuilder.MakeCompound(TopoDS::Compound(outShape));
619 aSingleShape.Orientation(TopAbs_FORWARD);
621 Iterator anIter (lstNodes);
622 for (; anIter.More(); anIter.Next()) {
623 // Try a Shape type of node
624 const Handle(VrmlData_ShapeNode) aNodeShape =
625 Handle(VrmlData_ShapeNode)::DownCast (anIter.Value());
626 if (aNodeShape.IsNull() == Standard_False) {
627 const Handle(VrmlData_Geometry) aNodeGeom = aNodeShape->Geometry();
628 if (aNodeGeom.IsNull() == Standard_False) {
629 if (aSingleShape.IsNull() == Standard_False)
630 isSingleShape = Standard_False;
631 const Handle(TopoDS_TShape) aTShape = aNodeGeom->TShape();
632 aSingleShape.TShape(aTShape);
633 if (aSingleShape.IsNull() == Standard_False) {
634 aBuilder.Add (outShape, aSingleShape);
635 if (pMapShapeApp != 0L) {
636 const Handle(VrmlData_Appearance)& anAppearance =
637 aNodeShape->Appearance();
638 if (anAppearance.IsNull() == Standard_False) {
639 // Check if the current topology is a single face
640 if (aTShape->IsKind(STANDARD_TYPE(TopoDS_TFace)))
641 pMapShapeApp->Bind(aTShape, anAppearance);
643 // This is not a face, explode it in faces and bind each face
644 TopoDS_Shape aCurShape;
645 aCurShape.TShape(aTShape);
646 TopExp_Explorer anExp(aCurShape, TopAbs_FACE);
647 for (; anExp.More(); anExp.Next()) {
648 const TopoDS_Face& aFace = TopoDS::Face(anExp.Current());
649 pMapShapeApp->Bind(aFace.TShape(), anAppearance);
658 // Try a Group type of node
659 const Handle(VrmlData_Group) aNodeGroup =
660 Handle(VrmlData_Group)::DownCast (anIter.Value());
661 if (aNodeGroup.IsNull() == Standard_False) {
663 aNodeGroup->Shape(aShape, pMapShapeApp);
664 if (aShape.IsNull() == Standard_False) {
665 aBuilder.Add (outShape, aShape);
666 isSingleShape = Standard_False;
671 outShape = aSingleShape;
674 //=======================================================================
675 //function : ReadReal
677 //=======================================================================
679 VrmlData_ErrorStatus VrmlData_Scene::ReadReal
680 (VrmlData_InBuffer& theBuffer,
681 Standard_Real& theResult,
682 Standard_Boolean isScale,
683 Standard_Boolean isOnlyPositive) const
685 Standard_Real aResult(0.);
686 VrmlData_ErrorStatus aStatus;
687 if (VrmlData_Node::OK(aStatus, VrmlData_Scene::ReadLine(theBuffer))) {
689 aResult = Strtod (theBuffer.LinePtr, &endptr);
690 if (endptr == theBuffer.LinePtr)
691 aStatus = VrmlData_NumericInputError;
692 else if (isOnlyPositive && aResult < 0.001*Precision::Confusion())
693 aStatus = VrmlData_IrrelevantNumber;
695 theResult = isScale ? (aResult * myLinearScale) : aResult;
696 theBuffer.LinePtr = endptr;
702 //=======================================================================
705 //=======================================================================
707 VrmlData_ErrorStatus VrmlData_Scene::ReadXYZ
708 (VrmlData_InBuffer& theBuffer,
710 Standard_Boolean isScale,
711 Standard_Boolean isOnlyPos) const
713 Standard_Real aVal[3] = {0., 0., 0.};
714 VrmlData_ErrorStatus aStatus = VrmlData_StatusOK;
715 for (Standard_Integer i = 0; i < 3; i++) {
716 if (!VrmlData_Node::OK(aStatus, VrmlData_Scene::ReadLine(theBuffer)))
719 aVal[i] = Strtod (theBuffer.LinePtr, &endptr);
720 if (endptr == theBuffer.LinePtr) {
721 aStatus = VrmlData_NumericInputError;
724 if (isOnlyPos && aVal[i] < 0.001*Precision::Confusion()) {
725 aStatus = VrmlData_IrrelevantNumber;
728 theBuffer.LinePtr = endptr;
731 if (aStatus == VrmlData_StatusOK) {
733 theXYZ.SetCoord (aVal[0] * myLinearScale,
734 aVal[1] * myLinearScale,
735 aVal[2] * myLinearScale);
738 theXYZ.SetCoord (aVal[0], aVal[1], aVal[2]);
744 //=======================================================================
747 //=======================================================================
749 VrmlData_ErrorStatus VrmlData_Scene::ReadXY
750 (VrmlData_InBuffer& theBuffer,
752 Standard_Boolean isScale,
753 Standard_Boolean isOnlyPos) const
755 Standard_Real aVal[2] = {0., 0.};
756 VrmlData_ErrorStatus aStatus = VrmlData_StatusOK;
757 for (Standard_Integer i = 0; i < 2; i++) {
758 if (!VrmlData_Node::OK(aStatus, VrmlData_Scene::ReadLine(theBuffer)))
761 aVal[i] = Strtod (theBuffer.LinePtr, &endptr);
762 if (endptr == theBuffer.LinePtr) {
763 aStatus = VrmlData_NumericInputError;
766 if (isOnlyPos && aVal[i] < 0.001*Precision::Confusion()) {
767 aStatus = VrmlData_IrrelevantNumber;
770 theBuffer.LinePtr = endptr;
773 if (aStatus == VrmlData_StatusOK) {
775 theXY.SetCoord (aVal[0] * myLinearScale, aVal[1] * myLinearScale);
777 theXY.SetCoord (aVal[0], aVal[1]);
782 //=======================================================================
783 //function : ReadArrIndex
784 //purpose : Read the body of the data node (comma-separated list of int
786 //=======================================================================
788 VrmlData_ErrorStatus VrmlData_Scene::ReadArrIndex
789 (VrmlData_InBuffer& theBuffer,
790 const Standard_Integer **& theArray,
791 Standard_Size& theNBlocks) const
793 VrmlData_ErrorStatus aStatus;
795 if (VrmlData_Node::OK(aStatus, ReadLine(theBuffer))) {
796 if (theBuffer.LinePtr[0] != '[') // opening bracket
797 aStatus = VrmlData_VrmlFormatError;
800 NCollection_Vector<const Standard_Integer *> vecIndice;
801 NCollection_Vector<Standard_Integer> vecInt;
802 Standard_Boolean isMore (Standard_True);
805 // Loop reading integers from the stream
806 while (isMore && VrmlData_Node::OK(aStatus, ReadLine(theBuffer)))
808 // closing bracket, in case that it follows a comma
809 if (theBuffer.LinePtr[0] == ']') {
813 if (!VrmlData_Node::OK(aStatus, VrmlData_Node::ReadInteger(theBuffer,
816 // Check for valid delimiter (']' or ',')
817 if (!VrmlData_Node::OK(aStatus, ReadLine(theBuffer)))
819 if (theBuffer.LinePtr[0] == ']') {
821 isMore = Standard_False;
824 // The input value is a node index, store it in the buffer vector
825 vecInt.Append (static_cast<Standard_Integer> (anIntValue));
826 if ((anIntValue < 0 || isMore == Standard_False)
827 && vecInt.Length() > 0)
829 const Standard_Integer aLen = vecInt.Length();
830 // The input is the end-of-face, store and close this face
831 Standard_Integer * bufFace = static_cast <Standard_Integer *>
832 (myAllocator->Allocate((aLen+1) * sizeof(Standard_Integer)));
834 aStatus = VrmlData_UnrecoverableError;
838 for (Standard_Integer i = 0; i < aLen; i++)
839 bufFace[i+1] = vecInt(i);
841 vecIndice.Append(bufFace);
844 if (aStatus == VrmlData_StatusOK) {
845 const Standard_Size aNbBlocks =
846 static_cast <Standard_Size> (vecIndice.Length());
848 const Standard_Integer ** anArray =
849 static_cast <const Standard_Integer **>
850 (myAllocator->Allocate (aNbBlocks * sizeof(Standard_Integer *)));
852 aStatus = VrmlData_UnrecoverableError;
854 for (size_t i = 0; i < aNbBlocks; i++)
855 anArray[i] = vecIndice((Standard_Integer)i);
856 theNBlocks = aNbBlocks;
866 //=======================================================================
867 //function : writeArrIndex
869 //=======================================================================
871 VrmlData_ErrorStatus VrmlData_Scene::WriteArrIndex
872 (const char * thePrefix,
873 const Standard_Integer ** theArrIndex,
874 const Standard_Size theNbBlocks) const
876 VrmlData_ErrorStatus aStatus (VrmlData_StatusOK);
877 if (theNbBlocks && (IsDummyWrite() == Standard_False)) {
878 if (VrmlData_Node::OK (aStatus,
879 WriteLine (thePrefix, "[", 1)))
881 const size_t aLineLimit = (myCurrentIndent < 41) ? 36 : 100;
883 for (Standard_Size iBlock = 0; iBlock < theNbBlocks; iBlock++) {
884 const Standard_Integer nVal (* theArrIndex[iBlock]);
885 const Standard_Integer * arrVal = theArrIndex[iBlock]+1;
888 Sprintf (buf, "%d,", arrVal[0]);
891 Sprintf (buf, "%d,%d,", arrVal[0], arrVal[1]);
894 Sprintf (buf, "%d,%d,%d,", arrVal[0], arrVal[1], arrVal[2]);
897 Sprintf (buf, "%d,%d,%d,%d,",
898 arrVal[0], arrVal[1], arrVal[2], arrVal[3]);
902 char * ptr = &buf[0];
903 for (Standard_Integer i = 0; i < nVal; i++) {
904 Sprintf (ptr, "%d,", arrVal[i]);
907 ptr = strchr (ptr, ',') + 1;
908 if ((ptr - &buf[0]) > (ptrdiff_t)aLineLimit) {
915 WriteLine (buf, iBlock < theNbBlocks-1 ? "-1," : "-1");
917 if (aStatus == VrmlData_StatusOK)
918 aStatus = WriteLine ("]", 0L, -1);
924 //=======================================================================
925 //function : WriteXYZ
927 //=======================================================================
929 VrmlData_ErrorStatus VrmlData_Scene::WriteXYZ
930 (const gp_XYZ& theXYZ,
931 const Standard_Boolean isApplyScale,
932 const char * thePostfix) const
935 if (IsDummyWrite() == Standard_False) {
936 if (isApplyScale && myLinearScale > Precision::Confusion())
937 Sprintf (buf, "%.12g %.12g %.12g%s", theXYZ.X() / myLinearScale,
938 theXYZ.Y() / myLinearScale, theXYZ.Z() / myLinearScale,
939 thePostfix ? thePostfix : "");
941 Sprintf (buf, "%.12g %.12g %.12g%s", theXYZ.X(), theXYZ.Y(), theXYZ.Z(),
942 thePostfix ? thePostfix : "");
944 return WriteLine (buf);
947 //=======================================================================
948 //function : WriteLine
949 //purpose : write the given string prepending the current indentation
950 //=======================================================================
952 VrmlData_ErrorStatus VrmlData_Scene::WriteLine
953 (const char * theLin0,
954 const char * theLin1,
955 const Standard_Integer theIndent) const
957 static const char spaces[] = " "
959 VrmlData_ErrorStatus& aStatus =
960 const_cast <VrmlData_ErrorStatus&> (myStatus);
962 aStatus = VrmlData_StatusOK;
964 Standard_Integer& aCurrentIndent =
965 const_cast <Standard_Integer&> (myCurrentIndent);
967 aCurrentIndent -= myIndent;
968 if (aCurrentIndent < 0)
970 if (theLin0 == 0L && theLin1 == 0L)
971 (* myOutput) << "\n";
973 const Standard_Integer nSpaces = Min (aCurrentIndent, sizeof(spaces)-1);
974 (* myOutput) << &spaces[sizeof(spaces)-1 - nSpaces];
976 (* myOutput) << theLin0;
978 (* myOutput) << " " << theLin1;
980 (* myOutput) << theLin1;
981 (* myOutput) << "\n";
983 const int stat = myOutput->rdstate();
984 if (stat & ios::badbit)
985 aStatus = VrmlData_UnrecoverableError;
986 else if (stat & ios::failbit)
987 // if (stat & ios::eofbit)
988 // aStatus = VrmlData_EndOfFile;
990 aStatus = VrmlData_GeneralError;
992 aCurrentIndent += myIndent;
997 //=======================================================================
998 //function : WriteNode
1000 //=======================================================================
1002 VrmlData_ErrorStatus VrmlData_Scene::WriteNode
1003 (const char * thePrefix,
1004 const Handle(VrmlData_Node)& theNode) const
1006 VrmlData_ErrorStatus aStatus (VrmlData_StatusOK);
1007 Standard_Boolean isNoName (Standard_False);
1008 if (theNode->Name() == 0L)
1009 isNoName = Standard_True;
1010 else if (theNode->Name()[0] == '\0')
1011 isNoName = Standard_True;
1013 if (theNode.IsNull() == Standard_False)
1014 if (theNode->IsDefault() == Standard_False) {
1015 if (isNoName && IsDummyWrite()) {
1016 // We are in a tentative 'write' session (nothing is written).
1017 // The goal is to identify multiply referred nodes.
1018 Standard_Address addrNode = theNode.operator->();
1019 if (!const_cast<NCollection_Map<Standard_Address>&>(myUnnamedNodesOut)
1022 Handle(VrmlData_UnknownNode) bidNode = new VrmlData_UnknownNode;
1025 Sprintf (buf, "_%d",
1026 ++const_cast<Standard_Integer&>(myAutoNameCounter));
1027 bidNode->myName = &buf[0];
1028 } while (myNamedNodes.Contains (bidNode));
1029 // We found the vacant automatic name, let us assign to it.
1030 theNode->setName (&buf[0]);
1031 const_cast<VrmlData_MapOfNode&>(myNamedNodes).Add (theNode);
1032 return aStatus; // do not search under already duplicated node
1036 aStatus = theNode->Write (thePrefix);
1038 // If the node name consists of blank characters, we do not write it
1039 const char * nptr = theNode->Name();
1040 for (; * nptr != '\0'; nptr++)
1041 if (* nptr != ' ' && * nptr != '\t')
1044 aStatus = theNode->Write (thePrefix);
1046 // Name is written under DEF clause
1047 TCollection_AsciiString buf;
1048 if (myNamedNodesOut.Contains (theNode))
1051 buf += theNode->Name();
1052 aStatus = WriteLine (thePrefix, buf.ToCString());
1062 buf += theNode->Name();
1063 aStatus = theNode->Write (buf.ToCString());
1064 const_cast<VrmlData_MapOfNode&>(myNamedNodesOut).Add (theNode);
1072 //=======================================================================
1075 //=======================================================================
1077 void VrmlData_Scene::Dump (Standard_OStream& theStream) const
1079 theStream << " ===== Diagnostic Dump of a Scene (" << myAllNodes.Extent()
1083 Iterator anIterA(myAllNodes);
1084 for (; anIterA.More(); anIterA.Next())
1085 dumpNode(theStream, anIterA.Value(), "");
1087 Iterator anIter(myLstNodes);
1088 for (; anIter.More(); anIter.Next())
1089 dumpNode(theStream, anIter.Value(), " ");
1092 //=======================================================================
1093 //function : dumpNode
1094 //purpose : static (local) function
1095 //=======================================================================
1097 void dumpNode (Standard_OStream& theStream,
1098 const Handle(VrmlData_Node)& theNode,
1099 const TCollection_AsciiString& theIndent)
1101 if (theNode.IsNull())
1103 TCollection_AsciiString aNewIndent =
1104 theIndent.IsEmpty() ? theIndent : theIndent + " ";
1105 if (theNode->IsKind(STANDARD_TYPE(VrmlData_Appearance))) {
1106 const Handle(VrmlData_Appearance) anAppearance =
1107 Handle(VrmlData_Appearance)::DownCast (theNode);
1108 dumpNodeHeader (theStream, theIndent, "Appearance", theNode->Name());
1109 if (theIndent.IsEmpty() == Standard_False) {
1110 dumpNode (theStream, anAppearance->Material(), aNewIndent);
1111 dumpNode (theStream, anAppearance->Texture(), aNewIndent);
1112 dumpNode (theStream, anAppearance->TextureTransform(), aNewIndent);
1114 } else if (theNode->IsKind(STANDARD_TYPE(VrmlData_ShapeNode))) {
1115 const Handle(VrmlData_ShapeNode) aShape =
1116 Handle(VrmlData_ShapeNode)::DownCast (theNode);
1117 dumpNodeHeader (theStream, theIndent, "Shape", theNode->Name());
1118 if (theIndent.IsEmpty() == Standard_False) {
1119 dumpNode (theStream, aShape->Appearance(), aNewIndent);
1120 dumpNode (theStream, aShape->Geometry(), aNewIndent);
1122 } else if (theNode->IsKind(STANDARD_TYPE(VrmlData_Box)))
1123 dumpNodeHeader (theStream, theIndent, "Box", theNode->Name());
1124 else if (theNode->IsKind(STANDARD_TYPE(VrmlData_Cylinder)))
1125 dumpNodeHeader (theStream, theIndent, "Cylinder", theNode->Name());
1126 else if (theNode->IsKind(STANDARD_TYPE(VrmlData_Sphere)))
1127 dumpNodeHeader (theStream, theIndent, "Sphere", theNode->Name());
1128 else if (theNode->IsKind(STANDARD_TYPE(VrmlData_Cone)))
1129 dumpNodeHeader (theStream, theIndent, "Cone", theNode->Name());
1130 else if (theNode->IsKind(STANDARD_TYPE(VrmlData_Coordinate)))
1131 dumpNodeHeader (theStream, theIndent, "Coordinate", theNode->Name());
1132 else if (theNode->IsKind(STANDARD_TYPE(VrmlData_Group))) {
1133 const Handle(VrmlData_Group) aGroup =
1134 Handle(VrmlData_Group)::DownCast (theNode);
1136 Sprintf (buf, "Group (%s)",
1137 aGroup->IsTransform() ? "Transform" : "Group");
1138 dumpNodeHeader (theStream, theIndent, buf, theNode->Name());
1139 if (theIndent.IsEmpty() == Standard_False) {
1140 VrmlData_ListOfNode::Iterator anIter = aGroup->NodeIterator();
1141 for (; anIter.More(); anIter.Next())
1142 dumpNode (theStream, anIter.Value(), aNewIndent);
1144 } else if (theNode->IsKind(STANDARD_TYPE(VrmlData_ImageTexture)))
1145 dumpNodeHeader (theStream, theIndent, "ImageTexture", theNode->Name());
1146 else if (theNode->IsKind(STANDARD_TYPE(VrmlData_IndexedFaceSet))) {
1147 const Handle(VrmlData_IndexedFaceSet) aNode =
1148 Handle(VrmlData_IndexedFaceSet)::DownCast(theNode);
1149 const Standard_Integer ** ppDummy;
1150 const Standard_Size nCoord = aNode->Coordinates()->Length();
1151 const Standard_Size nPoly = aNode->Polygons (ppDummy);
1153 Sprintf (buf, "IndexedFaceSet (%" PRIuPTR " vertices, %" PRIuPTR " polygons)",
1156 dumpNodeHeader (theStream, theIndent, buf, theNode->Name());
1157 } else if (theNode->IsKind(STANDARD_TYPE(VrmlData_IndexedLineSet))) {
1158 const Handle(VrmlData_IndexedLineSet) aNode =
1159 Handle(VrmlData_IndexedLineSet)::DownCast(theNode);
1160 const Standard_Integer ** ppDummy;
1161 const Standard_Size nCoord = aNode->Coordinates()->Length();
1162 const Standard_Size nPoly = aNode->Polygons (ppDummy);
1165 Sprintf(buf, "IndexedLineSet (%" PRIuPTR " vertices, %" PRIuPTR " polygons)",
1168 dumpNodeHeader (theStream, theIndent, buf, theNode->Name());
1169 } else if (theNode->IsKind(STANDARD_TYPE(VrmlData_Material))) {
1170 // const Handle(VrmlData_Material) aMaterial =
1171 // Handle(VrmlData_Material)::DownCast (theNode);
1172 dumpNodeHeader (theStream, theIndent, "Material", theNode->Name());
1174 else if (theNode->IsKind(STANDARD_TYPE(VrmlData_Normal)))
1175 dumpNodeHeader (theStream, theIndent, "Normal", theNode->Name());
1176 else if (theNode->IsKind(STANDARD_TYPE(VrmlData_TextureCoordinate)))
1177 dumpNodeHeader (theStream, theIndent, "TextureCoordinate", theNode->Name());
1178 else if (theNode->IsKind(STANDARD_TYPE(VrmlData_WorldInfo)))
1179 dumpNodeHeader (theStream, theIndent, "WorldInfo", theNode->Name());
1180 else if (theNode->IsKind(STANDARD_TYPE(VrmlData_UnknownNode))) {
1181 const Handle(VrmlData_UnknownNode) anUnknown =
1182 Handle(VrmlData_UnknownNode)::DownCast (theNode);
1184 Sprintf (buf, "Unknown (%s)", anUnknown->GetTitle().ToCString());
1185 dumpNodeHeader (theStream, theIndent, buf, theNode->Name());
1189 //=======================================================================
1190 //function : dumpNodeHeader
1192 //=======================================================================
1194 void dumpNodeHeader (Standard_OStream& theStream,
1195 const TCollection_AsciiString& theIndent,
1196 const char * theType,
1197 const char * theName)
1199 theStream << theIndent << theType << " node";
1200 if (theName[0] == '\0')
1203 theStream << ": \"" << theName << "\"\n";