Add algorithm to show direction of edges.
Two view windows
+The viewer is able to show direction of edges of objects.
+
+.. figure:: /images/edges_directions.png
+ :align: center
+
+ Showing the edges direction
+
The description of OCC 3D Viewer architecture and functionality is provided in GUI module user's guide in chapter **OCC 3D Viewer**.
.. _parameter_usage:
// trim: need to redisplay or set color in the python script
if (myObject && (theAttr->attributeType() == "Point2D" || theAttr->id() == "Color" ||
theAttr->id() == "Transparency" || theAttr->id() == "Deflection" ||
- theAttr->id() == "Iso_lines" || theAttr->id() == "Show_Iso_lines")) {
+ theAttr->id() == "Iso_lines" || theAttr->id() == "Show_Iso_lines" ||
+ theAttr->id() == "Show_Edges_direction")) {
static const Events_ID anEvent = Events_Loop::eventByName(EVENT_OBJECT_TO_REDISPLAY);
ModelAPI_EventCreator::get()->sendUpdated(myObject, anEvent);
}
aData->addAttribute(ISO_LINES_ID(), ModelAPI_AttributeIntArray::typeId())->setIsArgument(false);
aData->addAttribute(SHOW_ISO_LINES_ID(), ModelAPI_AttributeBoolean::typeId())->
setIsArgument(false);
+ aData->addAttribute(SHOW_EDGES_DIRECTION_ID(), ModelAPI_AttributeBoolean::typeId())->
+ setIsArgument(false);
}
bool ModelAPI_Result::setDisabled(std::shared_ptr<ModelAPI_Result> theThis, const bool theFlag)
return MY_SHOW_ISO_LINES_ID;
}
+ /// Reference to the transparency of the result.
+ /// The double value is used. The value is in [0, 1] range
+ inline static const std::string& SHOW_EDGES_DIRECTION_ID()
+ {
+ static const std::string MY_SHOW_EDGES_DIRECTION_ID("Show_Edges_direction");
+ return MY_SHOW_EDGES_DIRECTION_ID;
+ }
+
/// Returns true if the result is concealed from the data tree (referenced by other objects)
MODELAPI_EXPORT virtual bool isConcealed();
return false;
}
+//******************************************************
+void showEdgesDirection(std::shared_ptr<ModelAPI_Result> theResult, bool theShow)
+{
+ if (!theResult.get())
+ return;
+
+ AttributeBooleanPtr aAttr = theResult->data()->boolean(ModelAPI_Result::SHOW_EDGES_DIRECTION_ID());
+ if (aAttr.get() != NULL) {
+ aAttr->setValue(theShow);
+ }
+}
+
+//******************************************************
+bool isShowEdgesDirection(std::shared_ptr<ModelAPI_Result> theResult)
+{
+ if (!theResult.get())
+ return false;
+
+ AttributeBooleanPtr aAttr = theResult->data()->boolean(ModelAPI_Result::SHOW_EDGES_DIRECTION_ID());
+ if (aAttr.get() != NULL) {
+ return aAttr->value();
+ }
+ return false;
+}
+
//**************************************************************
void setTransparency(ResultPtr theResult, double theTransparency)
{
MODELAPI_EXPORT bool isShownIsoLines(std::shared_ptr<ModelAPI_Result> theResult);
+/*! Set visibility of edges direction
+* \param[in] theResult a result object
+* \param[in] theShow is a visibility flag
+*/
+MODELAPI_EXPORT void showEdgesDirection(std::shared_ptr<ModelAPI_Result> theResult, bool theShow);
+
+MODELAPI_EXPORT bool isShowEdgesDirection(std::shared_ptr<ModelAPI_Result> theResult);
+
/*! Returns current transparency in the given result
* \param theResult a result object
* \return a transparency value or -1 if it was not defined
--- /dev/null
+// Copyright (C) 2014-2022 CEA/DEN, EDF R&D
+//
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2.1 of the License, or (at your option) any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+//
+// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
+//
+
+#include "ModuleBase_ArrowPrs.h"
+
+#include <Prs3d_ArrowAspect.hxx>
+
+#include <Events_Loop.h>
+#include <ModelAPI_Events.h>
+
+#include <BRep_Builder.hxx>
+#include <BRep_Tool.hxx>
+#include <GCPnts_AbscissaPoint.hxx>
+#include <GeomAdaptor_Curve.hxx>
+#include <Prs3d_Arrow.hxx>
+#include <TopoDS_Edge.hxx>
+#include <TopoDS_Vertex.hxx>
+#include <TopExp.hxx>
+
+
+IMPLEMENT_STANDARD_RTTIEXT(ModuleBase_ArrowPrs, AIS_InteractiveContext)
+
+
+ModuleBase_ArrowPrs::ModuleBase_ArrowPrs(const Handle(V3d_Viewer)& theViewer,
+ const GeomEdgePtr& theEdge)
+ : AIS_InteractiveContext(theViewer),
+ myEdge(theEdge)
+{
+}
+
+//********************************************************************
+void ModuleBase_ArrowPrs::DrawArrow(const Handle(Prs3d_Presentation)& thePrs,
+ Quantity_Color theColor)
+{
+ Handle(Prs3d_Drawer) aDrawer = myDefaultDrawer;
+ Handle(Prs3d_ArrowAspect) anArrowAspect = aDrawer->ArrowAspect();
+
+ Handle(Graphic3d_AspectLine3d) PtA = anArrowAspect->Aspect();
+ PtA->SetColor(theColor);
+
+ Handle(Graphic3d_Group) TheGroup = thePrs->CurrentGroup();
+ TheGroup->SetPrimitivesAspect(PtA);
+
+ TopoDS_Vertex aV1, aV2;
+ TopoDS_Edge anEdgeE = myEdge->impl<TopoDS_Edge>();
+ anEdgeE.Orientation(TopAbs_FORWARD);
+ if (anEdgeE.IsNull()) return;
+
+ TopExp::Vertices(anEdgeE, aV1, aV2);
+ gp_Pnt aP1 = BRep_Tool::Pnt(aV1);
+ gp_Pnt aP2 = BRep_Tool::Pnt(aV2);
+
+ double fp, lp;
+ gp_Vec aDirVec;
+ Handle(Geom_Curve) C = BRep_Tool::Curve(anEdgeE, fp, lp);
+
+ if (C.IsNull()) return;
+
+ if (anEdgeE.Orientation() == TopAbs_FORWARD)
+ C->D1(lp, aP2, aDirVec);
+ else {
+ C->D1(fp, aP1, aDirVec);
+ aP2 = aP1;
+ }
+
+ GeomAdaptor_Curve aAdC;
+ aAdC.Load(C, fp, lp);
+ Standard_Real aDist = GCPnts_AbscissaPoint::Length(aAdC, fp, lp);
+
+ if (aDist > gp::Resolution()) {
+ gp_Dir aDir;
+ if (anEdgeE.Orientation() == TopAbs_FORWARD)
+ aDir = aDirVec;
+ else
+ aDir = -aDirVec;
+
+ TopoDS_Vertex aVertex;
+ BRep_Builder aB;
+ aB.MakeVertex(aVertex, aP2, Precision::Confusion());
+ Prs3d_Arrow::Draw(TheGroup, aP2, aDir, M_PI / 180. * 5., aDist / 10.);
+ }
+}
+
+//********************************************************************
+bool ModuleBase_ArrowPrs::Comparator::operator()(const std::shared_ptr<GeomAPI_Edge>& theEdge1,
+ const std::shared_ptr<GeomAPI_Edge>& theEdge2) const
+{
+ const TopoDS_Edge& aShape1 = theEdge1->impl<TopoDS_Edge>();
+ const TopoDS_Edge& aShape2 = theEdge2->impl<TopoDS_Edge>();
+ bool isLess = aShape1.TShape() < aShape2.TShape();
+ if (aShape1.TShape() == aShape2.TShape()) {
+ Standard_Integer aHash1 = aShape1.Location().HashCode(IntegerLast());
+ Standard_Integer aHash2 = aShape2.Location().HashCode(IntegerLast());
+ isLess = aHash1 < aHash2;
+ }
+ return isLess;
+}
--- /dev/null
+// Copyright (C) 2014-2022 CEA/DEN, EDF R&D
+//
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2.1 of the License, or (at your option) any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+//
+// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
+//
+
+#ifndef ModuleBase_ArrowPrs_H
+#define ModuleBase_ArrowPrs_H
+
+#include <ModuleBase.h>
+#include <GeomAPI_Edge.h>
+#include <AIS_InteractiveContext.hxx>
+
+#include <map>
+
+DEFINE_STANDARD_HANDLE(ModuleBase_ArrowPrs, AIS_InteractiveContext)
+
+/**
+* \ingroup GUI
+* A presentation class for displaying a direction of edge
+*/
+
+class ModuleBase_ArrowPrs : public AIS_InteractiveContext
+{
+public:
+ /// Constructor
+ /// \param theViewer a viewer which theEdge is displaying.
+ /// \param theEdge an edge whose direction to display.
+ Standard_EXPORT ModuleBase_ArrowPrs(const Handle(V3d_Viewer)& theViewer,
+ const GeomEdgePtr& theEdge);
+
+ /// Returns an edge shape
+ GeomEdgePtr Edge() const { return myEdge; }
+
+ /// Draw arrow that represent direction of the edge.
+ Standard_EXPORT void DrawArrow(const Handle(Prs3d_Presentation)& thePrs, Quantity_Color theColor);
+
+ /// \brief Compare addresses of edges
+ class Comparator
+ {
+ public:
+ /// Return \c true if the address of the first edge is less than the address of the second
+ MODULEBASE_EXPORT
+ bool operator ()(const std::shared_ptr<GeomAPI_Edge>& theEdge1,
+ const std::shared_ptr<GeomAPI_Edge>& theEdge2) const;
+ };
+
+ DEFINE_STANDARD_RTTIEXT(ModuleBase_ArrowPrs, AIS_InteractiveContext)
+
+private:
+
+ /// The edge whose direction to display.
+ GeomEdgePtr myEdge;
+};
+
+typedef std::pair<GeomEdgePtr, Handle(ModuleBase_ArrowPrs)> EdgeDirection;
+typedef std::map<GeomEdgePtr, Handle(ModuleBase_ArrowPrs), ModuleBase_ArrowPrs::Comparator> EdgesDirectionMap;
+
+#endif
\ No newline at end of file
#include <TopoDS_Edge.hxx>
#include <BRepMesh_IncrementalMesh.hxx>
#include <Standard_Version.hxx>
+#include <Prs3d_Arrow.hxx>
+#include <GeomAdaptor_Curve.hxx>
+#include <TopExp.hxx>
+#include <GCPnts_AbscissaPoint.hxx>
#if OCC_VERSION_HEX > 0x070400
#include <StdPrs_ToolTriangulatedShape.hxx>
catch (...) {
return;
}
+ if (myResult.get() && ModelAPI_Tools::isShowEdgesDirection(myResult))
+ {
+ TopExp_Explorer Exp(myshape, TopAbs_EDGE);
+ for (; Exp.More(); Exp.Next()) {
+ TopoDS_Edge anEdgeE = TopoDS::Edge(Exp.Current());
+ if (anEdgeE.IsNull())
+ continue;
+
+ // draw curve direction (issue 0021087)
+ anEdgeE.Orientation(TopAbs_FORWARD);
+
+ TopoDS_Vertex aV1, aV2;
+ TopExp::Vertices(anEdgeE, aV1, aV2);
+ gp_Pnt aP1 = BRep_Tool::Pnt(aV1);
+ gp_Pnt aP2 = BRep_Tool::Pnt(aV2);
+
+ double fp, lp;
+ gp_Vec aDirVec;
+ Handle(Geom_Curve) C = BRep_Tool::Curve(anEdgeE, fp, lp);
+
+ if (C.IsNull()) continue;
+
+ if (anEdgeE.Orientation() == TopAbs_FORWARD)
+ C->D1(lp, aP2, aDirVec);
+ else {
+ C->D1(fp, aP1, aDirVec);
+ aP2 = aP1;
+ }
+ GeomAdaptor_Curve aAdC;
+ aAdC.Load(C, fp, lp);
+ Standard_Real aDist = GCPnts_AbscissaPoint::Length(aAdC, fp, lp);
+
+ if (aDist > gp::Resolution()) {
+ gp_Dir aDir;
+ if (anEdgeE.Orientation() == TopAbs_FORWARD)
+ aDir = aDirVec;
+ else
+ aDir = -aDirVec;
+
+ Prs3d_Arrow::Draw(thePresentation->CurrentGroup(), aP2, aDir, M_PI / 180.*5., aDist / 10.);
+ }
+ }
+ }
// visualize hidden sub-shapes transparent
if (myResult.get()) {
aDesktop);
addAction("WIREFRAME_CMD", anAction);
+ anAction = ModuleBase_Tools::createAction(QIcon(":pictures/edges_dir.png"), tr("Show edges direction"),
+ aDesktop);
+ anAction->setCheckable(true);
+ addAction("SHOW_EDGES_DIRECTION_CMD", anAction);
+
anAction = ModuleBase_Tools::createAction(QIcon(":pictures/iso_lines.png"), tr("Define Isos..."),
aDesktop);
addAction("ISOLINES_CMD", anAction);
action("WIREFRAME_CMD")->setEnabled(true);
action("SHADING_CMD")->setEnabled(true);
}
+ action("SHOW_EDGES_DIRECTION_CMD")->setEnabled(true);
+ action("SHOW_EDGES_DIRECTION_CMD")->setChecked(ModelAPI_Tools::isShowEdgesDirection(aResult));
+
action("SHOW_ISOLINES_CMD")->setEnabled(true);
action("SHOW_ISOLINES_CMD")->setChecked(ModelAPI_Tools::isShownIsoLines(aResult));
action("ISOLINES_CMD")->setEnabled(true);
action("SHOW_ONLY_CMD")->setEnabled(true);
action("SHADING_CMD")->setEnabled(true);
action("WIREFRAME_CMD")->setEnabled(true);
+ action("SHOW_EDGES_DIRECTION_CMD")->setEnabled(true);
action("SHOW_ISOLINES_CMD")->setEnabled(true);
action("ISOLINES_CMD")->setEnabled(true);
}
if (aResult.get()) {
action("SHOW_ISOLINES_CMD")->setEnabled(true);
action("SHOW_ISOLINES_CMD")->setChecked(ModelAPI_Tools::isShownIsoLines(aResult));
+
+ action("SHOW_EDGES_DIRECTION_CMD")->setEnabled(true);
+ action("SHOW_EDGES_DIRECTION_CMD")->setChecked(
+ ModelAPI_Tools::isShowEdgesDirection(aResult));
}
}
}
aList.clear();
aList.append(action("WIREFRAME_CMD"));
aList.append(action("SHADING_CMD"));
+ aList.append(action("SHOW_EDGES_DIRECTION_CMD"));
aList.append(mySeparator1); // this separator is not shown as this action is added after show only
// qt list container contains only one instance of the same action
aList.append(action("SHOW_CMD"));
aList.clear();
aList.append(action("WIREFRAME_CMD"));
aList.append(action("SHADING_CMD"));
+ aList.append(action("SHOW_EDGES_DIRECTION_CMD"));
aList.append(mySeparator1); // this separator is not shown as this action is added after show only
// qt list container contains only one instance of the same action
aList.append(action("SHOW_CMD"));
aList.clear();
aList.append(action("WIREFRAME_CMD"));
aList.append(action("SHADING_CMD"));
+ aList.append(action("SHOW_EDGES_DIRECTION_CMD"));
aList.append(mySeparator2);
aList.append(action("COLOR_CMD"));
aList.append(action("DEFLECTION_CMD"));
} else if (aSelected > 1) {
anActions.append(action("WIREFRAME_CMD"));
anActions.append(action("SHADING_CMD"));
+ anActions.append(action("SHOW_EDGES_DIRECTION_CMD"));
anActions.append(mySeparator1);
anActions.append(action("SHOW_CMD"));
anActions.append(action("HIDE_CMD"));
setDisplayMode(anObjects, XGUI_Displayer::Shading);
else if (theId == "WIREFRAME_CMD")
setDisplayMode(anObjects, XGUI_Displayer::Wireframe);
+ else if (theId == "SHOW_EDGES_DIRECTION_CMD")
+ toggleEdgesDirection(anObjects);
else if (theId == "HIDEALL_CMD") {
QObjectPtrList aList = myDisplayer->displayedObjects();
foreach (ObjectPtr aObj, aList) {
myDisplayer->updateViewer();
}
+//**************************************************************
+void XGUI_Workshop::toggleEdgesDirection(const QObjectPtrList& theList)
+{
+ foreach(ObjectPtr anObj, theList) {
+ ResultPtr aResult = std::dynamic_pointer_cast<ModelAPI_Result>(anObj);
+ if (aResult.get() != NULL)
+ {
+ bool aToShow = !ModelAPI_Tools::isShowEdgesDirection(aResult);
+ ResultBodyPtr aBodyResult = std::dynamic_pointer_cast<ModelAPI_ResultBody>(aResult);
+ if (aBodyResult.get() != NULL) { // change property for all sub-solids
+ std::list<ResultPtr> allRes;
+ ModelAPI_Tools::allSubs(aBodyResult, allRes);
+ std::list<ResultPtr>::iterator aRes;
+ for (aRes = allRes.begin(); aRes != allRes.end(); aRes++) {
+ ModelAPI_Tools::showEdgesDirection(*aRes, aToShow);
+ myDisplayer->redisplay(*aRes, false);
+ }
+ }
+ ModelAPI_Tools::showEdgesDirection(aResult, aToShow);
+ myDisplayer->redisplay(anObj, false);
+ }
+ }
+ if (theList.size() > 0)
+ myDisplayer->updateViewer();
+}
+
//**************************************************************
void XGUI_Workshop::closeDocument()
{
/// \param theMode a mode to set (see \ref XGUI_Displayer)
void setDisplayMode(const QObjectPtrList& theList, int theMode);
+ /// Toggle visualisation of edges direction
+ void toggleEdgesDirection(const QObjectPtrList& theList);
+
/// Set selection mode in viewer. If theMode=-1 then activate default mode
/// \param theMode the selection mode (according to TopAbs_ShapeEnum)
void setViewerSelectionMode(int theMode);
<source>Recover</source>
<translation>Récupérer</translation>
</message>
+ <message>
+ <source>Show edges direction</source>
+ <translation>Afficher la direction des bords</translation>
+ </message>
</context>
<context>
<name>XGUI_DataTree</name>
<file>pictures/CrossCursor.png</file>
<file>pictures/HandCursor.png</file>
<file>pictures/iso_lines.png</file>
+ <file>pictures/edges_dir.png</file>
</qresource>
</RCC>