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