0025740: VrmlData_Scene::WriteArrIndex() writes extra point indices.
[occt.git] / src / VrmlData / VrmlData_Group.cxx
CommitLineData
b311480e 1// Created on: 2006-11-06
2// Created by: Alexander GRIGORIEV
973c2be1 3// Copyright (c) 2006-2014 OPEN CASCADE SAS
b311480e 4//
973c2be1 5// This file is part of Open CASCADE Technology software library.
b311480e 6//
d5f74e42 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
973c2be1 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.
b311480e 12//
973c2be1 13// Alternatively, this file may be used under the terms of Open CASCADE
14// commercial license or contractual agreement.
7fd59977 15
16#include <VrmlData_Group.hxx>
17#include <VrmlData_Geometry.hxx>
18#include <VrmlData_Scene.hxx>
19#include <VrmlData_WorldInfo.hxx>
20#include <VrmlData_InBuffer.hxx>
21#include <VrmlData_ListOfNode.hxx>
22#include <VrmlData_UnknownNode.hxx>
23#include <Precision.hxx>
24#include <gp_Ax1.hxx>
25
26#ifdef WNT
27#define _CRT_SECURE_NO_DEPRECATE
28#pragma warning (disable:4996)
29#endif
30
31IMPLEMENT_STANDARD_HANDLE (VrmlData_Group, VrmlData_Node)
32IMPLEMENT_STANDARD_RTTIEXT (VrmlData_Group, VrmlData_Node)
33
34//=======================================================================
35//function : VrmlData_Group
36//purpose : Constructor
37//=======================================================================
38
39VrmlData_Group::VrmlData_Group (const VrmlData_Scene& theScene,
40 const char * theName,
41 const Standard_Boolean isTransform)
42 : VrmlData_Node (theScene, theName),
43 myIsTransform (isTransform),
44 myNodes (theScene.Allocator())
45{}
46
47//=======================================================================
48//function : RemoveNode
49//purpose :
50//=======================================================================
51
52Standard_Boolean VrmlData_Group::RemoveNode
53 (const Handle(VrmlData_Node)& theNode)
54{
55 Standard_Boolean aResult (Standard_False);
56 for (Iterator anIter = NodeIterator(); anIter.More(); anIter.Next())
57 if (anIter.Value() == theNode) {
58 aResult = Standard_True;
59 myNodes.Remove (anIter);
60 break;
61 }
62 return aResult;
63}
64
65//=======================================================================
66//function : SetTransform
67//purpose :
68//=======================================================================
69
70Standard_Boolean VrmlData_Group::SetTransform (const gp_Trsf& theTrsf)
71{
72 Standard_Boolean aResult (Standard_False);
73 if (myIsTransform) {
74 myTrsf = theTrsf;
75 aResult = Standard_True;
76 }
77 return aResult;
78}
79
80//=======================================================================
81//function : VrmlData_Group::Clone
82//purpose :
83//=======================================================================
84
85Handle(VrmlData_Node) VrmlData_Group::Clone
86 (const Handle(VrmlData_Node)& theOther) const
87{
88 Handle(VrmlData_Group) aResult =
89 Handle(VrmlData_Group)::DownCast (VrmlData_Node::Clone(theOther));
90 if (aResult.IsNull())
91 aResult =
92 new VrmlData_Group (theOther.IsNull() ? Scene() : theOther->Scene(),
93 Name(), myIsTransform);
94
95 aResult->myIsTransform = myIsTransform;
96 if (&aResult->Scene() == &Scene())
97 aResult->myNodes = myNodes;
98 else {
99 // Create a dummy node to pass the different Scene instance to methods Clone
100 const Handle(VrmlData_UnknownNode) aDummyNode =
101 new VrmlData_UnknownNode (aResult->Scene());
102 Iterator anIter (myNodes);
103 for (; anIter.More(); anIter.Next()) {
104 const Handle(VrmlData_Node)& aNode = anIter.Value();
105 if (aNode.IsNull() == Standard_False)
106 aResult->myNodes.Append(aNode->Clone (aDummyNode));
107 }
108 }
109 if (myIsTransform)
110 aResult->SetTransform (myTrsf);
111 aResult->SetBox (myBox);
112
113 return aResult;
114}
115
116//=======================================================================
117//function : FindNode
118//purpose :
119//=======================================================================
120
121Handle(VrmlData_Node) VrmlData_Group::FindNode
122 (const char * theName,
123 gp_Trsf& theLocation) const
124{
125 Handle(VrmlData_Node) aResult;
126 Iterator anIter (myNodes);
127 for (; anIter.More(); anIter.Next()) {
128 const Handle(VrmlData_Node)& aNode = anIter.Value();
129 if (aNode.IsNull() == Standard_False) {
130 if (strcmp(aNode->Name(), theName) == 0)
131 {
132 aResult = aNode;
133 theLocation = myTrsf;
134 break;
135 }
136 // Try a Group type of node
137 if (aNode->IsKind(STANDARD_TYPE(VrmlData_Group)))
138 {
139 const Handle(VrmlData_Group) aGroup =
140 Handle(VrmlData_Group)::DownCast (aNode);
141 if (aGroup.IsNull() == Standard_False) {
142 aResult = aGroup->FindNode(theName, theLocation);
143 if (aResult.IsNull() == Standard_False) {
144 //theLocation *= myTrsf;
145 theLocation.PreMultiply(myTrsf);
146 break;
147 }
148 }
149 }
150 }
151 }
152 return aResult;
153}
154
155//=======================================================================
156//function : VrmlData_Group::Read
157//purpose :
158//=======================================================================
159
160VrmlData_ErrorStatus VrmlData_Group::Read (VrmlData_InBuffer& theBuffer)
161{
162 VrmlData_ErrorStatus aStatus;
163 gp_XYZ aBoxCenter(0., 0., 0.), aBoxSize(-1., -1., -1.);
164 gp_XYZ aCenter (0., 0., 0.), aScale (1., 1., 1.), aTrans (0., 0., 0.);
165 gp_XYZ aRotAxis (0., 0., 1.), aScaleAxis (0., 0., 1.);
166 Standard_Real aRotAngle (0.), aScaleAngle(0.);
167
168 while (OK(aStatus, VrmlData_Scene::ReadLine(theBuffer)))
169 {
170 if (VRMLDATA_LCOMPARE (theBuffer.LinePtr, "bboxCenter"))
171 aStatus = Scene().ReadXYZ (theBuffer, aBoxCenter,
172 Standard_True, Standard_False);
173
174 else if (VRMLDATA_LCOMPARE (theBuffer.LinePtr, "bboxSize"))
175 aStatus = Scene().ReadXYZ (theBuffer, aBoxSize,
176 Standard_True, Standard_False);
177
178 else if (VRMLDATA_LCOMPARE (theBuffer.LinePtr, "children")) {
179 Standard_Boolean isBracketed (Standard_False);
180 // Read the opening bracket for the list of children
181 if (!OK(aStatus, VrmlData_Scene::ReadLine(theBuffer)))
182 break;
183 if (theBuffer.LinePtr[0] == '[') {
184 theBuffer.LinePtr++;
185 if (!OK(aStatus, VrmlData_Scene::ReadLine(theBuffer)))
186 break;
187 isBracketed = Standard_True;
188 }
189
190 // Read the child nodes
191 Handle(VrmlData_Node) aChildNode;
192 while (OK(aStatus, VrmlData_Scene::ReadLine(theBuffer))) {
193 // read the end-of-list bracket
194 if (isBracketed && theBuffer.LinePtr[0] == ']') {
195 theBuffer.LinePtr++;
196 break;
197 }
198 // otherwise read a node
199 if (!OK(aStatus, ReadNode (theBuffer, aChildNode)))
200 break;
201 AddNode (aChildNode);
202 if (isBracketed == Standard_False)
203 break;
204 }
bd754989
V
205 }
206 else if (VRMLDATA_LCOMPARE (theBuffer.LinePtr, "Separator") ||
207 VRMLDATA_LCOMPARE (theBuffer.LinePtr, "Switch")) {
208 Standard_Boolean isBracketed (Standard_False);
209 // Read the opening bracket for the list of children
210 if (!OK(aStatus, VrmlData_Scene::ReadLine(theBuffer)))
211 break;
212
213 if (theBuffer.LinePtr[0] == '{') {
214 theBuffer.LinePtr++;
215 if (!OK(aStatus, VrmlData_Scene::ReadLine(theBuffer)))
216 break;
217 isBracketed = Standard_True;
218 }
219
220 // Read the child nodes
221 Handle(VrmlData_Node) aChildNode;
222 while (OK(aStatus, VrmlData_Scene::ReadLine(theBuffer))) {
223 // read the end-of-list bracket
224 if (isBracketed && theBuffer.LinePtr[0] == '}') {
225 theBuffer.LinePtr++;
226 break;
227 }
228
229 // otherwise read a node
230 if (!OK(aStatus, ReadNode (theBuffer, aChildNode)))
231 break;
232
233 AddNode (aChildNode);
234 if (isBracketed == Standard_False)
235 break;
236 }
237 }
238 else if (VRMLDATA_LCOMPARE (theBuffer.LinePtr, "ShapeHints")) {
239 // Skip this tag
240 if (!OK(aStatus, VrmlData_Scene::ReadLine(theBuffer)))
241 break;
242
243 if (theBuffer.LinePtr[0] == '{') {
244 theBuffer.LinePtr++;
245 if (!OK(aStatus, VrmlData_Scene::ReadLine(theBuffer)))
246 break;
247
248 while (OK(aStatus, VrmlData_Scene::ReadLine(theBuffer))) {
249 // read the end-of-list bracket
250 if (theBuffer.LinePtr[0] == '}') {
251 theBuffer.LinePtr++;
252 break;
253 }
254 theBuffer.LinePtr++;
255 }
256 }
7fd59977 257 } else if (VRMLDATA_LCOMPARE (theBuffer.LinePtr, "center"))
258 if (myIsTransform)
259 aStatus = Scene().ReadXYZ (theBuffer, aCenter,
260 Standard_True, Standard_False);
261 else {
262 aStatus = VrmlData_VrmlFormatError;
263 break;
264 }
265 else if (VRMLDATA_LCOMPARE (theBuffer.LinePtr, "rotation"))
266 if (myIsTransform) {
267 if (OK(aStatus, Scene().ReadXYZ (theBuffer, aRotAxis,
268 Standard_False, Standard_False)))
269 {
270 if (aRotAxis.SquareModulus() < Precision::Confusion())
271 aRotAxis.SetZ (1.0);
272 aStatus = Scene().ReadReal (theBuffer, aRotAngle,
273 Standard_False, Standard_False);
274 }
275 } else {
276 aStatus = VrmlData_VrmlFormatError;
277 break;
278 }
4366363b 279 else if (VRMLDATA_LCOMPARE (theBuffer.LinePtr, "scaleOrientation"))
7fd59977 280 if (myIsTransform) {
281 if (OK(aStatus, Scene().ReadXYZ (theBuffer, aScaleAxis,
282 Standard_False, Standard_False)))
283 aStatus = Scene().ReadReal (theBuffer, aScaleAngle,
284 Standard_False, Standard_False);
285 } else {
286 aStatus = VrmlData_VrmlFormatError;
287 break;
288 }
4366363b 289 else if (VRMLDATA_LCOMPARE (theBuffer.LinePtr, "scale"))
290 if (myIsTransform)
291 aStatus = Scene().ReadXYZ (theBuffer, aScale,
292 Standard_False, Standard_True);
293 else {
294 aStatus = VrmlData_VrmlFormatError;
295 break;
296 }
7fd59977 297 else if (VRMLDATA_LCOMPARE (theBuffer.LinePtr, "translation"))
298 if (myIsTransform)
299 aStatus = Scene().ReadXYZ (theBuffer, aTrans,
300 Standard_True, Standard_False);
301 else {
302 aStatus = VrmlData_VrmlFormatError;
303 break;
304 }
305 else if (VRMLDATA_LCOMPARE (theBuffer.LinePtr, "url")) {
306 NCollection_List<TCollection_AsciiString> lstURL;
307 if (OK(aStatus, ReadMultiString (theBuffer, lstURL))) {
308 NCollection_List<TCollection_AsciiString>::Iterator anIter (lstURL);
309 for (; anIter.More(); anIter.Next()) {
310 ifstream aStream;
311 const TCollection_AsciiString& aFileName = anIter.Value();
312 if (!OK(aStatus, openFile (aStream, aFileName)))
313 break;
314 VrmlData_Scene aScene (Scene().Allocator());
315 aScene.myLinearScale = Scene().myLinearScale;
316 aScene.myVrmlDir = Scene().myVrmlDir;
317 aScene << aStream;
318 if (!OK(aStatus, aScene.Status()))
319 break;
320 VrmlData_Scene::Iterator anIterN = aScene.GetIterator();
321 for (; anIterN.More(); anIterN.Next())
322 if (!anIterN.Value()->IsKind(STANDARD_TYPE(VrmlData_WorldInfo)))
323 AddNode (anIterN.Value());
324 VrmlData_Scene::Iterator anAllIter(aScene.myAllNodes);
325 for (; anAllIter.More(); anAllIter.Next()) {
326 const Handle(VrmlData_Node)& aNode = anAllIter.Value();
327 if (aNode->IsKind(STANDARD_TYPE(VrmlData_WorldInfo)))
328 continue;
329 const_cast <VrmlData_Scene&> (Scene()).myAllNodes.Append (aNode);
330 aNode->myScene = &Scene();
331 // The name of the imported node should be prefixed by the URL
332 // because each name must remain unique in the global scene.
333 if (aNode->Name())
334 if (* aNode->Name() != '\0') {
b6710675 335 TCollection_AsciiString buf;
336 buf += aFileName;
337 Standard_Integer aCharLocation = buf.Location (1, '.', 1, buf.Length());
338 if (aCharLocation != 0)
339 {
340 buf.Remove (aCharLocation, buf.Length() - aCharLocation + 1);
341 }
342 buf += '_';
343 buf += aNode->Name();
344 const size_t len = buf.Length();
7fd59977 345 char * aNewName =
346 static_cast<char *> (Scene().Allocator()->Allocate (len));
347 if (aNewName) {
348 aNode->myName = aNewName;
b6710675 349 memcpy (aNewName, buf.ToCString(), len);
7fd59977 350 }
351 }
352 }
353 }
354 }
355 } else
356 break;
357
358 if (!OK(aStatus))
359 break;
360 }
361
362 // Read the terminating (closing) brace
363 if (OK(aStatus))
364 aStatus = readBrace (theBuffer);
365 if (OK(aStatus)) {
366 // Check if the Bounding Box has been imported
367 if (aBoxSize.X() > -Precision::Confusion() &&
368 aBoxSize.Y() > -Precision::Confusion() &&
369 aBoxSize.Z() > -Precision::Confusion())
370 {
371 myBox.SetCenter (aBoxCenter);
372 myBox.SetHSize (aBoxSize*0.5);
373 }
374 if (myIsTransform) {
375 // Create the corresponding transformation.
376 gp_Trsf tRot, tCentInv;
377 myTrsf.SetTranslation(aTrans+aCenter);
378 gp_Ax1 aRotation (gp::Origin(), aRotAxis);
379 tRot.SetRotation(gp_Ax1 (gp::Origin(), aRotAxis), aRotAngle);
380 myTrsf.Multiply (tRot);
381 // Check that the scale is uniform (the same value in all 3 directions.
382 // Only in this case the scaling is applied.
383 const Standard_Real aScaleDiff[2] = {
384 aScale.X()-aScale.Y(),
385 aScale.X()-aScale.Z()
386 };
387 if (aScaleDiff[0]*aScaleDiff[0] + aScaleDiff[1]*aScaleDiff[1]
388 < Precision::Confusion())
389 {
390 gp_Trsf tScale;
391 tScale.SetScale (gp::Origin(), (aScale.X()+aScale.Y()+aScale.Z())/3.);
392 myTrsf.Multiply (tScale);
393 }
394 tCentInv.SetTranslation (aCenter.Reversed());
395 myTrsf.Multiply (tCentInv);
396 }
397 }
398 return aStatus;
399}
400
401//=======================================================================
402//function : Shape
403//purpose :
404//=======================================================================
405
406void VrmlData_Group::Shape (TopoDS_Shape& theShape,
407 VrmlData_DataMapOfShapeAppearance * pMapApp)
408{
409 VrmlData_Scene::createShape (theShape, myNodes, pMapApp);
410 theShape.Location(myTrsf);
411}
412
413//=======================================================================
414//function : openFile
415//purpose :
416//=======================================================================
417
418VrmlData_ErrorStatus VrmlData_Group::openFile
419 (Standard_IStream& theStream,
420 const TCollection_AsciiString& theFilename)
421{
422 ifstream& aStream = static_cast<ifstream&> (theStream);
423 VrmlData_ErrorStatus aStatus (VrmlData_EmptyData);
424 NCollection_List<TCollection_ExtendedString>::Iterator aDirIter =
425 Scene().VrmlDirIterator();
426 for (; aDirIter.More(); aDirIter.Next()) {
427 if (!aDirIter.Value().IsAscii())
428 continue;
429 const TCollection_AsciiString aFullName =
430 TCollection_AsciiString (aDirIter.Value()) + theFilename;
431 aStream.open (aFullName.ToCString(), ios::in);
432 if (aStream.fail())
433 aStream.clear();
434 else {
435 aStatus = VrmlData_StatusOK;
436 break;
437 }
438 }
439 if (aStatus == VrmlData_EmptyData) {
440 aStream.open (theFilename.ToCString(), ios::in);
441 if (!aStream.fail())
442 aStatus = VrmlData_StatusOK;
443 }
444 if (aStatus == VrmlData_EmptyData)
445 aStatus = VrmlData_CannotOpenFile;
446 return aStatus;
447}
448
449//=======================================================================
450//function : Write
451//purpose :
452//=======================================================================
453
454VrmlData_ErrorStatus VrmlData_Group::Write (const char * thePrefix) const
455{
456 VrmlData_ErrorStatus aStatus (VrmlData_StatusOK);
457 if (myNodes.IsEmpty() == Standard_False) {
458 const VrmlData_Scene& aScene = Scene();
459 Standard_Boolean isTransform = myIsTransform;
460 if (isTransform && myTrsf.Form() == gp_Identity)
461 isTransform = Standard_False;
462 static const char * header[2] = { "Group {" , "Transform {" };
463 if (OK (aStatus, aScene.WriteLine (thePrefix, header[isTransform ? 1 : 0],
464 GlobalIndent())))
465 {
466 char buf[240];
467 if (OK(aStatus) && aScene.IsDummyWrite() == Standard_False)
468 {
469 const gp_XYZ aBoxCorner[2] = {
470 myBox.CornerMin(),
471 myBox.CornerMax()
472 };
473 // Check that the box is not void
474 if (aBoxCorner[0].X() < aBoxCorner[1].X() + Precision::Confusion()) {
91322f44 475 Sprintf (buf, "bboxCenter %.9g %.9g %.9g",
7fd59977 476 0.5 * (aBoxCorner[0].X() + aBoxCorner[1].X()),
477 0.5 * (aBoxCorner[0].Y() + aBoxCorner[1].Y()),
478 0.5 * (aBoxCorner[0].Z() + aBoxCorner[1].Z()));
479 aStatus = aScene.WriteLine (buf);
480 if (OK(aStatus)) {
91322f44 481 Sprintf (buf, "bboxSize %.9g %.9g %.9g",
7fd59977 482 aBoxCorner[1].X() - aBoxCorner[0].X(),
483 aBoxCorner[1].Y() - aBoxCorner[0].Y(),
484 aBoxCorner[1].Z() - aBoxCorner[0].Z());
485 aStatus = aScene.WriteLine (buf);
486 }
487 }
488 }
489 if (OK(aStatus) && isTransform && aScene.IsDummyWrite() == Standard_False)
490 {
491 // Output the Scale
492 const Standard_Real aScaleFactor = myTrsf.ScaleFactor();
493 if ((aScaleFactor - 1.)*(aScaleFactor - 1.) >
494 0.0001*Precision::Confusion())
495 {
91322f44 496 Sprintf (buf, "scale %.12g %.12g %.12g",
7fd59977 497 aScaleFactor, aScaleFactor, aScaleFactor);
498 aStatus = aScene.WriteLine (buf);
499 }
500
501 // Output the Translation
502 const gp_XYZ& aTrans = myTrsf.TranslationPart();
503 if (aTrans.SquareModulus() > 0.0001*Precision::Confusion()) {
91322f44 504 Sprintf (buf, "translation %.12g %.12g %.12g",
7fd59977 505 aTrans.X(), aTrans.Y(), aTrans.Z());
506 aStatus = aScene.WriteLine (buf);
507 }
508
509 // Output the Rotation
510 gp_XYZ anAxis;
511 Standard_Real anAngle;
512 if (myTrsf.GetRotation (anAxis, anAngle)) {
513 // output the Rotation
91322f44 514 Sprintf (buf, "rotation %.12g %.12g %.12g %.9g",
7fd59977 515 anAxis.X(), anAxis.Y(), anAxis.Z(), anAngle);
516 aStatus = aScene.WriteLine (buf);
517 }
518 }
519
520 if (OK(aStatus)) {
521
522 aStatus = aScene.WriteLine ("children [", 0L, GlobalIndent());
523
524 VrmlData_ListOfNode::Iterator anIterChild (myNodes);
525 for (; anIterChild.More() && OK(aStatus); anIterChild.Next()) {
526 const Handle(VrmlData_Node)& aNode = anIterChild.Value();
527 aScene.WriteNode (0L, aNode);
528 }
529
530 if (OK(aStatus)) {
531 aStatus = aScene.WriteLine ("]", 0L, -GlobalIndent());
532 }
533 }
534 aStatus = WriteClosing();
535 }
536 }
537 return aStatus;
538}