1 // Created on: 2007-08-04
2 // Created by: Alexander GRIGORIEV
3 // Copyright (c) 2007-2014 OPEN CASCADE SAS
5 // This file is part of Open CASCADE Technology software library.
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.
13 // Alternatively, this file may be used under the terms of Open CASCADE
14 // commercial license or contractual agreement.
16 #include <VrmlData_ShapeConvert.hxx>
17 #include <VrmlData_Scene.hxx>
18 #include <VrmlData_Group.hxx>
19 #include <VrmlData_Coordinate.hxx>
20 #include <VrmlData_IndexedFaceSet.hxx>
21 #include <VrmlData_IndexedLineSet.hxx>
22 #include <VrmlData_ShapeNode.hxx>
23 #include <BRepMesh_IncrementalMesh.hxx>
24 #include <BRep_Builder.hxx>
25 #include <BRep_Tool.hxx>
26 #include <Geom_Surface.hxx>
27 #include <NCollection_DataMap.hxx>
28 #include <Poly_Triangulation.hxx>
29 #include <Poly_Connect.hxx>
30 #include <Poly_PolygonOnTriangulation.hxx>
31 #include <Poly_Polygon3D.hxx>
32 #include <Precision.hxx>
33 #include <TColgp_Array1OfPnt2d.hxx>
34 #include <TopExp_Explorer.hxx>
36 #include <TopoDS_Edge.hxx>
37 #include <TopoDS_Face.hxx>
38 #include <TopoDS_Shape.hxx>
39 #include <TopoDS_Wire.hxx>
40 #include <GCPnts_TangentialDeflection.hxx>
41 #include <BRepAdaptor_Curve.hxx>
42 #include <TColStd_Array1OfReal.hxx>
43 #include <TColStd_HArray1OfReal.hxx>
44 #include <TShort_Array1OfShortReal.hxx>
45 #include <GeomLib.hxx>
46 #include <TShort_HArray1OfShortReal.hxx>
47 #include <VrmlData_Appearance.hxx>
49 //=======================================================================
52 //=======================================================================
54 void VrmlData_ShapeConvert::AddShape (const TopoDS_Shape& theShape,
57 ShapeData aData;/* = { - compilation problem on SUN
58 TCollection_AsciiString(),
62 aData.Shape = theShape;
66 char buf[2048], * optr = &buf[0];
67 char * eptr = &buf[sizeof(buf)-1];
68 for (const char * ptr = theName;; ptr++) {
70 if (sym == '\0' || sym == '\n' || sym == '\r') {
74 if (sym == '\"' || sym == '\\')
87 myShapes.Append (aData);
90 //=======================================================================
93 //=======================================================================
95 void VrmlData_ShapeConvert::Convert (const Standard_Boolean theExtractFaces,
96 const Standard_Boolean theExtractEdges,
97 const Standard_Real theDeflection,
98 const Standard_Real theDeflAngle)
100 const Standard_Real aDeflection =
101 theDeflection < 0.0001 ? 0.0001 : theDeflection;
103 Standard_Boolean Extract[2] = {theExtractFaces, theExtractEdges};
104 TopAbs_ShapeEnum ShapeType[2] = {TopAbs_FACE, TopAbs_EDGE};
107 const Handle(NCollection_IncAllocator) anAlloc = new NCollection_IncAllocator;
109 // Relocation map for converted shapes. We should distinguish both TShape
110 // and Orientation in this map.
111 NCollection_DataMap <TopoDS_Shape,Handle(VrmlData_Geometry)>
112 aRelMap (100, anAlloc);
115 NCollection_List<ShapeData>::Iterator anIter (myShapes);
116 for (; anIter.More(); anIter.Next()) {
118 ShapeData& aData = anIter.ChangeValue();
119 Handle(VrmlData_Group) aGroup =
120 new VrmlData_Group (myScene, aData.Name.ToCString());
121 myScene.AddNode (aGroup);
123 for(i = 0; i < 2; ++i) {
125 if(!Extract[i]) continue;
127 TopExp_Explorer anExp (aData.Shape, ShapeType[i]);
128 for (; anExp.More(); anExp.Next()) {
129 const TopoDS_Shape& aShape = anExp.Current();
130 TopLoc_Location aLoc;
131 Handle(VrmlData_Geometry) aTShapeNode;
132 const Standard_Boolean isReverse=(aShape.Orientation()==TopAbs_REVERSED);
134 TopoDS_Shape aTestedShape;
135 aTestedShape.TShape (aShape.TShape());
136 aTestedShape.Orientation (isReverse ? TopAbs_REVERSED : TopAbs_FORWARD);
137 switch (ShapeType[i]) {
140 const TopoDS_Face& aFace = TopoDS::Face (aShape);
141 if (aFace.IsNull() == Standard_False) {
142 Handle(Poly_Triangulation) aTri =
143 BRep_Tool::Triangulation (aFace, aLoc);
145 if (aRelMap.IsBound (aTestedShape)) {
146 aTShapeNode = aRelMap(aTestedShape);
150 if (aTri.IsNull() == Standard_False) {
151 TopoDS_Shape aTestedShapeRev = aTestedShape;
152 aTestedShapeRev.Orientation (isReverse ?
153 TopAbs_FORWARD : TopAbs_REVERSED);
154 Handle(VrmlData_IndexedFaceSet) aFaceSetToReuse;
155 if (aRelMap.IsBound (aTestedShapeRev))
156 aFaceSetToReuse = Handle(VrmlData_IndexedFaceSet)::DownCast
157 (aRelMap(aTestedShapeRev));
159 Handle(VrmlData_Coordinate) aCoordToReuse;
160 if (aFaceSetToReuse.IsNull() == Standard_False)
161 aCoordToReuse = aFaceSetToReuse->Coordinates();
163 aTShapeNode = triToIndexedFaceSet (aTri, aFace, aCoordToReuse);
164 myScene.AddNode (aTShapeNode, Standard_False);
165 // Bind the converted face
166 aRelMap.Bind (aTestedShape, aTShapeNode);
173 const TopoDS_Wire& aWire = TopoDS::Wire (aShape);
174 if (aWire.IsNull() == Standard_False) {
180 const TopoDS_Edge& aEdge = TopoDS::Edge (aShape);
181 if (aEdge.IsNull() == Standard_False) {
182 if (aRelMap.IsBound (aTestedShape)) {
183 aTShapeNode = aRelMap(aTestedShape);
186 // Check the presence of reversly oriented Edge. It can also be used
187 // because we do not distinguish the orientation for edges.
188 aTestedShape.Orientation (isReverse ?
189 TopAbs_FORWARD : TopAbs_REVERSED);
190 if (aRelMap.IsBound (aTestedShape)) {
191 aTShapeNode = aRelMap(aTestedShape);
195 //try to find PolygonOnTriangulation
196 Handle(Poly_PolygonOnTriangulation) aPT;
197 Handle(Poly_Triangulation) aT;
199 BRep_Tool::PolygonOnTriangulation(aEdge, aPT, aT, aL);
201 // If PolygonOnTriangulation was found -> get the Polygon3D
202 Handle(Poly_Polygon3D) aPol;
203 if(!aPT.IsNull() && !aT.IsNull() && aPT->HasParameters()) {
204 BRepAdaptor_Curve aCurve(aEdge);
205 Handle(TColStd_HArray1OfReal) aPrs = aPT->Parameters();
206 Standard_Integer nbNodes = aPT->NbNodes();
207 TColgp_Array1OfPnt arrNodes(1, nbNodes);
208 TColStd_Array1OfReal arrUVNodes(1, nbNodes);
210 for(Standard_Integer j = 1; j <= nbNodes; j++) {
211 arrUVNodes(j) = aPrs->Value(aPrs->Lower() + j - 1);
212 arrNodes(j) = aCurve.Value(arrUVNodes(j));
214 aPol = new Poly_Polygon3D(arrNodes, arrUVNodes);
215 aPol->Deflection (aPT->Deflection());
218 aPol = BRep_Tool::Polygon3D(aEdge, aL);
220 // If polygon was not found -> generate it
222 BRepAdaptor_Curve aCurve(aEdge);
223 const Standard_Real aFirst = aCurve.FirstParameter();
224 const Standard_Real aLast = aCurve.LastParameter();
226 GCPnts_TangentialDeflection TD (aCurve, aFirst, aLast,
227 theDeflAngle, aDeflection, 2);
228 const Standard_Integer nbNodes = TD.NbPoints();
230 TColgp_Array1OfPnt arrNodes(1, nbNodes);
231 TColStd_Array1OfReal arrUVNodes(1, nbNodes);
232 for (Standard_Integer j = 1; j <= nbNodes; j++) {
233 arrNodes(j) = TD.Value(j);
234 arrUVNodes(j) = TD.Parameter(j);
236 aPol = new Poly_Polygon3D(arrNodes, arrUVNodes);
237 aPol->Deflection (aDeflection);
244 aTShapeNode = polToIndexedLineSet (aPol);
245 myScene.AddNode (aTShapeNode, Standard_False);
246 // Bind the converted face
247 aRelMap.Bind (aTestedShape, aTShapeNode);
255 if (aTShapeNode.IsNull() == Standard_False) {
256 const Handle(VrmlData_ShapeNode) aShapeNode =
257 new VrmlData_ShapeNode (myScene, 0L);
258 aShapeNode->SetAppearance (ShapeType[i] == TopAbs_FACE ?
259 defaultMaterialFace():defaultMaterialEdge());
260 myScene.AddNode (aShapeNode, Standard_False);
261 aShapeNode->SetGeometry (aTShapeNode);
262 if (aLoc.IsIdentity())
263 // Store the shape node directly into the main Group.
264 aGroup->AddNode (aShapeNode);
266 // Create a Transform grouping node
267 Handle(VrmlData_Group) aTrans = new VrmlData_Group (myScene, 0L,
269 gp_Trsf aTrsf (aLoc);
270 if (fabs(myScale - 1.) > Precision::Confusion()) {
271 const gp_XYZ aTransl = aTrsf.TranslationPart() * myScale;
272 aTrsf.SetTranslationPart (aTransl);
274 aTrans->SetTransform (aTrsf);
275 myScene.AddNode (aTrans, Standard_False);
276 aGroup->AddNode (aTrans);
278 // Store the shape node under the transform.
279 aTrans->AddNode (aShapeNode);
288 //=======================================================================
289 //function : triToIndexedFaceSet
291 //=======================================================================
293 Handle(VrmlData_Geometry) VrmlData_ShapeConvert::triToIndexedFaceSet
294 (const Handle(Poly_Triangulation)& theTri,
295 const TopoDS_Face& theFace,
296 const Handle(VrmlData_Coordinate)& theCoord)
299 const Standard_Integer nNodes (theTri->NbNodes());
300 const Standard_Integer nTriangles (theTri->NbTriangles());
301 const TColgp_Array1OfPnt& arrPolyNodes = theTri->Nodes();
302 const Poly_Array1OfTriangle& arrTriangles = theTri->Triangles();
304 const Handle(VrmlData_IndexedFaceSet) aFaceSet =
305 new VrmlData_IndexedFaceSet (myScene,
307 Standard_True, // IsCCW
308 Standard_False, // IsSolid
309 Standard_False); // IsConvex
310 const Handle(NCollection_IncAllocator)& anAlloc = myScene.Allocator();
311 const Standard_Boolean isReverse = (theFace.Orientation() == TopAbs_REVERSED);
313 // Create the array of triangles
314 const Standard_Integer ** arrPolygons = static_cast<const Standard_Integer **>
315 (anAlloc->Allocate (nTriangles * sizeof(const Standard_Integer *)));
316 aFaceSet->SetPolygons (nTriangles, arrPolygons);
318 // Store the triangles
319 for (i = 0; i < nTriangles; i++) {
320 Standard_Integer * aPolygon = static_cast<Standard_Integer *>
321 (anAlloc->Allocate (4*sizeof(Standard_Integer)));
323 arrTriangles(i+1).Get (aPolygon[1],aPolygon[2],aPolygon[3]);
326 const Standard_Integer aTmp = aPolygon[2]-1;
327 aPolygon[2] = aPolygon[3]-1;
333 arrPolygons[i] = aPolygon;
336 // Create the Coordinates node
337 if (theCoord.IsNull() == Standard_False)
338 aFaceSet->SetCoordinates (theCoord);
340 gp_XYZ * arrNodes = static_cast <gp_XYZ *>
341 (anAlloc->Allocate (nNodes * sizeof(gp_XYZ)));
342 for (i = 0; i < nNodes; i++)
343 arrNodes[i] = arrPolyNodes(i+1).XYZ() * myScale;
345 const Handle(VrmlData_Coordinate) aCoordNode =
346 new VrmlData_Coordinate (myScene, 0L, nNodes, arrNodes);
347 myScene.AddNode (aCoordNode, Standard_False);
348 aFaceSet->SetCoordinates (aCoordNode);
351 // Create the Normals node if theTri has normals
352 if(theTri->HasNormals()) {
353 gp_XYZ * arrVec = static_cast <gp_XYZ *>
354 (anAlloc->Allocate (nNodes * sizeof(gp_XYZ)));
355 const TShort_Array1OfShortReal& Norm = theTri->Normals();
357 for (i = 0, j = 1; i < nNodes; i++, j += 3) {
359 gp_XYZ aNormal(Norm(j), Norm(j+1), Norm(j+2));
363 const Handle(VrmlData_Normal) aNormalNode =
364 new VrmlData_Normal (myScene, 0L, nNodes, arrVec);
365 myScene.AddNode (aNormalNode, Standard_False);
366 aFaceSet->SetNormals (aNormalNode);
367 return Handle(VrmlData_Geometry) (aFaceSet);
370 Poly_Connect PC(theTri);
371 // Create the Normals node (if UV- values are available)
372 TopLoc_Location aLoc;
373 const Standard_Real aConf2 = Precision::SquareConfusion();
374 const Handle(Geom_Surface) aSurface = BRep_Tool::Surface (theFace, aLoc);
375 if (theTri->HasUVNodes() && aSurface.IsNull() == Standard_False) {
376 if (aSurface->IsCNu(1) && aSurface->IsCNv(1))
378 Standard_Integer nbNormVal = nNodes * 3;
379 Handle(TShort_HArray1OfShortReal) Normals =
380 new TShort_HArray1OfShortReal(1, nbNormVal);
382 const TColgp_Array1OfPnt2d& arrUV = theTri->UVNodes();
383 gp_XYZ * arrVec = static_cast <gp_XYZ *>
384 (anAlloc->Allocate (nNodes * sizeof(gp_XYZ)));
386 // Compute the normal vectors
387 Standard_Real Tol = Sqrt(aConf2);
388 for (i = 0; i < nNodes; i++) {
389 const gp_Pnt2d& aUV = arrUV(i+1);
393 if (GeomLib::NormEstim(aSurface, aUV, Tol, aNormal) > 1) {
394 //Try to estimate as middle normal of adjacent triangles
395 Standard_Integer n[3];
397 gp_XYZ eqPlan(0., 0., 0.);
398 for (PC.Initialize(i+1); PC.More(); PC.Next()) {
399 arrTriangles(PC.Value()).Get(n[0], n[1], n[2]);
400 gp_XYZ v1(arrPolyNodes(n[1]).Coord()-arrPolyNodes(n[0]).Coord());
401 gp_XYZ v2(arrPolyNodes(n[2]).Coord()-arrPolyNodes(n[1]).Coord());
404 Standard_Real mod = vv.Modulus();
411 if (eqPlan.SquareModulus() > gp::Resolution())
412 aNormal = gp_Dir(eqPlan);
417 if (aNormal.X()*aNormal.X() < aConf2)
419 if (aNormal.Y()*aNormal.Y() < aConf2)
421 if (aNormal.Z()*aNormal.Z() < aConf2)
423 arrVec[i] = aNormal.XYZ();
425 Standard_Integer j = i * 3;
426 Normals->SetValue(j + 1, (Standard_ShortReal)aNormal.X());
427 Normals->SetValue(j + 2, (Standard_ShortReal)aNormal.Y());
428 Normals->SetValue(j + 3, (Standard_ShortReal)aNormal.Z());
432 theTri->SetNormals(Normals);
434 const Handle(VrmlData_Normal) aNormalNode =
435 new VrmlData_Normal (myScene, 0L, nNodes, arrVec);
436 myScene.AddNode (aNormalNode, Standard_False);
437 aFaceSet->SetNormals (aNormalNode);
441 return Handle(VrmlData_Geometry) (aFaceSet);
444 //=======================================================================
445 //function : polToIndexedLineSet
446 //purpose : single polygon3D => IndexedLineSet
447 //=======================================================================
449 Handle(VrmlData_Geometry) VrmlData_ShapeConvert::polToIndexedLineSet
450 (const Handle(Poly_Polygon3D)& thePol)
453 const Standard_Integer nNodes (thePol->NbNodes());
454 const TColgp_Array1OfPnt& arrPolyNodes = thePol->Nodes();
455 const Handle(NCollection_IncAllocator)& anAlloc = myScene.Allocator();
457 const Handle(VrmlData_IndexedLineSet) aLineSet =
458 new VrmlData_IndexedLineSet (myScene, 0L);
460 // Create the array of polygons (1 member)
461 const Standard_Integer ** arrPolygons = static_cast<const Standard_Integer **>
462 (anAlloc->Allocate (sizeof(const Standard_Integer *)));
463 aLineSet->SetPolygons (1, arrPolygons);
466 Standard_Integer * aPolygon = static_cast<Standard_Integer *>
467 (anAlloc->Allocate ((nNodes+1)*sizeof(Standard_Integer)));
468 aPolygon[0] = nNodes;
469 for (i = 1; i <= nNodes; i++)
471 arrPolygons[0] = aPolygon;
473 // Create the Coordinates node
474 gp_XYZ * arrNodes = static_cast <gp_XYZ *>
475 (anAlloc->Allocate (nNodes * sizeof(gp_XYZ)));
476 for (i = 0; i < nNodes; i++)
477 arrNodes[i] = arrPolyNodes(i+1).XYZ() * myScale;
479 const Handle(VrmlData_Coordinate) aCoordNode =
480 new VrmlData_Coordinate (myScene, 0L, nNodes, arrNodes);
481 myScene.AddNode (aCoordNode, Standard_False);
482 aLineSet->SetCoordinates (aCoordNode);
484 return Handle(VrmlData_Geometry) (aLineSet);
487 //=======================================================================
488 //function : defaultMaterialFace
490 //=======================================================================
492 Handle(VrmlData_Appearance) VrmlData_ShapeConvert::defaultMaterialFace () const
494 static char aNodeName[] = "__defaultMaterialFace";
495 Handle(VrmlData_Appearance) anAppearance =
496 Handle(VrmlData_Appearance)::DownCast(myScene.FindNode(aNodeName));
497 if (anAppearance.IsNull()) {
498 const Handle(VrmlData_Material) aMaterial =
499 new VrmlData_Material (myScene, 0L, 1.0, 0.022, 0.);
500 aMaterial->SetDiffuseColor (Quantity_Color(0.780392, 0.568627, 0.113725,
502 aMaterial->SetEmissiveColor(Quantity_Color(0.329412, 0.223529, 0.027451,
504 aMaterial->SetSpecularColor(Quantity_Color(0.992157, 0.941176, 0.807843,
506 myScene.AddNode (aMaterial, Standard_False);
507 anAppearance = new VrmlData_Appearance (myScene, aNodeName);
508 anAppearance->SetMaterial (aMaterial);
509 myScene.AddNode (anAppearance, Standard_False);
514 //=======================================================================
515 //function : defaultMaterialEdge
517 //=======================================================================
519 Handle(VrmlData_Appearance) VrmlData_ShapeConvert::defaultMaterialEdge () const
521 static char aNodeName[] = "__defaultMaterialEdge";
522 Handle(VrmlData_Appearance) anAppearance =
523 Handle(VrmlData_Appearance)::DownCast(myScene.FindNode(aNodeName));
524 if (anAppearance.IsNull()) {
525 const Handle(VrmlData_Material) aMaterial =
526 new VrmlData_Material (myScene, 0L, 0.2, 0.2, 0.2);
527 aMaterial->SetDiffuseColor (Quantity_Color(0.2, 0.7, 0.2,
529 aMaterial->SetEmissiveColor(Quantity_Color(0.2, 0.7, 0.2,
531 aMaterial->SetSpecularColor(Quantity_Color(0.2, 0.7, 0.2,
533 myScene.AddNode (aMaterial, Standard_False);
534 anAppearance = new VrmlData_Appearance (myScene, aNodeName);
535 anAppearance->SetMaterial (aMaterial);
536 myScene.AddNode (anAppearance, Standard_False);