// Created on: 2007-08-04 // Created by: Alexander GRIGORIEV // Copyright (c) 2007-2012 OPEN CASCADE SAS // // The content of this file is subject to the Open CASCADE Technology Public // License Version 6.5 (the "License"). You may not use the content of this file // except in compliance with the License. Please obtain a copy of the License // at http://www.opencascade.org and read it completely before using this file. // // The Initial Developer of the Original Code is Open CASCADE S.A.S., having its // main offices at: 1, place des Freres Montgolfier, 78280 Guyancourt, France. // // The Original Code and all software distributed under the License is // distributed on an "AS IS" basis, without warranty of any kind, and the // Initial Developer hereby disclaims all such warranties, including without // limitation, any warranties of merchantability, fitness for a particular // purpose or non-infringement. Please see the License for the specific terms // and conditions governing the rights and limitations under the License. #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include //======================================================================= //function : IsEqual //purpose : for NCollection_DataMap interface //======================================================================= inline Standard_Boolean IsEqual (const TopoDS_Shape& one, const TopoDS_Shape& two) { return one == two; } //======================================================================= //function : AddShape //purpose : //======================================================================= void VrmlData_ShapeConvert::AddShape (const TopoDS_Shape& theShape, const char * theName) { ShapeData aData;/* = { - compilation problem on SUN TCollection_AsciiString(), theShape, NULL };*/ aData.Shape = theShape; aData.Node = NULL; if (theName) { char buf[2048], * optr = &buf[0]; char * eptr = &buf[sizeof(buf)-1]; for (const char * ptr = theName;; ptr++) { char sym = *ptr; if (sym == '\0' || sym == '\n' || sym == '\r') { * optr = '\0'; break; } if (sym == '\"' || sym == '\\') * optr = '/'; else if (sym == '.') * optr = '_'; else * optr = sym; if (++optr >= eptr) { *optr = '\0'; break; } } aData.Name = buf; } myShapes.Append (aData); } //======================================================================= //function : Convert //purpose : //======================================================================= void VrmlData_ShapeConvert::Convert (const Standard_Boolean theExtractFaces, const Standard_Boolean theExtractEdges, const Standard_Real theDeflection, const Standard_Real theDeflAngle) { const Standard_Real aDeflection = theDeflection < 0.0001 ? 0.0001 : theDeflection; Standard_Boolean Extract[2] = {theExtractFaces, theExtractEdges}; TopAbs_ShapeEnum ShapeType[2] = {TopAbs_FACE, TopAbs_EDGE}; Standard_Integer i; const Handle(NCollection_IncAllocator) anAlloc = new NCollection_IncAllocator; // Relocation map for converted shapes. We should distinguish both TShape // and Orientation in this map. NCollection_DataMap aRelMap (100, anAlloc); NCollection_List::Iterator anIter (myShapes); for (; anIter.More(); anIter.Next()) { ShapeData& aData = anIter.ChangeValue(); Handle(VrmlData_Group) aGroup = new VrmlData_Group (myScene, aData.Name.ToCString()); myScene.AddNode (aGroup); for(i = 0; i < 2; ++i) { if(!Extract[i]) continue; TopExp_Explorer anExp (aData.Shape, ShapeType[i]); for (; anExp.More(); anExp.Next()) { const TopoDS_Shape& aShape = anExp.Current(); TopLoc_Location aLoc; Handle(VrmlData_Geometry) aTShapeNode; const Standard_Boolean isReverse=(aShape.Orientation()==TopAbs_REVERSED); TopoDS_Shape aTestedShape; aTestedShape.TShape (aShape.TShape()); aTestedShape.Orientation (isReverse ? TopAbs_REVERSED : TopAbs_FORWARD); Standard_Boolean isTessellate (Standard_False); switch (ShapeType[i]) { case TopAbs_FACE: { const TopoDS_Face& aFace = TopoDS::Face (aShape); if (aFace.IsNull() == Standard_False) { Handle(Poly_Triangulation) aTri = BRep_Tool::Triangulation (aFace, aLoc); if (aRelMap.IsBound (aTestedShape)) { aTShapeNode = aRelMap(aTestedShape); break; } if (aTri.IsNull()) isTessellate = Standard_True; // Check the existing deflection else if (aTri->Deflection() > aDeflection+ Precision::Confusion()) isTessellate = Standard_True; if (isTessellate) { // Triangulate the face by the standard OCC mesher BRepMesh_IncrementalMesh IM (aFace, aDeflection, Standard_False, theDeflAngle); aTri = BRep_Tool::Triangulation (aFace, aLoc); } if (aTri.IsNull() == Standard_False) { TopoDS_Shape aTestedShapeRev = aTestedShape; aTestedShapeRev.Orientation (isReverse ? TopAbs_FORWARD : TopAbs_REVERSED); Handle(VrmlData_IndexedFaceSet) aFaceSetToReuse; if (aRelMap.IsBound (aTestedShapeRev)) aFaceSetToReuse = Handle(VrmlData_IndexedFaceSet)::DownCast (aRelMap(aTestedShapeRev)); Handle(VrmlData_Coordinate) aCoordToReuse; if (aFaceSetToReuse.IsNull() == Standard_False) aCoordToReuse = aFaceSetToReuse->Coordinates(); aTShapeNode = triToIndexedFaceSet (aTri, aFace, aCoordToReuse); myScene.AddNode (aTShapeNode, Standard_False); // Bind the converted face aRelMap.Bind (aTestedShape, aTShapeNode); } } } break; case TopAbs_WIRE: { const TopoDS_Wire& aWire = TopoDS::Wire (aShape); if (aWire.IsNull() == Standard_False) { } } break; case TopAbs_EDGE: { const TopoDS_Edge& aEdge = TopoDS::Edge (aShape); if (aEdge.IsNull() == Standard_False) { Handle(Poly_Polygon3D) aPol = BRep_Tool::Polygon3D (aEdge, aLoc); if (aRelMap.IsBound (aTestedShape)) { aTShapeNode = aRelMap(aTestedShape); break; } // Check the presence of reversly oriented Edge. It can also be used // because we do not distinguish the orientation for edges. aTestedShape.Orientation (isReverse ? TopAbs_FORWARD : TopAbs_REVERSED); if (aRelMap.IsBound (aTestedShape)) { aTShapeNode = aRelMap(aTestedShape); break; } if (aPol.IsNull()) isTessellate = Standard_True; // Check the existing deflection else if (aPol->Deflection() > aDeflection+ Precision::Confusion() && BRep_Tool::IsGeometric(aEdge)) isTessellate = Standard_True; if (isTessellate && BRep_Tool::IsGeometric(aEdge)) { //try to find PolygonOnTriangulation Handle(Poly_PolygonOnTriangulation) aPT; Handle(Poly_Triangulation) aT; TopLoc_Location aL; Standard_Boolean found = Standard_False; for(i = 1; ; i++) { BRep_Tool::PolygonOnTriangulation(aEdge, aPT, aT, aL, i); if(aPT.IsNull() || aT.IsNull()) break; if(aPT->Deflection() <= aDeflection + Precision::Confusion() && aPT->HasParameters()) { found = Standard_True; break; } } if(found) { BRepAdaptor_Curve aCurve(aEdge); Handle(TColStd_HArray1OfReal) aPrs = aPT->Parameters(); Standard_Integer nbNodes = aPT->NbNodes(); TColgp_Array1OfPnt arrNodes(1, nbNodes); TColStd_Array1OfReal arrUVNodes(1, nbNodes); for(Standard_Integer j = 1; j <= nbNodes; j++) { arrUVNodes(j) = aPrs->Value(aPrs->Lower() + j - 1); arrNodes(j) = aCurve.Value(arrUVNodes(j)); } aPol = new Poly_Polygon3D(arrNodes, arrUVNodes); aPol->Deflection (aPT->Deflection()); } else{ BRepAdaptor_Curve aCurve(aEdge); const Standard_Real aFirst = aCurve.FirstParameter(); const Standard_Real aLast = aCurve.LastParameter(); GCPnts_TangentialDeflection TD (aCurve, aFirst, aLast, theDeflAngle, aDeflection, 2); const Standard_Integer nbNodes = TD.NbPoints(); TColgp_Array1OfPnt arrNodes(1, nbNodes); TColStd_Array1OfReal arrUVNodes(1, nbNodes); for (Standard_Integer j = 1; j <= nbNodes; j++) { arrNodes(j) = TD.Value(j); arrUVNodes(j) = TD.Parameter(j); } aPol = new Poly_Polygon3D(arrNodes, arrUVNodes); aPol->Deflection (aDeflection); } BRep_Builder aBld; aBld.UpdateEdge (aEdge, aPol); } aTShapeNode = polToIndexedLineSet (aPol); myScene.AddNode (aTShapeNode, Standard_False); // Bind the converted face aRelMap.Bind (aTestedShape, aTShapeNode); } } break; default: break; } if (aTShapeNode.IsNull() == Standard_False) { const Handle(VrmlData_ShapeNode) aShapeNode = new VrmlData_ShapeNode (myScene, 0L); aShapeNode->SetAppearance (ShapeType[i] == TopAbs_FACE ? defaultMaterialFace():defaultMaterialEdge()); myScene.AddNode (aShapeNode, Standard_False); aShapeNode->SetGeometry (aTShapeNode); if (aLoc.IsIdentity()) // Store the shape node directly into the main Group. aGroup->AddNode (aShapeNode); else { // Create a Transform grouping node Handle(VrmlData_Group) aTrans = new VrmlData_Group (myScene, 0L, Standard_True); gp_Trsf aTrsf (aLoc); if (fabs(myScale - 1.) > Precision::Confusion()) { const gp_XYZ aTransl = aTrsf.TranslationPart() * myScale; aTrsf.SetTranslationPart (aTransl); } aTrans->SetTransform (aTrsf); myScene.AddNode (aTrans, Standard_False); aGroup->AddNode (aTrans); // Store the shape node under the transform. aTrans->AddNode (aShapeNode); } } } } } myShapes.Clear(); } //======================================================================= //function : triToIndexedFaceSet //purpose : //======================================================================= Handle_VrmlData_Geometry VrmlData_ShapeConvert::triToIndexedFaceSet (const Handle_Poly_Triangulation& theTri, const TopoDS_Face& theFace, const Handle_VrmlData_Coordinate& theCoord) { Standard_Integer i; const Standard_Integer nNodes (theTri->NbNodes()); const Standard_Integer nTriangles (theTri->NbTriangles()); const TColgp_Array1OfPnt& arrPolyNodes = theTri->Nodes(); const Poly_Array1OfTriangle& arrTriangles = theTri->Triangles(); const Handle(VrmlData_IndexedFaceSet) aFaceSet = new VrmlData_IndexedFaceSet (myScene, 0L, // no name Standard_True, // IsCCW Standard_False, // IsSolid Standard_False); // IsConvex const Handle(NCollection_IncAllocator)& anAlloc = myScene.Allocator(); const Standard_Boolean isReverse = (theFace.Orientation() == TopAbs_REVERSED); // Create the array of triangles const Standard_Integer ** arrPolygons = static_cast (anAlloc->Allocate (nTriangles * sizeof(const Standard_Integer *))); aFaceSet->SetPolygons (nTriangles, arrPolygons); // Store the triangles for (i = 0; i < nTriangles; i++) { Standard_Integer * aPolygon = static_cast (anAlloc->Allocate (4*sizeof(Standard_Integer))); aPolygon[0] = 3; arrTriangles(i+1).Get (aPolygon[1],aPolygon[2],aPolygon[3]); aPolygon[1]--; if (isReverse) { const Standard_Integer aTmp = aPolygon[2]-1; aPolygon[2] = aPolygon[3]-1; aPolygon[3] = aTmp; } else { aPolygon[2]--; aPolygon[3]--; } arrPolygons[i] = aPolygon; } // Create the Coordinates node if (theCoord.IsNull() == Standard_False) aFaceSet->SetCoordinates (theCoord); else { gp_XYZ * arrNodes = static_cast (anAlloc->Allocate (nNodes * sizeof(gp_XYZ))); for (i = 0; i < nNodes; i++) arrNodes[i] = arrPolyNodes(i+1).XYZ() * myScale; const Handle(VrmlData_Coordinate) aCoordNode = new VrmlData_Coordinate (myScene, 0L, nNodes, arrNodes); myScene.AddNode (aCoordNode, Standard_False); aFaceSet->SetCoordinates (aCoordNode); } // Create the Normals node if theTri has normals if(theTri->HasNormals()) { gp_XYZ * arrVec = static_cast (anAlloc->Allocate (nNodes * sizeof(gp_XYZ))); const TShort_Array1OfShortReal& Norm = theTri->Normals(); Standard_Integer j; for (i = 0, j = 1; i < nNodes; i++, j += 3) { gp_XYZ aNormal(Norm(j), Norm(j+1), Norm(j+2)); arrVec[i] = aNormal; } const Handle(VrmlData_Normal) aNormalNode = new VrmlData_Normal (myScene, 0L, nNodes, arrVec); myScene.AddNode (aNormalNode, Standard_False); aFaceSet->SetNormals (aNormalNode); return aFaceSet; } Poly_Connect PC(theTri); // Create the Normals node (if UV- values are available) TopLoc_Location aLoc; const Standard_Real aConf2 = Precision::SquareConfusion(); const Handle(Geom_Surface) aSurface = BRep_Tool::Surface (theFace, aLoc); if (theTri->HasUVNodes() && aSurface.IsNull() == Standard_False) { if (aSurface->IsCNu(1) && aSurface->IsCNv(1)) { Standard_Integer nbNormVal = nNodes * 3; Handle(TShort_HArray1OfShortReal) Normals = new TShort_HArray1OfShortReal(1, nbNormVal); const TColgp_Array1OfPnt2d& arrUV = theTri->UVNodes(); gp_XYZ * arrVec = static_cast (anAlloc->Allocate (nNodes * sizeof(gp_XYZ))); // Compute the normal vectors Standard_Real Tol = Sqrt(aConf2); for (i = 0; i < nNodes; i++) { const gp_Pnt2d& aUV = arrUV(i+1); gp_Dir aNormal; if (GeomLib::NormEstim(aSurface, aUV, Tol, aNormal) > 1) { //Try to estimate as middle normal of adjacent triangles Standard_Integer n[3]; gp_XYZ eqPlan(0., 0., 0.); for (PC.Initialize(i+1); PC.More(); PC.Next()) { arrTriangles(PC.Value()).Get(n[0], n[1], n[2]); gp_XYZ v1(arrPolyNodes(n[1]).Coord()-arrPolyNodes(n[0]).Coord()); gp_XYZ v2(arrPolyNodes(n[2]).Coord()-arrPolyNodes(n[1]).Coord()); gp_XYZ vv = v1^v2; Standard_Real mod = vv.Modulus(); if (mod < Tol) continue; eqPlan += vv/mod; } if (eqPlan.SquareModulus() > gp::Resolution()) aNormal = gp_Dir(eqPlan); } if (isReverse) aNormal.Reverse(); if (aNormal.X()*aNormal.X() < aConf2) aNormal.SetX(0.); if (aNormal.Y()*aNormal.Y() < aConf2) aNormal.SetY(0.); if (aNormal.Z()*aNormal.Z() < aConf2) aNormal.SetZ(0.); arrVec[i] = aNormal.XYZ(); Standard_Integer j = i * 3; Normals->SetValue(j + 1, (Standard_ShortReal)aNormal.X()); Normals->SetValue(j + 2, (Standard_ShortReal)aNormal.Y()); Normals->SetValue(j + 3, (Standard_ShortReal)aNormal.Z()); } theTri->SetNormals(Normals); const Handle(VrmlData_Normal) aNormalNode = new VrmlData_Normal (myScene, 0L, nNodes, arrVec); myScene.AddNode (aNormalNode, Standard_False); aFaceSet->SetNormals (aNormalNode); } } return aFaceSet; } //======================================================================= //function : polToIndexedLineSet //purpose : single polygon3D => IndexedLineSet //======================================================================= Handle_VrmlData_Geometry VrmlData_ShapeConvert::polToIndexedLineSet (const Handle_Poly_Polygon3D& thePol) { Standard_Integer i; const Standard_Integer nNodes (thePol->NbNodes()); const TColgp_Array1OfPnt& arrPolyNodes = thePol->Nodes(); const Handle(NCollection_IncAllocator)& anAlloc = myScene.Allocator(); const Handle(VrmlData_IndexedLineSet) aLineSet = new VrmlData_IndexedLineSet (myScene, 0L); // Create the array of polygons (1 member) const Standard_Integer ** arrPolygons = static_cast (anAlloc->Allocate (sizeof(const Standard_Integer *))); aLineSet->SetPolygons (1, arrPolygons); // Store the polygon Standard_Integer * aPolygon = static_cast (anAlloc->Allocate ((nNodes+1)*sizeof(Standard_Integer))); aPolygon[0] = nNodes; for (i = 1; i <= nNodes; i++) aPolygon[i] = i-1; arrPolygons[0] = aPolygon; // Create the Coordinates node gp_XYZ * arrNodes = static_cast (anAlloc->Allocate (nNodes * sizeof(gp_XYZ))); for (i = 0; i < nNodes; i++) arrNodes[i] = arrPolyNodes(i+1).XYZ() * myScale; const Handle(VrmlData_Coordinate) aCoordNode = new VrmlData_Coordinate (myScene, 0L, nNodes, arrNodes); myScene.AddNode (aCoordNode, Standard_False); aLineSet->SetCoordinates (aCoordNode); return aLineSet; } //======================================================================= //function : defaultMaterialFace //purpose : //======================================================================= Handle(VrmlData_Appearance) VrmlData_ShapeConvert::defaultMaterialFace () const { static char aNodeName[] = "__defaultMaterialFace"; Handle(VrmlData_Appearance) anAppearance = Handle(VrmlData_Appearance)::DownCast(myScene.FindNode(aNodeName)); if (anAppearance.IsNull()) { const Handle(VrmlData_Material) aMaterial = new VrmlData_Material (myScene, 0L, 1.0, 0.022, 0.); aMaterial->SetDiffuseColor (Quantity_Color(0.780392, 0.568627, 0.113725, Quantity_TOC_RGB)); aMaterial->SetEmissiveColor(Quantity_Color(0.329412, 0.223529, 0.027451, Quantity_TOC_RGB)); aMaterial->SetSpecularColor(Quantity_Color(0.992157, 0.941176, 0.807843, Quantity_TOC_RGB)); myScene.AddNode (aMaterial, Standard_False); anAppearance = new VrmlData_Appearance (myScene, aNodeName); anAppearance->SetMaterial (aMaterial); myScene.AddNode (anAppearance, Standard_False); } return anAppearance; } //======================================================================= //function : defaultMaterialEdge //purpose : //======================================================================= Handle(VrmlData_Appearance) VrmlData_ShapeConvert::defaultMaterialEdge () const { static char aNodeName[] = "__defaultMaterialEdge"; Handle(VrmlData_Appearance) anAppearance = Handle(VrmlData_Appearance)::DownCast(myScene.FindNode(aNodeName)); if (anAppearance.IsNull()) { const Handle(VrmlData_Material) aMaterial = new VrmlData_Material (myScene, 0L, 0.2, 0.2, 0.2); aMaterial->SetDiffuseColor (Quantity_Color(0.2, 0.7, 0.2, Quantity_TOC_RGB)); aMaterial->SetEmissiveColor(Quantity_Color(0.2, 0.7, 0.2, Quantity_TOC_RGB)); aMaterial->SetSpecularColor(Quantity_Color(0.2, 0.7, 0.2, Quantity_TOC_RGB)); myScene.AddNode (aMaterial, Standard_False); anAppearance = new VrmlData_Appearance (myScene, aNodeName); anAppearance->SetMaterial (aMaterial); myScene.AddNode (anAppearance, Standard_False); } return anAppearance; }