1 // Created on: 2006-05-25
2 // Created by: Alexander GRIGORIEV
3 // Copyright (c) 2006-2012 OPEN CASCADE SAS
5 // The content of this file is subject to the Open CASCADE Technology Public
6 // License Version 6.5 (the "License"). You may not use the content of this file
7 // except in compliance with the License. Please obtain a copy of the License
8 // at http://www.opencascade.org and read it completely before using this file.
10 // The Initial Developer of the Original Code is Open CASCADE S.A.S., having its
11 // main offices at: 1, place des Freres Montgolfier, 78280 Guyancourt, France.
13 // The Original Code and all software distributed under the License is
14 // distributed on an "AS IS" basis, without warranty of any kind, and the
15 // Initial Developer hereby disclaims all such warranties, including without
16 // limitation, any warranties of merchantability, fitness for a particular
17 // purpose or non-infringement. Please see the License for the specific terms
18 // and conditions governing the rights and limitations under the License.
21 #include <VrmlData_Scene.hxx>
22 #include <VrmlData_InBuffer.hxx>
23 #include <VrmlData_Appearance.hxx>
24 #include <VrmlData_Box.hxx>
25 #include <VrmlData_Color.hxx>
26 #include <VrmlData_Cone.hxx>
27 #include <VrmlData_Coordinate.hxx>
28 #include <VrmlData_Cylinder.hxx>
29 #include <VrmlData_DataMapOfShapeAppearance.hxx>
30 #include <VrmlData_Group.hxx>
31 #include <VrmlData_ImageTexture.hxx>
32 #include <VrmlData_InBuffer.hxx>
33 #include <VrmlData_IndexedFaceSet.hxx>
34 #include <VrmlData_IndexedLineSet.hxx>
35 #include <VrmlData_Material.hxx>
36 #include <VrmlData_Normal.hxx>
37 #include <VrmlData_Scene.hxx>
38 #include <VrmlData_ShapeNode.hxx>
39 #include <VrmlData_Sphere.hxx>
40 #include <VrmlData_TextureCoordinate.hxx>
41 #include <VrmlData_UnknownNode.hxx>
42 //#include <VrmlData_WorldInfo.hxx>
43 #include <NCollection_Vector.hxx>
44 #include <TopoDS_TFace.hxx>
46 #include <TopoDS_Face.hxx>
47 #include <TopExp_Explorer.hxx>
48 #include <BRep_Builder.hxx>
49 #include <Precision.hxx>
52 #define _CRT_SECURE_NO_DEPRECATE
53 #pragma warning (disable:4996)
56 static void dumpNode (Standard_OStream& theStream,
57 const Handle(VrmlData_Node)& theNode,
58 const TCollection_AsciiString& theIndent);
60 static void dumpNodeHeader (Standard_OStream& theStream,
61 const TCollection_AsciiString& theIndent,
63 const char * theName);
65 //=======================================================================
66 //function : VrmlData_Scene
67 //purpose : Constructor
68 //=======================================================================
70 VrmlData_Scene::VrmlData_Scene
71 (const Handle(NCollection_IncAllocator)& theAlloc)
73 myStatus (VrmlData_StatusOK),
74 myAllocator (theAlloc.IsNull() ?
75 new NCollection_IncAllocator : theAlloc.operator->()),
82 myWorldInfo = new VrmlData_WorldInfo (* this);
83 myWorldInfo->AddInfo ("Created by OPEN CASCADE (tm) VrmlData API");
84 myLstNodes.Append (myWorldInfo);
85 myAllNodes.Append (myWorldInfo);
88 //=======================================================================
91 //=======================================================================
93 const Handle(VrmlData_Node)& VrmlData_Scene::AddNode
94 (const Handle(VrmlData_Node)& theN,
95 const Standard_Boolean isTopLevel)
97 if (theN.IsNull() == Standard_False)
98 if (theN->IsKind (STANDARD_TYPE(VrmlData_WorldInfo)) == Standard_False) {
100 const Handle(VrmlData_Node)& aNode =
101 myAllNodes.Append ((&theN->Scene()== this) ? theN : theN->Clone (NULL));
102 // Name is checked for uniqueness. If not, letter 'D' is appended until
103 // the name proves to be unique.
104 if (aNode->Name()[0] != '\0')
105 while (myNamedNodes.Add (aNode) == Standard_False)
106 aNode->setName (aNode->Name(), "D");
108 myLstNodes.Append (aNode);
112 static Handle(VrmlData_Node) aNullNode;
117 //=======================================================================
118 //function : operator <<
119 //purpose : Export to text stream (file or else)
120 //=======================================================================
122 Standard_OStream& operator << (Standard_OStream& theOutput,
123 const VrmlData_Scene& theScene)
125 VrmlData_Scene& aScene = const_cast <VrmlData_Scene&> (theScene);
126 aScene.myMutex.Lock();
127 aScene.myCurrentIndent = 0;
128 aScene.myLineError = 0;
129 aScene.myOutput = 0L;
130 aScene.myNamedNodesOut.Clear();
131 aScene.myUnnamedNodesOut.Clear();
132 aScene.myAutoNameCounter = 0;
136 VrmlData_Scene::Iterator anIterD(aScene.myLstNodes);
137 for (; anIterD.More(); anIterD.Next()) {
138 const Handle(VrmlData_Node)& aNode = anIterD.Value();
139 if (aNode.IsNull() == Standard_False) {
140 const VrmlData_ErrorStatus aStatus = aScene.WriteNode (0L, aNode);
141 if (aStatus != VrmlData_StatusOK &&
142 aStatus != VrmlData_NotImplemented)
147 aScene.myOutput = &theOutput;
148 aScene.myNamedNodesOut.Clear();
149 theOutput << "#VRML V2.0 utf8" << endl << endl;
153 VrmlData_Scene::Iterator anIter(aScene.myLstNodes);
154 for (; anIter.More(); anIter.Next()) {
155 const Handle(VrmlData_Node)& aNode = anIter.Value();
156 if (aNode.IsNull() == Standard_False) {
157 const VrmlData_ErrorStatus aStatus = aScene.WriteNode (0L, aNode);
158 if (aStatus != VrmlData_StatusOK &&
159 aStatus != VrmlData_NotImplemented)
163 aScene.myOutput = 0L;
164 aScene.myNamedNodesOut.Clear();
165 aScene.myUnnamedNodesOut.Clear();
166 aScene.myMutex.Unlock();
170 //=======================================================================
171 //function : SetVrmlDir
173 //=======================================================================
175 void VrmlData_Scene::SetVrmlDir (const TCollection_ExtendedString& theDir)
177 TCollection_ExtendedString& aDir = myVrmlDir.Append (theDir);
178 const Standard_ExtCharacter aTerminator = aDir.Value(aDir.Length());
179 if (aTerminator != Standard_ExtCharacter('\\') &&
180 aTerminator != Standard_ExtCharacter('/'))
182 aDir += TCollection_ExtendedString ("\\");
184 aDir += TCollection_ExtendedString ("/");
188 //=======================================================================
189 //function : WorldInfo
191 //=======================================================================
193 const Handle_VrmlData_WorldInfo& VrmlData_Scene::WorldInfo() const
198 //=======================================================================
199 //function : readLine
201 //=======================================================================
203 VrmlData_ErrorStatus VrmlData_Scene::readLine (VrmlData_InBuffer& theBuffer)
205 VrmlData_ErrorStatus aStatus = VrmlData_StatusOK;
206 if (theBuffer.Input.eof())
207 aStatus = VrmlData_EndOfFile;
209 theBuffer.Input.getline (theBuffer.Line, sizeof(theBuffer.Line));
210 theBuffer.LineCount++;
211 const int stat = theBuffer.Input.rdstate();
212 if (stat & ios::badbit)
213 aStatus = VrmlData_UnrecoverableError;
214 else if (stat & ios::failbit)
215 if (stat & ios::eofbit)
216 aStatus = VrmlData_EndOfFile;
218 aStatus = VrmlData_GeneralError;
219 theBuffer.LinePtr = &theBuffer.Line[0];
220 theBuffer.IsProcessed = Standard_False;
225 //=======================================================================
226 //function : ReadLine
228 //=======================================================================
230 VrmlData_ErrorStatus VrmlData_Scene::ReadLine (VrmlData_InBuffer& theBuffer)
232 VrmlData_ErrorStatus aStatus (VrmlData_StatusOK);
234 while (aStatus == VrmlData_StatusOK) {
235 // Find the first significant character of the line
236 for (; * theBuffer.LinePtr != '\0'; theBuffer.LinePtr++) {
237 if (* theBuffer.LinePtr != ' ' && * theBuffer.LinePtr != '\t'
238 && * theBuffer.LinePtr != ',')
240 if (* theBuffer.LinePtr == '\n' || * theBuffer.LinePtr == '\r' ||
241 * theBuffer.LinePtr == '#')
242 // go requesting the next line
247 // the line is empty here (no significant characters). Read the next one.
248 aStatus = readLine (theBuffer);
251 // error or EOF detected
255 // Try to detect comment
256 if (theBuffer.IsProcessed == Standard_False) {
257 Standard_Boolean isQuoted (Standard_False);
258 Standard_Integer anOffset (0);
259 char * ptr = theBuffer.LinePtr;
260 for (; * ptr != '\0'; ptr++) {
262 * ptr = ptr[anOffset];
263 if (* ptr == '\n' || * ptr == '\r' || * ptr == '#') {
264 if (isQuoted == Standard_False) {
268 } else if (* ptr == '\\' && isQuoted)
269 ptr[0] = ptr[++anOffset];
270 else if (* ptr == '\"')
271 isQuoted = !isQuoted;
273 theBuffer.IsProcessed = Standard_True;
278 //=======================================================================
279 //function : readHeader
281 //=======================================================================
283 VrmlData_ErrorStatus VrmlData_Scene::readHeader (VrmlData_InBuffer& theBuffer)
285 VrmlData_ErrorStatus aStat = readLine (theBuffer);
286 if (aStat == VrmlData_StatusOK &&
287 !VRMLDATA_LCOMPARE(theBuffer.LinePtr, "#VRML V2.0"))
288 aStat = VrmlData_NotVrmlFile;
290 aStat = readLine(theBuffer);
294 //=======================================================================
295 //function : operator <<
296 //purpose : Import from text stream (file or else)
297 //=======================================================================
299 VrmlData_Scene& VrmlData_Scene::operator << (Standard_IStream& theInput)
301 VrmlData_InBuffer aBuffer (theInput);
303 // Read the VRML header
304 myStatus = readHeader (aBuffer);
305 const Handle(VrmlData_UnknownNode) aNullNode= new VrmlData_UnknownNode(*this);
306 // if (myStatus == StatusOK)
307 // myStatus = ReadLine (aBuffer);
308 // Read VRML data by nodes
310 if (!VrmlData_Node::OK(myStatus, ReadLine(aBuffer))) {
311 if (myStatus == VrmlData_EndOfFile)
312 myStatus = VrmlData_StatusOK;
315 // this line provides the method ReadNode in the present context
316 Handle(VrmlData_Node) aNode;
317 myStatus = aNullNode->ReadNode (aBuffer, aNode);
318 // Unknown nodes are not stored however they do not generate error
319 if (myStatus != VrmlData_StatusOK)
321 if (aNode.IsNull() == Standard_False /*&&
322 !aNode->IsKind (STANDARD_TYPE(VrmlData_UnknownNode))*/)
324 if (aNode->IsKind (STANDARD_TYPE(VrmlData_WorldInfo)) == Standard_False)
325 myLstNodes.Append (aNode);
326 else if (aNode->IsDefault() == Standard_False) {
327 const Handle(VrmlData_WorldInfo) aInfo =
328 Handle(VrmlData_WorldInfo)::DownCast (aNode);
329 myWorldInfo->SetTitle (aInfo->Title());
330 NCollection_List <const char *>::Iterator anIterInfo =
331 aInfo->InfoIterator();
332 for (; anIterInfo.More(); anIterInfo.Next())
333 myWorldInfo->AddInfo (anIterInfo.Value());
337 if (myStatus != VrmlData_StatusOK)
338 myLineError = aBuffer.LineCount;
343 //=======================================================================
344 //function : FindNode
346 //=======================================================================
348 Handle(VrmlData_Node) VrmlData_Scene::FindNode
349 (const char * theName,
350 const Handle(Standard_Type)& theType) const
352 Handle(VrmlData_Node) aResult;
354 Iterator anIter (myAllNodes);
355 for (; anIter.More(); anIter.Next())
356 if (!strcmp (anIter.Value()->Name(), theName)) {
357 aResult = anIter.Value();
358 if (theType.IsNull())
360 if (aResult->IsKind(theType))
365 const Handle(VrmlData_UnknownNode) aDummyNode = new VrmlData_UnknownNode;
366 aDummyNode->myName = theName;
367 if (myNamedNodes.Contains (aDummyNode))
368 aResult = const_cast<VrmlData_MapOfNode&>(myNamedNodes).Added(aDummyNode);
373 //=======================================================================
374 //function : FindNode
376 //=======================================================================
378 Handle(VrmlData_Node) VrmlData_Scene::FindNode
379 (const char * theName,
380 gp_Trsf& theLocation) const
383 Handle(VrmlData_Node) aResult;
384 Iterator anIter (myLstNodes);
385 for (; anIter.More(); anIter.Next()) {
386 const Handle(VrmlData_Node)& aNode = anIter.Value();
389 // Match a top-level node name
390 if (strcmp(aNode->Name(), theName) == 0) {
395 // Try a Group type of node
396 if (aNode->IsKind(STANDARD_TYPE(VrmlData_Group)))
398 const Handle(VrmlData_Group) aGroup =
399 Handle(VrmlData_Group)::DownCast (aNode);
400 if (aGroup.IsNull() == Standard_False) {
401 aResult = aGroup->FindNode(theName, theLocation);
402 if (aResult.IsNull() == Standard_False)
410 //=======================================================================
411 //function : ReadWord
413 //=======================================================================
415 VrmlData_ErrorStatus VrmlData_Scene::ReadWord
416 (VrmlData_InBuffer& theBuffer,
417 TCollection_AsciiString& theWord)
419 VrmlData_ErrorStatus aStatus = ReadLine(theBuffer);
420 if (aStatus == VrmlData_StatusOK) {
421 char * ptr = theBuffer.LinePtr;
422 while (* ptr != '\0' && * ptr != '\n' && * ptr != '\r' &&
423 * ptr != ' ' && * ptr != '\t' && * ptr != '{' && * ptr != '}' &&
424 * ptr != ',' && * ptr != '[' && * ptr != ']')
426 const Standard_Integer aLen = Standard_Integer(ptr - theBuffer.LinePtr);
428 aStatus = VrmlData_StringInputError;
430 theWord = TCollection_AsciiString ((Standard_CString)theBuffer.LinePtr,
432 theBuffer.LinePtr = ptr;
438 //=======================================================================
439 //function : createNode
441 //=======================================================================
443 VrmlData_ErrorStatus VrmlData_Scene::createNode
444 (VrmlData_InBuffer& theBuffer,
445 Handle(VrmlData_Node)& theNode,
446 const Handle(Standard_Type)& theType)
448 VrmlData_ErrorStatus aStatus;
449 Handle(VrmlData_Node) aNode;
450 TCollection_AsciiString aName;
452 // Read the DEF token to assign the node name
453 if (VrmlData_Node::OK(aStatus, ReadLine(theBuffer)))
454 if (VRMLDATA_LCOMPARE(theBuffer.LinePtr, "DEF")) {
455 if (VrmlData_Node::OK(aStatus, ReadWord (theBuffer, aName)))
456 aStatus = ReadLine(theBuffer);
457 } 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 == ']') {
546 if (aStatus == VrmlData_StatusOK)
547 aNode = new VrmlData_UnknownNode(* this,
552 aStatus = ReadLine(theBuffer);
553 if (aNode.IsNull() == Standard_False) {
554 if (aNode->Name()[0] != '\0')
555 myNamedNodes.Add (aNode);
556 if (theType.IsNull() == Standard_False)
557 if (aNode->IsKind(theType) == Standard_False)
558 aStatus = VrmlData_VrmlFormatError;
560 if (aStatus == VrmlData_StatusOK)
561 if (theBuffer.LinePtr[0] == '{') {
564 myAllNodes.Append(aNode);
566 aStatus = VrmlData_VrmlFormatError;
570 //=======================================================================
571 //function : operator TopoDS_Shape
573 //=======================================================================
575 VrmlData_Scene::operator TopoDS_Shape () const
578 VrmlData_Scene::createShape (aShape, myLstNodes, 0L);
582 //=======================================================================
583 //function : GetShape
585 //=======================================================================
587 TopoDS_Shape VrmlData_Scene::GetShape (VrmlData_DataMapOfShapeAppearance& aMap)
590 VrmlData_Scene::createShape (aShape, myLstNodes, &aMap);
594 //=======================================================================
595 //function : createShape
597 //=======================================================================
599 void VrmlData_Scene::createShape
600 (TopoDS_Shape& outShape,
601 const VrmlData_ListOfNode& lstNodes,
602 VrmlData_DataMapOfShapeAppearance* pMapShapeApp)
604 TopoDS_Shape aSingleShape; // used when there is a single ShapeNode
605 Standard_Boolean isSingleShape (Standard_True);
606 BRep_Builder aBuilder;
608 aBuilder.MakeCompound(TopoDS::Compound(outShape));
609 aSingleShape.Orientation(TopAbs_FORWARD);
611 Iterator anIter (lstNodes);
612 for (; anIter.More(); anIter.Next()) {
613 // Try a Shape type of node
614 const Handle(VrmlData_ShapeNode) aNodeShape =
615 Handle(VrmlData_ShapeNode)::DownCast (anIter.Value());
616 if (aNodeShape.IsNull() == Standard_False) {
617 const Handle(VrmlData_Geometry) aNodeGeom =
618 Handle(VrmlData_Geometry)::DownCast(aNodeShape->Geometry());
619 if (aNodeGeom.IsNull() == Standard_False) {
620 if (aSingleShape.IsNull() == Standard_False)
621 isSingleShape = Standard_False;
622 const Handle(TopoDS_TShape) aTShape = aNodeGeom->TShape();
623 aSingleShape.TShape(aTShape);
624 if (aSingleShape.IsNull() == Standard_False) {
625 aBuilder.Add (outShape, aSingleShape);
626 if (pMapShapeApp != 0L) {
627 const Handle(VrmlData_Appearance)& anAppearance =
628 aNodeShape->Appearance();
629 if (anAppearance.IsNull() == Standard_False) {
630 // Check if the current topology is a single face
631 if (aTShape->IsKind(STANDARD_TYPE(TopoDS_TFace)))
632 pMapShapeApp->Bind(aTShape, anAppearance);
634 // This is not a face, explode it in faces and bind each face
635 TopoDS_Shape aCurShape;
636 aCurShape.TShape(aTShape);
637 TopExp_Explorer anExp(aCurShape, TopAbs_FACE);
638 for (; anExp.More(); anExp.Next()) {
639 const TopoDS_Face& aFace = TopoDS::Face(anExp.Current());
640 pMapShapeApp->Bind(aFace.TShape(), anAppearance);
649 // Try a Group type of node
650 const Handle(VrmlData_Group) aNodeGroup =
651 Handle(VrmlData_Group)::DownCast (anIter.Value());
652 if (aNodeGroup.IsNull() == Standard_False) {
654 aNodeGroup->Shape(aShape, pMapShapeApp);
655 if (aShape.IsNull() == Standard_False) {
656 aBuilder.Add (outShape, aShape);
657 isSingleShape = Standard_False;
662 outShape = aSingleShape;
665 //=======================================================================
666 //function : ReadReal
668 //=======================================================================
670 VrmlData_ErrorStatus VrmlData_Scene::ReadReal
671 (VrmlData_InBuffer& theBuffer,
672 Standard_Real& theResult,
673 Standard_Boolean isScale,
674 Standard_Boolean isOnlyPositive) const
676 Standard_Real aResult(0.);
677 VrmlData_ErrorStatus aStatus;
678 if (VrmlData_Node::OK(aStatus, VrmlData_Scene::ReadLine(theBuffer))) {
680 aResult = strtod (theBuffer.LinePtr, &endptr);
681 if (endptr == theBuffer.LinePtr)
682 aStatus = VrmlData_NumericInputError;
683 else if (isOnlyPositive && aResult < 0.001*Precision::Confusion())
684 aStatus = VrmlData_IrrelevantNumber;
686 theResult = isScale ? (aResult * myLinearScale) : aResult;
687 theBuffer.LinePtr = endptr;
693 //=======================================================================
696 //=======================================================================
698 VrmlData_ErrorStatus VrmlData_Scene::ReadXYZ
699 (VrmlData_InBuffer& theBuffer,
701 Standard_Boolean isScale,
702 Standard_Boolean isOnlyPos) const
704 Standard_Real aVal[3] = {0., 0., 0.};
705 VrmlData_ErrorStatus aStatus;
706 for (Standard_Integer i = 0; i < 3; i++) {
707 if (!VrmlData_Node::OK(aStatus, VrmlData_Scene::ReadLine(theBuffer)))
710 aVal[i] = strtod (theBuffer.LinePtr, &endptr);
711 if (endptr == theBuffer.LinePtr) {
712 aStatus = VrmlData_NumericInputError;
715 if (isOnlyPos && aVal[i] < 0.001*Precision::Confusion()) {
716 aStatus = VrmlData_IrrelevantNumber;
719 theBuffer.LinePtr = endptr;
722 if (aStatus == VrmlData_StatusOK)
724 theXYZ.SetCoord (aVal[0] * myLinearScale,
725 aVal[1] * myLinearScale,
726 aVal[2] * myLinearScale);
728 theXYZ.SetCoord (aVal[0], aVal[1], aVal[2]);
732 //=======================================================================
735 //=======================================================================
737 VrmlData_ErrorStatus VrmlData_Scene::ReadXY
738 (VrmlData_InBuffer& theBuffer,
740 Standard_Boolean isScale,
741 Standard_Boolean isOnlyPos) const
743 Standard_Real aVal[2] = {0., 0.};
744 VrmlData_ErrorStatus aStatus;
745 for (Standard_Integer i = 0; i < 2; i++) {
746 if (!VrmlData_Node::OK(aStatus, VrmlData_Scene::ReadLine(theBuffer)))
749 aVal[i] = strtod (theBuffer.LinePtr, &endptr);
750 if (endptr == theBuffer.LinePtr) {
751 aStatus = VrmlData_NumericInputError;
754 if (isOnlyPos && aVal[i] < 0.001*Precision::Confusion()) {
755 aStatus = VrmlData_IrrelevantNumber;
758 theBuffer.LinePtr = endptr;
761 if (aStatus == VrmlData_StatusOK)
763 theXY.SetCoord (aVal[0] * myLinearScale, aVal[1] * myLinearScale);
765 theXY.SetCoord (aVal[0], aVal[1]);
769 //=======================================================================
770 //function : ReadArrIndex
771 //purpose : Read the body of the data node (comma-separated list of int
773 //=======================================================================
775 VrmlData_ErrorStatus VrmlData_Scene::ReadArrIndex
776 (VrmlData_InBuffer& theBuffer,
777 const Standard_Integer **& theArray,
778 Standard_Size& theNBlocks) const
780 VrmlData_ErrorStatus aStatus;
782 if (VrmlData_Node::OK(aStatus, ReadLine(theBuffer)))
783 if (theBuffer.LinePtr[0] != '[') // opening bracket
784 aStatus = VrmlData_VrmlFormatError;
787 NCollection_Vector<const Standard_Integer *> vecIndice;
788 NCollection_Vector<Standard_Integer> vecInt;
789 Standard_Boolean isMore (Standard_True);
792 // Loop reading integers from the stream
793 while (isMore && VrmlData_Node::OK(aStatus, ReadLine(theBuffer)))
795 // closing bracket, in case that it follows a comma
796 if (theBuffer.LinePtr[0] == ']') {
800 if (!VrmlData_Node::OK(aStatus, VrmlData_Node::ReadInteger(theBuffer,
803 // Check for valid delimiter (']' or ',')
804 if (!VrmlData_Node::OK(aStatus, ReadLine(theBuffer)))
806 if (theBuffer.LinePtr[0] == ']') {
808 isMore = Standard_False;
811 // The input value is a node index, store it in the buffer vector
812 vecInt.Append (static_cast<Standard_Integer> (anIntValue));
813 if ((anIntValue < 0 || isMore == Standard_False)
814 && vecInt.Length() > 0)
816 const Standard_Integer aLen = vecInt.Length();
817 // The input is the end-of-face, store and close this face
818 Standard_Integer * bufFace = static_cast <Standard_Integer *>
819 (myAllocator->Allocate((aLen+1) * sizeof(Standard_Integer)));
821 aStatus = VrmlData_UnrecoverableError;
825 for (Standard_Integer i = 0; i < aLen; i++)
826 bufFace[i+1] = vecInt(i);
828 vecIndice.Append(bufFace);
831 if (aStatus == VrmlData_StatusOK) {
832 const Standard_Size aNbBlocks =
833 static_cast <Standard_Size> (vecIndice.Length());
835 const Standard_Integer ** anArray =
836 static_cast <const Standard_Integer **>
837 (myAllocator->Allocate (aNbBlocks * sizeof(Standard_Integer *)));
839 aStatus = VrmlData_UnrecoverableError;
841 for (size_t i = 0; i < aNbBlocks; i++)
842 anArray[i] = vecIndice((Standard_Integer)i);
843 theNBlocks = aNbBlocks;
852 //=======================================================================
853 //function : writeArrIndex
855 //=======================================================================
857 VrmlData_ErrorStatus VrmlData_Scene::WriteArrIndex
858 (const char * thePrefix,
859 const Standard_Integer ** theArrIndex,
860 const Standard_Size theNbBlocks) const
862 VrmlData_ErrorStatus aStatus (VrmlData_StatusOK);
863 if (theNbBlocks && (IsDummyWrite() == Standard_False)) {
864 if (VrmlData_Node::OK (aStatus,
865 WriteLine (thePrefix, "[", 1)))
867 const size_t aLineLimit = (myCurrentIndent < 41) ? 36 : 100;
869 for (Standard_Size iBlock = 0; iBlock < theNbBlocks; iBlock++) {
870 const Standard_Integer nVal (* theArrIndex[iBlock]);
871 const Standard_Integer * arrVal = theArrIndex[iBlock]+1;
874 sprintf (buf, "%d,", arrVal[0]);
877 sprintf (buf, "%d,%d,", arrVal[0], arrVal[1]);
880 sprintf (buf, "%d,%d,%d,", arrVal[0], arrVal[1], arrVal[2]);
883 sprintf (buf, "%d,%d,%d,%d,",
884 arrVal[0], arrVal[1], arrVal[2], arrVal[3]);
888 char * ptr = &buf[0];
889 for (Standard_Integer i = 0; i < nVal; i++) {
890 sprintf (ptr, "%d,", arrVal[i]);
891 ptr = strchr (ptr, ',') + 1;
892 if ((ptr - &buf[0]) > (ptrdiff_t)aLineLimit) {
899 WriteLine (buf, iBlock < theNbBlocks-1 ? "-1," : "-1");
901 if (aStatus == VrmlData_StatusOK)
902 aStatus = WriteLine ("]", 0L, -1);
908 //=======================================================================
909 //function : WriteXYZ
911 //=======================================================================
913 VrmlData_ErrorStatus VrmlData_Scene::WriteXYZ
914 (const gp_XYZ& theXYZ,
915 const Standard_Boolean isApplyScale,
916 const char * thePostfix) const
919 if (IsDummyWrite() == Standard_False)
920 if (isApplyScale && myLinearScale > Precision::Confusion())
921 sprintf (buf, "%.12g %.12g %.12g%s", theXYZ.X() / myLinearScale,
922 theXYZ.Y() / myLinearScale, theXYZ.Z() / myLinearScale,
923 thePostfix ? thePostfix : "");
925 sprintf (buf, "%.12g %.12g %.12g%s", theXYZ.X(), theXYZ.Y(), theXYZ.Z(),
926 thePostfix ? thePostfix : "");
927 return WriteLine (buf);
930 //=======================================================================
931 //function : WriteLine
932 //purpose : write the given string prepending the current indentation
933 //=======================================================================
935 VrmlData_ErrorStatus VrmlData_Scene::WriteLine
936 (const char * theLin0,
937 const char * theLin1,
938 const Standard_Integer theIndent) const
940 static const char spaces[] = " "
942 VrmlData_ErrorStatus& aStatus =
943 const_cast <VrmlData_ErrorStatus&> (myStatus);
945 aStatus = VrmlData_StatusOK;
947 Standard_Integer& aCurrentIndent =
948 const_cast <Standard_Integer&> (myCurrentIndent);
950 aCurrentIndent -= myIndent;
951 if (aCurrentIndent < 0)
953 if (theLin0 == 0L && theLin1 == 0L)
954 (* myOutput) << endl;
956 const Standard_Integer nSpaces = Min (aCurrentIndent, sizeof(spaces)-1);
957 (* myOutput) << &spaces[sizeof(spaces)-1 - nSpaces];
959 (* myOutput) << theLin0;
961 (* myOutput) << ' ' << theLin1;
963 (* myOutput) << theLin1;
964 (* myOutput) << endl;
966 const int stat = myOutput->rdstate();
967 if (stat & ios::badbit)
968 aStatus = VrmlData_UnrecoverableError;
969 else if (stat & ios::failbit)
970 // if (stat & ios::eofbit)
971 // aStatus = VrmlData_EndOfFile;
973 aStatus = VrmlData_GeneralError;
975 aCurrentIndent += myIndent;
980 //=======================================================================
981 //function : WriteNode
983 //=======================================================================
985 VrmlData_ErrorStatus VrmlData_Scene::WriteNode
986 (const char * thePrefix,
987 const Handle(VrmlData_Node)& theNode) const
989 VrmlData_ErrorStatus aStatus (VrmlData_StatusOK);
990 Standard_Boolean isNoName (Standard_False);
991 if (theNode->Name() == 0L)
992 isNoName = Standard_True;
993 else if (theNode->Name()[0] == '\0')
994 isNoName = Standard_True;
996 if (theNode.IsNull() == Standard_False)
997 if (theNode->IsDefault() == Standard_False) {
998 if (isNoName && IsDummyWrite()) {
999 // We are in a tentative 'write' session (nothing is written).
1000 // The goal is to identify multiply referred nodes.
1001 Standard_Address addrNode = theNode.operator->();
1002 if (!const_cast<NCollection_Map<Standard_Address>&>(myUnnamedNodesOut)
1005 Handle(VrmlData_UnknownNode) bidNode = new VrmlData_UnknownNode;
1008 sprintf (buf, "_%d",
1009 ++const_cast<Standard_Integer&>(myAutoNameCounter));
1010 bidNode->myName = &buf[0];
1011 } while (myNamedNodes.Contains (bidNode));
1012 // We found the vacant automatic name, let us assign to it.
1013 theNode->setName (&buf[0]);
1014 const_cast<VrmlData_MapOfNode&>(myNamedNodes).Add (theNode);
1015 return aStatus; // do not search under already duplicated node
1019 aStatus = theNode->Write (thePrefix);
1021 // If the node name consists of blank characters, we do not write it
1022 const char * nptr = theNode->Name();
1023 for (; * nptr != '\0'; nptr++)
1024 if (* nptr != ' ' && * nptr != '\t')
1027 aStatus = theNode->Write (thePrefix);
1029 // Name is written under DEF clause
1030 TCollection_AsciiString buf;
1031 if (myNamedNodesOut.Contains (theNode))
1034 buf += theNode->Name();
1035 aStatus = WriteLine (thePrefix, buf.ToCString());
1045 buf += theNode->Name();
1046 aStatus = theNode->Write (buf.ToCString());
1047 const_cast<VrmlData_MapOfNode&>(myNamedNodesOut).Add (theNode);
1055 //=======================================================================
1058 //=======================================================================
1060 void VrmlData_Scene::Dump (Standard_OStream& theStream) const
1062 theStream << " ===== Diagnostic Dump of a Scene (" << myAllNodes.Extent()
1063 << " nodes)" << endl;
1066 Iterator anIterA(myAllNodes);
1067 for (; anIterA.More(); anIterA.Next())
1068 dumpNode(theStream, anIterA.Value(), "");
1070 Iterator anIter(myLstNodes);
1071 for (; anIter.More(); anIter.Next())
1072 dumpNode(theStream, anIter.Value(), " ");
1075 //=======================================================================
1076 //function : dumpNode
1077 //purpose : static (local) function
1078 //=======================================================================
1080 void dumpNode (Standard_OStream& theStream,
1081 const Handle(VrmlData_Node)& theNode,
1082 const TCollection_AsciiString& theIndent)
1084 if (theNode.IsNull())
1086 TCollection_AsciiString aNewIndent =
1087 theIndent.IsEmpty() ? theIndent : theIndent + " ";
1088 if (theNode->IsKind(STANDARD_TYPE(VrmlData_Appearance))) {
1089 const Handle(VrmlData_Appearance) anAppearance =
1090 Handle(VrmlData_Appearance)::DownCast (theNode);
1091 dumpNodeHeader (theStream, theIndent, "Appearance", theNode->Name());
1092 if (theIndent.IsEmpty() == Standard_False) {
1093 dumpNode (theStream, anAppearance->Material(), aNewIndent);
1094 dumpNode (theStream, anAppearance->Texture(), aNewIndent);
1095 dumpNode (theStream, anAppearance->TextureTransform(), aNewIndent);
1097 } else if (theNode->IsKind(STANDARD_TYPE(VrmlData_ShapeNode))) {
1098 const Handle(VrmlData_ShapeNode) aShape =
1099 Handle(VrmlData_ShapeNode)::DownCast (theNode);
1100 dumpNodeHeader (theStream, theIndent, "Shape", theNode->Name());
1101 if (theIndent.IsEmpty() == Standard_False) {
1102 dumpNode (theStream, aShape->Appearance(), aNewIndent);
1103 dumpNode (theStream, aShape->Geometry(), aNewIndent);
1105 } else if (theNode->IsKind(STANDARD_TYPE(VrmlData_Box)))
1106 dumpNodeHeader (theStream, theIndent, "Box", theNode->Name());
1107 else if (theNode->IsKind(STANDARD_TYPE(VrmlData_Cylinder)))
1108 dumpNodeHeader (theStream, theIndent, "Cylinder", theNode->Name());
1109 else if (theNode->IsKind(STANDARD_TYPE(VrmlData_Sphere)))
1110 dumpNodeHeader (theStream, theIndent, "Sphere", theNode->Name());
1111 else if (theNode->IsKind(STANDARD_TYPE(VrmlData_Cone)))
1112 dumpNodeHeader (theStream, theIndent, "Cone", theNode->Name());
1113 else if (theNode->IsKind(STANDARD_TYPE(VrmlData_Coordinate)))
1114 dumpNodeHeader (theStream, theIndent, "Coordinate", theNode->Name());
1115 else if (theNode->IsKind(STANDARD_TYPE(VrmlData_Group))) {
1116 const Handle(VrmlData_Group) aGroup =
1117 Handle(VrmlData_Group)::DownCast (theNode);
1119 sprintf (buf, "Group (%s)",
1120 aGroup->IsTransform() ? "Transform" : "Group");
1121 dumpNodeHeader (theStream, theIndent, buf, theNode->Name());
1122 if (theIndent.IsEmpty() == Standard_False) {
1123 VrmlData_ListOfNode::Iterator anIter = aGroup->NodeIterator();
1124 for (; anIter.More(); anIter.Next())
1125 dumpNode (theStream, anIter.Value(), aNewIndent);
1127 } else if (theNode->IsKind(STANDARD_TYPE(VrmlData_ImageTexture)))
1128 dumpNodeHeader (theStream, theIndent, "ImageTexture", theNode->Name());
1129 else if (theNode->IsKind(STANDARD_TYPE(VrmlData_IndexedFaceSet))) {
1130 const Handle(VrmlData_IndexedFaceSet) aNode =
1131 Handle(VrmlData_IndexedFaceSet)::DownCast(theNode);
1132 const Standard_Integer ** ppDummy;
1133 const Standard_Size nCoord = aNode->Coordinates()->Length();
1134 const Standard_Size nPoly = aNode->Polygons (ppDummy);
1136 sprintf (buf, "IndexedFaceSet (%d vertices, %d polygons)", nCoord, nPoly);
1137 dumpNodeHeader (theStream, theIndent, buf, theNode->Name());
1138 } else if (theNode->IsKind(STANDARD_TYPE(VrmlData_IndexedLineSet))) {
1139 const Handle(VrmlData_IndexedLineSet) aNode =
1140 Handle(VrmlData_IndexedLineSet)::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, "IndexedLineSet (%d vertices, %d polygons)", nCoord, nPoly);
1146 dumpNodeHeader (theStream, theIndent, buf, theNode->Name());
1147 } else if (theNode->IsKind(STANDARD_TYPE(VrmlData_Material))) {
1148 // const Handle(VrmlData_Material) aMaterial =
1149 // Handle(VrmlData_Material)::DownCast (theNode);
1150 dumpNodeHeader (theStream, theIndent, "Material", theNode->Name());
1152 else if (theNode->IsKind(STANDARD_TYPE(VrmlData_Normal)))
1153 dumpNodeHeader (theStream, theIndent, "Normal", theNode->Name());
1154 else if (theNode->IsKind(STANDARD_TYPE(VrmlData_TextureCoordinate)))
1155 dumpNodeHeader (theStream, theIndent, "TextureCoordinate", theNode->Name());
1156 else if (theNode->IsKind(STANDARD_TYPE(VrmlData_WorldInfo)))
1157 dumpNodeHeader (theStream, theIndent, "WorldInfo", theNode->Name());
1158 else if (theNode->IsKind(STANDARD_TYPE(VrmlData_UnknownNode))) {
1159 const Handle(VrmlData_UnknownNode) anUnknown =
1160 Handle(VrmlData_UnknownNode)::DownCast (theNode);
1162 sprintf (buf, "Unknown (%s)", anUnknown->GetTitle().ToCString());
1163 dumpNodeHeader (theStream, theIndent, buf, theNode->Name());
1167 //=======================================================================
1168 //function : dumpNodeHeader
1170 //=======================================================================
1172 void dumpNodeHeader (Standard_OStream& theStream,
1173 const TCollection_AsciiString& theIndent,
1174 const char * theType,
1175 const char * theName)
1177 theStream << theIndent << theType <<" node";
1178 if (theName[0] == '\0')
1181 theStream << ": \"" << theName << '\"' << endl;