0030221: Data Exchange - VRML is exported with inversed normals
[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       if (isReverse)
403       {
404         aNormal.Reverse();
405       }
406       arrVec[i] = aNormal;
407     }
408     const Handle(VrmlData_Normal) aNormalNode =
409       new VrmlData_Normal (myScene, 0L, nNodes, arrVec);
410     myScene.AddNode (aNormalNode, Standard_False);
411     aFaceSet->SetNormals (aNormalNode);
412     return Handle(VrmlData_Geometry) (aFaceSet);
413   }
414
415   Poly_Connect PC(theTri);
416   // Create the Normals node (if UV- values are available)
417   TopLoc_Location aLoc;
418   const Standard_Real aConf2 = Precision::SquareConfusion();
419   const Handle(Geom_Surface) aSurface = BRep_Tool::Surface (theFace, aLoc);
420   if (theTri->HasUVNodes() && aSurface.IsNull() == Standard_False) {
421     if (aSurface->IsCNu(1) && aSurface->IsCNv(1))
422     {
423       Standard_Integer nbNormVal  = nNodes * 3; 
424       Handle(TShort_HArray1OfShortReal) Normals = 
425         new TShort_HArray1OfShortReal(1, nbNormVal);
426
427       const TColgp_Array1OfPnt2d& arrUV = theTri->UVNodes();
428       gp_XYZ * arrVec = static_cast <gp_XYZ *>
429         (anAlloc->Allocate (nNodes * sizeof(gp_XYZ)));
430
431       // Compute the normal vectors
432       Standard_Real Tol = Sqrt(aConf2);
433       for  (i = 0; i < nNodes; i++) {
434         const gp_Pnt2d& aUV = arrUV(i+1);
435         
436         gp_Dir aNormal;
437         
438         if (GeomLib::NormEstim(aSurface, aUV, Tol, aNormal) > 1) {
439           //Try to estimate as middle normal of adjacent triangles
440           Standard_Integer n[3];
441
442           gp_XYZ eqPlan(0., 0., 0.);
443           for (PC.Initialize(i+1);  PC.More(); PC.Next()) {
444             aTriangles(PC.Value()).Get(n[0], n[1], n[2]);
445             gp_XYZ v1(arrPolyNodes(n[1]).Coord()-arrPolyNodes(n[0]).Coord());
446             gp_XYZ v2(arrPolyNodes(n[2]).Coord()-arrPolyNodes(n[1]).Coord());
447             gp_XYZ vv = v1^v2;
448
449             Standard_Real mod = vv.Modulus();
450             if (mod < Tol)
451               continue;
452
453             eqPlan += vv/mod;
454           }
455
456           if (eqPlan.SquareModulus() > gp::Resolution())
457             aNormal = gp_Dir(eqPlan);
458         }
459         if (isReverse)
460           aNormal.Reverse();
461
462         if (aNormal.X()*aNormal.X() < aConf2)
463           aNormal.SetX(0.);
464         if (aNormal.Y()*aNormal.Y() < aConf2)
465           aNormal.SetY(0.);
466         if (aNormal.Z()*aNormal.Z() < aConf2)
467           aNormal.SetZ(0.);
468         arrVec[i] = aNormal.XYZ();
469
470         Standard_Integer j = i * 3;
471         Normals->SetValue(j + 1, (Standard_ShortReal)aNormal.X());
472         Normals->SetValue(j + 2, (Standard_ShortReal)aNormal.Y());
473         Normals->SetValue(j + 3, (Standard_ShortReal)aNormal.Z());
474
475       }
476
477       theTri->SetNormals(Normals);  
478   
479       const Handle(VrmlData_Normal) aNormalNode =
480         new VrmlData_Normal (myScene, 0L, nNodes, arrVec);
481       myScene.AddNode (aNormalNode, Standard_False);
482       aFaceSet->SetNormals (aNormalNode);
483     }
484   }
485
486   return Handle(VrmlData_Geometry) (aFaceSet);
487 }
488
489 //=======================================================================
490 //function : polToIndexedLineSet
491 //purpose  : single polygon3D => IndexedLineSet
492 //=======================================================================
493
494 Handle(VrmlData_Geometry) VrmlData_ShapeConvert::polToIndexedLineSet
495                                         (const Handle(Poly_Polygon3D)& thePol)
496 {
497   Standard_Integer i;
498   const Standard_Integer    nNodes (thePol->NbNodes());
499   const TColgp_Array1OfPnt& arrPolyNodes = thePol->Nodes();
500   const Handle(NCollection_IncAllocator)& anAlloc = myScene.Allocator();
501
502   const Handle(VrmlData_IndexedLineSet) aLineSet =
503     new VrmlData_IndexedLineSet (myScene, 0L);
504
505   // Create the array of polygons (1 member)
506   const Standard_Integer ** arrPolygons = static_cast<const Standard_Integer **>
507     (anAlloc->Allocate (sizeof(const Standard_Integer *)));
508   aLineSet->SetPolygons (1, arrPolygons);
509
510   // Store the polygon
511   Standard_Integer * aPolygon = static_cast<Standard_Integer *>
512     (anAlloc->Allocate ((nNodes+1)*sizeof(Standard_Integer)));
513   aPolygon[0] = nNodes;
514   for (i = 1; i <= nNodes; i++)
515     aPolygon[i] = i-1;
516   arrPolygons[0] = aPolygon;
517
518   // Create the Coordinates node
519   gp_XYZ * arrNodes = static_cast <gp_XYZ *>
520     (anAlloc->Allocate (nNodes * sizeof(gp_XYZ)));
521   for  (i = 0; i < nNodes; i++)
522     arrNodes[i] = arrPolyNodes(i+1).XYZ() * myScale;
523
524   const Handle(VrmlData_Coordinate) aCoordNode =
525     new VrmlData_Coordinate (myScene, 0L, nNodes, arrNodes);
526   myScene.AddNode (aCoordNode, Standard_False);
527   aLineSet->SetCoordinates (aCoordNode);
528
529   return Handle(VrmlData_Geometry) (aLineSet);
530 }
531
532 //=======================================================================
533 //function : defaultMaterialFace
534 //purpose  : 
535 //=======================================================================
536
537 Handle(VrmlData_Appearance) VrmlData_ShapeConvert::defaultMaterialFace () const
538 {
539   static char aNodeName[] = "__defaultMaterialFace";
540   Handle(VrmlData_Appearance) anAppearance =
541     Handle(VrmlData_Appearance)::DownCast(myScene.FindNode(aNodeName));
542   if (anAppearance.IsNull()) {
543     const Handle(VrmlData_Material) aMaterial =
544       new VrmlData_Material (myScene, 0L, 1.0, 0.022, 0.);
545     aMaterial->SetDiffuseColor (Quantity_Color(0.780392, 0.568627, 0.113725,
546                                                Quantity_TOC_RGB));
547     aMaterial->SetEmissiveColor(Quantity_Color(0.329412, 0.223529, 0.027451,
548                                                Quantity_TOC_RGB));
549     aMaterial->SetSpecularColor(Quantity_Color(0.992157, 0.941176, 0.807843,
550                                                Quantity_TOC_RGB));
551     myScene.AddNode (aMaterial, Standard_False);
552     anAppearance = new VrmlData_Appearance (myScene, aNodeName);
553     anAppearance->SetMaterial (aMaterial);
554     myScene.AddNode (anAppearance, Standard_False);
555   }
556   return anAppearance;
557 }
558
559 //=======================================================================
560 //function : defaultMaterialEdge
561 //purpose  : 
562 //=======================================================================
563
564 Handle(VrmlData_Appearance) VrmlData_ShapeConvert::defaultMaterialEdge () const
565 {
566   static char aNodeName[] = "__defaultMaterialEdge";
567   Handle(VrmlData_Appearance) anAppearance =
568     Handle(VrmlData_Appearance)::DownCast(myScene.FindNode(aNodeName));
569   if (anAppearance.IsNull()) { 
570     const Handle(VrmlData_Material) aMaterial =
571       new VrmlData_Material (myScene, 0L, 0.2, 0.2, 0.2);
572     aMaterial->SetDiffuseColor (Quantity_Color(0.2, 0.7, 0.2,
573                                                Quantity_TOC_RGB));
574     aMaterial->SetEmissiveColor(Quantity_Color(0.2, 0.7, 0.2,
575                                                Quantity_TOC_RGB));
576     aMaterial->SetSpecularColor(Quantity_Color(0.2, 0.7, 0.2,
577                                                Quantity_TOC_RGB));
578     myScene.AddNode (aMaterial, Standard_False);
579     anAppearance = new VrmlData_Appearance (myScene, aNodeName);
580     anAppearance->SetMaterial (aMaterial);
581     myScene.AddNode (anAppearance, Standard_False);
582   }
583   return anAppearance;
584 }
585
586
587 //=======================================================================
588 //function : addShape
589 //purpose  : Adds the shape from the document
590 //=======================================================================
591 void VrmlData_ShapeConvert::addShape (const Handle(VrmlData_Group)& theParent,
592                                       const TDF_Label& theLabel,
593                                       const Handle(TDocStd_Document)& theDoc)
594 {
595   Handle(XCAFDoc_ShapeTool) aShapeTool = XCAFDoc_DocumentTool::ShapeTool(theDoc->Main());
596   Handle(XCAFDoc_ColorTool) aColorTool = XCAFDoc_DocumentTool::ColorTool(theDoc->Main());
597
598   NCollection_DataMap<TopoDS_Shape, TDF_Label> aChildShapeToLabels;
599   TDF_LabelSequence aChildLabels;
600   aShapeTool->GetSubShapes(theLabel, aChildLabels);
601   for (TDF_LabelSequence::Iterator aChildIter(aChildLabels); aChildIter.More(); aChildIter.Next())
602   {
603     const TDF_Label& aChildLabel = aChildIter.Value();
604     TopoDS_Shape aChildShape;
605     if (aShapeTool->GetShape(aChildLabel, aChildShape))
606     {
607       aChildShapeToLabels.Bind(aChildShape, aChildLabel);
608     }
609   }
610
611   const TopoDS_Shape aShape = aShapeTool->GetShape(theLabel);
612   Handle(VrmlData_Group) aGroup = 0L;
613   TopExp_Explorer anExp(aShape, TopAbs_FACE);
614   Standard_Integer nbFaces = 0;
615   for (; anExp.More(); anExp.Next()) {
616     nbFaces++;
617   }
618   Handle(TDataStd_Name) aNameAttribute;
619   theLabel.FindAttribute(TDataStd_Name::GetID(), aNameAttribute);
620   if (nbFaces > 1)
621   {
622     if (!aNameAttribute.IsNull())
623     {
624       TCollection_AsciiString aName = aNameAttribute->Get();
625       aGroup = new VrmlData_Group(myScene, aName.ToCString());
626     }
627     else
628     {
629       aGroup = new VrmlData_Group(myScene, 0L);
630     }
631     myScene.AddNode(aGroup, theParent.IsNull());
632     if (!theParent.IsNull())
633     {
634       theParent->AddNode(aGroup);
635     }
636   }
637
638   anExp.Init(aShape, TopAbs_FACE);
639   for (; anExp.More(); anExp.Next()) {
640     TopLoc_Location aLoc;
641     Handle(VrmlData_Geometry) aTShapeNode =
642       makeTShapeNode(anExp.Current(), TopAbs_FACE, aLoc);
643     if (!aTShapeNode.IsNull())
644     {
645       Handle(VrmlData_ShapeNode) aShapeNode = 0L;
646       if (aGroup.IsNull() && !aNameAttribute.IsNull())
647       {
648         TCollection_AsciiString aName = aNameAttribute->Get();
649         aName.ChangeAll(' ', '_');
650         aShapeNode = new VrmlData_ShapeNode(myScene, aName.ToCString());
651       }
652       else
653       {
654         aShapeNode = new VrmlData_ShapeNode(myScene, 0L);
655       }
656
657       // set color
658       TDF_Label aColorL;
659       Standard_Boolean findColor = Standard_False;
660       const TDF_Label* aLabel = aChildShapeToLabels.Seek(anExp.Current());
661       if (aLabel != NULL)
662       {
663         findColor = aColorTool->GetColor(*aLabel, XCAFDoc_ColorSurf, aColorL)
664           || aColorTool->GetColor(*aLabel, XCAFDoc_ColorGen, aColorL);
665       }
666       if (!findColor)
667       {
668         findColor = aColorTool->GetColor(theLabel, XCAFDoc_ColorSurf, aColorL)
669           || aColorTool->GetColor(theLabel, XCAFDoc_ColorGen, aColorL);
670       }
671       if (!findColor)
672       {
673         aShapeNode->SetAppearance(defaultMaterialFace());
674       }
675       else
676       {
677         aShapeNode->SetAppearance(makeMaterialFromColor(aColorL, aColorTool));
678       }
679
680       myScene.AddNode(aShapeNode, Standard_False);
681       aShapeNode->SetGeometry(aTShapeNode);
682       if (aLoc.IsIdentity())
683       {
684         // Store the shape node directly into the main Group.
685         if (!aGroup.IsNull())
686         {
687           aGroup->AddNode(aShapeNode);
688         }
689         else
690         {
691           theParent->AddNode(aShapeNode);
692         }
693       }
694       else
695       {
696         // Create a Transform grouping node
697         Handle(VrmlData_Group) aTrans = new VrmlData_Group(myScene, 0L,
698           Standard_True);
699         gp_Trsf aTrsf(aLoc);
700         if (fabs(myScale - 1.) > Precision::Confusion())
701         {
702           aTrsf.SetScaleFactor(myScale);
703         }
704         aTrans->SetTransform(aTrsf);
705         myScene.AddNode(aTrans, Standard_False);
706         if (!aGroup.IsNull())
707         {
708           aGroup->AddNode(aTrans);
709         }
710         else
711         {
712           theParent->AddNode(aTrans);
713         }
714         // Store the shape node under the transform.
715         aTrans->AddNode(aShapeNode);
716       }
717     }
718   }
719 }
720
721
722 //=======================================================================
723 //function : addInstance
724 //purpose  : Adds the reference from the document
725 //=======================================================================
726 void VrmlData_ShapeConvert::addInstance (const Handle(VrmlData_Group)& theParent,
727                                          const TDF_Label& theLabel,
728                                          const Handle(TDocStd_Document)& theDoc)
729 {
730   Handle(XCAFDoc_ShapeTool) aShapeTool = XCAFDoc_DocumentTool::ShapeTool(theDoc->Main());
731
732   const TopLoc_Location aLoc = aShapeTool->GetLocation(theLabel);
733   Handle(VrmlData_Group) aTrans = 0L;
734   if (!aLoc.IsIdentity())
735   {
736     // Create a Transform grouping node
737     aTrans = new VrmlData_Group(myScene, 0L, Standard_True);
738     gp_Trsf aTrsf(aLoc);
739     if (fabs(myScale - 1.) > Precision::Confusion()) {
740       aTrsf.SetScaleFactor(myScale);
741     }
742     aTrans->SetTransform(aTrsf);
743     myScene.AddNode(aTrans, theParent.IsNull());
744     if (!theParent.IsNull())
745     {
746       theParent->AddNode(aTrans);
747     }
748   }
749
750   Handle(TDataStd_Name) aNameAttribute;
751   theLabel.FindAttribute(TDataStd_Name::GetID(), aNameAttribute);
752
753   TDF_Label aRefLabel;
754   aShapeTool->GetReferredShape(theLabel, aRefLabel);
755   Handle(TDataStd_Name) aRefNameAttribute;
756   aRefLabel.FindAttribute(TDataStd_Name::GetID(), aRefNameAttribute);
757
758   if (aShapeTool->IsSimpleShape(aRefLabel))
759   {
760     addShape((aTrans.IsNull() ? theParent : aTrans), aRefLabel, theDoc);
761   }
762   else if (aShapeTool->IsAssembly(aRefLabel))
763   {
764     addAssembly((aTrans.IsNull() ? theParent : aTrans), aRefLabel, theDoc, aTrans.IsNull());
765   }
766 }
767
768
769 //=======================================================================
770 //function : addAssembly
771 //purpose  : Adds the assembly from the document
772 //=======================================================================
773 void VrmlData_ShapeConvert::addAssembly (const Handle(VrmlData_Group)& theParent,
774                                          const TDF_Label& theLabel,
775                                          const Handle(TDocStd_Document)& theDoc,
776                                          const Standard_Boolean theNeedCreateGroup)
777 {
778   Handle(XCAFDoc_ShapeTool) aShapeTool = XCAFDoc_DocumentTool::ShapeTool(theDoc->Main());
779
780   Handle(VrmlData_Group) anAssembly = 0L;
781   if (theNeedCreateGroup)
782   {
783     Handle(TDataStd_Name) aNameAttribute;
784     theLabel.FindAttribute(TDataStd_Name::GetID(), aNameAttribute);
785     if (!aNameAttribute.IsNull())
786     {
787       TCollection_AsciiString aName = aNameAttribute->Get();
788       anAssembly = new VrmlData_Group(myScene, aName.ToCString());
789     }
790     else
791     {
792       anAssembly = new VrmlData_Group(myScene, 0L);
793     }
794     TopLoc_Location aLoc = aShapeTool->GetLocation(theLabel);
795     if (!aLoc.IsIdentity())
796     {
797       gp_Trsf aTrsf(aLoc);
798       if (fabs(myScale - 1.) > Precision::Confusion()) {
799         const gp_XYZ aTransl = aTrsf.TranslationPart() * myScale;
800         aTrsf.SetTranslationPart(aTransl);
801       }
802       anAssembly->SetTransform(aTrsf);
803     }
804     myScene.AddNode(anAssembly, theParent.IsNull());
805     if (!theParent.IsNull())
806     {
807       theParent->AddNode(anAssembly);
808     }
809   }
810
811   TDF_LabelSequence aChildLabels;
812   aShapeTool->GetComponents(theLabel, aChildLabels);
813   for (TDF_LabelSequence::Iterator aChildIter(aChildLabels); aChildIter.More(); aChildIter.Next())
814   {
815     const TDF_Label& aChildLabel = aChildIter.Value();
816     if (aShapeTool->IsAssembly(aChildLabel))
817     {
818       addAssembly((anAssembly.IsNull() ? theParent : anAssembly), aChildLabel, theDoc, anAssembly.IsNull());
819     }
820     else if (aShapeTool->IsReference(aChildLabel))
821     {
822       addInstance((anAssembly.IsNull() ? theParent : anAssembly), aChildLabel, theDoc);
823     }
824     else if (aShapeTool->IsSimpleShape(aChildLabel))
825     {
826       addShape((anAssembly.IsNull() ? theParent : anAssembly), aChildLabel, theDoc);
827     }
828   }
829 }
830
831
832 //=======================================================================
833 //function : ConvertDocument
834 //purpose  : 
835 //=======================================================================
836 void VrmlData_ShapeConvert::ConvertDocument(const Handle(TDocStd_Document) &theDoc)
837 {
838   Handle(XCAFDoc_ShapeTool) aShapeTool = XCAFDoc_DocumentTool::ShapeTool(theDoc->Main());
839
840   TDF_LabelSequence aFreeShapeLabels;
841   aShapeTool->GetFreeShapes(aFreeShapeLabels);
842
843   Handle(VrmlData_Group) aGroup = 0L;
844   if (aFreeShapeLabels.Size() > 1)
845   {
846     aGroup = new VrmlData_Group(myScene, 0L);
847     myScene.AddNode(aGroup);
848   }
849
850   for (TDF_LabelSequence::Iterator aRootIter(aFreeShapeLabels); aRootIter.More(); aRootIter.Next())
851   {
852     const TDF_Label& aFreeShapeLabel = aRootIter.Value();
853     if (aShapeTool->IsSimpleShape(aFreeShapeLabel))
854     {
855       addShape(aGroup, aFreeShapeLabel, theDoc);
856     }
857     else if (aShapeTool->IsAssembly(aFreeShapeLabel))
858     {
859       addAssembly(aGroup, aFreeShapeLabel, theDoc, Standard_True);
860     }
861   }
862 }
863
864
865 //=======================================================================
866 //function : makeMaterialFromColor
867 //purpose  : 
868 //=======================================================================
869
870 Handle(VrmlData_Appearance) VrmlData_ShapeConvert::makeMaterialFromColor(
871   const TDF_Label& theColorL,
872   const Handle(XCAFDoc_ColorTool)& theColorTool) const
873 {
874   Quantity_ColorRGBA aColor;
875   theColorTool->GetColor(theColorL, aColor);
876
877   TCollection_AsciiString aNodeName = "_materialFace_";
878   Handle(TDataStd_Name) aNameAttribute;
879   if (theColorL.FindAttribute(TDataStd_Name::GetID(), aNameAttribute))
880   {
881     aNodeName.AssignCat(aNameAttribute->Get());
882     Standard_Integer n = aNodeName.Search(" ");
883     if (n > 0)
884     {
885       aNodeName = aNodeName.SubString(1, n - 1);
886     }
887   }
888   else
889   {
890     aNodeName.AssignCat(aColor.GetRGB().Red());
891     aNodeName.AssignCat("_");
892     aNodeName.AssignCat(aColor.GetRGB().Green());
893     aNodeName.AssignCat("_");
894     aNodeName.AssignCat(aColor.GetRGB().Blue());
895   }
896
897   Handle(VrmlData_Appearance) anAppearance =
898     Handle(VrmlData_Appearance)::DownCast(myScene.FindNode(aNodeName.ToCString()));
899   if (anAppearance.IsNull()) {
900     const Handle(VrmlData_Material) aMaterial =
901       new VrmlData_Material(myScene, 0L);
902     aMaterial->SetDiffuseColor(aColor.GetRGB());
903     myScene.AddNode(aMaterial, Standard_False);
904     anAppearance = new VrmlData_Appearance(myScene, aNodeName.ToCString());
905     anAppearance->SetMaterial(aMaterial);
906     myScene.AddNode(anAppearance, Standard_False);
907   }
908
909   return anAppearance;
910 }
911
912