0024814: Avoid using explicit names of Handle classes
[occt.git] / src / VrmlData / VrmlData_ShapeConvert.cxx
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_Coordinate.hxx>
20 #include <VrmlData_IndexedFaceSet.hxx>
21 #include <VrmlData_IndexedLineSet.hxx>
22 #include <VrmlData_ShapeNode.hxx>
23 #include <BRepMesh_IncrementalMesh.hxx>
24 #include <BRep_Builder.hxx>
25 #include <BRep_Tool.hxx>
26 #include <Geom_Surface.hxx>
27 #include <NCollection_DataMap.hxx>
28 #include <Poly_Triangulation.hxx>
29 #include <Poly_Connect.hxx>
30 #include <Poly_PolygonOnTriangulation.hxx>
31 #include <Poly_Polygon3D.hxx>
32 #include <Precision.hxx>
33 #include <TColgp_Array1OfPnt2d.hxx>
34 #include <TopExp_Explorer.hxx>
35 #include <TopoDS.hxx>
36 #include <TopoDS_Edge.hxx>
37 #include <TopoDS_Face.hxx>
38 #include <TopoDS_Shape.hxx>
39 #include <TopoDS_Wire.hxx>
40 #include <GCPnts_TangentialDeflection.hxx>
41 #include <BRepAdaptor_Curve.hxx>
42 #include <TColStd_Array1OfReal.hxx>
43 #include <TColStd_HArray1OfReal.hxx>
44 #include <TShort_Array1OfShortReal.hxx>
45 #include <GeomLib.hxx>
46 #include <TShort_HArray1OfShortReal.hxx>
47
48 //=======================================================================
49 //function : IsEqual
50 //purpose  : for NCollection_DataMap interface
51 //=======================================================================
52
53 inline Standard_Boolean IsEqual (const TopoDS_Shape& one,
54                                  const TopoDS_Shape& two) 
55 {
56   return one == two;
57 }
58
59 //=======================================================================
60 //function : AddShape
61 //purpose  : 
62 //=======================================================================
63
64 void VrmlData_ShapeConvert::AddShape (const TopoDS_Shape& theShape,
65                                       const char *        theName)
66 {
67   ShapeData aData;/* = { - compilation problem on SUN 
68     TCollection_AsciiString(),
69     theShape,
70     NULL
71   };*/
72   aData.Shape = theShape;
73   aData.Node = NULL;
74
75   if (theName) {
76     char buf[2048], * optr = &buf[0];
77     char * eptr = &buf[sizeof(buf)-1];
78     for (const char * ptr = theName;; ptr++) {
79       char sym = *ptr;
80       if (sym == '\0' || sym == '\n' || sym == '\r') {
81         * optr = '\0';
82         break;
83       }
84       if (sym == '\"' || sym == '\\')
85         * optr = '/';
86       else if (sym == '.')
87         * optr = '_';
88       else
89         * optr = sym;
90       if (++optr >= eptr) {
91         *optr = '\0';
92         break;
93       }
94     }
95     aData.Name = buf;
96   }
97   myShapes.Append (aData);
98 }
99
100 //=======================================================================
101 //function : Convert
102 //purpose  : 
103 //=======================================================================
104
105 void VrmlData_ShapeConvert::Convert (const Standard_Boolean theExtractFaces,
106                                      const Standard_Boolean theExtractEdges,
107                                      const Standard_Real    theDeflection,
108                                      const Standard_Real    theDeflAngle)
109 {
110   const Standard_Real aDeflection =
111     theDeflection < 0.0001 ? 0.0001 : theDeflection;
112
113   Standard_Boolean Extract[2] = {theExtractFaces, theExtractEdges};
114   TopAbs_ShapeEnum ShapeType[2] = {TopAbs_FACE, TopAbs_EDGE};
115   Standard_Integer i;
116
117   const Handle(NCollection_IncAllocator) anAlloc = new NCollection_IncAllocator;
118
119   // Relocation map for converted shapes. We should distinguish both TShape
120   // and Orientation in this map.
121   NCollection_DataMap <TopoDS_Shape,Handle(VrmlData_Geometry)>
122     aRelMap (100, anAlloc);
123
124
125   NCollection_List<ShapeData>::Iterator anIter (myShapes);
126   for (; anIter.More(); anIter.Next()) {
127
128     ShapeData& aData = anIter.ChangeValue();
129     Handle(VrmlData_Group) aGroup =
130       new VrmlData_Group (myScene, aData.Name.ToCString());
131     myScene.AddNode (aGroup);
132
133     for(i = 0; i < 2; ++i) {
134
135       if(!Extract[i]) continue;
136
137       TopExp_Explorer anExp (aData.Shape, ShapeType[i]);
138       for (; anExp.More(); anExp.Next()) {
139         const TopoDS_Shape& aShape = anExp.Current();
140         TopLoc_Location aLoc;
141         Handle(VrmlData_Geometry) aTShapeNode;
142         const Standard_Boolean isReverse=(aShape.Orientation()==TopAbs_REVERSED); 
143
144         TopoDS_Shape aTestedShape;
145         aTestedShape.TShape (aShape.TShape());
146         aTestedShape.Orientation (isReverse ? TopAbs_REVERSED : TopAbs_FORWARD);
147         Standard_Boolean isTessellate (Standard_False);
148         switch (ShapeType[i]) {
149         case TopAbs_FACE:
150           {
151             const TopoDS_Face& aFace = TopoDS::Face (aShape);
152             if (aFace.IsNull() == Standard_False) {
153               Handle(Poly_Triangulation) aTri =
154                 BRep_Tool::Triangulation (aFace, aLoc);
155       
156               if (aRelMap.IsBound (aTestedShape)) {
157                 aTShapeNode = aRelMap(aTestedShape);
158                 break;
159               }
160
161               if (aTri.IsNull())
162                 isTessellate = Standard_True;
163               // Check the existing deflection
164               else if (aTri->Deflection() > aDeflection+ Precision::Confusion())
165                 isTessellate = Standard_True;
166               if (isTessellate) {
167                 // Triangulate the face by the standard OCC mesher
168                 BRepMesh_IncrementalMesh IM (aFace, aDeflection, Standard_False, theDeflAngle);
169                 aTri = BRep_Tool::Triangulation (aFace, aLoc);
170               }
171               if (aTri.IsNull() == Standard_False) {
172                 TopoDS_Shape aTestedShapeRev = aTestedShape;
173                 aTestedShapeRev.Orientation (isReverse ?
174                                              TopAbs_FORWARD : TopAbs_REVERSED);
175                 Handle(VrmlData_IndexedFaceSet) aFaceSetToReuse;
176                 if (aRelMap.IsBound (aTestedShapeRev))
177                   aFaceSetToReuse = Handle(VrmlData_IndexedFaceSet)::DownCast
178                     (aRelMap(aTestedShapeRev));
179
180                 Handle(VrmlData_Coordinate) aCoordToReuse;
181                 if (aFaceSetToReuse.IsNull() == Standard_False)
182                   aCoordToReuse = aFaceSetToReuse->Coordinates();
183
184                 aTShapeNode = triToIndexedFaceSet (aTri, aFace, aCoordToReuse);
185                 myScene.AddNode (aTShapeNode, Standard_False);
186                 // Bind the converted face
187                 aRelMap.Bind (aTestedShape, aTShapeNode);
188               }
189             }
190           }
191           break;
192         case TopAbs_WIRE:
193           {
194             const TopoDS_Wire& aWire = TopoDS::Wire (aShape);
195             if (aWire.IsNull() == Standard_False) {
196             }
197           }
198           break;
199        case TopAbs_EDGE:
200          {
201            const TopoDS_Edge& aEdge = TopoDS::Edge (aShape);
202             if (aEdge.IsNull() == Standard_False) {
203               Handle(Poly_Polygon3D) aPol = BRep_Tool::Polygon3D (aEdge, aLoc);
204               
205               if (aRelMap.IsBound (aTestedShape)) {
206                 aTShapeNode = aRelMap(aTestedShape);
207                 break;
208               }
209               // Check the presence of reversly oriented Edge. It can also be used
210               // because we do not distinguish the orientation for edges.
211               aTestedShape.Orientation (isReverse ?
212                                         TopAbs_FORWARD : TopAbs_REVERSED);
213               if (aRelMap.IsBound (aTestedShape)) {
214                 aTShapeNode = aRelMap(aTestedShape);
215                 break;
216               }
217               
218               if (aPol.IsNull())
219                 isTessellate = Standard_True;
220               // Check the existing deflection
221               else if (aPol->Deflection() > aDeflection+ Precision::Confusion()
222                        && BRep_Tool::IsGeometric(aEdge))
223                 isTessellate = Standard_True;
224               
225               if (isTessellate && BRep_Tool::IsGeometric(aEdge)) {
226                 //try to find PolygonOnTriangulation
227                 Handle(Poly_PolygonOnTriangulation) aPT;
228                 Handle(Poly_Triangulation) aT;
229                 TopLoc_Location aL;
230
231                 Standard_Boolean found = Standard_False;
232                 for(i = 1; ; i++) {
233                   
234                   BRep_Tool::PolygonOnTriangulation(aEdge, aPT, aT, aL, i);
235
236                   if(aPT.IsNull() || aT.IsNull()) break;
237
238                   if(aPT->Deflection() <= aDeflection + Precision::Confusion() &&
239                      aPT->HasParameters()) {
240                     found = Standard_True;
241                     break;
242                   }
243
244                 }
245                 
246                 if(found) {
247
248                   BRepAdaptor_Curve aCurve(aEdge);
249                   Handle(TColStd_HArray1OfReal) aPrs = aPT->Parameters();
250                   Standard_Integer nbNodes = aPT->NbNodes();
251                   TColgp_Array1OfPnt arrNodes(1, nbNodes);
252                   TColStd_Array1OfReal arrUVNodes(1, nbNodes);
253
254                   for(Standard_Integer j = 1; j <= nbNodes; j++) {
255                     arrUVNodes(j) = aPrs->Value(aPrs->Lower() + j - 1);
256                     arrNodes(j) = aCurve.Value(arrUVNodes(j));
257                   }
258                   aPol = new Poly_Polygon3D(arrNodes, arrUVNodes);
259                   aPol->Deflection (aPT->Deflection());
260                 }
261                 else{
262                   
263                   BRepAdaptor_Curve aCurve(aEdge);
264                   const Standard_Real aFirst = aCurve.FirstParameter();
265                   const Standard_Real aLast  = aCurve.LastParameter();
266                 
267                   GCPnts_TangentialDeflection TD (aCurve, aFirst, aLast,
268                                                   theDeflAngle, aDeflection, 2);
269                   const Standard_Integer nbNodes = TD.NbPoints();
270                 
271                   TColgp_Array1OfPnt arrNodes(1, nbNodes);
272                   TColStd_Array1OfReal arrUVNodes(1, nbNodes);
273                   for (Standard_Integer j = 1; j <= nbNodes; j++) {
274                     arrNodes(j) = TD.Value(j);
275                     arrUVNodes(j) = TD.Parameter(j);
276                   }
277                   aPol = new Poly_Polygon3D(arrNodes, arrUVNodes);
278                   aPol->Deflection (aDeflection);
279                 }
280                 
281                 BRep_Builder aBld;
282                 aBld.UpdateEdge (aEdge, aPol);
283               }
284               aTShapeNode = polToIndexedLineSet (aPol);
285               myScene.AddNode (aTShapeNode, Standard_False);
286               // Bind the converted face
287               aRelMap.Bind (aTestedShape, aTShapeNode);
288             }
289           }
290           break;
291         default:
292           break;
293         }
294         
295         if (aTShapeNode.IsNull() == Standard_False) {
296           const Handle(VrmlData_ShapeNode) aShapeNode =
297             new VrmlData_ShapeNode (myScene, 0L);
298           aShapeNode->SetAppearance (ShapeType[i] == TopAbs_FACE ?
299                                      defaultMaterialFace():defaultMaterialEdge());
300           myScene.AddNode (aShapeNode, Standard_False);
301           aShapeNode->SetGeometry (aTShapeNode);
302           if (aLoc.IsIdentity())
303             // Store the shape node directly into the main Group.
304             aGroup->AddNode (aShapeNode);
305           else {
306             // Create a Transform grouping node
307             Handle(VrmlData_Group) aTrans = new VrmlData_Group (myScene, 0L,
308                                                                 Standard_True);
309             gp_Trsf aTrsf (aLoc);
310             if (fabs(myScale - 1.) > Precision::Confusion()) {
311               const gp_XYZ aTransl = aTrsf.TranslationPart() * myScale;
312               aTrsf.SetTranslationPart (aTransl);
313             }
314             aTrans->SetTransform (aTrsf);
315             myScene.AddNode (aTrans, Standard_False);
316             aGroup->AddNode (aTrans);
317             
318             // Store the shape node under the transform.
319             aTrans->AddNode (aShapeNode);
320           }
321         }
322       }
323     }
324   }
325   myShapes.Clear();
326 }
327
328 //=======================================================================
329 //function : triToIndexedFaceSet
330 //purpose  : 
331 //=======================================================================
332
333 Handle(VrmlData_Geometry) VrmlData_ShapeConvert::triToIndexedFaceSet
334                                   (const Handle(Poly_Triangulation)&  theTri,
335                                    const TopoDS_Face&                theFace,
336                                    const Handle(VrmlData_Coordinate)& theCoord)
337 {
338   Standard_Integer i;
339   const Standard_Integer nNodes         (theTri->NbNodes());
340   const Standard_Integer nTriangles     (theTri->NbTriangles());
341   const TColgp_Array1OfPnt&    arrPolyNodes = theTri->Nodes();
342   const Poly_Array1OfTriangle& arrTriangles = theTri->Triangles();
343
344   const Handle(VrmlData_IndexedFaceSet) aFaceSet =
345     new VrmlData_IndexedFaceSet (myScene,
346                                  0L,                    // no name
347                                  Standard_True,         // IsCCW
348                                  Standard_False,        // IsSolid
349                                  Standard_False);       // IsConvex
350   const Handle(NCollection_IncAllocator)& anAlloc = myScene.Allocator();
351   const Standard_Boolean isReverse = (theFace.Orientation() == TopAbs_REVERSED);
352
353   // Create the array of triangles
354   const Standard_Integer ** arrPolygons = static_cast<const Standard_Integer **>
355     (anAlloc->Allocate (nTriangles * sizeof(const Standard_Integer *)));
356   aFaceSet->SetPolygons (nTriangles, arrPolygons);
357
358   // Store the triangles
359   for (i = 0; i < nTriangles; i++) {
360     Standard_Integer * aPolygon = static_cast<Standard_Integer *>
361       (anAlloc->Allocate (4*sizeof(Standard_Integer)));
362     aPolygon[0] = 3;
363     arrTriangles(i+1).Get (aPolygon[1],aPolygon[2],aPolygon[3]);
364     aPolygon[1]--;
365     if (isReverse) {
366       const Standard_Integer aTmp = aPolygon[2]-1;
367       aPolygon[2] = aPolygon[3]-1;
368       aPolygon[3] = aTmp;
369     } else {
370       aPolygon[2]--;
371       aPolygon[3]--;
372     }
373     arrPolygons[i] = aPolygon;
374   }
375
376   // Create the Coordinates node
377   if (theCoord.IsNull() == Standard_False)
378     aFaceSet->SetCoordinates (theCoord);
379   else {
380     gp_XYZ * arrNodes = static_cast <gp_XYZ *>
381       (anAlloc->Allocate (nNodes * sizeof(gp_XYZ)));
382     for  (i = 0; i < nNodes; i++)
383       arrNodes[i] = arrPolyNodes(i+1).XYZ() * myScale;
384
385     const Handle(VrmlData_Coordinate) aCoordNode =
386       new VrmlData_Coordinate (myScene, 0L, nNodes, arrNodes);
387     myScene.AddNode (aCoordNode, Standard_False);
388     aFaceSet->SetCoordinates (aCoordNode);
389   }
390
391   // Create the Normals node if theTri has normals
392   if(theTri->HasNormals()) {
393     gp_XYZ * arrVec = static_cast <gp_XYZ *>
394       (anAlloc->Allocate (nNodes * sizeof(gp_XYZ)));
395     const TShort_Array1OfShortReal& Norm = theTri->Normals();
396     Standard_Integer j;
397     for  (i = 0, j = 1; i < nNodes; i++, j += 3) {
398       
399       gp_XYZ aNormal(Norm(j), Norm(j+1), Norm(j+2));
400       arrVec[i] = aNormal;
401
402     }
403     const Handle(VrmlData_Normal) aNormalNode =
404       new VrmlData_Normal (myScene, 0L, nNodes, arrVec);
405     myScene.AddNode (aNormalNode, Standard_False);
406     aFaceSet->SetNormals (aNormalNode);
407     return aFaceSet;
408   }
409
410   Poly_Connect PC(theTri);
411   // Create the Normals node (if UV- values are available)
412   TopLoc_Location aLoc;
413   const Standard_Real aConf2 = Precision::SquareConfusion();
414   const Handle(Geom_Surface) aSurface = BRep_Tool::Surface (theFace, aLoc);
415   if (theTri->HasUVNodes() && aSurface.IsNull() == Standard_False) {
416     if (aSurface->IsCNu(1) && aSurface->IsCNv(1))
417     {
418       Standard_Integer nbNormVal  = nNodes * 3; 
419       Handle(TShort_HArray1OfShortReal) Normals = 
420         new TShort_HArray1OfShortReal(1, nbNormVal);
421
422       const TColgp_Array1OfPnt2d& arrUV = theTri->UVNodes();
423       gp_XYZ * arrVec = static_cast <gp_XYZ *>
424         (anAlloc->Allocate (nNodes * sizeof(gp_XYZ)));
425
426       // Compute the normal vectors
427       Standard_Real Tol = Sqrt(aConf2);
428       for  (i = 0; i < nNodes; i++) {
429         const gp_Pnt2d& aUV = arrUV(i+1);
430         
431         gp_Dir aNormal;
432         
433         if (GeomLib::NormEstim(aSurface, aUV, Tol, aNormal) > 1) {
434           //Try to estimate as middle normal of adjacent triangles
435           Standard_Integer n[3];
436
437           gp_XYZ eqPlan(0., 0., 0.);
438           for (PC.Initialize(i+1);  PC.More(); PC.Next()) {
439             arrTriangles(PC.Value()).Get(n[0], n[1], n[2]);
440             gp_XYZ v1(arrPolyNodes(n[1]).Coord()-arrPolyNodes(n[0]).Coord());
441             gp_XYZ v2(arrPolyNodes(n[2]).Coord()-arrPolyNodes(n[1]).Coord());
442             gp_XYZ vv = v1^v2;
443
444             Standard_Real mod = vv.Modulus();
445             if (mod < Tol)
446               continue;
447
448             eqPlan += vv/mod;
449           }
450
451           if (eqPlan.SquareModulus() > gp::Resolution())
452             aNormal = gp_Dir(eqPlan);
453         }
454         if (isReverse)
455           aNormal.Reverse();
456
457         if (aNormal.X()*aNormal.X() < aConf2)
458           aNormal.SetX(0.);
459         if (aNormal.Y()*aNormal.Y() < aConf2)
460           aNormal.SetY(0.);
461         if (aNormal.Z()*aNormal.Z() < aConf2)
462           aNormal.SetZ(0.);
463         arrVec[i] = aNormal.XYZ();
464
465         Standard_Integer j = i * 3;
466         Normals->SetValue(j + 1, (Standard_ShortReal)aNormal.X());
467         Normals->SetValue(j + 2, (Standard_ShortReal)aNormal.Y());
468         Normals->SetValue(j + 3, (Standard_ShortReal)aNormal.Z());
469
470       }
471
472       theTri->SetNormals(Normals);  
473   
474       const Handle(VrmlData_Normal) aNormalNode =
475         new VrmlData_Normal (myScene, 0L, nNodes, arrVec);
476       myScene.AddNode (aNormalNode, Standard_False);
477       aFaceSet->SetNormals (aNormalNode);
478     }
479   }
480
481   return aFaceSet;
482 }
483
484 //=======================================================================
485 //function : polToIndexedLineSet
486 //purpose  : single polygon3D => IndexedLineSet
487 //=======================================================================
488
489 Handle(VrmlData_Geometry) VrmlData_ShapeConvert::polToIndexedLineSet
490                                         (const Handle(Poly_Polygon3D)& thePol)
491 {
492   Standard_Integer i;
493   const Standard_Integer    nNodes (thePol->NbNodes());
494   const TColgp_Array1OfPnt& arrPolyNodes = thePol->Nodes();
495   const Handle(NCollection_IncAllocator)& anAlloc = myScene.Allocator();
496
497   const Handle(VrmlData_IndexedLineSet) aLineSet =
498     new VrmlData_IndexedLineSet (myScene, 0L);
499
500   // Create the array of polygons (1 member)
501   const Standard_Integer ** arrPolygons = static_cast<const Standard_Integer **>
502     (anAlloc->Allocate (sizeof(const Standard_Integer *)));
503   aLineSet->SetPolygons (1, arrPolygons);
504
505   // Store the polygon
506   Standard_Integer * aPolygon = static_cast<Standard_Integer *>
507     (anAlloc->Allocate ((nNodes+1)*sizeof(Standard_Integer)));
508   aPolygon[0] = nNodes;
509   for (i = 1; i <= nNodes; i++)
510     aPolygon[i] = i-1;
511   arrPolygons[0] = aPolygon;
512
513   // Create the Coordinates node
514   gp_XYZ * arrNodes = static_cast <gp_XYZ *>
515     (anAlloc->Allocate (nNodes * sizeof(gp_XYZ)));
516   for  (i = 0; i < nNodes; i++)
517     arrNodes[i] = arrPolyNodes(i+1).XYZ() * myScale;
518
519   const Handle(VrmlData_Coordinate) aCoordNode =
520     new VrmlData_Coordinate (myScene, 0L, nNodes, arrNodes);
521   myScene.AddNode (aCoordNode, Standard_False);
522   aLineSet->SetCoordinates (aCoordNode);
523
524   return aLineSet;
525 }
526
527 //=======================================================================
528 //function : defaultMaterialFace
529 //purpose  : 
530 //=======================================================================
531
532 Handle(VrmlData_Appearance) VrmlData_ShapeConvert::defaultMaterialFace () const
533 {
534   static char aNodeName[] = "__defaultMaterialFace";
535   Handle(VrmlData_Appearance) anAppearance =
536     Handle(VrmlData_Appearance)::DownCast(myScene.FindNode(aNodeName));
537   if (anAppearance.IsNull()) {
538     const Handle(VrmlData_Material) aMaterial =
539       new VrmlData_Material (myScene, 0L, 1.0, 0.022, 0.);
540     aMaterial->SetDiffuseColor (Quantity_Color(0.780392, 0.568627, 0.113725,
541                                                Quantity_TOC_RGB));
542     aMaterial->SetEmissiveColor(Quantity_Color(0.329412, 0.223529, 0.027451,
543                                                Quantity_TOC_RGB));
544     aMaterial->SetSpecularColor(Quantity_Color(0.992157, 0.941176, 0.807843,
545                                                Quantity_TOC_RGB));
546     myScene.AddNode (aMaterial, Standard_False);
547     anAppearance = new VrmlData_Appearance (myScene, aNodeName);
548     anAppearance->SetMaterial (aMaterial);
549     myScene.AddNode (anAppearance, Standard_False);
550   }
551   return anAppearance;
552 }
553
554 //=======================================================================
555 //function : defaultMaterialEdge
556 //purpose  : 
557 //=======================================================================
558
559 Handle(VrmlData_Appearance) VrmlData_ShapeConvert::defaultMaterialEdge () const
560 {
561   static char aNodeName[] = "__defaultMaterialEdge";
562   Handle(VrmlData_Appearance) anAppearance =
563     Handle(VrmlData_Appearance)::DownCast(myScene.FindNode(aNodeName));
564   if (anAppearance.IsNull()) { 
565     const Handle(VrmlData_Material) aMaterial =
566       new VrmlData_Material (myScene, 0L, 0.2, 0.2, 0.2);
567     aMaterial->SetDiffuseColor (Quantity_Color(0.2, 0.7, 0.2,
568                                                Quantity_TOC_RGB));
569     aMaterial->SetEmissiveColor(Quantity_Color(0.2, 0.7, 0.2,
570                                                Quantity_TOC_RGB));
571     aMaterial->SetSpecularColor(Quantity_Color(0.2, 0.7, 0.2,
572                                                Quantity_TOC_RGB));
573     myScene.AddNode (aMaterial, Standard_False);
574     anAppearance = new VrmlData_Appearance (myScene, aNodeName);
575     anAppearance->SetMaterial (aMaterial);
576     myScene.AddNode (anAppearance, Standard_False);
577   }
578   return anAppearance;
579 }