From af69a9771accba3192bbb19edf77fb2dce428b7e Mon Sep 17 00:00:00 2001 From: nds Date: Tue, 28 Feb 2017 09:47:31 +0300 Subject: [PATCH] Issue #2027 Sketcher Trim Feature Trim Circle feature, Line and Arc features. --- src/GeomAPI/GeomAPI_Shape.cpp | 4 +- src/GeomAlgoAPI/GeomAlgoAPI_ShapeTools.cpp | 46 + src/GeomAlgoAPI/GeomAlgoAPI_ShapeTools.h | 15 +- src/ModelAPI/ModelAPI_Tools.cpp | 5 +- src/ModelAPI/ModelAPI_Tools.h | 4 +- src/ModelGeomAlgo/ModelGeomAlgo_Point2D.cpp | 116 ++ src/ModelGeomAlgo/ModelGeomAlgo_Point2D.h | 31 + src/PartSet/CMakeLists.txt | 44 +- src/PartSet/PartSet_Module.cpp | 7 + src/PartSet/PartSet_MouseProcessor.h | 8 + src/PartSet/PartSet_SketcherReetntrantMgr.cpp | 22 +- .../PartSet_WidgetFeaturePointSelector.cpp | 197 +++ .../PartSet_WidgetFeaturePointSelector.h | 119 ++ src/PartSet/PartSet_WidgetPoint2d.cpp | 6 +- src/PartSet/PartSet_WidgetPoint2d.h | 7 +- .../PartSet_WidgetSubShapeSelector.cpp | 12 +- src/SketchAPI/SketchAPI_Sketch.cpp | 19 + src/SketchAPI/SketchAPI_Sketch.h | 6 + src/SketchPlugin/CMakeLists.txt | 4 +- .../SketchPlugin_ConstraintSplit.cpp | 2 +- src/SketchPlugin/SketchPlugin_Plugin.cpp | 4 + src/SketchPlugin/SketchPlugin_Trim.cpp | 1074 +++++++++++++++++ src/SketchPlugin/SketchPlugin_Trim.h | 266 ++++ src/SketchPlugin/SketchPlugin_Validators.cpp | 21 +- src/SketchPlugin/Test/TestTrimCircle.py | 129 ++ src/SketchPlugin/icons/split.png | Bin 574 -> 566 bytes src/SketchPlugin/icons/trim.png | Bin 0 -> 563 bytes src/SketchPlugin/plugin-Sketch.xml | 35 +- src/XGUI/XGUI_Displayer.cpp | 2 +- 29 files changed, 2148 insertions(+), 57 deletions(-) create mode 100644 src/PartSet/PartSet_WidgetFeaturePointSelector.cpp create mode 100644 src/PartSet/PartSet_WidgetFeaturePointSelector.h create mode 100644 src/SketchPlugin/SketchPlugin_Trim.cpp create mode 100644 src/SketchPlugin/SketchPlugin_Trim.h create mode 100644 src/SketchPlugin/Test/TestTrimCircle.py create mode 100644 src/SketchPlugin/icons/trim.png diff --git a/src/GeomAPI/GeomAPI_Shape.cpp b/src/GeomAPI/GeomAPI_Shape.cpp index d79e365b4..b8c32ec28 100644 --- a/src/GeomAPI/GeomAPI_Shape.cpp +++ b/src/GeomAPI/GeomAPI_Shape.cpp @@ -7,7 +7,7 @@ #include "GeomAPI_Shape.h" #include -#include +#include #include #include #include @@ -436,7 +436,7 @@ GeomShapePtr GeomAPI_Shape::intersect(const GeomShapePtr theShape) const const TopoDS_Shape& aShape1 = const_cast(this)->impl(); const TopoDS_Shape& aShape2 = theShape->impl(); - BRepAlgoAPI_Common aCommon(aShape1, aShape2); + BRepAlgoAPI_Section aCommon(aShape1, aShape2); if (!aCommon.IsDone()) return GeomShapePtr(); diff --git a/src/GeomAlgoAPI/GeomAlgoAPI_ShapeTools.cpp b/src/GeomAlgoAPI/GeomAlgoAPI_ShapeTools.cpp index 14b2fbc41..1df2c7f87 100644 --- a/src/GeomAlgoAPI/GeomAlgoAPI_ShapeTools.cpp +++ b/src/GeomAlgoAPI/GeomAlgoAPI_ShapeTools.cpp @@ -695,6 +695,52 @@ bool GeomAlgoAPI_ShapeTools::isParallel(const std::shared_ptr theE //================================================================================================== void GeomAlgoAPI_ShapeTools::splitShape(const std::shared_ptr& theBaseShape, + const GeomAlgoAPI_ShapeTools::PointToRefsMap& thePointsInfo, + std::set >& theShapes) +{ + // General Fuse to split edge by vertices + BOPAlgo_Builder aBOP; + TopoDS_Edge aBaseEdge = theBaseShape->impl(); + // Rebuild closed edge to place vertex to one of split points. + // This will prevent edge to be split on same vertex. + if (BRep_Tool::IsClosed(aBaseEdge)) + { + Standard_Real aFirst, aLast; + Handle(Geom_Curve) aCurve = BRep_Tool::Curve(aBaseEdge, aFirst, aLast); + + PointToRefsMap::const_iterator aPIt = thePointsInfo.begin(); + std::shared_ptr aPnt = aPIt->first; + gp_Pnt aPoint(aPnt->x(), aPnt->y(), aPnt->z()); + + TopAbs_Orientation anOrientation = aBaseEdge.Orientation(); + aBaseEdge = BRepBuilderAPI_MakeEdge(aCurve, aPoint, aPoint).Edge(); + aBaseEdge.Orientation(anOrientation); + } + aBOP.AddArgument(aBaseEdge); + + PointToRefsMap::const_iterator aPIt = thePointsInfo.begin(); + for (; aPIt != thePointsInfo.end(); ++aPIt) { + std::shared_ptr aPnt = aPIt->first; + 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); + } +} + +//================================================================================================== +void GeomAlgoAPI_ShapeTools::splitShape_p(const std::shared_ptr& theBaseShape, const std::list >& thePoints, std::set >& theShapes) { diff --git a/src/GeomAlgoAPI/GeomAlgoAPI_ShapeTools.h b/src/GeomAlgoAPI/GeomAlgoAPI_ShapeTools.h index 22c886787..d3b712585 100644 --- a/src/GeomAlgoAPI/GeomAlgoAPI_ShapeTools.h +++ b/src/GeomAlgoAPI/GeomAlgoAPI_ShapeTools.h @@ -12,6 +12,7 @@ #include #include +#include #include class GeomAPI_Edge; @@ -20,6 +21,8 @@ class GeomAPI_Face; class GeomAPI_PlanarEdges; class GeomAPI_Pln; class GeomAPI_Pnt; +class GeomDataAPI_Point2D; +class ModelAPI_Object; /// \class GeomAlgoAPI_ShapeTools /// \ingroup DataAlgo @@ -116,14 +119,24 @@ public: GEOMALGOAPI_EXPORT static bool isParallel(const std::shared_ptr theEdge, const std::shared_ptr theFace); + typedef std::map, + std::pair >, + std::list > > > PointToRefsMap; /// \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::list >& thePoints, + const PointToRefsMap& thePointsInfo, std::set >& theShapes); + /// \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_p(const std::shared_ptr& theBaseShape, + const std::list >& thePoints, + std::set >& theShapes); GEOMALGOAPI_EXPORT static std::shared_ptr findShape( const std::list >& thePoints, diff --git a/src/ModelAPI/ModelAPI_Tools.cpp b/src/ModelAPI/ModelAPI_Tools.cpp index f6182527a..8d65638b9 100755 --- a/src/ModelAPI/ModelAPI_Tools.cpp +++ b/src/ModelAPI/ModelAPI_Tools.cpp @@ -92,15 +92,16 @@ std::shared_ptr shape(const ResultPtr& theResult) void shapesOfType(const FeaturePtr& theFeature, const GeomAPI_Shape::ShapeType& theType, - std::set& theShapes) + std::set& theShapeResults) { + theShapeResults.clear(); 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); + theShapeResults.insert(aResult); } } diff --git a/src/ModelAPI/ModelAPI_Tools.h b/src/ModelAPI/ModelAPI_Tools.h index 39e6f76d2..573ee12a3 100755 --- a/src/ModelAPI/ModelAPI_Tools.h +++ b/src/ModelAPI/ModelAPI_Tools.h @@ -29,10 +29,10 @@ 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 +/// \param an output container for result of shapes MODELAPI_EXPORT void shapesOfType(const FeaturePtr& theFeature, const GeomAPI_Shape::ShapeType& theType, - std::set& theShapes); + std::set& theShapeResults); /*! Returns the feature error generated according to feature error and exec state * \param theFeature a feature diff --git a/src/ModelGeomAlgo/ModelGeomAlgo_Point2D.cpp b/src/ModelGeomAlgo/ModelGeomAlgo_Point2D.cpp index f9fa6030d..e65a2786e 100755 --- a/src/ModelGeomAlgo/ModelGeomAlgo_Point2D.cpp +++ b/src/ModelGeomAlgo/ModelGeomAlgo_Point2D.cpp @@ -9,6 +9,10 @@ #include #include #include +#include +#include + +#include #include #include @@ -119,7 +123,119 @@ namespace ModelGeomAlgo_Point2D { } } + void appendPoint(const std::shared_ptr& thePoint, + const std::shared_ptr& theResult, + PointToRefsMap& thePointToAttributeOrObject) + { + if (thePointToAttributeOrObject.find(thePoint) != thePointToAttributeOrObject.end()) + thePointToAttributeOrObject.at(thePoint).second.push_back(theResult); + else { + std::list > anAttributes; + std::list > anObjects; + anObjects.push_back(theResult); + thePointToAttributeOrObject[thePoint] = std::make_pair(anAttributes, anObjects); + } + } + + void appendShapePoints(GeomShapePtr& theShape, + const std::shared_ptr& theResult, + PointToRefsMap& thePointToAttributeOrObject) + { + if (!theShape.get()) + return; + + switch (theShape->shapeType()) { + case GeomAPI_Shape::VERTEX: { + std::shared_ptr aVertex = + std::shared_ptr(new GeomAPI_Vertex(theShape)); + std::shared_ptr aPnt = aVertex->point(); + appendPoint(aPnt, theResult, thePointToAttributeOrObject); + } + break; + case GeomAPI_Shape::EDGE: { + std::shared_ptr anEdge = + std::shared_ptr(new GeomAPI_Edge(theShape)); + appendPoint(anEdge->firstPoint(), theResult, thePointToAttributeOrObject); + appendPoint(anEdge->lastPoint(), theResult, thePointToAttributeOrObject); + } + break; + case GeomAPI_Shape::COMPOUND: { + for(GeomAPI_ShapeIterator anIt(theShape); anIt.more(); anIt.next()) { + appendShapePoints(anIt.current(), theResult, thePointToAttributeOrObject); + } + } + break; + default: break; + } + } + + void getPointsIntersectedShape(const std::shared_ptr& theBaseFeature, + const std::list >& theFeatures, + PointToRefsMap& thePointToAttributeOrObject) + { + GeomShapePtr aFeatureShape; + { + std::set anEdgeShapes; + ModelAPI_Tools::shapesOfType(theBaseFeature, GeomAPI_Shape::EDGE, anEdgeShapes); + if (anEdgeShapes.empty()) + return; + aFeatureShape = (*anEdgeShapes.begin())->shape(); + } + + std::list >::const_iterator anIt = theFeatures.begin(), + aLast = theFeatures.end(); + for (; anIt != aLast; anIt++) { + FeaturePtr aFeature = *anIt; + if (aFeature.get() == theBaseFeature.get()) + continue; + if (aFeature.get()) { + std::set anEdgeShapes; + ModelAPI_Tools::shapesOfType(aFeature, GeomAPI_Shape::EDGE, anEdgeShapes); + if (anEdgeShapes.empty()) + continue; + ResultPtr aResult = *anEdgeShapes.begin(); + GeomShapePtr aShape = aResult->shape(); + + GeomShapePtr aShapeOfIntersection = aFeatureShape->intersect(aShape); + appendShapePoints(aShapeOfIntersection, aResult, thePointToAttributeOrObject); + } + } + } + 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, + PointToRefsMap& thePointToAttributeOrObject) + { + 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 aPoint = aPnt2d->to3D(theOrigin, theDirX, theDirY); + std::shared_ptr aProjectedPoint; + if (isPointOnEdge(theBaseShape, aPoint, aProjectedPoint)) { + if (thePointToAttributeOrObject.find(aProjectedPoint) != thePointToAttributeOrObject.end()) + thePointToAttributeOrObject.at(aProjectedPoint).first.push_back(anAttribute); + else { + //std::list< std::shared_ptr > anAttributes; + //anAttributes.push_back(anAttribute); + //thePointToAttributeOrObject.insert(aProjectedPoint, anAttributes); + + std::list > anAttributes; + std::list > anObjects; + anAttributes.push_back(anAttribute); + thePointToAttributeOrObject[aProjectedPoint] = std::make_pair(anAttributes, anObjects); + } + //thePoints.push_back(aProjectedPoint); + //theAttributeToPoint[anAttribute] = aProjectedPoint; + } + } + } + + void getPointsInsideShape_p(const std::shared_ptr theBaseShape, const std::set >& theAttributes, const std::shared_ptr& theOrigin, const std::shared_ptr& theDirX, diff --git a/src/ModelGeomAlgo/ModelGeomAlgo_Point2D.h b/src/ModelGeomAlgo/ModelGeomAlgo_Point2D.h index d8fd556c4..6e717c10e 100755 --- a/src/ModelGeomAlgo/ModelGeomAlgo_Point2D.h +++ b/src/ModelGeomAlgo/ModelGeomAlgo_Point2D.h @@ -57,6 +57,20 @@ namespace ModelGeomAlgo_Point2D { const std::string& theObjectFeatureAttribute = "", const bool isSkipFeatureAttributes = true); + /// Find points of intersection between the shape of the feature and all features in the sketch + /// \param theBaseFeature a feature: line, arc or circle that will be intersected + /// \param theFeatures a container of features to intersect with the base feature + /// \param thePoints a container of 3D points belong to the shape + /// \param theObjectToPoint a container of object to point + typedef std::map, + std::pair >, + std::list > > > PointToRefsMap; + + MODELGEOMALGO_EXPORT void getPointsIntersectedShape( + const std::shared_ptr& theBaseFeature, + const std::list >& theFeatures, + PointToRefsMap& thePointToAttributeOrObject); + /// Removes attributes which points are out of the base shape /// \param theBaseShape a shape of check /// \param theAttributes a container of point 2D attributes @@ -64,7 +78,24 @@ namespace ModelGeomAlgo_Point2D { /// \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 + /// \param theAttributeToPoint a container of attribute to point 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, + PointToRefsMap& thePointToAttributeOrObject); + + /// 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 + /// \param theAttributeToPoint a container of attribute to point + MODELGEOMALGO_EXPORT void getPointsInsideShape_p( const std::shared_ptr theBaseShape, const std::set >& theAttributes, const std::shared_ptr& theOrigin, diff --git a/src/PartSet/CMakeLists.txt b/src/PartSet/CMakeLists.txt index ad4506730..bb1035a06 100644 --- a/src/PartSet/CMakeLists.txt +++ b/src/PartSet/CMakeLists.txt @@ -14,40 +14,43 @@ SET(PROJECT_HEADERS PartSet_Constants.h PartSet_CustomPrs.h PartSet_ExternalObjectsMgr.h + PartSet_FilterInfinite.h + PartSet_Filters.h + PartSet_IconFactory.h + PartSet_MenuMgr.h PartSet_Module.h PartSet_MouseProcessor.h PartSet_OperationPrs.h PartSet_OverconstraintListener.h PartSet_PreviewPlanes.h + PartSet_ResultSketchPrs.h + PartSet_SketcherMgr.h + PartSet_SketcherReetntrantMgr.h PartSet_Tools.h - PartSet_WidgetSketchLabel.h PartSet_Validators.h - PartSet_WidgetPoint2d.h + PartSet_WidgetChoice.h PartSet_WidgetEditor.h + PartSet_WidgetFeaturePointSelector.h + PartSet_WidgetFileSelector.h PartSet_WidgetMultiSelector.h + PartSet_WidgetPoint2d.h PartSet_WidgetPoint2dDistance.h PartSet_WidgetPoint2DFlyout.h PartSet_WidgetShapeSelector.h - PartSet_WidgetFileSelector.h - PartSet_Filters.h - PartSet_FilterInfinite.h - PartSet_ResultSketchPrs.h - PartSet_SketcherMgr.h - PartSet_SketcherReetntrantMgr.h - PartSet_MenuMgr.h PartSet_WidgetSketchCreator.h - PartSet_IconFactory.h - PartSet_WidgetChoice.h + PartSet_WidgetSketchLabel.h PartSet_WidgetSubShapeSelector.h ) SET(PROJECT_MOC_HEADERS + PartSet_MenuMgr.h PartSet_Module.h PartSet_SketcherMgr.h PartSet_SketcherReetntrantMgr.h PartSet_WidgetChoice.h PartSet_WidgetEditor.h + PartSet_WidgetFeaturePointSelector.h PartSet_WidgetFileSelector.h PartSet_WidgetMultiSelector.h PartSet_WidgetPoint2d.h @@ -62,28 +65,29 @@ SET(PROJECT_MOC_HEADERS SET(PROJECT_SOURCES PartSet_CustomPrs.cpp PartSet_ExternalObjectsMgr.cpp + PartSet_FilterInfinite.cpp + PartSet_Filters.cpp + PartSet_IconFactory.cpp + PartSet_MenuMgr.cpp PartSet_Module.cpp PartSet_OperationPrs.cpp PartSet_OverconstraintListener.cpp PartSet_PreviewPlanes.cpp + PartSet_ResultSketchPrs.cpp + PartSet_SketcherMgr.cpp + PartSet_SketcherReetntrantMgr.cpp PartSet_Tools.cpp - PartSet_WidgetSketchLabel.cpp PartSet_Validators.cpp PartSet_WidgetEditor.cpp + PartSet_WidgetFeaturePointSelector.cpp + PartSet_WidgetFileSelector.cpp PartSet_WidgetMultiSelector.cpp PartSet_WidgetPoint2d.cpp PartSet_WidgetPoint2dDistance.cpp PartSet_WidgetPoint2DFlyout.cpp PartSet_WidgetShapeSelector.cpp - PartSet_WidgetFileSelector.cpp - PartSet_Filters.cpp - PartSet_FilterInfinite.cpp - PartSet_ResultSketchPrs.cpp - PartSet_SketcherMgr.cpp - PartSet_SketcherReetntrantMgr.cpp - PartSet_MenuMgr.cpp PartSet_WidgetSketchCreator.cpp - PartSet_IconFactory.cpp + PartSet_WidgetSketchLabel.cpp PartSet_WidgetSubShapeSelector.cpp ) diff --git a/src/PartSet/PartSet_Module.cpp b/src/PartSet/PartSet_Module.cpp index 4fc3b6ab0..d441445ca 100755 --- a/src/PartSet/PartSet_Module.cpp +++ b/src/PartSet/PartSet_Module.cpp @@ -11,6 +11,7 @@ #include "PartSet_WidgetShapeSelector.h" #include "PartSet_WidgetMultiSelector.h" #include "PartSet_WidgetSubShapeSelector.h" +#include "PartSet_WidgetFeaturePointSelector.h" #include "PartSet_WidgetEditor.h" #include "PartSet_WidgetFileSelector.h" #include "PartSet_WidgetSketchCreator.h" @@ -744,6 +745,12 @@ ModuleBase_ModelWidget* PartSet_Module::createWidgetByType(const std::string& th aSubShapeSelectorWgt->setSketcher(mySketchMgr->activeSketch()); aWgt = aSubShapeSelectorWgt; } + else if (theType == "sketch_feature_point_selector") { + PartSet_WidgetFeaturePointSelector* aPointSelectorWgt = + new PartSet_WidgetFeaturePointSelector(theParent, aWorkshop, theWidgetApi); + aPointSelectorWgt->setSketcher(mySketchMgr->activeSketch()); + aWgt = aPointSelectorWgt; + } else if (theType == WDG_DOUBLEVALUE_EDITOR) { aWgt = new PartSet_WidgetEditor(theParent, aWorkshop, theWidgetApi); } else if (theType == "export_file_selector") { diff --git a/src/PartSet/PartSet_MouseProcessor.h b/src/PartSet/PartSet_MouseProcessor.h index 6a123df60..91f40398a 100755 --- a/src/PartSet/PartSet_MouseProcessor.h +++ b/src/PartSet/PartSet_MouseProcessor.h @@ -9,7 +9,10 @@ #include "PartSet.h" +#include + class ModuleBase_IViewWindow; +class ModuleBase_ViewerPrs; class QMouseEvent; /** @@ -39,6 +42,11 @@ public: /// \param theEvent a mouse event PARTSET_EXPORT virtual void mouseDoubleClick(ModuleBase_IViewWindow* theWindow, QMouseEvent* theEvent) {} + + /// Fill preselection used in mouseReleased + virtual void setPreSelection(const std::shared_ptr& thePreSelected, + ModuleBase_IViewWindow* theWnd, + QMouseEvent* theEvent) {} }; #endif diff --git a/src/PartSet/PartSet_SketcherReetntrantMgr.cpp b/src/PartSet/PartSet_SketcherReetntrantMgr.cpp index 6f8ba11fd..3cbc1cc5d 100755 --- a/src/PartSet/PartSet_SketcherReetntrantMgr.cpp +++ b/src/PartSet/PartSet_SketcherReetntrantMgr.cpp @@ -233,15 +233,21 @@ bool PartSet_SketcherReetntrantMgr::processMouseReleased(ModuleBase_IViewWindow* // fill the first widget by the mouse event point // if the active widget is not the first, it means that the restarted operation is filled by // the current preselection. - PartSet_WidgetPoint2D* aPoint2DWdg = - dynamic_cast(module()->activeWidget()); - ModuleBase_ModelWidget* aFirstWidget = aPanel->findFirstAcceptingValueWidget(); - if (aPoint2DWdg && aPoint2DWdg == aFirstWidget) { + PartSet_MouseProcessor* aMouseProcessor = dynamic_cast( + module()->activeWidget()); + //PartSet_WidgetPoint2D* aPoint2DWdg = + // dynamic_cast(module()->activeWidget()); + PartSet_MouseProcessor* aFirstWidget = dynamic_cast( + aPanel->findFirstAcceptingValueWidget()); + //if (aPoint2DWdg && aPoint2DWdg == aFirstWidget) { + if (aMouseProcessor && aMouseProcessor == aFirstWidget) { + std::shared_ptr aSelectedPrs; if (!aPreSelected.empty()) - aPoint2DWdg->setPreSelection(aPreSelected.front()); - aPoint2DWdg->mouseReleased(theWnd, theEvent); - if (!aPreSelected.empty()) - aPoint2DWdg->setPreSelection(ModuleBase_ViewerPrsPtr()); + aSelectedPrs = aPreSelected.front(); + aMouseProcessor->setPreSelection(aSelectedPrs, theWnd, theEvent); + //aPoint2DWdg->mouseReleased(theWnd, theEvent); + //if (!aPreSelected.empty()) + // aPoint2DWdg->setPreSelection(ModuleBase_ViewerPrsPtr()); } // unblock viewer update ModuleBase_Tools::blockUpdateViewer(false); diff --git a/src/PartSet/PartSet_WidgetFeaturePointSelector.cpp b/src/PartSet/PartSet_WidgetFeaturePointSelector.cpp new file mode 100644 index 000000000..eaa7f58e2 --- /dev/null +++ b/src/PartSet/PartSet_WidgetFeaturePointSelector.cpp @@ -0,0 +1,197 @@ +// Copyright (C) 2014-20xx CEA/DEN, EDF R&D + +// File: PartSet_WidgetFeaturePointSelector.cpp +// Created: 28 Feb 2017 +// Author: Natalia ERMOLAEVA + +#include + +#include + +#include +#include +#include +#include +#include + +#include +#include + +#include +#include +#include + +#include +#include +#include + +#include "PartSet_WidgetFeaturePointSelector.h" +#include "PartSet_Tools.h" + +//#include +//#include +#include +#include + +#include +#include +#include +#include + +#include +#include + +#define HIGHLIGHT_STAYS_PROBLEM +#ifdef HIGHLIGHT_STAYS_PROBLEM +#include +#define SKETCH_ENTITY_COLOR "225,0,0" +#endif + +PartSet_WidgetFeaturePointSelector::PartSet_WidgetFeaturePointSelector(QWidget* theParent, + ModuleBase_IWorkshop* theWorkshop, + const Config_WidgetAPI* theData) +: ModuleBase_WidgetShapeSelector(theParent, theWorkshop, theData) +{ +} + +PartSet_WidgetFeaturePointSelector::~PartSet_WidgetFeaturePointSelector() +{ +} + +//******************************************************************** +bool PartSet_WidgetFeaturePointSelector::isValidSelection( + const std::shared_ptr& theValue) +{ + return true; +} + +//******************************************************************** +void PartSet_WidgetFeaturePointSelector::activateCustom() +{ + ModuleBase_WidgetShapeSelector::activateCustom(); + + myWorkshop->module()->activateCustomPrs(myFeature, + ModuleBase_IModule::CustomizeHighlightedObjects, true); + + Handle(AIS_InteractiveContext) aContext = + XGUI_Tools::workshop(myWorkshop)->viewer()->AISContext(); + + std::vector aColors; + aColors = Config_PropManager::color("Visualization", "sketch_entity_color", + SKETCH_ENTITY_COLOR); + Quantity_Color aColor(aColors[0] / 255., aColors[1] / 255., aColors[2] / 255., Quantity_TOC_RGB); + +#ifdef HIGHLIGHT_STAYS_PROBLEM + Handle(Graphic3d_HighlightStyle) aHStyle = aContext->HighlightStyle(); + myHighlightColor = aHStyle->Color(); + aHStyle->SetColor(aColor); + aContext->SetHighlightStyle(aHStyle); + + Handle(Graphic3d_HighlightStyle) aSStyle = aContext->SelectionStyle(); + mySelectionColor = aSStyle->Color(); + aSStyle->SetColor(aColor); + aContext->SetSelectionStyle(aSStyle); +#endif +} + +//******************************************************************** +void PartSet_WidgetFeaturePointSelector::deactivate() +{ + ModuleBase_WidgetShapeSelector::deactivate(); + + Handle(AIS_InteractiveContext) aContext = + XGUI_Tools::workshop(myWorkshop)->viewer()->AISContext(); + +#ifdef HIGHLIGHT_STAYS_PROBLEM + Handle(Graphic3d_HighlightStyle) aHStyle = aContext->HighlightStyle(); + aHStyle->SetColor(myHighlightColor); + aContext->SetHighlightStyle(aHStyle); + + Handle(Graphic3d_HighlightStyle) aSStyle = aContext->SelectionStyle(); + aSStyle->SetColor(mySelectionColor); + aContext->SetSelectionStyle(aSStyle); +#endif +} + +//******************************************************************** +void PartSet_WidgetFeaturePointSelector::mouseMoved(ModuleBase_IViewWindow* theWindow, + QMouseEvent* theEvent) +{ + ModuleBase_ISelection* aSelect = myWorkshop->selection(); + QList aHighlighted = aSelect->getHighlighted(); + + if (!aHighlighted.empty()) { + ModuleBase_ViewerPrsPtr aPrs = aHighlighted.first(); + fillFeature(aPrs, theWindow, theEvent); + } +} + +//******************************************************************** +void PartSet_WidgetFeaturePointSelector::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; + + emit focusOutWidget(this); +} + +//******************************************************************** +bool PartSet_WidgetFeaturePointSelector::fillFeature( + const std::shared_ptr& theSelectedPrs, + ModuleBase_IViewWindow* theWindow, + QMouseEvent* theEvent) +{ + bool aFilled = false; + if (theSelectedPrs.get() && theSelectedPrs->object().get()) { + ObjectPtr anObject = theSelectedPrs->object(); + gp_Pnt aPnt = PartSet_Tools::convertClickToPoint(theEvent->pos(), theWindow->v3dView()); + double aX, anY; + Handle(V3d_View) aView = theWindow->v3dView(); + PartSet_Tools::convertTo2D(aPnt, mySketch, aView, aX, anY); + + std::shared_ptr aRef = + std::dynamic_pointer_cast( + feature()->data()->attribute(SketchPlugin_Trim::BASE_OBJECT())); + aRef->setValue(anObject); + + std::shared_ptr anAttributePoint = + std::dynamic_pointer_cast( + feature()->data()->attribute(SketchPlugin_Trim::ENTITY_POINT())); + anAttributePoint->setValue(aX, anY); + // redisplay AIS presentation in viewer +#ifndef HIGHLIGHT_STAYS_PROBLEM + // an attempt to clear highlighted item in the viewer: but of OCCT + XGUI_Tools::workshop(myWorkshop)->displayer()->clearSelected(true); +#endif + updateObject(feature()); + aFilled = true; + } + return aFilled; +} + +//******************************************************************** +QList PartSet_WidgetFeaturePointSelector::getAttributeSelection() const +{ + return QList(); +} + + +//******************************************************************** +bool PartSet_WidgetFeaturePointSelector::setSelection( + QList>& theValues, + const bool theToValidate) +{ + // false is returned to do not emit focus out widget by selected sub-shape + return false; +} + +void PartSet_WidgetFeaturePointSelector::setPreSelection( + const std::shared_ptr& thePreSelected, + ModuleBase_IViewWindow* theWnd, + QMouseEvent* theEvent) +{ + if (fillFeature(thePreSelected, theWnd, theEvent)) + mouseReleased(theWnd, theEvent); +} diff --git a/src/PartSet/PartSet_WidgetFeaturePointSelector.h b/src/PartSet/PartSet_WidgetFeaturePointSelector.h new file mode 100644 index 000000000..cfb6329db --- /dev/null +++ b/src/PartSet/PartSet_WidgetFeaturePointSelector.h @@ -0,0 +1,119 @@ +// Copyright (C) 2014-20xx CEA/DEN, EDF R&D + +// File: PartSet_WidgetFeaturePointSelector.h +// Created: 28 Feb 2017 +// Author: Natalia ERMOLAEVA + + +#ifndef PartSet_WidgetFeaturePointSelector_H +#define PartSet_WidgetFeaturePointSelector_H + +#include +#include + +#include "PartSet.h" +#include "PartSet_MouseProcessor.h" + +#include + +#include + +class ModuleBase_IWorkshop; +class Config_WidgetAPI; +class ModuleBase_IViewWindow; +class ModuleBase_ViewerPrs; + +class GeomAPI_Pnt; +class GeomDataAPI_Point2D; + +class QWidget; +class QMouseEvent; + +/** +* \ingroup Modules +* Customosation of PartSet_WidgetFeaturePointSelector 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_WidgetFeaturePointSelector: public ModuleBase_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_WidgetFeaturePointSelector(QWidget* theParent, ModuleBase_IWorkshop* theWorkshop, + const Config_WidgetAPI* theData); + + virtual ~PartSet_WidgetFeaturePointSelector(); + + /// Checks all widget validator if the owner is valid. Firstly it checks custom widget validating, + /// next, the attribute's validating. It trying on the give selection to current attribute by + /// setting the value inside and calling validators. After this, the previous attribute value is + /// restored.The valid/invalid value is cashed. + /// \param theValue a selected presentation in the view + /// \return a boolean value + virtual bool isValidSelection(const std::shared_ptr& theValue); + + /// Set sketcher + /// \param theSketch a sketcher object + void setSketcher(CompositeFeaturePtr theSketch) { mySketch = theSketch; } + + /// Retrurns installed sketcher + CompositeFeaturePtr sketch() const { return mySketch; } + + /// The methiod called when widget is deactivated + virtual void deactivate(); + + /// 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); + + /// 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); + + /// Returns values which should be highlighted when the whidget is active + /// \param theValues a list of presentations + //virtual void getHighlighted(QList>& theValues); + + /// Set the given wrapped value to the current widget + /// This value should be processed in the widget according to the needs + /// The method is called by the current operation to process the operation preselection. + /// It is redefined to fill attributes responsible for the sub selection + /// \param theValues the wrapped selection values + /// \param theToValidate a flag on validation of the values + virtual bool setSelection(QList>& theValues, + const bool theToValidate); + + /// Fill preselection used in mouseReleased + //virtual void setPreSelection(const std::shared_ptr& thePreSelected); + virtual void setPreSelection(const std::shared_ptr& thePreSelected, + ModuleBase_IViewWindow* theWnd, + QMouseEvent* theEvent); +protected: + /// Return the attribute values wrapped in a list of viewer presentations + /// \return a list of viewer presentations, which contains an attribute result and + /// a shape. If the attribute do not uses the shape, it is empty + virtual QList> getAttributeSelection() const; + +protected: + /// The methiod called when widget is activated + virtual void activateCustom(); + +protected: + bool fillFeature(const std::shared_ptr& theSelectedPrs, + ModuleBase_IViewWindow* theWnd, + QMouseEvent* theEvent); + + /// Pointer to a sketch + CompositeFeaturePtr mySketch; + Quantity_Color myHighlightColor; + Quantity_Color mySelectionColor; +}; + +#endif \ No newline at end of file diff --git a/src/PartSet/PartSet_WidgetPoint2d.cpp b/src/PartSet/PartSet_WidgetPoint2d.cpp index e6c1cf1d3..2a7ef76fa 100644 --- a/src/PartSet/PartSet_WidgetPoint2d.cpp +++ b/src/PartSet/PartSet_WidgetPoint2d.cpp @@ -582,9 +582,13 @@ void PartSet_WidgetPoint2D::mouseReleased(ModuleBase_IViewWindow* theWindow, QMo } void PartSet_WidgetPoint2D::setPreSelection( - const std::shared_ptr& thePreSelected) + const std::shared_ptr& thePreSelected, + ModuleBase_IViewWindow* theWnd, + QMouseEvent* theEvent) { myPreSelected = thePreSelected; + mouseReleased(theWnd, theEvent); + myPreSelected = ModuleBase_ViewerPrsPtr(); } void PartSet_WidgetPoint2D::mouseMoved(ModuleBase_IViewWindow* theWindow, QMouseEvent* theEvent) diff --git a/src/PartSet/PartSet_WidgetPoint2d.h b/src/PartSet/PartSet_WidgetPoint2d.h index ab56c058b..3de0dc147 100755 --- a/src/PartSet/PartSet_WidgetPoint2d.h +++ b/src/PartSet/PartSet_WidgetPoint2d.h @@ -111,7 +111,10 @@ Q_OBJECT virtual void mouseReleased(ModuleBase_IViewWindow* theWindow, QMouseEvent* theEvent); /// Fill preselection used in mouseReleased - void setPreSelection(const std::shared_ptr& thePreSelected); + //virtual void setPreSelection(const std::shared_ptr& thePreSelected); + virtual void setPreSelection(const std::shared_ptr& thePreSelected, + ModuleBase_IViewWindow* theWnd, + QMouseEvent* theEvent); signals: /// Signal about selection of an existing vertex from an object @@ -206,7 +209,7 @@ private: ModuleBase_LabelValue* myXSpin; ///< the label for the X coordinate ModuleBase_LabelValue* myYSpin; ///< the label for the Y coordinate - /// value used as selection in mouse release method + /// value used as selection in mouse release method std::shared_ptr myPreSelected; /// it is important during restart operation diff --git a/src/PartSet/PartSet_WidgetSubShapeSelector.cpp b/src/PartSet/PartSet_WidgetSubShapeSelector.cpp index 3db87368e..b0e41e4f1 100755 --- a/src/PartSet/PartSet_WidgetSubShapeSelector.cpp +++ b/src/PartSet/PartSet_WidgetSubShapeSelector.cpp @@ -228,11 +228,11 @@ void PartSet_WidgetSubShapeSelector::fillObjectShapes(const ObjectPtr& theObject std::set > aRefAttributes; // 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(); + std::set anEdgeResults; + ModelAPI_Tools::shapesOfType(aFeature, GeomAPI_Shape::EDGE, anEdgeResults); + if (!anEdgeResults.empty()) { + GeomShapePtr aFeatureShape = (*anEdgeResults.begin())->shape(); // coincidences to the feature ModelGeomAlgo_Point2D::getPointsOfReference(aFeature, SketchPlugin_ConstraintCoincidence::ID(), @@ -248,10 +248,10 @@ void PartSet_WidgetSubShapeSelector::fillObjectShapes(const ObjectPtr& theObject aData->attribute(SketchPlugin_Sketch::NORM_ID())); std::shared_ptr aY(new GeomAPI_Dir(aNorm->dir()->cross(aX->dir()))); std::list > aPoints; - ModelGeomAlgo_Point2D::getPointsInsideShape(aFeatureShape, aRefAttributes, aC->pnt(), + ModelGeomAlgo_Point2D::getPointsInsideShape_p(aFeatureShape, aRefAttributes, aC->pnt(), aX->dir(), aY, aPoints, aPointToAttributes); - GeomAlgoAPI_ShapeTools::splitShape(aFeatureShape, aPoints, aShapes); + GeomAlgoAPI_ShapeTools::splitShape_p(aFeatureShape, aPoints, aShapes); } myCashedShapes[theObject] = aShapes; myCashedReferences[theObject] = aPointToAttributes; diff --git a/src/SketchAPI/SketchAPI_Sketch.cpp b/src/SketchAPI/SketchAPI_Sketch.cpp index bacc3c147..fdc8a71fb 100644 --- a/src/SketchAPI/SketchAPI_Sketch.cpp +++ b/src/SketchAPI/SketchAPI_Sketch.cpp @@ -24,6 +24,7 @@ #include #include #include +#include #include #include #include @@ -481,6 +482,24 @@ std::shared_ptr SketchAPI_Sketch::addSplit( return InterfacePtr(new ModelHighAPI_Interface(aFeature)); } +//-------------------------------------------------------------------------------------- +std::shared_ptr SketchAPI_Sketch::addTrim( + const ModelHighAPI_Reference& theFeature, + const std::shared_ptr& thePositionPoint) +{ + std::shared_ptr aFeature = + compositeFeature()->addFeature(SketchPlugin_Trim::ID()); + fillAttribute(theFeature, aFeature->reference(SketchPlugin_Trim::BASE_OBJECT())); + + AttributePtr anAttribute = aFeature->attribute(SketchPlugin_Trim::ENTITY_POINT()); + if (anAttribute->attributeType() == GeomDataAPI_Point2D::typeId()) { + AttributePoint2DPtr aPointAttr = std::dynamic_pointer_cast(anAttribute); + fillAttribute(thePositionPoint, aPointAttr); + } + + return InterfacePtr(new ModelHighAPI_Interface(aFeature)); +} + //-------------------------------------------------------------------------------------- std::shared_ptr SketchAPI_Sketch::setAngle( const ModelHighAPI_RefAttr & theLine1, diff --git a/src/SketchAPI/SketchAPI_Sketch.h b/src/SketchAPI/SketchAPI_Sketch.h index 500c06a68..216474474 100644 --- a/src/SketchAPI/SketchAPI_Sketch.h +++ b/src/SketchAPI/SketchAPI_Sketch.h @@ -263,6 +263,12 @@ public: const ModelHighAPI_RefAttr& thePoint1, const ModelHighAPI_RefAttr& thePoint2); + /// Add trim + SKETCHAPI_EXPORT + std::shared_ptr addTrim( + const ModelHighAPI_Reference& theFeature, + const std::shared_ptr& thePositionPoint); + /// Set angle SKETCHAPI_EXPORT std::shared_ptr setAngle( diff --git a/src/SketchPlugin/CMakeLists.txt b/src/SketchPlugin/CMakeLists.txt index d7fb311d3..a6c654e09 100644 --- a/src/SketchPlugin/CMakeLists.txt +++ b/src/SketchPlugin/CMakeLists.txt @@ -38,6 +38,7 @@ SET(PROJECT_HEADERS SketchPlugin_Sketch.h SketchPlugin_SketchEntity.h SketchPlugin_Tools.h + SketchPlugin_Trim.h SketchPlugin_Validators.h ) @@ -75,6 +76,7 @@ SET(PROJECT_SOURCES SketchPlugin_Sketch.cpp SketchPlugin_SketchEntity.cpp SketchPlugin_Tools.cpp + SketchPlugin_Trim.cpp SketchPlugin_Validators.cpp ) @@ -150,4 +152,4 @@ ADD_UNIT_TESTS(TestSketchPointLine.py Test1924.py Test1966.py Test1967.py -) + TestTrimCircle.py ) diff --git a/src/SketchPlugin/SketchPlugin_ConstraintSplit.cpp b/src/SketchPlugin/SketchPlugin_ConstraintSplit.cpp index b8a7102d9..08be7f169 100755 --- a/src/SketchPlugin/SketchPlugin_ConstraintSplit.cpp +++ b/src/SketchPlugin/SketchPlugin_ConstraintSplit.cpp @@ -360,7 +360,7 @@ AISObjectPtr SketchPlugin_ConstraintSplit::getAISObject(AISObjectPtr thePrevious std::set > aSplitShapes; - GeomAlgoAPI_ShapeTools::splitShape(aBaseShape, aPoints, aSplitShapes); + GeomAlgoAPI_ShapeTools::splitShape_p(aBaseShape, aPoints, aSplitShapes); std::shared_ptr aShape = GeomAlgoAPI_ShapeTools::findShape(aPoints, aSplitShapes); diff --git a/src/SketchPlugin/SketchPlugin_Plugin.cpp b/src/SketchPlugin/SketchPlugin_Plugin.cpp index 2c6c5772f..e422ef436 100644 --- a/src/SketchPlugin/SketchPlugin_Plugin.cpp +++ b/src/SketchPlugin/SketchPlugin_Plugin.cpp @@ -27,6 +27,7 @@ #include #include #include +#include #include #include @@ -174,6 +175,8 @@ FeaturePtr SketchPlugin_Plugin::createFeature(std::string theFeatureID) return FeaturePtr(new SketchPlugin_MultiRotation); } else if (theFeatureID == SketchPlugin_ConstraintAngle::ID()) { return FeaturePtr(new SketchPlugin_ConstraintAngle); + } else if (theFeatureID == SketchPlugin_Trim::ID()) { + return FeaturePtr(new SketchPlugin_Trim); } // feature of such kind is not found return FeaturePtr(); @@ -236,6 +239,7 @@ std::shared_ptr SketchPlugin_Plugin aMsg->setState(SketchPlugin_ConstraintAngle::ID(), aHasSketchPlane); aMsg->setState(SketchPlugin_MultiRotation::ID(), aHasSketchPlane); aMsg->setState(SketchPlugin_MultiTranslation::ID(), aHasSketchPlane); + aMsg->setState(SketchPlugin_Trim::ID(), aHasSketchPlane); // SketchRectangle is a python feature, so its ID is passed just as a string aMsg->setState("SketchRectangle", aHasSketchPlane); } diff --git a/src/SketchPlugin/SketchPlugin_Trim.cpp b/src/SketchPlugin/SketchPlugin_Trim.cpp new file mode 100644 index 000000000..ac0630cfd --- /dev/null +++ b/src/SketchPlugin/SketchPlugin_Trim.cpp @@ -0,0 +1,1074 @@ +// Copyright (C) 2014-20xx CEA/DEN, EDF R&D --> + +// File: SketchPlugin_Trim.cpp +// Created: 22 Feb 2017 +// Author: Natalia ERMOLAEVA + +#include "SketchPlugin_Trim.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 +#include +#include +#include +#include + +#include +#include +#include +#include + +#include +#include + +#include + +#define DEBUG_TRIM +#ifdef DEBUG_TRIM +#include +#endif + +static const double PI = 3.141592653589793238463; + +static const std::string OPERATION_HIGHLIGHT_COLOR() { return "128, 0, 0"; } + +SketchPlugin_Trim::SketchPlugin_Trim() +{ +} + +void SketchPlugin_Trim::initAttributes() +{ + data()->addAttribute(SketchPlugin_Trim::BASE_OBJECT(), ModelAPI_AttributeReference::typeId()); + data()->addAttribute(ENTITY_POINT(), GeomDataAPI_Point2D::typeId()); +} + +void SketchPlugin_Trim::findShapePoints(std::shared_ptr& aStartPoint, + std::shared_ptr& aLastPoint) +{ + AttributeReferencePtr aBaseObjectAttr = std::dynamic_pointer_cast( + data()->attribute(SketchPlugin_Trim::BASE_OBJECT())); + ObjectPtr aBaseObject = aBaseObjectAttr->value(); + + AttributePoint2DPtr aPoint = std::dynamic_pointer_cast( + data()->attribute(ENTITY_POINT())); + std::shared_ptr anAttributePnt2d = aPoint->pnt(); + std::shared_ptr anAttributePnt = sketch()->to3D(anAttributePnt2d->x(), + anAttributePnt2d->y()); + + if (myCashedShapes.find(aBaseObject) == myCashedShapes.end()) + fillObjectShapes(aBaseObject); + + const std::set& aShapes = myCashedShapes[aBaseObject]; + if (!aShapes.empty()) { + std::set::const_iterator anIt = aShapes.begin(), aLast = aShapes.end(); + for (; anIt != aLast; anIt++) { + GeomShapePtr aBaseShape = *anIt; + std::shared_ptr aProjectedPoint; + if (ModelGeomAlgo_Point2D::isPointOnEdge(aBaseShape, anAttributePnt, aProjectedPoint)) { + + if (aBaseShape->shapeType() == GeomAPI_Shape::EDGE) { + std::shared_ptr anEdge(new GeomAPI_Edge(aBaseShape)); + aStartPoint = anEdge->lastPoint(); + aLastPoint = anEdge->firstPoint(); + } + } + } + } +#ifdef DEBUG_TRIM + std::cout << " => " + << "Start Point: [" + << aStartPoint->x() << ", " << aStartPoint->y() << ", " << aStartPoint->z() << "]" + << "Last Point: [" + << aLastPoint->x() << ", " << aLastPoint->y() << ", " << aLastPoint->z() << "]" + << std::endl; +#endif +} + +std::shared_ptr SketchPlugin_Trim::convertPoint( + const std::shared_ptr& thePoint) +{ + std::shared_ptr aPoint; + + AttributeReferencePtr aBaseObjectAttr = std::dynamic_pointer_cast( + data()->attribute(SketchPlugin_Trim::BASE_OBJECT())); + ObjectPtr aBaseObject = aBaseObjectAttr->value(); + if (myObjectToPoints.find(aBaseObject) == myObjectToPoints.end()) + return aPoint; + + bool aFound = false; + const PointToRefsMap& aRefsMap = myObjectToPoints.at(aBaseObject); + for (PointToRefsMap::const_iterator aPointIt = aRefsMap.begin(); + aPointIt != aRefsMap.end() && !aFound; aPointIt++) { + if (aPointIt->first->isEqual(thePoint)) { + const std::pair, + std::list >& anInfo = aPointIt->second; + const std::list& anAttributes = anInfo.first; + if (!anAttributes.empty()) { + aPoint = anAttributes.front()->pnt(); + aFound = true; + } + else { + std::shared_ptr aPlane = sketch()->plane(); + aPoint = thePoint->to2D(aPlane); + aFound = true; + } + } + } + if (!aFound) { + // returns an end of the shape to define direction of split if feature's attribute participates + std::shared_ptr aPlane = sketch()->plane(); + aPoint = thePoint->to2D(aPlane); + } + return aPoint; +} + +void SketchPlugin_Trim::execute() +{ +#ifdef DEBUG_TRIM + std::cout << "SketchPlugin_Trim::execute" << std::endl; +#endif + + SketchPlugin_Sketch* aSketch = sketch(); + if (!aSketch) + return; + + // Check the base objects are initialized. + AttributeReferencePtr aBaseObjectAttr = std::dynamic_pointer_cast( + data()->attribute(SketchPlugin_Trim::BASE_OBJECT())); + if(!aBaseObjectAttr->isInitialized()) { + setError("Error: Base object is not initialized."); + return; + } + ObjectPtr aBaseObject = aBaseObjectAttr->value(); + if (!aBaseObject.get()) + return; + FeaturePtr aBaseFeature = ModelAPI_Feature::feature(aBaseObjectAttr->value()); + + /// points of trim + std::shared_ptr aStartShapePoint, aLastShapePoint; + findShapePoints(aStartShapePoint, aLastShapePoint); + std::shared_ptr aStartShapePoint2d = convertPoint(aStartShapePoint); + + std::shared_ptr aLastShapePoint2d = convertPoint(aLastShapePoint); + + std::set aFeaturesToDelete, aFeaturesToUpdate; + getConstraints(aFeaturesToDelete, aFeaturesToUpdate); + + std::map > aBaseRefAttributes; + std::list aRefsToFeature; + getRefAttributes(aBaseFeature, aBaseRefAttributes, aRefsToFeature); + + std::set aFurtherCoincidences; + std::set aCreatedFeatures; + std::set> aModifiedAttributes; + const std::string& aKind = aBaseFeature->getKind(); + if (aKind == SketchPlugin_Circle::ID()) { + trimCircle(aStartShapePoint2d, aLastShapePoint2d, + aFurtherCoincidences, aCreatedFeatures, aModifiedAttributes); + updateRefFeatureConstraints(getFeatureResult(aBaseFeature), aRefsToFeature); + + aFeaturesToDelete.insert(aBaseFeature); + // as circle is removed, temporary fill this attribute + aBaseObjectAttr->setObject(ResultPtr()); + } + else if (aKind == SketchPlugin_Line::ID()) { + trimLine(aStartShapePoint2d, aLastShapePoint2d, + aFurtherCoincidences, aCreatedFeatures, aModifiedAttributes); + } + else if (aKind == SketchPlugin_Arc::ID()) { + trimArc(aStartShapePoint2d, aLastShapePoint2d, + aFurtherCoincidences, aCreatedFeatures, aModifiedAttributes); + } + + // coincidence to result points + const PointToRefsMap& aRefsMap = myObjectToPoints.at(aBaseObject); + std::set::const_iterator anIt = aFurtherCoincidences.begin(), + aLast = aFurtherCoincidences.end(); + for (; anIt != aLast; anIt++) { + AttributePoint2DPtr aPointAttribute = (*anIt); + std::shared_ptr aPoint2d = aPointAttribute->pnt(); + + std::shared_ptr aPoint; + if (aStartShapePoint2d.get() && aPoint2d->isEqual(aStartShapePoint2d)) + aPoint = aStartShapePoint; + else if (aLastShapePoint2d.get() && aPoint2d->isEqual(aLastShapePoint2d)) + aPoint = aLastShapePoint; + + if (!aPoint.get()) + continue; + + std::pair, std::list > anInfo; + for (PointToRefsMap::const_iterator aRefIt = aRefsMap.begin(); aRefIt != aRefsMap.end(); + aRefIt++) + { + if (aRefIt->first->isEqual(aPoint)) { + anInfo = aRefIt->second; + break; + } + } + const std::list& anAttributes = anInfo.first; + for (std::list::const_iterator anAttrIt = anAttributes.begin(); + anAttrIt != anAttributes.end(); anAttrIt++) { + createConstraint(SketchPlugin_ConstraintCoincidence::ID(), aPointAttribute, *anAttrIt); + } + + const std::list& anObjects = anInfo.second; + for (std::list::const_iterator anObjectIt = anObjects.begin(); + anObjectIt != anObjects.end(); anObjectIt++) { + createConstraint(SketchPlugin_ConstraintCoincidence::ID(), aPointAttribute, *anObjectIt); + } + } + + // 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); + + updateRefAttConstraints(aBaseRefAttributes, aModifiedAttributes, aFeaturesToDelete); + + // delete constraints +#ifdef DEBUG_TRIM + std::cout << "remove features and references:" << std::endl; + std::set::const_iterator aDIt = aFeaturesToDelete.begin(), + aDLast = aFeaturesToDelete.end(); + for (; aDIt != aDLast; aDIt++) { + //std::cout << getFeatureInfo(*aDIt, false) << std::endl; + //std::cout << std::endl; + } +#endif + ModelAPI_Tools::removeFeaturesAndReferences(aFeaturesToDelete); + Events_Loop::loop()->flush(Events_Loop::eventByName(EVENT_OBJECT_DELETED)); + + // Send events to update the sub-features by the solver. + if(isUpdateFlushed) { + Events_Loop::loop()->setFlushed(anUpdateEvent, true); + } + +#ifdef DEBUG_TRIM + std::cout << "SketchPlugin_Trim::done" << std::endl; +#endif +} + +bool SketchPlugin_Trim::isMacro() const +{ + return true; +} + +AISObjectPtr SketchPlugin_Trim::getAISObject(AISObjectPtr thePrevious) +{ + AISObjectPtr anAIS = thePrevious; + // feature for trim + AttributeReferencePtr aBaseObjectAttr = std::dynamic_pointer_cast( + data()->attribute(SketchPlugin_Trim::BASE_OBJECT())); + ObjectPtr aBaseObject = aBaseObjectAttr->value(); + if (!aBaseObject.get()) + return anAIS; + FeaturePtr aBaseFeature = ModelAPI_Feature::feature(aBaseObjectAttr->value()); + + // point on feature + AttributePoint2DPtr aPoint = std::dynamic_pointer_cast( + data()->attribute(ENTITY_POINT())); + std::shared_ptr anAttributePnt2d = aPoint->pnt(); + std::shared_ptr anAttributePnt = sketch()->to3D(anAttributePnt2d->x(), anAttributePnt2d->y()); + + if (myCashedShapes.find(aBaseObject) == myCashedShapes.end()) + fillObjectShapes(aBaseObject); + + const std::set& aShapes = myCashedShapes[aBaseObject]; + if (!aShapes.empty()) { + std::set::const_iterator anIt = aShapes.begin(), aLast = aShapes.end(); + for (; anIt != aLast; anIt++) { + GeomShapePtr aBaseShape = *anIt; + std::shared_ptr aProjectedPoint; + if (ModelGeomAlgo_Point2D::isPointOnEdge(aBaseShape, anAttributePnt, aProjectedPoint)) { + if (aBaseShape) { + if (!anAIS) + anAIS = AISObjectPtr(new GeomAPI_AISObject); + anAIS->createShape(aBaseShape); + + std::shared_ptr anAuxiliaryAttr = + aBaseFeature->data()->boolean(SketchPlugin_SketchEntity::AUXILIARY_ID()); + + bool isConstruction = anAuxiliaryAttr.get() != NULL && anAuxiliaryAttr->value(); + + std::vector aColor; + aColor = Config_PropManager::color("Visualization", "operation_highlight_color", + OPERATION_HIGHLIGHT_COLOR()); + double aWidth = SketchPlugin_SketchEntity::SKETCH_LINE_WIDTH(); + int aLineStyle = SketchPlugin_SketchEntity::SKETCH_LINE_STYLE(); + if (isConstruction) { + aWidth = SketchPlugin_SketchEntity::SKETCH_LINE_WIDTH_AUXILIARY(); + aLineStyle = SketchPlugin_SketchEntity::SKETCH_LINE_STYLE_AUXILIARY(); + } + anAIS->setColor(aColor[0], aColor[1], aColor[2]); + // modification of width should be replaced to value 1 after highlight problem is fixed + anAIS->setWidth(aWidth + 2);//1); + anAIS->setLineStyle(aLineStyle); + break; + } + } + } + } + + return anAIS; +} + +void SketchPlugin_Trim::getFeaturePoints(const FeaturePtr& theFeature, + AttributePoint2DPtr& theStartPointAttr, + AttributePoint2DPtr& theEndPointAttr) +{ + std::string aFeatureKind = theFeature->getKind(); + std::string aStartAttributeName, anEndAttributeName; + if (aFeatureKind == SketchPlugin_Line::ID()) { + aStartAttributeName = SketchPlugin_Line::START_ID(); + anEndAttributeName = SketchPlugin_Line::END_ID(); + } + else if (aFeatureKind == SketchPlugin_Arc::ID()) { + aStartAttributeName = SketchPlugin_Arc::START_ID(); + anEndAttributeName = SketchPlugin_Arc::END_ID(); + } + if (!aStartAttributeName.empty() && !anEndAttributeName.empty()) { + theStartPointAttr = std::dynamic_pointer_cast( + theFeature->attribute(aStartAttributeName)); + theEndPointAttr = std::dynamic_pointer_cast( + theFeature->attribute(anEndAttributeName)); + } +} + +void SketchPlugin_Trim::getConstraints(std::set& theFeaturesToDelete, + std::set& theFeaturesToUpdate) +{ + std::shared_ptr aData = data(); + + // Check the base objects are initialized. + AttributeReferencePtr aBaseObjectAttr = std::dynamic_pointer_cast( + aData->attribute(SketchPlugin_Trim::BASE_OBJECT())); + FeaturePtr aBaseFeature = ModelAPI_Feature::feature(aBaseObjectAttr->value()); + ResultPtr aBaseFeatureResult = getFeatureResult(aBaseFeature); + + std::set aRefsList = aBaseFeatureResult->data()->refsToMe(); + std::set aFRefsList = aBaseFeature->data()->refsToMe(); + aRefsList.insert(aFRefsList.begin(), aFRefsList.end()); + + 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()); + std::string aRefFeatureKind = aRefFeature->getKind(); + if (aRefFeatureKind == SketchPlugin_ConstraintMirror::ID() || + aRefFeatureKind == SketchPlugin_MultiRotation::ID() || + aRefFeatureKind == SketchPlugin_MultiTranslation::ID() || + aRefFeatureKind == SketchPlugin_ConstraintMiddle::ID()) + theFeaturesToDelete.insert(aRefFeature); + else if (aRefFeatureKind == SketchPlugin_ConstraintLength::ID()) + theFeaturesToUpdate.insert(aRefFeature); + else if (aRefFeatureKind == SketchPlugin_ConstraintTangent::ID()) { + if (aBaseFeature->getKind() == SketchPlugin_Circle::ID()) /// TEMPORARY limitaion + /// until tangency between arc and line is implemented + theFeaturesToDelete.insert(aRefFeature); + else { + std::string anAttributeToBeModified; + AttributePoint2DPtr aTangentPoint; + ObjectPtr aResult1 = aRefFeature->refattr(SketchPlugin_Constraint::ENTITY_A())->object(); + ObjectPtr aResult2 = aRefFeature->refattr(SketchPlugin_Constraint::ENTITY_B())->object(); + if (aResult1.get() && aResult2.get()) { + FeaturePtr aCoincidenceFeature = + SketchPlugin_ConstraintCoincidence::findCoincidenceFeature + (ModelAPI_Feature::feature(aResult1), + ModelAPI_Feature::feature(aResult2)); + // get the point not lying on the splitting feature + for (int i = 0; i < CONSTRAINT_ATTR_SIZE; ++i) { + AttributeRefAttrPtr aRefAttr = aCoincidenceFeature->refattr(SketchPlugin_Trim::BASE_OBJECT()); + if (!aRefAttr || aRefAttr->isObject()) + continue; + AttributePoint2DPtr aPoint = + std::dynamic_pointer_cast(aRefAttr->attr()); + if (!aPoint) + continue; + if (aPoint->owner() != aBaseFeature) { + aTangentPoint = aPoint; + break; + } + } + } + if (aTangentPoint.get()) { + //FeaturePtr aFeature1 = ModelAPI_Feature::feature(aResult1); + //std::string anAttributeToBeModified = aFeature1 == aBaseFeature + // ? SketchPlugin_Constraint::ENTITY_A() : SketchPlugin_Constraint::ENTITY_B(); + //theTangentFeatures[aRefFeature] = std::make_pair(anAttributeToBeModified, aTangentPoint); + } + else /// there is not coincident point between tangent constraint + theFeaturesToDelete.insert(aRefFeature); + } + } + } +} + +void SketchPlugin_Trim::getRefAttributes(const FeaturePtr& theFeature, + std::map >& theRefs, + std::list& theRefsToFeature) +{ + theRefs.clear(); + + std::list aPointAttributes = + theFeature->data()->attributes(GeomDataAPI_Point2D::typeId()); + std::set aPointAttributesSet; + + std::list::const_iterator aPIt = + aPointAttributes.begin(), aPLast = aPointAttributes.end(); + for (; aPIt != aPLast; aPIt++) + aPointAttributesSet.insert(*aPIt); + + std::set aRefsAttributes = getFeatureResult(theFeature)->data()->refsToMe(); + std::set aFRefsList = theFeature->data()->refsToMe(); + aRefsAttributes.insert(aFRefsList.begin(), aFRefsList.end()); + + std::set::const_iterator aIt; + for (aIt = aRefsAttributes.cbegin(); aIt != aRefsAttributes.cend(); ++aIt) { + AttributePtr anAttr = (*aIt); + FeaturePtr anAttrFeature = ModelAPI_Feature::feature(anAttr->owner()); + if (anAttrFeature.get() != this && + anAttr.get() && anAttr->attributeType() == ModelAPI_AttributeRefAttr::typeId()) { + AttributeRefAttrPtr aRefAttr = std::dynamic_pointer_cast(anAttr); + if (!aRefAttr->isObject()) { /// find attributes referenced to feature point attributes + AttributePtr anAttrInRef = aRefAttr->attr(); + if (anAttrInRef.get() && + aPointAttributesSet.find(anAttrInRef) != aPointAttributesSet.end()) { + if (theRefs.find(anAttrInRef) != theRefs.end()) + theRefs[anAttrInRef].push_back(aRefAttr); + else { + std::list anAttrList; + anAttrList.push_back(aRefAttr); + theRefs[anAttrInRef] = anAttrList; + } + } + } + else { /// find attributes referenced to feature itself + theRefsToFeature.push_back(anAttr); + } + } + } +} + +void SketchPlugin_Trim::updateRefFeatureConstraints( + const ResultPtr& theFeatureBaseResult, + const std::list& theRefsToFeature) +{ + std::list::const_iterator anIt = theRefsToFeature.begin(), + aLast = theRefsToFeature.end(); + for (; anIt != aLast; anIt++) { + AttributeRefAttrPtr aRefAttr = std::dynamic_pointer_cast(*anIt); + if (aRefAttr.get()) + aRefAttr->setObject(theFeatureBaseResult); + } +} + +void SketchPlugin_Trim::updateRefAttConstraints( + const std::map >& theBaseRefAttributes, + const std::set >& theModifiedAttributes, + std::set& theFeaturesToDelete) +{ +#ifdef DEBUG_TRIM + std::cout << "SketchPlugin_Trim::updateRefAttConstraints" << std::endl; +#endif + + std::set >::const_iterator + anIt = theModifiedAttributes.begin(), aLast = theModifiedAttributes.end(); + for (; anIt != aLast; anIt++) { + AttributePtr anAttribute = anIt->first; + + /// not found in references + if (theBaseRefAttributes.find(anAttribute) == theBaseRefAttributes.end()) + continue; + std::list aRefAttributes = theBaseRefAttributes.at(anAttribute); + std::list::const_iterator aRefIt = aRefAttributes.begin(), + aRLast = aRefAttributes.end(); + + AttributePtr aNewAttribute = anIt->second; + for (; aRefIt != aRLast; aRefIt++) { + AttributeRefAttrPtr aRefAttr = std::dynamic_pointer_cast(*aRefIt); + if (aRefAttr.get()) { + if (aNewAttribute.get()) + aRefAttr->setAttr(aNewAttribute); + else + theFeaturesToDelete.insert(ModelAPI_Feature::feature(aRefAttr->owner())); +#ifdef DEBUG_TRIM + //FeaturePtr aFeature = ModelAPI_Feature::feature(aRefAttr->owner()); + //std::cout << " -" << getFeatureInfo(aFeature) << std::endl; +#endif + } + } + } +} + +void SketchPlugin_Trim::trimLine(const std::shared_ptr& theStartShapePoint, + const std::shared_ptr& theLastShapePoint, + std::set& thePoints, + std::set& theCreatedFeatures, + std::set>& theModifiedAttributes) +{ + // Check the base objects are initialized. + AttributeReferencePtr aBaseObjectAttr = std::dynamic_pointer_cast( + data()->attribute(SketchPlugin_Trim::BASE_OBJECT())); + ObjectPtr aBaseObject = aBaseObjectAttr->value(); + FeaturePtr aBaseFeature = ModelAPI_Feature::feature(aBaseObjectAttr->value()); + + /// points of trim + AttributePoint2DPtr aStartPointAttrOfBase, anEndPointAttrOfBase; + getFeaturePoints(aBaseFeature, aStartPointAttrOfBase, anEndPointAttrOfBase); + + std::shared_ptr aStartFeaturePoint = aStartPointAttrOfBase->pnt(); + std::shared_ptr aLastFeaturePoint = anEndPointAttrOfBase->pnt(); + + std::shared_ptr aStartShapePoint = theStartShapePoint; + std::shared_ptr aLastShapePoint = theLastShapePoint; + arrangePointsOnLine(aStartPointAttrOfBase, anEndPointAttrOfBase, + aStartShapePoint, aLastShapePoint); +#ifdef DEBUG_TRIM + std::cout << "Arranged points (to build split between 1st and 2nd points:" << std::endl; + if (aStartShapePoint.get()) + std::cout << "Start point: [" << aStartShapePoint->x() << ", " << + aStartShapePoint->y() << "]" << std::endl; + std::cout << "1st point: [" << aStartFeaturePoint->x() << ", " << + aStartFeaturePoint->y() << "]" << std::endl; + if (aLastShapePoint.get()) + std::cout << "2st point: [" << aLastShapePoint->x() << ", " << + aLastShapePoint->y() << "]" << std::endl; + std::cout << "End point: [" << aLastFeaturePoint->x() << ", " << + aLastFeaturePoint->y() << "]" << std::endl; +#endif + + bool isStartPoint = !aStartShapePoint.get() || aStartFeaturePoint->isEqual(aStartShapePoint); + bool isLastPoint = !aLastShapePoint.get() || aLastFeaturePoint->isEqual(aLastShapePoint); + if (isStartPoint || isLastPoint) { + // result is one line: changed existing line + std::string aModifiedAttribute = isStartPoint ? SketchPlugin_Line::START_ID() + : SketchPlugin_Line::END_ID(); + std::shared_ptr aPoint; + if (aStartShapePoint.get() && aLastShapePoint.get()) + aPoint = isStartPoint ? aLastShapePoint : aStartShapePoint; + else + aPoint = aStartShapePoint.get() ? aStartShapePoint : aLastShapePoint; + + fillPointAttribute(aBaseFeature->attribute(aModifiedAttribute), aPoint); + theModifiedAttributes.insert( + std::make_pair(aBaseFeature->attribute(aModifiedAttribute), AttributePtr())); + + thePoints.insert(std::dynamic_pointer_cast + (aBaseFeature->attribute(aModifiedAttribute))); + } + else { + // result is two lines: start line point - start shape point, last shape point - last line point + // create second line + FeaturePtr anNewFeature = createLineFeature(aBaseFeature, aLastShapePoint, aLastFeaturePoint); + thePoints.insert(std::dynamic_pointer_cast + (anNewFeature->attribute(SketchPlugin_Line::START_ID()))); + + std::string aModifiedAttribute = SketchPlugin_Line::END_ID(); + theModifiedAttributes.insert( + std::make_pair(aBaseFeature->attribute(aModifiedAttribute), + anNewFeature->attribute(SketchPlugin_Line::END_ID()))); + + // modify base arc + fillPointAttribute(aBaseFeature->attribute(aModifiedAttribute), aStartShapePoint); + + thePoints.insert(std::dynamic_pointer_cast + (aBaseFeature->attribute(aModifiedAttribute))); + + // Collinear constraint for lines + createConstraintForObjects(SketchPlugin_ConstraintCollinear::ID(), + getFeatureResult(aBaseFeature), + getFeatureResult(anNewFeature)); + + } +} + +void SketchPlugin_Trim::trimArc(const std::shared_ptr& theStartShapePoint, + const std::shared_ptr& theLastShapePoint, + std::set& thePoints, + std::set& theCreatedFeatures, + std::set>& theModifiedAttributes) +{ + // Check the base objects are initialized. + AttributeReferencePtr aBaseObjectAttr = std::dynamic_pointer_cast( + data()->attribute(SketchPlugin_Trim::BASE_OBJECT())); + ObjectPtr aBaseObject = aBaseObjectAttr->value(); + FeaturePtr aBaseFeature = ModelAPI_Feature::feature(aBaseObjectAttr->value()); + + /// points of trim + AttributePoint2DPtr aStartPointAttrOfBase, anEndPointAttrOfBase; + getFeaturePoints(aBaseFeature, aStartPointAttrOfBase, anEndPointAttrOfBase); + + std::shared_ptr aStartArcPoint = aStartPointAttrOfBase->pnt(); + std::shared_ptr aLastArcPoint = anEndPointAttrOfBase->pnt(); + + std::shared_ptr aStartShapePoint = theStartShapePoint; + std::shared_ptr aLastShapePoint = theLastShapePoint; + arrangePointsOnArc(aBaseFeature, aStartPointAttrOfBase, anEndPointAttrOfBase, + aStartShapePoint, aLastShapePoint); +#ifdef DEBUG_TRIM + std::cout << "Arranged points (to build split between 1st and 2nd points:" << std::endl; + if (aStartShapePoint.get()) + std::cout << "Start point: [" << aStartShapePoint->x() << ", " << + aStartShapePoint->y() << "]" << std::endl; + std::cout << "1st point: [" << aStartArcPoint->x() << ", " << + aStartArcPoint->y() << "]" << std::endl; + if (aLastShapePoint.get()) + std::cout << "2st point: [" << aLastShapePoint->x() << ", " << + aLastShapePoint->y() << "]" << std::endl; + std::cout << "End point: [" << aLastArcPoint->x() << ", " << + aLastArcPoint->y() << "]" << std::endl; +#endif + + bool isStartPoint = !aStartShapePoint.get() || aStartArcPoint->isEqual(aStartShapePoint); + bool isLastPoint = !aLastShapePoint.get() || aLastArcPoint->isEqual(aLastShapePoint); + if (isStartPoint || isLastPoint) { + // result is one arc: changed existing arc + std::string aModifiedAttribute = isStartPoint ? SketchPlugin_Arc::START_ID() + : SketchPlugin_Arc::END_ID(); + std::shared_ptr aPoint; + if (aStartShapePoint.get() && aLastShapePoint.get()) + aPoint = isStartPoint ? aLastShapePoint : aStartShapePoint; + else + aPoint = aStartShapePoint.get() ? aStartShapePoint : aLastShapePoint; + + fillPointAttribute(aBaseFeature->attribute(aModifiedAttribute), aPoint); + theModifiedAttributes.insert( + std::make_pair(aBaseFeature->attribute(aModifiedAttribute), AttributePtr())); + + thePoints.insert(std::dynamic_pointer_cast + (aBaseFeature->attribute(aModifiedAttribute))); + } + else { + // result is two arcs: start arc point - start shape point, last shape point - last arc point + // create second arc + FeaturePtr anArcFeature = createArcFeature(aBaseFeature, aLastShapePoint, aLastArcPoint); + thePoints.insert(std::dynamic_pointer_cast + (anArcFeature->attribute(SketchPlugin_Arc::START_ID()))); + + std::string aModifiedAttribute = SketchPlugin_Arc::END_ID(); + theModifiedAttributes.insert( + std::make_pair(aBaseFeature->attribute(aModifiedAttribute), + anArcFeature->attribute(SketchPlugin_Arc::END_ID()))); + + // modify base arc + fillPointAttribute(aBaseFeature->attribute(aModifiedAttribute), aStartShapePoint); + + thePoints.insert(std::dynamic_pointer_cast + (aBaseFeature->attribute(aModifiedAttribute))); + + // equal Radius constraint for arcs + createConstraintForObjects(SketchPlugin_ConstraintEqual::ID(), + getFeatureResult(aBaseFeature), + getFeatureResult(anArcFeature)); + // coincident centers constraint + createConstraint(SketchPlugin_ConstraintCoincidence::ID(), + aBaseFeature->attribute(SketchPlugin_Arc::CENTER_ID()), + anArcFeature->attribute(SketchPlugin_Arc::CENTER_ID())); + } +} + +void SketchPlugin_Trim::trimCircle(const std::shared_ptr& theStartShapePoint, + const std::shared_ptr& theLastShapePoint, + std::set& thePoints, + std::set& theCreatedFeatures, + std::set>& theModifiedAttributes) +{ + // Check the base objects are initialized. + AttributeReferencePtr aBaseObjectAttr = std::dynamic_pointer_cast( + data()->attribute(SketchPlugin_Trim::BASE_OBJECT())); + ObjectPtr aBaseObject = aBaseObjectAttr->value(); + FeaturePtr aBaseFeature = ModelAPI_Feature::feature(aBaseObjectAttr->value()); + + /// points of trim + AttributePoint2DPtr aStartPointAttrOfBase, anEndPointAttrOfBase; + getFeaturePoints(aBaseFeature, aStartPointAttrOfBase, anEndPointAttrOfBase); + + /// trim feature + FeaturePtr anArcFeature = createArcFeature(aBaseFeature, theStartShapePoint, theLastShapePoint); + + theModifiedAttributes.insert( + std::make_pair(aBaseFeature->attribute(SketchPlugin_Circle::CENTER_ID()), + anArcFeature->attribute(SketchPlugin_Arc::CENTER_ID()))); + + thePoints.insert(std::dynamic_pointer_cast + (anArcFeature->attribute(SketchPlugin_Arc::START_ID()))); + thePoints.insert(std::dynamic_pointer_cast + (anArcFeature->attribute(SketchPlugin_Arc::END_ID()))); +} + +void SketchPlugin_Trim::arrangePointsOnLine(const AttributePoint2DPtr& theStartPointAttr, + const AttributePoint2DPtr& theEndPointAttr, + std::shared_ptr& theFirstPoint, + std::shared_ptr& theLastPoint) const +{ + if (!theFirstPoint.get() || !theLastPoint.get()) + return; + + // if first point is closer to last point, swap first and last values + if (theStartPointAttr->pnt()->distance(theFirstPoint) > + theStartPointAttr->pnt()->distance(theLastPoint)) { + std::shared_ptr aTmpPoint = theFirstPoint; + theFirstPoint = theLastPoint; + theLastPoint = aTmpPoint; + } +} + +void SketchPlugin_Trim::arrangePointsOnArc(const FeaturePtr& theArc, + const AttributePoint2DPtr& theStartPointAttr, + const AttributePoint2DPtr& theEndPointAttr, + std::shared_ptr& theFirstPoint, + std::shared_ptr& theSecondPoint) const +{ + if (!theFirstPoint.get() || !theSecondPoint.get()) + return; + + static const double anAngleTol = 1.e-12; + + std::shared_ptr aCenter = std::dynamic_pointer_cast( + theArc->attribute(SketchPlugin_Arc::CENTER_ID()))->pnt(); + bool isReversed = theArc->boolean(SketchPlugin_Arc::INVERSED_ID())->value(); + + // collect directions to each point + std::shared_ptr aStartDir( + new GeomAPI_Dir2d(theStartPointAttr->pnt()->xy()->decreased(aCenter->xy()))); + std::shared_ptr aFirstPtDir( + new GeomAPI_Dir2d(theFirstPoint->xy()->decreased(aCenter->xy()))); + std::shared_ptr aSecondPtDir( + new GeomAPI_Dir2d(theSecondPoint->xy()->decreased(aCenter->xy()))); + + // sort points by their angular values + double aFirstPtAngle = aStartDir->angle(aFirstPtDir); + double aSecondPtAngle = aStartDir->angle(aSecondPtDir); + double aPeriod = isReversed ? -2.0 * PI : 2.0 * PI; + if (fabs(aFirstPtAngle) > anAngleTol && isReversed == (aFirstPtAngle > 0.)) + aFirstPtAngle += aPeriod; + if (fabs(aSecondPtAngle) > anAngleTol && isReversed == (aSecondPtAngle > 0.)) + aSecondPtAngle += aPeriod; + + if (fabs(aFirstPtAngle) > fabs(aSecondPtAngle)) { + std::shared_ptr aTmpPoint = theFirstPoint; + theFirstPoint = theSecondPoint; + theSecondPoint = aTmpPoint; + } +} + +void SketchPlugin_Trim::fillPointAttribute(const AttributePtr& theModifiedAttribute, + const std::shared_ptr& thePoint) +{ + std::string anAttributeType = theModifiedAttribute->attributeType(); + if (anAttributeType == GeomDataAPI_Point2D::typeId()) { + AttributePoint2DPtr aModifiedAttribute = std::dynamic_pointer_cast( + theModifiedAttribute); + aModifiedAttribute->setValue(thePoint); + +#ifdef DEBUG_TRIM + std::cout << " => Pnt2d - [" << thePoint->x() << ", " << thePoint->y() << "]" << std::endl; +#endif + } +} + + +void SketchPlugin_Trim::fillAttribute(const AttributePtr& theModifiedAttribute, + const AttributePtr& theSourceAttribute) +{ + std::string anAttributeType = theModifiedAttribute->attributeType(); + if (anAttributeType == GeomDataAPI_Point2D::typeId()) { + AttributePoint2DPtr aModifiedAttribute = std::dynamic_pointer_cast( + theModifiedAttribute); + AttributePoint2DPtr aSourceAttribute = std::dynamic_pointer_cast( + theSourceAttribute); + + if (aModifiedAttribute.get() && aSourceAttribute.get()) + aModifiedAttribute->setValue(aSourceAttribute->pnt()); + } + else if (anAttributeType == ModelAPI_AttributeBoolean::typeId()) { + AttributeBooleanPtr aModifiedAttribute = std::dynamic_pointer_cast( + theModifiedAttribute); + AttributeBooleanPtr aSourceAttribute = std::dynamic_pointer_cast( + theSourceAttribute); + + if (aModifiedAttribute.get() && aSourceAttribute.get()) + aModifiedAttribute->setValue(aSourceAttribute->value()); + } + else if (anAttributeType == ModelAPI_AttributeRefAttr::typeId()) { + AttributeRefAttrPtr aRefAttributeToFill = std::dynamic_pointer_cast( + theModifiedAttribute); + AttributeRefAttrPtr aSourceRefAttr = std::dynamic_pointer_cast( + theSourceAttribute); + if (!aSourceRefAttr.get()) + aRefAttributeToFill->setAttr(theSourceAttribute); + else { + if (aSourceRefAttr->isObject()) + aRefAttributeToFill->setObject(aSourceRefAttr->object()); + else + aRefAttributeToFill->setAttr(aSourceRefAttr->attr()); + } + } +} + +FeaturePtr SketchPlugin_Trim::createLineFeature(const FeaturePtr& theBaseFeature, + const std::shared_ptr& theFirstPoint, + const std::shared_ptr& theSecondPoint) +{ + FeaturePtr aFeature; + SketchPlugin_Sketch* aSketch = sketch(); + if (!aSketch || !theBaseFeature.get()) + return aFeature; + + aFeature = aSketch->addFeature(SketchPlugin_Line::ID()); + + fillPointAttribute(aFeature->attribute(SketchPlugin_Line::START_ID()), theFirstPoint); + fillPointAttribute(aFeature->attribute(SketchPlugin_Line::END_ID()), theSecondPoint); + + fillAttribute(aFeature->attribute(SketchPlugin_SketchEntity::AUXILIARY_ID()), + theBaseFeature->attribute(SketchPlugin_SketchEntity::AUXILIARY_ID())); + + aFeature->execute(); // to obtain result + + return aFeature; +} + + +FeaturePtr SketchPlugin_Trim::createArcFeature(const FeaturePtr& theBaseFeature, + const std::shared_ptr& theFirstPoint, + const std::shared_ptr& theSecondPoint) +{ + FeaturePtr aFeature; + SketchPlugin_Sketch* aSketch = sketch(); + if (!aSketch || !theBaseFeature.get()) + return aFeature; + + std::string aCenterAttributeId; + if (theBaseFeature->getKind() == SketchPlugin_Arc::ID()) + aCenterAttributeId = SketchPlugin_Arc::CENTER_ID(); + else if (theBaseFeature->getKind() == SketchPlugin_Circle::ID()) + aCenterAttributeId = SketchPlugin_Circle::CENTER_ID(); + + if (aCenterAttributeId.empty()) + return aFeature; + + aFeature = aSketch->addFeature(SketchPlugin_Arc::ID()); + // 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 + bool aWasBlocked = aFeature->data()->blockSendAttributeUpdated(true); + + aFeature->string(SketchPlugin_Arc::ARC_TYPE())->setValue( + SketchPlugin_Arc::ARC_TYPE_CENTER_START_END()); + + fillAttribute(aFeature->attribute(SketchPlugin_Arc::CENTER_ID()), + theBaseFeature->attribute(aCenterAttributeId)); + fillPointAttribute(aFeature->attribute(SketchPlugin_Arc::START_ID()), theFirstPoint); + fillPointAttribute(aFeature->attribute(SketchPlugin_Arc::END_ID()), theSecondPoint); + + fillAttribute(aFeature->attribute(SketchPlugin_SketchEntity::AUXILIARY_ID()), + theBaseFeature->attribute(SketchPlugin_SketchEntity::AUXILIARY_ID())); + + /// fill referersed state of created arc as it is on the base arc + if (theBaseFeature->getKind() == SketchPlugin_Arc::ID()) { + bool aReversed = theBaseFeature->boolean(SketchPlugin_Arc::INVERSED_ID())->value(); + aFeature->boolean(SketchPlugin_Arc::INVERSED_ID())->setValue(aReversed); + } + aFeature->execute(); // to obtain result + aFeature->data()->blockSendAttributeUpdated(aWasBlocked); + + return aFeature; +} + +FeaturePtr SketchPlugin_Trim::createConstraint(const std::string& theConstraintId, + const AttributePtr& theFirstAttribute, + const AttributePtr& theSecondAttribute) +{ + FeaturePtr aConstraint = sketch()->addFeature(theConstraintId); + AttributeRefAttrPtr aRefAttr = std::dynamic_pointer_cast( + aConstraint->attribute(SketchPlugin_Constraint::ENTITY_A())); + aRefAttr->setAttr(theFirstAttribute); + + aRefAttr = std::dynamic_pointer_cast( + aConstraint->attribute(SketchPlugin_Constraint::ENTITY_B())); + aRefAttr->setAttr(theSecondAttribute); + +#ifdef DEBUG_TRIM + std::cout << " :" + << "first attribute - " << theFirstAttribute->id() + << "second attribute - " << theSecondAttribute->id() + << std::endl; +#endif + + return aConstraint; +} + +FeaturePtr SketchPlugin_Trim::createConstraint(const std::string& theConstraintId, + const AttributePtr& theFirstAttribute, + const ObjectPtr& theSecondObject) +{ + FeaturePtr aConstraint = sketch()->addFeature(theConstraintId); + AttributeRefAttrPtr aRefAttr = std::dynamic_pointer_cast( + aConstraint->attribute(SketchPlugin_Constraint::ENTITY_A())); + aRefAttr->setAttr(theFirstAttribute); + + aRefAttr = std::dynamic_pointer_cast( + aConstraint->attribute(SketchPlugin_Constraint::ENTITY_B())); + aRefAttr->setObject(theSecondObject); + +#ifdef DEBUG_TRIM + std::cout << " :" + << "first attribute - " << theFirstAttribute->id() + << "second object - " << ModelAPI_Feature::feature(theSecondObject)->getKind() + << std::endl; +#endif + + return aConstraint; +} + +FeaturePtr SketchPlugin_Trim::createConstraintForObjects( + const std::string& theConstraintId, + const ObjectPtr& theFirstObject, + const ObjectPtr& theSecondObject) +{ + FeaturePtr aConstraint = sketch()->addFeature(theConstraintId); + AttributeRefAttrPtr aRefAttr = std::dynamic_pointer_cast( + aConstraint->attribute(SketchPlugin_Constraint::ENTITY_A())); + aRefAttr->setObject(theFirstObject); + + aRefAttr = std::dynamic_pointer_cast( + aConstraint->attribute(SketchPlugin_Constraint::ENTITY_B())); + aRefAttr->setObject(theSecondObject); + + return aConstraint; +} + +std::shared_ptr SketchPlugin_Trim::getFeatureResult( + const std::shared_ptr& theFeature) +{ + std::shared_ptr aResult; + + std::string aFeatureKind = theFeature->getKind(); + if (aFeatureKind == SketchPlugin_Line::ID()) + aResult = theFeature->firstResult(); + else if (aFeatureKind == SketchPlugin_Arc::ID()) + aResult = theFeature->lastResult(); + else if (aFeatureKind == SketchPlugin_Circle::ID()) + aResult = theFeature->lastResult(); + + return aResult; +} + +//******************************************************************** +bool SketchPlugin_Trim::useGraphicIntersection() const +{ + return true; +} + +//******************************************************************** +void SketchPlugin_Trim::fillObjectShapes(const ObjectPtr& theObject) +{ + PointToRefsMap aPointsInfo; + + std::set > aShapes; + std::map, + std::list< AttributePoint2DPtr > > aPointToAttributes; + std::map, + std::list< ObjectPtr > > aPointToObjects; + + std::set aRefAttributes; + // 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())->shape(); + + // coincidences to the feature + 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 + SketchPlugin_Sketch* 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()))); + + ModelGeomAlgo_Point2D::getPointsInsideShape(aFeatureShape, aRefAttributes, aC->pnt(), + aX->dir(), aY, aPointsInfo); + + // intersection points + if (useGraphicIntersection()) { + std::list aFeatures; + for (int i = 0; i < aSketch->numberOfSubs(); i++) { + FeaturePtr aFeature = aSketch->subFeature(i); + if (aFeature.get()) + aFeatures.push_back(aFeature); + } + ModelGeomAlgo_Point2D::getPointsIntersectedShape(aFeature, aFeatures, aPointsInfo); + } + GeomAlgoAPI_ShapeTools::splitShape(aFeatureShape, aPointsInfo, aShapes); + } + myObjectToPoints[theObject] = aPointsInfo; + myCashedShapes[theObject] = aShapes; +} + +//******************************************************************** +void SketchPlugin_Trim::attributeChanged(const std::string& theID) +{ + //data()->addAttribute(SketchPlugin_Trim::BASE_OBJECT(), ModelAPI_AttributeReference::typeId()); + if (theID == SketchPlugin_Trim::BASE_OBJECT()) { + bool isValidAttribute = false; + // feature for trim + AttributeReferencePtr aBaseObjectAttr = std::dynamic_pointer_cast( + data()->attribute(SketchPlugin_Trim::BASE_OBJECT())); + ObjectPtr aBaseObject = aBaseObjectAttr->value(); + if (aBaseObject.get()) { + FeaturePtr aBaseFeature = ModelAPI_Feature::feature(aBaseObjectAttr->value()); + // point on feature + AttributePoint2DPtr aPoint = std::dynamic_pointer_cast( + data()->attribute(ENTITY_POINT())); + std::shared_ptr anAttributePnt2d = aPoint->pnt(); + std::shared_ptr anAttributePnt = sketch()->to3D(anAttributePnt2d->x(), anAttributePnt2d->y()); + + if (myCashedShapes.find(aBaseObject) == myCashedShapes.end()) + fillObjectShapes(aBaseObject); + + const std::set& aShapes = myCashedShapes[aBaseObject]; + isValidAttribute = !aShapes.empty(); + + if (!isValidAttribute) { + bool aWasBlocked = data()->blockSendAttributeUpdated(true); + aBaseObjectAttr->setValue(ObjectPtr()); + data()->blockSendAttributeUpdated(aWasBlocked); + } + } + } +} diff --git a/src/SketchPlugin/SketchPlugin_Trim.h b/src/SketchPlugin/SketchPlugin_Trim.h new file mode 100644 index 000000000..70bffe0a8 --- /dev/null +++ b/src/SketchPlugin/SketchPlugin_Trim.h @@ -0,0 +1,266 @@ +// Copyright (C) 2014-20xx CEA/DEN, EDF R&D --> + +// File: SketchPlugin_Trim.h +// Created: 22 Feb 2017 +// Author: Natalia ERMOLAEVA + +#ifndef SketchPlugin_Trim_H_ +#define SketchPlugin_Trim_H_ + +#include "SketchPlugin.h" +#include +#include "SketchPlugin_ConstraintBase.h" + +class GeomDataAPI_Point2D; +class ModelAPI_Feature; +class ModelAPI_Result; + +typedef std::pair > IdToPointPair; + +/** \class SketchPlugin_Trim + * \ingroup Plugins + * \brief Feature for creation of a new constraint trimming object. Entities for split: + */ +class SketchPlugin_Trim : public SketchPlugin_Feature, public GeomAPI_IPresentable +{ + public: + /// Split constraint kind + inline static const std::string& ID() + { + static const std::string MY_TRIM_ID("SketchTrim"); + return MY_TRIM_ID; + } + /// \brief Returns the kind of a feature + SKETCHPLUGIN_EXPORT virtual const std::string& getKind() + { + static std::string MY_KIND = SketchPlugin_Trim::ID(); + return MY_KIND; + } + + /// The value parameter for the constraint + inline static const std::string& BASE_OBJECT() + { + static const std::string MY_CONSTRAINT_BASE_OBJECT("BaseObject"); + return MY_CONSTRAINT_BASE_OBJECT; + } + + /// Start 2D point of the split segment + inline static const std::string& ENTITY_POINT() + { + static const std::string MY_ENTITY_POINT("ConstraintEntityPoint"); + return MY_ENTITY_POINT; + } + + /// \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(); + + /// Reimplemented from ModelAPI_Feature::isMacro() + /// \returns true + SKETCHPLUGIN_EXPORT virtual bool isMacro() const; + + /// Reimplemented from ModelAPI_Feature::isPreviewNeeded(). Returns false. + /// This is necessary to perform execute only by apply the feature + SKETCHPLUGIN_EXPORT virtual bool isPreviewNeeded() const { return false; } + + /// 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); + + /// \brief Use plugin manager for features creation + SketchPlugin_Trim(); + + /// Returns the AIS preview + SKETCHPLUGIN_EXPORT virtual AISObjectPtr getAISObject(AISObjectPtr thePrevious); + + /// Moves the feature : Empty + SKETCHPLUGIN_EXPORT virtual void move(const double theDeltaX, const double theDeltaY) {}; + +private: + /// Returns geom point attribute of the feature bounds. It processes line or arc. + /// For circle feature, the result attributes are null + /// \param theFeature a source feature + /// \param theStartPointAttr an out attribute to start point + /// \param theStartPointAttr an out attribute to end point + void getFeaturePoints(const FeaturePtr& theFeature, + std::shared_ptr& theStartPointAttr, + std::shared_ptr& theEndPointAttr); + + /// Obtains those constraints of the feature that should be modified. output maps contain + /// point of coincidence and attribute id to be modified after split + /// \param theFeaturesToDelete [out] constrains that will be deleted after split + /// \param theFeaturesToUpdate [out] constrains that will be updated after split + void getConstraints(std::set>& theFeaturesToDelete, + std::set>& theFeaturesToUpdate); + + /// Obtains references to feature point attributes and to feature, + /// e.g. for feature line: 1st container is + /// <1st line point, list > + /// <2nd line point, list<> > + /// for feature circle 2nd container is + /// \param theFeature an investigated feature + /// \param theRefs a container of list of referenced attributes + void getRefAttributes(const FeaturePtr& theFeature, + std::map >& theRefs, + std::list& theRefsToFeature); + + /// Move constraints from base feature to given feature + /// \param theFeature a base feature + /// \param theRefsToFeature list of attributes referenced to base feature + void updateRefFeatureConstraints(const std::shared_ptr& theFeatureBaseResult, + const std::list& theRefsToFeature); + + /// Move constraints from attribute of base feature to attribute after modification + /// \param theBaseRefAttributes container of references to the attributes of base feature + /// \param theModifiedAttributes container of attributes placed instead of base attributes + /// at the same place + void updateRefAttConstraints( + const std::map >& theBaseRefAttributes, + const std::set >& theModifiedAttributes, + std::set>& theFeaturesToDelete); + +// /// Make the base object is splitted by the point attributes +// /// \param theSplitFeature a result split feature +// /// \param theBeforeFeature a feature between start point and the 1st point of split feature +// /// \param theAfterFeature a feature between last point of split feature and the end point +// /// \param thePoints a list of points where coincidences will be build +// /// \param theCreatedFeatures a container of created features +// /// \param theModifiedAttributes a container of attribute on base +// /// feature to attribute on new feature + void trimLine(const std::shared_ptr& theStartShapePoint, + const std::shared_ptr& theLastShapePoint, + std::set >& thePoints, + std::set>& theCreatedFeatures, + std::set>& theModifiedAttributes); + + /// Make the base object is splitted by the point attributes + /// \param theSplitFeature a result split feature + /// \param theBeforeFeature a feature between start point and the 1st point of split feature + /// \param theAfterFeature a feature between last point of split feature and the end point + /// \param thePoints a list of points where coincidences will be build + /// \param theCreatedFeatures a container of created features + void trimArc(const std::shared_ptr& theStartShapePoint, + const std::shared_ptr& theLastShapePoint, + std::set >& thePoints, + std::set>& theCreatedFeatures, + std::set>& theModifiedAttributes); + + /// Make the base object is splitted by the point attributes + /// \param theSplitFeature a result split feature + /// \param theBeforeFeature a feature between start point and the 1st point of split feature + /// \param theAfterFeature a feature between last point of split feature and the end point + /// \param thePoints a list of points where coincidences will be build + /// \param theCreatedFeatures a container of created features + void trimCircle(const std::shared_ptr& theStartShapePoint, + const std::shared_ptr& theLastShapePoint, + std::set >& thePoints, + std::set>& theCreatedFeatures, + std::set>& theModifiedAttributes); + + /// Correct the first and the second point to provide condition that the first is closer to + /// the start point and the second point - to the last end of current segment. To rearrange + /// them if this condition is not satisfied. + /// \param theStartPointAttr a start point of a segment + /// \param theEndPointAttr an end point of a segment + /// \param theFirstPoint a start point of a segment + /// \param theSecondPoint an end point of a segment + void arrangePointsOnLine(const std::shared_ptr& theStartPointAttr, + const std::shared_ptr& theEndPointAttr, + std::shared_ptr& theFirstPoint, + std::shared_ptr& theSecondPoint) const; + + /// Correct the first and the second point to provide condition that the first is closer to + /// the start point and the second point - to the last end of current segment. To rearrange + /// them if this condition is not satisfied. + /// \param theArc an arc to be split + /// \param theStartPointAttr a start point of a segment + /// \param theEndPointAttr an end point of a segment + /// \param theFirstPoint a start point of a segment + /// \param theSecondPoint an end point of a segment + void arrangePointsOnArc(const FeaturePtr& theArc, + const std::shared_ptr& theStartPointAttr, + const std::shared_ptr& theEndPointAttr, + std::shared_ptr& theFirstPoint, + std::shared_ptr& theSecondPoint) const; + + /// Fill attribute by value of another attribute. It processes only Point 2D attributes. + /// \param theModifiedAttribute an attribute of GeomDataAPI_Point2D on feature to be modified + /// \param theSourceAttribute an attribute of GeomDataAPI_Point2D to obtain data + void fillAttribute(const AttributePtr& theModifiedAttribute, + const AttributePtr& theSourceAttribute); + + /// Fill attribute by value of another attribute. It processes only Point 2D attributes. + /// \param theModifiedAttribute an attribute of GeomDataAPI_Point2D on feature to be modified + /// \param thePoint a point value + void fillPointAttribute(const AttributePtr& theModifiedAttribute, + const std::shared_ptr& thePoint); + + /// Creates a line feature filled by center of base feature and given points + /// \param theBaseFeature another arc feature + /// \param theFirstAttribute an attribute with coordinates for the start point + /// \param theSecondAttribute an attribute with coordinates for the end point + FeaturePtr createLineFeature(const FeaturePtr& theBaseFeature, + const std::shared_ptr& theFirstPoint, + const std::shared_ptr& theSecondPoint); + + /// Creates an arc feature filled by center of base feature and given points + /// \param theBaseFeature another arc feature + /// \param theFirstAttribute an attribute with coordinates for the start point + /// \param theSecondAttribute an attribute with coordinates for the end point + FeaturePtr createArcFeature(const FeaturePtr& theBaseFeature, + const std::shared_ptr& theFirstPoint, + const std::shared_ptr& theSecondPoint); + + /// Add feature coincidence constraint between given attributes + /// \param theConstraintId a constraint index + /// \param theFirstAttribute an attribute of further coincidence + /// \param theSecondAttribute an attribute of further coincidence + std::shared_ptr createConstraint(const std::string& theConstraintId, + const std::shared_ptr& theFirstAttribute, + const std::shared_ptr& theSecondAttribute); + + /// Add feature coincidence constraint between given attributes + /// \param theConstraintId a constraint index + /// \param theFirstAttribute an attribute of further coincidence + /// \param theSecondObject an object of further coincidence + std::shared_ptr createConstraint(const std::string& theConstraintId, + const std::shared_ptr& theFirstAttribute, + const std::shared_ptr& theSecondObject); + + /// Add feature coincidence constraint between given attributes + /// \param theConstraintId a constraint index + /// \param theFirstAttribute an attribute of further coincidence + /// \param theFirstAttribute an attribute of further coincidence + std::shared_ptr createConstraintForObjects(const std::string& theConstraintId, + const std::shared_ptr& theFirstObject, + const std::shared_ptr& theSecondObject); + + /// Result result of the feature to build constraint with. For arc, circle it is an edge result. + /// \param theFeature a feature + /// \return result object + std::shared_ptr getFeatureResult( + const std::shared_ptr& theFeature); + +private: + bool useGraphicIntersection() const; + + void fillObjectShapes(const ObjectPtr& theObject); + + void findShapePoints(std::shared_ptr& aStartPoint, + std::shared_ptr& aLastPoint); + + std::shared_ptr convertPoint(const std::shared_ptr& thePoint); + +private: + std::map > myCashedShapes; + + typedef std::map, + std::pair >, + std::list > > > PointToRefsMap; + + std::map myObjectToPoints; +}; + +#endif diff --git a/src/SketchPlugin/SketchPlugin_Validators.cpp b/src/SketchPlugin/SketchPlugin_Validators.cpp index 51d0b8fc1..8e85e516b 100755 --- a/src/SketchPlugin/SketchPlugin_Validators.cpp +++ b/src/SketchPlugin/SketchPlugin_Validators.cpp @@ -854,7 +854,7 @@ bool SketchPlugin_SplitValidator::isValid(const AttributePtr& theAttribute, aKind == SketchPlugin_Arc::ID() || aKind == SketchPlugin_Circle::ID()) { - std::set anEdgeShapes; + std::set anEdgeShapes; ModelAPI_Tools::shapesOfType(anAttrFeature, GeomAPI_Shape::EDGE, anEdgeShapes); if (anEdgeShapes.empty() || anEdgeShapes.size() > 1 /*there case has not existed yet*/) return aValid; @@ -865,7 +865,7 @@ bool SketchPlugin_SplitValidator::isValid(const AttributePtr& theAttribute, SketchPlugin_ConstraintCoincidence::ID(), aRefAttributes, SketchPlugin_Point::ID(), SketchPlugin_Point::COORD_ID()); - GeomShapePtr anAttrShape = *anEdgeShapes.begin(); + GeomShapePtr anAttrShape = (*anEdgeShapes.begin())->shape(); std::shared_ptr aSFeature = std::dynamic_pointer_cast(anAttrFeature); SketchPlugin_Sketch* aSketch = aSFeature->sketch(); @@ -879,13 +879,20 @@ bool SketchPlugin_SplitValidator::isValid(const AttributePtr& theAttribute, aData->attribute(SketchPlugin_Sketch::NORM_ID())); std::shared_ptr aDirY(new GeomAPI_Dir(aNorm->dir()->cross(aX->dir()))); - std::list > aPoints; - std::map, std::shared_ptr > - aPointToAttributes; + typedef std::map, + std::pair >, + std::list > > > PointToRefsMap; + PointToRefsMap aPointsInfo; + + //std::list > aPoints; + //std::map, std::shared_ptr > + // aPointToAttributes; + //std::map, + // std::list< std::shared_ptr > > aPointToAttributes; ModelGeomAlgo_Point2D::getPointsInsideShape(anAttrShape, aRefAttributes, aC->pnt(), - aX->dir(), aDirY, aPoints, aPointToAttributes); + aX->dir(), aDirY, aPointsInfo);//aPoints, aPointToAttributes); - int aCoincidentToFeature = (int)aPoints.size(); + int aCoincidentToFeature = (int)aPointsInfo.size();//aPoints.size(); if (aKind == SketchPlugin_Circle::ID()) aValid = aCoincidentToFeature >= 2; else diff --git a/src/SketchPlugin/Test/TestTrimCircle.py b/src/SketchPlugin/Test/TestTrimCircle.py new file mode 100644 index 000000000..aecbb4efa --- /dev/null +++ b/src/SketchPlugin/Test/TestTrimCircle.py @@ -0,0 +1,129 @@ +from salome.shaper import model + +from ModelAPI import * +from GeomDataAPI import * +from salome.shaper import geom +import math + +TOLERANCE = 1.e-7 + +SketchPointId = 'SketchPoint' +SketchLineId = 'SketchLine' +SketchArcId = 'SketchArc' +SketchCircleId = 'SketchCircle' +SketchConstraintCoincidenceId = 'SketchConstraintCoincidence' +SketchConstraintParallelId = 'SketchConstraintParallel' +SketchConstraintTangentId = 'SketchConstraintTangent' +SketchConstraintEqualId = 'SketchConstraintEqual' + +model.begin() +partSet = model.moduleDocument() +Part_1 = model.addPart(partSet) +Part_1_doc = Part_1.document() + +# Test1:begin split on circle with coincident point and intersection line : smaller part +Sketch_1 = model.addSketch(Part_1_doc, model.defaultPlane("XOY")) +SketchCircle_1_1 = Sketch_1.addCircle(50, 50, 20) +SketchLine_1_1 = Sketch_1.addLine(50, 30, 100, 30) +SketchLine_1_2 = Sketch_1.addLine(60, 50, 100, 30) + +SketchConstraintCoincidence_1_1 = Sketch_1.setCoincident(SketchLine_1_1.startPoint(), SketchCircle_1_1.results()[1]) +SketchConstraintCoincidence_1_2 = Sketch_1.setCoincident(SketchLine_1_1.endPoint(), SketchLine_1_2.endPoint()) +GeomPoint_1_1 = geom.Pnt2d(60, 35) + +#check number of features before trim +Sketch_1_feature = featureToCompositeFeature(Sketch_1.feature()) +idList_before_1 = [] +for index in range(Sketch_1_feature.numberOfSubs()): + idList_before_1.append(Sketch_1_feature.subFeature(index).getKind()) +assert(idList_before_1.count(SketchCircleId) == 1) +assert(idList_before_1.count(SketchArcId) == 0) +assert(idList_before_1.count(SketchLineId) == 2) +assert(idList_before_1.count(SketchConstraintCoincidenceId) == 2) + +#perform trim +SketchTrim_1_1 = Sketch_1.addTrim(SketchCircle_1_1, GeomPoint_1_1) +SketchTrim_1_1.execute() +model.do() + +#check number of features after trim +SketchFeatures = featureToCompositeFeature(Sketch_1.feature()) +idList_after_1 = [] +for SubIndex in range(SketchFeatures.numberOfSubs()): + SubFeature = SketchFeatures.subFeature(SubIndex) + idList_after_1.append(SubFeature.getKind()) + if SubFeature.getKind() == SketchArcId: + ArcFeature_1 = SubFeature + + +assert(idList_after_1.count(SketchCircleId) == 0) +assert(idList_after_1.count(SketchArcId) == 1) +assert(idList_after_1.count(SketchLineId) == 2) +assert(idList_after_1.count(SketchConstraintCoincidenceId) == 3) + +#test created arc: it is not inversed, has coincidence to end line point +anInversed_1 = ArcFeature_1.boolean("InversedArc").value() +assert(anInversed_1 == False) +ArcPoint_1 = geomDataAPI_Point2D(ArcFeature_1.attribute("ArcEndPoint")) +LinePoint_1 = geomDataAPI_Point2D(SketchLine_1_1.startPoint()) +aDistance_1 = math.hypot(LinePoint_1.x() - ArcPoint_1.x(), LinePoint_1.y() - ArcPoint_1.y()) +#print "Distance " + repr(aDistance) +assert (math.fabs(aDistance_1) <= TOLERANCE) +# Test1:end + + +# Test2: split on circle with coincident point and intersection line : largest part +Sketch_2 = model.addSketch(Part_1_doc, model.defaultPlane("XOY")) +move_test_delta_y = 100 +move_test_delta_x = 0 +SketchCircle_2_1 = Sketch_2.addCircle(50, 50 + move_test_delta_y, 20) +SketchLine_2_1 = Sketch_2.addLine(50, 30 + move_test_delta_y, 100, 30 + move_test_delta_y) +SketchLine_2_2 = Sketch_2.addLine(60, 50 + move_test_delta_y, 100, 30 + move_test_delta_y) + +SketchConstraintCoincidence_2_1 = Sketch_2.setCoincident(SketchLine_2_1.startPoint(), SketchCircle_2_1.results()[1]) +SketchConstraintCoincidence_2_2 = Sketch_2.setCoincident(SketchLine_2_1.endPoint(), SketchLine_2_2.endPoint()) +GeomPoint_2_1 = geom.Pnt2d(50, 75 + move_test_delta_y) + +#check number of features before trim +Sketch_2_feature = featureToCompositeFeature(Sketch_2.feature()) +idList_before_2 = [] +for index in range(Sketch_2_feature.numberOfSubs()): + idList_before_2.append(Sketch_2_feature.subFeature(index).getKind()) +assert(idList_before_2.count(SketchCircleId) == 1) +assert(idList_before_2.count(SketchArcId) == 0) +assert(idList_before_2.count(SketchLineId) == 2) +assert(idList_before_2.count(SketchConstraintCoincidenceId) == 2) + +#perform trim +SketchTrim_2_1 = Sketch_2.addTrim(SketchCircle_2_1, GeomPoint_2_1) +SketchTrim_2_1.execute() +model.do() + +#check number of features after trim +SketchFeatures = featureToCompositeFeature(Sketch_2.feature()) +idList_after_2 = [] +for SubIndex in range(SketchFeatures.numberOfSubs()): + SubFeature = SketchFeatures.subFeature(SubIndex) + idList_after_2.append(SubFeature.getKind()) + if SubFeature.getKind() == SketchArcId: + ArcFeature_2 = SubFeature + + +assert(idList_after_2.count(SketchCircleId) == 0) +assert(idList_after_2.count(SketchArcId) == 1) +assert(idList_after_2.count(SketchLineId) == 2) +assert(idList_after_2.count(SketchConstraintCoincidenceId) == 3) + +#test created arc : it is not inversed, has coincidence to start line point +anInversed_2 = ArcFeature_2.boolean("InversedArc").value() +assert(anInversed_2 == False) +ArcPoint_2 = geomDataAPI_Point2D(ArcFeature_2.attribute("ArcStartPoint")) +LinePoint_2 = geomDataAPI_Point2D(SketchLine_2_1.startPoint()) +aDistance_2 = math.hypot(LinePoint_2.x() - ArcPoint_2.x(), LinePoint_2.y() - ArcPoint_2.y()) +#print "Distance " + repr(aDistance_2) +assert (math.fabs(aDistance_2) <= TOLERANCE) +# Test2:end + +model.end() + +#assert(model.checkPythonDump()) diff --git a/src/SketchPlugin/icons/split.png b/src/SketchPlugin/icons/split.png index 535b7e725b5b0c525ea653336db4cf134c5e24a9..f3f3ff486e4cfc7a83bdebf8404a681db2682f18 100644 GIT binary patch delta 541 zcmV+&0^N2bPDNB8b~7$DE-^4L^m3s900E^* zL_t(IPmPm5NW(xB#;>*=6j71pQj1_+bPybL(m`zREEP<15r2w$*64sIfDE`=%%BI@G5@1<9vSRo($Nci5n?~cn0tLmFEKWG3E;*+tg zDbxa&_AHOv!)$Ods9Wm`ivl1Ba^M5J8^S3d;DAeY4IcTJ%D0WGHoc@)SRlX|cm42qSKci}!ROyNvWzzJB>zGu-XxODa@;1-N)-?PFotB<}81>At7_C2d3 zKG}tUI|?`ktJ?Q0Bas^6!a1ja47k+3XPMI8!bN5&pnn;Z!IFM&)II;oOgJ3Je=rkP zw`*Y03U~&Gpa%rpLLGGur5m|WrD8q#uk16_zICz+{Dal00000NkvXXu0mjfr-JFI delta 549 zcmV+=0^0qy1il22B!2{RLP=Bz2nYy#2xN!=000SaNLh0L01ejw01ejxLMWSf0000P zbVXQnQ*UN;cVTj60C#tHE@^ISb7Ns}WiD@WXPfRk8UO$RyGcYrR5*>5(%);%aU93- z$LG5rnTf4!=M>^bl%&v_-3aFpmN}CjH>`*YH~t0WLatoNkAJx5hG`d4Tg^&|T!`G5 zJ0?diM5Jxsw+qu|nVi?v`{w!V_3r&nrV}*d4z^(68T~z_N`Iu7kQ=LhEj zX3ajDIFR{0lDb>?=ebFH<(v1%lJT z=iqkmHdr&MTy^-~71NhXzwJR6c44Sk>K#j|?nJOUiKd)) nS;XVIg&z6f_~78T*{yy8)YOx?Fd3JZ00000NkvXXu0mjf$tw+` diff --git a/src/SketchPlugin/icons/trim.png b/src/SketchPlugin/icons/trim.png new file mode 100644 index 0000000000000000000000000000000000000000..9a5a2592e8e9d03893cb028b219a100dd344fe37 GIT binary patch literal 563 zcmV-30?hr1P)Px#1ZP1_K>z@;j|==^1poj532;bRa{vGh)&Kwv)&Y=jd7J1;MAa*k@H7+qQF!XYv0004^Nkl(I6mB0@?%MjLtA>=)lJ{2$r(r(GSa38mf+ruj094u(xv(zc5 zun)4o-{;!i6%3he>g%ZH3Q(YZ&#Dc_8WHfM0?xp^_C3ppMEfbXZ&W}6+-cvln6Nf+ zk?Sg;9Qc4*R{`d3`ClwzQyl-DMa*W$&;g&|7`%ddr;tYtJ@FFChOj4bQDX*|%W5i){YJT!K+E6H zj>c}V3i>dK;mxn8hk}VGDvWV!q|P);^>!^negKL|jz3-TEy4f*002ovPDHLkV1jZr B@7w?Y literal 0 HcmV?d00001 diff --git a/src/SketchPlugin/plugin-Sketch.xml b/src/SketchPlugin/plugin-Sketch.xml index b72f3d8d3..50c1a6552 100644 --- a/src/SketchPlugin/plugin-Sketch.xml +++ b/src/SketchPlugin/plugin-Sketch.xml @@ -5,7 +5,18 @@ - + + use_external="false" + use_graphic_intersection="false"> + + + + + + + diff --git a/src/XGUI/XGUI_Displayer.cpp b/src/XGUI/XGUI_Displayer.cpp index e38dc3dc3..f51ac398f 100644 --- a/src/XGUI/XGUI_Displayer.cpp +++ b/src/XGUI/XGUI_Displayer.cpp @@ -702,7 +702,7 @@ void XGUI_Displayer::clearSelected(const bool theUpdateViewer) { Handle(AIS_InteractiveContext) aContext = AISContext(); if (!aContext.IsNull()) { - aContext->UnhilightCurrents(false); + aContext->UnhilightSelected(false);//UnhilightCurrents(false); aContext->ClearSelected(theUpdateViewer); #ifdef VINSPECTOR if (getCallBack()) getCallBack()->ClearSelected(); -- 2.30.2