1
0
mirror of https://git.dev.opencascade.org/repos/occt.git synced 2025-06-20 11:54:07 +03:00
occt/src/StdPrs/StdPrs_ShadedShape.cxx
abv 68858c7dd6 0027097: GCC and CLang compiler warnings and errors with -Wpedantic
Useless semicolons are removed after closing braces of namespaces and macros in code dependent on FreeImage and VTK.
Comments added at the closing braces of namespaces to help comprehension.
In OSD_File.cxx and OSD_Disk.cxx, unnecessary declarations of system functions are removed
2016-01-22 11:42:51 +03:00

571 lines
21 KiB
C++

// Created on: 1993-09-23
// Created by: Jean-Louis FRENKEL
// Copyright (c) 1993-1999 Matra Datavision
// Copyright (c) 1999-2014 OPEN CASCADE SAS
//
// This file is part of Open CASCADE Technology software library.
//
// This library is free software; you can redistribute it and/or modify it under
// the terms of the GNU Lesser General Public License version 2.1 as published
// by the Free Software Foundation, with special exception defined in the file
// OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
// distribution for complete text of the license and disclaimer of any warranty.
//
// Alternatively, this file may be used under the terms of Open CASCADE
// commercial license or contractual agreement.
#include <StdPrs_ShadedShape.hxx>
#include <Bnd_Box.hxx>
#include <BRepTools.hxx>
#include <BRepBndLib.hxx>
#include <BRep_Builder.hxx>
#include <BRep_Tool.hxx>
#include <Graphic3d_ArrayOfSegments.hxx>
#include <Graphic3d_ArrayOfTriangles.hxx>
#include <Graphic3d_AspectFillArea3d.hxx>
#include <Graphic3d_Group.hxx>
#include <gp_Dir.hxx>
#include <gp_Vec.hxx>
#include <gp_Pnt.hxx>
#include <NCollection_List.hxx>
#include <Precision.hxx>
#include <Prs3d_Drawer.hxx>
#include <Prs3d_IsoAspect.hxx>
#include <Prs3d_LineAspect.hxx>
#include <Prs3d_Presentation.hxx>
#include <Prs3d_ShadingAspect.hxx>
#include <Poly_Connect.hxx>
#include <Poly_PolygonOnTriangulation.hxx>
#include <Poly_Triangulation.hxx>
#include <StdPrs_ToolTriangulatedShape.hxx>
#include <StdPrs_WFShape.hxx>
#include <TopExp.hxx>
#include <TopExp_Explorer.hxx>
#include <TopoDS.hxx>
#include <TopoDS_Compound.hxx>
#include <TopoDS_Face.hxx>
#include <TopoDS_Shape.hxx>
#include <TColgp_Array1OfDir.hxx>
#include <TColgp_Array1OfPnt2d.hxx>
#include <TColgp_HArray1OfPnt.hxx>
#include <TopTools_ListOfShape.hxx>
#include <TopTools_IndexedDataMapOfShapeListOfShape.hxx>
namespace
{
//! Computes wireframe presentation for free wires and vertices
void wireframeFromShape (const Handle (Prs3d_Presentation)& thePrs,
const TopoDS_Shape& theShape,
const Handle (Prs3d_Drawer)& theDrawer)
{
Standard_Boolean aDrawAllVerticesFlag = (theDrawer->VertexDrawMode() == Prs3d_VDM_All);
if (!aDrawAllVerticesFlag && theShape.ShapeType() != TopAbs_COMPOUND)
{
return;
}
TopExp_Explorer aShapeIter (theShape, TopAbs_FACE);
if (!aShapeIter.More())
{
// compound contains no shaded elements at all
StdPrs_WFShape::Add (thePrs, theShape, theDrawer);
return;
}
// We have to create a compound and collect all subshapes not drawn by the shading algo.
// This includes:
// - isolated edges
// - isolated vertices, if aDrawAllVerticesFlag == Standard_False
// - all shape's vertices, if aDrawAllVerticesFlag == Standard_True
TopoDS_Compound aCompoundWF;
BRep_Builder aBuilder;
aBuilder.MakeCompound (aCompoundWF);
Standard_Boolean hasElement = Standard_False;
// isolated edges
for (aShapeIter.Init (theShape, TopAbs_EDGE, TopAbs_FACE); aShapeIter.More(); aShapeIter.Next())
{
hasElement = Standard_True;
aBuilder.Add (aCompoundWF, aShapeIter.Current());
}
// isolated or all vertices
aShapeIter.Init (theShape, TopAbs_VERTEX, aDrawAllVerticesFlag ? TopAbs_SHAPE : TopAbs_EDGE);
for (; aShapeIter.More(); aShapeIter.Next())
{
hasElement = Standard_True;
aBuilder.Add (aCompoundWF, aShapeIter.Current());
}
if (hasElement)
{
StdPrs_WFShape::Add (thePrs, aCompoundWF, theDrawer);
}
}
//! Computes special wireframe presentation for faces without triangulation.
void wireframeNoTriangFacesFromShape (const Handle(Prs3d_Presentation)& thePrs,
const TopoDS_Shape& theShape,
const Handle(Prs3d_Drawer)& theDrawer)
{
TopoDS_Compound aCompoundWF;
BRep_Builder aBuilder;
aBuilder.MakeCompound (aCompoundWF);
TopLoc_Location aLoc;
Standard_Boolean hasElement = Standard_False;
for (TopExp_Explorer aShapeIter(theShape, TopAbs_FACE); aShapeIter.More(); aShapeIter.Next())
{
const TopoDS_Face& aFace = TopoDS::Face (aShapeIter.Current());
const Handle(Poly_Triangulation) aTriang = BRep_Tool::Triangulation (aFace, aLoc);
if (aTriang.IsNull())
{
hasElement = Standard_True;
aBuilder.Add (aCompoundWF, aFace);
}
}
if (hasElement)
{
Standard_Integer aPrevUIsoNb = theDrawer->UIsoAspect()->Number();
Standard_Integer aPrevVIsoNb = theDrawer->VIsoAspect()->Number();
theDrawer->UIsoAspect()->SetNumber (5);
theDrawer->VIsoAspect()->SetNumber (5);
StdPrs_WFShape::Add (thePrs, aCompoundWF, theDrawer);
theDrawer->UIsoAspect()->SetNumber (aPrevUIsoNb);
theDrawer->VIsoAspect()->SetNumber (aPrevVIsoNb);
}
}
//! Gets triangulation of every face of shape and fills output array of triangles
static Handle(Graphic3d_ArrayOfTriangles) fillTriangles (const TopoDS_Shape& theShape,
const Standard_Boolean theHasTexels,
const gp_Pnt2d& theUVOrigin,
const gp_Pnt2d& theUVRepeat,
const gp_Pnt2d& theUVScale)
{
Handle(Poly_Triangulation) aT;
TopLoc_Location aLoc;
gp_Pnt aPoint;
Standard_Integer aNbTriangles = 0;
Standard_Integer aNbVertices = 0;
// Precision for compare square distances
const Standard_Real aPreci = Precision::SquareConfusion();
TopExp_Explorer aFaceIt(theShape, TopAbs_FACE);
for (; aFaceIt.More(); aFaceIt.Next())
{
const TopoDS_Face& aFace = TopoDS::Face(aFaceIt.Current());
aT = BRep_Tool::Triangulation (aFace, aLoc);
if (!aT.IsNull())
{
aNbTriangles += aT->NbTriangles();
aNbVertices += aT->NbNodes();
}
}
if (aNbVertices < 3 || aNbTriangles <= 0)
{
return Handle(Graphic3d_ArrayOfTriangles)();
}
Handle(Graphic3d_ArrayOfTriangles) anArray = new Graphic3d_ArrayOfTriangles (aNbVertices, 3 * aNbTriangles,
Standard_True, Standard_False, theHasTexels);
Standard_Real aUmin (0.0), aUmax (0.0), aVmin (0.0), aVmax (0.0), dUmax (0.0), dVmax (0.0);
for (aFaceIt.Init (theShape, TopAbs_FACE); aFaceIt.More(); aFaceIt.Next())
{
const TopoDS_Face& aFace = TopoDS::Face(aFaceIt.Current());
aT = BRep_Tool::Triangulation (aFace, aLoc);
if (aT.IsNull())
{
continue;
}
const gp_Trsf& aTrsf = aLoc.Transformation();
// Determinant of transform matrix less then 0 means that mirror transform applied.
Standard_Boolean isMirrored = aTrsf.VectorialPart().Determinant() < 0;
Poly_Connect aPolyConnect (aT);
// Extracts vertices & normals from nodes
const TColgp_Array1OfPnt& aNodes = aT->Nodes();
const TColgp_Array1OfPnt2d& aUVNodes = aT->UVNodes();
TColgp_Array1OfDir aNormals (aNodes.Lower(), aNodes.Upper());
StdPrs_ToolTriangulatedShape::Normal (aFace, aPolyConnect, aNormals);
if (theHasTexels)
{
BRepTools::UVBounds (aFace, aUmin, aUmax, aVmin, aVmax);
dUmax = (aUmax - aUmin);
dVmax = (aVmax - aVmin);
}
const Standard_Integer aDecal = anArray->VertexNumber();
for (Standard_Integer aNodeIter = aNodes.Lower(); aNodeIter <= aNodes.Upper(); ++aNodeIter)
{
aPoint = aNodes (aNodeIter);
if (!aLoc.IsIdentity())
{
aPoint.Transform (aTrsf);
aNormals (aNodeIter) = aNormals (aNodeIter).Transformed (aTrsf);
}
if (theHasTexels && aUVNodes.Upper() == aNodes.Upper())
{
const gp_Pnt2d aTexel = gp_Pnt2d ((-theUVOrigin.X() + (theUVRepeat.X() * (aUVNodes (aNodeIter).X() - aUmin)) / dUmax) / theUVScale.X(),
(-theUVOrigin.Y() + (theUVRepeat.Y() * (aUVNodes (aNodeIter).Y() - aVmin)) / dVmax) / theUVScale.Y());
anArray->AddVertex (aPoint, aNormals (aNodeIter), aTexel);
}
else
{
anArray->AddVertex (aPoint, aNormals (aNodeIter));
}
}
// Fill array with vertex and edge visibility info
const Poly_Array1OfTriangle& aTriangles = aT->Triangles();
Standard_Integer anIndex[3];
for (Standard_Integer aTriIter = 1; aTriIter <= aT->NbTriangles(); ++aTriIter)
{
if ((aFace.Orientation() == TopAbs_REVERSED) ^ isMirrored)
{
aTriangles (aTriIter).Get (anIndex[0], anIndex[2], anIndex[1]);
}
else
{
aTriangles (aTriIter).Get (anIndex[0], anIndex[1], anIndex[2]);
}
gp_Pnt aP1 = aNodes (anIndex[0]);
gp_Pnt aP2 = aNodes (anIndex[1]);
gp_Pnt aP3 = aNodes (anIndex[2]);
gp_Vec aV1 (aP1, aP2);
if (aV1.SquareMagnitude() <= aPreci)
{
continue;
}
gp_Vec aV2 (aP2, aP3);
if (aV2.SquareMagnitude() <= aPreci)
{
continue;
}
gp_Vec aV3 (aP3, aP1);
if (aV3.SquareMagnitude() <= aPreci)
{
continue;
}
aV1.Normalize();
aV2.Normalize();
aV1.Cross (aV2);
if (aV1.SquareMagnitude() > aPreci)
{
anArray->AddEdge (anIndex[0] + aDecal);
anArray->AddEdge (anIndex[1] + aDecal);
anArray->AddEdge (anIndex[2] + aDecal);
}
}
}
return anArray;
}
//! Prepare shaded presentation for specified shape
static Standard_Boolean shadeFromShape (const TopoDS_Shape& theShape,
const Handle(Prs3d_Presentation)& thePrs,
const Handle(Prs3d_Drawer)& theDrawer,
const Standard_Boolean theHasTexels,
const gp_Pnt2d& theUVOrigin,
const gp_Pnt2d& theUVRepeat,
const gp_Pnt2d& theUVScale,
const Standard_Boolean theIsClosed)
{
Handle(Graphic3d_ArrayOfTriangles) aPArray = fillTriangles (theShape, theHasTexels, theUVOrigin, theUVRepeat, theUVScale);
if (aPArray.IsNull())
{
return Standard_False;
}
Handle(Graphic3d_Group) aGroup = Prs3d_Root::NewGroup (thePrs);
aGroup->SetClosed (theIsClosed);
if (!theDrawer->ShadingAspectGlobal())
{
Handle(Graphic3d_AspectFillArea3d) anAsp = theDrawer->ShadingAspect()->Aspect();
theIsClosed ? anAsp->SuppressBackFace() : anAsp->AllowBackFace();
aGroup->SetGroupPrimitivesAspect (anAsp);
}
aGroup->AddPrimitiveArray (aPArray);
return Standard_True;
}
//! Compute boundary presentation for faces of the shape.
static void computeFaceBoundaries (const TopoDS_Shape& theShape,
const Handle(Prs3d_Presentation)& thePrs,
const Handle(Prs3d_Drawer)& theDrawer)
{
// collection of all triangulation nodes on edges
// for computing boundaries presentation
NCollection_List<Handle(TColgp_HArray1OfPnt)> aNodeCollection;
Standard_Integer aNodeNumber = 0;
TopLoc_Location aTrsf;
// explore all boundary edges
TopTools_IndexedDataMapOfShapeListOfShape anEdgesMap;
TopExp::MapShapesAndAncestors (
theShape, TopAbs_EDGE, TopAbs_FACE, anEdgesMap);
Standard_Integer anEdgeIdx = 1;
for ( ; anEdgeIdx <= anEdgesMap.Extent (); anEdgeIdx++)
{
// reject free edges
const TopTools_ListOfShape& aFaceList = anEdgesMap.FindFromIndex (anEdgeIdx);
if (aFaceList.Extent() == 0)
continue;
// take one of the shared edges and get edge triangulation
const TopoDS_Face& aFace = TopoDS::Face (aFaceList.First ());
const TopoDS_Edge& anEdge = TopoDS::Edge (anEdgesMap.FindKey (anEdgeIdx));
Handle(Poly_Triangulation) aTriangulation =
BRep_Tool::Triangulation (aFace, aTrsf);
if (aTriangulation.IsNull ())
continue;
Handle(Poly_PolygonOnTriangulation) anEdgePoly =
BRep_Tool::PolygonOnTriangulation (anEdge, aTriangulation, aTrsf);
if (anEdgePoly.IsNull ())
continue;
// get edge nodes indexes from face triangulation
const TColgp_Array1OfPnt& aTriNodes = aTriangulation->Nodes ();
const TColStd_Array1OfInteger& anEdgeNodes = anEdgePoly->Nodes ();
if (anEdgeNodes.Length () < 2)
continue;
// collect the edge nodes
Handle(TColgp_HArray1OfPnt) aCollected =
new TColgp_HArray1OfPnt (anEdgeNodes.Lower (), anEdgeNodes.Upper ());
Standard_Integer aNodeIdx = anEdgeNodes.Lower ();
for ( ; aNodeIdx <= anEdgeNodes.Upper (); aNodeIdx++)
{
// node index in face triangulation
Standard_Integer aTriIndex = anEdgeNodes.Value (aNodeIdx);
// get node and apply location transformation to the node
gp_Pnt aTriNode = aTriNodes.Value (aTriIndex);
if (!aTrsf.IsIdentity ())
aTriNode.Transform (aTrsf);
// add node to the boundary array
aCollected->SetValue (aNodeIdx, aTriNode);
}
aNodeNumber += anEdgeNodes.Length ();
aNodeCollection.Append (aCollected);
}
// check if it possible to continue building the presentation
if (aNodeNumber == 0)
return;
// allocate polyline array for presentation
Standard_Integer aSegmentEdgeNb =
(aNodeNumber - aNodeCollection.Extent()) * 2;
Handle(Graphic3d_ArrayOfSegments) aSegments =
new Graphic3d_ArrayOfSegments (aNodeNumber, aSegmentEdgeNb);
// build presentation for edge bondaries
NCollection_List<Handle(TColgp_HArray1OfPnt)>::Iterator
aCollIt (aNodeCollection);
// the edge index is increased in each iteration step to
// avoid contiguous segments between different face edges.
for ( ; aCollIt.More(); aCollIt.Next () )
{
const Handle(TColgp_HArray1OfPnt)& aNodeArray = aCollIt.Value ();
Standard_Integer aNodeIdx = aNodeArray->Lower ();
// add first node (this node is not shared with previous segment).
// for each face edge, indices for sharing nodes
// between segments begin from the first added node.
Standard_Integer aSegmentEdge =
aSegments->AddVertex (aNodeArray->Value (aNodeIdx));
// add subsequent nodes and provide edge indexes for sharing
// the nodes between the sequential segments.
for ( aNodeIdx++; aNodeIdx <= aNodeArray->Upper (); aNodeIdx++ )
{
aSegments->AddVertex (aNodeArray->Value (aNodeIdx));
aSegments->AddEdge ( aSegmentEdge);
aSegments->AddEdge (++aSegmentEdge);
}
}
// set up aspect and add polyline data
Handle(Graphic3d_AspectLine3d) aBoundaryAspect =
theDrawer->FaceBoundaryAspect ()->Aspect ();
Handle(Graphic3d_Group) aPrsGrp = Prs3d_Root::CurrentGroup (thePrs);
aPrsGrp->SetGroupPrimitivesAspect (aBoundaryAspect);
aPrsGrp->AddPrimitiveArray (aSegments);
}
} // anonymous namespace
// =======================================================================
// function : ExploreSolids
// purpose :
// =======================================================================
void StdPrs_ShadedShape::ExploreSolids (const TopoDS_Shape& theShape,
const BRep_Builder& theBuilder,
TopoDS_Compound& theClosed,
TopoDS_Compound& theOpened,
const Standard_Boolean theIgnore1DSubShape)
{
if (theShape.IsNull())
{
return;
}
switch (theShape.ShapeType())
{
case TopAbs_COMPOUND:
case TopAbs_COMPSOLID:
{
for (TopoDS_Iterator anIter (theShape); anIter.More(); anIter.Next())
{
ExploreSolids (anIter.Value(), theBuilder, theClosed, theOpened, theIgnore1DSubShape);
}
return;
}
case TopAbs_SOLID:
{
for (TopoDS_Iterator anIter (theShape); anIter.More(); anIter.Next())
{
const TopoDS_Shape& aSubShape = anIter.Value();
const Standard_Boolean isClosed = aSubShape.ShapeType() == TopAbs_SHELL &&
BRep_Tool::IsClosed (aSubShape) &&
StdPrs_ToolTriangulatedShape::IsTriangulated (aSubShape);
theBuilder.Add (isClosed ? theClosed : theOpened, aSubShape);
}
return;
}
case TopAbs_SHELL:
case TopAbs_FACE:
{
theBuilder.Add (theOpened, theShape);
return;
}
case TopAbs_WIRE:
case TopAbs_EDGE:
case TopAbs_VERTEX:
{
if (!theIgnore1DSubShape)
{
theBuilder.Add (theOpened, theShape);
}
return;
}
case TopAbs_SHAPE:
default:
return;
}
}
// =======================================================================
// function : Add
// purpose :
// =======================================================================
void StdPrs_ShadedShape::Add (const Handle(Prs3d_Presentation)& thePrs,
const TopoDS_Shape& theShape,
const Handle(Prs3d_Drawer)& theDrawer,
const StdPrs_Volume theVolume)
{
gp_Pnt2d aDummy;
StdPrs_ShadedShape::Add (thePrs, theShape, theDrawer,
Standard_False, aDummy, aDummy, aDummy, theVolume);
}
// =======================================================================
// function : Add
// purpose :
// =======================================================================
void StdPrs_ShadedShape::Add (const Handle (Prs3d_Presentation)& thePrs,
const TopoDS_Shape& theShape,
const Handle (Prs3d_Drawer)& theDrawer,
const Standard_Boolean theHasTexels,
const gp_Pnt2d& theUVOrigin,
const gp_Pnt2d& theUVRepeat,
const gp_Pnt2d& theUVScale,
const StdPrs_Volume theVolume)
{
if (theShape.IsNull())
{
return;
}
// add wireframe presentation for isolated edges and vertices
wireframeFromShape (thePrs, theShape, theDrawer);
// Use automatic re-triangulation with deflection-check logic only if this feature is enable
if (theDrawer->IsAutoTriangulation())
{
// Triangulation completeness is important for "open-closed" analysis - perform tessellation beforehand
StdPrs_ToolTriangulatedShape::Tessellate (theShape, theDrawer);
}
// add special wireframe presentation for faces without triangulation
wireframeNoTriangFacesFromShape (thePrs, theShape, theDrawer);
// The shape types listed below need advanced analysis as potentially containing
// both closed and open parts. Solids are also included, because they might
// contain non-manifold parts inside (internal open shells)
if ((theShape.ShapeType() == TopAbs_COMPOUND
|| theShape.ShapeType() == TopAbs_COMPSOLID
|| theShape.ShapeType() == TopAbs_SOLID)
&& theVolume == StdPrs_Volume_Autodetection)
{
// collect two compounds: for opened and closed (solid) sub-shapes
TopoDS_Compound anOpened, aClosed;
BRep_Builder aBuilder;
aBuilder.MakeCompound (aClosed);
aBuilder.MakeCompound (anOpened);
ExploreSolids (theShape, aBuilder, aClosed, anOpened, Standard_True);
TopoDS_Iterator aShapeIter (aClosed);
if (aShapeIter.More())
{
shadeFromShape (aClosed, thePrs, theDrawer,
theHasTexels, theUVOrigin, theUVRepeat, theUVScale, Standard_True);
}
aShapeIter.Initialize (anOpened);
if (aShapeIter.More())
{
shadeFromShape (anOpened, thePrs, theDrawer,
theHasTexels, theUVOrigin, theUVRepeat, theUVScale, Standard_False);
}
}
else
{
// if the shape type is not compound, composolid or solid, use autodetection back-facing filled
shadeFromShape (theShape, thePrs, theDrawer,
theHasTexels, theUVOrigin, theUVRepeat, theUVScale,
(theVolume == StdPrs_Volume_Closed ? Standard_True : Standard_False));
}
if (theDrawer->FaceBoundaryDraw())
{
computeFaceBoundaries (theShape, thePrs, theDrawer);
}
}