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