From: nds Date: Fri, 22 Jul 2016 18:39:43 +0000 (+0300) Subject: Preparations for Split operation. It includes: X-Git-Tag: V_2.5.0~178 X-Git-Url: http://git.salome-platform.org/gitweb/?a=commitdiff_plain;h=ded1e8998ec9d6d57f5a5a122c4abced86874273;p=modules%2Fshaper.git Preparations for Split operation. It includes: 1. restart operation for tangent arc (do not use send of signal, do it linear) 2. MouseProcessor interface for mouseMove/mouseRelease sketch controls 3. ModelWidget::setFeature - do not store value if the attribute is initialized(reentrant operation, tangent arc) 4. initial split --- diff --git a/CMakeLists.txt b/CMakeLists.txt index b24566bcb..cdc22d071 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -86,6 +86,7 @@ ADD_SUBDIRECTORY (src/Model) ADD_SUBDIRECTORY (src/XAO) ADD_SUBDIRECTORY (src/GeomAPI) ADD_SUBDIRECTORY (src/ModelAPI) +ADD_SUBDIRECTORY (src/ModelGeomAlgo) ADD_SUBDIRECTORY (src/GeomAlgoAPI) ADD_SUBDIRECTORY (src/GeomAlgoImpl) ADD_SUBDIRECTORY (src/GeomData) diff --git a/src/GeomAlgoAPI/GeomAlgoAPI_ShapeTools.cpp b/src/GeomAlgoAPI/GeomAlgoAPI_ShapeTools.cpp index a40aff14e..6fa8f4b31 100644 --- a/src/GeomAlgoAPI/GeomAlgoAPI_ShapeTools.cpp +++ b/src/GeomAlgoAPI/GeomAlgoAPI_ShapeTools.cpp @@ -50,6 +50,11 @@ #include #include #include +#include + +#include +#include +#include //================================================================================================== double GeomAlgoAPI_ShapeTools::volume(const std::shared_ptr theShape) @@ -663,3 +668,34 @@ bool GeomAlgoAPI_ShapeTools::isParallel(const std::shared_ptr theE BRepExtrema_ExtCF anExt(anEdge, aFace); return anExt.IsParallel() == Standard_True; } + +//================================================================================================== +void GeomAlgoAPI_ShapeTools::splitShape(const std::shared_ptr& theBaseShape, + const std::set >& thePoints, + std::set >& theShapes) +{ + // General Fuse to split edge by vertices + BOPAlgo_Builder aBOP; + const TopoDS_Edge& aBaseEdge = theBaseShape->impl(); + aBOP.AddArgument(aBaseEdge); + + std::set >::const_iterator aPtIt = thePoints.begin(); + for (; aPtIt != thePoints.end(); ++aPtIt) { + std::shared_ptr aPnt = *aPtIt; + TopoDS_Vertex aV = BRepBuilderAPI_MakeVertex(gp_Pnt(aPnt->x(), aPnt->y(), aPnt->z())); + aBOP.AddArgument(aV); + } + + aBOP.Perform(); + if (aBOP.ErrorStatus()) + return; + + // Collect splits + const TopTools_ListOfShape& aSplits = aBOP.Modified(aBaseEdge); + TopTools_ListIteratorOfListOfShape anIt(aSplits); + for (; anIt.More(); anIt.Next()) { + std::shared_ptr anEdge(new GeomAPI_Shape); + anEdge->setImpl(new TopoDS_Shape(anIt.Value())); + theShapes.insert(anEdge); + } +} diff --git a/src/GeomAlgoAPI/GeomAlgoAPI_ShapeTools.h b/src/GeomAlgoAPI/GeomAlgoAPI_ShapeTools.h index 95a97f0bb..6a1da0e23 100644 --- a/src/GeomAlgoAPI/GeomAlgoAPI_ShapeTools.h +++ b/src/GeomAlgoAPI/GeomAlgoAPI_ShapeTools.h @@ -12,6 +12,8 @@ #include #include +#include + class GeomAPI_Edge; class GeomAPI_Dir; class GeomAPI_Face; @@ -102,6 +104,13 @@ public: /// \return true if edge is parallel to face. GEOMALGOAPI_EXPORT static bool isParallel(const std::shared_ptr theEdge, const std::shared_ptr theFace); + /// \brief Performs the split of the shape by points. + /// \param[in] theBaseShape shape that should be splitted. + /// \param[in] thePoints container of points to split + /// \param[out] theShapes container of shapes after split + GEOMALGOAPI_EXPORT static void splitShape(const std::shared_ptr& theBaseShape, + const std::set >& thePoints, + std::set >& theShapes); }; #endif diff --git a/src/ModelAPI/ModelAPI_Tools.cpp b/src/ModelAPI/ModelAPI_Tools.cpp index 7a7bbecb7..74a33d366 100755 --- a/src/ModelAPI/ModelAPI_Tools.cpp +++ b/src/ModelAPI/ModelAPI_Tools.cpp @@ -89,6 +89,20 @@ std::shared_ptr shape(const ResultPtr& theResult) return theResult->shape(); } +void shapesOfType(const FeaturePtr& theFeature, + const GeomAPI_Shape::ShapeType& theType, + std::set& theShapes) +{ + std::list aResults = theFeature->results(); + std::list::const_iterator aRIter = aResults.cbegin(); + for (; aRIter != aResults.cend(); aRIter++) { + ResultPtr aResult = *aRIter; + GeomShapePtr aShape = aResult->shape(); + if (aShape.get() && aShape->shapeType() == theType) + theShapes.insert(aShape); + } +} + const char* toString(ModelAPI_ExecState theExecState) { #define TO_STRING(__NAME__) case __NAME__: return #__NAME__; diff --git a/src/ModelAPI/ModelAPI_Tools.h b/src/ModelAPI/ModelAPI_Tools.h index 00f6cd4fd..14f028823 100755 --- a/src/ModelAPI/ModelAPI_Tools.h +++ b/src/ModelAPI/ModelAPI_Tools.h @@ -26,6 +26,14 @@ namespace ModelAPI_Tools { /// Returns shape from the given Result object MODELAPI_EXPORT std::shared_ptr shape(const ResultPtr& theResult); +/// Creates a container of shape of the feature results satisfied the given shape type +/// \param theFeature a source feature +/// \param theType shape type +/// \param an output container for shapes +MODELAPI_EXPORT void shapesOfType(const FeaturePtr& theFeature, + const GeomAPI_Shape::ShapeType& theType, + std::set& theShapes); + /*! Returns the feature error generated according to feature error and exec state * \param theFeature a feature * \return error value or empty string diff --git a/src/ModelGeomAlgo/CMakeLists.txt b/src/ModelGeomAlgo/CMakeLists.txt new file mode 100755 index 000000000..3d4a48070 --- /dev/null +++ b/src/ModelGeomAlgo/CMakeLists.txt @@ -0,0 +1,68 @@ +## Copyright (C) 2014-20xx CEA/DEN, EDF R&D + +FIND_PACKAGE(SWIG REQUIRED) +INCLUDE(${SWIG_USE_FILE}) +INCLUDE_DIRECTORIES(${CMAKE_CURRENT_SOURCE_DIR}) +INCLUDE(UnitTest) + +SET(PROJECT_HEADERS + ModelGeomAlgo.h + ModelGeomAlgo_Point2D.h +) + +SET(PROJECT_SOURCES + ModelGeomAlgo_Point2D.cpp +) + +SET(PROJECT_LIBRARIES + Config + GeomAPI + GeomDataAPI + GeomAlgoAPI + ModelAPI +) + +SET(CMAKE_SWIG_FLAGS -threads -Wall) +ADD_DEFINITIONS(-DMODELGEOMALGO_EXPORTS) + +ADD_LIBRARY(ModelGeomAlgo SHARED ${PROJECT_SOURCES} ${PROJECT_HEADERS}) +SET_TARGET_PROPERTIES(ModelGeomAlgo PROPERTIES LINKER_LANGUAGE CXX) +TARGET_LINK_LIBRARIES(ModelGeomAlgo ${PROJECT_LIBRARIES}) + +INCLUDE_DIRECTORIES(${PROJECT_SOURCE_DIR}/src/Config + ${PROJECT_SOURCE_DIR}/src/Events + ${PROJECT_SOURCE_DIR}/src/GeomAPI + ${PROJECT_SOURCE_DIR}/src/GeomDataAPI + ${PROJECT_SOURCE_DIR}/src/GeomAlgoAPI + ${PROJECT_SOURCE_DIR}/src/ModelAPI +) + + +SET_SOURCE_FILES_PROPERTIES(ModelGeomAlgo.i PROPERTIES CPLUSPLUS ON) +# "-includeall" is not needed: it starts to follow the standard inludes (like "string") without success +# SET_SOURCE_FILES_PROPERTIES(ModelGeomAlgo.i PROPERTIES SWIG_FLAGS) +SET_SOURCE_FILES_PROPERTIES(ModelGeomAlgo.i PROPERTIES SWIG_DEFINITIONS "-shadow") +#SET_SOURCE_FILES_PROPERTIES(ModelGeomAlgoPYTHON_wrap.cxx PROPERTIES COMPILE_FLAGS "-D_WIN32") + +SET(SWIG_SCRIPTS + ${CMAKE_CURRENT_BINARY_DIR}/ModelGeomAlgo.py +) + +SET(SWIG_LINK_LIBRARIES + ModelGeomAlgo + GeomAPI + ${PYTHON_LIBRARIES} +) + +SWIG_ADD_MODULE(ModelGeomAlgo python ModelGeomAlgo.i ${PROJECT_HEADERS}) +SWIG_LINK_LIBRARIES(ModelGeomAlgo ${SWIG_LINK_LIBRARIES}) + +IF(WIN32) + SET_TARGET_PROPERTIES(_ModelGeomAlgo PROPERTIES DEBUG_OUTPUT_NAME _ModelGeomAlgo_d) +ENDIF(WIN32) + +INSTALL(TARGETS _ModelGeomAlgo DESTINATION ${SHAPER_INSTALL_SWIG}) +INSTALL(TARGETS ModelGeomAlgo DESTINATION ${SHAPER_INSTALL_BIN}) +INSTALL(FILES ${SWIG_SCRIPTS} DESTINATION ${SHAPER_INSTALL_SWIG}) + +ADD_UNIT_TESTS(TestPoint2D.py) diff --git a/src/ModelGeomAlgo/ModelGeomAlgo.h b/src/ModelGeomAlgo/ModelGeomAlgo.h new file mode 100755 index 000000000..4121ef738 --- /dev/null +++ b/src/ModelGeomAlgo/ModelGeomAlgo.h @@ -0,0 +1,20 @@ +// Copyright (C) 2014-20xx CEA/DEN, EDF R&D + +#ifndef MODELGEOMALGO_H +#define MODELGEOMALGO_H + +#if defined MODELGEOMALGO_EXPORTS +#if defined WIN32 +#define MODELGEOMALGO_EXPORT __declspec( dllexport ) +#else +#define MODELGEOMALGO_EXPORT +#endif +#else +#if defined WIN32 +#define MODELGEOMALGO_EXPORT __declspec( dllimport ) +#else +#define MODELGEOMALGO_EXPORT +#endif +#endif + +#endif diff --git a/src/ModelGeomAlgo/ModelGeomAlgo.i b/src/ModelGeomAlgo/ModelGeomAlgo.i new file mode 100755 index 000000000..93438c9df --- /dev/null +++ b/src/ModelGeomAlgo/ModelGeomAlgo.i @@ -0,0 +1,37 @@ +/* ModelAPI.i */ +%module(directors="1") ModelGeomAlgo +%feature("director:except") { + if ($error != NULL) { + PyErr_Print(); + std::cerr << std::endl; + throw Swig::DirectorMethodException(); + } +} + +%{ + #include "ModelGeomAlgo_swig.h" +%} + +// import other modules +%import "GeomAPI.i" +%import "GeomDataAPI.i" +%import "ModelAPI.i" + + +// to avoid error on this +#define MODELGEOMALGO_EXPORT + +// standard definitions +%include "typemaps.i" +%include "std_string.i" +%include "std_list.i" +%include "std_shared_ptr.i" +%include "std_set.i" + +// shared pointers +// For Point2D.method() +%shared_ptr(ModelAPI_Point2D) + +// all supported interfaces +%include "ModelGeomAlgo_Point2D.h" + diff --git a/src/ModelGeomAlgo/ModelGeomAlgo_Point2D.cpp b/src/ModelGeomAlgo/ModelGeomAlgo_Point2D.cpp new file mode 100755 index 000000000..adaf45907 --- /dev/null +++ b/src/ModelGeomAlgo/ModelGeomAlgo_Point2D.cpp @@ -0,0 +1,103 @@ +// Copyright (C) 2014-20xx CEA/DEN, EDF R&D + +// File: ModelAPI_Tools.cpp +// Created: 20 Jul 2016 +// Author: Natalia ERMOLAEVA + +#include "ModelGeomAlgo_Point2D.h" + +#include +#include + +#include +#include + +#include +#include +#include +#include + +namespace ModelGeomAlgo_Point2D { + std::shared_ptr getPointOfRefAttr(ModelAPI_Feature* theFeature, + const std::string& theAttribute, + const std::string& theObjectFeatureKind, + const std::string& theObjectFeatureAttribute) + { + std::shared_ptr aPointAttr; + + /// essential check as it is called in openGl thread + if (!theFeature || !theFeature->data().get() || !theFeature->data()->isValid()) + return std::shared_ptr(); + + FeaturePtr aFeature; + std::shared_ptr anAttr = std::dynamic_pointer_cast< + ModelAPI_AttributeRefAttr>(theFeature->data()->attribute(theAttribute)); + if(!anAttr.get()) { + return std::shared_ptr(); + } + aFeature = ModelAPI_Feature::feature(anAttr->object()); + + bool aFeatureOfObjectKind = !theObjectFeatureKind.empty() && + !theObjectFeatureAttribute.empty() && + aFeature->getKind() == theObjectFeatureKind; + if (aFeature.get() && aFeatureOfObjectKind) + aPointAttr = std::dynamic_pointer_cast( + aFeature->data()->attribute(theObjectFeatureAttribute)); + else if (anAttr->attr()) + aPointAttr = std::dynamic_pointer_cast(anAttr->attr()); + + return aPointAttr; + } + + void getPointsOfReference(const std::shared_ptr& theFeature, + const std::string& theReferenceFeatureKind, + std::set >& theAttributes, + const std::string& theObjectFeatureKind, + const std::string& theObjectFeatureAttribute) + { + const std::set& aRefsList = theFeature->data()->refsToMe(); + std::set::const_iterator aIt; + for (aIt = aRefsList.cbegin(); aIt != aRefsList.cend(); ++aIt) { + std::shared_ptr aAttr = (*aIt); + FeaturePtr aRefFeature = std::dynamic_pointer_cast(aAttr->owner()); + if (aRefFeature->getKind() == theReferenceFeatureKind) { + std::list anAttributes = + theFeature->data()->attributes(ModelAPI_AttributeRefAttr::typeId()); + std::list::iterator anIter = anAttributes.begin(); + // it searches the first point of AttributeRefAtt + std::shared_ptr aPointAttr; + for(; anIter != anAttributes.end() && !aPointAttr.get(); anIter++) { + AttributeRefAttrPtr aRefAttribute = + std::dynamic_pointer_cast(*anIter); + if (aRefAttribute.get()) + aPointAttr = getPointOfRefAttr(aRefFeature.get(), aRefAttribute->id(), + theObjectFeatureKind, theObjectFeatureAttribute); + } + if (aPointAttr.get()) { + theAttributes.insert(aPointAttr); + } + } + } + } + + void getPointsInsideShape(const std::shared_ptr theBaseShape, + const std::set >& theAttributes, + const std::shared_ptr& theOrigin, + const std::shared_ptr& theDirX, + const std::shared_ptr& theDirY, + std::set >& thePoints) + { + std::set >::const_iterator anIt = theAttributes.begin(), + aLast = theAttributes.end(); + for (; anIt != aLast; anIt++) { + std::shared_ptr anAttribute = *anIt; + std::shared_ptr aPnt2d = anAttribute->pnt(); + std::shared_ptr aPnt = aPnt2d->to3D(theOrigin, theDirX, theDirY); + std::shared_ptr aVertexShape(new GeomAPI_Vertex(aPnt->x(), aPnt->y(), aPnt->z())); + if (GeomAlgoAPI_ShapeTools::isSubShapeInsideShape(aVertexShape, theBaseShape)) + thePoints.insert(aPnt); + } + } + + +} // namespace ModelGeomAlgo_Point2D diff --git a/src/ModelGeomAlgo/ModelGeomAlgo_Point2D.h b/src/ModelGeomAlgo/ModelGeomAlgo_Point2D.h new file mode 100755 index 000000000..b79aaff9d --- /dev/null +++ b/src/ModelGeomAlgo/ModelGeomAlgo_Point2D.h @@ -0,0 +1,67 @@ +// Copyright (C) 2014-20xx CEA/DEN, EDF R&D + +// File: ModelGeomAlgo_Point2D.h +// Created: 20 Jul 2016 +// Author: Natalia ERMOLAEVA + +#ifndef ModelGeomAlgo_Point2D_H +#define ModelGeomAlgo_Point2D_H + +#include "ModelGeomAlgo.h" + +class ModelAPI_Feature; +class GeomAPI_Shape; +class GeomAPI_Pnt; +class GeomAPI_Dir; + +class GeomDataAPI_Point2D; + +#include +#include + + +namespace ModelGeomAlgo_Point2D { + + /// Searches Point2D attribute of reference of the attribute of given feature + /// \param theFeature a feature to obtain AttributeRefAttr + /// \param theAttribute a name of AttributeRefAttr on the given feature + /// \param theObjectFeatureKind a feature kind in object of attribute that satisfies the search + /// \param theObjectFeatureAttribute a feature attribute in object that satisfies the search + /// \returns found point attribute or NULL + MODELGEOMALGO_EXPORT std::shared_ptr getPointOfRefAttr( + ModelAPI_Feature* theFeature, + const std::string& theAttribute, + const std::string& theObjectFeatureKind = "", + const std::string& theObjectFeatureAttribute = ""); + + /// Fills container of point 2D attributes, which refer to the feature through the references + /// features with the given kind + /// \param theFeature a feature where references should be searched (e.g. a sketch line) + /// \param theReferenceFeatureKind a kind of the feature to be processed (e.g. coincidence constraint) + /// \param theAttributes a container of found point 2D attributes + /// \param theObjectFeatureKind a feature kind in object of attribute that satisfies the search + /// \param theObjectFeatureAttribute a feature attribute in object that satisfies the search + /// \returns found point attribute or NULL + MODELGEOMALGO_EXPORT void getPointsOfReference(const std::shared_ptr& theFeature, + const std::string& theReferenceFeatureKind, + std::set >& theAttributes, + const std::string& theObjectFeatureKind = "", + const std::string& theObjectFeatureAttribute = ""); + + /// Removes attributes which points are out of the base shape + /// \param theBaseShape a shape of check + /// \param theAttributes a container of point 2D attributes + /// \param theOrigin origin of a plane to generate 3D point by 2D attribute point + /// \param theDirX plane X direction to generate 3D point by 2D attribute point + /// \param theDirY plane X direction to generate 3D point by 2D attribute point + /// \param thePoints a container of 3D points belong to the shape + MODELGEOMALGO_EXPORT void getPointsInsideShape( + const std::shared_ptr theBaseShape, + const std::set >& theAttributes, + const std::shared_ptr& theOrigin, + const std::shared_ptr& theDirX, + const std::shared_ptr& theDirY, + std::set >& thePoints); +} + +#endif diff --git a/src/ModelGeomAlgo/ModelGeomAlgo_swig.h b/src/ModelGeomAlgo/ModelGeomAlgo_swig.h new file mode 100755 index 000000000..c5522dc79 --- /dev/null +++ b/src/ModelGeomAlgo/ModelGeomAlgo_swig.h @@ -0,0 +1,20 @@ +// Copyright (C) 2014-20xx CEA/DEN, EDF R&D + +// File: ModelAPI_swig.h +// Created: Jul 20, 2016 +// Author: Natalia ERMOLAEVA + +#ifndef SRC_MODELGEOMALGO_MODELGEOMALGO_SWIG_H_ +#define SRC_MODELGEOMALGO_MODELGEOMALGO_SWIG_H_ + + #include + #include + #include + + #include "ModelGeomAlgo.h" + #include "ModelGeomAlgo_Point2D.h" + + #include + #include + +#endif /* SRC_MODELGEOMALGO_MODELGEOMALGO_SWIG_H_ */ diff --git a/src/ModelGeomAlgo/Test/TestPoint2D.py b/src/ModelGeomAlgo/Test/TestPoint2D.py new file mode 100755 index 000000000..c0344eab2 --- /dev/null +++ b/src/ModelGeomAlgo/Test/TestPoint2D.py @@ -0,0 +1,17 @@ +""" + TestPoint2D.py + Unit test for testing the Point2D algorithms + +""" +#========================================================================= +# Initialization of the test +#========================================================================= +from ModelAPI import * +from GeomDataAPI import * +from GeomAlgoAPI import * +from GeomAPI import * +from ModelGeomAlgo import * + +__updated__ = "2016-07-20" + +aSession = ModelAPI_Session.get() diff --git a/src/ModuleBase/ModuleBase_IModule.cpp b/src/ModuleBase/ModuleBase_IModule.cpp index a41824958..424260dcb 100644 --- a/src/ModuleBase/ModuleBase_IModule.cpp +++ b/src/ModuleBase/ModuleBase_IModule.cpp @@ -69,8 +69,7 @@ void ModuleBase_IModule::launchModal(const QString& theCmdId) } -void ModuleBase_IModule::launchOperation(const QString& theCmdId, - const bool isUpdatePropertyPanel) +void ModuleBase_IModule::launchOperation(const QString& theCmdId) { if (!myWorkshop->canStartOperation(theCmdId)) return; @@ -81,17 +80,10 @@ void ModuleBase_IModule::launchOperation(const QString& theCmdId, ModuleBase_ISelection* aSelection = myWorkshop->selection(); // Initialise operation with preliminary selection aFOperation->initSelection(aSelection, myWorkshop->viewer()); - sendOperation(aFOperation, isUpdatePropertyPanel); + workshop()->processLaunchOperation(aFOperation); } } - -void ModuleBase_IModule::sendOperation(ModuleBase_Operation* theOperation, - const bool isUpdatePropertyPanel) -{ - workshop()->processLaunchOperation(theOperation, isUpdatePropertyPanel); -} - Handle(AIS_InteractiveObject) ModuleBase_IModule::createPresentation(const ResultPtr& theResult) { return Handle(AIS_InteractiveObject)(); @@ -225,7 +217,7 @@ void ModuleBase_IModule::editFeature(FeaturePtr theFeature) (createOperation(aFeatureId)); if (aFOperation) { aFOperation->setFeature(theFeature); - sendOperation(aFOperation); + workshop()->processLaunchOperation(aFOperation); } } diff --git a/src/ModuleBase/ModuleBase_IModule.h b/src/ModuleBase/ModuleBase_IModule.h index ad8132e4a..e0937f09e 100755 --- a/src/ModuleBase/ModuleBase_IModule.h +++ b/src/ModuleBase/ModuleBase_IModule.h @@ -82,8 +82,7 @@ class MODULEBASE_EXPORT ModuleBase_IModule : public QObject /// Creates an operation and send it to loop /// \param theCmdId the operation name - /// \param isUpdatePropertyPanel if false, the property panel filling might be postponed - virtual void launchOperation(const QString& theCmdId, const bool isUpdatePropertyPanel = true); + virtual void launchOperation(const QString& theCmdId); /// Executes feature as a modal dialog box /// \param theCmdId the operation name @@ -239,11 +238,6 @@ class MODULEBASE_EXPORT ModuleBase_IModule : public QObject /// \param theCmdId the operation name virtual ModuleBase_Operation* createOperation(const std::string& theCmdId); - /// Sends the operation for launching - /// \param theOperation the operation - /// \param isUpdatePropertyPanel if false, the property panel filling might be postponed - virtual void sendOperation(ModuleBase_Operation* theOperation, const bool isUpdatePropertyPanel = true); - /// Create specific for the module presentation /// \param theResult an object for presentation /// \return created presentation or NULL(default value) @@ -292,10 +286,6 @@ class MODULEBASE_EXPORT ModuleBase_IModule : public QObject /// \param thePreviousAttributeID an index of the previous active attribute virtual bool processEnter(const std::string& thePreviousAttributeID) { return false; }; - /// Performs some GUI actions after an operation transaction is opened - /// Default realization is empty - virtual void beforeOperationStarted(ModuleBase_Operation* theOperation) {}; - /// Performs some GUI actions before an operation transaction is stopped /// Default realization is empty virtual void beforeOperationStopped(ModuleBase_Operation* theOperation) {}; diff --git a/src/ModuleBase/ModuleBase_IWorkshop.h b/src/ModuleBase/ModuleBase_IWorkshop.h index 432b5accd..5588ef63c 100644 --- a/src/ModuleBase/ModuleBase_IWorkshop.h +++ b/src/ModuleBase/ModuleBase_IWorkshop.h @@ -78,7 +78,7 @@ Q_OBJECT //! Performs the operation launch //! \param theOperation an operation to be launched - virtual void processLaunchOperation(ModuleBase_Operation* theOperation, const bool isUpdatePropertyPanel) = 0; + virtual void processLaunchOperation(ModuleBase_Operation* theOperation) = 0; //! Returns started operation by the operation identifier //! \param theId an operation id diff --git a/src/ModuleBase/ModuleBase_ModelWidget.cpp b/src/ModuleBase/ModuleBase_ModelWidget.cpp index 4420aff9a..77d58959b 100644 --- a/src/ModuleBase/ModuleBase_ModelWidget.cpp +++ b/src/ModuleBase/ModuleBase_ModelWidget.cpp @@ -209,8 +209,13 @@ void ModuleBase_ModelWidget::setFeature(const FeaturePtr& theFeature, const bool /// after debug, it may be corrected myFlushUpdateBlocked = !isUpdateFlushed; myFeature = theFeature; - if (theToStoreValue) - storeValue(); + if (theToStoreValue) { + /// it is possible that the attribute is filled before the operation is started, + /// e.g. by reentrant operation case some attributes are filled by values of + /// feature of previous operation, we should not lost them here + if (!theFeature->data()->attribute(attributeID())->isInitialized()) + storeValue(); + } myFlushUpdateBlocked = false; } diff --git a/src/ModuleBase/ModuleBase_Tools.cpp b/src/ModuleBase/ModuleBase_Tools.cpp index 8f184df15..305d2dfd1 100755 --- a/src/ModuleBase/ModuleBase_Tools.cpp +++ b/src/ModuleBase/ModuleBase_Tools.cpp @@ -62,6 +62,10 @@ #include #include +#ifdef WIN32 +#pragma warning(disable : 4996) // for getenv +#endif + const double tolerance = 1e-7; const double DEFAULT_DEVIATION_COEFFICIENT = 1.e-4; diff --git a/src/PartSet/CMakeLists.txt b/src/PartSet/CMakeLists.txt index e0d363f52..f237ce295 100644 --- a/src/PartSet/CMakeLists.txt +++ b/src/PartSet/CMakeLists.txt @@ -10,6 +10,7 @@ SET(PROJECT_HEADERS PartSet_CustomPrs.h PartSet_ExternalObjectsMgr.h PartSet_Module.h + PartSet_MouseProcessor.h PartSet_OperationPrs.h PartSet_OverconstraintListener.h PartSet_PreviewPlanes.h @@ -32,6 +33,7 @@ SET(PROJECT_HEADERS PartSet_WidgetSketchCreator.h PartSet_IconFactory.h PartSet_WidgetChoice.h + PartSet_WidgetSubShapeSelector.h ) SET(PROJECT_SOURCES @@ -59,6 +61,7 @@ SET(PROJECT_SOURCES PartSet_MenuMgr.cpp PartSet_WidgetSketchCreator.cpp PartSet_IconFactory.cpp + PartSet_WidgetSubShapeSelector.cpp ) SET(PROJECT_RESOURCES @@ -71,10 +74,11 @@ SET(PROJECT_RESOURCES SET(PROJECT_LIBRARIES ModuleBase + ModelGeomAlgo Config GeomAPI GeomDataAPI - SketcherPrs + SketcherPrs ${QT_LIBRARIES} ${CAS_KERNEL} ${CAS_SHAPE} @@ -102,6 +106,7 @@ INCLUDE_DIRECTORIES(${PROJECT_SOURCE_DIR}/src/XGUI ${PROJECT_SOURCE_DIR}/src/Events ${PROJECT_SOURCE_DIR}/src/ModuleBase ${PROJECT_SOURCE_DIR}/src/ModelAPI + ${PROJECT_SOURCE_DIR}/src/ModelGeomAlgo ${PROJECT_SOURCE_DIR}/src/GeomDataAPI ${PROJECT_SOURCE_DIR}/src/GeomAlgoAPI ${PROJECT_SOURCE_DIR}/src/SketchPlugin diff --git a/src/PartSet/PartSet_Module.cpp b/src/PartSet/PartSet_Module.cpp index 7f8367528..6ca6ad713 100755 --- a/src/PartSet/PartSet_Module.cpp +++ b/src/PartSet/PartSet_Module.cpp @@ -283,97 +283,98 @@ void PartSet_Module::operationAborted(ModuleBase_Operation* theOperation) void PartSet_Module::operationStarted(ModuleBase_Operation* theOperation) { - ModuleBase_IWorkshop* anIWorkshop = workshop(); - if (!theOperation->getDescription()->hasXmlRepresentation()) { //!< No need for property panel - anIWorkshop->updateCommandStatus(); - } - else { - ModuleBase_OperationFeature* aFOperation = dynamic_cast - (theOperation); - if (aFOperation) { - XGUI_Workshop* aWorkshop = XGUI_Tools::workshop(anIWorkshop); - XGUI_PropertyPanel* aPropertyPanel = aWorkshop->propertyPanel(); - ModuleBase_ModelWidget* aFilledWidget = 0; - bool aPostonedWidgetActivation = false; - FeaturePtr aFeature = aFOperation->feature(); - - std::string aGreedAttributeId = ModuleBase_Tools::findGreedAttribute(anIWorkshop, aFeature); + ModuleBase_OperationFeature* aFOperation = dynamic_cast + (theOperation); + if (aFOperation) { + XGUI_Workshop* aWorkshop = XGUI_Tools::workshop(workshop()); + XGUI_PropertyPanel* aPropertyPanel = aWorkshop->propertyPanel(); + + ModuleBase_ModelWidget* aFilledWidget = 0; + bool aPostonedWidgetActivation = false; + + FeaturePtr aFeature = aFOperation->feature(); + /// Restart sketcher operations automatically + /// it is important to call method of sketch reentrant manager before filling of PP + /// because it fills some created feature attributes, these new values should be used + /// to fill the property panel + mySketchReentrantMgr->operationStarted(theOperation); + + aWorkshop->fillPropertyPanel(aFOperation); + // filling the operation values by the current selection + // if the operation can be committed after the controls filling, the method perform should + // be stopped. Otherwise unnecessary presentations can be shown(e.g. operation prs in sketch) + bool isOperationCommitted = false; + if (!aFOperation->isEditOperation()) { + std::string aGreedAttributeId = ModuleBase_Tools::findGreedAttribute(workshop(), aFeature); // if there is a greed attribute, automatic commit by preselection for this feature is prohibited - aWorkshop->setPropertyPanel(aFOperation); - - // filling the operation values by the current selection - // if the operation can be committed after the controls filling, the method perform should - // be stopped. Otherwise unnecessary presentations can be shown(e.g. operation prs in sketch) - bool isOperationCommitted = false; - if (!aFOperation->isEditOperation()) { - aFilledWidget = aFOperation->activateByPreselection(aGreedAttributeId); - if (currentOperation() != aFOperation) - isOperationCommitted = true; - else { - if (aGreedAttributeId.empty()) { - // a signal should be emitted before the next widget activation - // because, the activation of the next widget will give a focus to the widget. As a result - // the value of the widget is initialized. And commit may happens until the value is entered. - if (aFilledWidget) { - if (mySketchReentrantMgr->canBeCommittedByPreselection()) - isOperationCommitted = mySketchMgr->operationActivatedByPreselection(); - // activate the next obligatory widget - if (!isOperationCommitted) - aPropertyPanel->activateNextWidget(aFilledWidget); - } + aFilledWidget = aFOperation->activateByPreselection(aGreedAttributeId); + if (currentOperation() != aFOperation) + isOperationCommitted = true; + else { + if (aGreedAttributeId.empty()) { + // a signal should be emitted before the next widget activation + // because, the activation of the next widget will give a focus to the widget. As a result + // the value of the widget is initialized. And commit may happens until the value is entered. + if (aFilledWidget) { + if (mySketchReentrantMgr->canBeCommittedByPreselection()) + isOperationCommitted = mySketchMgr->operationActivatedByPreselection(); + // activate the next obligatory widget + if (!isOperationCommitted) + aPropertyPanel->activateNextWidget(aFilledWidget); } - else { // there is a greed widget - const QList& aWidgets = aPropertyPanel->modelWidgets(); - std::string aFirstAttributeId = aWidgets.front()->attributeID(); - // activate next widget after greeded if it is the first widget in the panel - // else the first panel widget is already activated by operation start - if (aFirstAttributeId == aGreedAttributeId) - aPostonedWidgetActivation = true; - } - } - } if (!isOperationCommitted) { - anIWorkshop->updateCommandStatus(); - aWorkshop->connectToPropertyPanel(true); - operationStartedInternal(aFOperation); - - // the objects of the current operation should be deactivated - QObjectPtrList anObjects; - anObjects.append(aFeature); - std::list aResults; - ModelAPI_Tools::allResults(aFeature, aResults); - std::list::const_iterator aIt; - for (aIt = aResults.begin(); aIt != aResults.end(); ++aIt) { - anObjects.append(*aIt); } - QObjectPtrList::const_iterator anIt = anObjects.begin(), aLast = anObjects.end(); - for (; anIt != aLast; anIt++) - aWorkshop->deactivateActiveObject(*anIt, false); - if (anObjects.size() > 0) { - XGUI_Displayer* aDisplayer = aWorkshop->displayer(); - aDisplayer->updateViewer(); + else { // there is a greed widget + const QList& aWidgets = aPropertyPanel->modelWidgets(); + std::string aFirstAttributeId = aWidgets.front()->attributeID(); + // activate next widget after greeded if it is the first widget in the panel + // else the first panel widget is already activated by operation start + if (aFirstAttributeId == aGreedAttributeId) + aPostonedWidgetActivation = true; } } - if (aPostonedWidgetActivation) { - // if the widget is an empty in the chain of activated widgets, the current operation - // is restarted. It should be performed after functionality of the operation starting - aPropertyPanel->activateNextWidget(aFilledWidget); + } if (!isOperationCommitted) { + workshop()->updateCommandStatus(); + aWorkshop->connectToPropertyPanel(true); + updateSketcherOnStart(aFOperation); + updatePresentationsOnStart(aFOperation); + + // the objects of the current operation should be deactivated + QObjectPtrList anObjects; + anObjects.append(aFeature); + std::list aResults; + ModelAPI_Tools::allResults(aFeature, aResults); + std::list::const_iterator aIt; + for (aIt = aResults.begin(); aIt != aResults.end(); ++aIt) { + anObjects.append(*aIt); } + QObjectPtrList::const_iterator anIt = anObjects.begin(), aLast = anObjects.end(); + for (; anIt != aLast; anIt++) + aWorkshop->deactivateActiveObject(*anIt, false); + if (anObjects.size() > 0) { + XGUI_Displayer* aDisplayer = aWorkshop->displayer(); + aDisplayer->updateViewer(); + } + } + if (aPostonedWidgetActivation) { + // if the widget is an empty in the chain of activated widgets, the current operation + // is restarted. It should be performed after functionality of the operation starting + aPropertyPanel->activateNextWidget(aFilledWidget); } } } -void PartSet_Module::operationStartedInternal(ModuleBase_Operation* theOperation) +void PartSet_Module::updateSketcherOnStart(ModuleBase_Operation* theOperation) { - /// Restart sketcher operations automatically - mySketchReentrantMgr->operationStarted(theOperation); - if (PartSet_SketcherMgr::isSketchOperation(theOperation)) { mySketchMgr->startSketch(theOperation); } else if (PartSet_SketcherMgr::isNestedSketchOperation(theOperation)) { mySketchMgr->startNestedSketch(theOperation); } +} +void PartSet_Module::updatePresentationsOnStart(ModuleBase_Operation* theOperation) +{ ModuleBase_OperationFeature* aFOperation = dynamic_cast(theOperation); if (aFOperation) { myCustomPrs->activate(aFOperation->feature(), ModuleBase_IModule::CustomizeArguments, true); @@ -854,14 +855,13 @@ bool PartSet_Module::canCommitOperation() const return true; } -void PartSet_Module::launchOperation(const QString& theCmdId, - const bool isUpdatePropertyPanel) +void PartSet_Module::launchOperation(const QString& theCmdId) { myIsOperationIsLaunched = true; storeConstraintsState(theCmdId.toStdString()); updateConstraintsState(theCmdId.toStdString()); - ModuleBase_IModule::launchOperation(theCmdId, isUpdatePropertyPanel); + ModuleBase_IModule::launchOperation(theCmdId); myIsOperationIsLaunched = false; } @@ -1299,11 +1299,6 @@ bool PartSet_Module::processEnter(const std::string& thePreviousAttributeID) return mySketchReentrantMgr->processEnter(thePreviousAttributeID); } -//****************************************************** -void PartSet_Module::beforeOperationStarted(ModuleBase_Operation* theOperation) -{ -} - //****************************************************** void PartSet_Module::beforeOperationStopped(ModuleBase_Operation* theOperation) { diff --git a/src/PartSet/PartSet_Module.h b/src/PartSet/PartSet_Module.h index 0ad602e0c..014790aa4 100755 --- a/src/PartSet/PartSet_Module.h +++ b/src/PartSet/PartSet_Module.h @@ -102,8 +102,7 @@ public: /// Creates an operation and send it to loop /// \param theCmdId the operation name - /// \param isUpdatePropertyPanel if false, the property panel filling might be postponed - virtual void launchOperation(const QString& theCmdId, const bool isUpdatePropertyPanel = true); + virtual void launchOperation(const QString& theCmdId); /// Realizes some functionality by an operation start /// Displays all sketcher sub-Objects, hides sketcher result, appends selection filters @@ -303,10 +302,6 @@ public: /// \param thePreviousAttributeID an index of the previous active attribute virtual bool processEnter(const std::string& thePreviousAttributeID); - /// Performs some GUI actions after an operation transaction is opened - /// Default realization is empty - virtual void beforeOperationStarted(ModuleBase_Operation* theOperation); - /// Performs some GUI actions before an operation transaction is stopped /// Default realization is empty virtual void beforeOperationStopped(ModuleBase_Operation* theOperation); @@ -385,11 +380,13 @@ protected: /// \param isToConnect a boolean value whether connect or disconnect virtual void connectToPropertyPanel(ModuleBase_ModelWidget* theWidget, const bool isToConnect); - /// Realizes some functionality by an operation start - /// Displays all sketcher sub-Objects, hides sketcher result, appends selection filters - /// Activate the operation presentation - /// \param theOperation a started operation - virtual void operationStartedInternal(ModuleBase_Operation* theOperation); + /// Updates reentrant manager state or sketcher operations for the started operation + /// \param theOperation the started operation + void updateSketcherOnStart(ModuleBase_Operation* theOperation); + + /// Updates presetnations of results and arguments by operation start + /// \param theOperation the started operation + void updatePresentationsOnStart(ModuleBase_Operation* theOperation); private slots: void onTreeViewDoubleClick(const QModelIndex&); diff --git a/src/PartSet/PartSet_MouseProcessor.h b/src/PartSet/PartSet_MouseProcessor.h new file mode 100755 index 000000000..08f9eedce --- /dev/null +++ b/src/PartSet/PartSet_MouseProcessor.h @@ -0,0 +1,40 @@ +// Copyright (C) 2014-20xx CEA/DEN, EDF R&D + +// File: PartSet_MouseProcessor.hxx +// Created: 21 Jul 2016 +// Author: Natalia ERMOLAEVA + +#ifndef PartSet_MouseProcessor_H +#define PartSet_MouseProcessor_H + +#include "PartSet.h" + +class ModuleBase_IViewWindow; +class QMouseEvent; + +/** + * This is an interface to allow processing of mouse events. Implementation of necessary methods +* should be done in a child. +*/ +class PartSet_MouseProcessor +{ +public: + /// Processing the mouse move event in the viewer + /// \param theWindow a view window + /// \param theEvent a mouse event + PARTSET_EXPORT virtual void mouseMoved(ModuleBase_IViewWindow* theWindow, QMouseEvent* theEvent) {} + /// Processing the mouse press event in the viewer + /// \param theWindow a view window + /// \param theEvent a mouse event + PARTSET_EXPORT virtual void mousePressed(ModuleBase_IViewWindow* theWindow, QMouseEvent* theEvent) {} + /// Processing the mouse release event in the viewer + /// \param theWindow a view window + /// \param theEvent a mouse event + PARTSET_EXPORT virtual void mouseReleased(ModuleBase_IViewWindow* theWindow, QMouseEvent* theEvent) {} + /// Processing the mouse double click event in the viewer + /// \param theWindow a view window + /// \param theEvent a mouse event + PARTSET_EXPORT virtual void mouseDoubleClick(ModuleBase_IViewWindow* theWindow, QMouseEvent* theEvent) {} +}; + +#endif diff --git a/src/PartSet/PartSet_SketcherMgr.cpp b/src/PartSet/PartSet_SketcherMgr.cpp index 29a428ed1..0974ef4b6 100755 --- a/src/PartSet/PartSet_SketcherMgr.cpp +++ b/src/PartSet/PartSet_SketcherMgr.cpp @@ -7,8 +7,7 @@ #include "PartSet_SketcherMgr.h" #include "PartSet_SketcherReetntrantMgr.h" #include "PartSet_Module.h" -#include "PartSet_WidgetPoint2d.h" -#include "PartSet_WidgetPoint2dDistance.h" +#include "PartSet_MouseProcessor.h" #include "PartSet_Tools.h" #include "PartSet_WidgetSketchLabel.h" #include "PartSet_WidgetEditor.h" @@ -476,6 +475,11 @@ void PartSet_SketcherMgr::onMouseReleased(ModuleBase_IViewWindow* theWnd, QMouse aWorkshop->viewer()->enableDrawMode(myPreviousDrawModeEnabled); myIsDragging = false; + + ModuleBase_ModelWidget* anActiveWidget = getActiveWidget(); + PartSet_MouseProcessor* aProcessor = dynamic_cast(anActiveWidget); + if (aProcessor) + aProcessor->mouseReleased(theWnd, theEvent); } void PartSet_SketcherMgr::onMouseMoved(ModuleBase_IViewWindow* theWnd, QMouseEvent* theEvent) @@ -483,31 +487,27 @@ void PartSet_SketcherMgr::onMouseMoved(ModuleBase_IViewWindow* theWnd, QMouseEve if (myModule->sketchReentranceMgr()->processMouseMoved(theWnd, theEvent)) return; - if (isNestedCreateOperation(getCurrentOperation()) && !myIsMouseOverViewProcessed) { - myIsMouseOverViewProcessed = true; + if (isNestedCreateOperation(getCurrentOperation())) { // 1. perform the widget mouse move functionality and display the presentation // the mouse move should be processed in the widget, if it can in order to visualize correct // presentation. These widgets correct the feature attribute according to the mouse position ModuleBase_ModelWidget* anActiveWidget = getActiveWidget(); - PartSet_WidgetPoint2D* aPoint2DWdg = dynamic_cast(anActiveWidget); - if (aPoint2DWdg) { - aPoint2DWdg->onMouseMove(theWnd, theEvent); - } - PartSet_WidgetPoint2dDistance* aDistanceWdg = dynamic_cast - (anActiveWidget); - if (aDistanceWdg) { - aDistanceWdg->onMouseMove(theWnd, theEvent); - } - // the feature is to be erased here, but it is correct to call canDisplayObject because - // there can be additional check (e.g. editor widget in distance constraint) - ModuleBase_OperationFeature* aFOperation = dynamic_cast - (getCurrentOperation()); - if (aFOperation) { - FeaturePtr aFeature = aFOperation->feature(); - visualizeFeature(aFeature, aFOperation->isEditOperation(), canDisplayObject(aFeature)); + PartSet_MouseProcessor* aProcessor = dynamic_cast(anActiveWidget); + if (aProcessor) + aProcessor->mouseMoved(theWnd, theEvent); + if (!myIsMouseOverViewProcessed) { + myIsMouseOverViewProcessed = true; + + // the feature is to be erased here, but it is correct to call canDisplayObject because + // there can be additional check (e.g. editor widget in distance constraint) + ModuleBase_OperationFeature* aFOperation = dynamic_cast + (getCurrentOperation()); + if (aFOperation) { + FeaturePtr aFeature = aFOperation->feature(); + visualizeFeature(aFeature, aFOperation->isEditOperation(), canDisplayObject(aFeature)); + } } } - //myClickedPoint.clear(); if (myIsDragging) { @@ -1048,7 +1048,7 @@ void PartSet_SketcherMgr::stopNestedSketch(ModuleBase_Operation* theOperation) /// improvement to deselect automatically all eventual selected objects, when // returning to the neutral point of the Sketcher // if the operation is restarted, the previous selection is used to initialize started operation - if (myModule->isSketchNeutralPointActivated()) + if (!myModule->sketchReentranceMgr()->isInternalEditStarted()) workshop()->selector()->clearSelection(); } @@ -1233,11 +1233,9 @@ bool PartSet_SketcherMgr::canDisplayConstraint(const FeaturePtr& theFeature, bool aSwitchedOn = true; const QStringList& aConstrIds = constraintsIdList(); - const QStringList& aReplicationIds = replicationsIdList(); std::string aKind = theFeature->getKind(); - if (aConstrIds.contains(aKind.c_str()) || - aReplicationIds.contains(aKind.c_str())) { + if (aConstrIds.contains(QString(aKind.c_str()))) { bool isTypedConstraint = false; switch (theState) { diff --git a/src/PartSet/PartSet_SketcherReetntrantMgr.cpp b/src/PartSet/PartSet_SketcherReetntrantMgr.cpp index 7f92c9646..e11f6d61c 100755 --- a/src/PartSet/PartSet_SketcherReetntrantMgr.cpp +++ b/src/PartSet/PartSet_SketcherReetntrantMgr.cpp @@ -108,6 +108,12 @@ void PartSet_SketcherReetntrantMgr::operationStarted(ModuleBase_Operation* theOp if (!isActiveMgr()) return; + if (myPreviousFeature.get() && myRestartingMode == RM_LastFeatureUsed) { + ModuleBase_OperationFeature* aCurrentOperation = dynamic_cast( + myWorkshop->currentOperation()); + CompositeFeaturePtr aSketch = module()->sketchMgr()->activeSketch(); + copyReetntrantAttributes(myPreviousFeature, aCurrentOperation->feature(), aSketch); + } resetFlags(); } @@ -136,7 +142,6 @@ bool PartSet_SketcherReetntrantMgr::processMouseMoved(ModuleBase_IViewWindow* /* ModuleBase_IPropertyPanel* aPanel = myWorkshop->currentOperation()->propertyPanel(); bool aWidgetIsFilled = false; - //bool aCanBeActivatedByMove = false; FeaturePtr aCurrentFeature = aFOperation->feature(); bool isLineFeature = false, isArcFeature = false; if (aCurrentFeature->getKind() == SketchPlugin_Line::ID()) @@ -146,34 +151,15 @@ bool PartSet_SketcherReetntrantMgr::processMouseMoved(ModuleBase_IViewWindow* /* bool aCanBeActivatedByMove = isLineFeature || isArcFeature; if (aCanBeActivatedByMove) { + myPreviousFeature = aFOperation->feature(); restartOperation(); + myPreviousFeature = FeaturePtr(); anActiveWidget = module()->activeWidget(); aCurrentFeature = anActiveWidget->feature(); aProcessed = true; - if (isLineFeature) { - PartSet_WidgetPoint2D* aPoint2DWdg = dynamic_cast(anActiveWidget); - if (aPoint2DWdg) { // line, start point should be equal last point of the last feature line - QList aSelection; - aSelection.append(std::shared_ptr( - new ModuleBase_ViewerPrs(aLastFeature, GeomShapePtr(), NULL))); - aWidgetIsFilled = aPoint2DWdg->setSelection(aSelection, true); - } - } - else if (isArcFeature) { // arc, start point should be equal last point of the last feature arc - if (aCurrentFeature->getKind() == SketchPlugin_Arc::ID()) { - // get the last point of the previuos arc feature(geom point 2d) - std::shared_ptr aData = aLastFeature->data(); - std::shared_ptr aPointAttr = - std::dynamic_pointer_cast( - aData->attribute(SketchPlugin_Arc::END_ID())); - // get point attribute on the current feature - AttributeRefAttrPtr aTangentPointAttr = aCurrentFeature->data()->refattr( - SketchPlugin_Arc::TANGENT_POINT_ID()); - aTangentPointAttr->setAttr(aPointAttr); - aWidgetIsFilled = true; - } - } + if (isLineFeature || isArcFeature) + aWidgetIsFilled = true; } if (aWidgetIsFilled) aPanel->activateNextWidget(anActiveWidget); @@ -209,7 +195,11 @@ bool PartSet_SketcherReetntrantMgr::processMouseReleased(ModuleBase_IViewWindow* // onMouseRelease happens, which correct the point position ModuleBase_Tools::blockUpdateViewer(true); + ModuleBase_OperationFeature* aFOperation = dynamic_cast + (myWorkshop->currentOperation()); + myPreviousFeature = aFOperation->feature(); restartOperation(); + myPreviousFeature = FeaturePtr(); aProcessed = true; // fill the first widget by the mouse event point @@ -218,7 +208,7 @@ bool PartSet_SketcherReetntrantMgr::processMouseReleased(ModuleBase_IViewWindow* PartSet_WidgetPoint2D* aPoint2DWdg = dynamic_cast(module()->activeWidget()); ModuleBase_ModelWidget* aFirstWidget = aPanel->findFirstAcceptingValueWidget(); if (aPoint2DWdg && aPoint2DWdg == aFirstWidget) { - aPoint2DWdg->onMouseRelease(theWnd, theEvent); + aPoint2DWdg->mouseReleased(theWnd, theEvent); } // unblock viewer update ModuleBase_Tools::blockUpdateViewer(false); @@ -458,16 +448,7 @@ void PartSet_SketcherReetntrantMgr::restartOperation() myIsFlagsBlocked = true; FeaturePtr aPrevFeature = aFOperation->feature(); aFOperation->commit(); - module()->launchOperation(aFOperation->id(), false); - // allow the same attribute values in restarted operation - ModuleBase_OperationFeature* aCurrentOperation = dynamic_cast( - myWorkshop->currentOperation()); - copyReetntrantAttributes(aPrevFeature, aCurrentOperation->feature()); - - // update property panel: it should be done because in launchOperation, the 'false' is given - workshop()->propertyPanel()->updateContentWidget(aCurrentOperation->feature()); - workshop()->propertyPanel()->createContentPanel(aCurrentOperation->feature()); - + module()->launchOperation(aFOperation->id()); myIsFlagsBlocked = false; resetFlags(); // we should avoid processing of the signal about no more widgets attributes and @@ -493,7 +474,8 @@ void PartSet_SketcherReetntrantMgr::createInternalFeature() CompositeFeaturePtr aSketch = module()->sketchMgr()->activeSketch(); myInternalFeature = aSketch->addFeature(anOperationFeature->getKind()); - bool isFeatureChanged = copyReetntrantAttributes(anOperationFeature, myInternalFeature); + bool isFeatureChanged = copyReetntrantAttributes(anOperationFeature, myInternalFeature, + aSketch, false); XGUI_PropertyPanel* aPropertyPanel = dynamic_cast (aFOperation->propertyPanel()); @@ -538,6 +520,7 @@ void PartSet_SketcherReetntrantMgr::deleteInternalFeature() QObjectPtrList anObjects; anObjects.append(myInternalFeature); workshop()->deleteFeatures(anObjects); + myInternalFeature = FeaturePtr(); } void PartSet_SketcherReetntrantMgr::resetFlags() @@ -550,21 +533,66 @@ void PartSet_SketcherReetntrantMgr::resetFlags() } bool PartSet_SketcherReetntrantMgr::copyReetntrantAttributes(const FeaturePtr& theSourceFeature, - const FeaturePtr& theNewFeature) + const FeaturePtr& theNewFeature, + const CompositeFeaturePtr& theSketch, + const bool isTemporary) { bool aChanged = false; - std::string aTypeAttributeId; - if (theSourceFeature->getKind() == SketchPlugin_Circle::ID()) { - aTypeAttributeId = SketchPlugin_Circle::CIRCLE_TYPE(); + if (!theSourceFeature.get()) + return aChanged; + + std::string aFeatureKind = theSourceFeature->getKind(); + if (aFeatureKind == SketchPlugin_Line::ID()) { + // Initialize new line with first point equal to end of previous + std::shared_ptr aSFData = theSourceFeature->data(); + std::shared_ptr aSPoint = std::dynamic_pointer_cast( + aSFData->attribute(SketchPlugin_Line::END_ID())); + std::shared_ptr aNFData = theNewFeature->data(); + std::shared_ptr aNPoint = std::dynamic_pointer_cast( + aNFData->attribute(SketchPlugin_Line::START_ID())); + aNPoint->setValue(aSPoint->x(), aSPoint->y()); + PartSet_Tools::createConstraint(theSketch, aSPoint, aNPoint); + + aNPoint = std::dynamic_pointer_cast( + aSFData->attribute(SketchPlugin_Line::END_ID())); + aNPoint->setValue(aSPoint->x(), aSPoint->y()); } - if (theSourceFeature->getKind() == SketchPlugin_Arc::ID()) { - aTypeAttributeId = SketchPlugin_Arc::ARC_TYPE(); + else if (aFeatureKind == SketchPlugin_Circle::ID()) { + // set circle type + std::string aTypeAttributeId = SketchPlugin_Circle::CIRCLE_TYPE(); + AttributeStringPtr aSourceFeatureTypeAttr = theSourceFeature->data()->string(aTypeAttributeId); + AttributeStringPtr aNewFeatureTypeAttr = theNewFeature->data()->string(aTypeAttributeId); + aNewFeatureTypeAttr->setValue(aSourceFeatureTypeAttr->value()); + //ModuleBase_Tools::flushUpdated(theNewFeature); + aChanged = true; } - if (!aTypeAttributeId.empty()) { + else if (aFeatureKind == SketchPlugin_Arc::ID()) { + // set arc type + std::string aTypeAttributeId = SketchPlugin_Arc::ARC_TYPE(); AttributeStringPtr aSourceFeatureTypeAttr = theSourceFeature->data()->string(aTypeAttributeId); AttributeStringPtr aNewFeatureTypeAttr = theNewFeature->data()->string(aTypeAttributeId); aNewFeatureTypeAttr->setValue(aSourceFeatureTypeAttr->value()); - ModuleBase_Tools::flushUpdated(theNewFeature); + + // if the arc is tangent, set coincidence to end point of the previous arc + std::string anArcType = aSourceFeatureTypeAttr->value(); + if (anArcType == SketchPlugin_Arc::ARC_TYPE_TANGENT()) { + // get the last point of the previuos arc feature(geom point 2d) + std::shared_ptr aSData = theSourceFeature->data(); + std::shared_ptr aSPointAttr = + std::dynamic_pointer_cast( + aSData->attribute(SketchPlugin_Arc::END_ID())); + // get point attribute on the current feature + AttributeRefAttrPtr aTangentPointAttr = theNewFeature->data()->refattr( + SketchPlugin_Arc::TANGENT_POINT_ID()); + aTangentPointAttr->setAttr(aSPointAttr); + + std::shared_ptr aNPointAttr = + std::dynamic_pointer_cast( + theNewFeature->data()->attribute(SketchPlugin_Arc::END_ID())); + aNPointAttr->setValue(aSPointAttr->x(), aSPointAttr->y()); + + } + //ModuleBase_Tools::flushUpdated(theNewFeature); aChanged = true; } return aChanged; diff --git a/src/PartSet/PartSet_SketcherReetntrantMgr.h b/src/PartSet/PartSet_SketcherReetntrantMgr.h index 74e8bd92b..72921d803 100755 --- a/src/PartSet/PartSet_SketcherReetntrantMgr.h +++ b/src/PartSet/PartSet_SketcherReetntrantMgr.h @@ -16,6 +16,8 @@ class ModuleBase_Operation; class ModuleBase_ModelWidget; class ModuleBase_IViewWindow; +class ModelAPI_CompositeFeature; + class QMouseEvent; class XGUI_Workshop; @@ -150,9 +152,13 @@ private: /// This is type for Circle and Arc features /// \param theSourceFeature a source feature /// \param theNewFeature a new feature + /// \param theSketch an active sketch + /// \param isTemporary is used to do not create additional features(e.g. coicidence for line) /// \return true is something is copied static bool copyReetntrantAttributes(const FeaturePtr& theSourceFeature, - const FeaturePtr& theNewFeature); + const FeaturePtr& theNewFeature, + const std::shared_ptr& theSketch, + const bool isTemporary = false); static bool isTangentArc(ModuleBase_Operation* theOperation); @@ -172,6 +178,7 @@ private: bool myIsFlagsBlocked; /// true when reset of flags should not be perfromed bool myIsInternalEditOperation; /// true when the 'internal' edit is started + FeaturePtr myPreviousFeature; /// feature of the previous operation, which is restarted FeaturePtr myInternalFeature; QWidget* myInternalWidget; ModuleBase_ModelWidget* myInternalActiveWidget; diff --git a/src/PartSet/PartSet_WidgetPoint2d.cpp b/src/PartSet/PartSet_WidgetPoint2d.cpp index 4cfede1e2..e0e577163 100644 --- a/src/PartSet/PartSet_WidgetPoint2d.cpp +++ b/src/PartSet/PartSet_WidgetPoint2d.cpp @@ -225,24 +225,6 @@ bool PartSet_WidgetPoint2D::setSelection(QList& theValu PartSet_Tools::setConstraints(mySketch, feature(), attributeID(), aX, aY); } } - else if (canBeActivatedByMove()) { - if (feature()->getKind() == SketchPlugin_Line::ID()) { - FeaturePtr aFeature = std::dynamic_pointer_cast(aValue->object()); - // Initialize new line with first point equal to end of previous - if (aFeature.get()) { - std::shared_ptr aData = aFeature->data(); - std::shared_ptr aPoint = - std::dynamic_pointer_cast( - aData->attribute(SketchPlugin_Line::END_ID())); - if (aPoint) { - setPoint(aPoint->x(), aPoint->y()); - PartSet_Tools::setConstraints(mySketch, feature(), attributeID(), aPoint->x(), - aPoint->y()); - isDone = true; - } - } - } - } return isDone; } @@ -378,12 +360,6 @@ QList PartSet_WidgetPoint2D::getControls() const void PartSet_WidgetPoint2D::activateCustom() { - ModuleBase_IViewer* aViewer = myWorkshop->viewer(); - connect(aViewer, SIGNAL(mouseMove(ModuleBase_IViewWindow*, QMouseEvent*)), - this, SLOT(onMouseMove(ModuleBase_IViewWindow*, QMouseEvent*))); - connect(aViewer, SIGNAL(mouseRelease(ModuleBase_IViewWindow*, QMouseEvent*)), - this, SLOT(onMouseRelease(ModuleBase_IViewWindow*, QMouseEvent*))); - QIntList aModes; aModes << TopAbs_VERTEX; aModes << TopAbs_EDGE; @@ -396,16 +372,6 @@ void PartSet_WidgetPoint2D::activateCustom() } } -bool PartSet_WidgetPoint2D::canBeActivatedByMove() -{ - bool aCanBeActivated = false; - if (feature()->getKind() == SketchPlugin_Line::ID() && - attributeID() == SketchPlugin_Line::START_ID()) - aCanBeActivated = true; - - return aCanBeActivated; -} - void PartSet_WidgetPoint2D::deactivate() { // the value of the control should be stored to model if it was not @@ -417,12 +383,6 @@ void PartSet_WidgetPoint2D::deactivate() storeValue(); ModuleBase_ModelWidget::deactivate(); - ModuleBase_IViewer* aViewer = myWorkshop->viewer(); - disconnect(aViewer, SIGNAL(mouseMove(ModuleBase_IViewWindow*, QMouseEvent*)), - this, SLOT(onMouseMove(ModuleBase_IViewWindow*, QMouseEvent*))); - disconnect(aViewer, SIGNAL(mouseRelease(ModuleBase_IViewWindow*, QMouseEvent*)), - this, SLOT(onMouseRelease(ModuleBase_IViewWindow*, QMouseEvent*))); - myWorkshop->deactivateSubShapesSelection(); } @@ -484,14 +444,14 @@ bool PartSet_WidgetPoint2D::setConstraintWith(const ObjectPtr& theObject) return true; } -void PartSet_WidgetPoint2D::onMouseRelease(ModuleBase_IViewWindow* theWnd, QMouseEvent* theEvent) +void PartSet_WidgetPoint2D::mouseReleased(ModuleBase_IViewWindow* theWindow, QMouseEvent* theEvent) { // the contex menu release by the right button should not be processed by this widget if (theEvent->button() != Qt::LeftButton) return; ModuleBase_ISelection* aSelection = myWorkshop->selection(); - Handle(V3d_View) aView = theWnd->v3dView(); + Handle(V3d_View) aView = theWindow->v3dView(); QList aList = aSelection->getSelected(ModuleBase_ISelection::Viewer); ModuleBase_ViewerPrsPtr aFirstValue = aList.size() > 0 ? aList.first() : ModuleBase_ViewerPrsPtr(); @@ -569,7 +529,7 @@ void PartSet_WidgetPoint2D::onMouseRelease(ModuleBase_IViewWindow* theWnd, QMous } else if (aShape.ShapeType() == TopAbs_EDGE) { if (!setConstraintWith(aObject)) { - gp_Pnt aPoint = PartSet_Tools::convertClickToPoint(theEvent->pos(), theWnd->v3dView()); + gp_Pnt aPoint = PartSet_Tools::convertClickToPoint(theEvent->pos(), theWindow->v3dView()); PartSet_Tools::convertTo2D(aPoint, mySketch, aView, aX, aY); setPoint(aX, aY); } @@ -592,7 +552,7 @@ void PartSet_WidgetPoint2D::onMouseRelease(ModuleBase_IViewWindow* theWnd, QMous // End of Bug dependent fragment else { // A case when point is taken from mouse event - gp_Pnt aPoint = PartSet_Tools::convertClickToPoint(theEvent->pos(), theWnd->v3dView()); + gp_Pnt aPoint = PartSet_Tools::convertClickToPoint(theEvent->pos(), theWindow->v3dView()); double aX, anY; PartSet_Tools::convertTo2D(aPoint, mySketch, aView, aX, anY); @@ -620,15 +580,15 @@ void PartSet_WidgetPoint2D::onMouseRelease(ModuleBase_IViewWindow* theWnd, QMous } -void PartSet_WidgetPoint2D::onMouseMove(ModuleBase_IViewWindow* theWnd, QMouseEvent* theEvent) +void PartSet_WidgetPoint2D::mouseMoved(ModuleBase_IViewWindow* theWindow, QMouseEvent* theEvent) { if (isEditingMode()) return; - gp_Pnt aPoint = PartSet_Tools::convertClickToPoint(theEvent->pos(), theWnd->v3dView()); + gp_Pnt aPoint = PartSet_Tools::convertClickToPoint(theEvent->pos(), theWindow->v3dView()); double aX, anY; - PartSet_Tools::convertTo2D(aPoint, mySketch, theWnd->v3dView(), aX, anY); + PartSet_Tools::convertTo2D(aPoint, mySketch, theWindow->v3dView(), aX, anY); if (myState != ModifiedInViewer) storeCurentValue(); // we need to block the value state change diff --git a/src/PartSet/PartSet_WidgetPoint2d.h b/src/PartSet/PartSet_WidgetPoint2d.h index 6992569ba..a65a51c08 100755 --- a/src/PartSet/PartSet_WidgetPoint2d.h +++ b/src/PartSet/PartSet_WidgetPoint2d.h @@ -8,6 +8,8 @@ #define PartSet_WidgetPoint2D_H #include "PartSet.h" +#include "PartSet_MouseProcessor.h" + #include #include @@ -34,7 +36,8 @@ class QMouseEvent; * * \endcode */ -class PARTSET_EXPORT PartSet_WidgetPoint2D : public ModuleBase_ModelWidget +class PARTSET_EXPORT PartSet_WidgetPoint2D : public ModuleBase_ModelWidget, + public PartSet_MouseProcessor { Q_OBJECT public: @@ -68,10 +71,6 @@ Q_OBJECT //bool initFromPrevious(ObjectPtr theObject); - /// Defines if the widget can be activated by mouse move. - /// By default it returns false - virtual bool canBeActivatedByMove(); - /// The methiod called when widget is deactivated virtual void deactivate(); @@ -100,20 +99,19 @@ Q_OBJECT /// and creating a coincidence constraint to them. This control use them. virtual bool useSelectedShapes() const; -signals: - /// Signal about selection of an existing vertex from an object - void vertexSelected(); - -public slots: - /// Process mouse move event - /// \param theWnd a view window + /// Processing the mouse move event in the viewer + /// \param theWindow a view window /// \param theEvent a mouse event - void onMouseMove(ModuleBase_IViewWindow* theWnd, QMouseEvent* theEvent); + virtual void mouseMoved(ModuleBase_IViewWindow* theWindow, QMouseEvent* theEvent); - /// Process mouse release event - /// \param theWnd a view window + /// Processing the mouse release event in the viewer + /// \param theWindow a view window /// \param theEvent a mouse event - void onMouseRelease(ModuleBase_IViewWindow* theWnd, QMouseEvent* theEvent); + virtual void mouseReleased(ModuleBase_IViewWindow* theWindow, QMouseEvent* theEvent); + +signals: + /// Signal about selection of an existing vertex from an object + void vertexSelected(); protected: /// Saves the internal parameters to the given feature diff --git a/src/PartSet/PartSet_WidgetPoint2dDistance.cpp b/src/PartSet/PartSet_WidgetPoint2dDistance.cpp index 427efc273..2c7daebde 100644 --- a/src/PartSet/PartSet_WidgetPoint2dDistance.cpp +++ b/src/PartSet/PartSet_WidgetPoint2dDistance.cpp @@ -91,26 +91,7 @@ double PartSet_WidgetPoint2dDistance::computeValue(const std::shared_ptrdistance(theFirstPnt); } -void PartSet_WidgetPoint2dDistance::activateCustom() -{ - ModuleBase_IViewer* aViewer = myWorkshop->viewer(); - connect(aViewer, SIGNAL(mouseMove(ModuleBase_IViewWindow*, QMouseEvent*)), - this, SLOT(onMouseMove(ModuleBase_IViewWindow*, QMouseEvent*))); - connect(aViewer, SIGNAL(mouseRelease(ModuleBase_IViewWindow*, QMouseEvent*)), - this, SLOT(onMouseRelease(ModuleBase_IViewWindow*, QMouseEvent*))); -} - -void PartSet_WidgetPoint2dDistance::deactivate() -{ - ModuleBase_ModelWidget::deactivate(); - ModuleBase_IViewer* aViewer = myWorkshop->viewer(); - disconnect(aViewer, SIGNAL(mouseMove(ModuleBase_IViewWindow*, QMouseEvent*)), - this, SLOT(onMouseMove(ModuleBase_IViewWindow*, QMouseEvent*))); - disconnect(aViewer, SIGNAL(mouseRelease(ModuleBase_IViewWindow*, QMouseEvent*)), - this, SLOT(onMouseRelease(ModuleBase_IViewWindow*, QMouseEvent*))); -} - -void PartSet_WidgetPoint2dDistance::onMouseRelease(ModuleBase_IViewWindow* theWnd, QMouseEvent* theEvent) +void PartSet_WidgetPoint2dDistance::mouseReleased(ModuleBase_IViewWindow* theWnd, QMouseEvent* theEvent) { // the contex menu release by the right button should not be processed by this widget if (theEvent->button() != Qt::LeftButton) @@ -132,7 +113,7 @@ void PartSet_WidgetPoint2dDistance::onMouseRelease(ModuleBase_IViewWindow* theWn emit focusOutWidget(this); } -void PartSet_WidgetPoint2dDistance::onMouseMove(ModuleBase_IViewWindow* theWnd, QMouseEvent* theEvent) +void PartSet_WidgetPoint2dDistance::mouseMoved(ModuleBase_IViewWindow* theWnd, QMouseEvent* theEvent) { if (isEditingMode()) return; diff --git a/src/PartSet/PartSet_WidgetPoint2dDistance.h b/src/PartSet/PartSet_WidgetPoint2dDistance.h index 1c4e05b2a..0836b20b1 100644 --- a/src/PartSet/PartSet_WidgetPoint2dDistance.h +++ b/src/PartSet/PartSet_WidgetPoint2dDistance.h @@ -8,6 +8,8 @@ #define PartSet_WidgetPoint2dDistance_H #include "PartSet.h" +#include "PartSet_MouseProcessor.h" + #include #include @@ -34,7 +36,8 @@ class QMouseEvent; * * \endcode */ -class PARTSET_EXPORT PartSet_WidgetPoint2dDistance : public ModuleBase_WidgetDoubleValue +class PARTSET_EXPORT PartSet_WidgetPoint2dDistance : public ModuleBase_WidgetDoubleValue, + public PartSet_MouseProcessor { Q_OBJECT public: @@ -52,9 +55,6 @@ Q_OBJECT /// \return a boolean value virtual bool isValidSelectionCustom(const std::shared_ptr& theValue); - /// The methiod called when widget is deactivated - virtual void deactivate(); - /// \returns the sketch instance CompositeFeaturePtr sketch() const { return mySketch; } @@ -64,17 +64,15 @@ Q_OBJECT /// Returns true if the event is processed. virtual bool processEnter(); -public slots: - /// Process of mouse move - /// \param theWnd a pointer to a window - /// \param theEvent a mouse event - void onMouseMove(ModuleBase_IViewWindow* theWnd, QMouseEvent* theEvent); + /// Processing the mouse move event in the viewer + /// \param theWindow a view window + /// \param theEvent a mouse event + virtual void mouseMoved(ModuleBase_IViewWindow* theWindow, QMouseEvent* theEvent); - protected slots: - /// Process of mouse release - /// \param theWnd a pointer to a window - /// \param theEvent a mouse event - void onMouseRelease(ModuleBase_IViewWindow* theWnd, QMouseEvent* theEvent); + /// Processing the mouse release event in the viewer + /// \param theWindow a view window + /// \param theEvent a mouse event + virtual void mouseReleased(ModuleBase_IViewWindow* theWindow, QMouseEvent* theEvent); protected: /// Store current value in cashed value @@ -88,9 +86,6 @@ protected: /// \return true if the widget current value is reset virtual bool resetCustom(); - /// The methiod called when widget is activated - virtual void activateCustom(); - /// Set the second point which defines a value in the widget as a distance with a first point defined by feature void setPoint(FeaturePtr theFeature, const std::shared_ptr& thePnt); diff --git a/src/PartSet/PartSet_WidgetSketchCreator.cpp b/src/PartSet/PartSet_WidgetSketchCreator.cpp index c4035cc22..394756ca5 100644 --- a/src/PartSet/PartSet_WidgetSketchCreator.cpp +++ b/src/PartSet/PartSet_WidgetSketchCreator.cpp @@ -335,7 +335,7 @@ bool PartSet_WidgetSketchCreator::startSketchOperation(const QListsetPreselection(aValues); - myModule->sendOperation(aFOperation); + myWorkshop->processLaunchOperation(aFOperation); return aSketchStarted; } diff --git a/src/PartSet/PartSet_WidgetSubShapeSelector.cpp b/src/PartSet/PartSet_WidgetSubShapeSelector.cpp new file mode 100755 index 000000000..21b0277bd --- /dev/null +++ b/src/PartSet/PartSet_WidgetSubShapeSelector.cpp @@ -0,0 +1,188 @@ +// Copyright (C) 2014-20xx CEA/DEN, EDF R&D + +// File: PartSet_WidgetSubShapeSelector.cpp +// Created: 21 Jul 2016 +// Author: Natalia ERMOLAEVA + +#include "PartSet_WidgetSubShapeSelector.h" +#include "PartSet_Tools.h" + +#include +#include + +#include +#include +#include + +#include + +#include +#include + +#include + +#include +#include + +#include +#include +#include + +#include + +#include +#include + +PartSet_WidgetSubShapeSelector::PartSet_WidgetSubShapeSelector(QWidget* theParent, + ModuleBase_IWorkshop* theWorkshop, + const Config_WidgetAPI* theData) +: PartSet_WidgetShapeSelector(theParent, theWorkshop, theData) +{ + //myUseSketchPlane = theData->getBooleanAttribute("use_sketch_plane", true); + //myExternalObjectMgr = new PartSet_ExternalObjectsMgr(theData->getProperty("use_external"), true); +} + +PartSet_WidgetSubShapeSelector::~PartSet_WidgetSubShapeSelector() +{ +} + +//******************************************************************** +void PartSet_WidgetSubShapeSelector::mouseMoved(ModuleBase_IViewWindow* theWindow, + QMouseEvent* theEvent) +{ + ModuleBase_ISelection* aSelect = myWorkshop->selection(); + QList aHighlighted = aSelect->getHighlighted(); + + if (aHighlighted.empty()) { + ModuleBase_ViewerPrsPtr aPrs = aHighlighted.first(); + if (aPrs.get() && aPrs->object().get()) { + ObjectPtr anObject = aPrs->object(); + if (myCashedShapes.find(anObject) == myCashedShapes.end()) + fillObjectShapes(anObject); + const std::set& aShapes = myCashedShapes[anObject]; + if (!aShapes.empty()) { + gp_Pnt aPnt = PartSet_Tools::convertClickToPoint(theEvent->pos(), theWindow->v3dView()); + std::shared_ptr aVertexShape(new GeomAPI_Vertex(aPnt.X(), aPnt.Y(), aPnt.Z())); + + std::set::const_iterator anIt = aShapes.begin(), aLast = aShapes.end(); + for (; anIt != aLast; anIt++) { + GeomShapePtr aBaseShape = *anIt; + if (GeomAlgoAPI_ShapeTools::isSubShapeInsideShape(aVertexShape, aBaseShape)) { + myCurrentSubShape->setObject(anObject); + myCurrentSubShape->setShape(aBaseShape); + break; + } + } + } + } + } + myWorkshop->module()->customizeObject(myFeature, ModuleBase_IModule::CustomizeHighlightedObjects, + true); +} + +//******************************************************************** +void PartSet_WidgetSubShapeSelector::getHighlighted( + QList>& theValues) +{ + if (myCurrentSubShape.get() && myCurrentSubShape->object().get()) + theValues.append(myCurrentSubShape); +} + +//******************************************************************** +void PartSet_WidgetSubShapeSelector::fillObjectShapes(const ObjectPtr& theObject) +{ + std::set > aShapes; + + // current feature + FeaturePtr aFeature = ModelAPI_Feature::feature(theObject); + std::set anEdgeShapes; + // edges on feature + ModelAPI_Tools::shapesOfType(aFeature, GeomAPI_Shape::EDGE, anEdgeShapes); + if (!anEdgeShapes.empty()) { + GeomShapePtr aFeatureShape = *anEdgeShapes.begin(); + + // coincidences to the feature + std::set > aRefAttributes; + ModelGeomAlgo_Point2D::getPointsOfReference(aFeature, SketchPlugin_ConstraintCoincidence::ID(), + aRefAttributes, SketchPlugin_Point::ID(), SketchPlugin_Point::COORD_ID()); + // layed on feature coincidences to divide it on several shapes + FeaturePtr aSketch = sketch(); + std::shared_ptr aData = aSketch->data(); + std::shared_ptr aC = std::dynamic_pointer_cast( + aData->attribute(SketchPlugin_Sketch::ORIGIN_ID())); + std::shared_ptr aX = std::dynamic_pointer_cast( + aData->attribute(SketchPlugin_Sketch::DIRX_ID())); + std::shared_ptr aNorm = std::dynamic_pointer_cast( + aData->attribute(SketchPlugin_Sketch::NORM_ID())); + std::shared_ptr aY(new GeomAPI_Dir(aNorm->dir()->cross(aX->dir()))); + std::set > aPoints; + ModelGeomAlgo_Point2D::getPointsInsideShape(aFeatureShape, aRefAttributes, aC->pnt(), + aX->dir(), aY, aPoints); + + GeomAlgoAPI_ShapeTools::splitShape(aFeatureShape, aPoints, aShapes); + } + myCashedShapes[theObject] = aShapes; +} + +//******************************************************************** +/*bool PartSet_WidgetSubShapeSelector::activateSelectionAndFilters(bool toActivate) +{ + bool aHasSelectionFilter = ModuleBase_WidgetShapeSelector::activateSelectionAndFilters + (toActivate); + if (!myUseSketchPlane) { + XGUI_Workshop* aWorkshop = XGUI_Tools::workshop(myWorkshop); + PartSet_Module* aModule = dynamic_cast(aWorkshop->module()); + bool isUsePlaneFilterOnly = !toActivate; + aModule->sketchMgr()->activatePlaneFilter(isUsePlaneFilterOnly); + } + return aHasSelectionFilter; +} + +//******************************************************************** +bool PartSet_WidgetSubShapeSelector::isValidSelectionCustom(const ModuleBase_ViewerPrsPtr& thePrs) +{ + bool aValid = ModuleBase_WidgetShapeSelector::isValidSelectionCustom(thePrs); + if (aValid) { + ObjectPtr anObject = myWorkshop->selection()->getResult(thePrs); + aValid = myExternalObjectMgr->isValidObject(anObject); + } + return aValid; +} + +void PartSet_WidgetSubShapeSelector::getGeomSelection(const ModuleBase_ViewerPrsPtr& thePrs, + ObjectPtr& theObject, + GeomShapePtr& theShape) +{ + ModuleBase_WidgetShapeSelector::getGeomSelection(thePrs, theObject, theShape); + + FeaturePtr aSelectedFeature = ModelAPI_Feature::feature(theObject); + std::shared_ptr aSPFeature = + std::dynamic_pointer_cast(aSelectedFeature); + // there is no a sketch feature is selected, but the shape exists, try to create an exernal object + // TODO: unite with the same functionality in PartSet_WidgetSubShapeSelector + if (aSPFeature.get() == NULL) { + ObjectPtr anExternalObject = ObjectPtr(); + if (myExternalObjectMgr->useExternal()) { + GeomShapePtr aShape = theShape; + if (!aShape.get()) { + ResultPtr aResult = myWorkshop->selection()->getResult(thePrs); + if (aResult.get()) + aShape = aResult->shape(); + } + if (aShape.get() != NULL && !aShape->isNull()) + anExternalObject = myExternalObjectMgr->externalObject(theObject, aShape, sketch(), myIsInValidate); + } + /// the object is null if the selected feature is "external"(not sketch entity feature of the + /// current sketch) and it is not created by object manager + theObject = anExternalObject; + } +} + +//******************************************************************** +void PartSet_WidgetSubShapeSelector::restoreAttributeValue(const AttributePtr& theAttribute, + const bool theValid) +{ + ModuleBase_WidgetShapeSelector::restoreAttributeValue(theAttribute, theValid); + myExternalObjectMgr->removeExternal(sketch(), myFeature, myWorkshop, true); +} +*/ diff --git a/src/PartSet/PartSet_WidgetSubShapeSelector.h b/src/PartSet/PartSet_WidgetSubShapeSelector.h new file mode 100644 index 000000000..4c0945799 --- /dev/null +++ b/src/PartSet/PartSet_WidgetSubShapeSelector.h @@ -0,0 +1,78 @@ +// Copyright (C) 2014-20xx CEA/DEN, EDF R&D + +// File: PartSet_WidgetSubShapeSelector.h +// Created: 21 Jul 2016 +// Author: Natalia ERMOLAEVA + + +#ifndef PartSet_WidgetSubShapeSelector_H +#define PartSet_WidgetSubShapeSelector_H + +#include "PartSet.h" + +#include +#include + +#include + +#include +#include + +class ModuleBase_IWorkshop; +class Config_WidgetAPI; +class ModuleBase_IViewWindow; +class ModuleBase_ViewerPrs; + +class QWidget; +class QMouseEvent; + +/** +* \ingroup Modules +* Customosation of PartSet_WidgetSubShapeSelector in order to visualize sub-shape +* by mouse move over shape in the viewer. Split of the object is performed by +* coincident points to the object. Segment between nearest coincidence is highlighted +*/ +class PARTSET_EXPORT PartSet_WidgetSubShapeSelector: public PartSet_WidgetShapeSelector, + public PartSet_MouseProcessor +{ +Q_OBJECT + public: + /// Constructor + /// \param theParent the parent object + /// \param theWorkshop instance of workshop interface + /// \param theData the widget configuation. The attribute of the model widget is obtained from + PartSet_WidgetSubShapeSelector(QWidget* theParent, ModuleBase_IWorkshop* theWorkshop, + const Config_WidgetAPI* theData); + + virtual ~PartSet_WidgetSubShapeSelector(); + + /// Processing the mouse move event in the viewer + /// \param theWindow a view window + /// \param theEvent a mouse event + virtual void mouseMoved(ModuleBase_IViewWindow* theWindow, QMouseEvent* theEvent); + + /// Returns values which should be highlighted when the whidget is active + /// \param theValues a list of presentations + virtual void getHighlighted(QList>& theValues); + +protected: + /// Checks the widget validity. By default, it returns true. + /// \param thePrs a selected presentation in the view + /// \return a boolean value + //virtual bool isValidSelectionCustom(const std::shared_ptr& thePrs); + + /// Return an object and geom shape by the viewer presentation + /// \param thePrs a selection + /// \param theObject an output object + /// \param theShape a shape of the selection + //virtual void getGeomSelection(const std::shared_ptr& thePrs, + // ObjectPtr& theObject, + // GeomShapePtr& theShape); + void fillObjectShapes(const ObjectPtr& theObject); + +protected: + std::shared_ptr myCurrentSubShape; + std::map > myCashedShapes; +}; + +#endif \ No newline at end of file diff --git a/src/SketchPlugin/CMakeLists.txt b/src/SketchPlugin/CMakeLists.txt index d4d4dfc3e..9016965a7 100644 --- a/src/SketchPlugin/CMakeLists.txt +++ b/src/SketchPlugin/CMakeLists.txt @@ -5,75 +5,77 @@ INCLUDE(UnitTest) SET(PROJECT_HEADERS SketchPlugin.h - SketchPlugin_Feature.h - SketchPlugin_Plugin.h - SketchPlugin_Sketch.h - SketchPlugin_SketchEntity.h - SketchPlugin_Line.h - SketchPlugin_Point.h - SketchPlugin_IntersectionPoint.h - SketchPlugin_Circle.h SketchPlugin_Arc.h + SketchPlugin_Circle.h SketchPlugin_Constraint.h + SketchPlugin_ConstraintAngle.h SketchPlugin_ConstraintBase.h SketchPlugin_ConstraintCoincidence.h SketchPlugin_ConstraintCollinear.h SketchPlugin_ConstraintDistance.h + SketchPlugin_ConstraintEqual.h + SketchPlugin_ConstraintFillet.h + SketchPlugin_ConstraintHorizontal.h SketchPlugin_ConstraintLength.h SketchPlugin_ConstraintMiddle.h + SketchPlugin_ConstraintMirror.h SketchPlugin_ConstraintParallel.h SketchPlugin_ConstraintPerpendicular.h SketchPlugin_ConstraintRadius.h SketchPlugin_ConstraintRigid.h - SketchPlugin_ConstraintHorizontal.h - SketchPlugin_ConstraintVertical.h - SketchPlugin_ConstraintEqual.h + SketchPlugin_ConstraintSplit.h SketchPlugin_ConstraintTangent.h - SketchPlugin_ConstraintMirror.h - SketchPlugin_ConstraintFillet.h - SketchPlugin_ConstraintAngle.h + SketchPlugin_ConstraintVertical.h + SketchPlugin_ExternalValidator.h + SketchPlugin_Feature.h + SketchPlugin_IntersectionPoint.h + SketchPlugin_Line.h SketchPlugin_MultiRotation.h SketchPlugin_MultiTranslation.h - SketchPlugin_ExternalValidator.h - SketchPlugin_Validators.h - SketchPlugin_Tools.h + SketchPlugin_Plugin.h + SketchPlugin_Point.h SketchPlugin_Projection.h + SketchPlugin_Sketch.h + SketchPlugin_SketchEntity.h + SketchPlugin_Tools.h + SketchPlugin_Validators.h ) SET(PROJECT_SOURCES - SketchPlugin_Feature.cpp - SketchPlugin_Plugin.cpp - SketchPlugin_Sketch.cpp - SketchPlugin_SketchEntity.cpp - SketchPlugin_Line.cpp - SketchPlugin_Point.cpp - SketchPlugin_IntersectionPoint.cpp - SketchPlugin_Circle.cpp SketchPlugin_Arc.cpp + SketchPlugin_Circle.cpp SketchPlugin_Constraint.cpp + SketchPlugin_ConstraintAngle.cpp SketchPlugin_ConstraintBase.cpp SketchPlugin_ConstraintCoincidence.cpp SketchPlugin_ConstraintCollinear.cpp SketchPlugin_ConstraintDistance.cpp + SketchPlugin_ConstraintEqual.cpp + SketchPlugin_ConstraintFillet.cpp + SketchPlugin_ConstraintHorizontal.cpp SketchPlugin_ConstraintLength.cpp SketchPlugin_ConstraintMiddle.cpp + SketchPlugin_ConstraintMirror.cpp SketchPlugin_ConstraintParallel.cpp SketchPlugin_ConstraintPerpendicular.cpp SketchPlugin_ConstraintRadius.cpp SketchPlugin_ConstraintRigid.cpp - SketchPlugin_ConstraintHorizontal.cpp - SketchPlugin_ConstraintVertical.cpp - SketchPlugin_ConstraintEqual.cpp + SketchPlugin_ConstraintSplit.cpp SketchPlugin_ConstraintTangent.cpp - SketchPlugin_ConstraintMirror.cpp - SketchPlugin_ConstraintFillet.cpp - SketchPlugin_ConstraintAngle.cpp + SketchPlugin_ConstraintVertical.cpp + SketchPlugin_ExternalValidator.cpp + SketchPlugin_Feature.cpp + SketchPlugin_IntersectionPoint.cpp + SketchPlugin_Line.cpp SketchPlugin_MultiRotation.cpp SketchPlugin_MultiTranslation.cpp - SketchPlugin_ExternalValidator.cpp - SketchPlugin_Validators.cpp - SketchPlugin_Tools.cpp + SketchPlugin_Plugin.cpp + SketchPlugin_Point.cpp SketchPlugin_Projection.cpp + SketchPlugin_Sketch.cpp + SketchPlugin_SketchEntity.cpp + SketchPlugin_Tools.cpp + SketchPlugin_Validators.cpp ) SET(PROJECT_LIBRARIES @@ -81,6 +83,7 @@ SET(PROJECT_LIBRARIES GeomAPI GeomAlgoAPI ModelAPI + ModelGeomAlgo SketcherPrs GeomDataAPI ) @@ -103,6 +106,7 @@ INCLUDE_DIRECTORIES( ../Config ../Events ../ModelAPI + ../ModelGeomAlgo ../GeomAPI ../GeomAlgoAPI ../GeomDataAPI diff --git a/src/SketchPlugin/SketchPlugin_Arc.cpp b/src/SketchPlugin/SketchPlugin_Arc.cpp index be3f9e568..5ba8163ea 100644 --- a/src/SketchPlugin/SketchPlugin_Arc.cpp +++ b/src/SketchPlugin/SketchPlugin_Arc.cpp @@ -370,6 +370,8 @@ void SketchPlugin_Arc::attributeChanged(const std::string& theID) std::shared_ptr aTangentPoint = std::dynamic_pointer_cast(aTangPtAttr->attr()); std::shared_ptr aTangPnt2d = aTangentPoint->pnt(); + if (aTangPnt2d->isEqual(anEndAttr->pnt())) + return; FeaturePtr aTangFeature = ModelAPI_Feature::feature(aTangentPoint->owner()); std::shared_ptr aTangEdge = std::dynamic_pointer_cast( aTangFeature->lastResult()->shape()); diff --git a/src/SketchPlugin/SketchPlugin_ConstraintSplit.cpp b/src/SketchPlugin/SketchPlugin_ConstraintSplit.cpp new file mode 100755 index 000000000..b029f638e --- /dev/null +++ b/src/SketchPlugin/SketchPlugin_ConstraintSplit.cpp @@ -0,0 +1,1087 @@ +// Copyright (C) 2014-20xx CEA/DEN, EDF R&D --> + +// File: SketchPlugin_ConstraintSplit.cpp +// Created: 17 Jul 2016 +// Author: Natalia ERMOLAEVA + +#include "SketchPlugin_ConstraintSplit.h" + +//#include +//#include +//#include +//#include +//#include +//#include +//#include +#include +//#include +//#include +//#include +//#include +//#include +//#include +// +//#include +//#include +//#include +//#include +//#include +//#include +//#include +//#include +// +//#include +// +//#include +// +//const double tolerance = 1.e-7; +//const double paramTolerance = 1.e-4; + +///// \brief Attract specified point on theNewArc to the attribute of theFeature +//static void recalculateAttributes(FeaturePtr theNewArc, const std::string& theNewArcAttribute, +// FeaturePtr theFeature, const std::string& theFeatureAttribute); +// +///// \brief Calculates center of fillet arc and coordinates of tangency points +//static void calculateFilletCenter(FeaturePtr theFeatureA, FeaturePtr theFeatureB, +// double theRadius, bool theNotInversed[2], +// std::shared_ptr& theCenter, +// std::shared_ptr& theTangentA, +// std::shared_ptr& theTangentB); +// +///// Get point on 1/3 length of edge from fillet point +//static void getPointOnEdge(const FeaturePtr theFeature, +// const std::shared_ptr theFilletPoint, +// std::shared_ptr& thePoint); +// +///// Get distance from point to feature +//static double getProjectionDistance(const FeaturePtr theFeature, +// const std::shared_ptr thePoint); +// +///// Get coincide edges for fillet +//static std::set getCoincides(const FeaturePtr& theConstraintCoincidence); + +SketchPlugin_ConstraintSplit::SketchPlugin_ConstraintSplit() +//: myListOfPointsChangedInCode(false), +// myRadiusChangedByUser(false), +// myRadiusChangedInCode(false), +// myRadiusInitialized(false) +{ +} + +void SketchPlugin_ConstraintSplit::initAttributes() +{ + data()->addAttribute(SketchPlugin_Constraint::ENTITY_A(), ModelAPI_AttributeSelection::typeId()); + + //data()->addAttribute(SketchPlugin_Constraint::VALUE(), ModelAPI_AttributeDouble::typeId()); + //data()->addAttribute(SketchPlugin_Constraint::ENTITY_A(), ModelAPI_AttributeRefAttrList::typeId()); +} + +void SketchPlugin_ConstraintSplit::execute() +{ +/* std::shared_ptr aData = data(); + + // Check the base objects are initialized. + AttributeRefAttrListPtr aPointsRefList = std::dynamic_pointer_cast( + aData->attribute(SketchPlugin_Constraint::ENTITY_A())); + if(!aPointsRefList->isInitialized()) { + setError("Error: List of points is not initialized."); + return; + } + + // Get fillet radius. + double aFilletRadius = std::dynamic_pointer_cast( + aData->attribute(SketchPlugin_Constraint::VALUE()))->value(); + + // Wait all constraints being created, then send update events + static Events_ID anUpdateEvent = Events_Loop::eventByName(EVENT_OBJECT_UPDATED); + bool isUpdateFlushed = Events_Loop::loop()->isFlushed(anUpdateEvent); + if (isUpdateFlushed) + Events_Loop::loop()->setFlushed(anUpdateEvent, false); + + for(std::set::iterator aPointsIter = myNewPoints.begin(); + aPointsIter != myNewPoints.end(); + ++aPointsIter) { + AttributePtr aPointAttr = *aPointsIter; + std::shared_ptr aFilletPoint2d = std::dynamic_pointer_cast(aPointAttr); + if(!aFilletPoint2d.get()) { + setError("Error: One of the selected points is empty."); + return; + } + std::shared_ptr aFilletPnt2d = aFilletPoint2d->pnt(); + + // Obtain base lines for fillet. + bool anIsNeedNewObjects = true; + FilletFeatures aFilletFeatures; + std::map::iterator aPrevPointsIter = myPointFeaturesMap.find(aPointAttr); + if(aPrevPointsIter != myPointFeaturesMap.end()) { + anIsNeedNewObjects = false; + aFilletFeatures = aPrevPointsIter->second; + } + FeaturePtr aBaseEdgeA, aBaseEdgeB; + if(!anIsNeedNewObjects) { + aBaseEdgeA = aFilletFeatures.baseEdgesState.front().first; + aBaseEdgeB = aFilletFeatures.baseEdgesState.back().first; + } else { + // Obtain constraint coincidence for the fillet point. + FeaturePtr aConstraintCoincidence; + const std::set& aRefsList = aFilletPoint2d->owner()->data()->refsToMe(); + for(std::set::const_iterator anIt = aRefsList.cbegin(); anIt != aRefsList.cend(); ++anIt) { + std::shared_ptr anAttr = (*anIt); + FeaturePtr aConstrFeature = std::dynamic_pointer_cast(anAttr->owner()); + if(aConstrFeature->getKind() == SketchPlugin_ConstraintCoincidence::ID()) { + AttributeRefAttrPtr anAttrRefA = std::dynamic_pointer_cast( + aConstrFeature->attribute(SketchPlugin_ConstraintCoincidence::ENTITY_A())); + AttributeRefAttrPtr anAttrRefB = std::dynamic_pointer_cast( + aConstrFeature->attribute(SketchPlugin_ConstraintCoincidence::ENTITY_B())); + if(anAttrRefA.get() && !anAttrRefA->isObject()) { + AttributePtr anAttrA = anAttrRefA->attr(); + if(aFilletPoint2d == anAttrA) { + aConstraintCoincidence = aConstrFeature; + break; + } + } + if(anAttrRefB.get() && !anAttrRefB->isObject()) { + AttributePtr anAttrB = anAttrRefB->attr(); + if(aFilletPoint2d == anAttrB) { + aConstraintCoincidence = aConstrFeature; + break; + } + } + } + } + + if(!aConstraintCoincidence.get()) { + setError("Error: No coincident edges at one of the selected points."); + return; + } + + // Get coincide edges. + std::set aCoincides = getCoincides(aConstraintCoincidence); + if(aCoincides.size() != 2) { + setError("Error: One of the selected points does not have two suitable edges for fillet."); + return; + } + + std::set::iterator aLinesIt = aCoincides.begin(); + aBaseEdgeA = *aLinesIt++; + aBaseEdgeB = *aLinesIt; + + std::pair aBasePairA = std::make_pair(aBaseEdgeA, aBaseEdgeA->boolean(SketchPlugin_SketchEntity::AUXILIARY_ID())->value()); + std::pair aBasePairB = std::make_pair(aBaseEdgeB, aBaseEdgeB->boolean(SketchPlugin_SketchEntity::AUXILIARY_ID())->value()); + aFilletFeatures.baseEdgesState.push_back(aBasePairA); + aFilletFeatures.baseEdgesState.push_back(aBasePairB); + } + + if(!aBaseEdgeA.get() || !aBaseEdgeB.get()) { + setError("Error: One of the base edges is empty."); + return; + } + + // Create new edges and arc if needed. + FeaturePtr aResultEdgeA, aResultEdgeB, aResultArc; + if(!anIsNeedNewObjects) { + // Obtain features from the list. + std::list::iterator aResultEdgesIt = aFilletFeatures.resultEdges.begin(); + aResultEdgeA = *aResultEdgesIt++; + aResultEdgeB = *aResultEdgesIt++; + aResultArc = *aResultEdgesIt; + } else { + // Copy edges and create arc. + aResultEdgeA = SketchPlugin_Sketch::addUniqueNamedCopiedFeature(aBaseEdgeA, sketch()); + aResultEdgeA->boolean(SketchPlugin_SketchEntity::AUXILIARY_ID())->setValue(false); + aResultEdgeB = SketchPlugin_Sketch::addUniqueNamedCopiedFeature(aBaseEdgeB, sketch()); + aResultEdgeB->boolean(SketchPlugin_SketchEntity::AUXILIARY_ID())->setValue(false); + aResultArc = sketch()->addFeature(SketchPlugin_Arc::ID()); + + aFilletFeatures.resultEdges.push_back(aResultEdgeA); + aFilletFeatures.resultEdges.push_back(aResultEdgeB); + aFilletFeatures.resultEdges.push_back(aResultArc); + } + + // Calculate arc attributes + static const int aNbFeatures = 2; + FeaturePtr aBaseFeatures[aNbFeatures] = {aBaseEdgeA, aBaseEdgeB}; + FeaturePtr aResultFeatures[aNbFeatures] = {aResultEdgeA, aResultEdgeB}; + std::shared_ptr aTangentDir[aNbFeatures]; // tangent directions of the features in coincident point + bool isStart[aNbFeatures]; // indicates which point the features share + std::shared_ptr aStartEndPnt[aNbFeatures * 2]; // first pair of points relate to first feature, second pair - to second + std::string aFeatAttributes[aNbFeatures * 2]; // attributes of features + for (int i = 0; i < aNbFeatures; i++) { + std::string aStartAttr, aEndAttr; + if (aResultFeatures[i]->getKind() == SketchPlugin_Line::ID()) { + aStartAttr = SketchPlugin_Line::START_ID(); + aEndAttr = SketchPlugin_Line::END_ID(); + } else if (aResultFeatures[i]->getKind() == SketchPlugin_Arc::ID()) { + aStartAttr = SketchPlugin_Arc::START_ID(); + aEndAttr = SketchPlugin_Arc::END_ID(); + } else { // wrong argument + setError("Error: One of the points has wrong coincide feature"); + return; + } + aFeatAttributes[2*i] = aStartAttr; + aStartEndPnt[2*i] = std::dynamic_pointer_cast( + aBaseFeatures[i]->attribute(aStartAttr))->pnt(); + aFeatAttributes[2*i+1] = aEndAttr; + aStartEndPnt[2*i+1] = std::dynamic_pointer_cast( + aBaseFeatures[i]->attribute(aEndAttr))->pnt(); + } + for (int aFeatInd = 0; aFeatInd < aNbFeatures; aFeatInd++) { + for (int j = 0; j < 2; j++) // loop on start-end of each feature + if (aStartEndPnt[aFeatInd * aNbFeatures + j]->distance(aFilletPnt2d) < 1.e-10) { + isStart[aFeatInd] = (j==0); + break; + } + } + // tangent directions of the features + for (int i = 0; i < aNbFeatures; i++) { + std::shared_ptr aDir; + if (aResultFeatures[i]->getKind() == SketchPlugin_Line::ID()) { + aDir = aStartEndPnt[2*i+1]->xy()->decreased(aStartEndPnt[2*i]->xy()); + if (!isStart[i]) + aDir = aDir->multiplied(-1.0); + } else if (aResultFeatures[i]->getKind() == SketchPlugin_Arc::ID()) { + std::shared_ptr aCenterPoint = std::dynamic_pointer_cast( + aResultFeatures[i]->attribute(SketchPlugin_Arc::CENTER_ID()))->pnt(); + aDir = isStart[i] ? aStartEndPnt[2*i]->xy() : aStartEndPnt[2*i+1]->xy(); + aDir = aDir->decreased(aCenterPoint->xy()); + + double x = aDir->x(); + double y = aDir->y(); + aDir->setX(-y); + aDir->setY(x); + if (isStart[i] == std::dynamic_pointer_cast(aBaseFeatures[i])->isReversed()) + aDir = aDir->multiplied(-1.0); + } + aTangentDir[i] = std::shared_ptr(new GeomAPI_Dir2d(aDir)); + } + + // By default, the start point of fillet arc is connected to FeatureA, + // and the end point - to FeatureB. But when the angle between TangentDirA and + // TangentDirB greater 180 degree, the sequaence of features need to be reversed. + double cosBA = aTangentDir[0]->cross(aTangentDir[1]); // cos(B-A), where A and B - angles between corresponding tanget direction and the X axis + bool isReversed = cosBA > 0.0; + + // Calculate fillet arc parameters + std::shared_ptr aCenter, aTangentPntA, aTangentPntB; + calculateFilletCenter(aBaseEdgeA, aBaseEdgeB, aFilletRadius, isStart, aCenter, aTangentPntA, aTangentPntB); + if(!aCenter.get() || !aTangentPntA.get() || !aTangentPntB.get()) { + setError("Can not create fillet with the specified parameters."); + return; + } + // update features + std::dynamic_pointer_cast( + aResultEdgeA->attribute(aFeatAttributes[isStart[0] ? 0 : 1]))->setValue(aTangentPntA->x(), aTangentPntA->y()); + aResultEdgeA->execute(); + std::dynamic_pointer_cast( + aResultEdgeB->attribute(aFeatAttributes[2 + (isStart[1] ? 0 : 1)]))->setValue(aTangentPntB->x(), aTangentPntB->y()); + aResultEdgeB->execute(); + // update fillet arc: make the arc correct for sure, so, it is not needed to process the "attribute updated" + // by arc; moreover, it may cause cyclicity in hte mechanism of updater + aResultArc->data()->blockSendAttributeUpdated(true); + std::dynamic_pointer_cast( + aResultArc->attribute(SketchPlugin_Arc::CENTER_ID()))->setValue(aCenter->x(), aCenter->y()); + if(isReversed) { + std::shared_ptr aTmp = aTangentPntA; + aTangentPntA = aTangentPntB; + aTangentPntB = aTmp; + } + std::shared_ptr aStartPoint = std::dynamic_pointer_cast( + aResultArc->attribute(SketchPlugin_Arc::START_ID())); + std::shared_ptr aEndPoint = std::dynamic_pointer_cast( + aResultArc->attribute(SketchPlugin_Arc::END_ID())); + if(aStartPoint->isInitialized() && aEndPoint->isInitialized() && + (aStartPoint->pnt()->xy()->distance(aTangentPntA) > tolerance || + aEndPoint->pnt()->xy()->distance(aTangentPntB) > tolerance)) { + std::dynamic_pointer_cast(aResultArc)->setReversed(false); + } + aStartPoint->setValue(aTangentPntA->x(), aTangentPntA->y()); + aEndPoint->setValue(aTangentPntB->x(), aTangentPntB->y()); + aResultArc->data()->blockSendAttributeUpdated(false); + aResultArc->execute(); + + if(anIsNeedNewObjects) { + // Create list of additional constraints: + // 1. Coincidence of boundary points of features (copied lines/arcs) and fillet arc + // 1.1. coincidence + FeaturePtr aConstraint = sketch()->addFeature(SketchPlugin_ConstraintCoincidence::ID()); + AttributeRefAttrPtr aRefAttr = std::dynamic_pointer_cast( + aConstraint->attribute(SketchPlugin_Constraint::ENTITY_A())); + aRefAttr->setAttr(aResultArc->attribute(SketchPlugin_Arc::START_ID())); + aRefAttr = std::dynamic_pointer_cast( + aConstraint->attribute(SketchPlugin_Constraint::ENTITY_B())); + int aFeatInd = isReversed ? 1 : 0; + int anAttrInd = (isReversed ? 2 : 0) + (isStart[isReversed ? 1 : 0] ? 0 : 1); + aRefAttr->setAttr(aResultFeatures[aFeatInd]->attribute(aFeatAttributes[anAttrInd])); + recalculateAttributes(aResultArc, SketchPlugin_Arc::START_ID(), aResultFeatures[aFeatInd], aFeatAttributes[anAttrInd]); + aConstraint->execute(); + aFilletFeatures.resultConstraints.push_back(aConstraint); + ModelAPI_EventCreator::get()->sendUpdated(aConstraint, anUpdateEvent); + // 1.2. coincidence + aConstraint = sketch()->addFeature(SketchPlugin_ConstraintCoincidence::ID()); + aRefAttr = std::dynamic_pointer_cast( + aConstraint->attribute(SketchPlugin_Constraint::ENTITY_A())); + aRefAttr->setAttr(aResultArc->attribute(SketchPlugin_Arc::END_ID())); + aRefAttr = std::dynamic_pointer_cast( + aConstraint->attribute(SketchPlugin_Constraint::ENTITY_B())); + aFeatInd = isReversed ? 0 : 1; + anAttrInd = (isReversed ? 0 : 2) + (isStart[isReversed ? 0 : 1] ? 0 : 1); + aRefAttr->setAttr(aResultFeatures[aFeatInd]->attribute(aFeatAttributes[anAttrInd])); + recalculateAttributes(aResultArc, SketchPlugin_Arc::END_ID(), aResultFeatures[aFeatInd], aFeatAttributes[anAttrInd]); + aConstraint->execute(); + aFilletFeatures.resultConstraints.push_back(aConstraint); + ModelAPI_EventCreator::get()->sendUpdated(aConstraint, anUpdateEvent); + // 2. Fillet arc radius + //aConstraint = sketch()->addFeature(SketchPlugin_ConstraintRadius::ID()); + //aRefAttr = std::dynamic_pointer_cast( + // aConstraint->attribute(SketchPlugin_Constraint::ENTITY_A())); + //aRefAttr->setObject(aNewArc->lastResult()); + //std::dynamic_pointer_cast( + // aConstraint->attribute(SketchPlugin_Constraint::VALUE()))->setValue(aFilletRadius); + //std::dynamic_pointer_cast( + // aConstraint->attribute(SketchPlugin_Constraint::FLYOUT_VALUE_PNT()))->setValue( + // isStart[0] ? aStartEndPnt[0] : aStartEndPnt[1]); + //aConstraint->execute(); + //myProducedFeatures.push_back(aConstraint); + //ModelAPI_EventCreator::get()->sendUpdated(aConstraint, anUpdateEvent); + // 3. Tangency of fillet arc and features + for (int i = 0; i < aNbFeatures; i++) { + aConstraint = sketch()->addFeature(SketchPlugin_ConstraintTangent::ID()); + aRefAttr = std::dynamic_pointer_cast( + aConstraint->attribute(SketchPlugin_Constraint::ENTITY_A())); + aRefAttr->setObject(aResultArc->lastResult()); + aRefAttr = std::dynamic_pointer_cast( + aConstraint->attribute(SketchPlugin_Constraint::ENTITY_B())); + bool isArc = aResultFeatures[i]->getKind() == SketchPlugin_Arc::ID(); + aRefAttr->setObject(isArc ? aResultFeatures[i]->lastResult() : aResultFeatures[i]->firstResult()); + aConstraint->execute(); + aFilletFeatures.resultConstraints.push_back(aConstraint); + ModelAPI_EventCreator::get()->sendUpdated(aConstraint, anUpdateEvent); + } + // 4. Coincidence of free boundaries of base and copied features + for (int i = 0; i < aNbFeatures; i++) { + anAttrInd = 2*i + (isStart[i] ? 1 : 0); + aConstraint = sketch()->addFeature(SketchPlugin_ConstraintCoincidence::ID()); + aRefAttr = std::dynamic_pointer_cast( + aConstraint->attribute(SketchPlugin_Constraint::ENTITY_A())); + aRefAttr->setAttr(aBaseFeatures[i]->attribute(aFeatAttributes[anAttrInd])); + aRefAttr = std::dynamic_pointer_cast( + aConstraint->attribute(SketchPlugin_Constraint::ENTITY_B())); + aRefAttr->setAttr(aResultFeatures[i]->attribute(aFeatAttributes[anAttrInd])); + aFilletFeatures.resultConstraints.push_back(aConstraint); + } + // 4.1. Additional tangency constraints when the fillet is based on arcs. + // It is used to verify the created arc will be placed on a source. + for (int i = 0; i < aNbFeatures; ++i) { + if (aResultFeatures[i]->getKind() != SketchPlugin_Arc::ID()) + continue; + aConstraint = sketch()->addFeature(SketchPlugin_ConstraintTangent::ID()); + aRefAttr = std::dynamic_pointer_cast( + aConstraint->attribute(SketchPlugin_Constraint::ENTITY_A())); + aRefAttr->setObject(aBaseFeatures[i]->lastResult()); + aRefAttr = std::dynamic_pointer_cast( + aConstraint->attribute(SketchPlugin_Constraint::ENTITY_B())); + aRefAttr->setObject(aResultFeatures[i]->lastResult()); + aConstraint->execute(); + aFilletFeatures.resultConstraints.push_back(aConstraint); + ModelAPI_EventCreator::get()->sendUpdated(aConstraint, anUpdateEvent); + } + // 5. Tangent points should be placed on the base features + for (int i = 0; i < aNbFeatures; i++) { + anAttrInd = 2*i + (isStart[i] ? 0 : 1); + aConstraint = sketch()->addFeature(SketchPlugin_ConstraintCoincidence::ID()); + aRefAttr = std::dynamic_pointer_cast( + aConstraint->attribute(SketchPlugin_Constraint::ENTITY_A())); + aRefAttr->setAttr(aResultFeatures[i]->attribute(aFeatAttributes[anAttrInd])); + aRefAttr = std::dynamic_pointer_cast( + aConstraint->attribute(SketchPlugin_Constraint::ENTITY_B())); + aRefAttr->setObject(aBaseFeatures[i]->lastResult()); + aFilletFeatures.resultConstraints.push_back(aConstraint); + } + // make base features auxiliary + aBaseEdgeA->boolean(SketchPlugin_SketchEntity::AUXILIARY_ID())->setValue(true); + aBaseEdgeB->boolean(SketchPlugin_SketchEntity::AUXILIARY_ID())->setValue(true); + + // exchange the naming IDs of newly created and old line that become auxiliary + sketch()->exchangeIDs(aBaseEdgeA, aResultEdgeA); + sketch()->exchangeIDs(aBaseEdgeB, aResultEdgeB); + + // store point and features in the map. + myPointFeaturesMap[aPointAttr] = aFilletFeatures; + } else { + // Update radius value + int aNbSubs = sketch()->numberOfSubs(); + FeaturePtr aSubFeature; + for (int aSub = 0; aSub < aNbSubs; aSub++) { + aSubFeature = sketch()->subFeature(aSub); + if (aSubFeature->getKind() != SketchPlugin_ConstraintRadius::ID()) + continue; + AttributeRefAttrPtr aRefAttr = std::dynamic_pointer_cast( + aSubFeature->attribute(SketchPlugin_Constraint::ENTITY_A())); + if (!aRefAttr || !aRefAttr->isObject()) + continue; + FeaturePtr aFeature = ModelAPI_Feature::feature(aRefAttr->object()); + if (aFeature == aResultArc) { + AttributeDoublePtr aRadius = std::dynamic_pointer_cast( + aSubFeature->attribute(SketchPlugin_Constraint::VALUE())); + aRadius->setValue(aFilletRadius); + break; + } + } + } + } + + // Send events to update the sub-features by the solver. + if(isUpdateFlushed) { + Events_Loop::loop()->setFlushed(anUpdateEvent, true); + } +*/ +} + +void SketchPlugin_ConstraintSplit::attributeChanged(const std::string& theID) +{ +/* if(theID == SketchPlugin_Constraint::ENTITY_A()) { + if(myListOfPointsChangedInCode) { + return; + } + + // Clear results. + clearResults(); + + // Clear list of new points. + myNewPoints.clear(); + + // Get list of points for fillets and current radius. + AttributeRefAttrListPtr aRefListOfFilletPoints = std::dynamic_pointer_cast( + data()->attribute(SketchPlugin_Constraint::ENTITY_A())); + AttributeDoublePtr aRadiusAttribute = real(VALUE()); + int aListSize = aRefListOfFilletPoints->size(); + if(aListSize == 0 && !myRadiusChangedByUser) { + // If list is empty reset radius to zero (if it was not changed by user). + myRadiusChangedInCode = true; + aRadiusAttribute->setValue(0); + myRadiusChangedInCode = false; + return; + } + + // Iterate over points to get base lines an calculate radius for fillets. + double aMinimumRadius = 0; + std::list> aSelectedPointsList = aRefListOfFilletPoints->list(); + std::list>::iterator anIter = aSelectedPointsList.begin(); + std::set aPointsToSkeep; + for(int anIndex = 0; anIndex < aListSize; anIndex++, anIter++) { + AttributePtr aFilletPointAttr = (*anIter).second; + std::shared_ptr aFilletPoint2D = + std::dynamic_pointer_cast(aFilletPointAttr); + if(!aFilletPoint2D.get()) { + myNewPoints.clear(); + setError("Error: One of the selected points is invalid."); + return; + } + + // If point or coincident point is already in list remove it from attribute. + if(aPointsToSkeep.find(aFilletPointAttr) != aPointsToSkeep.end()) { + myListOfPointsChangedInCode = true; + aRefListOfFilletPoints->remove(aFilletPointAttr); + myListOfPointsChangedInCode = false; + continue; + } + + // Obtain constraint coincidence for the fillet point. + FeaturePtr aConstraintCoincidence; + const std::set& aRefsList = aFilletPointAttr->owner()->data()->refsToMe(); + for(std::set::const_iterator anIt = aRefsList.cbegin(); anIt != aRefsList.cend(); ++anIt) { + std::shared_ptr anAttr = (*anIt); + FeaturePtr aConstrFeature = std::dynamic_pointer_cast(anAttr->owner()); + if(aConstrFeature->getKind() == SketchPlugin_ConstraintCoincidence::ID()) { + AttributeRefAttrPtr anAttrRefA = std::dynamic_pointer_cast( + aConstrFeature->attribute(SketchPlugin_ConstraintCoincidence::ENTITY_A())); + AttributeRefAttrPtr anAttrRefB = std::dynamic_pointer_cast( + aConstrFeature->attribute(SketchPlugin_ConstraintCoincidence::ENTITY_B())); + if(anAttrRefA.get()) { + AttributePtr anAttrA = anAttrRefA->attr(); + if(aFilletPointAttr == anAttrA) { + aConstraintCoincidence = aConstrFeature; + break; + } + } + if(anAttrRefB.get()) { + AttributePtr anAttrB = anAttrRefB->attr(); + if(aFilletPointAttr == anAttrB) { + aConstraintCoincidence = aConstrFeature; + break; + } + } + } + } + + if(!aConstraintCoincidence.get()) { + myNewPoints.clear(); + setError("Error: No coincident edges at one of the selected points."); + return; + } + + // Get coincides from constraint. + std::set aCoincides; + + + SketchPlugin_Tools::findCoincidences(aConstraintCoincidence, + SketchPlugin_ConstraintCoincidence::ENTITY_A(), + aCoincides); + SketchPlugin_Tools::findCoincidences(aConstraintCoincidence, + SketchPlugin_ConstraintCoincidence::ENTITY_B(), + aCoincides); + + // Remove points from set of coincides. Also get all attributes which is equal to this point to exclude it. + std::shared_ptr aFilletPnt2d = aFilletPoint2D->pnt(); + std::set aNewSetOfCoincides; + for(std::set::iterator anIt = aCoincides.begin(); anIt != aCoincides.end(); ++anIt) { + std::string aFeatureKind = (*anIt)->getKind(); + if(aFeatureKind == SketchPlugin_Point::ID()) { + AttributePtr anAttr = (*anIt)->attribute(SketchPlugin_Point::COORD_ID()); + std::shared_ptr aPoint2D = + std::dynamic_pointer_cast(anAttr); + if(aPoint2D.get() && aFilletPnt2d->isEqual(aPoint2D->pnt())) { + aPointsToSkeep.insert(anAttr); + } + } else if(aFeatureKind == SketchPlugin_Line::ID()) { + AttributePtr anAttrStart = (*anIt)->attribute(SketchPlugin_Line::START_ID()); + std::shared_ptr aPointStart2D = + std::dynamic_pointer_cast(anAttrStart); + if(aPointStart2D.get() && aFilletPnt2d->isEqual(aPointStart2D->pnt())) { + aPointsToSkeep.insert(anAttrStart); + } + AttributePtr anAttrEnd = (*anIt)->attribute(SketchPlugin_Line::END_ID()); + std::shared_ptr aPointEnd2D = + std::dynamic_pointer_cast(anAttrEnd); + if(aPointEnd2D.get() && aFilletPnt2d->isEqual(aPointEnd2D->pnt())) { + aPointsToSkeep.insert(anAttrEnd); + } + aNewSetOfCoincides.insert(*anIt); + } else if(aFeatureKind == SketchPlugin_Arc::ID() ) { + AttributePtr anAttrCenter = (*anIt)->attribute(SketchPlugin_Arc::CENTER_ID()); + std::shared_ptr aPointCenter2D = + std::dynamic_pointer_cast(anAttrCenter); + if(aPointCenter2D.get() && aFilletPnt2d->isEqual(aPointCenter2D->pnt())) { + aPointsToSkeep.insert(anAttrCenter); + continue; + } + AttributePtr anAttrStart = (*anIt)->attribute(SketchPlugin_Arc::START_ID()); + std::shared_ptr aPointStart2D = + std::dynamic_pointer_cast(anAttrStart); + if(aPointStart2D.get() && aFilletPnt2d->isEqual(aPointStart2D->pnt())) { + aPointsToSkeep.insert(anAttrStart); + } + AttributePtr anAttrEnd = (*anIt)->attribute(SketchPlugin_Arc::END_ID()); + std::shared_ptr aPointEnd2D = + std::dynamic_pointer_cast(anAttrEnd); + if(aPointEnd2D.get() && aFilletPnt2d->isEqual(aPointEnd2D->pnt())) { + aPointsToSkeep.insert(anAttrEnd); + } + aNewSetOfCoincides.insert(*anIt); + } + } + aCoincides = aNewSetOfCoincides; + + // If we still have more than two coincides remove auxilary entities from set of coincides. + if(aCoincides.size() > 2) { + aNewSetOfCoincides.clear(); + for(std::set::iterator anIt = aCoincides.begin(); anIt != aCoincides.end(); ++anIt) { + if(!(*anIt)->boolean(SketchPlugin_SketchEntity::AUXILIARY_ID())->value()) { + aNewSetOfCoincides.insert(*anIt); + } + } + aCoincides = aNewSetOfCoincides; + } + + if(aCoincides.size() != 2) { + myNewPoints.clear(); + setError("Error: One of the selected points does not have two suitable edges for fillet."); + return; + } + + // Store base point for fillet. + aPointsToSkeep.insert(aFilletPointAttr); + myNewPoints.insert(aFilletPointAttr); + + // Get base lines for fillet. + FeaturePtr anOldFeatureA, anOldFeatureB; + std::set::iterator aLinesIt = aCoincides.begin(); + anOldFeatureA = *aLinesIt++; + anOldFeatureB = *aLinesIt; + + // Getting radius value if it was not changed by user. + if(!myRadiusChangedByUser) { + // Getting points located at 1/3 of edge length from fillet point. + std::shared_ptr aFilletPnt2d = aFilletPoint2D->pnt(); + std::shared_ptr aPntA, aPntB; + getPointOnEdge(anOldFeatureA, aFilletPnt2d, aPntA); + getPointOnEdge(anOldFeatureB, aFilletPnt2d, aPntB); + + /// Getting distances. + double aDistanceA = getProjectionDistance(anOldFeatureB, aPntA); + double aDistanceB = getProjectionDistance(anOldFeatureA, aPntB); + double aRadius = aDistanceA < aDistanceB ? aDistanceA / 2.0 : aDistanceB / 2.0; + aMinimumRadius = aMinimumRadius == 0 ? aRadius : aRadius < aMinimumRadius ? aRadius : aMinimumRadius; + } + } + + // Set new default radius if it was not changed by user. + if(!myRadiusChangedByUser) { + myRadiusChangedInCode = true; + aRadiusAttribute->setValue(aMinimumRadius); + myRadiusChangedInCode = false; + } + + } else if(theID == SketchPlugin_Constraint::VALUE()) { + if(myRadiusInitialized && !myRadiusChangedInCode) { + myRadiusChangedByUser = true; + } + if(!myRadiusInitialized) { + myRadiusInitialized = true; + } + } +*/ +} + +//AISObjectPtr SketchPlugin_ConstraintSplit::getAISObject(AISObjectPtr thePrevious) +//{ +// if (!sketch()) +// return thePrevious; +// +// AISObjectPtr anAIS = thePrevious; +// /// TODO: Equal constraint presentation should be put here +// return anAIS; +//} + +bool SketchPlugin_ConstraintSplit::isMacro() const +{ + return true; +} + +//void SketchPlugin_ConstraintSplit::clearResults() +//{ +///* // Clear auxiliary flag on initial objects. +// for(std::map::iterator aPointsIter = myPointFeaturesMap.begin(); +// aPointsIter != myPointFeaturesMap.end();) { +// const FilletFeatures& aFilletFeatures = aPointsIter->second; +// std::list>::const_iterator aFeatureIt; +// for(aFeatureIt = aFilletFeatures.baseEdgesState.cbegin(); +// aFeatureIt != aFilletFeatures.baseEdgesState.cend(); +// ++aFeatureIt) { +// aFeatureIt->first->boolean(SketchPlugin_SketchEntity::AUXILIARY_ID())->setValue(aFeatureIt->second); +// } +// ++aPointsIter; +// } +// +// // And remove all produced features. +// DocumentPtr aDoc = sketch()->document(); +// for(std::map::iterator aPointsIter = myPointFeaturesMap.begin(); +// aPointsIter != myPointFeaturesMap.end();) { +// // Remove all produced constraints. +// const FilletFeatures& aFilletFeatures = aPointsIter->second; +// std::list::const_iterator aFeatureIt; +// for(aFeatureIt = aFilletFeatures.resultConstraints.cbegin(); +// aFeatureIt != aFilletFeatures.resultConstraints.cend(); +// ++aFeatureIt) { +// aDoc->removeFeature(*aFeatureIt); +// } +// +// // Remove all result edges. +// for(aFeatureIt = aFilletFeatures.resultEdges.cbegin(); +// aFeatureIt != aFilletFeatures.resultEdges.cend(); +// ++aFeatureIt) { +// aDoc->removeFeature(*aFeatureIt); +// } +// +// // Remove point from map. +// myPointFeaturesMap.erase(aPointsIter++); +// } +//*/ +//}; +// +// +//// ========= Auxiliary functions ================= +//void recalculateAttributes(FeaturePtr theNewArc, const std::string& theNewArcAttribute, +// FeaturePtr theFeature, const std::string& theFeatureAttribute) +//{ +// std::shared_ptr anArcPoint = std::dynamic_pointer_cast( +// theNewArc->attribute(theNewArcAttribute))->pnt(); +// std::dynamic_pointer_cast( +// theFeature->attribute(theFeatureAttribute))->setValue(anArcPoint->x(), anArcPoint->y()); +//} + +/*/// \brief Find intersections of lines shifted along normal direction +void possibleFilletCenterLineLine( + std::shared_ptr thePointA, std::shared_ptr theDirA, + std::shared_ptr thePointB, std::shared_ptr theDirB, + double theRadius, std::list< std::shared_ptr >& theCenters) +{ + std::shared_ptr aDirAT(new GeomAPI_Dir2d(-theDirA->y(), theDirA->x())); + std::shared_ptr aDirBT(new GeomAPI_Dir2d(-theDirB->y(), theDirB->x())); + std::shared_ptr aPntA, aPntB; + double aDet = theDirA->cross(theDirB); + for (double aStepA = -1.0; aStepA <= 1.0; aStepA += 2.0) { + aPntA = thePointA->added(aDirAT->xy()->multiplied(aStepA * theRadius)); + for (double aStepB = -1.0; aStepB <= 1.0; aStepB += 2.0) { + aPntB = thePointB->added(aDirBT->xy()->multiplied(aStepB * theRadius)); + double aVX = aDirAT->xy()->dot(aPntA); + double aVY = aDirBT->xy()->dot(aPntB); + std::shared_ptr aPoint(new GeomAPI_XY( + (theDirB->x() * aVX - theDirA->x() * aVY) / aDet, + (theDirB->y() * aVX - theDirA->y() * aVY) / aDet)); + theCenters.push_back(aPoint); + } + } +} + +/// \brief Find intersections of line shifted along normal direction in both sides +/// and a circle with extended radius +void possibleFilletCenterLineArc( + std::shared_ptr theStartLine, std::shared_ptr theDirLine, + std::shared_ptr theCenterArc, double theRadiusArc, + double theRadius, std::list< std::shared_ptr >& theCenters) +{ + std::shared_ptr aDirT(new GeomAPI_Dir2d(-theDirLine->y(), theDirLine->x())); + std::shared_ptr aPnt; + double aDirNorm2 = theDirLine->dot(theDirLine); + double aRad = 0.0; + double aDirX = theDirLine->x(); + double aDirX2 = theDirLine->x() * theDirLine->x(); + double aDirY2 = theDirLine->y() * theDirLine->y(); + double aDirXY = theDirLine->x() * theDirLine->y(); + for (double aStepA = -1.0; aStepA <= 1.0; aStepA += 2.0) { + aPnt = theStartLine->added(aDirT->xy()->multiplied(aStepA * theRadius)); + double aCoeff = aDirT->xy()->dot(aPnt->decreased(theCenterArc)); + double aCoeff2 = aCoeff * aCoeff; + for (double aStepB = -1.0; aStepB <= 1.0; aStepB += 2.0) { + aRad = theRadiusArc + aStepB * theRadius; + double aD = aRad * aRad * aDirNorm2 - aCoeff2; + if (aD < 0.0) + continue; + double aDs = sqrt(aD); + double x1 = theCenterArc->x() + (aCoeff * aDirT->x() - aDirT->y() * aDs) / aDirNorm2; + double x2 = theCenterArc->x() + (aCoeff * aDirT->x() + aDirT->y() * aDs) / aDirNorm2; + double y1 = (aDirX2 * aPnt->y() + aDirY2 * theCenterArc->y() - + aDirXY * (aPnt->x() - theCenterArc->x()) - theDirLine->y() * aDs) / aDirNorm2; + double y2 = (aDirX2 * aPnt->y() + aDirY2 * theCenterArc->y() - + aDirXY * (aPnt->x() - theCenterArc->x()) + theDirLine->y() * aDs) / aDirNorm2; + + std::shared_ptr aPoint1(new GeomAPI_XY(x1, y1)); + theCenters.push_back(aPoint1); + std::shared_ptr aPoint2(new GeomAPI_XY(x2, y2)); + theCenters.push_back(aPoint2); + } + } +} + +/// \brief Find intersections of two circles with extended radii +void possibleFilletCenterArcArc( + std::shared_ptr theCenterA, double theRadiusA, + std::shared_ptr theCenterB, double theRadiusB, + double theRadius, std::list< std::shared_ptr >& theCenters) +{ + std::shared_ptr aCenterDir = theCenterB->decreased(theCenterA); + double aCenterDist2 = aCenterDir->dot(aCenterDir); + double aCenterDist = sqrt(aCenterDist2); + + double aRadA, aRadB; + for (double aStepA = -1.0; aStepA <= 1.0; aStepA += 2.0) { + aRadA = theRadiusA + aStepA * theRadius; + for (double aStepB = -1.0; aStepB <= 1.0; aStepB += 2.0) { + aRadB = theRadiusB + aStepB * theRadius; + if (aRadA + aRadB < aCenterDist || fabs(aRadA - aRadB) > aCenterDist) + continue; // there is no intersections + + double aMedDist = (aRadA * aRadA - aRadB * aRadB + aCenterDist2) / (2.0 * aCenterDist); + double aHeight = sqrt(aRadA * aRadA - aMedDist * aMedDist); + + double x1 = theCenterA->x() + (aMedDist * aCenterDir->x() + aCenterDir->y() * aHeight) / aCenterDist; + double y1 = theCenterA->y() + (aMedDist * aCenterDir->y() - aCenterDir->x() * aHeight) / aCenterDist; + + double x2 = theCenterA->x() + (aMedDist * aCenterDir->x() - aCenterDir->y() * aHeight) / aCenterDist; + double y2 = theCenterA->y() + (aMedDist * aCenterDir->y() + aCenterDir->x() * aHeight) / aCenterDist; + + std::shared_ptr aPoint1(new GeomAPI_XY(x1, y1)); + theCenters.push_back(aPoint1); + std::shared_ptr aPoint2(new GeomAPI_XY(x2, y2)); + theCenters.push_back(aPoint2); + } + } +} + +void calculateFilletCenter(FeaturePtr theFeatureA, FeaturePtr theFeatureB, + double theRadius, bool theNotInversed[2], + std::shared_ptr& theCenter, + std::shared_ptr& theTangentA, + std::shared_ptr& theTangentB) +{ + static const int aNbFeatures = 2; + FeaturePtr aFeature[aNbFeatures] = {theFeatureA, theFeatureB}; + std::shared_ptr aStart[aNbFeatures], aEnd[aNbFeatures], aCenter[aNbFeatures]; + std::shared_ptr aStartPoint, aEndPoint; + + for (int i = 0; i < aNbFeatures; i++) { + if (aFeature[i]->getKind() == SketchPlugin_Line::ID()) { + aStartPoint = std::dynamic_pointer_cast( + aFeature[i]->attribute(SketchPlugin_Line::START_ID())); + aEndPoint = std::dynamic_pointer_cast( + aFeature[i]->attribute(SketchPlugin_Line::END_ID())); + } else if (aFeature[i]->getKind() == SketchPlugin_Arc::ID()) { + aStartPoint = std::dynamic_pointer_cast( + aFeature[i]->attribute(SketchPlugin_Arc::START_ID())); + aEndPoint = std::dynamic_pointer_cast( + aFeature[i]->attribute(SketchPlugin_Arc::END_ID())); + aCenter[i] = std::dynamic_pointer_cast( + aFeature[i]->attribute(SketchPlugin_Arc::CENTER_ID()))->pnt()->xy(); + } else + return; + aStart[i] = std::shared_ptr(theNotInversed[i] ? + new GeomAPI_XY(aStartPoint->x(), aStartPoint->y()) : + new GeomAPI_XY(aEndPoint->x(), aEndPoint->y())); + aEnd[i] = std::shared_ptr(theNotInversed[i] ? + new GeomAPI_XY(aEndPoint->x(), aEndPoint->y()) : + new GeomAPI_XY(aStartPoint->x(), aStartPoint->y())); + } + + if (theFeatureA->getKind() == SketchPlugin_Line::ID() && + theFeatureB->getKind() == SketchPlugin_Line::ID()) { + std::shared_ptr aDir[2]; + std::shared_ptr aDirT[2]; + for (int i = 0; i < aNbFeatures; i++) { + aDir[i] = std::shared_ptr(new GeomAPI_Dir2d(aEnd[i]->decreased(aStart[i]))); + aDirT[i] = std::shared_ptr(new GeomAPI_Dir2d(-aDir[i]->y(), aDir[i]->x())); + } + + // get and filter possible centers + std::list< std::shared_ptr > aSuspectCenters; + possibleFilletCenterLineLine(aStart[0], aDir[0], aStart[1], aDir[1], theRadius, aSuspectCenters); + double aDot = 0.0; + std::list< std::shared_ptr >::iterator anIt = aSuspectCenters.begin(); + for (; anIt != aSuspectCenters.end(); anIt++) { + aDot = aDirT[0]->xy()->dot(aStart[0]->decreased(*anIt)); + theTangentA = (*anIt)->added(aDirT[0]->xy()->multiplied(aDot)); + if (theTangentA->decreased(aStart[0])->dot(aDir[0]->xy()) < 0.0) + continue; // incorrect position + aDot = aDirT[1]->xy()->dot(aStart[1]->decreased(*anIt)); + theTangentB = (*anIt)->added(aDirT[1]->xy()->multiplied(aDot)); + if (theTangentB->decreased(aStart[1])->dot(aDir[1]->xy()) < 0.0) + continue; // incorrect position + // the center is found, stop searching + theCenter = *anIt; + return; + } + } else if ((theFeatureA->getKind() == SketchPlugin_Arc::ID() && + theFeatureB->getKind() == SketchPlugin_Line::ID()) || + (theFeatureA->getKind() == SketchPlugin_Line::ID() && + theFeatureB->getKind() == SketchPlugin_Arc::ID())) { + int aLineInd = theFeatureA->getKind() == SketchPlugin_Line::ID() ? 0 : 1; + double anArcRadius = aStart[1-aLineInd]->distance(aCenter[1-aLineInd]); + std::shared_ptr aDirLine = std::shared_ptr( + new GeomAPI_Dir2d(aEnd[aLineInd]->decreased(aStart[aLineInd]))); + std::shared_ptr aDirT = std::shared_ptr( + new GeomAPI_Dir2d(-aDirLine->y(), aDirLine->x())); + + std::shared_ptr aStartArcDir = std::shared_ptr( + new GeomAPI_Dir2d(aStart[1-aLineInd]->decreased(aCenter[1-aLineInd]))); + std::shared_ptr aEndArcDir = std::shared_ptr( + new GeomAPI_Dir2d(aEnd[1-aLineInd]->decreased(aCenter[1-aLineInd]))); + double anArcAngle = aEndArcDir->angle(aStartArcDir); + + // get possible centers and filter them + std::list< std::shared_ptr > aSuspectCenters; + possibleFilletCenterLineArc(aStart[aLineInd], aDirLine, aCenter[1-aLineInd], anArcRadius, theRadius, aSuspectCenters); + double aDot = 0.0; + // the line is forward into the arc + double innerArc = aCenter[1-aLineInd]->decreased(aStart[aLineInd])->dot(aDirLine->xy()); + std::shared_ptr aLineTgPoint, anArcTgPoint; + // The possible centers are ranged by their positions. + // If the point is not satisfy one of criteria, the weight is decreased with penalty. + int aBestWeight = 0; + std::list< std::shared_ptr >::iterator anIt = aSuspectCenters.begin(); + for (; anIt != aSuspectCenters.end(); anIt++) { + int aWeight = 2; + aDot = aDirT->xy()->dot(aStart[aLineInd]->decreased(*anIt)); + aLineTgPoint = (*anIt)->added(aDirT->xy()->multiplied(aDot)); + // Check the point is placed on the correct arc (penalty if false) + if (aCenter[1-aLineInd]->distance(*anIt) * innerArc > anArcRadius * innerArc) + aWeight -= 1; + std::shared_ptr aCurDir = std::shared_ptr( + new GeomAPI_Dir2d((*anIt)->decreased(aCenter[1-aLineInd]))); + double aCurAngle = aCurDir->angle(aStartArcDir); + if (anArcAngle < 0.0) aCurAngle *= -1.0; + if (aCurAngle < 0.0 || aCurAngle > fabs(anArcAngle)) + continue; + if (aWeight > aBestWeight) + aBestWeight = aWeight; + else if (aWeight < aBestWeight || + aStart[aLineInd]->distance(*anIt) > + aStart[aLineInd]->distance(theCenter)) // <-- take closer point + continue; + // the center is found, stop searching + theCenter = *anIt; + anArcTgPoint = aCenter[1-aLineInd]->added(aCurDir->xy()->multiplied(anArcRadius)); + if (theFeatureA->getKind() == SketchPlugin_Line::ID()) { + theTangentA = aLineTgPoint; + theTangentB = anArcTgPoint; + } else { + theTangentA = anArcTgPoint; + theTangentB = aLineTgPoint; + } + //return; + } + } else if (theFeatureA->getKind() == SketchPlugin_Arc::ID() && + theFeatureB->getKind() == SketchPlugin_Arc::ID()) { + double anArcRadius[aNbFeatures]; + double anArcAngle[aNbFeatures]; + std::shared_ptr aStartArcDir[aNbFeatures]; + for (int i = 0; i < aNbFeatures; i++) { + anArcRadius[i] = aStart[i]->distance(aCenter[i]); + aStartArcDir[i] = std::shared_ptr( + new GeomAPI_Dir2d(aStart[i]->decreased(aCenter[i]))); + std::shared_ptr aEndArcDir = std::shared_ptr( + new GeomAPI_Dir2d(aEnd[i]->decreased(aCenter[i]))); + anArcAngle[i] = aEndArcDir->angle(aStartArcDir[i]); + } + + // get and filter possible centers + std::list< std::shared_ptr > aSuspectCenters; + possibleFilletCenterArcArc(aCenter[0], anArcRadius[0], aCenter[1], anArcRadius[1], theRadius, aSuspectCenters); + double aDot = 0.0; + std::shared_ptr aLineTgPoint, anArcTgPoint; + std::list< std::shared_ptr >::iterator anIt = aSuspectCenters.begin(); + for (; anIt != aSuspectCenters.end(); anIt++) { + std::shared_ptr aCurDir = std::shared_ptr( + new GeomAPI_Dir2d((*anIt)->decreased(aCenter[0]))); + double aCurAngle = aCurDir->angle(aStartArcDir[0]); + if (anArcAngle[0] < 0.0) aCurAngle *= -1.0; + if (aCurAngle < 0.0 || aCurAngle > fabs(anArcAngle[0])) + continue; // incorrect position + theTangentA = aCenter[0]->added(aCurDir->xy()->multiplied(anArcRadius[0])); + + aCurDir = std::shared_ptr(new GeomAPI_Dir2d((*anIt)->decreased(aCenter[1]))); + aCurAngle = aCurDir->angle(aStartArcDir[1]); + if (anArcAngle[1] < 0.0) aCurAngle *= -1.0; + if (aCurAngle < 0.0 || aCurAngle > fabs(anArcAngle[1])) + continue; // incorrect position + theTangentB = aCenter[1]->added(aCurDir->xy()->multiplied(anArcRadius[1])); + + // the center is found, stop searching + theCenter = *anIt; + return; + } + } +} + +void getPointOnEdge(const FeaturePtr theFeature, + const std::shared_ptr theFilletPoint, + std::shared_ptr& thePoint) { + if(theFeature->getKind() == SketchPlugin_Line::ID()) { + std::shared_ptr aPntStart = std::dynamic_pointer_cast( + theFeature->attribute(SketchPlugin_Line::START_ID()))->pnt(); + std::shared_ptr aPntEnd = std::dynamic_pointer_cast( + theFeature->attribute(SketchPlugin_Line::END_ID()))->pnt(); + if(aPntStart->distance(theFilletPoint) > 1.e-7) { + aPntStart = std::dynamic_pointer_cast( + theFeature->attribute(SketchPlugin_Line::END_ID()))->pnt(); + aPntEnd = std::dynamic_pointer_cast( + theFeature->attribute(SketchPlugin_Line::START_ID()))->pnt(); + } + thePoint.reset( new GeomAPI_Pnt2d(aPntStart->xy()->added( aPntEnd->xy()->decreased( aPntStart->xy() )->multiplied(1.0 / 3.0) ) ) ); + } else { + std::shared_ptr aPntTemp; + std::shared_ptr aPntStart = std::dynamic_pointer_cast( + theFeature->attribute(SketchPlugin_Arc::START_ID()))->pnt(); + std::shared_ptr aPntEnd = std::dynamic_pointer_cast( + theFeature->attribute(SketchPlugin_Arc::END_ID()))->pnt(); + if(theFeature->attribute(SketchPlugin_Arc::INVERSED_ID())) { + aPntTemp = aPntStart; + aPntStart = aPntEnd; + aPntEnd = aPntTemp; + } + std::shared_ptr aCenterPnt = std::dynamic_pointer_cast( + theFeature->attribute(SketchPlugin_Arc::CENTER_ID()))->pnt(); + std::shared_ptr aCirc(new GeomAPI_Circ2d(aCenterPnt, aPntStart)); + double aStartParameter(0), anEndParameter(0); + aCirc->parameter(aPntStart, paramTolerance, aStartParameter); + aCirc->parameter(aPntEnd, paramTolerance, anEndParameter); + if(aPntStart->distance(theFilletPoint) > tolerance) { + double aTmpParameter = aStartParameter; + aStartParameter = anEndParameter; + anEndParameter = aTmpParameter; + } + double aPntParameter = aStartParameter + (anEndParameter - aStartParameter) / 3.0; + aCirc->D0(aPntParameter, thePoint); + } +} + +double getProjectionDistance(const FeaturePtr theFeature, + const std::shared_ptr thePoint) +{ + std::shared_ptr aProjectPnt; + if(theFeature->getKind() == SketchPlugin_Line::ID()) { + std::shared_ptr aPntStart = std::dynamic_pointer_cast( + theFeature->attribute(SketchPlugin_Line::START_ID()))->pnt(); + std::shared_ptr aPntEnd = std::dynamic_pointer_cast( + theFeature->attribute(SketchPlugin_Line::END_ID()))->pnt(); + std::shared_ptr aLin(new GeomAPI_Lin2d(aPntStart, aPntEnd)); + aProjectPnt = aLin->project(thePoint); + } else { + std::shared_ptr aPntStart = std::dynamic_pointer_cast( + theFeature->attribute(SketchPlugin_Arc::START_ID()))->pnt(); + std::shared_ptr aPntEnd = std::dynamic_pointer_cast( + theFeature->attribute(SketchPlugin_Arc::END_ID()))->pnt(); + std::shared_ptr aCenterPnt = std::dynamic_pointer_cast( + theFeature->attribute(SketchPlugin_Arc::CENTER_ID()))->pnt(); + std::shared_ptr aCirc(new GeomAPI_Circ2d(aCenterPnt, aPntStart)); + aProjectPnt = aCirc->project(thePoint); + } + if(aProjectPnt.get()) { + return aProjectPnt->distance(thePoint); + } + return -1; +} + +std::set getCoincides(const FeaturePtr& theConstraintCoincidence) +{ + std::set aCoincides; + + std::shared_ptr aFilletPnt = SketchPlugin_Tools::getCoincidencePoint(theConstraintCoincidence); + + SketchPlugin_Tools::findCoincidences(theConstraintCoincidence, + SketchPlugin_ConstraintCoincidence::ENTITY_A(), + aCoincides); + SketchPlugin_Tools::findCoincidences(theConstraintCoincidence, + SketchPlugin_ConstraintCoincidence::ENTITY_B(), + aCoincides); + + // Remove points from set of coincides. + std::set aNewSetOfCoincides; + for(std::set::iterator anIt = aCoincides.begin(); anIt != aCoincides.end(); ++anIt) { + if((*anIt)->getKind() == SketchPlugin_Line::ID()) { + aNewSetOfCoincides.insert(*anIt); + } else if((*anIt)->getKind() == SketchPlugin_Arc::ID()) { + AttributePtr anAttrCenter = (*anIt)->attribute(SketchPlugin_Arc::CENTER_ID()); + std::shared_ptr aPointCenter2D = + std::dynamic_pointer_cast(anAttrCenter); + if(aPointCenter2D.get() && aFilletPnt->isEqual(aPointCenter2D->pnt())) { + continue; + } + aNewSetOfCoincides.insert(*anIt); + } + } + aCoincides = aNewSetOfCoincides; + + // If we still have more than two coincides remove auxilary entities from set of coincides. + if(aCoincides.size() > 2) { + aNewSetOfCoincides.clear(); + for(std::set::iterator anIt = aCoincides.begin(); anIt != aCoincides.end(); ++anIt) { + if(!(*anIt)->boolean(SketchPlugin_SketchEntity::AUXILIARY_ID())->value()) { + aNewSetOfCoincides.insert(*anIt); + } + } + aCoincides = aNewSetOfCoincides; + } + + return aCoincides; +} +*/ diff --git a/src/SketchPlugin/SketchPlugin_ConstraintSplit.h b/src/SketchPlugin/SketchPlugin_ConstraintSplit.h new file mode 100755 index 000000000..d084b8083 --- /dev/null +++ b/src/SketchPlugin/SketchPlugin_ConstraintSplit.h @@ -0,0 +1,85 @@ +// Copyright (C) 2014-20xx CEA/DEN, EDF R&D --> + +// File: SketchPlugin_ConstraintSplit.h +// Created: 19 Mar 2015 +// Author: Artem ZHIDKOV + +#ifndef SketchPlugin_ConstraintSplit_H_ +#define SketchPlugin_ConstraintSplit_H_ + +#include "SketchPlugin.h" +#include +#include "SketchPlugin_ConstraintBase.h" + +/** \class SketchPlugin_ConstraintSplit + * \ingroup Plugins + * \brief Feature for creation of a new constraint filleting two objects which have coincident point + * + * This constraint has three attributes: + * SketchPlugin_Constraint::ENTITY_A() and SketchPlugin_Constraint::ENTITY_B() for the filleting objects; + * SketchPlugin_Constraint::VALUE() contains radius of filleting circular arc + * + * Also the constraint has attribute SketchPlugin_Constraint::ENTITY_C() + * which contains created list objects forming the fillet + */ +class SketchPlugin_ConstraintSplit : public SketchPlugin_ConstraintBase +{ + public: + /*struct FilletFeatures { + std::list> baseEdgesState; ///< list of objects the fillet is based and its states + std::list resultEdges; ///< list of result edges + std::list resultConstraints; ///< list of constraints provided by the fillet + };*/ + + /// Split constraint kind + inline static const std::string& ID() + { + static const std::string MY_CONSTRAINT_SPLIT_ID("SketchConstraintSplit"); + return MY_CONSTRAINT_SPLIT_ID; + } + /// \brief Returns the kind of a feature + SKETCHPLUGIN_EXPORT virtual const std::string& getKind() + { + static std::string MY_KIND = SketchPlugin_ConstraintSplit::ID(); + return MY_KIND; + } + + /// \brief Creates a new part document if needed + SKETCHPLUGIN_EXPORT virtual void execute(); + + /// \brief Request for initialization of data model of the feature: adding all attributes + SKETCHPLUGIN_EXPORT virtual void initAttributes(); + + /// Called on change of any argument-attribute of this object + /// \param theID identifier of changed attribute + SKETCHPLUGIN_EXPORT virtual void attributeChanged(const std::string& theID); + + /// Returns the AIS preview + //SKETCHPLUGIN_EXPORT virtual AISObjectPtr getAISObject(AISObjectPtr thePrevious); + + /// Reimplemented from ModelAPI_Feature::isMacro(). + /// \returns true + SKETCHPLUGIN_EXPORT virtual bool isMacro() const; + + /// \brief Use plugin manager for features creation + SketchPlugin_ConstraintSplit(); + + /// \return map of base points and features; + //SKETCHPLUGIN_EXPORT const std::map pointsFeaturesMap() const { + // return myPointFeaturesMap; + //}; + +private: + /// \ Removes all produced features and restore base edges. + //void clearResults(); + +private: + //std::set myNewPoints; ///< set of new points + //std::map myPointFeaturesMap; ///< map of point and features for fillet + //bool myListOfPointsChangedInCode; ///< flag to track that list of points changed in code + //bool myRadiusChangedByUser; ///< flag to track that radius changed by user + //bool myRadiusChangedInCode; ///< flag to track that radius changed in code + //bool myRadiusInitialized; /// < flag to track that radius initialized +}; + +#endif diff --git a/src/SketchPlugin/SketchPlugin_Plugin.cpp b/src/SketchPlugin/SketchPlugin_Plugin.cpp index 635583b0c..ebead598f 100644 --- a/src/SketchPlugin/SketchPlugin_Plugin.cpp +++ b/src/SketchPlugin/SketchPlugin_Plugin.cpp @@ -14,6 +14,7 @@ #include #include #include +#include #include #include #include @@ -76,6 +77,8 @@ SketchPlugin_Plugin::SketchPlugin_Plugin() new SketchPlugin_SolverErrorValidator); aFactory->registerValidator("SketchPlugin_FilletVertexValidator", new SketchPlugin_FilletVertexValidator); + aFactory->registerValidator("SketchPlugin_SplitValidator", + new SketchPlugin_SplitValidator); aFactory->registerValidator("SketchPlugin_MiddlePointAttr", new SketchPlugin_MiddlePointAttrValidator); aFactory->registerValidator("SketchPlugin_ArcTangentPoint", @@ -161,6 +164,8 @@ FeaturePtr SketchPlugin_Plugin::createFeature(string theFeatureID) return FeaturePtr(new SketchPlugin_ConstraintMirror); } else if (theFeatureID == SketchPlugin_ConstraintFillet::ID()) { return FeaturePtr(new SketchPlugin_ConstraintFillet); + } else if (theFeatureID == SketchPlugin_ConstraintSplit::ID()) { + return FeaturePtr(new SketchPlugin_ConstraintSplit); } else if (theFeatureID == SketchPlugin_MultiTranslation::ID()) { return FeaturePtr(new SketchPlugin_MultiTranslation); } else if (theFeatureID == SketchPlugin_MultiRotation::ID()) { @@ -224,6 +229,7 @@ std::shared_ptr SketchPlugin_Plugin aMsg->setState(SketchPlugin_ConstraintMiddle::ID(), aHasSketchPlane); aMsg->setState(SketchPlugin_ConstraintMirror::ID(), aHasSketchPlane); aMsg->setState(SketchPlugin_ConstraintFillet::ID(), aHasSketchPlane); + aMsg->setState(SketchPlugin_ConstraintSplit::ID(), aHasSketchPlane); aMsg->setState(SketchPlugin_ConstraintAngle::ID(), aHasSketchPlane); aMsg->setState(SketchPlugin_MultiRotation::ID(), aHasSketchPlane); aMsg->setState(SketchPlugin_MultiTranslation::ID(), aHasSketchPlane); diff --git a/src/SketchPlugin/SketchPlugin_Validators.cpp b/src/SketchPlugin/SketchPlugin_Validators.cpp index 9b3d82c82..b488d4fa0 100755 --- a/src/SketchPlugin/SketchPlugin_Validators.cpp +++ b/src/SketchPlugin/SketchPlugin_Validators.cpp @@ -32,8 +32,11 @@ #include #include #include +#include #include +#include + #include #include #include @@ -847,6 +850,56 @@ bool SketchPlugin_IntersectionValidator::isValid(const AttributePtr& theAttribut return fabs(aNormal->dot(aLineDir)) > tolerance * tolerance; } +bool SketchPlugin_SplitValidator::isValid(const AttributePtr& theAttribute, + const std::list& theArguments, + Events_InfoMessage& theError) const +{ + bool aValid = false; + + if (theAttribute->attributeType() != ModelAPI_AttributeSelection::typeId()) { + theError = "The attribute with the %1 type is not processed"; + theError.arg(theAttribute->attributeType()); + return aValid; + } + AttributeSelectionPtr aFeatureAttr = + std::dynamic_pointer_cast(theAttribute); + + ObjectPtr anAttrObject = aFeatureAttr->context(); + FeaturePtr anAttrFeature = ModelAPI_Feature::feature(anAttrObject); + if (!anAttrFeature) + return aValid; + + std::string aKind = anAttrFeature->getKind(); + if (aKind == SketchPlugin_Line::ID() || + aKind == SketchPlugin_Arc::ID() || + aKind == SketchPlugin_Circle::ID()) { + + std::set anEdgeShapes; + ModelAPI_Tools::shapesOfType(anAttrFeature, GeomAPI_Shape::EDGE, anEdgeShapes); + if (anEdgeShapes.empty()) + return aValid; + + GeomShapePtr anAttrShape = *anEdgeShapes.begin(); + + //std::shared_ptr aPointAttr = ModelGeomAlgo_Point2D::getPointOfRefAttr( + // anAttrFeature, theAttribute, SketchPlugin_Point::ID(), SketchPlugin_Point::COORD_ID()); + + std::set > aRefAttributes; + //ModelGeomAlgo_Point2D::getPointsOfReference(anAttrFeature.get(), SketchPlugin_ConstraintCoincidence::ID(), + // aRefAttributes, SketchPlugin_Point::ID(), SketchPlugin_Point::COORD_ID()); + + //ModelGeomAlgo_Point2D::filterPointsToBeInsideShape(anAttrShape, aRefAttributes, ); + + int aCoincidentToFeature = aRefAttributes.size(); + if (aKind == SketchPlugin_Circle::ID()) + aValid = aCoincidentToFeature > 2; + else + aValid = aCoincidentToFeature > 1; + } + + return true; +} + bool SketchPlugin_ProjectionValidator::isValid(const AttributePtr& theAttribute, const std::list& theArguments, Events_InfoMessage& theError) const diff --git a/src/SketchPlugin/SketchPlugin_Validators.h b/src/SketchPlugin/SketchPlugin_Validators.h index 2ebb8ad76..70120d614 100644 --- a/src/SketchPlugin/SketchPlugin_Validators.h +++ b/src/SketchPlugin/SketchPlugin_Validators.h @@ -218,6 +218,27 @@ class SketchPlugin_ArcTangentPointValidator : public ModelAPI_AttributeValidator Events_InfoMessage& theError) const; }; +/**\class SketchPlugin_SplitValidator + * \ingroup Validators + * \brief Validator for the entity of the following type: + * - Linear segment with point(s) coinident to this line + * - Arc with point(s) coincident to the arc + * - Circle with at least 2 split-points on this circle + * + * Checks that there are coincident point on selected feature. + */ +class SketchPlugin_SplitValidator : public ModelAPI_AttributeValidator +{ + public: + //! returns true if attribute is valid + //! \param theAttribute the checked attribute + //! \param theArguments arguments of the attribute + //! \param theError error message + virtual bool isValid(const AttributePtr& theAttribute, + const std::list& theArguments, + Events_InfoMessage& theError) const; +}; + /**\class SketchPlugin_IntersectionValidator * \ingroup Validators * \brief Validator for the attribute to be intersected with the sketch plane. diff --git a/src/SketchPlugin/SketchPlugin_msg_en.ts b/src/SketchPlugin/SketchPlugin_msg_en.ts index 5a7e90e6e..e3c2e600a 100644 --- a/src/SketchPlugin/SketchPlugin_msg_en.ts +++ b/src/SketchPlugin/SketchPlugin_msg_en.ts @@ -1186,7 +1186,15 @@ Second object is not selected - + + + SketchConstraintSplit + + ConstraintEntityA - SketchPlugin_SplitValidator: The attribute with the %1 type is not processed + Only attribute selection can be used for the sketch face, not %1 + + + SketchConstraintFillet diff --git a/src/SketchPlugin/plugin-Sketch.xml b/src/SketchPlugin/plugin-Sketch.xml index 0d2eb9c05..3f1db5400 100644 --- a/src/SketchPlugin/plugin-Sketch.xml +++ b/src/SketchPlugin/plugin-Sketch.xml @@ -5,7 +5,7 @@ + + + + + + diff --git a/src/SketcherPrs/CMakeLists.txt b/src/SketcherPrs/CMakeLists.txt index 236833f24..624b98cb6 100644 --- a/src/SketcherPrs/CMakeLists.txt +++ b/src/SketcherPrs/CMakeLists.txt @@ -55,6 +55,7 @@ SET(PROJECT_SOURCES SET(PROJECT_LIBRARIES Config ModelAPI + ModelGeomAlgo GeomAPI GeomDataAPI Events @@ -96,6 +97,7 @@ INCLUDE_DIRECTORIES( ${PROJECT_SOURCE_DIR}/src/Config ${PROJECT_SOURCE_DIR}/src/Events ${PROJECT_SOURCE_DIR}/src/ModelAPI + ${PROJECT_SOURCE_DIR}/src/ModelGeomAlgo ${PROJECT_SOURCE_DIR}/src/GeomAPI ${PROJECT_SOURCE_DIR}/src/GeomDataAPI ${PROJECT_SOURCE_DIR}/src/SketchPlugin diff --git a/src/SketcherPrs/SketcherPrs_Tools.cpp b/src/SketcherPrs/SketcherPrs_Tools.cpp index 45f4eaaf9..84d0878f6 100644 --- a/src/SketcherPrs/SketcherPrs_Tools.cpp +++ b/src/SketcherPrs/SketcherPrs_Tools.cpp @@ -17,6 +17,8 @@ #include #include +#include + #include #include @@ -77,27 +79,8 @@ std::shared_ptr getShape(ObjectPtr theObject) std::shared_ptr getPoint(ModelAPI_Feature* theFeature, const std::string& theAttribute) { - std::shared_ptr aPointAttr; - - /// essential check as it is called in openGl thread - if (!theFeature || !theFeature->data().get() || !theFeature->data()->isValid()) - return std::shared_ptr(); - - FeaturePtr aFeature; - std::shared_ptr anAttr = std::dynamic_pointer_cast< - ModelAPI_AttributeRefAttr>(theFeature->data()->attribute(theAttribute)); - if(!anAttr.get()) { - return std::shared_ptr(); - } - aFeature = ModelAPI_Feature::feature(anAttr->object()); - - if (aFeature && aFeature->getKind() == SketchPlugin_Point::ID()) - aPointAttr = std::dynamic_pointer_cast( - aFeature->data()->attribute(SketchPlugin_Point::COORD_ID())); - - else if (anAttr->attr()) { - aPointAttr = std::dynamic_pointer_cast(anAttr->attr()); - } + std::shared_ptr aPointAttr = ModelGeomAlgo_Point2D::getPointOfRefAttr( + theFeature, theAttribute, SketchPlugin_Point::ID(), SketchPlugin_Point::COORD_ID()); if (aPointAttr.get() != NULL) return aPointAttr->pnt(); return std::shared_ptr(); diff --git a/src/XGUI/XGUI_ModuleConnector.cpp b/src/XGUI/XGUI_ModuleConnector.cpp index 6312c827b..c3b079f05 100644 --- a/src/XGUI/XGUI_ModuleConnector.cpp +++ b/src/XGUI/XGUI_ModuleConnector.cpp @@ -130,18 +130,15 @@ bool XGUI_ModuleConnector::canStartOperation(QString theId) return myWorkshop->operationMgr()->canStartOperation(theId); } -void XGUI_ModuleConnector::processLaunchOperation(ModuleBase_Operation* theOperation, - const bool isUpdatePropertyPanel) +void XGUI_ModuleConnector::processLaunchOperation(ModuleBase_Operation* theOperation) { XGUI_OperationMgr* anOperationMgr = workshop()->operationMgr(); if (anOperationMgr->startOperation(theOperation)) { - if (isUpdatePropertyPanel) { - ModuleBase_OperationFeature* aFOperation = dynamic_cast(theOperation); - if (aFOperation) { - workshop()->propertyPanel()->updateContentWidget(aFOperation->feature()); - workshop()->propertyPanel()->createContentPanel(aFOperation->feature()); - } + ModuleBase_OperationFeature* aFOperation = dynamic_cast(theOperation); + if (aFOperation) { + workshop()->propertyPanel()->updateContentWidget(aFOperation->feature()); + workshop()->propertyPanel()->createContentPanel(aFOperation->feature()); } if (!theOperation->getDescription()->hasXmlRepresentation()) { if (theOperation->commit()) diff --git a/src/XGUI/XGUI_ModuleConnector.h b/src/XGUI/XGUI_ModuleConnector.h index 423bcbdcd..0a00cf57b 100644 --- a/src/XGUI/XGUI_ModuleConnector.h +++ b/src/XGUI/XGUI_ModuleConnector.h @@ -59,8 +59,7 @@ Q_OBJECT //! Performs the operation launch //! \param theOperation an operation to be launched - virtual void processLaunchOperation(ModuleBase_Operation* theOperation, - const bool isUpdatePropertyPanel); + virtual void processLaunchOperation(ModuleBase_Operation* theOperation); //! Returns started operation by the operation identifier. The operation manager is called. //! \param theId an operation id diff --git a/src/XGUI/XGUI_OperationMgr.cpp b/src/XGUI/XGUI_OperationMgr.cpp index d975519a3..1fb45442d 100644 --- a/src/XGUI/XGUI_OperationMgr.cpp +++ b/src/XGUI/XGUI_OperationMgr.cpp @@ -470,9 +470,6 @@ void XGUI_OperationMgr::onBeforeOperationStarted() qDebug(QString("\tdocument->currentFeature(false) = %1").arg( ModuleBase_Tools::objectInfo(ModelAPI_Session::get()->activeDocument()->currentFeature(false))).toStdString().c_str()); #endif - ModuleBase_IModule* aModule = myWorkshop->module(); - if (aModule) - aModule->beforeOperationStarted(aFOperation); } } @@ -480,7 +477,8 @@ void XGUI_OperationMgr::onOperationStarted() { ModuleBase_Operation* aSenderOperation = dynamic_cast(sender()); updateApplyOfOperations(aSenderOperation); - emit operationStarted(aSenderOperation); + XGUI_Workshop* aWorkshop = XGUI_Tools::workshop(myWorkshop); + aWorkshop->operationStarted(aSenderOperation); } void XGUI_OperationMgr::onBeforeOperationAborted() diff --git a/src/XGUI/XGUI_OperationMgr.h b/src/XGUI/XGUI_OperationMgr.h index 41d678c59..cca5bb926 100755 --- a/src/XGUI/XGUI_OperationMgr.h +++ b/src/XGUI/XGUI_OperationMgr.h @@ -127,9 +127,6 @@ public slots: bool abortAllOperations(); signals: - /// Signal about an operation is started. It is emitted after the start() of operation is done. - void operationStarted(ModuleBase_Operation* theOperation); - /// Signal about an operation is stopped. It is emitted after the stop() of operation is done. /// \param theOperation a stopped operation void operationStopped(ModuleBase_Operation* theOperation); diff --git a/src/XGUI/XGUI_Workshop.cpp b/src/XGUI/XGUI_Workshop.cpp index ca80dce9f..fd3b111b6 100755 --- a/src/XGUI/XGUI_Workshop.cpp +++ b/src/XGUI/XGUI_Workshop.cpp @@ -177,8 +177,6 @@ XGUI_Workshop::XGUI_Workshop(XGUI_SalomeConnector* theConnector) myErrorMgr = new XGUI_ErrorMgr(this, aWorkshop); - connect(myOperationMgr, SIGNAL(operationStarted(ModuleBase_Operation*)), - SLOT(onOperationStarted(ModuleBase_Operation*))); connect(myOperationMgr, SIGNAL(operationResumed(ModuleBase_Operation*)), SLOT(onOperationResumed(ModuleBase_Operation*))); connect(myOperationMgr, SIGNAL(operationStopped(ModuleBase_Operation*)), @@ -488,7 +486,7 @@ bool XGUI_Workshop::isFeatureOfNested(const FeaturePtr& theFeature) return aHasNested; } -void XGUI_Workshop::setPropertyPanel(ModuleBase_Operation* theOperation) +void XGUI_Workshop::fillPropertyPanel(ModuleBase_Operation* theOperation) { ModuleBase_OperationFeature* aFOperation = dynamic_cast(theOperation); if (!aFOperation) @@ -583,20 +581,13 @@ void XGUI_Workshop::connectToPropertyPanel(const bool isToConnect) } } -//****************************************************** -void XGUI_Workshop::onOperationStarted(ModuleBase_Operation* theOperation) -{ - setGrantedFeatures(theOperation); - myModule->operationStarted(theOperation); -} - //****************************************************** void XGUI_Workshop::onOperationResumed(ModuleBase_Operation* theOperation) { setGrantedFeatures(theOperation); if (theOperation->getDescription()->hasXmlRepresentation()) { //!< No need for property panel - setPropertyPanel(theOperation); + fillPropertyPanel(theOperation); connectToPropertyPanel(true); } updateCommandStatus(); @@ -679,10 +670,7 @@ void XGUI_Workshop::setGrantedFeatures(ModuleBase_Operation* theOperation) aFOperation->setGrantedOperationIds(aGrantedIds); } - -/* - * Saves document with given name. - */ +//****************************************************** void XGUI_Workshop::saveDocument(const QString& theName, std::list& theFileNames) { QApplication::restoreOverrideCursor(); @@ -691,11 +679,24 @@ void XGUI_Workshop::saveDocument(const QString& theName, std::list& QApplication::restoreOverrideCursor(); } +//****************************************************** bool XGUI_Workshop::abortAllOperations() { return myOperationMgr->abortAllOperations(); } +//****************************************************** +void XGUI_Workshop::operationStarted(ModuleBase_Operation* theOperation) +{ + setGrantedFeatures(theOperation); + if (!theOperation->getDescription()->hasXmlRepresentation()) { //!< No need for property panel + updateCommandStatus(); + } + else { + myModule->operationStarted(theOperation); + } +} + //****************************************************** void XGUI_Workshop::onOpen() { diff --git a/src/XGUI/XGUI_Workshop.h b/src/XGUI/XGUI_Workshop.h index fea7600a0..1a90b4dc6 100755 --- a/src/XGUI/XGUI_Workshop.h +++ b/src/XGUI/XGUI_Workshop.h @@ -246,6 +246,12 @@ Q_OBJECT */ bool abortAllOperations(); + /// Updates workshop state according to the started operation, e.g. visualizes the property panel + /// and connect to it. + /// \param theOpertion a started operation + void operationStarted(ModuleBase_Operation* theOperation); + + //! Delete features. Delete the referenced features. There can be a question with a list of //! referenced objects. //! \param theFeatures a list of objects to be deleted @@ -277,7 +283,7 @@ Q_OBJECT /// Update the property panel content by the XML description of the operation and set the panel /// into the operation /// \param theOperation an operation - void setPropertyPanel(ModuleBase_Operation* theOperation); + void fillPropertyPanel(ModuleBase_Operation* theOperation); /// Connects or disconnects to the value changed signal of the property panel widgets /// \param isToConnect a boolean value whether connect or disconnect @@ -405,7 +411,7 @@ private: /// SLOT, that is called after the operation is started. Update workshop state according to /// the started operation, e.g. visualizes the property panel and connect to it. /// \param theOpertion a started operation - void onOperationStarted(ModuleBase_Operation* theOperation); + // void onOperationStarted(ModuleBase_Operation* theOperation); /// SLOT, that is called after the operation is resumed. Update workshop state according to /// the started operation, e.g. visualizes the property panel and connect to it.