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_Appearance.hxx>
18 #include <VrmlData_Box.hxx>
19 #include <VrmlData_Cone.hxx>
20 #include <VrmlData_Cylinder.hxx>
21 #include <VrmlData_DataMapOfShapeAppearance.hxx>
22 #include <VrmlData_Group.hxx>
23 #include <VrmlData_ImageTexture.hxx>
24 #include <VrmlData_InBuffer.hxx>
25 #include <VrmlData_IndexedFaceSet.hxx>
26 #include <VrmlData_IndexedLineSet.hxx>
27 #include <VrmlData_Material.hxx>
28 #include <VrmlData_Normal.hxx>
29 #include <VrmlData_Scene.hxx>
30 #include <VrmlData_ShapeNode.hxx>
31 #include <VrmlData_Sphere.hxx>
32 #include <VrmlData_TextureCoordinate.hxx>
33 #include <VrmlData_UnknownNode.hxx>
34 //#include <VrmlData_WorldInfo.hxx>
35 #include <NCollection_Vector.hxx>
37 #include <TopExp_Explorer.hxx>
38 #include <BRep_Builder.hxx>
39 #include <Precision.hxx>
40 #include <Standard_Version.hxx>
41 #include <VrmlData_WorldInfo.hxx>
42 #include <VrmlData_Geometry.hxx>
45 #define _CRT_SECURE_NO_DEPRECATE
46 #pragma warning (disable:4996)
49 static void dumpNode (Standard_OStream& theStream,
50 const Handle(VrmlData_Node)& theNode,
51 const TCollection_AsciiString& theIndent);
53 static void dumpNodeHeader (Standard_OStream& theStream,
54 const TCollection_AsciiString& theIndent,
56 const char * theName);
58 //=======================================================================
59 //function : VrmlData_Scene
60 //purpose : Constructor
61 //=======================================================================
63 VrmlData_Scene::VrmlData_Scene
64 (const Handle(NCollection_IncAllocator)& theAlloc)
66 myStatus (VrmlData_StatusOK),
67 myAllocator (theAlloc.IsNull() ?
68 new NCollection_IncAllocator : theAlloc.operator->()),
75 myWorldInfo = new VrmlData_WorldInfo (* this);
76 Standard_CString anInfo = "Generated by Open CASCADE Technology " OCC_VERSION_STRING;
77 myWorldInfo->AddInfo (anInfo);
78 myLstNodes.Append (myWorldInfo);
79 myAllNodes.Append (myWorldInfo);
82 //=======================================================================
85 //=======================================================================
87 const Handle(VrmlData_Node)& VrmlData_Scene::AddNode
88 (const Handle(VrmlData_Node)& theN,
89 const Standard_Boolean isTopLevel)
91 if (theN.IsNull() == Standard_False)
92 if (theN->IsKind (STANDARD_TYPE(VrmlData_WorldInfo)) == Standard_False) {
94 const Handle(VrmlData_Node)& aNode =
95 myAllNodes.Append ((&theN->Scene()== this) ? theN : theN->Clone (NULL));
96 // Name is checked for uniqueness. If not, letter 'D' is appended until
97 // the name proves to be unique.
98 if (aNode->Name()[0] != '\0')
99 while (myNamedNodes.Add (aNode) == Standard_False)
100 aNode->setName (aNode->Name(), "D");
102 myLstNodes.Append (aNode);
106 static Handle(VrmlData_Node) aNullNode;
111 //=======================================================================
112 //function : operator <<
113 //purpose : Export to text stream (file or else)
114 //=======================================================================
116 Standard_OStream& operator << (Standard_OStream& theOutput,
117 const VrmlData_Scene& theScene)
119 VrmlData_Scene& aScene = const_cast <VrmlData_Scene&> (theScene);
120 aScene.myMutex.Lock();
121 aScene.myCurrentIndent = 0;
122 aScene.myLineError = 0;
123 aScene.myOutput = 0L;
124 aScene.myNamedNodesOut.Clear();
125 aScene.myUnnamedNodesOut.Clear();
126 aScene.myAutoNameCounter = 0;
130 VrmlData_Scene::Iterator anIterD(aScene.myLstNodes);
131 for (; anIterD.More(); anIterD.Next()) {
132 const Handle(VrmlData_Node)& aNode = anIterD.Value();
133 if (aNode.IsNull() == Standard_False) {
134 const VrmlData_ErrorStatus aStatus = aScene.WriteNode (0L, aNode);
135 if (aStatus != VrmlData_StatusOK &&
136 aStatus != VrmlData_NotImplemented)
141 aScene.myOutput = &theOutput;
142 aScene.myNamedNodesOut.Clear();
143 theOutput << "#VRML V2.0 utf8\n\n";
147 VrmlData_Scene::Iterator anIter(aScene.myLstNodes);
148 for (; anIter.More(); anIter.Next()) {
149 const Handle(VrmlData_Node)& aNode = anIter.Value();
150 if (aNode.IsNull() == Standard_False) {
151 const VrmlData_ErrorStatus aStatus = aScene.WriteNode (0L, aNode);
152 if (aStatus != VrmlData_StatusOK &&
153 aStatus != VrmlData_NotImplemented)
157 aScene.myOutput = 0L;
158 aScene.myNamedNodesOut.Clear();
159 aScene.myUnnamedNodesOut.Clear();
160 aScene.myMutex.Unlock();
164 //=======================================================================
165 //function : SetVrmlDir
167 //=======================================================================
169 void VrmlData_Scene::SetVrmlDir (const TCollection_ExtendedString& theDir)
171 TCollection_ExtendedString& aDir = myVrmlDir.Append (theDir);
172 const Standard_ExtCharacter aTerminator = aDir.Value(aDir.Length());
173 if (aTerminator != Standard_ExtCharacter('\\') &&
174 aTerminator != Standard_ExtCharacter('/'))
176 aDir += TCollection_ExtendedString ("\\");
178 aDir += TCollection_ExtendedString ("/");
182 //=======================================================================
183 //function : WorldInfo
185 //=======================================================================
187 const Handle(VrmlData_WorldInfo)& VrmlData_Scene::WorldInfo() const
192 //=======================================================================
193 //function : readLine
195 //=======================================================================
197 VrmlData_ErrorStatus VrmlData_Scene::readLine (VrmlData_InBuffer& theBuffer)
199 VrmlData_ErrorStatus aStatus = VrmlData_StatusOK;
200 if (theBuffer.Input.eof())
201 aStatus = VrmlData_EndOfFile;
203 theBuffer.Input.getline (theBuffer.Line, sizeof(theBuffer.Line));
204 theBuffer.LineCount++;
205 const int stat = theBuffer.Input.rdstate();
206 if (stat & std::ios::badbit) {
207 aStatus = VrmlData_UnrecoverableError;
209 else if (stat & std::ios::failbit) {
210 if (stat & std::ios::eofbit) {
211 aStatus = VrmlData_EndOfFile;
214 aStatus = VrmlData_GeneralError;
217 theBuffer.LinePtr = &theBuffer.Line[0];
218 theBuffer.IsProcessed = Standard_False;
223 //=======================================================================
224 //function : ReadLine
226 //=======================================================================
228 VrmlData_ErrorStatus VrmlData_Scene::ReadLine (VrmlData_InBuffer& theBuffer)
230 VrmlData_ErrorStatus aStatus (VrmlData_StatusOK);
232 while (aStatus == VrmlData_StatusOK) {
233 // Find the first significant character of the line
234 for (; * theBuffer.LinePtr != '\0'; theBuffer.LinePtr++) {
235 if (* theBuffer.LinePtr != ' ' && * theBuffer.LinePtr != '\t'
236 && * theBuffer.LinePtr != ',')
238 if (* theBuffer.LinePtr == '\n' || * theBuffer.LinePtr == '\r' ||
239 * theBuffer.LinePtr == '#')
240 // go requesting the next line
245 // the line is empty here (no significant characters). Read the next one.
246 aStatus = readLine (theBuffer);
249 // error or EOF detected
253 // Try to detect comment
254 if (theBuffer.IsProcessed == Standard_False) {
255 Standard_Boolean isQuoted (Standard_False);
256 Standard_Integer anOffset (0);
257 char * ptr = theBuffer.LinePtr;
258 for (; * ptr != '\0'; ptr++) {
260 * ptr = ptr[anOffset];
261 if (* ptr == '\n' || * ptr == '\r' || * ptr == '#') {
262 if (isQuoted == Standard_False) {
266 } else if (* ptr == '\\' && isQuoted)
267 ptr[0] = ptr[++anOffset];
268 else if (* ptr == '\"')
269 isQuoted = !isQuoted;
271 theBuffer.IsProcessed = Standard_True;
276 //=======================================================================
277 //function : readHeader
279 //=======================================================================
281 VrmlData_ErrorStatus VrmlData_Scene::readHeader (VrmlData_InBuffer& theBuffer)
283 VrmlData_ErrorStatus aStat = readLine (theBuffer);
284 if (aStat == VrmlData_StatusOK &&
285 !VRMLDATA_LCOMPARE(theBuffer.LinePtr, "#VRML V2.0"))
286 aStat = VrmlData_NotVrmlFile;
288 aStat = readLine(theBuffer);
292 //=======================================================================
293 //function : operator <<
294 //purpose : Import from text stream (file or else)
295 //=======================================================================
297 VrmlData_Scene& VrmlData_Scene::operator << (Standard_IStream& theInput)
299 VrmlData_InBuffer aBuffer (theInput);
301 // Read the VRML header
302 myStatus = readHeader (aBuffer);
303 const Handle(VrmlData_UnknownNode) aNullNode= new VrmlData_UnknownNode(*this);
304 // if (myStatus == StatusOK)
305 // myStatus = ReadLine (aBuffer);
306 // Read VRML data by nodes
308 if (!VrmlData_Node::OK(myStatus, ReadLine(aBuffer))) {
309 if (myStatus == VrmlData_EndOfFile)
310 myStatus = VrmlData_StatusOK;
313 // this line provides the method ReadNode in the present context
314 Handle(VrmlData_Node) aNode;
315 myStatus = aNullNode->ReadNode (aBuffer, aNode);
316 // Unknown nodes are not stored however they do not generate error
317 if (myStatus != VrmlData_StatusOK)
319 if (aNode.IsNull() == Standard_False /*&&
320 !aNode->IsKind (STANDARD_TYPE(VrmlData_UnknownNode))*/)
322 if (aNode->IsKind (STANDARD_TYPE(VrmlData_WorldInfo)) == Standard_False)
323 myLstNodes.Append (aNode);
324 else if (aNode->IsDefault() == Standard_False) {
325 const Handle(VrmlData_WorldInfo) aInfo =
326 Handle(VrmlData_WorldInfo)::DownCast (aNode);
327 myWorldInfo->SetTitle (aInfo->Title());
328 NCollection_List <const char *>::Iterator anIterInfo =
329 aInfo->InfoIterator();
330 for (; anIterInfo.More(); anIterInfo.Next())
331 myWorldInfo->AddInfo (anIterInfo.Value());
335 if (myStatus != VrmlData_StatusOK)
336 myLineError = aBuffer.LineCount;
341 //=======================================================================
342 //function : FindNode
344 //=======================================================================
346 Handle(VrmlData_Node) VrmlData_Scene::FindNode
347 (const char * theName,
348 const Handle(Standard_Type)& /*theType*/) const
350 Handle(VrmlData_Node) aResult;
352 Iterator anIter (myAllNodes);
353 for (; anIter.More(); anIter.Next())
354 if (!strcmp (anIter.Value()->Name(), theName)) {
355 aResult = anIter.Value();
356 if (theType.IsNull())
358 if (aResult->IsKind(theType))
363 const Handle(VrmlData_UnknownNode) aDummyNode = new VrmlData_UnknownNode;
364 aDummyNode->myName = theName;
365 if (myNamedNodes.Contains (aDummyNode))
366 aResult = const_cast<VrmlData_MapOfNode&>(myNamedNodes).Added(aDummyNode);
371 //=======================================================================
372 //function : FindNode
374 //=======================================================================
376 Handle(VrmlData_Node) VrmlData_Scene::FindNode
377 (const char * theName,
378 gp_Trsf& theLocation) const
381 Handle(VrmlData_Node) aResult;
382 Iterator anIter (myLstNodes);
383 for (; anIter.More(); anIter.Next()) {
384 const Handle(VrmlData_Node)& aNode = anIter.Value();
387 // Match a top-level node name
388 if (strcmp(aNode->Name(), theName) == 0) {
393 // Try a Group type of node
394 if (aNode->IsKind(STANDARD_TYPE(VrmlData_Group)))
396 const Handle(VrmlData_Group) aGroup =
397 Handle(VrmlData_Group)::DownCast (aNode);
398 if (aGroup.IsNull() == Standard_False) {
399 aResult = aGroup->FindNode(theName, theLocation);
400 if (aResult.IsNull() == Standard_False)
408 //=======================================================================
409 //function : ReadWord
411 //=======================================================================
413 VrmlData_ErrorStatus VrmlData_Scene::ReadWord
414 (VrmlData_InBuffer& theBuffer,
415 TCollection_AsciiString& theWord)
417 VrmlData_ErrorStatus aStatus = ReadLine(theBuffer);
418 if (aStatus == VrmlData_StatusOK) {
419 char * ptr = theBuffer.LinePtr;
420 while (* ptr != '\0' && * ptr != '\n' && * ptr != '\r' &&
421 * ptr != ' ' && * ptr != '\t' && * ptr != '{' && * ptr != '}' &&
422 * ptr != ',' && * ptr != '[' && * ptr != ']')
424 const Standard_Integer aLen = Standard_Integer(ptr - theBuffer.LinePtr);
426 aStatus = VrmlData_StringInputError;
428 theWord = TCollection_AsciiString ((Standard_CString)theBuffer.LinePtr,
430 theBuffer.LinePtr = ptr;
436 //=======================================================================
437 //function : createNode
439 //=======================================================================
441 VrmlData_ErrorStatus VrmlData_Scene::createNode
442 (VrmlData_InBuffer& theBuffer,
443 Handle(VrmlData_Node)& theNode,
444 const Handle(Standard_Type)& theType)
446 VrmlData_ErrorStatus aStatus;
447 Handle(VrmlData_Node) aNode;
448 TCollection_AsciiString aName;
450 // Read the DEF token to assign the node name
451 if (VrmlData_Node::OK(aStatus, ReadLine(theBuffer))) {
452 if (VRMLDATA_LCOMPARE(theBuffer.LinePtr, "DEF")) {
453 if (VrmlData_Node::OK(aStatus, ReadWord (theBuffer, aName)))
454 aStatus = ReadLine(theBuffer);
455 } else if (VRMLDATA_LCOMPARE(theBuffer.LinePtr, "NULL")) {
461 const char * strName = aName.ToCString();
462 if (aStatus == VrmlData_StatusOK) {
463 // create the new node
464 if (VRMLDATA_LCOMPARE(theBuffer.LinePtr, "Appearance"))
465 aNode = new VrmlData_Appearance (* this, strName);
466 else if (VRMLDATA_LCOMPARE(theBuffer.LinePtr, "Shape"))
467 aNode = new VrmlData_ShapeNode (* this, strName);
468 else if (VRMLDATA_LCOMPARE(theBuffer.LinePtr, "Box"))
469 aNode = new VrmlData_Box (* this, strName);
470 else if (VRMLDATA_LCOMPARE(theBuffer.LinePtr, "Color"))
471 aNode = new VrmlData_Color (* this, strName);
472 else if (VRMLDATA_LCOMPARE(theBuffer.LinePtr, "Cone"))
473 aNode = new VrmlData_Cone (* this, strName);
474 else if (VRMLDATA_LCOMPARE(theBuffer.LinePtr, "Coordinate")) {
475 aNode = new VrmlData_Coordinate (* this, strName);
477 // Check for "Coordinate3"
478 if (VRMLDATA_LCOMPARE (theBuffer.LinePtr, "3"))
481 else if (VRMLDATA_LCOMPARE(theBuffer.LinePtr, "Cylinder"))
482 aNode = new VrmlData_Cylinder (* this, strName);
483 else if (VRMLDATA_LCOMPARE(theBuffer.LinePtr, "Group"))
484 aNode = new VrmlData_Group (* this, strName,
486 else if (VRMLDATA_LCOMPARE(theBuffer.LinePtr, "Transform"))
487 aNode = new VrmlData_Group (* this, strName,
489 else if (VRMLDATA_LCOMPARE(theBuffer.LinePtr, "Inline"))
490 aNode = new VrmlData_Group (* this, strName,
492 else if (VRMLDATA_LCOMPARE(theBuffer.LinePtr, "Separator"))
493 aNode = new VrmlData_Group (* this, strName,
495 else if (VRMLDATA_LCOMPARE(theBuffer.LinePtr, "Collision"))
496 aNode = new VrmlData_Group (* this, strName,
498 else if (VRMLDATA_LCOMPARE(theBuffer.LinePtr, "Switch"))
499 aNode = new VrmlData_Group (* this, strName,
501 else if (VRMLDATA_LCOMPARE(theBuffer.LinePtr, "ImageTexture"))
502 aNode = new VrmlData_ImageTexture (* this, strName);
503 else if (VRMLDATA_LCOMPARE(theBuffer.LinePtr, "IndexedFaceSet"))
504 aNode = new VrmlData_IndexedFaceSet (* this, strName);
505 else if (VRMLDATA_LCOMPARE(theBuffer.LinePtr, "IndexedLineSet"))
506 aNode = new VrmlData_IndexedLineSet (* this, strName);
507 else if (VRMLDATA_LCOMPARE(theBuffer.LinePtr, "Material"))
508 aNode = new VrmlData_Material (* this, strName);
509 else if (VRMLDATA_LCOMPARE(theBuffer.LinePtr, "Normal"))
510 aNode = new VrmlData_Normal (* this, strName);
511 else if (VRMLDATA_LCOMPARE(theBuffer.LinePtr, "Sphere"))
512 aNode = new VrmlData_Sphere (* this, strName);
513 else if (VRMLDATA_LCOMPARE(theBuffer.LinePtr, "TextureCoordinate"))
514 aNode = new VrmlData_TextureCoordinate(* this, strName);
515 else if (VRMLDATA_LCOMPARE(theBuffer.LinePtr, "WorldInfo"))
516 aNode = new VrmlData_WorldInfo (* this, strName);
518 void * isProto = VRMLDATA_LCOMPARE(theBuffer.LinePtr, "PROTO");
519 TCollection_AsciiString aTitle;
520 aStatus = ReadWord (theBuffer, aTitle);
522 aStatus = ReadLine(theBuffer);
523 if (aStatus == VrmlData_StatusOK) {
524 if (theBuffer.LinePtr[0] != '[')
525 aStatus = VrmlData_VrmlFormatError;
528 Standard_Integer aLevelCounter(0);
529 // This loop searches for any opening bracket '['.
530 // Such bracket increments the level counter. A closing bracket decrements
531 // the counter. The loop terminates when the counter becomes negative.
532 while (aLevelCounter >= 0 &&
533 (aStatus = ReadLine(theBuffer)) == VrmlData_StatusOK) {
535 while ((aChar = theBuffer.LinePtr[0]) != '\0') {
540 } else if (aChar == ']') {
549 if (aStatus == VrmlData_StatusOK)
550 aNode = new VrmlData_UnknownNode(* this,
555 aStatus = ReadLine(theBuffer);
556 if (aNode.IsNull() == Standard_False) {
557 if (aNode->Name()[0] != '\0')
558 myNamedNodes.Add (aNode);
559 if (theType.IsNull() == Standard_False)
560 if (aNode->IsKind(theType) == Standard_False)
561 aStatus = VrmlData_VrmlFormatError;
563 if (aStatus == VrmlData_StatusOK) {
564 if (theBuffer.LinePtr[0] == '{') {
567 myAllNodes.Append(aNode);
569 aStatus = VrmlData_VrmlFormatError;
575 //=======================================================================
576 //function : operator TopoDS_Shape
578 //=======================================================================
580 VrmlData_Scene::operator TopoDS_Shape () const
583 VrmlData_Scene::createShape (aShape, myLstNodes, 0L);
587 //=======================================================================
588 //function : GetShape
590 //=======================================================================
592 TopoDS_Shape VrmlData_Scene::GetShape (VrmlData_DataMapOfShapeAppearance& aMap)
595 VrmlData_Scene::createShape (aShape, myLstNodes, &aMap);
599 //=======================================================================
600 //function : createShape
602 //=======================================================================
604 void VrmlData_Scene::createShape
605 (TopoDS_Shape& outShape,
606 const VrmlData_ListOfNode& lstNodes,
607 VrmlData_DataMapOfShapeAppearance* pMapShapeApp)
609 TopoDS_Shape aSingleShape; // used when there is a single ShapeNode
610 Standard_Boolean isSingleShape (Standard_True);
611 BRep_Builder aBuilder;
613 aBuilder.MakeCompound(TopoDS::Compound(outShape));
614 aSingleShape.Orientation(TopAbs_FORWARD);
616 Iterator anIter (lstNodes);
617 for (; anIter.More(); anIter.Next()) {
618 // Try a Shape type of node
619 const Handle(VrmlData_ShapeNode) aNodeShape =
620 Handle(VrmlData_ShapeNode)::DownCast (anIter.Value());
621 if (aNodeShape.IsNull() == Standard_False) {
622 const Handle(VrmlData_Geometry) aNodeGeom = aNodeShape->Geometry();
623 if (aNodeGeom.IsNull() == Standard_False) {
624 if (aSingleShape.IsNull() == Standard_False)
625 isSingleShape = Standard_False;
626 const Handle(TopoDS_TShape) aTShape = aNodeGeom->TShape();
627 aSingleShape.TShape(aTShape);
628 if (aSingleShape.IsNull() == Standard_False) {
629 aBuilder.Add (outShape, aSingleShape);
630 if (pMapShapeApp != 0L) {
631 const Handle(VrmlData_Appearance)& anAppearance =
632 aNodeShape->Appearance();
633 if (anAppearance.IsNull() == Standard_False) {
634 // Check if the current topology is a single face
635 if (aTShape->IsKind(STANDARD_TYPE(TopoDS_TFace)))
636 pMapShapeApp->Bind(aTShape, anAppearance);
638 // This is not a face, explode it in faces and bind each face
639 TopoDS_Shape aCurShape;
640 aCurShape.TShape(aTShape);
641 TopExp_Explorer anExp(aCurShape, TopAbs_FACE);
642 for (; anExp.More(); anExp.Next()) {
643 const TopoDS_Face& aFace = TopoDS::Face(anExp.Current());
644 pMapShapeApp->Bind(aFace.TShape(), anAppearance);
653 // Try a Group type of node
654 const Handle(VrmlData_Group) aNodeGroup =
655 Handle(VrmlData_Group)::DownCast (anIter.Value());
656 if (aNodeGroup.IsNull() == Standard_False) {
658 aNodeGroup->Shape(aShape, pMapShapeApp);
659 if (aShape.IsNull() == Standard_False) {
660 aBuilder.Add (outShape, aShape);
661 isSingleShape = Standard_False;
666 outShape = aSingleShape;
669 //=======================================================================
670 //function : ReadReal
672 //=======================================================================
674 VrmlData_ErrorStatus VrmlData_Scene::ReadReal
675 (VrmlData_InBuffer& theBuffer,
676 Standard_Real& theResult,
677 Standard_Boolean isScale,
678 Standard_Boolean isOnlyPositive) const
680 Standard_Real aResult(0.);
681 VrmlData_ErrorStatus aStatus;
682 if (VrmlData_Node::OK(aStatus, VrmlData_Scene::ReadLine(theBuffer))) {
684 aResult = Strtod (theBuffer.LinePtr, &endptr);
685 if (endptr == theBuffer.LinePtr)
686 aStatus = VrmlData_NumericInputError;
687 else if (isOnlyPositive && aResult < 0.001*Precision::Confusion())
688 aStatus = VrmlData_IrrelevantNumber;
690 theResult = isScale ? (aResult * myLinearScale) : aResult;
691 theBuffer.LinePtr = endptr;
697 //=======================================================================
700 //=======================================================================
702 VrmlData_ErrorStatus VrmlData_Scene::ReadXYZ
703 (VrmlData_InBuffer& theBuffer,
705 Standard_Boolean isScale,
706 Standard_Boolean isOnlyPos) const
708 Standard_Real aVal[3] = {0., 0., 0.};
709 VrmlData_ErrorStatus aStatus = VrmlData_StatusOK;
710 for (Standard_Integer i = 0; i < 3; i++) {
711 if (!VrmlData_Node::OK(aStatus, VrmlData_Scene::ReadLine(theBuffer)))
714 aVal[i] = Strtod (theBuffer.LinePtr, &endptr);
715 if (endptr == theBuffer.LinePtr) {
716 aStatus = VrmlData_NumericInputError;
719 if (isOnlyPos && aVal[i] < 0.001*Precision::Confusion()) {
720 aStatus = VrmlData_IrrelevantNumber;
723 theBuffer.LinePtr = endptr;
726 if (aStatus == VrmlData_StatusOK) {
728 theXYZ.SetCoord (aVal[0] * myLinearScale,
729 aVal[1] * myLinearScale,
730 aVal[2] * myLinearScale);
733 theXYZ.SetCoord (aVal[0], aVal[1], aVal[2]);
739 //=======================================================================
742 //=======================================================================
744 VrmlData_ErrorStatus VrmlData_Scene::ReadXY
745 (VrmlData_InBuffer& theBuffer,
747 Standard_Boolean isScale,
748 Standard_Boolean isOnlyPos) const
750 Standard_Real aVal[2] = {0., 0.};
751 VrmlData_ErrorStatus aStatus = VrmlData_StatusOK;
752 for (Standard_Integer i = 0; i < 2; i++) {
753 if (!VrmlData_Node::OK(aStatus, VrmlData_Scene::ReadLine(theBuffer)))
756 aVal[i] = Strtod (theBuffer.LinePtr, &endptr);
757 if (endptr == theBuffer.LinePtr) {
758 aStatus = VrmlData_NumericInputError;
761 if (isOnlyPos && aVal[i] < 0.001*Precision::Confusion()) {
762 aStatus = VrmlData_IrrelevantNumber;
765 theBuffer.LinePtr = endptr;
768 if (aStatus == VrmlData_StatusOK) {
770 theXY.SetCoord (aVal[0] * myLinearScale, aVal[1] * myLinearScale);
772 theXY.SetCoord (aVal[0], aVal[1]);
777 //=======================================================================
778 //function : ReadArrIndex
779 //purpose : Read the body of the data node (comma-separated list of int
781 //=======================================================================
783 VrmlData_ErrorStatus VrmlData_Scene::ReadArrIndex
784 (VrmlData_InBuffer& theBuffer,
785 const Standard_Integer **& theArray,
786 Standard_Size& theNBlocks) const
788 VrmlData_ErrorStatus aStatus;
790 if (VrmlData_Node::OK(aStatus, ReadLine(theBuffer))) {
791 if (theBuffer.LinePtr[0] != '[') // opening bracket
792 aStatus = VrmlData_VrmlFormatError;
795 NCollection_Vector<const Standard_Integer *> vecIndice;
796 NCollection_Vector<Standard_Integer> vecInt;
797 Standard_Boolean isMore (Standard_True);
800 // Loop reading integers from the stream
801 while (isMore && VrmlData_Node::OK(aStatus, ReadLine(theBuffer)))
803 // closing bracket, in case that it follows a comma
804 if (theBuffer.LinePtr[0] == ']') {
808 if (!VrmlData_Node::OK(aStatus, VrmlData_Node::ReadInteger(theBuffer,
811 // Check for valid delimiter (']' or ',')
812 if (!VrmlData_Node::OK(aStatus, ReadLine(theBuffer)))
814 if (theBuffer.LinePtr[0] == ']') {
816 isMore = Standard_False;
820 if (vecInt.Length() > 2)
822 // additional check for redundant point:
823 // ignore last point which is a dublicate of first point
824 if (anIntValue == vecInt[0])
829 // The input value is a node index, store it in the buffer vector
830 vecInt.Append(static_cast<Standard_Integer> (anIntValue));
832 if ((anIntValue < 0 || isMore == Standard_False)
833 && vecInt.Length() > 0)
835 const Standard_Integer aLen = vecInt.Length();
836 // The input is the end-of-face, store and close this face
837 Standard_Integer * bufFace = static_cast <Standard_Integer *>
838 (myAllocator->Allocate((aLen+1) * sizeof(Standard_Integer)));
840 aStatus = VrmlData_UnrecoverableError;
844 for (Standard_Integer i = 0; i < aLen; i++)
845 bufFace[i+1] = vecInt(i);
847 vecIndice.Append(bufFace);
850 if (aStatus == VrmlData_StatusOK) {
851 const Standard_Size aNbBlocks =
852 static_cast <Standard_Size> (vecIndice.Length());
854 const Standard_Integer ** anArray =
855 static_cast <const Standard_Integer **>
856 (myAllocator->Allocate (aNbBlocks * sizeof(Standard_Integer *)));
858 aStatus = VrmlData_UnrecoverableError;
860 for (size_t i = 0; i < aNbBlocks; i++)
861 anArray[i] = vecIndice((Standard_Integer)i);
862 theNBlocks = aNbBlocks;
872 //=======================================================================
873 //function : writeArrIndex
875 //=======================================================================
877 VrmlData_ErrorStatus VrmlData_Scene::WriteArrIndex
878 (const char * thePrefix,
879 const Standard_Integer ** theArrIndex,
880 const Standard_Size theNbBlocks) const
882 VrmlData_ErrorStatus aStatus (VrmlData_StatusOK);
883 if (theNbBlocks && (IsDummyWrite() == Standard_False)) {
884 if (VrmlData_Node::OK (aStatus,
885 WriteLine (thePrefix, "[", 1)))
887 const size_t aLineLimit = (myCurrentIndent < 41) ? 36 : 100;
889 for (Standard_Size iBlock = 0; iBlock < theNbBlocks; iBlock++) {
890 const Standard_Integer nVal (* theArrIndex[iBlock]);
891 const Standard_Integer * arrVal = theArrIndex[iBlock]+1;
894 Sprintf (buf, "%d,", arrVal[0]);
897 Sprintf (buf, "%d,%d,", arrVal[0], arrVal[1]);
900 Sprintf (buf, "%d,%d,%d,", arrVal[0], arrVal[1], arrVal[2]);
903 Sprintf (buf, "%d,%d,%d,%d,",
904 arrVal[0], arrVal[1], arrVal[2], arrVal[3]);
908 char * ptr = &buf[0];
909 for (Standard_Integer i = 0; i < nVal; i++) {
910 Sprintf (ptr, "%d,", arrVal[i]);
913 ptr = strchr (ptr, ',') + 1;
914 if ((ptr - &buf[0]) > (ptrdiff_t)aLineLimit) {
921 WriteLine (buf, iBlock < theNbBlocks-1 ? "-1," : "-1");
923 if (aStatus == VrmlData_StatusOK)
924 aStatus = WriteLine ("]", 0L, -1);
930 //=======================================================================
931 //function : WriteXYZ
933 //=======================================================================
935 VrmlData_ErrorStatus VrmlData_Scene::WriteXYZ
936 (const gp_XYZ& theXYZ,
937 const Standard_Boolean isApplyScale,
938 const char * thePostfix) const
941 if (IsDummyWrite() == Standard_False) {
942 if (isApplyScale && myLinearScale > Precision::Confusion())
943 Sprintf (buf, "%.12g %.12g %.12g%s", theXYZ.X() / myLinearScale,
944 theXYZ.Y() / myLinearScale, theXYZ.Z() / myLinearScale,
945 thePostfix ? thePostfix : "");
947 Sprintf (buf, "%.12g %.12g %.12g%s", theXYZ.X(), theXYZ.Y(), theXYZ.Z(),
948 thePostfix ? thePostfix : "");
950 return WriteLine (buf);
953 //=======================================================================
954 //function : WriteLine
955 //purpose : write the given string prepending the current indentation
956 //=======================================================================
958 VrmlData_ErrorStatus VrmlData_Scene::WriteLine
959 (const char * theLin0,
960 const char * theLin1,
961 const Standard_Integer theIndent) const
963 static const char spaces[] = " "
965 VrmlData_ErrorStatus& aStatus =
966 const_cast <VrmlData_ErrorStatus&> (myStatus);
968 aStatus = VrmlData_StatusOK;
970 Standard_Integer& aCurrentIndent =
971 const_cast <Standard_Integer&> (myCurrentIndent);
973 aCurrentIndent -= myIndent;
974 if (aCurrentIndent < 0)
976 if (theLin0 == 0L && theLin1 == 0L)
977 (* myOutput) << "\n";
979 const Standard_Integer nSpaces = Min (aCurrentIndent, sizeof(spaces)-1);
980 (* myOutput) << &spaces[sizeof(spaces)-1 - nSpaces];
982 (* myOutput) << theLin0;
984 (* myOutput) << " " << theLin1;
986 (* myOutput) << theLin1;
987 (* myOutput) << "\n";
989 const int stat = myOutput->rdstate();
990 if (stat & std::ios::badbit)
991 aStatus = VrmlData_UnrecoverableError;
992 else if (stat & std::ios::failbit)
993 // if (stat & std::ios::eofbit)
994 // aStatus = VrmlData_EndOfFile;
996 aStatus = VrmlData_GeneralError;
998 aCurrentIndent += myIndent;
1003 //=======================================================================
1004 //function : WriteNode
1006 //=======================================================================
1008 VrmlData_ErrorStatus VrmlData_Scene::WriteNode
1009 (const char * thePrefix,
1010 const Handle(VrmlData_Node)& theNode) const
1012 VrmlData_ErrorStatus aStatus (VrmlData_StatusOK);
1013 Standard_Boolean isNoName (Standard_False);
1014 if (theNode->Name() == 0L)
1015 isNoName = Standard_True;
1016 else if (theNode->Name()[0] == '\0')
1017 isNoName = Standard_True;
1019 if (theNode.IsNull() == Standard_False)
1020 if (theNode->IsDefault() == Standard_False) {
1021 if (isNoName && IsDummyWrite()) {
1022 // We are in a tentative 'write' session (nothing is written).
1023 // The goal is to identify multiply referred nodes.
1024 Standard_Address addrNode = theNode.operator->();
1025 if (!const_cast<NCollection_Map<Standard_Address>&>(myUnnamedNodesOut)
1028 Handle(VrmlData_UnknownNode) bidNode = new VrmlData_UnknownNode;
1031 Sprintf (buf, "_%d",
1032 ++const_cast<Standard_Integer&>(myAutoNameCounter));
1033 bidNode->myName = &buf[0];
1034 } while (myNamedNodes.Contains (bidNode));
1035 // We found the vacant automatic name, let us assign to it.
1036 theNode->setName (&buf[0]);
1037 const_cast<VrmlData_MapOfNode&>(myNamedNodes).Add (theNode);
1038 return aStatus; // do not search under already duplicated node
1042 aStatus = theNode->Write (thePrefix);
1044 // If the node name consists of blank characters, we do not write it
1045 const char * nptr = theNode->Name();
1046 for (; * nptr != '\0'; nptr++)
1047 if (* nptr != ' ' && * nptr != '\t')
1050 aStatus = theNode->Write (thePrefix);
1052 // Name is written under DEF clause
1053 TCollection_AsciiString buf;
1054 if (myNamedNodesOut.Contains (theNode))
1057 buf += theNode->Name();
1058 aStatus = WriteLine (thePrefix, buf.ToCString());
1068 buf += theNode->Name();
1069 aStatus = theNode->Write (buf.ToCString());
1070 const_cast<VrmlData_MapOfNode&>(myNamedNodesOut).Add (theNode);
1078 //=======================================================================
1081 //=======================================================================
1083 void VrmlData_Scene::Dump (Standard_OStream& theStream) const
1085 theStream << " ===== Diagnostic Dump of a Scene (" << myAllNodes.Extent()
1089 Iterator anIterA(myAllNodes);
1090 for (; anIterA.More(); anIterA.Next())
1091 dumpNode(theStream, anIterA.Value(), "");
1093 Iterator anIter(myLstNodes);
1094 for (; anIter.More(); anIter.Next())
1095 dumpNode(theStream, anIter.Value(), " ");
1098 //=======================================================================
1099 //function : dumpNode
1100 //purpose : static (local) function
1101 //=======================================================================
1103 void dumpNode (Standard_OStream& theStream,
1104 const Handle(VrmlData_Node)& theNode,
1105 const TCollection_AsciiString& theIndent)
1107 if (theNode.IsNull())
1109 TCollection_AsciiString aNewIndent =
1110 theIndent.IsEmpty() ? theIndent : theIndent + " ";
1111 if (theNode->IsKind(STANDARD_TYPE(VrmlData_Appearance))) {
1112 const Handle(VrmlData_Appearance) anAppearance =
1113 Handle(VrmlData_Appearance)::DownCast (theNode);
1114 dumpNodeHeader (theStream, theIndent, "Appearance", theNode->Name());
1115 if (theIndent.IsEmpty() == Standard_False) {
1116 dumpNode (theStream, anAppearance->Material(), aNewIndent);
1117 dumpNode (theStream, anAppearance->Texture(), aNewIndent);
1118 dumpNode (theStream, anAppearance->TextureTransform(), aNewIndent);
1120 } else if (theNode->IsKind(STANDARD_TYPE(VrmlData_ShapeNode))) {
1121 const Handle(VrmlData_ShapeNode) aShape =
1122 Handle(VrmlData_ShapeNode)::DownCast (theNode);
1123 dumpNodeHeader (theStream, theIndent, "Shape", theNode->Name());
1124 if (theIndent.IsEmpty() == Standard_False) {
1125 dumpNode (theStream, aShape->Appearance(), aNewIndent);
1126 dumpNode (theStream, aShape->Geometry(), aNewIndent);
1128 } else if (theNode->IsKind(STANDARD_TYPE(VrmlData_Box)))
1129 dumpNodeHeader (theStream, theIndent, "Box", theNode->Name());
1130 else if (theNode->IsKind(STANDARD_TYPE(VrmlData_Cylinder)))
1131 dumpNodeHeader (theStream, theIndent, "Cylinder", theNode->Name());
1132 else if (theNode->IsKind(STANDARD_TYPE(VrmlData_Sphere)))
1133 dumpNodeHeader (theStream, theIndent, "Sphere", theNode->Name());
1134 else if (theNode->IsKind(STANDARD_TYPE(VrmlData_Cone)))
1135 dumpNodeHeader (theStream, theIndent, "Cone", theNode->Name());
1136 else if (theNode->IsKind(STANDARD_TYPE(VrmlData_Coordinate)))
1137 dumpNodeHeader (theStream, theIndent, "Coordinate", theNode->Name());
1138 else if (theNode->IsKind(STANDARD_TYPE(VrmlData_Group))) {
1139 const Handle(VrmlData_Group) aGroup =
1140 Handle(VrmlData_Group)::DownCast (theNode);
1142 Sprintf (buf, "Group (%s)",
1143 aGroup->IsTransform() ? "Transform" : "Group");
1144 dumpNodeHeader (theStream, theIndent, buf, theNode->Name());
1145 if (theIndent.IsEmpty() == Standard_False) {
1146 VrmlData_ListOfNode::Iterator anIter = aGroup->NodeIterator();
1147 for (; anIter.More(); anIter.Next())
1148 dumpNode (theStream, anIter.Value(), aNewIndent);
1150 } else if (theNode->IsKind(STANDARD_TYPE(VrmlData_ImageTexture)))
1151 dumpNodeHeader (theStream, theIndent, "ImageTexture", theNode->Name());
1152 else if (theNode->IsKind(STANDARD_TYPE(VrmlData_IndexedFaceSet))) {
1153 const Handle(VrmlData_IndexedFaceSet) aNode =
1154 Handle(VrmlData_IndexedFaceSet)::DownCast(theNode);
1155 const Standard_Integer ** ppDummy;
1156 const Standard_Size nCoord = aNode->Coordinates()->Length();
1157 const Standard_Size nPoly = aNode->Polygons (ppDummy);
1159 Sprintf (buf, "IndexedFaceSet (%" PRIuPTR " vertices, %" PRIuPTR " polygons)",
1162 dumpNodeHeader (theStream, theIndent, buf, theNode->Name());
1163 } else if (theNode->IsKind(STANDARD_TYPE(VrmlData_IndexedLineSet))) {
1164 const Handle(VrmlData_IndexedLineSet) aNode =
1165 Handle(VrmlData_IndexedLineSet)::DownCast(theNode);
1166 const Standard_Integer ** ppDummy;
1167 const Standard_Size nCoord = aNode->Coordinates()->Length();
1168 const Standard_Size nPoly = aNode->Polygons (ppDummy);
1171 Sprintf(buf, "IndexedLineSet (%" PRIuPTR " vertices, %" PRIuPTR " polygons)",
1174 dumpNodeHeader (theStream, theIndent, buf, theNode->Name());
1175 } else if (theNode->IsKind(STANDARD_TYPE(VrmlData_Material))) {
1176 // const Handle(VrmlData_Material) aMaterial =
1177 // Handle(VrmlData_Material)::DownCast (theNode);
1178 dumpNodeHeader (theStream, theIndent, "Material", theNode->Name());
1180 else if (theNode->IsKind(STANDARD_TYPE(VrmlData_Normal)))
1181 dumpNodeHeader (theStream, theIndent, "Normal", theNode->Name());
1182 else if (theNode->IsKind(STANDARD_TYPE(VrmlData_TextureCoordinate)))
1183 dumpNodeHeader (theStream, theIndent, "TextureCoordinate", theNode->Name());
1184 else if (theNode->IsKind(STANDARD_TYPE(VrmlData_WorldInfo)))
1185 dumpNodeHeader (theStream, theIndent, "WorldInfo", theNode->Name());
1186 else if (theNode->IsKind(STANDARD_TYPE(VrmlData_UnknownNode))) {
1187 const Handle(VrmlData_UnknownNode) anUnknown =
1188 Handle(VrmlData_UnknownNode)::DownCast (theNode);
1190 Sprintf (buf, "Unknown (%s)", anUnknown->GetTitle().ToCString());
1191 dumpNodeHeader (theStream, theIndent, buf, theNode->Name());
1195 //=======================================================================
1196 //function : dumpNodeHeader
1198 //=======================================================================
1200 void dumpNodeHeader (Standard_OStream& theStream,
1201 const TCollection_AsciiString& theIndent,
1202 const char * theType,
1203 const char * theName)
1205 theStream << theIndent << theType << " node";
1206 if (theName[0] == '\0')
1209 theStream << ": \"" << theName << "\"\n";