| 1 | // Created on: 2007-08-04 |
| 2 | // Created by: Alexander GRIGORIEV |
| 3 | // Copyright (c) 2007-2014 OPEN CASCADE SAS |
| 4 | // |
| 5 | // This file is part of Open CASCADE Technology software library. |
| 6 | // |
| 7 | // This library is free software; you can redistribute it and/or modify it under |
| 8 | // the terms of the GNU Lesser General Public License version 2.1 as published |
| 9 | // by the Free Software Foundation, with special exception defined in the file |
| 10 | // OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT |
| 11 | // distribution for complete text of the license and disclaimer of any warranty. |
| 12 | // |
| 13 | // Alternatively, this file may be used under the terms of Open CASCADE |
| 14 | // commercial license or contractual agreement. |
| 15 | |
| 16 | #include <VrmlData_ShapeConvert.hxx> |
| 17 | #include <VrmlData_Scene.hxx> |
| 18 | #include <VrmlData_Group.hxx> |
| 19 | #include <VrmlData_IndexedFaceSet.hxx> |
| 20 | #include <VrmlData_IndexedLineSet.hxx> |
| 21 | #include <VrmlData_ShapeNode.hxx> |
| 22 | #include <BRep_Builder.hxx> |
| 23 | #include <BRep_Tool.hxx> |
| 24 | #include <Geom_Surface.hxx> |
| 25 | #include <NCollection_DataMap.hxx> |
| 26 | #include <Poly_Triangulation.hxx> |
| 27 | #include <Poly_Connect.hxx> |
| 28 | #include <Poly_PolygonOnTriangulation.hxx> |
| 29 | #include <Poly_Polygon3D.hxx> |
| 30 | #include <TDataStd_Name.hxx> |
| 31 | #include <TDF_Label.hxx> |
| 32 | //#include <TDF_LabelSequence.hxx> |
| 33 | #include <TDocStd_Document.hxx> |
| 34 | #include <TopExp_Explorer.hxx> |
| 35 | #include <TopoDS.hxx> |
| 36 | #include <TopoDS_Face.hxx> |
| 37 | #include <TopoDS_Shape.hxx> |
| 38 | #include <TopoDS_Wire.hxx> |
| 39 | #include <GCPnts_TangentialDeflection.hxx> |
| 40 | #include <BRepAdaptor_Curve.hxx> |
| 41 | #include <TColStd_Array1OfReal.hxx> |
| 42 | #include <TColStd_HArray1OfReal.hxx> |
| 43 | #include <GeomLib.hxx> |
| 44 | #include <TShort_HArray1OfShortReal.hxx> |
| 45 | #include <VrmlData_Appearance.hxx> |
| 46 | #include <XCAFDoc_ColorTool.hxx> |
| 47 | #include <XCAFDoc_DocumentTool.hxx> |
| 48 | #include <XCAFDoc_ShapeTool.hxx> |
| 49 | #include <XCAFPrs_Style.hxx> |
| 50 | #include <XCAFDoc_VisMaterial.hxx> |
| 51 | #include <XCAFDoc_VisMaterialTool.hxx> |
| 52 | |
| 53 | //======================================================================= |
| 54 | //function : AddShape |
| 55 | //purpose : |
| 56 | //======================================================================= |
| 57 | |
| 58 | void VrmlData_ShapeConvert::AddShape (const TopoDS_Shape& theShape, |
| 59 | const char * theName) |
| 60 | { |
| 61 | ShapeData aData;/* = { - compilation problem on SUN |
| 62 | TCollection_AsciiString(), |
| 63 | theShape, |
| 64 | NULL |
| 65 | };*/ |
| 66 | aData.Shape = theShape; |
| 67 | aData.Node = NULL; |
| 68 | |
| 69 | if (theName) { |
| 70 | char buf[2048], * optr = &buf[0]; |
| 71 | char * eptr = &buf[sizeof(buf)-1]; |
| 72 | for (const char * ptr = theName;; ptr++) { |
| 73 | char sym = *ptr; |
| 74 | if (sym == '\0' || sym == '\n' || sym == '\r') { |
| 75 | * optr = '\0'; |
| 76 | break; |
| 77 | } |
| 78 | if (sym == '\"' || sym == '\\') |
| 79 | * optr = '/'; |
| 80 | else if (sym == '.') |
| 81 | * optr = '_'; |
| 82 | else |
| 83 | * optr = sym; |
| 84 | if (++optr >= eptr) { |
| 85 | *optr = '\0'; |
| 86 | break; |
| 87 | } |
| 88 | } |
| 89 | aData.Name = buf; |
| 90 | } |
| 91 | myShapes.Append (aData); |
| 92 | } |
| 93 | |
| 94 | |
| 95 | //======================================================================= |
| 96 | //function : makeTShapeNode |
| 97 | //purpose : auxiliary |
| 98 | //======================================================================= |
| 99 | Handle(VrmlData_Geometry) VrmlData_ShapeConvert::makeTShapeNode(const TopoDS_Shape& theShape, |
| 100 | const TopAbs_ShapeEnum theShapeType, |
| 101 | TopLoc_Location& theLoc) |
| 102 | { |
| 103 | Handle(VrmlData_Geometry) aTShapeNode = 0L; |
| 104 | const Standard_Boolean isReverse = (theShape.Orientation() == TopAbs_REVERSED); |
| 105 | |
| 106 | TopoDS_Shape aTestedShape; |
| 107 | aTestedShape.TShape(theShape.TShape()); |
| 108 | aTestedShape.Orientation(isReverse ? TopAbs_REVERSED : TopAbs_FORWARD); |
| 109 | switch (theShapeType) { |
| 110 | case TopAbs_FACE: |
| 111 | { |
| 112 | const TopoDS_Face& aFace = TopoDS::Face(theShape); |
| 113 | if (aFace.IsNull() == Standard_False) { |
| 114 | Handle(Poly_Triangulation) aTri = |
| 115 | BRep_Tool::Triangulation(aFace, theLoc); |
| 116 | |
| 117 | if (myRelMap.IsBound(aTestedShape)) { |
| 118 | aTShapeNode = myRelMap(aTestedShape); |
| 119 | break; |
| 120 | } |
| 121 | |
| 122 | if (aTri.IsNull() == Standard_False) { |
| 123 | TopoDS_Shape aTestedShapeRev = aTestedShape; |
| 124 | aTestedShapeRev.Orientation(isReverse ? |
| 125 | TopAbs_FORWARD : TopAbs_REVERSED); |
| 126 | Handle(VrmlData_IndexedFaceSet) aFaceSetToReuse; |
| 127 | if (myRelMap.IsBound(aTestedShapeRev)) |
| 128 | aFaceSetToReuse = Handle(VrmlData_IndexedFaceSet)::DownCast |
| 129 | (myRelMap(aTestedShapeRev)); |
| 130 | |
| 131 | Handle(VrmlData_Coordinate) aCoordToReuse; |
| 132 | if (aFaceSetToReuse.IsNull() == Standard_False) |
| 133 | aCoordToReuse = aFaceSetToReuse->Coordinates(); |
| 134 | |
| 135 | aTShapeNode = triToIndexedFaceSet(aTri, aFace, aCoordToReuse); |
| 136 | myScene.AddNode(aTShapeNode, Standard_False); |
| 137 | // Bind the converted face |
| 138 | myRelMap.Bind(aTestedShape, aTShapeNode); |
| 139 | } |
| 140 | } |
| 141 | } |
| 142 | break; |
| 143 | case TopAbs_WIRE: |
| 144 | { |
| 145 | const TopoDS_Wire& aWire = TopoDS::Wire(theShape); |
| 146 | if (aWire.IsNull() == Standard_False) { |
| 147 | } |
| 148 | } |
| 149 | break; |
| 150 | case TopAbs_EDGE: |
| 151 | { |
| 152 | const TopoDS_Edge& aEdge = TopoDS::Edge(theShape); |
| 153 | if (aEdge.IsNull() == Standard_False) { |
| 154 | if (myRelMap.IsBound(aTestedShape)) { |
| 155 | aTShapeNode = myRelMap(aTestedShape); |
| 156 | break; |
| 157 | } |
| 158 | // Check the presence of reversly oriented Edge. It can also be used |
| 159 | // because we do not distinguish the orientation for edges. |
| 160 | aTestedShape.Orientation(isReverse ? |
| 161 | TopAbs_FORWARD : TopAbs_REVERSED); |
| 162 | if (myRelMap.IsBound(aTestedShape)) { |
| 163 | aTShapeNode = myRelMap(aTestedShape); |
| 164 | break; |
| 165 | } |
| 166 | |
| 167 | //try to find PolygonOnTriangulation |
| 168 | Handle(Poly_PolygonOnTriangulation) aPT; |
| 169 | Handle(Poly_Triangulation) aT; |
| 170 | TopLoc_Location aL; |
| 171 | BRep_Tool::PolygonOnTriangulation(aEdge, aPT, aT, aL); |
| 172 | |
| 173 | // If PolygonOnTriangulation was found -> get the Polygon3D |
| 174 | Handle(Poly_Polygon3D) aPol; |
| 175 | if (!aPT.IsNull() && !aT.IsNull() && aPT->HasParameters()) { |
| 176 | BRepAdaptor_Curve aCurve(aEdge); |
| 177 | Handle(TColStd_HArray1OfReal) aPrs = aPT->Parameters(); |
| 178 | Standard_Integer nbNodes = aPT->NbNodes(); |
| 179 | TColgp_Array1OfPnt arrNodes(1, nbNodes); |
| 180 | TColStd_Array1OfReal arrUVNodes(1, nbNodes); |
| 181 | |
| 182 | for (Standard_Integer j = 1; j <= nbNodes; j++) { |
| 183 | arrUVNodes(j) = aPrs->Value(aPrs->Lower() + j - 1); |
| 184 | arrNodes(j) = aCurve.Value(arrUVNodes(j)); |
| 185 | } |
| 186 | aPol = new Poly_Polygon3D(arrNodes, arrUVNodes); |
| 187 | aPol->Deflection(aPT->Deflection()); |
| 188 | } |
| 189 | else { |
| 190 | aPol = BRep_Tool::Polygon3D(aEdge, aL); |
| 191 | |
| 192 | // If polygon was not found -> generate it |
| 193 | if (aPol.IsNull()) { |
| 194 | BRepAdaptor_Curve aCurve(aEdge); |
| 195 | const Standard_Real aFirst = aCurve.FirstParameter(); |
| 196 | const Standard_Real aLast = aCurve.LastParameter(); |
| 197 | |
| 198 | GCPnts_TangentialDeflection TD(aCurve, aFirst, aLast, |
| 199 | myDeflAngle, myDeflection, 2); |
| 200 | const Standard_Integer nbNodes = TD.NbPoints(); |
| 201 | |
| 202 | TColgp_Array1OfPnt arrNodes(1, nbNodes); |
| 203 | TColStd_Array1OfReal arrUVNodes(1, nbNodes); |
| 204 | for (Standard_Integer j = 1; j <= nbNodes; j++) { |
| 205 | arrNodes(j) = TD.Value(j); |
| 206 | arrUVNodes(j) = TD.Parameter(j); |
| 207 | } |
| 208 | aPol = new Poly_Polygon3D(arrNodes, arrUVNodes); |
| 209 | aPol->Deflection(myDeflection); |
| 210 | } |
| 211 | } |
| 212 | |
| 213 | if (!aPol.IsNull()) |
| 214 | { |
| 215 | aTShapeNode = polToIndexedLineSet(aPol); |
| 216 | myScene.AddNode(aTShapeNode, Standard_False); |
| 217 | // Bind the converted face |
| 218 | myRelMap.Bind(aTestedShape, aTShapeNode); |
| 219 | } |
| 220 | } |
| 221 | } |
| 222 | break; |
| 223 | default: |
| 224 | break; |
| 225 | } |
| 226 | |
| 227 | return aTShapeNode; |
| 228 | } |
| 229 | |
| 230 | |
| 231 | //======================================================================= |
| 232 | //function : Convert |
| 233 | //purpose : |
| 234 | //======================================================================= |
| 235 | |
| 236 | void VrmlData_ShapeConvert::Convert (const Standard_Boolean theExtractFaces, |
| 237 | const Standard_Boolean theExtractEdges, |
| 238 | const Standard_Real theDeflection, |
| 239 | const Standard_Real theDeflAngle) |
| 240 | { |
| 241 | //const Standard_Real aDeflection = |
| 242 | // theDeflection < 0.0001 ? 0.0001 : theDeflection; |
| 243 | |
| 244 | myDeflection = theDeflection < 0.0001 ? 0.0001 : theDeflection; |
| 245 | myDeflAngle = theDeflAngle; |
| 246 | |
| 247 | Standard_Boolean Extract[2] = {theExtractFaces, theExtractEdges}; |
| 248 | TopAbs_ShapeEnum ShapeType[2] = {TopAbs_FACE, TopAbs_EDGE}; |
| 249 | Standard_Integer i; |
| 250 | |
| 251 | const Handle(NCollection_IncAllocator) anAlloc = new NCollection_IncAllocator; |
| 252 | |
| 253 | // Relocation map for converted shapes. We should distinguish both TShape |
| 254 | // and Orientation in this map. |
| 255 | //NCollection_DataMap <TopoDS_Shape,Handle(VrmlData_Geometry)> |
| 256 | // aRelMap (100, anAlloc); |
| 257 | myRelMap = NCollection_DataMap <TopoDS_Shape, Handle(VrmlData_Geometry)>(100, anAlloc); |
| 258 | |
| 259 | NCollection_List<ShapeData>::Iterator anIter (myShapes); |
| 260 | for (; anIter.More(); anIter.Next()) |
| 261 | { |
| 262 | ShapeData& aData = anIter.ChangeValue(); |
| 263 | TCollection_AsciiString aGrName = aData.Name; |
| 264 | aGrName.ChangeAll(' ', '_'); |
| 265 | aGrName.ChangeAll('#', '_'); |
| 266 | Handle(VrmlData_Group) aGroup = |
| 267 | new VrmlData_Group (myScene, aGrName.ToCString()); |
| 268 | myScene.AddNode (aGroup); |
| 269 | |
| 270 | for(i = 0; i < 2; ++i) { |
| 271 | |
| 272 | if(!Extract[i]) continue; |
| 273 | |
| 274 | TopExp_Explorer anExp (aData.Shape, ShapeType[i]); |
| 275 | for (; anExp.More(); anExp.Next()) { |
| 276 | const TopoDS_Shape& aShape = anExp.Current(); |
| 277 | TopLoc_Location aLoc; |
| 278 | Handle(VrmlData_Geometry) aTShapeNode = |
| 279 | makeTShapeNode(aShape, ShapeType[i], aLoc); |
| 280 | if (!aTShapeNode.IsNull()) { |
| 281 | const Handle(VrmlData_ShapeNode) aShapeNode = |
| 282 | new VrmlData_ShapeNode (myScene, 0L); |
| 283 | aShapeNode->SetAppearance (ShapeType[i] == TopAbs_FACE ? |
| 284 | defaultMaterialFace():defaultMaterialEdge()); |
| 285 | myScene.AddNode (aShapeNode, Standard_False); |
| 286 | aShapeNode->SetGeometry (aTShapeNode); |
| 287 | if (aLoc.IsIdentity()) |
| 288 | // Store the shape node directly into the main Group. |
| 289 | aGroup->AddNode (aShapeNode); |
| 290 | else { |
| 291 | // Create a Transform grouping node |
| 292 | Handle(VrmlData_Group) aTrans = new VrmlData_Group (myScene, 0L, |
| 293 | Standard_True); |
| 294 | gp_Trsf aTrsf (aLoc); |
| 295 | if (fabs(myScale - 1.) > Precision::Confusion()) |
| 296 | { |
| 297 | const gp_XYZ aTransl = aTrsf.TranslationPart() * myScale; |
| 298 | aTrsf.SetTranslationPart (aTransl); |
| 299 | } |
| 300 | aTrans->SetTransform (aTrsf); |
| 301 | myScene.AddNode (aTrans, Standard_False); |
| 302 | aGroup->AddNode (aTrans); |
| 303 | |
| 304 | // Store the shape node under the transform. |
| 305 | aTrans->AddNode (aShapeNode); |
| 306 | } |
| 307 | } |
| 308 | } |
| 309 | } |
| 310 | } |
| 311 | myShapes.Clear(); |
| 312 | } |
| 313 | |
| 314 | //======================================================================= |
| 315 | //function : triToIndexedFaceSet |
| 316 | //purpose : |
| 317 | //======================================================================= |
| 318 | |
| 319 | Handle(VrmlData_Geometry) VrmlData_ShapeConvert::triToIndexedFaceSet |
| 320 | (const Handle(Poly_Triangulation)& theTri, |
| 321 | const TopoDS_Face& theFace, |
| 322 | const Handle(VrmlData_Coordinate)& theCoord) |
| 323 | { |
| 324 | Standard_Integer i; |
| 325 | const Standard_Integer nNodes (theTri->NbNodes()); |
| 326 | const Standard_Integer nTriangles (theTri->NbTriangles()); |
| 327 | |
| 328 | // protection against creation degenerative triangles |
| 329 | Standard_Integer nbTri = 0; |
| 330 | Poly_Array1OfTriangle aTriangles(1, nTriangles); |
| 331 | for (i = 0; i < nTriangles; i++) { |
| 332 | Standard_Integer idx[3]; |
| 333 | theTri->Triangle (i + 1).Get (idx[0], idx[1], idx[2]); |
| 334 | if (idx[0] == idx[1] || idx[0] == idx[2] || idx[1] == idx[2]) |
| 335 | { |
| 336 | continue; |
| 337 | } |
| 338 | nbTri++; |
| 339 | aTriangles.SetValue (nbTri, theTri->Triangle (i + 1)); |
| 340 | } |
| 341 | aTriangles.Resize(1, nbTri, Standard_True); |
| 342 | |
| 343 | const Handle(VrmlData_IndexedFaceSet) aFaceSet = |
| 344 | new VrmlData_IndexedFaceSet (myScene, |
| 345 | 0L, // no name |
| 346 | Standard_True, // IsCCW |
| 347 | Standard_False, // IsSolid |
| 348 | Standard_False); // IsConvex |
| 349 | const Handle(NCollection_IncAllocator)& anAlloc = myScene.Allocator(); |
| 350 | const Standard_Boolean isReverse = (theFace.Orientation() == TopAbs_REVERSED); |
| 351 | |
| 352 | // Create the array of triangles |
| 353 | const Standard_Integer ** arrPolygons = static_cast<const Standard_Integer **> |
| 354 | (anAlloc->Allocate (nbTri * sizeof(const Standard_Integer *))); |
| 355 | aFaceSet->SetPolygons (nbTri, arrPolygons); |
| 356 | |
| 357 | // Store the triangles |
| 358 | for (i = 0; i < nbTri; i++) { |
| 359 | Standard_Integer * aPolygon = static_cast<Standard_Integer *> |
| 360 | (anAlloc->Allocate (4*sizeof(Standard_Integer))); |
| 361 | aPolygon[0] = 3; |
| 362 | aTriangles(i + 1).Get(aPolygon[1], aPolygon[2], aPolygon[3]); |
| 363 | aPolygon[1]--; |
| 364 | if (isReverse) { |
| 365 | const Standard_Integer aTmp = aPolygon[2]-1; |
| 366 | aPolygon[2] = aPolygon[3]-1; |
| 367 | aPolygon[3] = aTmp; |
| 368 | } else { |
| 369 | aPolygon[2]--; |
| 370 | aPolygon[3]--; |
| 371 | } |
| 372 | arrPolygons[i] = aPolygon; |
| 373 | } |
| 374 | |
| 375 | // Create the Coordinates node |
| 376 | if (theCoord.IsNull() == Standard_False) |
| 377 | aFaceSet->SetCoordinates (theCoord); |
| 378 | else { |
| 379 | gp_XYZ * arrNodes = static_cast <gp_XYZ *> |
| 380 | (anAlloc->Allocate (nNodes * sizeof(gp_XYZ))); |
| 381 | for (i = 0; i < nNodes; i++) |
| 382 | { |
| 383 | arrNodes[i] = theTri->Node (i+1).XYZ() * myScale; |
| 384 | } |
| 385 | |
| 386 | const Handle(VrmlData_Coordinate) aCoordNode = |
| 387 | new VrmlData_Coordinate (myScene, 0L, nNodes, arrNodes); |
| 388 | myScene.AddNode (aCoordNode, Standard_False); |
| 389 | aFaceSet->SetCoordinates (aCoordNode); |
| 390 | } |
| 391 | |
| 392 | // Create the Normals node if theTri has normals |
| 393 | if (theTri->HasNormals()) |
| 394 | { |
| 395 | gp_XYZ* arrVec = static_cast<gp_XYZ*>(anAlloc->Allocate (nNodes * sizeof(gp_XYZ))); |
| 396 | gp_Vec3f aVec3; |
| 397 | for (i = 0; i < nNodes; i++) |
| 398 | { |
| 399 | theTri->Normal (i + 1, aVec3); |
| 400 | gp_XYZ aNormal (aVec3.x(), aVec3.y(), aVec3.z()); |
| 401 | if (isReverse) |
| 402 | { |
| 403 | aNormal.Reverse(); |
| 404 | } |
| 405 | arrVec[i] = aNormal; |
| 406 | } |
| 407 | const Handle(VrmlData_Normal) aNormalNode = |
| 408 | new VrmlData_Normal (myScene, 0L, nNodes, arrVec); |
| 409 | myScene.AddNode (aNormalNode, Standard_False); |
| 410 | aFaceSet->SetNormals (aNormalNode); |
| 411 | return Handle(VrmlData_Geometry) (aFaceSet); |
| 412 | } |
| 413 | |
| 414 | Poly_Connect PC(theTri); |
| 415 | // Create the Normals node (if UV- values are available) |
| 416 | TopLoc_Location aLoc; |
| 417 | const Standard_Real aConf2 = Precision::SquareConfusion(); |
| 418 | const Handle(Geom_Surface) aSurface = BRep_Tool::Surface (theFace, aLoc); |
| 419 | if (theTri->HasUVNodes() && aSurface.IsNull() == Standard_False) |
| 420 | { |
| 421 | if (aSurface->IsCNu(1) && aSurface->IsCNv(1)) |
| 422 | { |
| 423 | gp_XYZ* arrVec = static_cast<gp_XYZ*> (anAlloc->Allocate (nNodes * sizeof(gp_XYZ))); |
| 424 | |
| 425 | // Compute the normal vectors |
| 426 | Standard_Real Tol = Sqrt(aConf2); |
| 427 | for (i = 0; i < nNodes; i++) |
| 428 | { |
| 429 | const gp_Pnt2d aUV = theTri->UVNode (i+1); |
| 430 | gp_Dir aNormal; |
| 431 | if (GeomLib::NormEstim(aSurface, aUV, Tol, aNormal) > 1) { |
| 432 | //Try to estimate as middle normal of adjacent triangles |
| 433 | Standard_Integer n[3]; |
| 434 | |
| 435 | gp_XYZ eqPlan(0., 0., 0.); |
| 436 | for (PC.Initialize(i+1); PC.More(); PC.Next()) { |
| 437 | aTriangles(PC.Value()).Get(n[0], n[1], n[2]); |
| 438 | gp_XYZ v1 (theTri->Node (n[1]).Coord()-theTri->Node (n[0]).Coord()); |
| 439 | gp_XYZ v2 (theTri->Node (n[2]).Coord()-theTri->Node (n[1]).Coord()); |
| 440 | gp_XYZ vv = v1^v2; |
| 441 | |
| 442 | Standard_Real mod = vv.Modulus(); |
| 443 | if (mod < Tol) |
| 444 | continue; |
| 445 | |
| 446 | eqPlan += vv/mod; |
| 447 | } |
| 448 | |
| 449 | if (eqPlan.SquareModulus() > gp::Resolution()) |
| 450 | aNormal = gp_Dir(eqPlan); |
| 451 | } |
| 452 | if (isReverse) |
| 453 | aNormal.Reverse(); |
| 454 | |
| 455 | if (aNormal.X()*aNormal.X() < aConf2) |
| 456 | aNormal.SetX(0.); |
| 457 | if (aNormal.Y()*aNormal.Y() < aConf2) |
| 458 | aNormal.SetY(0.); |
| 459 | if (aNormal.Z()*aNormal.Z() < aConf2) |
| 460 | aNormal.SetZ(0.); |
| 461 | |
| 462 | arrVec[i] = aNormal.XYZ(); |
| 463 | } |
| 464 | |
| 465 | const Handle(VrmlData_Normal) aNormalNode = |
| 466 | new VrmlData_Normal (myScene, 0L, nNodes, arrVec); |
| 467 | myScene.AddNode (aNormalNode, Standard_False); |
| 468 | aFaceSet->SetNormals (aNormalNode); |
| 469 | } |
| 470 | } |
| 471 | |
| 472 | return Handle(VrmlData_Geometry) (aFaceSet); |
| 473 | } |
| 474 | |
| 475 | //======================================================================= |
| 476 | //function : polToIndexedLineSet |
| 477 | //purpose : single polygon3D => IndexedLineSet |
| 478 | //======================================================================= |
| 479 | |
| 480 | Handle(VrmlData_Geometry) VrmlData_ShapeConvert::polToIndexedLineSet |
| 481 | (const Handle(Poly_Polygon3D)& thePol) |
| 482 | { |
| 483 | Standard_Integer i; |
| 484 | const Standard_Integer nNodes (thePol->NbNodes()); |
| 485 | const TColgp_Array1OfPnt& arrPolyNodes = thePol->Nodes(); |
| 486 | const Handle(NCollection_IncAllocator)& anAlloc = myScene.Allocator(); |
| 487 | |
| 488 | const Handle(VrmlData_IndexedLineSet) aLineSet = |
| 489 | new VrmlData_IndexedLineSet (myScene, 0L); |
| 490 | |
| 491 | // Create the array of polygons (1 member) |
| 492 | const Standard_Integer ** arrPolygons = static_cast<const Standard_Integer **> |
| 493 | (anAlloc->Allocate (sizeof(const Standard_Integer *))); |
| 494 | aLineSet->SetPolygons (1, arrPolygons); |
| 495 | |
| 496 | // Store the polygon |
| 497 | Standard_Integer * aPolygon = static_cast<Standard_Integer *> |
| 498 | (anAlloc->Allocate ((nNodes+1)*sizeof(Standard_Integer))); |
| 499 | aPolygon[0] = nNodes; |
| 500 | for (i = 1; i <= nNodes; i++) |
| 501 | aPolygon[i] = i-1; |
| 502 | arrPolygons[0] = aPolygon; |
| 503 | |
| 504 | // Create the Coordinates node |
| 505 | gp_XYZ * arrNodes = static_cast <gp_XYZ *> |
| 506 | (anAlloc->Allocate (nNodes * sizeof(gp_XYZ))); |
| 507 | for (i = 0; i < nNodes; i++) |
| 508 | arrNodes[i] = arrPolyNodes(i+1).XYZ() * myScale; |
| 509 | |
| 510 | const Handle(VrmlData_Coordinate) aCoordNode = |
| 511 | new VrmlData_Coordinate (myScene, 0L, nNodes, arrNodes); |
| 512 | myScene.AddNode (aCoordNode, Standard_False); |
| 513 | aLineSet->SetCoordinates (aCoordNode); |
| 514 | |
| 515 | return Handle(VrmlData_Geometry) (aLineSet); |
| 516 | } |
| 517 | |
| 518 | //======================================================================= |
| 519 | //function : defaultMaterialFace |
| 520 | //purpose : |
| 521 | //======================================================================= |
| 522 | |
| 523 | Handle(VrmlData_Appearance) VrmlData_ShapeConvert::defaultMaterialFace () const |
| 524 | { |
| 525 | static char aNodeName[] = "__defaultMaterialFace"; |
| 526 | Handle(VrmlData_Appearance) anAppearance = |
| 527 | Handle(VrmlData_Appearance)::DownCast(myScene.FindNode(aNodeName)); |
| 528 | if (anAppearance.IsNull()) { |
| 529 | const Handle(VrmlData_Material) aMaterial = |
| 530 | new VrmlData_Material (myScene, 0L, 1.0, 0.022, 0.); |
| 531 | aMaterial->SetDiffuseColor (Quantity_Color(0.780392, 0.568627, 0.113725, |
| 532 | Quantity_TOC_sRGB)); |
| 533 | aMaterial->SetEmissiveColor(Quantity_Color(0.329412, 0.223529, 0.027451, |
| 534 | Quantity_TOC_sRGB)); |
| 535 | aMaterial->SetSpecularColor(Quantity_Color(0.992157, 0.941176, 0.807843, |
| 536 | Quantity_TOC_sRGB)); |
| 537 | myScene.AddNode (aMaterial, Standard_False); |
| 538 | anAppearance = new VrmlData_Appearance (myScene, aNodeName); |
| 539 | anAppearance->SetMaterial (aMaterial); |
| 540 | myScene.AddNode (anAppearance, Standard_False); |
| 541 | } |
| 542 | return anAppearance; |
| 543 | } |
| 544 | |
| 545 | //======================================================================= |
| 546 | //function : defaultMaterialEdge |
| 547 | //purpose : |
| 548 | //======================================================================= |
| 549 | |
| 550 | Handle(VrmlData_Appearance) VrmlData_ShapeConvert::defaultMaterialEdge () const |
| 551 | { |
| 552 | static char aNodeName[] = "__defaultMaterialEdge"; |
| 553 | Handle(VrmlData_Appearance) anAppearance = |
| 554 | Handle(VrmlData_Appearance)::DownCast(myScene.FindNode(aNodeName)); |
| 555 | if (anAppearance.IsNull()) { |
| 556 | const Handle(VrmlData_Material) aMaterial = |
| 557 | new VrmlData_Material (myScene, 0L, 0.2, 0.2, 0.2); |
| 558 | aMaterial->SetDiffuseColor (Quantity_Color(0.2, 0.7, 0.2, |
| 559 | Quantity_TOC_RGB)); |
| 560 | aMaterial->SetEmissiveColor(Quantity_Color(0.2, 0.7, 0.2, |
| 561 | Quantity_TOC_RGB)); |
| 562 | aMaterial->SetSpecularColor(Quantity_Color(0.2, 0.7, 0.2, |
| 563 | Quantity_TOC_RGB)); |
| 564 | myScene.AddNode (aMaterial, Standard_False); |
| 565 | anAppearance = new VrmlData_Appearance (myScene, aNodeName); |
| 566 | anAppearance->SetMaterial (aMaterial); |
| 567 | myScene.AddNode (anAppearance, Standard_False); |
| 568 | } |
| 569 | return anAppearance; |
| 570 | } |
| 571 | |
| 572 | |
| 573 | //======================================================================= |
| 574 | //function : addShape |
| 575 | //purpose : Adds the shape from the document |
| 576 | //======================================================================= |
| 577 | void VrmlData_ShapeConvert::addShape (const Handle(VrmlData_Group)& theParent, |
| 578 | const TDF_Label& theLabel, |
| 579 | const Handle(TDocStd_Document)& theDoc) |
| 580 | { |
| 581 | Handle(XCAFDoc_ShapeTool) aShapeTool = XCAFDoc_DocumentTool::ShapeTool(theDoc->Main()); |
| 582 | Handle(XCAFDoc_ColorTool) aColorTool = XCAFDoc_DocumentTool::ColorTool(theDoc->Main()); |
| 583 | Handle(XCAFDoc_VisMaterialTool) aMatTool = XCAFDoc_DocumentTool::VisMaterialTool(theDoc->Main()); |
| 584 | |
| 585 | NCollection_DataMap<TopoDS_Shape, TDF_Label> aChildShapeToLabels; |
| 586 | TDF_LabelSequence aChildLabels; |
| 587 | aShapeTool->GetSubShapes(theLabel, aChildLabels); |
| 588 | for (TDF_LabelSequence::Iterator aChildIter(aChildLabels); aChildIter.More(); aChildIter.Next()) |
| 589 | { |
| 590 | const TDF_Label& aChildLabel = aChildIter.Value(); |
| 591 | TopoDS_Shape aChildShape; |
| 592 | if (aShapeTool->GetShape(aChildLabel, aChildShape)) |
| 593 | { |
| 594 | aChildShapeToLabels.Bind(aChildShape, aChildLabel); |
| 595 | } |
| 596 | } |
| 597 | |
| 598 | const TopoDS_Shape aShape = aShapeTool->GetShape(theLabel); |
| 599 | Handle(VrmlData_Group) aGroup = 0L; |
| 600 | TopExp_Explorer anExp(aShape, TopAbs_FACE); |
| 601 | Standard_Integer nbFaces = 0; |
| 602 | for (; anExp.More(); anExp.Next()) { |
| 603 | nbFaces++; |
| 604 | } |
| 605 | Handle(TDataStd_Name) aNameAttribute; |
| 606 | theLabel.FindAttribute(TDataStd_Name::GetID(), aNameAttribute); |
| 607 | if (nbFaces > 1) |
| 608 | { |
| 609 | if (!aNameAttribute.IsNull()) |
| 610 | { |
| 611 | TCollection_AsciiString aName = aNameAttribute->Get(); |
| 612 | aName.ChangeAll(' ', '_'); |
| 613 | aName.ChangeAll('#', '_'); |
| 614 | aGroup = new VrmlData_Group(myScene, aName.ToCString()); |
| 615 | } |
| 616 | else |
| 617 | { |
| 618 | aGroup = new VrmlData_Group(myScene, 0L); |
| 619 | } |
| 620 | myScene.AddNode(aGroup, theParent.IsNull()); |
| 621 | if (!theParent.IsNull()) |
| 622 | { |
| 623 | theParent->AddNode(aGroup); |
| 624 | } |
| 625 | } |
| 626 | |
| 627 | anExp.Init(aShape, TopAbs_FACE); |
| 628 | for (; anExp.More(); anExp.Next()) { |
| 629 | TopLoc_Location aLoc; |
| 630 | Handle(VrmlData_Geometry) aTShapeNode = |
| 631 | makeTShapeNode(anExp.Current(), TopAbs_FACE, aLoc); |
| 632 | if (!aTShapeNode.IsNull()) |
| 633 | { |
| 634 | Handle(VrmlData_ShapeNode) aShapeNode = 0L; |
| 635 | if (aGroup.IsNull() && !aNameAttribute.IsNull()) |
| 636 | { |
| 637 | TCollection_AsciiString aName = aNameAttribute->Get(); |
| 638 | aName.ChangeAll(' ', '_'); |
| 639 | aName.ChangeAll('#', '_'); |
| 640 | aShapeNode = new VrmlData_ShapeNode(myScene, aName.ToCString()); |
| 641 | } |
| 642 | else |
| 643 | { |
| 644 | aShapeNode = new VrmlData_ShapeNode(myScene, 0L); |
| 645 | } |
| 646 | |
| 647 | // set color |
| 648 | XCAFPrs_Style aStyle; |
| 649 | Quantity_ColorRGBA aColor; |
| 650 | TDF_Label aLabel, anAttribLab; |
| 651 | if (aChildShapeToLabels.Find (anExp.Current(), aLabel)) |
| 652 | { |
| 653 | Handle(XCAFDoc_VisMaterial) aVisMat = aMatTool->GetShapeMaterial (aLabel); |
| 654 | if (!aVisMat.IsNull() |
| 655 | && !aVisMat->IsEmpty()) |
| 656 | { |
| 657 | anAttribLab = aVisMat->Label(); |
| 658 | aStyle.SetMaterial (aVisMat); |
| 659 | } |
| 660 | else if (aColorTool->GetColor (aLabel, XCAFDoc_ColorSurf, anAttribLab) |
| 661 | || aColorTool->GetColor (aLabel, XCAFDoc_ColorGen, anAttribLab)) |
| 662 | { |
| 663 | aColorTool->GetColor (anAttribLab, aColor); |
| 664 | aStyle.SetColorSurf (aColor); |
| 665 | } |
| 666 | } |
| 667 | if (!aStyle.IsSetColorSurf() |
| 668 | && aStyle.Material().IsNull()) |
| 669 | { |
| 670 | Handle(XCAFDoc_VisMaterial) aVisMat = aMatTool->GetShapeMaterial (theLabel); |
| 671 | if (!aVisMat.IsNull() |
| 672 | && !aVisMat->IsEmpty()) |
| 673 | { |
| 674 | anAttribLab = aVisMat->Label(); |
| 675 | aStyle.SetMaterial (aVisMat); |
| 676 | } |
| 677 | if (aColorTool->GetColor (theLabel, XCAFDoc_ColorSurf, anAttribLab) |
| 678 | || aColorTool->GetColor (theLabel, XCAFDoc_ColorGen, anAttribLab)) |
| 679 | { |
| 680 | aColorTool->GetColor (anAttribLab, aColor); |
| 681 | aStyle.SetColorSurf (aColor); |
| 682 | } |
| 683 | } |
| 684 | if (!aStyle.IsSetColorSurf() |
| 685 | && aStyle.Material().IsNull()) |
| 686 | { |
| 687 | aShapeNode->SetAppearance(defaultMaterialFace()); |
| 688 | } |
| 689 | else |
| 690 | { |
| 691 | aShapeNode->SetAppearance (makeMaterialFromStyle (aStyle, anAttribLab)); |
| 692 | } |
| 693 | |
| 694 | myScene.AddNode(aShapeNode, theParent.IsNull() && aGroup.IsNull()); |
| 695 | aShapeNode->SetGeometry(aTShapeNode); |
| 696 | if (aLoc.IsIdentity()) |
| 697 | { |
| 698 | // Store the shape node directly into the main Group. |
| 699 | if (!aGroup.IsNull()) |
| 700 | { |
| 701 | aGroup->AddNode(aShapeNode); |
| 702 | } |
| 703 | else if (!theParent.IsNull()) |
| 704 | { |
| 705 | theParent->AddNode(aShapeNode); |
| 706 | } |
| 707 | } |
| 708 | else |
| 709 | { |
| 710 | // Create a Transform grouping node |
| 711 | Handle(VrmlData_Group) aTrans = new VrmlData_Group(myScene, 0L, |
| 712 | Standard_True); |
| 713 | gp_Trsf aTrsf(aLoc); |
| 714 | if (fabs(myScale - 1.) > Precision::Confusion()) |
| 715 | { |
| 716 | const gp_XYZ aTransl = aTrsf.TranslationPart() * myScale; |
| 717 | aTrsf.SetTranslationPart(aTransl); |
| 718 | } |
| 719 | aTrans->SetTransform(aTrsf); |
| 720 | myScene.AddNode(aTrans, theParent.IsNull() && aGroup.IsNull()); |
| 721 | if (!aGroup.IsNull()) |
| 722 | { |
| 723 | aGroup->AddNode(aTrans); |
| 724 | } |
| 725 | else if (!theParent.IsNull()) |
| 726 | { |
| 727 | theParent->AddNode(aTrans); |
| 728 | } |
| 729 | // Store the shape node under the transform. |
| 730 | aTrans->AddNode(aShapeNode); |
| 731 | } |
| 732 | } |
| 733 | } |
| 734 | } |
| 735 | |
| 736 | |
| 737 | //======================================================================= |
| 738 | //function : addInstance |
| 739 | //purpose : Adds the reference from the document |
| 740 | //======================================================================= |
| 741 | void VrmlData_ShapeConvert::addInstance (const Handle(VrmlData_Group)& theParent, |
| 742 | const TDF_Label& theLabel, |
| 743 | const Handle(TDocStd_Document)& theDoc) |
| 744 | { |
| 745 | Handle(XCAFDoc_ShapeTool) aShapeTool = XCAFDoc_DocumentTool::ShapeTool(theDoc->Main()); |
| 746 | |
| 747 | const TopLoc_Location aLoc = aShapeTool->GetLocation(theLabel); |
| 748 | Handle(VrmlData_Group) aTrans = 0L; |
| 749 | if (!aLoc.IsIdentity()) |
| 750 | { |
| 751 | // Create a Transform grouping node |
| 752 | aTrans = new VrmlData_Group(myScene, 0L, Standard_True); |
| 753 | gp_Trsf aTrsf(aLoc); |
| 754 | if (fabs(myScale - 1.) > Precision::Confusion()) |
| 755 | { |
| 756 | const gp_XYZ aTransl = aTrsf.TranslationPart() * myScale; |
| 757 | aTrsf.SetTranslationPart(aTransl); |
| 758 | } |
| 759 | aTrans->SetTransform(aTrsf); |
| 760 | myScene.AddNode(aTrans, theParent.IsNull()); |
| 761 | if (!theParent.IsNull()) |
| 762 | { |
| 763 | theParent->AddNode(aTrans); |
| 764 | } |
| 765 | } |
| 766 | |
| 767 | Handle(TDataStd_Name) aNameAttribute; |
| 768 | theLabel.FindAttribute(TDataStd_Name::GetID(), aNameAttribute); |
| 769 | |
| 770 | TDF_Label aRefLabel; |
| 771 | aShapeTool->GetReferredShape(theLabel, aRefLabel); |
| 772 | Handle(TDataStd_Name) aRefNameAttribute; |
| 773 | aRefLabel.FindAttribute(TDataStd_Name::GetID(), aRefNameAttribute); |
| 774 | |
| 775 | if (aShapeTool->IsSimpleShape(aRefLabel)) |
| 776 | { |
| 777 | addShape((aTrans.IsNull() ? theParent : aTrans), aRefLabel, theDoc); |
| 778 | } |
| 779 | else if (aShapeTool->IsAssembly(aRefLabel)) |
| 780 | { |
| 781 | addAssembly((aTrans.IsNull() ? theParent : aTrans), aRefLabel, theDoc, aTrans.IsNull()); |
| 782 | } |
| 783 | } |
| 784 | |
| 785 | |
| 786 | //======================================================================= |
| 787 | //function : addAssembly |
| 788 | //purpose : Adds the assembly from the document |
| 789 | //======================================================================= |
| 790 | void VrmlData_ShapeConvert::addAssembly (const Handle(VrmlData_Group)& theParent, |
| 791 | const TDF_Label& theLabel, |
| 792 | const Handle(TDocStd_Document)& theDoc, |
| 793 | const Standard_Boolean theNeedCreateGroup) |
| 794 | { |
| 795 | Handle(XCAFDoc_ShapeTool) aShapeTool = XCAFDoc_DocumentTool::ShapeTool(theDoc->Main()); |
| 796 | |
| 797 | Handle(VrmlData_Group) anAssembly = 0L; |
| 798 | if (theNeedCreateGroup) |
| 799 | { |
| 800 | Handle(TDataStd_Name) aNameAttribute; |
| 801 | theLabel.FindAttribute(TDataStd_Name::GetID(), aNameAttribute); |
| 802 | if (!aNameAttribute.IsNull()) |
| 803 | { |
| 804 | TCollection_AsciiString aName = aNameAttribute->Get(); |
| 805 | aName.ChangeAll(' ', '_'); |
| 806 | aName.ChangeAll('#', '_'); |
| 807 | anAssembly = new VrmlData_Group(myScene, aName.ToCString()); |
| 808 | } |
| 809 | else |
| 810 | { |
| 811 | anAssembly = new VrmlData_Group(myScene, 0L); |
| 812 | } |
| 813 | TopLoc_Location aLoc = aShapeTool->GetLocation(theLabel); |
| 814 | if (!aLoc.IsIdentity()) |
| 815 | { |
| 816 | gp_Trsf aTrsf(aLoc); |
| 817 | if (fabs(myScale - 1.) > Precision::Confusion()) |
| 818 | { |
| 819 | const gp_XYZ aTransl = aTrsf.TranslationPart() * myScale; |
| 820 | aTrsf.SetTranslationPart(aTransl); |
| 821 | } |
| 822 | anAssembly->SetTransform(aTrsf); |
| 823 | } |
| 824 | myScene.AddNode(anAssembly, theParent.IsNull()); |
| 825 | if (!theParent.IsNull()) |
| 826 | { |
| 827 | theParent->AddNode(anAssembly); |
| 828 | } |
| 829 | } |
| 830 | |
| 831 | TDF_LabelSequence aChildLabels; |
| 832 | aShapeTool->GetComponents(theLabel, aChildLabels); |
| 833 | for (TDF_LabelSequence::Iterator aChildIter(aChildLabels); aChildIter.More(); aChildIter.Next()) |
| 834 | { |
| 835 | const TDF_Label& aChildLabel = aChildIter.Value(); |
| 836 | if (aShapeTool->IsAssembly(aChildLabel)) |
| 837 | { |
| 838 | addAssembly((anAssembly.IsNull() ? theParent : anAssembly), aChildLabel, theDoc, anAssembly.IsNull()); |
| 839 | } |
| 840 | else if (aShapeTool->IsReference(aChildLabel)) |
| 841 | { |
| 842 | addInstance((anAssembly.IsNull() ? theParent : anAssembly), aChildLabel, theDoc); |
| 843 | } |
| 844 | else if (aShapeTool->IsSimpleShape(aChildLabel)) |
| 845 | { |
| 846 | addShape((anAssembly.IsNull() ? theParent : anAssembly), aChildLabel, theDoc); |
| 847 | } |
| 848 | } |
| 849 | } |
| 850 | |
| 851 | |
| 852 | //======================================================================= |
| 853 | //function : ConvertDocument |
| 854 | //purpose : |
| 855 | //======================================================================= |
| 856 | void VrmlData_ShapeConvert::ConvertDocument(const Handle(TDocStd_Document) &theDoc) |
| 857 | { |
| 858 | Handle(XCAFDoc_ShapeTool) aShapeTool = XCAFDoc_DocumentTool::ShapeTool(theDoc->Main()); |
| 859 | |
| 860 | TDF_LabelSequence aFreeShapeLabels; |
| 861 | aShapeTool->GetFreeShapes(aFreeShapeLabels); |
| 862 | |
| 863 | Handle(VrmlData_Group) aGroup = 0L; |
| 864 | if (aFreeShapeLabels.Size() > 1) |
| 865 | { |
| 866 | aGroup = new VrmlData_Group(myScene, 0L); |
| 867 | myScene.AddNode(aGroup); |
| 868 | } |
| 869 | |
| 870 | for (TDF_LabelSequence::Iterator aRootIter(aFreeShapeLabels); aRootIter.More(); aRootIter.Next()) |
| 871 | { |
| 872 | const TDF_Label& aFreeShapeLabel = aRootIter.Value(); |
| 873 | if (aShapeTool->IsAssembly (aFreeShapeLabel)) |
| 874 | { |
| 875 | addAssembly (aGroup, aFreeShapeLabel, theDoc, Standard_True); |
| 876 | } |
| 877 | else if (aShapeTool->IsReference (aFreeShapeLabel)) |
| 878 | { |
| 879 | addInstance (aGroup, aFreeShapeLabel, theDoc); |
| 880 | } |
| 881 | else if (aShapeTool->IsSimpleShape (aFreeShapeLabel)) |
| 882 | { |
| 883 | addShape (aGroup, aFreeShapeLabel, theDoc); |
| 884 | } |
| 885 | } |
| 886 | } |
| 887 | |
| 888 | //======================================================================= |
| 889 | //function : makeMaterialFromStyle |
| 890 | //purpose : |
| 891 | //======================================================================= |
| 892 | Handle(VrmlData_Appearance) VrmlData_ShapeConvert::makeMaterialFromStyle (const XCAFPrs_Style& theStyle, |
| 893 | const TDF_Label& theAttribLab) const |
| 894 | { |
| 895 | const Quantity_ColorRGBA aColor = !theStyle.Material().IsNull() |
| 896 | ? theStyle.Material()->BaseColor() |
| 897 | : theStyle.GetColorSurfRGBA(); |
| 898 | |
| 899 | TCollection_AsciiString aNodeName = "_materialFace_"; |
| 900 | Handle(TDataStd_Name) aNameAttribute; |
| 901 | if (theAttribLab.FindAttribute(TDataStd_Name::GetID(), aNameAttribute)) |
| 902 | { |
| 903 | aNodeName.AssignCat(aNameAttribute->Get()); |
| 904 | Standard_Integer n = aNodeName.Search(" "); |
| 905 | if (n > 0) |
| 906 | { |
| 907 | aNodeName = aNodeName.SubString(1, n - 1); |
| 908 | } |
| 909 | } |
| 910 | else |
| 911 | { |
| 912 | NCollection_Vec3<Standard_Real> aColor_sRGB; |
| 913 | aColor.GetRGB().Values (aColor_sRGB.r(), aColor_sRGB.g(), aColor_sRGB.b(), Quantity_TOC_sRGB); |
| 914 | aNodeName.AssignCat(aColor_sRGB.r()); |
| 915 | aNodeName.AssignCat("_"); |
| 916 | aNodeName.AssignCat(aColor_sRGB.g()); |
| 917 | aNodeName.AssignCat("_"); |
| 918 | aNodeName.AssignCat(aColor_sRGB.b()); |
| 919 | } |
| 920 | |
| 921 | Handle(VrmlData_Appearance) anAppearance = Handle(VrmlData_Appearance)::DownCast(myScene.FindNode(aNodeName.ToCString())); |
| 922 | if (anAppearance.IsNull()) |
| 923 | { |
| 924 | Handle(VrmlData_Material) aMaterial = new VrmlData_Material (myScene, 0L); |
| 925 | aMaterial->SetDiffuseColor (aColor.GetRGB()); |
| 926 | myScene.AddNode (aMaterial, Standard_False); |
| 927 | anAppearance = new VrmlData_Appearance (myScene, aNodeName.ToCString()); |
| 928 | anAppearance->SetMaterial (aMaterial); |
| 929 | myScene.AddNode (anAppearance, Standard_False); |
| 930 | } |
| 931 | |
| 932 | return anAppearance; |
| 933 | } |