1
0
mirror of https://git.dev.opencascade.org/repos/occt.git synced 2025-04-03 17:56:21 +03:00

0026072: Visualization - more realistic display of face edges

Added calculation of normals to boundary edges.
Extended draw harness commands.
Added new test case.
This commit is contained in:
drochalo 2024-03-11 09:46:04 +00:00
parent f286953d85
commit b63fe6e31f
7 changed files with 231 additions and 54 deletions

View File

@ -636,12 +636,22 @@ void AIS_ColoredShape::addShapesWithCustomProps (const Handle(Prs3d_Presentation
{
if (Handle(Graphic3d_ArrayOfSegments) aBndSegments = StdPrs_ShadedShape::FillFaceBoundaries (aShapeDraw, aDrawer->FaceBoundaryUpperContinuity()))
{
if (anEdgesGroup.IsNull())
Handle(Graphic3d_AspectLine3d) aLineAspect = aDrawer->FaceBoundaryAspect()->Aspect();
if (aDrawer->FaceBoundaryShadingOverride())
{
Quantity_Color aColor = aDrawer->Color();
if (aDrawer->HasOwnShadingAspect())
{
aColor = aDrawer->ShadingAspect()->Color();
}
aLineAspect->SetColor (aColor);
anEdgesGroup = thePrs->NewGroup();
}
else if (anEdgesGroup.IsNull())
{
anEdgesGroup = thePrs->NewGroup();
}
anEdgesGroup->SetPrimitivesAspect (aDrawer->FaceBoundaryAspect()->Aspect());
anEdgesGroup->SetGroupPrimitivesAspect (aLineAspect);
anEdgesGroup->AddPrimitiveArray (aBndSegments);
}
}

View File

@ -54,11 +54,16 @@ public:
//! @param theMaxVertexs defines the maximum allowed vertex number in the array
//! @param theMaxEdges defines the maximum allowed edge number in the array
//! @param theHasVColors when TRUE, AddVertex(Point,Color) should be used for specifying vertex color
//! @param theHasVNormals when TRUE, AddVertex(Point,Normal) or AddVertex(Point,Normal,Color) should be used to specify vertex normal;
//! vertex normals should be specified coherent to the edge's neighbour triangle face's orientation
//! (defined by order of vertexes within triangle) for proper rendering
Graphic3d_ArrayOfSegments (Standard_Integer theMaxVertexs,
Standard_Integer theMaxEdges = 0,
Standard_Boolean theHasVColors = Standard_False)
: Graphic3d_ArrayOfPrimitives (Graphic3d_TOPA_SEGMENTS, theMaxVertexs, 0, theMaxEdges, theHasVColors ? Graphic3d_ArrayFlags_VertexColor : Graphic3d_ArrayFlags_None) {}
Standard_Integer theMaxEdges = 0,
Standard_Boolean theHasVColors = Standard_False,
Standard_Boolean theHasVNormals = Standard_False)
: Graphic3d_ArrayOfPrimitives (Graphic3d_TOPA_SEGMENTS, theMaxVertexs, 0, theMaxEdges,
(theHasVNormals ? Graphic3d_ArrayFlags_VertexNormal : Graphic3d_ArrayFlags_None)
| (theHasVColors ? Graphic3d_ArrayFlags_VertexColor : Graphic3d_ArrayFlags_None)) {}
};

View File

@ -772,6 +772,17 @@ public:
myFaceBoundaryDraw = false;
}
//! Return flag value for boundary shading edge color override
Standard_Boolean FaceBoundaryShadingOverride() const
{
return myHasOwnFaceBoundaryDraw || myLink.IsNull()
? myFaceBoundaryShadingOverride
: myLink->FaceBoundaryShadingOverride();
}
//! Return flag value for boundary shading edge color override
void SetFaceBoundaryShadingOverride (Standard_Boolean theFlag) { myFaceBoundaryShadingOverride = theFlag; }
//! Returns true if the drawer has its own attribute for face boundaries upper edge continuity class that overrides the one in the link.
Standard_Boolean HasOwnFaceBoundaryUpperContinuity() const { return myFaceBoundaryUpperContinuity != -1; }
@ -1008,6 +1019,7 @@ protected:
Standard_Integer myFaceBoundaryUpperContinuity; //!< the most edge continuity class (GeomAbs_Shape) to be included to face boundaries presentation, or -1 if undefined
Standard_Boolean myFaceBoundaryDraw;
Standard_Boolean myHasOwnFaceBoundaryDraw;
Standard_Boolean myFaceBoundaryShadingOverride;
Handle(Prs3d_DimensionAspect) myDimensionAspect;
Prs3d_DimensionUnits myDimensionModelUnits;

View File

@ -299,9 +299,7 @@ namespace
// for computing boundaries presentation
Standard_Integer aNodeNumber = 0;
Standard_Integer aNbPolylines = 0;
TopLoc_Location aTrsf;
TopLoc_Location aLoc;
Handle(NCollection_Shared<TColgp_SequenceOfPnt>) aSeqPntsExtra;
for (TopExp_Explorer aFaceIter (theShape, TopAbs_FACE); aFaceIter.More(); aFaceIter.Next())
{
@ -331,7 +329,7 @@ namespace
// take one of the shared edges and get edge triangulation
const TopoDS_Face& aFace = TopoDS::Face (anEdgeIter.Value().First());
Handle(Poly_Triangulation) aTriangulation = BRep_Tool::Triangulation (aFace, aTrsf);
Handle(Poly_Triangulation) aTriangulation = BRep_Tool::Triangulation (aFace, aLoc);
if (aTriangulation.IsNull())
{
continue;
@ -345,7 +343,7 @@ namespace
continue;
}
Handle(Poly_PolygonOnTriangulation) anEdgePoly = BRep_Tool::PolygonOnTriangulation (anEdge, aTriangulation, aTrsf);
Handle(Poly_PolygonOnTriangulation) anEdgePoly = BRep_Tool::PolygonOnTriangulation (anEdge, aTriangulation, aLoc);
if (!anEdgePoly.IsNull()
&& anEdgePoly->Nodes().Length() >= 2)
{
@ -371,7 +369,9 @@ namespace
// create indexed segments array to pack polylines from different edges into single array
const Standard_Integer aSegmentEdgeNb = (aNodeNumber - aNbPolylines) * 2;
Handle(Graphic3d_ArrayOfSegments) aSegments = new Graphic3d_ArrayOfSegments (aNodeNumber + aNbExtra, aSegmentEdgeNb + aNbExtra);
const Standard_Boolean aToAddNormals = Standard_True;
Handle(Graphic3d_ArrayOfSegments) aSegments = new Graphic3d_ArrayOfSegments (aNodeNumber + aNbExtra, aSegmentEdgeNb + aNbExtra,
Standard_False, aToAddNormals);
for (TopTools_IndexedDataMapOfShapeListOfShape::Iterator anEdgeIter (anEdgesMap); anEdgeIter.More(); anEdgeIter.Next())
{
if (anEdgeIter.Value().Extent() == 0)
@ -379,49 +379,75 @@ namespace
continue;
}
const TopoDS_Face& aFace = TopoDS::Face (anEdgeIter.Value().First());
Handle(Poly_Triangulation) aTriangulation = BRep_Tool::Triangulation (aFace, aTrsf);
if (aTriangulation.IsNull())
Standard_Integer aFaceIndex = 0;
const Standard_Integer aFirstNodeInFace = aSegments->VertexNumber() + 1;
for (TopTools_ListOfShape::Iterator aFaceIter (anEdgeIter.Value()); aFaceIter.More(); aFaceIter.Next())
{
continue;
}
const TopoDS_Edge& anEdge = TopoDS::Edge (anEdgeIter.Key());
if (theUpperContinuity < GeomAbs_CN
&& anEdgeIter.Value().Extent() >= 2
&& BRep_Tool::MaxContinuity (anEdge) > theUpperContinuity)
{
continue;
}
Handle(Poly_PolygonOnTriangulation) anEdgePoly = BRep_Tool::PolygonOnTriangulation (anEdge, aTriangulation, aTrsf);
if (anEdgePoly.IsNull()
|| anEdgePoly->Nodes().Length () < 2)
{
continue;
}
// get edge nodes indexes from face triangulation
const TColStd_Array1OfInteger& anEdgeNodes = anEdgePoly->Nodes();
// collect the edge nodes
Standard_Integer aSegmentEdge = aSegments->VertexNumber() + 1;
for (Standard_Integer aNodeIdx = anEdgeNodes.Lower(); aNodeIdx <= anEdgeNodes.Upper(); ++aNodeIdx)
{
// node index in face triangulation
// get node and apply location transformation to the node
const Standard_Integer aTriIndex = anEdgeNodes.Value (aNodeIdx);
gp_Pnt aTriNode = aTriangulation->Node (aTriIndex);
if (!aTrsf.IsIdentity())
const TopoDS_Face& aFace = TopoDS::Face (aFaceIter.Value());
Handle(Poly_Triangulation) aTriangulation = BRep_Tool::Triangulation (aFace, aLoc);
if (aTriangulation.IsNull())
{
aTriNode.Transform (aTrsf);
continue;
}
aSegments->AddVertex (aTriNode);
if (aNodeIdx != anEdgeNodes.Lower())
const TopoDS_Edge& anEdge = TopoDS::Edge (anEdgeIter.Key());
if (theUpperContinuity < GeomAbs_CN
&& anEdgeIter.Value().Extent() >= 2
&& BRep_Tool::MaxContinuity (anEdge) > theUpperContinuity)
{
aSegments->AddEdge ( aSegmentEdge);
aSegments->AddEdge (++aSegmentEdge);
continue;
}
Handle(Poly_PolygonOnTriangulation) anEdgePoly = BRep_Tool::PolygonOnTriangulation (anEdge, aTriangulation, aLoc);
if (anEdgePoly.IsNull()
|| anEdgePoly->Nodes().Length () < 2)
{
continue;
}
// get edge nodes indexes from face triangulation
++aFaceIndex;
const TColStd_Array1OfInteger& anEdgeNodes = anEdgePoly->Nodes();
const gp_Trsf& aTrsf = aLoc.Transformation();
// collect the edge nodes
Standard_Integer aSegmentEdge = aFirstNodeInFace;
for (Standard_Integer aNodeIdx = anEdgeNodes.Lower(); aNodeIdx <= anEdgeNodes.Upper(); ++aNodeIdx)
{
// node index in face triangulation
// get node and apply location transformation to the node
const Standard_Integer aTriIndex = anEdgeNodes.Value (aNodeIdx);
gp_Pnt aTriNode = aTriangulation->Node (aTriIndex);
gp_Dir aNorm = aTriangulation->Normal (aTriIndex);
if (aFace.Orientation() == TopAbs_REVERSED)
{
aNorm.Reverse();
}
if (!aLoc.IsIdentity())
{
aTriNode.Transform (aTrsf);
aNorm.Transform (aTrsf);
}
if (aFaceIndex == 1)
{
aSegments->AddVertex (aTriNode, aNorm);
if (aNodeIdx != anEdgeNodes.Lower())
{
aSegments->AddEdge (aSegmentEdge);
aSegments->AddEdge (++aSegmentEdge);
}
}
else
{
gp_XYZ aNormSum;
aSegments->VertexNormal (aSegmentEdge, aNormSum.ChangeCoord (1), aNormSum.ChangeCoord (2), aNormSum.ChangeCoord (3));
aNormSum += aNorm.XYZ();
aNormSum.Normalize();
aSegments->SetVertexNormal (aSegmentEdge, aNormSum.ChangeCoord (1), aNormSum.ChangeCoord (2), aNormSum.ChangeCoord (3));
++aSegmentEdge;
}
}
}
}
@ -588,7 +614,13 @@ void StdPrs_ShadedShape::Add (const Handle (Prs3d_Presentation)& thePrs,
if (Handle(Graphic3d_ArrayOfSegments) aBndSegments = fillFaceBoundaries (theShape, theDrawer->FaceBoundaryUpperContinuity()))
{
Handle(Graphic3d_Group) aPrsGrp = !theGroup.IsNull() ? theGroup : thePrs->NewGroup();
aPrsGrp->SetGroupPrimitivesAspect (theDrawer->FaceBoundaryAspect()->Aspect());
Handle(Graphic3d_AspectLine3d) aLineAspect = theDrawer->FaceBoundaryAspect()->Aspect();
if (theDrawer->FaceBoundaryShadingOverride())
{
Quantity_Color aColor = theDrawer->ShadingAspect()->Color();
aLineAspect->SetColor (aColor);
}
aPrsGrp->SetGroupPrimitivesAspect (aLineAspect);
aPrsGrp->AddPrimitiveArray (aBndSegments);
}
}

View File

@ -1713,6 +1713,11 @@ struct ViewerTest_AspectsChangeSet
Standard_Integer ToSetTypeOfFaceBoundaryLine;
Aspect_TypeOfLine TypeOfFaceBoundaryLine;
Standard_Integer ToSetFaceBoundaryShading;
Standard_Integer ToFaceBoundaryEdgeColorOverride;
Graphic3d_TypeOfShadingModel FaceBoundaryShading;
TCollection_AsciiString FaceBoundaryShadingModelName;
Standard_Integer ToSetMaxParamValue;
Standard_Real MaxParamValue;
@ -1787,6 +1792,9 @@ struct ViewerTest_AspectsChangeSet
FaceBoundaryWidth (1.0f),
ToSetTypeOfFaceBoundaryLine(0),
TypeOfFaceBoundaryLine (Aspect_TOL_SOLID),
ToSetFaceBoundaryShading (0),
ToFaceBoundaryEdgeColorOverride (0),
FaceBoundaryShading (Graphic3d_TypeOfShadingModel_DEFAULT),
//
ToSetMaxParamValue (0),
MaxParamValue (500000),
@ -1828,6 +1836,7 @@ struct ViewerTest_AspectsChangeSet
&& ToSetFaceBoundaryUpperContinuity == 0
&& ToSetFaceBoundaryColor == 0
&& ToSetFaceBoundaryWidth == 0
&& ToSetFaceBoundaryShading == 0
&& ToSetTypeOfFaceBoundaryLine == 0
&& ToSetMaxParamValue == 0
&& ToSetSensitivity == 0
@ -1875,6 +1884,12 @@ struct ViewerTest_AspectsChangeSet
Message::SendFail() << "Error: the free boundary width should be within [1; 10] range (specified " << FreeBoundaryWidth << ")";
isOk = Standard_False;
}
if (ToSetFaceBoundaryShading == 1
&& (FaceBoundaryShading < Graphic3d_TypeOfShadingModel_DEFAULT || FaceBoundaryShading > Graphic3d_TypeOfShadingModel_PbrFacet))
{
Message::SendFail() << "Error: unknown face boundary shading model " << FaceBoundaryShadingModelName << ".";
isOk = Standard_False;
}
if (MaxParamValue < 0.0)
{
Message::SendFail() << "Error: the max parameter value should be greater than zero (specified " << MaxParamValue << ")";
@ -2034,6 +2049,16 @@ struct ViewerTest_AspectsChangeSet
theDrawer->FaceBoundaryAspect()->SetWidth (FaceBoundaryWidth);
}
}
if (ToSetFaceBoundaryShading != 0)
{
if (ToSetFaceBoundaryShading != -1
|| theDrawer->HasOwnFaceBoundaryAspect())
{
toRecompute = theDrawer->SetupOwnFaceBoundaryAspect (aDefDrawer) || toRecompute;
theDrawer->FaceBoundaryAspect()->Aspect()->SetShadingModel (FaceBoundaryShading);
theDrawer->SetFaceBoundaryShadingOverride (ToFaceBoundaryEdgeColorOverride);
}
}
if (ToSetTypeOfFaceBoundaryLine != 0)
{
if (ToSetTypeOfFaceBoundaryLine != -1
@ -2389,6 +2414,17 @@ static Standard_Integer VAspects (Draw_Interpretor& theDI,
if (aNames.Size() >= 2
&& aNames.Value (2).IsIntegerValue())
{
if (aNames.Size() == 9 && aNames.Value (9).IsIntegerValue())
{
if (ViewerTest::ParseShadingModel (aNames.Value (8).ToCString(), aChangeSet->FaceBoundaryShading)
&& (aNames.Value (9).IsIntegerValue() == 0 || aNames.Value (9).IsIntegerValue() == 1))
{
aChangeSet->ToSetFaceBoundaryShading = 1;
aChangeSet->ToFaceBoundaryEdgeColorOverride = aNames.Value (9).IsIntegerValue();
aNames.Remove (9);
aNames.Remove (8);
}
}
if (aNames.Size() == 7)
{
if (ViewerTest::ParseLineType (aNames.Value (7).ToCString(), aChangeSet->TypeOfFaceBoundaryLine))
@ -3148,6 +3184,29 @@ static Standard_Integer VAspects (Draw_Interpretor& theDI,
aChangeSet->ToSetShadingModel = -1;
aChangeSet->ShadingModel = Graphic3d_TypeOfShadingModel_DEFAULT;
}
else if (anArg == "-setboundaryshading")
{
aChangeSet->ToSetFaceBoundaryShading = 1;
aChangeSet->FaceBoundaryShadingModelName = theArgVec[++anArgIter];
if (!ViewerTest::ParseShadingModel (theArgVec[anArgIter], aChangeSet->FaceBoundaryShading))
{
Message::SendFail() << "Error: wrong syntax at " << anArg;
return 1;
}
Standard_Integer anOverrideFlag = Draw::Atoi (theArgVec[++anArgIter]);
if (!(anOverrideFlag == 0 || anOverrideFlag == 1))
{
Message::SendFail() << "Error: wrong syntax at " << anArg;
return 1;
}
aChangeSet->ToFaceBoundaryEdgeColorOverride = anOverrideFlag;
}
else if (anArg == "-unsetboundaryshading")
{
aChangeSet->ToSetFaceBoundaryShading = -1;
aChangeSet->ToFaceBoundaryEdgeColorOverride = 0;
aChangeSet->FaceBoundaryShading = Graphic3d_TypeOfShadingModel_Unlit;
}
else if (anArg == "-setinterior"
|| anArg == "-setinteriorstyle"
|| anArg == "-interior"
@ -3272,6 +3331,8 @@ static Standard_Integer VAspects (Draw_Interpretor& theDI,
aChangeSet->FaceBoundaryWidth = 1.0f;
aChangeSet->ToSetTypeOfFaceBoundaryLine = -1;
aChangeSet->TypeOfFaceBoundaryLine = Aspect_TOL_SOLID;
aChangeSet->ToSetFaceBoundaryShading = -1;
aChangeSet->FaceBoundaryShading = Graphic3d_TypeOfShadingModel_DEFAULT;
//
aChangeSet->ToSetHatch = -1;
aChangeSet->StdHatchStyle = -1;
@ -6804,6 +6865,8 @@ vaspects [-noupdate|-update] [name1 [name2 [...]] | -defaults] [-subshapes subna
[-sensitivity {selection_mode} {value}]
[-shadingModel {unlit|flat|gouraud|phong|pbr|pbr_facet}]
[-unsetShadingModel]
[-setboundaryshading {unlit|flat|gouraud|phong|pbr|pbr_facet}]
[-unsetboundaryshading]
[-interior {solid|hatch|hidenline|point}] [-setHatch HatchStyle]
[-unsetInterior]
[-faceBoundaryDraw {0|1}] [-mostContinuity {c0|g1|c1|g2|c2|c3|cn}]

View File

@ -1197,7 +1197,7 @@ static Standard_Integer XShowFaceBoundary (Draw_Interpretor& di,
Standard_Integer argc,
const char ** argv)
{
if (( argc != 4 && argc < 7 ) || argc > 9)
if (( argc != 4 && argc < 7 ) || argc > 11)
{
di << "Usage :\n " << argv[0]
<< " Doc Label IsOn [R G B [LineWidth [LineStyle]]]\n"
@ -1216,7 +1216,11 @@ static Standard_Integer XShowFaceBoundary (Draw_Interpretor& di,
<< " 1 - dashed \n"
<< " 2 - dot \n"
<< " 3 - dashdot\n"
<< " (default is solid)";
<< " (default is solid)\n"
<< " Shading - flag indicating if the boundaries\n"
<< " should be shaded:"
<< " 0 - no override edge color"
<< " 1 - override edge color";
return 1;
}
@ -1310,6 +1314,17 @@ static Standard_Integer XShowFaceBoundary (Draw_Interpretor& di,
aDrawer->SetFaceBoundaryAspect (aBoundaryAspect);
// set shading properties for face boundaries
if (argc == 11)
{
Graphic3d_TypeOfShadingModel aShadingModel;
if (ViewerTest::ParseShadingModel (argv[9], aShadingModel))
{
aDrawer->FaceBoundaryAspect()->Aspect()->SetShadingModel (aShadingModel);
aDrawer->SetFaceBoundaryShadingOverride (Draw::Atoi (argv[10]) == 1 ? Standard_True : Standard_False);
}
}
aContext->Redisplay (anInteractive, Standard_True);
return 0;

40
tests/v3d/bugs/bug26072 Normal file
View File

@ -0,0 +1,40 @@
puts "========"
puts "0026072: Visualization - more realistic display of face edges"
puts "========"
pload MODELING VISUALIZATION XDE
testreadstep [locate_data_file as1-oc-214-mat.stp] s
vclear
vinit
vdisplay s -dispmode 1
vfit
vshowfaceboundary s -setboundaryshading phong 1 -boundarycolor 50 250 50
vviewparams -scale 4.0 -proj 1.0 1.0 1.0 -up -1.0 -1.0 0.0 -at 20.0 0.0 -20.0
vdump $::imagedir/${::casename}_shading_1.png
vviewparams -scale 4.0 -proj 2.0 -1.5 3.0 -up 0.0 1.0 1.0 -at 20.0 130.0 -50.0
vdump $::imagedir/${::casename}_shading_2.png
vshowfaceboundary s -setboundaryshading phong 0 -boundarycolor 50 250 50
vviewparams -scale 4.0 -proj 1.0 1.0 1.0 -up -1.0 -1.0 0.0 -at 20.0 0.0 -20.0
vdump $::imagedir/${::casename}_noshading_1.png
vviewparams -scale 4.0 -proj 2.0 -1.5 3.0 -up 0.0 1.0 1.0 -at 20.0 130.0 -50.0
vdump $::imagedir/${::casename}_noshading_2.png
vclear
vclose
ReadStep D [locate_data_file as1-oc-214-mat.stp]
XShow D
vfit
vsetdispmode 1
XShowFaceBoundary D 0:1:1:1 1 156 156 156 1 0 phong 1
vviewparams -scale 4.0 -proj 1.0 1.0 1.0 -up -1.0 -1.0 0.0 -at 20.0 0.0 -20.0
vdump $::imagedir/${::casename}_xview_shading_1.png
vviewparams -scale 4.0 -proj 2.0 -1.5 3.0 -up 0.0 1.0 1.0 -at 20.0 130.0 -50.0
vdump $::imagedir/${::casename}_xview_shading_2.png
XShowFaceBoundary D 0:1:1:1 1 156 156 156 1 0 phong 0
vviewparams -scale 4.0 -proj 1.0 1.0 1.0 -up -1.0 -1.0 0.0 -at 20.0 0.0 -20.0
vdump $::imagedir/${::casename}_xview_noshading_1.png
vviewparams -scale 4.0 -proj 2.0 -1.5 3.0 -up 0.0 1.0 1.0 -at 20.0 130.0 -50.0
vdump $::imagedir/${::casename}_xview_noshading_2.png