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