Adding test cases from chl grid
[occt.git] / src / VrmlData / VrmlData_Scene.cxx
CommitLineData
b311480e 1// Created on: 2006-05-25
2// Created by: Alexander GRIGORIEV
3// Copyright (c) 2006-2012 OPEN CASCADE SAS
4//
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.
9//
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.
12//
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.
19
7fd59977 20
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>
45#include <TopoDS.hxx>
46#include <TopoDS_Face.hxx>
47#include <TopExp_Explorer.hxx>
48#include <BRep_Builder.hxx>
49#include <Precision.hxx>
50
51#ifdef WNT
52#define _CRT_SECURE_NO_DEPRECATE
53#pragma warning (disable:4996)
54#endif
55
56static void dumpNode (Standard_OStream& theStream,
57 const Handle(VrmlData_Node)& theNode,
58 const TCollection_AsciiString& theIndent);
59
60static void dumpNodeHeader (Standard_OStream& theStream,
61 const TCollection_AsciiString& theIndent,
62 const char * theType,
63 const char * theName);
64
65//=======================================================================
66//function : VrmlData_Scene
67//purpose : Constructor
68//=======================================================================
69
70VrmlData_Scene::VrmlData_Scene
71 (const Handle(NCollection_IncAllocator)& theAlloc)
72 : myLinearScale (1.),
73 myStatus (VrmlData_StatusOK),
74 myAllocator (theAlloc.IsNull() ?
75 new NCollection_IncAllocator : theAlloc.operator->()),
76 myLineError (0),
77 myOutput (0L),
78 myIndent (2),
79 myCurrentIndent (0),
80 myAutoNameCounter (0)
81{
82 myWorldInfo = new VrmlData_WorldInfo (* this);
83 myWorldInfo->AddInfo ("Created by OPEN CASCADE (tm) VrmlData API");
84 myLstNodes.Append (myWorldInfo);
85 myAllNodes.Append (myWorldInfo);
86}
87
88//=======================================================================
89//function : AddNode
90//purpose :
91//=======================================================================
92
93const Handle(VrmlData_Node)& VrmlData_Scene::AddNode
94 (const Handle(VrmlData_Node)& theN,
95 const Standard_Boolean isTopLevel)
96{
97 if (theN.IsNull() == Standard_False)
98 if (theN->IsKind (STANDARD_TYPE(VrmlData_WorldInfo)) == Standard_False) {
99 myMutex.Lock();
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");
107 if (isTopLevel)
108 myLstNodes.Append (aNode);
109 myMutex.Unlock();
110 return aNode;
111 }
112 static Handle(VrmlData_Node) aNullNode;
113 aNullNode.Nullify();
114 return aNullNode;
115}
116
117//=======================================================================
118//function : operator <<
119//purpose : Export to text stream (file or else)
120//=======================================================================
121
122Standard_OStream& operator << (Standard_OStream& theOutput,
123 const VrmlData_Scene& theScene)
124{
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;
133
134 // Dummy write
135
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)
143 break;
144 }
145 }
146
147 aScene.myOutput = &theOutput;
148 aScene.myNamedNodesOut.Clear();
149 theOutput << "#VRML V2.0 utf8" << endl << endl;
150
151 // Real write
152
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)
160 break;
161 }
162 }
163 aScene.myOutput = 0L;
164 aScene.myNamedNodesOut.Clear();
165 aScene.myUnnamedNodesOut.Clear();
166 aScene.myMutex.Unlock();
167 return theOutput;
168}
169
170//=======================================================================
171//function : SetVrmlDir
172//purpose :
173//=======================================================================
174
175void VrmlData_Scene::SetVrmlDir (const TCollection_ExtendedString& theDir)
176{
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('/'))
181#ifdef WNT
182 aDir += TCollection_ExtendedString ("\\");
183#else
184 aDir += TCollection_ExtendedString ("/");
185#endif
186}
187
188//=======================================================================
189//function : WorldInfo
190//purpose :
191//=======================================================================
192
193const Handle_VrmlData_WorldInfo& VrmlData_Scene::WorldInfo() const
194{
195 return myWorldInfo;
196}
197
198//=======================================================================
199//function : readLine
200//purpose :
201//=======================================================================
202
203VrmlData_ErrorStatus VrmlData_Scene::readLine (VrmlData_InBuffer& theBuffer)
204{
205 VrmlData_ErrorStatus aStatus = VrmlData_StatusOK;
206 if (theBuffer.Input.eof())
207 aStatus = VrmlData_EndOfFile;
208 else {
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;
217 else
218 aStatus = VrmlData_GeneralError;
219 theBuffer.LinePtr = &theBuffer.Line[0];
220 theBuffer.IsProcessed = Standard_False;
221 }
222 return aStatus;
223}
224
225//=======================================================================
226//function : ReadLine
227//purpose :
228//=======================================================================
229
230VrmlData_ErrorStatus VrmlData_Scene::ReadLine (VrmlData_InBuffer& theBuffer)
231{
232 VrmlData_ErrorStatus aStatus (VrmlData_StatusOK);
233
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 != ',')
239 {
240 if (* theBuffer.LinePtr == '\n' || * theBuffer.LinePtr == '\r' ||
241 * theBuffer.LinePtr == '#')
242 // go requesting the next line
243 break;
244 goto nonempty_line;
245 }
246 }
247 // the line is empty here (no significant characters). Read the next one.
248 aStatus = readLine (theBuffer);
249 }
250
251 // error or EOF detected
252 return aStatus;
253
254 nonempty_line:
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++) {
261 if (anOffset)
262 * ptr = ptr[anOffset];
263 if (* ptr == '\n' || * ptr == '\r' || * ptr == '#') {
264 if (isQuoted == Standard_False) {
265 * ptr = '\0';
266 break;
267 }
268 } else if (* ptr == '\\' && isQuoted)
269 ptr[0] = ptr[++anOffset];
270 else if (* ptr == '\"')
271 isQuoted = !isQuoted;
272 }
273 theBuffer.IsProcessed = Standard_True;
274 }
275 return aStatus;
276}
277
278//=======================================================================
279//function : readHeader
280//purpose :
281//=======================================================================
282
283VrmlData_ErrorStatus VrmlData_Scene::readHeader (VrmlData_InBuffer& theBuffer)
284{
285 VrmlData_ErrorStatus aStat = readLine (theBuffer);
286 if (aStat == VrmlData_StatusOK &&
287 !VRMLDATA_LCOMPARE(theBuffer.LinePtr, "#VRML V2.0"))
288 aStat = VrmlData_NotVrmlFile;
289 else
290 aStat = readLine(theBuffer);
291 return aStat;
292}
293
294//=======================================================================
295//function : operator <<
296//purpose : Import from text stream (file or else)
297//=======================================================================
298
299VrmlData_Scene& VrmlData_Scene::operator << (Standard_IStream& theInput)
300{
301 VrmlData_InBuffer aBuffer (theInput);
302 myMutex.Lock();
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
309 while (~0) {
310 if (!VrmlData_Node::OK(myStatus, ReadLine(aBuffer))) {
311 if (myStatus == VrmlData_EndOfFile)
312 myStatus = VrmlData_StatusOK;
313 break;
314 }
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)
320 break;
321 if (aNode.IsNull() == Standard_False /*&&
322 !aNode->IsKind (STANDARD_TYPE(VrmlData_UnknownNode))*/)
323 {
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());
334 }
335 }
336 }
337 if (myStatus != VrmlData_StatusOK)
338 myLineError = aBuffer.LineCount;
339 myMutex.Unlock();
340 return * this;
341}
342
343//=======================================================================
344//function : FindNode
345//purpose :
346//=======================================================================
347
348Handle(VrmlData_Node) VrmlData_Scene::FindNode
349 (const char * theName,
350 const Handle(Standard_Type)& theType) const
351{
352 Handle(VrmlData_Node) aResult;
353#ifdef USE_LIST_API
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())
359 break;
360 if (aResult->IsKind(theType))
361 break;
362 aResult.Nullify();
363 }
364#else
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);
369#endif
370 return aResult;
371}
372
373//=======================================================================
374//function : FindNode
375//purpose :
376//=======================================================================
377
378Handle(VrmlData_Node) VrmlData_Scene::FindNode
379 (const char * theName,
380 gp_Trsf& theLocation) const
381{
382 gp_Trsf aLoc;
383 Handle(VrmlData_Node) aResult;
384 Iterator anIter (myLstNodes);
385 for (; anIter.More(); anIter.Next()) {
386 const Handle(VrmlData_Node)& aNode = anIter.Value();
387 if (aNode.IsNull())
388 continue;
389 // Match a top-level node name
390 if (strcmp(aNode->Name(), theName) == 0) {
391 aResult = aNode;
392 theLocation = aLoc;
393 break;
394 }
395 // Try a Group type of node
396 if (aNode->IsKind(STANDARD_TYPE(VrmlData_Group)))
397 {
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)
403 break;
404 }
405 }
406 }
407 return aResult;
408}
409
410//=======================================================================
411//function : ReadWord
412//purpose :
413//=======================================================================
414
415VrmlData_ErrorStatus VrmlData_Scene::ReadWord
416 (VrmlData_InBuffer& theBuffer,
417 TCollection_AsciiString& theWord)
418{
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 != ']')
425 ptr++;
426 const Standard_Integer aLen = Standard_Integer(ptr - theBuffer.LinePtr);
427 if (aLen <= 0)
428 aStatus = VrmlData_StringInputError;
429 else {
430 theWord = TCollection_AsciiString ((Standard_CString)theBuffer.LinePtr,
431 aLen);
432 theBuffer.LinePtr = ptr;
433 }
434 }
435 return aStatus;
436}
437
438//=======================================================================
439//function : createNode
440//purpose :
441//=======================================================================
442
443VrmlData_ErrorStatus VrmlData_Scene::createNode
444 (VrmlData_InBuffer& theBuffer,
445 Handle(VrmlData_Node)& theNode,
446 const Handle(Standard_Type)& theType)
447{
448 VrmlData_ErrorStatus aStatus;
449 Handle(VrmlData_Node) aNode;
450 TCollection_AsciiString aName;
7fd59977 451
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")) {
458 theNode.Nullify();
459 return aStatus;
460 }
461
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);
bd754989 475 else if (VRMLDATA_LCOMPARE(theBuffer.LinePtr, "Coordinate")) {
7fd59977 476 aNode = new VrmlData_Coordinate (* this, strName);
bd754989
V
477
478 // Check for "Coordinate3"
479 if (VRMLDATA_LCOMPARE (theBuffer.LinePtr, "3"))
480 theBuffer.LinePtr++;
481 }
7fd59977 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,
486 Standard_False);
487 else if (VRMLDATA_LCOMPARE(theBuffer.LinePtr, "Transform"))
488 aNode = new VrmlData_Group (* this, strName,
489 Standard_True);
490 else if (VRMLDATA_LCOMPARE(theBuffer.LinePtr, "Inline"))
491 aNode = new VrmlData_Group (* this, strName,
492 Standard_False);
bd754989
V
493 else if (VRMLDATA_LCOMPARE(theBuffer.LinePtr, "Separator"))
494 aNode = new VrmlData_Group (* this, strName,
495 Standard_False);
496 else if (VRMLDATA_LCOMPARE(theBuffer.LinePtr, "Switch"))
497 aNode = new VrmlData_Group (* this, strName,
498 Standard_False);
7fd59977 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);
515 else {
516 void * isProto = VRMLDATA_LCOMPARE(theBuffer.LinePtr, "PROTO");
517 TCollection_AsciiString aTitle;
518 aStatus = ReadWord (theBuffer, aTitle);
519 if (isProto) {
520 aStatus = ReadLine(theBuffer);
521 if (aStatus == VrmlData_StatusOK)
522 if (theBuffer.LinePtr[0] != '[')
523 aStatus = VrmlData_VrmlFormatError;
524 else {
525 theBuffer.LinePtr++;
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) {
532 int aChar;
533 while ((aChar = theBuffer.LinePtr[0]) != '\0') {
534 theBuffer.LinePtr++;
535 if (aChar == '[') {
536 aLevelCounter++;
537 break;
538 } else if (aChar == ']') {
539 aLevelCounter--;
540 break;
541 }
542 }
543 }
544 }
545 }
546 if (aStatus == VrmlData_StatusOK)
547 aNode = new VrmlData_UnknownNode(* this,
548 strName,
549 aTitle.ToCString());
550 }
551 }
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;
7fd59977 559 }
560 if (aStatus == VrmlData_StatusOK)
561 if (theBuffer.LinePtr[0] == '{') {
562 theBuffer.LinePtr++;
563 theNode = aNode;
564 myAllNodes.Append(aNode);
565 } else
566 aStatus = VrmlData_VrmlFormatError;
567 return aStatus;
568}
569
570//=======================================================================
571//function : operator TopoDS_Shape
572//purpose :
573//=======================================================================
574
575VrmlData_Scene::operator TopoDS_Shape () const
576{
577 TopoDS_Shape aShape;
578 VrmlData_Scene::createShape (aShape, myLstNodes, 0L);
579 return aShape;
580}
581
582//=======================================================================
583//function : GetShape
584//purpose :
585//=======================================================================
586
587TopoDS_Shape VrmlData_Scene::GetShape (VrmlData_DataMapOfShapeAppearance& aMap)
588{
589 TopoDS_Shape aShape;
590 VrmlData_Scene::createShape (aShape, myLstNodes, &aMap);
591 return aShape;
592}
593
594//=======================================================================
595//function : createShape
596//purpose :
597//=======================================================================
598
599void VrmlData_Scene::createShape
600 (TopoDS_Shape& outShape,
601 const VrmlData_ListOfNode& lstNodes,
602 VrmlData_DataMapOfShapeAppearance* pMapShapeApp)
603{
604 TopoDS_Shape aSingleShape; // used when there is a single ShapeNode
605 Standard_Boolean isSingleShape (Standard_True);
606 BRep_Builder aBuilder;
607 outShape.Nullify();
608 aBuilder.MakeCompound(TopoDS::Compound(outShape));
609 aSingleShape.Orientation(TopAbs_FORWARD);
610
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);
bd754989 624 if (aSingleShape.IsNull() == Standard_False) {
7fd59977 625 aBuilder.Add (outShape, aSingleShape);
bd754989
V
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);
633 else {
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);
641 }
7fd59977 642 }
643 }
644 }
645 }
646 }
647 continue;
648 }
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) {
653 TopoDS_Shape aShape;
654 aNodeGroup->Shape(aShape, pMapShapeApp);
655 if (aShape.IsNull() == Standard_False) {
656 aBuilder.Add (outShape, aShape);
657 isSingleShape = Standard_False;
658 }
659 }
660 }
661 if (isSingleShape)
662 outShape = aSingleShape;
663}
664
665//=======================================================================
666//function : ReadReal
667//purpose :
668//=======================================================================
669
670VrmlData_ErrorStatus VrmlData_Scene::ReadReal
671 (VrmlData_InBuffer& theBuffer,
672 Standard_Real& theResult,
673 Standard_Boolean isScale,
674 Standard_Boolean isOnlyPositive) const
675{
676 Standard_Real aResult(0.);
677 VrmlData_ErrorStatus aStatus;
678 if (VrmlData_Node::OK(aStatus, VrmlData_Scene::ReadLine(theBuffer))) {
679 char * endptr;
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;
685 else {
686 theResult = isScale ? (aResult * myLinearScale) : aResult;
687 theBuffer.LinePtr = endptr;
688 }
689 }
690 return aStatus;
691}
692
693//=======================================================================
694//function : ReadXYZ
695//purpose :
696//=======================================================================
697
698VrmlData_ErrorStatus VrmlData_Scene::ReadXYZ
699 (VrmlData_InBuffer& theBuffer,
700 gp_XYZ& theXYZ,
701 Standard_Boolean isScale,
702 Standard_Boolean isOnlyPos) const
703{
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)))
708 break;
709 char * endptr;
710 aVal[i] = strtod (theBuffer.LinePtr, &endptr);
711 if (endptr == theBuffer.LinePtr) {
712 aStatus = VrmlData_NumericInputError;
713 break;
714 } else {
715 if (isOnlyPos && aVal[i] < 0.001*Precision::Confusion()) {
716 aStatus = VrmlData_IrrelevantNumber;
717 break;
718 }
719 theBuffer.LinePtr = endptr;
720 }
721 }
722 if (aStatus == VrmlData_StatusOK)
723 if (isScale)
724 theXYZ.SetCoord (aVal[0] * myLinearScale,
725 aVal[1] * myLinearScale,
726 aVal[2] * myLinearScale);
727 else
728 theXYZ.SetCoord (aVal[0], aVal[1], aVal[2]);
729 return aStatus;
730}
731
732//=======================================================================
733//function : ReadXY
734//purpose :
735//=======================================================================
736
737VrmlData_ErrorStatus VrmlData_Scene::ReadXY
738 (VrmlData_InBuffer& theBuffer,
739 gp_XY& theXY,
740 Standard_Boolean isScale,
741 Standard_Boolean isOnlyPos) const
742{
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)))
747 break;
748 char * endptr;
749 aVal[i] = strtod (theBuffer.LinePtr, &endptr);
750 if (endptr == theBuffer.LinePtr) {
751 aStatus = VrmlData_NumericInputError;
752 break;
753 } else {
754 if (isOnlyPos && aVal[i] < 0.001*Precision::Confusion()) {
755 aStatus = VrmlData_IrrelevantNumber;
756 break;
757 }
758 theBuffer.LinePtr = endptr;
759 }
760 }
761 if (aStatus == VrmlData_StatusOK)
762 if (isScale)
763 theXY.SetCoord (aVal[0] * myLinearScale, aVal[1] * myLinearScale);
764 else
765 theXY.SetCoord (aVal[0], aVal[1]);
766 return aStatus;
767}
768
769//=======================================================================
770//function : ReadArrIndex
771//purpose : Read the body of the data node (comma-separated list of int
772// multiplets)
773//=======================================================================
774
775VrmlData_ErrorStatus VrmlData_Scene::ReadArrIndex
776 (VrmlData_InBuffer& theBuffer,
777 const Standard_Integer **& theArray,
778 Standard_Size& theNBlocks) const
779{
780 VrmlData_ErrorStatus aStatus;
781 theNBlocks = 0;
782 if (VrmlData_Node::OK(aStatus, ReadLine(theBuffer)))
783 if (theBuffer.LinePtr[0] != '[') // opening bracket
784 aStatus = VrmlData_VrmlFormatError;
785 else {
786 theBuffer.LinePtr++;
787 NCollection_Vector<const Standard_Integer *> vecIndice;
788 NCollection_Vector<Standard_Integer> vecInt;
789 Standard_Boolean isMore (Standard_True);
790 long anIntValue;
791
792 // Loop reading integers from the stream
793 while (isMore && VrmlData_Node::OK(aStatus, ReadLine(theBuffer)))
794 {
795 // closing bracket, in case that it follows a comma
796 if (theBuffer.LinePtr[0] == ']') {
797 theBuffer.LinePtr++;
798 break;
799 }
800 if (!VrmlData_Node::OK(aStatus, VrmlData_Node::ReadInteger(theBuffer,
801 anIntValue)))
802 break;
803 // Check for valid delimiter (']' or ',')
804 if (!VrmlData_Node::OK(aStatus, ReadLine(theBuffer)))
805 break;
806 if (theBuffer.LinePtr[0] == ']') {
807 theBuffer.LinePtr++;
808 isMore = Standard_False;
809 }
810 if (anIntValue >= 0)
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)
815 {
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)));
820 if (bufFace == 0L) {
821 aStatus = VrmlData_UnrecoverableError;
822 break;
823 }
824 bufFace[0] = aLen;
825 for (Standard_Integer i = 0; i < aLen; i++)
826 bufFace[i+1] = vecInt(i);
827 vecInt.Clear();
828 vecIndice.Append(bufFace);
829 }
830 }
831 if (aStatus == VrmlData_StatusOK) {
832 const Standard_Size aNbBlocks =
833 static_cast <Standard_Size> (vecIndice.Length());
834 if (aNbBlocks) {
835 const Standard_Integer ** anArray =
836 static_cast <const Standard_Integer **>
837 (myAllocator->Allocate (aNbBlocks * sizeof(Standard_Integer *)));
838 if (anArray == 0L)
839 aStatus = VrmlData_UnrecoverableError;
840 else {
841 for (size_t i = 0; i < aNbBlocks; i++)
60be1f9b 842 anArray[i] = vecIndice((Standard_Integer)i);
7fd59977 843 theNBlocks = aNbBlocks;
844 theArray = anArray;
845 }
846 }
847 }
848 }
849 return aStatus;
850}
851
852//=======================================================================
853//function : writeArrIndex
854//purpose :
855//=======================================================================
856
857VrmlData_ErrorStatus VrmlData_Scene::WriteArrIndex
858 (const char * thePrefix,
859 const Standard_Integer ** theArrIndex,
860 const Standard_Size theNbBlocks) const
861{
862 VrmlData_ErrorStatus aStatus (VrmlData_StatusOK);
863 if (theNbBlocks && (IsDummyWrite() == Standard_False)) {
864 if (VrmlData_Node::OK (aStatus,
865 WriteLine (thePrefix, "[", 1)))
866 {
867 const size_t aLineLimit = (myCurrentIndent < 41) ? 36 : 100;
868 char buf[256];
869 for (Standard_Size iBlock = 0; iBlock < theNbBlocks; iBlock++) {
870 const Standard_Integer nVal (* theArrIndex[iBlock]);
871 const Standard_Integer * arrVal = theArrIndex[iBlock]+1;
872 switch (nVal) {
873 case 1:
874 sprintf (buf, "%d,", arrVal[0]);
875 break;
876 case 2:
877 sprintf (buf, "%d,%d,", arrVal[0], arrVal[1]);
878 break;
879 case 3:
880 sprintf (buf, "%d,%d,%d,", arrVal[0], arrVal[1], arrVal[2]);
881 break;
882 case 4:
883 sprintf (buf, "%d,%d,%d,%d,",
884 arrVal[0], arrVal[1], arrVal[2], arrVal[3]);
885 break;
886 default:
887 if (nVal > 0) {
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) {
893 WriteLine(buf);
894 ptr = &buf[0];
895 }
896 }
897 }
898 }
899 WriteLine (buf, iBlock < theNbBlocks-1 ? "-1," : "-1");
900 }
901 if (aStatus == VrmlData_StatusOK)
902 aStatus = WriteLine ("]", 0L, -1);
903 }
904 }
905 return aStatus;
906}
907
908//=======================================================================
909//function : WriteXYZ
910//purpose :
911//=======================================================================
912
913VrmlData_ErrorStatus VrmlData_Scene::WriteXYZ
914 (const gp_XYZ& theXYZ,
915 const Standard_Boolean isApplyScale,
916 const char * thePostfix) const
917{
918 char buf[240];
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 : "");
924 else
925 sprintf (buf, "%.12g %.12g %.12g%s", theXYZ.X(), theXYZ.Y(), theXYZ.Z(),
926 thePostfix ? thePostfix : "");
927 return WriteLine (buf);
928}
929
930//=======================================================================
931//function : WriteLine
932//purpose : write the given string prepending the current indentation
933//=======================================================================
934
935VrmlData_ErrorStatus VrmlData_Scene::WriteLine
936 (const char * theLin0,
937 const char * theLin1,
938 const Standard_Integer theIndent) const
939{
940 static const char spaces[] = " "
941 " ";
942 VrmlData_ErrorStatus& aStatus =
943 const_cast <VrmlData_ErrorStatus&> (myStatus);
944 if (IsDummyWrite())
945 aStatus = VrmlData_StatusOK;
946 else {
947 Standard_Integer& aCurrentIndent =
948 const_cast <Standard_Integer&> (myCurrentIndent);
949 if (theIndent < 0)
950 aCurrentIndent -= myIndent;
951 if (aCurrentIndent < 0)
952 aCurrentIndent = 0;
953 if (theLin0 == 0L && theLin1 == 0L)
954 (* myOutput) << endl;
955 else {
956 const Standard_Integer nSpaces = Min (aCurrentIndent, sizeof(spaces)-1);
957 (* myOutput) << &spaces[sizeof(spaces)-1 - nSpaces];
958 if (theLin0) {
959 (* myOutput) << theLin0;
960 if (theLin1)
961 (* myOutput) << ' ' << theLin1;
962 } else
963 (* myOutput) << theLin1;
964 (* myOutput) << endl;
965 }
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;
972// else
973 aStatus = VrmlData_GeneralError;
974 if (theIndent > 0)
975 aCurrentIndent += myIndent;
976 }
977 return myStatus;
978}
979
980//=======================================================================
981//function : WriteNode
982//purpose :
983//=======================================================================
984
985VrmlData_ErrorStatus VrmlData_Scene::WriteNode
986 (const char * thePrefix,
987 const Handle(VrmlData_Node)& theNode) const
988{
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;
995
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)
1003 .Add (addrNode))
1004 {
1005 Handle(VrmlData_UnknownNode) bidNode = new VrmlData_UnknownNode;
1006 char buf[32];
1007 do {
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
1016 }
1017 }
1018 if (isNoName)
1019 aStatus = theNode->Write (thePrefix);
1020 else {
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')
1025 break;
1026 if (* nptr == '\0')
1027 aStatus = theNode->Write (thePrefix);
1028 else {
1029 // Name is written under DEF clause
b6710675 1030 TCollection_AsciiString buf;
1031 if (myNamedNodesOut.Contains (theNode))
1032 {
1033 buf += "USE ";
1034 buf += theNode->Name();
1035 aStatus = WriteLine (thePrefix, buf.ToCString());
1036 }
1037 else
1038 {
1039 if (thePrefix)
1040 {
1041 buf += thePrefix;
1042 buf += ' ';
1043 }
1044 buf += "DEF ";
1045 buf += theNode->Name();
1046 aStatus = theNode->Write (buf.ToCString());
7fd59977 1047 const_cast<VrmlData_MapOfNode&>(myNamedNodesOut).Add (theNode);
1048 }
1049 }
1050 }
1051 }
1052 return aStatus;
1053}
1054
1055//=======================================================================
1056//function : Dump
1057//purpose :
1058//=======================================================================
1059
1060void VrmlData_Scene::Dump (Standard_OStream& theStream) const
1061{
1062 theStream << " ===== Diagnostic Dump of a Scene (" << myAllNodes.Extent()
1063 << " nodes)" << endl;
1064
1065 /*
1066 Iterator anIterA(myAllNodes);
1067 for (; anIterA.More(); anIterA.Next())
1068 dumpNode(theStream, anIterA.Value(), "");
1069 */
1070 Iterator anIter(myLstNodes);
1071 for (; anIter.More(); anIter.Next())
1072 dumpNode(theStream, anIter.Value(), " ");
1073}
1074
1075//=======================================================================
1076//function : dumpNode
1077//purpose : static (local) function
1078//=======================================================================
1079
1080void dumpNode (Standard_OStream& theStream,
1081 const Handle(VrmlData_Node)& theNode,
1082 const TCollection_AsciiString& theIndent)
1083{
1084 if (theNode.IsNull())
1085 return;
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);
1096 }
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);
1104 }
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);
1118 char buf[64];
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);
1126 }
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);
1135 char buf[64];
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);
1144 char buf[64];
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());
1151 }
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);
1161 char buf[64];
1162 sprintf (buf, "Unknown (%s)", anUnknown->GetTitle().ToCString());
1163 dumpNodeHeader (theStream, theIndent, buf, theNode->Name());
1164 }
1165}
1166
1167//=======================================================================
1168//function : dumpNodeHeader
1169//purpose :
1170//=======================================================================
1171
1172void dumpNodeHeader (Standard_OStream& theStream,
1173 const TCollection_AsciiString& theIndent,
1174 const char * theType,
1175 const char * theName)
1176{
1177 theStream << theIndent << theType <<" node";
1178 if (theName[0] == '\0')
1179 theStream << endl;
1180 else
1181 theStream << ": \"" << theName << '\"' << endl;
1182}