From: dish Date: Tue, 19 Nov 2024 02:05:58 +0000 (+0000) Subject: [bos #35154][EDF](2023-T1) Edge thickness. X-Git-Url: http://git.salome-platform.org/gitweb/?a=commitdiff_plain;h=refs%2Fheads%2Fdish%2FCR35154--Edge_Thickness3;p=modules%2Fshaper.git [bos #35154][EDF](2023-T1) Edge thickness. Add edge thickness feature. Edge thickness can be assigned to any shapes and subshapes, except vertices. If different edge thickness values assigned both to a shape and to its subshape, subshape value overrides shape value. Thickness data (de)serialized into xCAF and TUI.py files. --- diff --git a/src/GeomAlgoAPI/GeomAlgoAPI_STEPImportXCAF.cpp b/src/GeomAlgoAPI/GeomAlgoAPI_STEPImportXCAF.cpp index 30f06dbf3..409cf7bcd 100644 --- a/src/GeomAlgoAPI/GeomAlgoAPI_STEPImportXCAF.cpp +++ b/src/GeomAlgoAPI/GeomAlgoAPI_STEPImportXCAF.cpp @@ -171,6 +171,30 @@ void setColors(std::shared_ptr theResultBody) } } +void setEdgeThicknessValues(std::shared_ptr theResultBody) +{ + TopoDS_Shape aShape = theResultBody->shape()->impl(); + TopExp_Explorer anExp(aShape, TopAbs_SOLID); // TODO Should it be everything, except VERTEX? + while (anExp.More()) { + auto aSolid = anExp.Current(); + + std::shared_ptr aGeomShape(new GeomAPI_Shape); + aGeomShape->setImpl(new TopoDS_Shape(aSolid)); + auto aName = theResultBody->findShapeName(aGeomShape); + + if (!aName.empty()) { + auto aColor = theResultBody->findShapeColor(aName); // TODO + + if (!aColor.empty()) + theResultBody->setSubShapeColor(theResultBody, aGeomShape, { 128, 222, 2 }); // TODO + else + theResultBody->setSubShapeColor(theResultBody, aGeomShape, { 255, 0, 0 }); // TODO + + } + anExp.Next(); + } +} + //============================================================================= std::shared_ptr setGeom(const Handle(XCAFDoc_ShapeTool) &theShapeTool, const TDF_Label& /*theLabel*/, diff --git a/src/GeomAlgoAPI/GeomAlgoAPI_STEPImportXCAF.h b/src/GeomAlgoAPI/GeomAlgoAPI_STEPImportXCAF.h index d8674a696..b4c57a7f9 100644 --- a/src/GeomAlgoAPI/GeomAlgoAPI_STEPImportXCAF.h +++ b/src/GeomAlgoAPI/GeomAlgoAPI_STEPImportXCAF.h @@ -34,4 +34,7 @@ std::shared_ptr readAttributes(STEPCAFControl_Reader &theReader, std::string& theError); GEOMALGOAPI_EXPORT void setColors(std::shared_ptr theResultBody); + +GEOMALGOAPI_EXPORT void setEdgeThicknessValues(std::shared_ptr theResultBody); + #endif /* GEOMALGOAPI_STEPIMPORTXCAF_H_ */ diff --git a/src/Model/Model_Objects.cpp b/src/Model/Model_Objects.cpp index d7d6190d5..9675b4c3d 100644 --- a/src/Model/Model_Objects.cpp +++ b/src/Model/Model_Objects.cpp @@ -54,6 +54,7 @@ #include #include #include +#include // relocate to other file #include @@ -112,6 +113,8 @@ static const int TAG_RESULT_SHAPES = 2; ///< where the shapes are located /// 0:1:2:N:2:K:1 - data of the K result of the feature N /// 0:1:2:N:2:K:2:M:1 - data of the M shape of the K result of the feature N +/*static*/ const Standard_GUID Model_Objects::GUID_EDGE_THICKNESS = Standard_GUID("9b31b32b-aaba-37c7-b8f0-58b793d81dd9"); + Model_Objects::Model_Objects(TDF_Label theMainLab) : myMain(theMainLab) { } @@ -814,6 +817,17 @@ void Model_Objects::setAttribute(const Handle(TDF_Attribute)& theAttribute, static const Events_ID anEvent = Events_Loop::eventByName(EVENT_OBJECT_UPDATED); ModelAPI_EventCreator::get()->sendUpdated(theResult, anEvent); } + else if (theAttribute->ID() == Model_Objects::GUID_EDGE_THICKNESS) { + Handle(TDataStd_Integer) aThicknessAttr; + Handle(TDataStd_Integer) anAttr = Handle(TDataStd_Integer)::DownCast(theAttribute); + + if (anAttributeLabel.FindAttribute(Model_Objects::GUID_EDGE_THICKNESS, aThicknessAttr)) + anAttributeLabel.ForgetAttribute(Model_Objects::GUID_EDGE_THICKNESS); + + anAttributeLabel.AddAttribute(anAttr); + static const Events_ID anEvent = Events_Loop::eventByName(EVENT_OBJECT_UPDATED); + ModelAPI_EventCreator::get()->sendUpdated(theResult, anEvent); + } } Handle(TDF_Attribute) Model_Objects::getAttribute(const Standard_GUID& theID, @@ -823,21 +837,80 @@ Handle(TDF_Attribute) Model_Objects::getAttribute(const Standard_GUID& theID, ResultBodyPtr aMain = std::dynamic_pointer_cast(theResult); aMain = ModelAPI_Tools::mainBody(aMain); - int anIndex = index(theResult, theShape); - Handle(TDataStd_IntegerArray) anColor; + const int anIndex = index(theResult, theShape); + if (anIndex == -1) + return opencascade::handle(nullptr); + + TDF_Label aResultLabel; + if (aMain.get()) + aResultLabel = resultLabel(theResult->data(), index(aMain)); + else + aResultLabel = resultLabel(theResult->data(), index(theResult)); + + TDF_Label anAttributeLabel = subShapeLabel(aResultLabel, anIndex).FindChild(TAG_FEATURE_ARGUMENTS); - if (anIndex != -1) + Handle(TDF_Attribute) anAttr; + anAttributeLabel.FindAttribute(theID, anAttr); + return anAttr; +} + +void Model_Objects::getSubShapesWithEdgeThickness( + const std::shared_ptr theResult, + std::map, int>& oShapes +) const { + ResultBodyPtr aMainBody = std::dynamic_pointer_cast(theResult); + aMainBody = ModelAPI_Tools::mainBody(aMainBody); + TDF_Label aShapesLabel; + if (aMainBody.get()) + aShapesLabel = shapesFromResult(resultLabel(theResult->data(), index(aMainBody))); + else + aShapesLabel = shapesFromResult(resultLabel(theResult->data(), index(theResult))); + + for (TDF_ChildIterator aChilds(aShapesLabel); aChilds.More(); aChilds.Next()) { - TDF_Label aResultLabel; - if (aMain.get()) - aResultLabel = resultLabel(theResult->data(), index(aMain)); - else - aResultLabel = resultLabel(theResult->data(), index(theResult)); + TDF_Label aCurSubShape = aChilds.Value(); + Handle(TNaming_NamedShape) aNamedShape; + aCurSubShape.FindAttribute(TNaming_NamedShape::GetID(), aNamedShape); + if (aNamedShape.IsNull()) + continue; + + std::shared_ptr aSub(new GeomAPI_Shape); + aSub->setImpl(new TopoDS_Shape(aNamedShape->Get())); + + Handle(TDataStd_Integer) aEdgeThicknessAttr; + aCurSubShape.FindChild(TAG_FEATURE_ARGUMENTS).FindAttribute(Model_Objects::GUID_EDGE_THICKNESS, aEdgeThicknessAttr); + if (aEdgeThicknessAttr.IsNull()) + continue; + + oShapes[aSub] = aEdgeThicknessAttr->Get(); + } +} + +void Model_Objects::removeSubShapeEdgeThickness(const std::shared_ptr theResult) const +{ + ResultBodyPtr aMainBody = std::dynamic_pointer_cast(theResult); + aMainBody = ModelAPI_Tools::mainBody(aMainBody); + + TDF_Label aShapesLabel; + if (aMainBody.get()) + aShapesLabel = shapesFromResult(resultLabel(theResult->data(), index(aMainBody))); + else + { + ResultPartPtr aResPart = std::dynamic_pointer_cast(theResult); + if (!aResPart.get()) + return; + aShapesLabel = shapesFromResult(resultLabel(theResult->data(), index(aResPart))); + } + for (TDF_ChildIterator aChilds(aShapesLabel); aChilds.More(); aChilds.Next()) + { + TDF_Label aCurSubShape = aChilds.Value(); + Handle(TNaming_NamedShape) aNamedShape; + aCurSubShape.FindAttribute(TNaming_NamedShape::GetID(), aNamedShape); + if (aNamedShape.IsNull()) + continue; - TDF_Label anAttributeLabel = subShapeLabel(aResultLabel, anIndex).FindChild(TAG_FEATURE_ARGUMENTS); - anAttributeLabel.FindAttribute(TDataStd_IntegerArray::GetID(), anColor); + aCurSubShape.FindChild(TAG_FEATURE_ARGUMENTS).ForgetAttribute(Model_Objects::GUID_EDGE_THICKNESS); } - return anColor; } void Model_Objects::getColoredShapes(const std::shared_ptr theResult, diff --git a/src/Model/Model_Objects.h b/src/Model/Model_Objects.h index 364a3dddd..f3e0c511d 100644 --- a/src/Model/Model_Objects.h +++ b/src/Model/Model_Objects.h @@ -36,6 +36,10 @@ extern int kUNDEFINED_FEATURE_INDEX; + +class Standard_GUID; + + /**\class Model_Objects * \ingroup DataModel * \brief Manager of objects of the document. Normally one this class corresponds to @@ -45,6 +49,8 @@ extern int kUNDEFINED_FEATURE_INDEX; class Model_Objects { public: + static const Standard_GUID GUID_EDGE_THICKNESS; + //! Registers the feature in the data structure //! \param theFeature feature that must be added to the data structure //! \param theAfterThis the feature will be added after this feature; @@ -199,6 +205,13 @@ class Model_Objects std::shared_ptr theResult, std::shared_ptr theShape); + void getSubShapesWithEdgeThickness( + const std::shared_ptr theResult, + std::map, int>& oShapes + ) const; + + void removeSubShapeEdgeThickness(const std::shared_ptr theResult) const; + //! Get colored shapes from result void getColoredShapes(const std::shared_ptr theResult, std::map, std::vector>& theColoredShapes); diff --git a/src/Model/Model_ResultBody.cpp b/src/Model/Model_ResultBody.cpp index 6dc5538ef..1956b7696 100644 --- a/src/Model/Model_ResultBody.cpp +++ b/src/Model/Model_ResultBody.cpp @@ -39,6 +39,7 @@ #include #include #include +#include #include #include #include @@ -255,6 +256,56 @@ void Model_ResultBody::updateConcealment() } } +void Model_ResultBody::setSubShapeEdgeThickness( + const std::shared_ptr theResult, + const std::shared_ptr theSubShape, + int theEdgeThickness +) +{ + TopoDS_Shape aShape = shape()->impl(); + TopoDS_Shape aSubShape = theSubShape->impl(); + if (!shape()->isSubShape(theSubShape)) + return; + + Model_Objects* anObjects = std::dynamic_pointer_cast(document())->objects(); + document()->storeShape(data(), theResult, theSubShape); + + Handle(TDataStd_Integer) aThickness = new TDataStd_Integer(); + aThickness->SetID(Model_Objects::GUID_EDGE_THICKNESS); + aThickness->Set(theEdgeThickness); + anObjects->setAttribute(aThickness, theResult, theSubShape); +} + +int Model_ResultBody::getSubShapeEdgeThickness(const std::shared_ptr theResult, const std::shared_ptr theSubShape) const +{ + TopoDS_Shape aShape = shape()->impl(); + TopoDS_Shape aSubShape = theSubShape->impl(); + if (!shape()->isSubShape(theSubShape)) + return -1; + + Model_Objects* anObjects = std::dynamic_pointer_cast(document())->objects(); + auto anAttr = Handle(TDataStd_Integer)::DownCast(anObjects->getAttribute(Model_Objects::GUID_EDGE_THICKNESS, theResult, theSubShape)); + if (anAttr.IsNull()) + return -1; + + return anAttr->Get(); +} + +void Model_ResultBody::getSubShapesWithEdgeThickness( + const std::shared_ptr theResult, + std::map, int>& oShapes +) const +{ + Model_Objects* anObjects = std::dynamic_pointer_cast(document())->objects(); + anObjects->getSubShapesWithEdgeThickness(theResult, oShapes); +} + +void Model_ResultBody::removeSubShapeEdgeThickness(const std::shared_ptr theResult) +{ + Model_Objects* anObjects = std::dynamic_pointer_cast(document())->objects(); + anObjects->removeSubShapeEdgeThickness(theResult); +} + void Model_ResultBody::addShapeColor( const std::wstring& theName,std::vector& color) { if (myColorsShape.find(theName) == myColorsShape.end()) diff --git a/src/Model/Model_ResultBody.h b/src/Model/Model_ResultBody.h index 3f5727e5d..7ff38f672 100644 --- a/src/Model/Model_ResultBody.h +++ b/src/Model/Model_ResultBody.h @@ -139,6 +139,21 @@ protected: /// Checks the state of children and parents to send events of creation/erase when needed void updateConcealment(); + void setSubShapeEdgeThickness( + const std::shared_ptr theResult, + const std::shared_ptr theSubShape, + int theEdgeThickness + ); + + int getSubShapeEdgeThickness(const std::shared_ptr theResult, const std::shared_ptr theSubShape) const; + + void getSubShapesWithEdgeThickness( + const std::shared_ptr theResult, + std::map, int>& oSubShapes + ) const; + + void removeSubShapeEdgeThickness(const std::shared_ptr theResult); + /// Adds to theOldForSub only old shapes that where used for theSub creation void computeOldForSub(const GeomShapePtr& theSub, const std::list& theAllOlds, std::list& theOldForSub); diff --git a/src/Model/Model_ResultPart.cpp b/src/Model/Model_ResultPart.cpp index 5f46da178..45470ce48 100644 --- a/src/Model/Model_ResultPart.cpp +++ b/src/Model/Model_ResultPart.cpp @@ -26,6 +26,7 @@ #include #include #include +#include #include #include #include @@ -45,6 +46,7 @@ #include #include #include +#include #include #include #include @@ -61,6 +63,7 @@ void Model_ResultPart::initAttributes() AttributeDocRefPtr aDocRef = std::dynamic_pointer_cast( data()->addAttribute(DOC_REF(), ModelAPI_AttributeDocRef::typeId())); data()->addAttribute(COLOR_ID(), ModelAPI_AttributeIntArray::typeId()); + data()->addAttribute(EDGE_THICKNESS_ID(), ModelAPI_AttributeInteger::typeId()); data()->addAttribute(BASE_REF_ID(), ModelAPI_AttributeReference::typeId()); data()->addAttribute(DEFLECTION_ID(), ModelAPI_AttributeDouble::typeId()); data()->addAttribute(TRANSPARENCY_ID(), ModelAPI_AttributeDouble::typeId()); @@ -439,6 +442,49 @@ std::shared_ptr Model_ResultPart::shapeInPart( return aResult; } +void Model_ResultPart::setSubShapeEdgeThickness(const std::shared_ptr& theSubShape, int theThickness) +{ + TopoDS_Shape aShape = shape()->impl(); + TopoDS_Shape aSubShape = theSubShape->impl(); + if (!shape()->isSubShape(theSubShape)) + return; + + Model_Objects* anObjects = std::dynamic_pointer_cast(document())->objects(); + + document()->storeShape(data(), original(), theSubShape); + Handle(TDataStd_Integer) aThickness = new TDataStd_Integer(); + aThickness->SetID(Model_Objects::GUID_EDGE_THICKNESS); + aThickness->Set(theThickness); + anObjects->setAttribute(aThickness, original(), theSubShape); +} + +int Model_ResultPart::getSubShapeEdgeThickness(const std::shared_ptr& theSubShape) const +{ + TopoDS_Shape aShape = shape()->impl(); + TopoDS_Shape aSubShape = theSubShape->impl(); + if (!shape()->isSubShape(theSubShape)) + return -1; + + Model_Objects* anObjects = std::dynamic_pointer_cast(document())->objects(); + Handle(TDataStd_Integer) anAttr = Handle(TDataStd_Integer)::DownCast(anObjects->getAttribute(Model_Objects::GUID_EDGE_THICKNESS, original(), theSubShape)); + if (anAttr.IsNull()) + return -1; + + return anAttr->Get(); +} + +void Model_ResultPart::getSubShapesWithEdgeThickness(std::map, int>& oShapes) +{ + Model_Objects* anObjects = std::dynamic_pointer_cast(document())->objects(); + anObjects->getSubShapesWithEdgeThickness(original(), oShapes); +} + +void Model_ResultPart::removeSubShapeEdgeThickness() +{ + Model_Objects* anObjects = std::dynamic_pointer_cast(document())->objects(); + anObjects->removeSubShapeEdgeThickness(original()); +} + void Model_ResultPart::setSubShapeColor(const std::shared_ptr& theShape, const std::vector& theColor) { diff --git a/src/Model/Model_ResultPart.h b/src/Model/Model_ResultPart.h index 2ba7d9ac9..43074b2e1 100644 --- a/src/Model/Model_ResultPart.h +++ b/src/Model/Model_ResultPart.h @@ -78,7 +78,17 @@ class Model_ResultPart : public ModelAPI_ResultPart MODEL_EXPORT virtual bool updateInPart(const int theIndex); /// Returns the shape by the name in the part MODEL_EXPORT virtual std::shared_ptr shapeInPart( - const std::wstring& theName, const std::string& theType, int& theIndex); /// Set color on subshape + const std::wstring& theName, const std::string& theType, int& theIndex); + + MODEL_EXPORT virtual void setSubShapeEdgeThickness(const std::shared_ptr& theSubShape, int theThickness); + + MODEL_EXPORT virtual int getSubShapeEdgeThickness(const std::shared_ptr& theSubShape) const; + + MODEL_EXPORT virtual void getSubShapesWithEdgeThickness(std::map, int>& oSubShapes); + + MODEL_EXPORT virtual void removeSubShapeEdgeThickness(); + + /// Set color on subshape MODEL_EXPORT virtual void setSubShapeColor(const std::shared_ptr& theShape, const std::vector& theColor); diff --git a/src/ModelAPI/ModelAPI_Result.cpp b/src/ModelAPI/ModelAPI_Result.cpp index 2c3bdc9f9..fcdd6cfcb 100644 --- a/src/ModelAPI/ModelAPI_Result.cpp +++ b/src/ModelAPI/ModelAPI_Result.cpp @@ -21,6 +21,7 @@ #include #include #include +#include #include #include #include @@ -44,6 +45,7 @@ void ModelAPI_Result::initAttributes() // append the color attribute. It is empty, the attribute will be filled by a request DataPtr aData = data(); aData->addAttribute(COLOR_ID(), ModelAPI_AttributeIntArray::typeId())->setIsArgument(false); + aData->addAttribute(EDGE_THICKNESS_ID(), ModelAPI_AttributeInteger::typeId()); aData->addAttribute(DEFLECTION_ID(), ModelAPI_AttributeDouble::typeId())->setIsArgument(false); aData->addAttribute(TRANSPARENCY_ID(), ModelAPI_AttributeDouble::typeId())->setIsArgument(false); aData->addAttribute(ISO_LINES_ID(), ModelAPI_AttributeIntArray::typeId())->setIsArgument(false); diff --git a/src/ModelAPI/ModelAPI_Result.h b/src/ModelAPI/ModelAPI_Result.h index e82ea2f35..31a64ae4c 100644 --- a/src/ModelAPI/ModelAPI_Result.h +++ b/src/ModelAPI/ModelAPI_Result.h @@ -49,6 +49,14 @@ class ModelAPI_Result : public ModelAPI_Object return MY_COLOR_ID; } + /// Reference to the edge thickness of the result. + /// The integer value is used. The value is in [1, 5] range + inline static const std::string& EDGE_THICKNESS_ID() + { + static const std::string MY_EDGE_THICKNESS_ID("Edge_Thickness"); + return MY_EDGE_THICKNESS_ID; + } + /// Reference to the deflection of the result. /// The double value is used. The value is in [0, 1] range inline static const std::string& DEFLECTION_ID() @@ -122,7 +130,7 @@ class ModelAPI_Result : public ModelAPI_Object MODELAPI_EXPORT virtual ~ModelAPI_Result(); /// Returns the shape-result produced by this feature (or null if no shapes) - MODELAPI_EXPORT virtual std::shared_ptr shape(); + MODELAPI_EXPORT virtual std::shared_ptr shape(); /// Returns all the vertices of this result MODELAPI_EXPORT virtual ListOfShape diff --git a/src/ModelAPI/ModelAPI_ResultBody.h b/src/ModelAPI/ModelAPI_ResultBody.h index 3d1df1837..64fb56d68 100644 --- a/src/ModelAPI/ModelAPI_ResultBody.h +++ b/src/ModelAPI/ModelAPI_ResultBody.h @@ -196,6 +196,24 @@ public: MODELAPI_EXPORT virtual std::wstring addShapeName (std::shared_ptr, const std::wstring& theName) = 0; + MODELAPI_EXPORT virtual void setSubShapeEdgeThickness( + const std::shared_ptr theResult, + const std::shared_ptr theSubShape, + int theEdgeThickness + ) = 0; + + MODELAPI_EXPORT virtual int getSubShapeEdgeThickness( + const std::shared_ptr theResult, + const std::shared_ptr theSubShape + ) const = 0; + + MODELAPI_EXPORT virtual void getSubShapesWithEdgeThickness( + const std::shared_ptr theResult, + std::map, int>& oSubShapes + ) const = 0; + + MODELAPI_EXPORT virtual void removeSubShapeEdgeThickness(const std::shared_ptr theResult) = 0; + /// Add color for shape Name read shape in step file MODELAPI_EXPORT virtual void addShapeColor (const std::wstring& theName, std::vector& theColor) = 0; diff --git a/src/ModelAPI/ModelAPI_ResultPart.h b/src/ModelAPI/ModelAPI_ResultPart.h index 8dcd85723..d3adf16ea 100644 --- a/src/ModelAPI/ModelAPI_ResultPart.h +++ b/src/ModelAPI/ModelAPI_ResultPart.h @@ -89,6 +89,15 @@ class ModelAPI_ResultPart : public ModelAPI_Result /// Returns the shape by the name in the part virtual std::shared_ptr shapeInPart( const std::wstring& theName, const std::string& theType, int& theIndex) = 0; + + virtual void setSubShapeEdgeThickness(const std::shared_ptr& theSubShape, int theThickness) = 0; + + virtual int getSubShapeEdgeThickness(const std::shared_ptr& theSubShape) const = 0; + + virtual void getSubShapesWithEdgeThickness(std::map, int>& oSubShapes) = 0; + + virtual void removeSubShapeEdgeThickness() = 0; + /// Set color on subshape virtual void setSubShapeColor(const std::shared_ptr& theShape, const std::vector& theColor) = 0; diff --git a/src/ModelAPI/ModelAPI_Session.cpp b/src/ModelAPI/ModelAPI_Session.cpp index d00c9e50f..e9ed94a80 100644 --- a/src/ModelAPI/ModelAPI_Session.cpp +++ b/src/ModelAPI/ModelAPI_Session.cpp @@ -83,6 +83,9 @@ std::shared_ptr ModelAPI_Session::get() Config_PropManager::registerProp("Visualization", "shaper_default_transparency", "Default transparency (%)", Config_Prop::IntSpin, "0", "0", "100"); + Config_PropManager::registerProp("Visualization", "shaper_default_edge_thickness", + "Default edge thickness (pt)", Config_Prop::IntSpin, "3", "1", "5"); + } return MY_MANAGER; } diff --git a/src/ModelAPI/ModelAPI_Tools.cpp b/src/ModelAPI/ModelAPI_Tools.cpp index f7d7a5699..57915dc1f 100644 --- a/src/ModelAPI/ModelAPI_Tools.cpp +++ b/src/ModelAPI/ModelAPI_Tools.cpp @@ -21,6 +21,7 @@ #include #include #include +#include #include #include #include @@ -1124,6 +1125,134 @@ void setColor(ResultPtr theResult, GeomShapePtr theShape, const std::vector } +//************************************************************** +int getEdgeThickness(const std::shared_ptr& theResult) +{ + int aThickness = -1; + if (theResult && theResult->data()->attribute(ModelAPI_Result::EDGE_THICKNESS_ID())) { + AttributeIntegerPtr aIntAttr = theResult->data()->integer(ModelAPI_Result::EDGE_THICKNESS_ID()); + if (aIntAttr && aIntAttr->isInitialized()) + aThickness = aIntAttr->value(); + } + return aThickness; +} + +int getSubShapeEdgeThickness(const std::shared_ptr theResult, const std::shared_ptr theSubShape) +{ + if (!theResult || theSubShape->isNull()) + return -1; + + if (!theResult->shape()->isSubShape(theSubShape)) + return -1; + + auto resultBody = std::dynamic_pointer_cast(theResult); + if (resultBody) { + resultBody = mainBody(resultBody); + return resultBody->getSubShapeEdgeThickness(theResult, theSubShape); + } + else { + const auto resultPart = std::dynamic_pointer_cast(theResult); + if (!resultPart) + return -1; + + return resultPart->getSubShapeEdgeThickness(theSubShape); + } +} + +void getSubShapesWithEdgeThickness( + const std::shared_ptr theResult, + std::map, int>& oShapes, + bool theGetSubResults +) { + if (!theResult) + return; + + const auto resultBody = std::dynamic_pointer_cast(theResult); + if (resultBody) { + ResultBodyPtr mainBody = ModelAPI_Tools::mainBody(resultBody); + if (!mainBody) + return; + + if (theGetSubResults) { + std::list subResults; + allSubs(resultBody, subResults); + for (auto itSubRes = subResults.begin(); itSubRes != subResults.end(); ++itSubRes) { + mainBody->getSubShapesWithEdgeThickness(*itSubRes, oShapes); + } + } + + mainBody->getSubShapesWithEdgeThickness(theResult, oShapes); + } + else { + const auto resultPart = std::dynamic_pointer_cast(theResult); + if (!resultPart) + return; + + resultPart->getSubShapesWithEdgeThickness(oShapes); + } +} + +void removeSubShapeEdgeThickness(const std::shared_ptr theResult) +{ + if (!theResult) + return; + + auto resultBody = std::dynamic_pointer_cast(theResult); + if (resultBody) { + resultBody = mainBody(resultBody); + resultBody->removeSubShapeEdgeThickness(theResult); + } + else { + auto resultPart = std::dynamic_pointer_cast(theResult); + if (!resultPart) + return; + + resultPart->removeSubShapeEdgeThickness(); + } +} + +void setEdgeThickness(std::shared_ptr theResult, int theEdgeThickness) +{ + if (!theResult) + return; + + const AttributeIntegerPtr anAttribute = theResult->data()->integer(ModelAPI_Result::EDGE_THICKNESS_ID()); + if (anAttribute) { + anAttribute->setValue(theEdgeThickness); + removeSubShapeEdgeThickness(theResult); + } +} + +void setSubShapeEdgeThickness( + std::shared_ptr theResult, + std::shared_ptr theSubShape, + int theEdgeThickness +) { + if (!theResult || theSubShape->isNull()) + return; + + if (!theResult->shape()->isSubShape(theSubShape)) + return; + + auto resultBody = std::dynamic_pointer_cast(theResult); + if (resultBody) { + resultBody = mainBody(resultBody); + resultBody->setSubShapeEdgeThickness(theResult, theSubShape, theEdgeThickness); + } + else { + const auto resultPart = std::dynamic_pointer_cast(theResult); + if (!resultPart) + return; + + resultPart->setSubShapeEdgeThickness(theSubShape, theEdgeThickness); + } + + static const Events_ID EVENT = Events_Loop::eventByName(EVENT_OBJECT_TO_REDISPLAY); + ModelAPI_EventCreator::get()->sendUpdated(theResult, EVENT); +} + + +//************************************************************** void getColor(const std::shared_ptr& theResult, std::vector& theColor) { theColor.clear(); diff --git a/src/ModelAPI/ModelAPI_Tools.h b/src/ModelAPI/ModelAPI_Tools.h index dcb62e0d3..d67e4d0f1 100644 --- a/src/ModelAPI/ModelAPI_Tools.h +++ b/src/ModelAPI/ModelAPI_Tools.h @@ -276,6 +276,32 @@ MODELAPI_EXPORT double getDeflection(const std::shared_ptr& the MODELAPI_EXPORT void setDeflection(std::shared_ptr theResult, const double theDeflection); +/*! \returns -1, if edge thickness is not defined. */ +MODELAPI_EXPORT int getEdgeThickness(const std::shared_ptr& theResult); + +/*! \returns -1, if edge thickness is not defined. */ +MODELAPI_EXPORT int getSubShapeEdgeThickness(const std::shared_ptr theResult, const std::shared_ptr theSubShape); + +/*! \returns theResult subshapes with defined edge thickness. +* \param theSubResults - true, to include subshapes of subresults. */ +MODELAPI_EXPORT void getSubShapesWithEdgeThickness( + const std::shared_ptr theResult, + std::map,int>& oShapes, + bool theGetSubResults = false +); + +/*! \brief Removes edge thickness data of result subshapes. */ +MODELAPI_EXPORT void removeSubShapeEdgeThickness(const std::shared_ptr theResult); + +MODELAPI_EXPORT void setEdgeThickness(std::shared_ptr theResult, int theEdgeThickness); + +/*! \param theShape belongs to theResult. */ +MODELAPI_EXPORT void setSubShapeEdgeThickness( + std::shared_ptr theResult, + std::shared_ptr theSubShape, + int theEdgeThickness +); + /*! Returns current color of the current result * \param[in] theResult a result object * \param[out] theColor a color values if it is defined diff --git a/src/ModelHighAPI/ModelHighAPI_Dumper.cpp b/src/ModelHighAPI/ModelHighAPI_Dumper.cpp index f7cd5b96c..308821fd2 100644 --- a/src/ModelHighAPI/ModelHighAPI_Dumper.cpp +++ b/src/ModelHighAPI/ModelHighAPI_Dumper.cpp @@ -940,6 +940,30 @@ void ModelHighAPI_Dumper::dumpEntitySetName() anEntityNames.myUserName.clear(); anEntityNames.myIsDefault = true; } + + // Set result edge thickness. + if (isEdgeThicknessDefined(*aResIt)) { + AttributeIntegerPtr attrThickness = (*aResIt)->data()->integer(ModelAPI_Result::EDGE_THICKNESS_ID()); + if (attrThickness && attrThickness->isInitialized()) { + *this << *aResIt; + *myDumpStorage << ".setEdgeThickness(" << attrThickness->value() << ")\n"; + } + } + // Set subresult edge thickness. + std::map aShapesWithEdgeThickness; + ModelAPI_Tools::getSubShapesWithEdgeThickness(*aResIt, aShapesWithEdgeThickness, true /*theGetSubResults*/); + + if ((isParentResult(*aResIt)) && !aShapesWithEdgeThickness.empty()) { + for (const auto& shapeAndThickness : aShapesWithEdgeThickness) { + const GeomShapePtr& aShape = shapeAndThickness.first; + + *this << *aResIt; + *myDumpStorage << ".setEdgeThickness(model.selection(\"" << aShape->shapeTypeStr() << "\", \"" + << Locale::Convert::toString((*aResIt)->data()->name(aShape)) << "\"), " + << shapeAndThickness.second << ")\n"; + } + } + // set result color if (!isDefaultColor(*aResIt)) { AttributeIntArrayPtr aColor = (*aResIt)->data()->intArray(ModelAPI_Result::COLOR_ID()); @@ -1044,6 +1068,13 @@ static bool isSketchSub(const FeaturePtr& theFeature) return anOwner && anOwner->getKind() == SKETCH; } +bool ModelHighAPI_Dumper::hasShapeWithEdgeThickness(const ResultPtr& theResult, bool theGetSubResults = false) const +{ + std::map aShapes; + ModelAPI_Tools::getSubShapesWithEdgeThickness(theResult, aShapes, theGetSubResults); + return !aShapes.empty(); +} + bool ModelHighAPI_Dumper::hasColoredShape(const ResultPtr& theResult, bool theGetSubResults) const { std::map> aColoredShapes; @@ -1062,6 +1093,23 @@ bool ModelHighAPI_Dumper::isParentResult(const ResultPtr& theResult) const return false; } +bool ModelHighAPI_Dumper::isEdgeThicknessDefined(const ResultPtr& theResult) const +{ + const auto anAttribute = theResult->data()->integer(ModelAPI_Result::EDGE_THICKNESS_ID()); + if (!anAttribute || !anAttribute->isInitialized()) + return false; + + // Do not dump edge thickness, if theResult belongs to sketch entity. + const auto aResConstr = std::dynamic_pointer_cast(theResult); + if (aResConstr) { + FeaturePtr aFeature = ModelAPI_Feature::feature(theResult->data()->owner()); + if (isSketchSub(aFeature)) + return false; + } + + return true; +} + bool ModelHighAPI_Dumper::isDefaultColor(const ResultPtr& theResult) const { AttributeIntArrayPtr aColor = theResult->data()->intArray(ModelAPI_Result::COLOR_ID()); @@ -1367,20 +1415,20 @@ ModelHighAPI_Dumper& ModelHighAPI_Dumper::operator<<(const FeaturePtr& theEntity if (!myNames[theEntity].myIsDumped) { bool isUserDefinedName = !myNames[theEntity].myIsDefault; - // store results if they have user-defined names or colors - std::list aResultsWithNameOrColor; + // Store results if they have user-defined names, colors or edge thickness. + std::list aResultsWithNonDefaultAttr; std::list allRes; ModelAPI_Tools::allResults(theEntity, allRes); - for(std::list::iterator aRes = allRes.begin(); aRes != allRes.end(); aRes++) { - if(!myNames[*aRes].myIsDefault || !isDefaultColor(*aRes) || - !isDefaultDeflection(*aRes) || !isDefaultTransparency(*aRes) || - (isParentResult(*aRes) && hasColoredShape(*aRes, true))) - aResultsWithNameOrColor.push_back(*aRes); + for (const auto& aRes : allRes) { + if (!myNames[aRes].myIsDefault || !isDefaultColor(aRes) || isEdgeThicknessDefined(aRes) || + !isDefaultDeflection(aRes) || !isDefaultTransparency(aRes) || + (isParentResult(aRes) && (hasColoredShape(aRes, true) || hasShapeWithEdgeThickness(aRes, true)))) + aResultsWithNonDefaultAttr.push_back(aRes); } + // store just dumped entity to stack if (myEntitiesStack.empty() || myEntitiesStack.top().myEntity != theEntity) - myEntitiesStack.push( - LastDumpedEntity(theEntity, isUserDefinedName, aResultsWithNameOrColor)); + myEntitiesStack.push(LastDumpedEntity(theEntity, isUserDefinedName, aResultsWithNonDefaultAttr)); } // remove entity from the list of not dumped items diff --git a/src/ModelHighAPI/ModelHighAPI_Dumper.h b/src/ModelHighAPI/ModelHighAPI_Dumper.h index 3c85b9ac1..3b5fee985 100644 --- a/src/ModelHighAPI/ModelHighAPI_Dumper.h +++ b/src/ModelHighAPI/ModelHighAPI_Dumper.h @@ -403,12 +403,17 @@ private: /// Stores names of results for the given feature void saveResultNames(const FeaturePtr& theFeature); + bool hasShapeWithEdgeThickness(const ResultPtr& theResult, bool theGetSubResults = false) const; + /// Check the result feature has colored shape bool hasColoredShape(const ResultPtr& theResult, bool theGetSubResults = false) const; /// Check the result is parent result int the feature bool isParentResult(const ResultPtr& theResult) const; + /// Check the result feature has edge thickness attribute + bool isEdgeThicknessDefined(const ResultPtr& theResult) const; + /// Check the result feature has default color bool isDefaultColor(const ResultPtr& theResult) const; diff --git a/src/ModelHighAPI/ModelHighAPI_Selection.cpp b/src/ModelHighAPI/ModelHighAPI_Selection.cpp index e2d07d5f3..751caab71 100644 --- a/src/ModelHighAPI/ModelHighAPI_Selection.cpp +++ b/src/ModelHighAPI/ModelHighAPI_Selection.cpp @@ -20,6 +20,7 @@ #include "ModelHighAPI_Selection.h" #include +#include #include #include #include @@ -210,6 +211,44 @@ std::wstring ModelHighAPI_Selection::name() const return std::wstring(); } +void ModelHighAPI_Selection::setEdgeThickness(int theValue) +{ + if (myVariantType != VT_ResultSubShapePair || !myResultSubShapePair.first.get()) + return; + + const auto attr = myResultSubShapePair.first->data()->integer(ModelAPI_Result::EDGE_THICKNESS_ID()); + attr->setValue(theValue); +} + +void ModelHighAPI_Selection::setEdgeThickness(const ModelHighAPI_Selection& theShape, int theValue) +{ + if (myVariantType != VT_ResultSubShapePair || !myResultSubShapePair.first.get()) + return; + + std::shared_ptr aShape = myResultSubShapePair.second; + ResultBodyPtr aResBody = std::dynamic_pointer_cast(myResultSubShapePair.first); + + ResultPtr aRes; + AttributeSelectionPtr aSelAttr; + if (aResBody.get()) + { + aSelAttr = aResBody->selection(); + theShape.fillAttribute(aSelAttr); + } + else + { + std::wstring aSubShapeName = theShape.myTypeSubShapeNamePair.second; + aSubShapeName = changePartName(theShape, aSubShapeName); + ResultPartPtr aPart = std::dynamic_pointer_cast(myResultSubShapePair.first); + aSelAttr = aPart->selection(); + aSelAttr->selectSubShape(myTypeSubShapeNamePair.first, aSubShapeName); + } + aRes = aSelAttr->context(); + aShape = aSelAttr->value(); + if (aRes.get() && aShape.get() && !aShape->isNull()) + ModelAPI_Tools::setSubShapeEdgeThickness(aRes, aShape, theValue); +} + void ModelHighAPI_Selection::setColor(int theRed, int theGreen, int theBlue, bool random) { if (myVariantType != VT_ResultSubShapePair || !myResultSubShapePair.first.get()) diff --git a/src/ModelHighAPI/ModelHighAPI_Selection.h b/src/ModelHighAPI/ModelHighAPI_Selection.h index bffa214aa..9c98dc804 100644 --- a/src/ModelHighAPI/ModelHighAPI_Selection.h +++ b/src/ModelHighAPI/ModelHighAPI_Selection.h @@ -132,6 +132,14 @@ public: MODELHIGHAPI_EXPORT std::wstring name() const; + /// Change edge thickness of result + MODELHIGHAPI_EXPORT + void setEdgeThickness(int theValue); + + /// Change edge thickness of subshape. + MODELHIGHAPI_EXPORT + void setEdgeThickness(const ModelHighAPI_Selection& theShape, int theValue); + /// Change result's color MODELHIGHAPI_EXPORT void setColor(int theRed = 0, int theGreen = 0, int theBlue = 0, bool random = false); diff --git a/src/PartSet/PartSet_Module.cpp b/src/PartSet/PartSet_Module.cpp index 825d5a254..9836754a3 100644 --- a/src/PartSet/PartSet_Module.cpp +++ b/src/PartSet/PartSet_Module.cpp @@ -273,13 +273,12 @@ PartSet_Module::PartSet_Module(ModuleBase_IWorkshop* theWshop) Config_PropManager::registerProp("Visualization", "axis_arrow_size", "Trihedron arrows constant size", Config_Prop::IntSpin, "10"); + Config_PropManager::registerProp("Visualization", "result_subshape_with_edge_thickness", + "Set edge thickness of subshape of result", Config_Prop::Boolean, "true"); + Config_PropManager::registerProp("Visualization", "color_subshape_result", "Set color on subshape of result", Config_Prop::Boolean, "true"); - Config_PropManager::registerProp("Shortcuts", "add_parameter_shortcut", - "Add parameter in parameters manager dialog", - Config_Prop::Shortcut, "Ctrl+A"); - Config_PropManager::registerProp("Windows", "use_hide_faces_panel", "Use HideFaces panel in operations", Config_Prop::Boolean, "false"); } diff --git a/src/PartSet/PartSet_Tools.cpp b/src/PartSet/PartSet_Tools.cpp index fd71ff50b..d5dbd95c4 100644 --- a/src/PartSet/PartSet_Tools.cpp +++ b/src/PartSet/PartSet_Tools.cpp @@ -853,6 +853,12 @@ void PartSet_Tools::getFirstAndLastIndexInFolder(const ObjectPtr& theFolder, } +int PartSet_Tools::getDefaultEdgeThickness() +{ + return Config_PropManager::integer("Visualization", "shaper_default_edge_thickness"); +} + + void PartSet_Tools::getDefaultColor(ObjectPtr theObject, const bool isEmptyColorValid, std::vector& theColor) { diff --git a/src/PartSet/PartSet_Tools.h b/src/PartSet/PartSet_Tools.h index f8ae5dba7..d3a3c8761 100644 --- a/src/PartSet/PartSet_Tools.h +++ b/src/PartSet/PartSet_Tools.h @@ -313,6 +313,10 @@ public: static void getFirstAndLastIndexInFolder(const ObjectPtr& theFolder, int& theFirst, int& theLast); + /** + * Returns user-defined default edge thickness value + */ + static int getDefaultEdgeThickness(); /** * Returns default color value for the given object diff --git a/src/SHAPERGUI/resources/LightApp.xml.in b/src/SHAPERGUI/resources/LightApp.xml.in index 06636c0fb..f6873c917 100644 --- a/src/SHAPERGUI/resources/LightApp.xml.in +++ b/src/SHAPERGUI/resources/LightApp.xml.in @@ -52,6 +52,7 @@ + diff --git a/src/XGUI/CMakeLists.txt b/src/XGUI/CMakeLists.txt index dd690533e..136034ef5 100644 --- a/src/XGUI/CMakeLists.txt +++ b/src/XGUI/CMakeLists.txt @@ -39,6 +39,7 @@ SET(PROJECT_HEADERS XGUI_DataModel.h XGUI_DeflectionDialog.h XGUI_Displayer.h + XGUI_EdgeThicknessWidget.h XGUI_ErrorDialog.h XGUI_ErrorMgr.h XGUI_FacesPanel.h @@ -76,6 +77,7 @@ SET(PROJECT_MOC_HEADERS XGUI_DataModel.h XGUI_DeflectionDialog.h XGUI_Displayer.h + XGUI_EdgeThicknessWidget.h XGUI_ErrorDialog.h XGUI_ErrorMgr.h XGUI_FacesPanel.h @@ -106,6 +108,7 @@ SET(PROJECT_SOURCES XGUI_DataModel.cpp XGUI_DeflectionDialog.cpp XGUI_Displayer.cpp + XGUI_EdgeThicknessWidget.cpp XGUI_ErrorDialog.cpp XGUI_ErrorMgr.cpp XGUI_FacesPanel.cpp diff --git a/src/XGUI/XGUI_ContextMenuMgr.cpp b/src/XGUI/XGUI_ContextMenuMgr.cpp index 5b4365658..cddc7578e 100644 --- a/src/XGUI/XGUI_ContextMenuMgr.cpp +++ b/src/XGUI/XGUI_ContextMenuMgr.cpp @@ -133,6 +133,9 @@ void XGUI_ContextMenuMgr::createActions() tr("Transparency..."), aDesktop); addAction("TRANSPARENCY_CMD", anAction); + anAction = ModuleBase_Tools::createAction(QIcon(), tr("Edge Thickness..."), aDesktop); + addAction("EDGE_THICKNESS_CMD", anAction); + anAction = ModuleBase_Tools::createAction(QIcon(":pictures/eye_pencil.png"), tr("Show"), aDesktop); addAction("SHOW_CMD", anAction); @@ -553,6 +556,7 @@ void XGUI_ContextMenuMgr::updateObjectBrowserMenu() action("COLOR_CMD")->setEnabled(myWorkshop->canChangeProperty("COLOR_CMD")); action("DEFLECTION_CMD")->setEnabled(myWorkshop->canChangeProperty("DEFLECTION_CMD")); action("TRANSPARENCY_CMD")->setEnabled(myWorkshop->canChangeProperty("TRANSPARENCY_CMD")); + action("EDGE_THICKNESS_CMD")->setEnabled(myWorkshop->canChangeProperty("EDGE_THICKNESS_CMD")); action("AUTOCOLOR_CMD")->setEnabled(myWorkshop->canChangeProperty("AUTOCOLOR_CMD")); #ifdef _DEBUG @@ -684,6 +688,9 @@ void XGUI_ContextMenuMgr::updateViewerMenu() if (myWorkshop->canChangeProperty("TRANSPARENCY_CMD")) action("TRANSPARENCY_CMD")->setEnabled(true); + if (myWorkshop->canChangeProperty("EDGE_THICKNESS_CMD")) + action("EDGE_THICKNESS_CMD")->setEnabled(true); + action("DELETE_CMD")->setEnabled(true); } @@ -717,6 +724,7 @@ void XGUI_ContextMenuMgr::buildObjBrowserMenu() aList.append(action("COLOR_CMD")); aList.append(action("DEFLECTION_CMD")); aList.append(action("TRANSPARENCY_CMD")); + aList.append(action("EDGE_THICKNESS_CMD")); aList.append(action("SHOW_FEATURE_CMD")); aList.append(mySeparator2); aList.append(action("DELETE_CMD")); @@ -738,6 +746,7 @@ void XGUI_ContextMenuMgr::buildObjBrowserMenu() aList.append(action("COLOR_CMD")); aList.append(action("DEFLECTION_CMD")); aList.append(action("TRANSPARENCY_CMD")); + aList.append(action("EDGE_THICKNESS_CMD")); aList.append(action("SHOW_ISOLINES_CMD")); aList.append(action("ISOLINES_CMD")); aList.append(action("SHOW_FEATURE_CMD")); @@ -768,6 +777,7 @@ void XGUI_ContextMenuMgr::buildObjBrowserMenu() aList.append(action("COLOR_CMD")); aList.append(action("DEFLECTION_CMD")); aList.append(action("TRANSPARENCY_CMD")); + aList.append(action("EDGE_THICKNESS_CMD")); aList.append(action("SHOW_ISOLINES_CMD")); aList.append(action("ISOLINES_CMD")); aList.append(action("SHOW_FEATURE_CMD")); @@ -827,6 +837,7 @@ void XGUI_ContextMenuMgr::buildViewerMenu() aList.append(action("COLOR_CMD")); aList.append(action("DEFLECTION_CMD")); aList.append(action("TRANSPARENCY_CMD")); + aList.append(action("EDGE_THICKNESS_CMD")); aList.append(mySeparator3); aList.append(action("SET_VIEW_NORMAL_CMD")); aList.append(action("SET_VIEW_INVERTEDNORMAL_CMD")); @@ -846,6 +857,7 @@ void XGUI_ContextMenuMgr::buildViewerMenu() aList.append(action("COLOR_CMD")); aList.append(action("DEFLECTION_CMD")); aList.append(action("TRANSPARENCY_CMD")); + aList.append(action("EDGE_THICKNESS_CMD")); aList.append(action("SHOW_ISOLINES_CMD")); aList.append(action("ISOLINES_CMD")); aList.append(mySeparator3); @@ -869,6 +881,7 @@ void XGUI_ContextMenuMgr::buildViewerMenu() aList.append(action("COLOR_CMD")); aList.append(action("DEFLECTION_CMD")); aList.append(action("TRANSPARENCY_CMD")); + aList.append(action("EDGE_THICKNESS_CMD")); aList.append(action("SHOW_ISOLINES_CMD")); aList.append(action("ISOLINES_CMD")); aList.append(mySeparator3); @@ -925,6 +938,7 @@ void XGUI_ContextMenuMgr::addObjBrowserMenu(QMenu* theMenu) const anActions.append(action("COLOR_CMD")); anActions.append(action("DEFLECTION_CMD")); anActions.append(action("TRANSPARENCY_CMD")); + anActions.append(action("EDGE_THICKNESS_CMD")); anActions.append(action("SHOW_ISOLINES_CMD")); anActions.append(action("ISOLINES_CMD")); anActions.append(action("CLEAN_HISTORY_CMD")); @@ -978,6 +992,7 @@ void XGUI_ContextMenuMgr::addViewerMenu(QMenu* theMenu) const anActions.append(action("COLOR_CMD")); anActions.append(action("DEFLECTION_CMD")); anActions.append(action("TRANSPARENCY_CMD")); + anActions.append(action("EDGE_THICKNESS_CMD")); anActions.append(mySeparator1); anActions.append(action("SHOW_ONLY_CMD")); anActions.append(action("HIDE_CMD")); diff --git a/src/XGUI/XGUI_Displayer.cpp b/src/XGUI/XGUI_Displayer.cpp index 96386fe08..2bd55d6e7 100644 --- a/src/XGUI/XGUI_Displayer.cpp +++ b/src/XGUI/XGUI_Displayer.cpp @@ -100,6 +100,11 @@ #pragma warning(disable: 4702) #endif +#define EDGE_THICKNESS_DBG +#ifdef EDGE_THICKNESS_DBG + #include +#endif /*EDGE_THICKNESS_DBG*/ + /// defines the local context mouse selection sensitivity const int MOUSE_SENSITIVITY_IN_PIXEL = 10; @@ -248,7 +253,7 @@ bool XGUI_Displayer::display(ObjectPtr theObject, AISObjectPtr theAIS, // bos#40617: Apply clipping planes // Retrieve the clipping plane from the OCCT Presentation Manager directly, - // as they are stored in the ViewModel of the OCCViewer in GUI, where we + // as they are stored in the ViewModel of the OCCViewer in GUI, where we // don't have access to. Handle(ViewerData_AISShape) aShape = Handle(ViewerData_AISShape)::DownCast (anAISIO); if (!aShape.IsNull() && aShape->IsClippable()) { @@ -279,6 +284,7 @@ bool XGUI_Displayer::display(ObjectPtr theObject, AISObjectPtr theAIS, // appear "behind" the Groups. aContext->SetDisplayPriority(anAISIO, FRONT_DISPLAY_PRIORITY); } + #ifdef TINSPECTOR if (getCallBack()) getCallBack()->Display(anAISIO); #endif @@ -374,7 +380,113 @@ bool XGUI_Displayer::redisplay(ObjectPtr theObject, bool theUpdateViewer) if (!aAISIO.IsNull()) { ResultPtr aResult = std::dynamic_pointer_cast(theObject); - if (aResult.get()) { + if (aResult) { + #ifdef EDGE_THICKNESS_DBG + std::cout << "XGUI_Displayer::redisplay. theObject is ModelAPI_Result and has AIS_InteractiveObject." << std::endl; + #endif /*EDGE_THICKNESS_DBG*/ + + { // Set edge thickness + // Set edge thickness to subshapes of result + std::map aShapes; + ModelAPI_Tools::getSubShapesWithEdgeThickness(aResult, aShapes); + + #ifdef EDGE_THICKNESS_DBG + for (const auto& shapeAndThickness : aShapes) { + std::cout << "Edge thickness of subshape at \"" << shapeAndThickness.first.get() << "\" is " << shapeAndThickness.second << std::endl; + } + #endif /*EDGE_THICKNESS_DBG*/ + + // Displayer overlays presentations of edge shapes with edges of face presentations. + // Edges of face presentations are overlaid by edges of solid presentations. + // Etc... + // + // This snippet is circumvention of the behaviour. + // Thickness is only assigned to presentations of edge subshapes of a shape. + // If a subshape has non-default thickness value, the value overrides thickness value of the parental shape. + std::map edges; + std::map wires; + std::map faces; + std::map shells; + std::map solids; + std::map compsolids; + std::map compounds; + + for (auto itShapes = aShapes.begin(); itShapes != aShapes.end();) { + const auto& shape = itShapes->first; + const auto& thickness = itShapes->second; + const auto shapeType = shape->shapeType(); + + if (shapeType > GeomAPI_Shape::ShapeType::EDGE) { + // Do nothing. + } + else if (shapeType == GeomAPI_Shape::ShapeType::EDGE) + edges.emplace(shape, thickness); + else if (shapeType == GeomAPI_Shape::ShapeType::WIRE) + wires.emplace(shape, thickness); + else if (shapeType == GeomAPI_Shape::ShapeType::FACE) + faces.emplace(shape, thickness); + else if (shapeType == GeomAPI_Shape::ShapeType::SHELL) + shells.emplace(shape, thickness); + else if (shapeType == GeomAPI_Shape::ShapeType::SOLID) + solids.emplace(shape, thickness); + else if (shapeType == GeomAPI_Shape::ShapeType::COMPSOLID) + compsolids.emplace(shape, thickness); + else if (shapeType == GeomAPI_Shape::ShapeType::COMPOUND) + compounds.emplace(shape, thickness); + + itShapes = aShapes.erase(itShapes); + } + + std::map mapResultShapeThickness; + { + const int resultThickness = ModelAPI_Tools::getEdgeThickness(aResult); + if (resultThickness > 0) { + mapResultShapeThickness.emplace(aResult->shape(), resultThickness); + #ifdef EDGE_THICKNESS_DBG + std::cout << "Result edge thickness: " << resultThickness << std::endl; + #endif /*EDGE_THICKNESS_DBG*/ + } + } + + #ifdef EDGE_THICKNESS_DBG + std::cout << std::endl; + #endif /*EDGE_THICKNESS_DBG*/ + + const std::list*> thicknessMaps = {&wires, &faces, &shells, &solids, &compsolids, &compounds, &mapResultShapeThickness}; + for (const auto pThicknessMap : thicknessMaps) { + const std::map& thicknessMap = *pThicknessMap; + for (const auto& shapeAndThickness : thicknessMap) { + const GeomShapePtr& shape = shapeAndThickness.first; + const int thickness = shapeAndThickness.second; + + const std::list shapeEdges = shape->subShapes(GeomAPI_Shape::ShapeType::EDGE, true /*theOnlyUnique*/); + for (const auto& shapeEdge : shapeEdges) { + if (edges.find(shapeEdge) == edges.end()) + edges.emplace(shapeEdge, thickness); + } + } + } + + Handle(AIS_ColoredShape) aResShape = Handle(AIS_ColoredShape)::DownCast(aAISIO); + Handle(ModuleBase_ResultPrs) aResPrsShape = Handle(ModuleBase_ResultPrs)::DownCast(aResShape); + if (!aResPrsShape.IsNull()) { + for (const auto& edgeAndTickness : edges) { + const GeomShapePtr& edge = edgeAndTickness.first; + const int thickness = edgeAndTickness.second; + + if (aAISObj->getShape()->isSubShape(edge)) { + aResPrsShape->SetCustomWidth(edge->impl(), thickness); + aResPrsShape->SetCustomColor(edge->impl(), Quantity_Color(Quantity_NameOfColor::Quantity_NOC_BLACK)); + } + else { + #ifdef EDGE_THICKNESS_DBG + std::cout << "Edge at \"" << edge.get() << "\" is not a subshape of result !" << std::endl; + #endif /*EDGE_THICKNESS_DBG*/ + } + } + } + } + // Set color std::vector aColor; ModelAPI_Tools::getColor(aResult, aColor); @@ -406,7 +518,8 @@ bool XGUI_Displayer::redisplay(ObjectPtr theObject, bool theUpdateViewer) } else { - aResShape->ClearCustomAspects(); + // Edge thickness is also custom aspect. Don't remove aspects just because colors aren't assigned. + // aResShape->ClearCustomAspects(); } // Set deflection double aDeflection = ModelAPI_Tools::getDeflection(aResult); diff --git a/src/XGUI/XGUI_EdgeThicknessWidget.cpp b/src/XGUI/XGUI_EdgeThicknessWidget.cpp new file mode 100644 index 000000000..7fb5e7d21 --- /dev/null +++ b/src/XGUI/XGUI_EdgeThicknessWidget.cpp @@ -0,0 +1,55 @@ +// Copyright (C) 2014-2023 CEA, EDF +// +// 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 "XGUI_EdgeThicknessWidget.h" + + +#include +#include + + +XGUI_EdgeThicknessWidget::XGUI_EdgeThicknessWidget(QWidget* theParent) + : QWidget(theParent) +{ + auto aLayout = new QHBoxLayout(this); + aLayout->setContentsMargins(0, 0, 0, 0); + + mySpinBox = new SalomeApp_IntSpinBox(); + mySpinBox->setRange(1, 5); + mySpinBox->setDefaultValue(1); + mySpinBox->setSingleStep(1); + mySpinBox->setObjectName("EdgeThicknessSpinBox"); + mySpinBox->setSizePolicy(QSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed)); + mySpinBox->setValue(1); + aLayout->addWidget(mySpinBox, 0, Qt::AlignCenter); + + connect(mySpinBox, SIGNAL(valueChanged(int)), this, SIGNAL(thicknessValueChanged(int))); +} + +void XGUI_EdgeThicknessWidget::setValue(int theValue) +{ + bool isSpinBoxBlocked = mySpinBox->blockSignals(true); + mySpinBox->setValue(theValue); + mySpinBox->blockSignals(isSpinBoxBlocked); +} + +int XGUI_EdgeThicknessWidget::getValue() const +{ + return mySpinBox->value(); +} \ No newline at end of file diff --git a/src/XGUI/XGUI_EdgeThicknessWidget.h b/src/XGUI/XGUI_EdgeThicknessWidget.h new file mode 100644 index 000000000..c72ae369b --- /dev/null +++ b/src/XGUI/XGUI_EdgeThicknessWidget.h @@ -0,0 +1,58 @@ +// Copyright (C) 2014-2023 CEA, EDF +// +// 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 XGUI_EdgeThicknessWidget_H +#define XGUI_EdgeThicknessWidget_H + +#include "XGUI.h" +#include + +class SalomeApp_IntSpinBox; + +/** +* \ingroup GUI +* A class of a widget to chose edge thickness. Range of values is Natural:[0; 5]. +*/ +class XGUI_EdgeThicknessWidget : public QWidget +{ + Q_OBJECT + +public: +/// Constructor + /// \param theParent a parent widget for the dialog + /// \param theLabelText if not empty, the information label will be shown in the widget + XGUI_EXPORT XGUI_EdgeThicknessWidget(QWidget* theParent); + XGUI_EXPORT ~XGUI_EdgeThicknessWidget() = default; + + /// Initializes the dialog with the given value. + /// \param theValue edge thickness value + void setValue(int theValue); + + /// Returns the current edge thickness value. + /// \return value + int getValue() const; + +signals: + void thicknessValueChanged(int); + +private: + SalomeApp_IntSpinBox* mySpinBox; +}; + +#endif // XGUI_EdgeThicknessWidget_H \ No newline at end of file diff --git a/src/XGUI/XGUI_Workshop.cpp b/src/XGUI/XGUI_Workshop.cpp index 3d128ef70..f2edff5f9 100644 --- a/src/XGUI/XGUI_Workshop.cpp +++ b/src/XGUI/XGUI_Workshop.cpp @@ -25,6 +25,7 @@ #include "XGUI_MenuMgr.h" #include "XGUI_ColorDialog.h" #include "XGUI_DeflectionDialog.h" +#include "XGUI_EdgeThicknessWidget.h" #include "XGUI_TransparencyWidget.h" #include "XGUI_ContextMenuMgr.h" #include "XGUI_Displayer.h" @@ -1794,6 +1795,8 @@ void XGUI_Workshop::onContextMenuCommand(const QString& theId, bool isChecked) moveObjects(theId == "MOVE_SPLIT_CMD"); else if (theId == "RECOVER_CMD") recoverFeature(); + else if (theId == "EDGE_THICKNESS_CMD") + changeEdgeThickness(aSelectedObjects); else if (theId == "COLOR_CMD") changeColor(aSelectedObjects); else if (theId == "AUTOCOLOR_CMD") @@ -2517,9 +2520,11 @@ bool XGUI_Workshop::canBeShaded(const ObjectPtr& theObject) const bool XGUI_Workshop::canChangeProperty(const QString& theActionName) const { if (theActionName == "COLOR_CMD" || + theActionName == "EDGE_THICKNESS_CMD" || theActionName == "DEFLECTION_CMD" || theActionName == "TRANSPARENCY_CMD") { QObjectPtrList anObjects = mySelector->selection()->selectedObjects(); + // List of std::shared_ptr std::set aTypes; aTypes.insert(ModelAPI_ResultGroup::group()); @@ -2527,6 +2532,34 @@ bool XGUI_Workshop::canChangeProperty(const QString& theActionName) const aTypes.insert(ModelAPI_ResultBody::group()); aTypes.insert(ModelAPI_ResultPart::group()); + /* TODO Get shape type correctly. + if (theActionName == "COLOR_CMD") { + // Do not show Color dialog in context menus if nothing face-containing is selected. + bool isFaceContainingShapeSelected = false; + for (const auto& object : anObjects) { + if (object->shape().ShapeType() <= TopAbs_ShapeEnum::TopAbs_FACE) { + isFaceContainingShapeSelected = true; + break; + } + } + + if (!isFaceContainingShapeSelected) + return false; + } + else if (theActionName == "EDGE_THICKNESS_CMD") { + // Do not show Edge Thickness dialog in context menus if nothing edge-containing is selected. + bool isEdgeContainingShapeSelected = false; + for (const auto& object : anObjects) { + if (object->shape().ShapeType() <= TopAbs_ShapeEnum::TopAbs_EDGE) { + isEdgeContainingShapeSelected = true; + break; + } + } + + if (!isEdgeContainingShapeSelected) + return false; + }*/ + return hasResults(anObjects, aTypes); } if (theActionName == "AUTOCOLOR_CMD") { @@ -2564,6 +2597,117 @@ void getDefaultColor(ObjectPtr theObject, const bool isEmptyColorValid, } } + +//************************************************************** +/// Returns user-defined default edge thickness. +int getDefaultEdgeThickness() +{ + return Config_PropManager::integer("Visualization", "shaper_default_edge_thickness"); +} + + + +//************************************************************** +void XGUI_Workshop::changeEdgeThickness(const QMap>& theSelectedObjects) +{ + int thickness = -1; + // 1. find current edge thickness of the object. This is an edge thickness of AIS presentation. + // The objects are iterated until a first valid thickness is found. + QList aValues = mySelector->selection()->getSelected(ModuleBase_ISelection::Viewer); + const bool aEdgeThicknessOfSubShapesEnabled = Config_PropManager::boolean("Visualization", "result_subshape_with_edge_thickness"); + foreach(ResultPtr aResult, theSelectedObjects.keys()) + { + if (!aResult) + continue; + + foreach(GeomShapePtr aShape, theSelectedObjects[aResult]) { + if (aResult->shape()->impl().IsEqual(aShape->impl()) || !aEdgeThicknessOfSubShapesEnabled) + thickness = ModelAPI_Tools::getEdgeThickness(aResult); + else if (!aShape->isNull()) { + thickness = ModelAPI_Tools::getSubShapeEdgeThickness(aResult, aShape); + if (thickness <= 0) + thickness = ModelAPI_Tools::getEdgeThickness(aResult); + } + + if (thickness <= 0) { + AISObjectPtr anAISObj = myDisplayer->getAISObject(aResult); + if (anAISObj) { + thickness = getDefaultEdgeThickness(); + const double aAISThickness = anAISObj->width(); + if (aAISThickness >= 1) + thickness = int(aAISThickness); + } + } + + if (thickness <= 0) + thickness = getDefaultEdgeThickness(); + + if (thickness > 0 || !aEdgeThicknessOfSubShapesEnabled) + break; + } + + if (thickness > 0) + break; + } + + if (thickness <= 0) + return; + + if (!abortAllOperations()) + return; + + // 2. show the dialog to change the value + const auto dialog = new XGUI_PropertyDialog(desktop()); + dialog->setWindowTitle(tr("Edge Thickness")); + const XGUI_EdgeThicknessWidget* edgeThicknessWidget = new XGUI_EdgeThicknessWidget(dialog); + dialog->setContent(edgeThicknessWidget); + edgeThicknessWidget->setValue(thickness); + if (dialog->exec() != QDialog::Accepted) + return; + + // bool isSetToShape = dialog->isSetOnSubShape(); + const bool isSetToShape = true; + + // 3. abort the previous operation and start a new one + SessionPtr aMgr = ModelAPI_Session::get(); + QString aDescription = contextMenuMgr()->action("EDGE_THICKNESS_CMD")->text(); + + aMgr->startOperation(aDescription.toStdString()); + + // 4. set the value to all results and subshapes from result (if subshape of result were selected). + const int newThickness = edgeThicknessWidget->getValue(); + foreach(ResultPtr aResult, theSelectedObjects.keys()) { + if (!aResult) + continue; + + ResultBodyPtr aBodyResult = std::dynamic_pointer_cast(aResult); + foreach(GeomShapePtr aShape, theSelectedObjects[aResult]) { + if (aResult->shape()->impl().IsEqual(aShape->impl()) || !aEdgeThicknessOfSubShapesEnabled || !isSetToShape) { + if (aResult.get() != NULL) { + // change edge thickness for all sub-solids + std::list allRes; + ModelAPI_Tools::allSubs(aBodyResult, allRes); + for (std::list::iterator aRes = allRes.begin(); aRes != allRes.end(); aRes++) { + ModelAPI_Tools::setEdgeThickness(*aRes, newThickness); + } + ModelAPI_Tools::setEdgeThickness(aResult, newThickness); + } + if (!aEdgeThicknessOfSubShapesEnabled) + break; + } + else if (!aShape->isNull()) { + ModelAPI_Tools::setSubShapeEdgeThickness(aResult, aShape, newThickness); + } + } + } + + Events_Loop::loop()->flush(Events_Loop::eventByName(EVENT_OBJECT_TO_REDISPLAY)); + aMgr->finishOperation(); + updateCommandStatus(); + myViewerProxy->update(); +} + + //************************************************************** void XGUI_Workshop::changeColor(const QMap>& theSelectedObjects) { diff --git a/src/XGUI/XGUI_Workshop.h b/src/XGUI/XGUI_Workshop.h index e3d949a7e..7d013bdb5 100644 --- a/src/XGUI/XGUI_Workshop.h +++ b/src/XGUI/XGUI_Workshop.h @@ -201,6 +201,11 @@ Q_OBJECT /// \return boolean value bool canChangeProperty(const QString& theActionName) const; + /// Change edge thickness of the results if it is possible. + /// The operation is available for construction, body and group results. + /// \param theObjects refers to selected objects. + void changeEdgeThickness(const QMap>& theObjects); + /// Change color of the selected objects (result and subshape of result) if it is possible /// The operation is available for subshape of result, construction, body and group results /// theSelectedObjects a list of selected objects diff --git a/src/XGUI/XGUI_msg_fr.ts b/src/XGUI/XGUI_msg_fr.ts index 9d89050d2..643f74d70 100644 --- a/src/XGUI/XGUI_msg_fr.ts +++ b/src/XGUI/XGUI_msg_fr.ts @@ -128,6 +128,10 @@ Transparency... Transparence... + + Edge Thickness... + Epaisseur Des Aretes... + Show Voir