Initial implementation of non-periodic B-spline curves.
# make a working copy of report
cp -f coverage.info.noext covfile
# remove all reports of GUI and external parts (for all the next kinds of reports)
-# RefAttrList is unused type of attribute for now
-for MASK in '*wrap*' 'moc_*' 'XAO_*' 'SketcherPrs_*' 'GeomAlgoImpl_*' 'ModuleBase_*' '*Widget*' '*Splitter*' '*RefAttrList*'; do
+for MASK in '*wrap*' 'moc_*' 'XAO_*' 'SketcherPrs_*' 'GeomAlgoImpl_*' 'ModuleBase_*' '*Widget*' '*Splitter*'; do
lcov -r covfile ${MASK} --output-file covfile_res -q
mv -f covfile_res covfile
done
#include <TopoDS_Face.hxx>
#include <TopoDS.hxx>
#include <BRep_Tool.hxx>
+#include <Geom_BSplineCurve.hxx>
#include <Geom_Plane.hxx>
#include <Geom_CylindricalSurface.hxx>
#include <Geom_RectangularTrimmedSurface.hxx>
aRes->setImpl(new TopoDS_Shape(anEdge));
return aRes;
}
+
+GeomEdgePtr GeomAlgoAPI_EdgeBuilder::bspline(const std::vector<GeomPointPtr>& thePoles,
+ const std::vector<double>& theWeights,
+ const bool thePeriodic)
+{
+ int aDegree = 3;
+ if ((int)thePoles.size() <= aDegree)
+ aDegree = (int)thePoles.size() - 1;
+ if (aDegree <= 0)
+ return GeomEdgePtr();
+
+ int aNbKnots = (int)thePoles.size() - aDegree + 1;
+
+ // collect arrays of poles, weights, knots and multiplicities
+ TColgp_Array1OfPnt aPoles(1, (int)thePoles.size());
+ TColStd_Array1OfReal aWeights(1, (int)theWeights.size());
+ TColStd_Array1OfReal aKnots(1, aNbKnots);
+ TColStd_Array1OfInteger aMults(1, aNbKnots);
+
+ int anIndex = 1;
+ for (std::vector<GeomPointPtr>::const_iterator aPIt = thePoles.begin();
+ aPIt != thePoles.end(); ++aPIt, ++anIndex)
+ aPoles.SetValue(anIndex, gp_Pnt((*aPIt)->x(), (*aPIt)->y(), (*aPIt)->z()));
+ anIndex = 1;
+ for (std::vector<double>::const_iterator aWIt = theWeights.begin();
+ aWIt != theWeights.end(); ++aWIt, ++anIndex)
+ aWeights.SetValue(anIndex, *aWIt);
+ anIndex = 1;
+ static const double aStartParam = 0.0;
+ static const double aEndParam = 1.0;
+ double aStep = aEndParam / (aNbKnots - 1);
+ for (double aKnot = aStartParam; anIndex < aNbKnots; ++anIndex, aKnot += aStep)
+ aKnots.SetValue(anIndex, aKnot);
+ aKnots.ChangeLast() = aEndParam;
+ anIndex = 1;
+ aMults.SetValue(anIndex, aDegree + 1);
+ for (++anIndex; anIndex < aNbKnots; ++anIndex)
+ aMults.SetValue(anIndex, 1);
+ aMults.SetValue(aNbKnots, aDegree + 1);
+
+ Handle(Geom_BSplineCurve) aCurve =
+ new Geom_BSplineCurve(aPoles, aWeights, aKnots, aMults, aDegree, thePeriodic);
+
+ BRepBuilderAPI_MakeEdge anEdgeBuilder(aCurve, aStartParam, aEndParam);
+ GeomEdgePtr aRes(new GeomAPI_Edge);
+ TopoDS_Edge anEdge = anEdgeBuilder.Edge();
+ aRes->setImpl(new TopoDS_Shape(anEdge));
+ return aRes;
+}
#include <GeomAPI_Lin.h>
#include <GeomAPI_Circ.h>
#include <memory>
+#include <vector>
/**\class GeomAlgoAPI_EdgeBuilder
* \ingroup DataAlgo
const double theMinorRadius,
const std::shared_ptr<GeomAPI_Pnt>& theStart,
const std::shared_ptr<GeomAPI_Pnt>& theEnd);
+
+ /// Creates B-spline edge
+ static GeomEdgePtr bspline(const std::vector<GeomPointPtr>& thePoles,
+ const std::vector<double>& theWeights,
+ const bool thePeriodic);
};
#endif
GeomData_Point.h
GeomData_Dir.h
GeomData_Point2D.h
+ GeomData_Point2DArray.h
)
SET(PROJECT_SOURCES
GeomData_Point.cpp
GeomData_Dir.cpp
GeomData_Point2D.cpp
+ GeomData_Point2DArray.cpp
)
SET(PROJECT_LIBRARIES
--- /dev/null
+// Copyright (C) 2019-2020 CEA/DEN, EDF R&D
+//
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2.1 of the License, or (at your option) any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+//
+// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
+//
+
+#include "GeomData_Point2DArray.h"
+
+#include <GeomAPI_Pnt2d.h>
+
+#include <ModelAPI_Data.h>
+#include <ModelAPI_Events.h>
+#include <ModelAPI_Expression.h>
+#include <ModelAPI_Feature.h>
+
+#include <cassert>
+
+GeomData_Point2DArray::GeomData_Point2DArray(TDF_Label& theLabel)
+ : myLab(theLabel)
+{
+ reinit();
+}
+
+void GeomData_Point2DArray::reinit()
+{
+ // check the attribute could be already presented in this doc (after load document)
+ myIsInitialized = myLab.FindAttribute(TDataStd_RealArray::GetID(), myArray) == Standard_True;
+}
+
+bool GeomData_Point2DArray::assign(std::shared_ptr<GeomDataAPI_Point2DArray> theOther)
+{
+ std::shared_ptr<GeomData_Point2DArray> anOther =
+ std::dynamic_pointer_cast<GeomData_Point2DArray>(theOther);
+ if (!anOther)
+ return false;
+
+ setSize(anOther->size());
+ myArray->ChangeArray(anOther->myArray->Array(), false);
+}
+
+int GeomData_Point2DArray::size()
+{
+ if (myArray.IsNull() || !myArray->IsValid()) {
+ // this could be on undo and then redo creation of the attribute
+ // in result creation it may be uninitialized
+ myIsInitialized = myLab.FindAttribute(TDataStd_RealArray::GetID(), myArray) == Standard_True;
+ }
+ // checking the validity because attribute (as a field) may be presented,
+ // but without label: it is undoed
+ return (myArray.IsNull() || !myArray->IsValid()) ? 0 : myArray->Length() / 2;
+}
+
+void GeomData_Point2DArray::setSize(const int theSize)
+{
+ int aValuesSize = 2 * theSize;
+ if (myArray.IsNull() || !myArray->IsValid()) { // create array if it is not done yet
+ if (aValuesSize != 0) { // if size is zero, nothing to do (null array means there is no array)
+ myArray = TDataStd_RealArray::Set(myLab, 0, aValuesSize - 1);
+ owner()->data()->sendAttributeUpdated(this);
+ }
+ }
+ else { // reset the old array
+ if (aValuesSize) {
+ if (aValuesSize != myArray->Length()) { // old data is not keept, a new array is created
+ Handle(TColStd_HArray1OfReal) aNewArray = new TColStd_HArray1OfReal(0, aValuesSize - 1);
+ myArray->ChangeArray(aNewArray);
+ owner()->data()->sendAttributeUpdated(this);
+ }
+ }
+ else { // size is zero => array must be erased
+ if (!myArray.IsNull()) {
+ myArray.Nullify();
+ myLab.ForgetAttribute(TDataStd_RealArray::GetID());
+ owner()->data()->sendAttributeUpdated(this);
+ }
+ }
+ }
+}
+
+void GeomData_Point2DArray::setPnt(const int theIndex,
+ const double theX,
+ const double theY)
+{
+ if (myArray->Value(2 * theIndex) != theX || myArray->Value(2 * theIndex + 1) != theY) {
+ myArray->SetValue(2 * theIndex, theX);
+ myArray->SetValue(2 * theIndex + 1, theY);
+ owner()->data()->sendAttributeUpdated(this);
+ }
+}
+
+void GeomData_Point2DArray::setPnt(const int theIndex, const GeomPnt2dPtr& thePoint)
+{
+ setPnt(theIndex, thePoint->x(), thePoint->y());
+}
+
+GeomPnt2dPtr GeomData_Point2DArray::pnt(const int theIndex)
+{
+ GeomPnt2dPtr aPoint;
+ if (theIndex >= 0 && theIndex * 2 < myArray->Length())
+ aPoint.reset(new GeomAPI_Pnt2d(myArray->Value(2 * theIndex), myArray->Value(2 * theIndex + 1)));
+ return aPoint;
+}
--- /dev/null
+// Copyright (C) 2019-2020 CEA/DEN, EDF R&D
+//
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2.1 of the License, or (at your option) any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+//
+// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
+//
+
+#ifndef GeomData_Point2DArray_H_
+#define GeomData_Point2DArray_H_
+
+#include "GeomData.h"
+
+#include <GeomDataAPI_Point2DArray.h>
+
+#include <TDataStd_RealArray.hxx>
+#include <TDF_Label.hxx>
+
+/** \class GeomData_Point2DArray
+ * \ingroup DataModel
+ * \brief Attribute that contains an array of 2D points.
+ */
+class GeomData_Point2DArray : public GeomDataAPI_Point2DArray
+{
+ TDF_Label myLab; ///< the main label of the attribute
+ Handle_TDataStd_RealArray myArray; ///< array that keeps all coordinates of the points
+
+public:
+ /// Copy values from another array
+ /// \return \c true if the copy was successful
+ GEOMDATA_EXPORT virtual bool assign(std::shared_ptr<GeomDataAPI_Point2DArray> theOther);
+
+ /// Returns the size of the array (zero means that it is empty)
+ GEOMDATA_EXPORT virtual int size();
+
+ /// Sets the new size of the array. The previous data is erased.
+ GEOMDATA_EXPORT virtual void setSize(const int theSize);
+
+ /// Defines the value of the array by index [0; size-1]
+ GEOMDATA_EXPORT virtual void setPnt(const int theIndex,
+ const double theX, const double theY);
+
+ /// Defines the value of the array by index [0; size-1]
+ GEOMDATA_EXPORT virtual void setPnt(const int theIndex,
+ const std::shared_ptr<GeomAPI_Pnt2d>& thePoint);
+
+ /// Returns the value by the index
+ GEOMDATA_EXPORT virtual std::shared_ptr<GeomAPI_Pnt2d> pnt(const int theIndex);
+
+protected:
+ /// Initializes attributes
+ GEOMDATA_EXPORT GeomData_Point2DArray(TDF_Label& theLabel);
+ /// Reinitializes the internal state of the attribute (may be needed on undo/redo, abort, etc)
+ virtual void reinit();
+
+ friend class Model_Data;
+};
+
+#endif
GeomDataAPI_Point.h
GeomDataAPI_Dir.h
GeomDataAPI_Point2D.h
+ GeomDataAPI_Point2DArray.h
)
SET(PROJECT_SOURCES
GeomDataAPI_Point.cpp
GeomDataAPI_Dir.cpp
GeomDataAPI_Point2D.cpp
+ GeomDataAPI_Point2DArray.cpp
)
SET(PROJECT_LIBRARIES
--- /dev/null
+// Copyright (C) 2019-2020 CEA/DEN, EDF R&D
+//
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2.1 of the License, or (at your option) any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+//
+// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
+//
+
+#include <GeomDataAPI_Point2DArray.h>
+
+std::string GeomDataAPI_Point2DArray::attributeType()
+{
+ return typeId();
+}
+
+GeomDataAPI_Point2DArray::GeomDataAPI_Point2DArray()
+{
+}
+
+GeomDataAPI_Point2DArray::~GeomDataAPI_Point2DArray()
+{
+}
--- /dev/null
+// Copyright (C) 2019-2020 CEA/DEN, EDF R&D
+//
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2.1 of the License, or (at your option) any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+//
+// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
+//
+
+#ifndef GeomDataAPI_Point2DArray_H_
+#define GeomDataAPI_Point2DArray_H_
+
+#include <GeomDataAPI.h>
+#include <ModelAPI_Attribute.h>
+
+class GeomAPI_Pnt2d;
+
+/**\class GeomDataAPI_Point2DArray
+ * \ingroup DataModel
+ * \brief Attribute that contains array of 2D point coordinates.
+ */
+
+class GeomDataAPI_Point2DArray : public ModelAPI_Attribute
+{
+public:
+ /// Copy values from another array
+ /// \return \c true if the copy was successful
+ GEOMDATAAPI_EXPORT virtual bool assign(std::shared_ptr<GeomDataAPI_Point2DArray> theOther) = 0;
+
+ /// Returns the size of the array (zero means that it is empty)
+ GEOMDATAAPI_EXPORT virtual int size() = 0;
+
+ /// Sets the new size of the array. The previous data is erased.
+ GEOMDATAAPI_EXPORT virtual void setSize(const int theSize) = 0;
+
+ /// Defines the value of the array by index [0; size-1]
+ GEOMDATAAPI_EXPORT virtual void setPnt(const int theIndex,
+ const double theX, const double theY) = 0;
+
+ /// Defines the value of the array by index [0; size-1]
+ GEOMDATAAPI_EXPORT virtual void setPnt(const int theIndex,
+ const std::shared_ptr<GeomAPI_Pnt2d>& thePoint) = 0;
+
+ /// Returns the value by the index
+ GEOMDATAAPI_EXPORT virtual std::shared_ptr<GeomAPI_Pnt2d> pnt(const int theIndex) = 0;
+
+ /// Returns the type of this class of attributes
+ static std::string typeId()
+ {
+ return std::string("Point2DArray");
+ }
+
+ /// Returns the type of this class of attributes, not static method
+ GEOMDATAAPI_EXPORT virtual std::string attributeType();
+
+protected:
+ /// Objects are created for features automatically
+ GEOMDATAAPI_EXPORT GeomDataAPI_Point2DArray();
+ GEOMDATAAPI_EXPORT virtual ~GeomDataAPI_Point2DArray();
+};
+
+typedef std::shared_ptr<GeomDataAPI_Point2DArray> AttributePoint2DArrayPtr;
+
+#endif
void Model_AttributeRefAttrList::append(ObjectPtr theObject)
{
- std::shared_ptr<Model_Data> aData = std::dynamic_pointer_cast<Model_Data>(theObject->data());
- myRef->Append(aData->label().Father()); // store label of the object
+ TDF_Label aLabel;
+ if (theObject) {
+ std::shared_ptr<Model_Data> aData = std::dynamic_pointer_cast<Model_Data>(theObject->data());
+ aLabel = aData->label().Father();
+ }
+
+ myRef->Append(aLabel); // store label of the object
myIDs->Append(""); // for the object store an empty string
// do it before the transaction finish to make just created/removed objects know dependencies
// and reference from composite feature is removed automatically
myIDs->Append(anIDIter.Value());
} else { // found, so need to update the dependencies
aOneisDeleted = true;
- ObjectPtr anObj = aDoc->objects()->object(aRefIter.Value());
+ ObjectPtr anObj;
+ if (!aRefIter.Value().IsNull())
+ anObj = aDoc->objects()->object(aRefIter.Value());
if (anObj.get()) {
REMOVE_BACK_REF(anObj);
}
#include <GeomDataAPI_Point.h>
#include <GeomDataAPI_Point2D.h>
+#include <GeomDataAPI_Point2DArray.h>
#include <GeomData_Point.h>
#include <GeomData_Point2D.h>
+#include <GeomData_Point2DArray.h>
#include <GeomData_Dir.h>
#include <Events_Loop.h>
#include <Events_InfoMessage.h>
}
anAttribute->myIsInitialized = anAllInitialized;
anAttr = anAttribute;
+ } else if (theAttrType == GeomData_Point2DArray::typeId()) {
+ anAttr = new GeomData_Point2DArray(anAttrLab);
}
+
if (anAttr) {
aResult = std::shared_ptr<ModelAPI_Attribute>(anAttr);
myAttrs[theID] = std::pair<AttributePtr, int>(aResult, anAttrIndex);
myMovedAttribute = AttributePtr();
}
-void ModelAPI_ObjectMovedMessage::setMovedAttribute(const AttributePtr& theMovedAttribute)
+void ModelAPI_ObjectMovedMessage::setMovedAttribute(const AttributePtr& theMovedAttribute,
+ const int thePointIndex)
{
myMovedAttribute = theMovedAttribute;
myMovedObject = ObjectPtr();
+ myMovedPointIndex = thePointIndex;
}
void ModelAPI_ObjectMovedMessage::setOriginalPosition(double theX, double theY)
{
ObjectPtr myMovedObject;
AttributePtr myMovedAttribute;
+ int myMovedPointIndex;
std::shared_ptr<GeomAPI_Pnt2d> myOriginalPosition;
std::shared_ptr<GeomAPI_Pnt2d> myCurrentPosition;
/// Set object which is being moved (if the message already contains attribute it will be cleared)
MODELAPI_EXPORT void setMovedObject(const ObjectPtr& theMovedObject);
/// Set attribute which is being moved (if the message already contains object it will be cleared)
- MODELAPI_EXPORT void setMovedAttribute(const AttributePtr& theMovedAttribute);
+ /// \param[in] theMovedAttribute moved attribute
+ /// \param[in] thePointIndex index of the point if the moved attribute is an array of points
+ MODELAPI_EXPORT void setMovedAttribute(const AttributePtr& theMovedAttribute,
+ const int thePointIndex = -1);
/// Return moved object
ObjectPtr movedObject() const
/// Return moved attribute
AttributePtr movedAttribute() const
{ return myMovedAttribute; }
+ /// Return index of the moved point
+ int movedPointIndex() const
+ { return myMovedPointIndex; }
/// Set original mouse position
MODELAPI_EXPORT void setOriginalPosition(double theX, double theY);
PartSet_WidgetSketchLabel.h
PartSet_CenterPrs.h
PartSet_ExternalPointsMgr.h
- PartSet_TreeNodes.h
- PartSet_FieldStepPrs.h
+ PartSet_TreeNodes.h
+ PartSet_FieldStepPrs.h
+ PartSet_WidgetBSplinePoints.h
)
SET(PROJECT_MOC_HEADERS
PartSet_WidgetShapeSelector.h
PartSet_WidgetSketchCreator.h
PartSet_WidgetSketchLabel.h
+ PartSet_WidgetBSplinePoints.h
PartSet_ExternalPointsMgr.h
)
PartSet_WidgetSketchLabel.cpp
PartSet_CenterPrs.cpp
PartSet_ExternalPointsMgr.cpp
- PartSet_TreeNodes.cpp
- PartSet_FieldStepPrs.cpp
+ PartSet_TreeNodes.cpp
+ PartSet_FieldStepPrs.cpp
+ PartSet_WidgetBSplinePoints.cpp
)
SET(PROJECT_RESOURCES
#include "PartSet_Validators.h"
#include "PartSet_Tools.h"
#include "PartSet_PreviewPlanes.h"
+#include "PartSet_WidgetBSplinePoints.h"
#include "PartSet_WidgetPoint2d.h"
#include "PartSet_WidgetPoint2DFlyout.h"
#include "PartSet_WidgetShapeSelector.h"
aPointSelectorWgt->setSketcher(mySketchMgr->activeSketch());
aWgt = aPointSelectorWgt;
}
+ else if (theType == "sketch-bspline_selector") {
+ PartSet_WidgetBSplinePoints* aBSplineWgt =
+ new PartSet_WidgetBSplinePoints(theParent, aWorkshop, theWidgetApi);
+ aBSplineWgt->setSketch(mySketchMgr->activeSketch());
+ aWgt = aBSplineWgt;
+ }
else if (theType == WDG_DOUBLEVALUE_EDITOR) {
aWgt = new PartSet_WidgetEditor(theParent, aWorkshop, theWidgetApi);
} else if (theType == "export_file_selector") {
return std::shared_ptr<GeomAPI_Pnt2d>(new GeomAPI_Pnt2d(aX, anY));
}
+std::shared_ptr<GeomAPI_Pnt2d> PartSet_Tools::getPnt2d(const Handle(V3d_View)& theView,
+ const TopoDS_Shape& theShape,
+ const FeaturePtr& theSketch)
+{
+ GeomPnt2dPtr aPoint2D;
+ if (!theShape.IsNull() && theShape.ShapeType() == TopAbs_VERTEX) {
+ const TopoDS_Vertex& aVertex = TopoDS::Vertex(theShape);
+ if (!aVertex.IsNull()) {
+ // the case when the point is taken from the existing vertex
+ gp_Pnt aPoint = BRep_Tool::Pnt(aVertex);
+ double aX, aY;
+ PartSet_Tools::convertTo2D(aPoint, theSketch, theView, aX, aY);
+ aPoint2D.reset(new GeomAPI_Pnt2d(aX, aY));
+ }
+ }
+ return aPoint2D;
+}
+
FeaturePtr findFirstCoincidenceByData(const DataPtr& theData,
std::shared_ptr<GeomAPI_Pnt2d> thePoint)
{
/**
* Convertes parameters into a geom point
- * \theEvent a Qt event to find mouse position
+ * \param theEvent a Qt event to find mouse position
* \param theWindow view window to define eye of view
* \param theSketch to convert 3D point coordinates into coorditates of the sketch plane
*/
ModuleBase_IViewWindow* theWindow,
const FeaturePtr& theSketch);
+ /** Returns point 2d from selected shape
+ * \param theView a view window
+ * \param theShape a vertex shape
+ * \param theX an output value of X coordinate
+ * \param theY an output value of Y coordinate
+ */
+ static std::shared_ptr<GeomAPI_Pnt2d> getPnt2d(const Handle(V3d_View)& theView,
+ const TopoDS_Shape& theShape,
+ const FeaturePtr& theSketch);
+
/**
* Gets all references to the feature, take coincidence constraint features, get point 2d attributes
* and compare the point value to be equal with the given. Returns the first feature, which has
--- /dev/null
+// Copyright (C) 2019-2020 CEA/DEN, EDF R&D
+//
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2.1 of the License, or (at your option) any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+//
+// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
+//
+
+#include <PartSet_WidgetBSplinePoints.h>
+
+#include <PartSet_CenterPrs.h>
+#include <PartSet_ExternalObjectsMgr.h>
+#include <PartSet_Module.h>
+#include <PartSet_SketcherReentrantMgr.h>
+#include <PartSet_WidgetPoint2d.h>
+
+#include <XGUI_Tools.h>
+#include <XGUI_Workshop.h>
+#include <XGUI_Displayer.h>
+
+#include <ModuleBase_ISelection.h>
+#include <ModuleBase_IViewer.h>
+#include <ModuleBase_IViewWindow.h>
+#include <ModuleBase_LabelValue.h>
+#include <ModuleBase_Tools.h>
+#include <ModuleBase_ViewerPrs.h>
+#include <ModuleBase_WidgetValidator.h>
+#include <ModuleBase_WidgetValidated.h>
+
+#include <Config_Keywords.h>
+#include <Config_WidgetAPI.h>
+
+#include <Events_Loop.h>
+
+#include <ModelAPI_Events.h>
+#include <ModelAPI_AttributeDoubleArray.h>
+#include <ModelAPI_AttributeRefAttrList.h>
+#include <ModelAPI_CompositeFeature.h>
+
+#include <GeomDataAPI_Point2D.h>
+#include <GeomDataAPI_Point2DArray.h>
+
+#include <GeomAPI_Pnt2d.h>
+
+#include <SketchPlugin_ConstraintCoincidence.h>
+
+#include <QGridLayout>
+#include <QGroupBox>
+#include <QMouseEvent>
+
+static const double MaxCoordinate = 1e12;
+
+PartSet_WidgetBSplinePoints::PartSet_WidgetBSplinePoints(QWidget* theParent,
+ ModuleBase_IWorkshop* theWorkshop,
+ const Config_WidgetAPI* theData)
+: ModuleBase_ModelWidget(theParent, theData), myWorkshop(theWorkshop),
+ myValueIsCashed(false), myIsFeatureVisibleInCash(true),
+ myXValueInCash(0), myYValueInCash(0),
+ myPointIndex(0), myFinished(false)
+{
+ myRefAttribute = theData->getProperty("reference_attribute");
+
+ // the control should accept the focus, so the boolean flag is corrected to be true
+ myIsObligatory = true;
+ QString aPageName = translate(theData->getProperty(CONTAINER_PAGE_NAME));
+ myGroupBox = new QGroupBox(aPageName, theParent);
+ myGroupBox->setFlat(false);
+
+ bool aAcceptVariables = theData->getBooleanAttribute(DOUBLE_WDG_ACCEPT_EXPRESSIONS, true);
+
+ // B-spline weights attribute
+ myWeightsAttr = theData->getProperty("weights");
+
+ QGridLayout* aGroupLay = new QGridLayout(myGroupBox);
+ ModuleBase_Tools::adjustMargins(aGroupLay);
+ aGroupLay->setSpacing(4);
+ aGroupLay->setColumnStretch(1, 1);
+ createNextPoint();
+
+ QVBoxLayout* aLayout = new QVBoxLayout(this);
+ ModuleBase_Tools::zeroMargins(aLayout);
+ aLayout->addWidget(myGroupBox);
+ setLayout(aLayout);
+
+ myWidgetValidator = new ModuleBase_WidgetValidator(this, myWorkshop);
+ myExternalObjectMgr = new PartSet_ExternalObjectsMgr(theData->getProperty("use_external"),
+ theData->getProperty("can_create_external"), true);
+}
+
+void PartSet_WidgetBSplinePoints::createNextPoint()
+{
+ storeCurentValue();
+
+ QGridLayout* aGroupLay = dynamic_cast<QGridLayout*>(myGroupBox->layout());
+ int row = (int)(myXSpin.size() + myWeightSpin.size());
+
+ QString aPoleStr = tr("Pole %1");
+ aPoleStr = aPoleStr.arg(myXSpin.size() + 1);
+
+ QGroupBox* aPoleGroupBox = new QGroupBox(aPoleStr, myGroupBox);
+ QGridLayout* aPoleLay = new QGridLayout(aPoleGroupBox);
+ ModuleBase_Tools::adjustMargins(aPoleLay);
+ aPoleLay->setSpacing(2);
+ aPoleLay->setColumnStretch(1, 1);
+
+ myXSpin.push_back(new ModuleBase_LabelValue(aPoleGroupBox, tr("X")));
+ aPoleLay->addWidget(myXSpin.back(), 0, 1);
+ myYSpin.push_back(new ModuleBase_LabelValue(aPoleGroupBox, tr("Y")));
+ aPoleLay->addWidget(myYSpin.back(), 1, 1);
+
+ aGroupLay->addWidget(aPoleGroupBox, row, 1);
+
+ QString aWeightStr = tr("Weight %1");
+ aWeightStr = aWeightStr.arg(myWeightSpin.size() + 1);
+
+ myWeightSpin.push_back(new ModuleBase_LabelValue(myGroupBox, aWeightStr));
+ aGroupLay->addWidget(myWeightSpin.back(), ++row, 1);
+}
+
+void PartSet_WidgetBSplinePoints::removeLastPoint()
+{
+ QGridLayout* aGroupLay = dynamic_cast<QGridLayout*>(myGroupBox->layout());
+ aGroupLay->removeWidget(myWeightSpin.back());
+ myWeightSpin.pop_back();
+ aGroupLay->removeWidget(myYSpin.back());
+ aGroupLay->removeWidget(myXSpin.back());
+ aGroupLay->removeWidget(myXSpin.back()->parentWidget());
+ myYSpin.pop_back();
+ myXSpin.pop_back();
+
+ // update B-spline feature attributes
+ storeValueCustom();
+}
+
+bool PartSet_WidgetBSplinePoints::isValidSelectionCustom(const ModuleBase_ViewerPrsPtr& theValue)
+{
+ bool aValid = true;
+
+ PartSet_Module* aModule = dynamic_cast<PartSet_Module*>(myWorkshop->module());
+ if (aModule->sketchReentranceMgr()->isInternalEditActive())
+ return true; // when internal edit is started a new feature is created. I has not results, AIS
+
+ // the selection is not possible if the current feature has no presentation for the current
+ // attribute not in AIS not in results. If so, no object in current feature where make
+ // coincidence, so selection is not necessary
+ GeomShapePtr anAISShape;
+ GeomPresentablePtr aPrs = std::dynamic_pointer_cast<GeomAPI_IPresentable>(myFeature);
+ if (aPrs.get()) {
+ AISObjectPtr anAIS;
+ anAIS = aPrs->getAISObject(anAIS);
+ if (anAIS.get()) {
+ anAISShape = anAIS->getShape();
+ }
+ }
+ const std::list<std::shared_ptr<ModelAPI_Result> >& aResults = myFeature->results();
+ if (!anAISShape.get() && aResults.empty())
+ return true;
+
+ AttributeRefAttrListPtr aRefAttrList = attributeRefAttrList();
+ if (aRefAttrList)
+ return isValidSelectionForAttribute_(theValue, myFeature->attribute(attributeID()));
+ return true;
+}
+
+bool PartSet_WidgetBSplinePoints::isValidSelectionForAttribute_(
+ const ModuleBase_ViewerPrsPtr& theValue,
+ const AttributePtr& theAttribute)
+{
+ bool aValid = false;
+
+ // stores the current values of the widget attribute
+ bool isFlushesActived, isAttributeSetInitializedBlocked, isAttributeSendUpdatedBlocked;
+
+ AttributeRefAttrListPtr aRefAttrList = attributeRefAttrList();
+ ModuleBase_WidgetValidated::blockFeatureAttribute(aRefAttrList, myFeature, true,
+ isFlushesActived, isAttributeSetInitializedBlocked, isAttributeSendUpdatedBlocked);
+ myWidgetValidator->storeAttributeValue(aRefAttrList);
+
+ // saves the owner value to the widget attribute
+ aValid = setSelectionCustom(theValue);
+ if (aValid)
+ // checks the attribute validity
+ aValid = myWidgetValidator->isValidAttribute(theAttribute);
+
+ // restores the current values of the widget attribute
+ myWidgetValidator->restoreAttributeValue(aRefAttrList, aValid);
+ myExternalObjectMgr->removeExternal(sketch(), myFeature, myWorkshop, true);
+
+ ModuleBase_WidgetValidated::blockFeatureAttribute(aRefAttrList, myFeature, false,
+ isFlushesActived, isAttributeSetInitializedBlocked, isAttributeSendUpdatedBlocked);
+ return aValid;
+}
+
+bool PartSet_WidgetBSplinePoints::setSelectionCustom(const ModuleBase_ViewerPrsPtr& theValue)
+{
+ bool isDone = false;
+ GeomShapePtr aShape = theValue->shape();
+ if (aShape.get() && !aShape->isNull()) {
+ Handle(V3d_View) aView = myWorkshop->viewer()->activeView();
+ const TopoDS_Shape& aTDShape = aShape->impl<TopoDS_Shape>();
+ GeomPnt2dPtr aPnt = PartSet_Tools::getPnt2d(aView, aTDShape, mySketch);
+ if (aPnt) {
+ fillRefAttribute(aPnt, theValue);
+ isDone = true;
+ }
+ else if (aTDShape.ShapeType() == TopAbs_EDGE) {
+ fillRefAttribute(theValue);
+ isDone = true;
+ }
+ }
+ return isDone;
+}
+
+static void fillLabels(std::vector<ModuleBase_LabelValue*>& theLabels, const double theValue)
+{
+ for (std::vector<ModuleBase_LabelValue*>::iterator anIt = theLabels.begin();
+ anIt != theLabels.end(); ++anIt)
+ (*anIt)->setValue(theValue);
+}
+
+bool PartSet_WidgetBSplinePoints::resetCustom()
+{
+ bool aDone = false;
+ if (!isUseReset() || isComputedDefault())
+ aDone = false;
+ else {
+ if (myValueIsCashed) {
+ // if the restored value should be hidden, aDone = true to set
+ // reset state for the widget in the parent
+ aDone = restoreCurentValue();
+ emit objectUpdated();
+ }
+ else {
+ // it is important to block the spin box control in order to do not through out the
+ // locking of the validating state.
+ fillLabels(myXSpin, 0.0);
+ fillLabels(myYSpin, 0.0);
+ fillLabels(myWeightSpin, 1.0);
+
+ storeValueCustom();
+ aDone = true;
+ }
+ }
+ return aDone;
+}
+
+PartSet_WidgetBSplinePoints::~PartSet_WidgetBSplinePoints()
+{
+ delete myExternalObjectMgr;
+}
+
+bool PartSet_WidgetBSplinePoints::setPoint(double theX, double theY)
+{
+ if (fabs(theX) >= MaxCoordinate || fabs(theY) >= MaxCoordinate)
+ return false;
+
+ myXSpin.back()->setValue(theX);
+ myYSpin.back()->setValue(theY);
+ myWeightSpin.back()->setValue(1.0);
+
+ storeValue();
+ return true;
+}
+
+void PartSet_WidgetBSplinePoints::storePolesAndWeights() const
+{
+ std::shared_ptr<ModelAPI_Data> aData = myFeature->data();
+ AttributePoint2DArrayPtr aPointArray = std::dynamic_pointer_cast<GeomDataAPI_Point2DArray>(
+ aData->attribute(attributeID()));
+ AttributeDoubleArrayPtr aWeightsArray = aData->realArray(myWeightsAttr);
+
+ aPointArray->setSize((int)myXSpin.size());
+ aWeightsArray->setSize((int)myWeightSpin.size());
+
+ std::vector<ModuleBase_LabelValue*>::const_iterator aXIt = myXSpin.begin();
+ std::vector<ModuleBase_LabelValue*>::const_iterator aYIt = myYSpin.begin();
+ for (int anIndex = 0; aXIt != myXSpin.end() && aYIt != myYSpin.end(); ++anIndex, ++aXIt, ++aYIt)
+ aPointArray->setPnt(anIndex, (*aXIt)->value(), (*aYIt)->value());
+
+ std::vector<ModuleBase_LabelValue*>::const_iterator aWIt = myWeightSpin.begin();
+ for (int anIndex = 0; aWIt != myWeightSpin.end(); ++anIndex, ++aWIt)
+ aWeightsArray->setValue(anIndex, (*aWIt)->value());
+}
+
+bool PartSet_WidgetBSplinePoints::storeValueCustom()
+{
+ std::shared_ptr<ModelAPI_Data> aData = myFeature->data();
+ if (!aData || !aData->isValid()) // can be on abort of sketcher element
+ return false;
+ AttributePoint2DArrayPtr aPointArray = std::dynamic_pointer_cast<GeomDataAPI_Point2DArray>(
+ aData->attribute(attributeID()));
+ AttributeDoubleArrayPtr aWeightsArray = aData->realArray(myWeightsAttr);
+
+ PartSet_WidgetBSplinePoints* that = (PartSet_WidgetBSplinePoints*) this;
+ bool isBlocked = that->blockSignals(true);
+ bool isImmutable = aPointArray->setImmutable(true);
+
+ if (myFeature->isMacro()) {
+ // Moving points of macro-features has been processed directly (without solver)
+ storePolesAndWeights();
+ updateObject(myFeature);
+
+ } else {
+ if (!aPointArray->isInitialized()) {
+ storePolesAndWeights();
+ }
+
+ std::shared_ptr<ModelAPI_ObjectMovedMessage> aMessage(
+ new ModelAPI_ObjectMovedMessage(this));
+ aMessage->setMovedAttribute(aPointArray, aPointArray->size() - 1);
+ aMessage->setOriginalPosition(aPointArray->pnt(aPointArray->size() - 1));
+ aMessage->setCurrentPosition(myXSpin.back()->value(), myYSpin.back()->value());
+ Events_Loop::loop()->send(aMessage);
+ }
+
+ aPointArray->setImmutable(isImmutable);
+ that->blockSignals(isBlocked);
+
+ return true;
+}
+
+bool PartSet_WidgetBSplinePoints::restoreValueCustom()
+{
+ std::shared_ptr<ModelAPI_Data> aData = myFeature->data();
+ AttributePoint2DArrayPtr aPointArray = std::dynamic_pointer_cast<GeomDataAPI_Point2DArray>(
+ aData->attribute(attributeID()));
+ AttributeDoubleArrayPtr aWeightsArray = aData->realArray(myWeightsAttr);
+
+ if (aPointArray->isInitialized()) {
+ while (myXSpin.size() < aPointArray->size())
+ createNextPoint();
+
+ std::vector<ModuleBase_LabelValue*>::iterator aXIt = myXSpin.begin();
+ std::vector<ModuleBase_LabelValue*>::iterator aYIt = myYSpin.begin();
+ for (int anIndex = 0; aXIt != myXSpin.end() && aYIt != myYSpin.end();
+ ++anIndex, ++aXIt, ++aYIt) {
+ GeomPnt2dPtr aPoint = aPointArray->pnt(anIndex);
+ (*aXIt)->setValue(aPoint->x());
+ (*aYIt)->setValue(aPoint->y());
+ }
+
+ std::vector<ModuleBase_LabelValue*>::iterator aWIt = myWeightSpin.begin();
+ for (int anIndex = 0; aWIt != myWeightSpin.end(); ++anIndex, ++aWIt)
+ (*aWIt)->setValue(aWeightsArray->value(anIndex));
+ }
+ else {
+ if (myXSpin.empty())
+ createNextPoint();
+
+ myXSpin.back()->setValue(0.0);
+ myYSpin.back()->setValue(0.0);
+ myWeightSpin.back()->setValue(0.0);
+ }
+
+ return true;
+}
+
+static void storeArray(const std::vector<ModuleBase_LabelValue*>& theLabels,
+ std::vector<double>& theValues)
+{
+ theValues.clear();
+ theValues.reserve(theLabels.size());
+ for (std::vector<ModuleBase_LabelValue*>::const_iterator anIt = theLabels.begin();
+ anIt != theLabels.end(); ++anIt)
+ theValues.push_back((*anIt)->value());
+}
+
+void PartSet_WidgetBSplinePoints::storeCurentValue()
+{
+ myValueIsCashed = true;
+ myIsFeatureVisibleInCash = XGUI_Displayer::isVisible(
+ XGUI_Tools::workshop(myWorkshop)->displayer(), myFeature);
+
+ storeArray(myXSpin, myXValueInCash);
+ storeArray(myYSpin, myYValueInCash);
+ storeArray(myWeightSpin, myWeightInCash);
+}
+
+static void restoreArray(std::vector<double>& theCacheValues,
+ std::vector<ModuleBase_LabelValue*>& theLabels)
+{
+ std::vector<double>::iterator aCIt = theCacheValues.begin();
+ std::vector<ModuleBase_LabelValue*>::iterator anIt = theLabels.begin();
+ for (; anIt != theLabels.end(); ++anIt) {
+ if (aCIt != theCacheValues.end())
+ (*anIt)->setValue(*aCIt++);
+ else
+ (*anIt)->setValue(0.0);
+ }
+ theCacheValues.clear();
+}
+
+bool PartSet_WidgetBSplinePoints::restoreCurentValue()
+{
+ bool aRestoredAndHidden = true;
+
+ bool isVisible = myIsFeatureVisibleInCash;
+
+ myValueIsCashed = false;
+ myIsFeatureVisibleInCash = true;
+ // fill the control widgets by the cashed value
+ restoreArray(myXValueInCash, myXSpin);
+ restoreArray(myYValueInCash, myYSpin);
+ restoreArray(myWeightInCash, myWeightSpin);
+
+ // store value to the model
+ storeValueCustom();
+ if (isVisible) {
+ setValueState(Stored);
+ aRestoredAndHidden = false;
+ }
+ else
+ aRestoredAndHidden = true;
+
+ return aRestoredAndHidden;
+}
+
+QList<QWidget*> PartSet_WidgetBSplinePoints::getControls() const
+{
+ QList<QWidget*> aControls;
+ std::vector<ModuleBase_LabelValue*>::const_iterator aXIt = myXSpin.begin();
+ std::vector<ModuleBase_LabelValue*>::const_iterator aYIt = myYSpin.begin();
+ std::vector<ModuleBase_LabelValue*>::const_iterator aWIt = myWeightSpin.begin();
+ for (; aXIt != myXSpin.end() && aYIt != myYSpin.end() && aWIt != myWeightSpin.end();
+ ++aXIt, ++aYIt, ++aWIt) {
+ aControls.append(*aXIt);
+ aControls.append(*aYIt);
+ aControls.append(*aWIt);
+ }
+ return aControls;
+}
+
+void PartSet_WidgetBSplinePoints::selectionModes(int& theModuleSelectionModes, QIntList& theModes)
+{
+ theModuleSelectionModes = -1;
+ theModes << TopAbs_VERTEX;
+ theModes << TopAbs_EDGE;
+}
+
+void PartSet_WidgetBSplinePoints::deactivate()
+{
+ // the value of the control should be stored to model if it was not
+ // initialized yet. It is important when we leave this control by Tab key.
+ // It should not be performed by the widget activation as the preview
+ // is visualized with default value. Line point is moved to origin.
+ AttributePtr anAttribute = myFeature->data()->attribute(attributeID());
+ if (anAttribute && !anAttribute->isInitialized())
+ storeValue();
+
+ ModuleBase_ModelWidget::deactivate();
+}
+
+void PartSet_WidgetBSplinePoints::mouseReleased(ModuleBase_IViewWindow* theWindow, QMouseEvent* theEvent)
+{
+ // the contex menu release by the right button should not be processed by this widget
+ if (theEvent->button() != Qt::LeftButton)
+ return;
+
+ ModuleBase_ISelection* aSelection = myWorkshop->selection();
+ Handle(V3d_View) aView = theWindow->v3dView();
+
+ QList<ModuleBase_ViewerPrsPtr> aList = aSelection->getSelected(ModuleBase_ISelection::Viewer);
+ ModuleBase_ViewerPrsPtr aFirstValue =
+ aList.size() > 0 ? aList.first() : ModuleBase_ViewerPrsPtr();
+ if (!aFirstValue.get() && myPreSelected.get()) {
+ aFirstValue = myPreSelected;
+ }
+
+ TopoDS_Shape aSelectedShape;
+ ObjectPtr aSelectedObject;
+
+ // if we have selection and use it
+ if (aFirstValue.get() && isValidSelectionCustom(aFirstValue) &&
+ aFirstValue->shape().get()) { // Trihedron Axis may be selected, but shape is empty
+ GeomShapePtr aGeomShape = aFirstValue->shape();
+ aSelectedShape = aGeomShape->impl<TopoDS_Shape>();
+ aSelectedObject = aFirstValue->object();
+
+ FeaturePtr aSelectedFeature = ModelAPI_Feature::feature(aSelectedObject);
+ std::shared_ptr<SketchPlugin_Feature> aSPFeature;
+ if (aSelectedFeature.get())
+ aSPFeature = std::dynamic_pointer_cast<SketchPlugin_Feature>(aSelectedFeature);
+
+ bool isSketchExternalFeature = aSPFeature.get() && aSPFeature->isExternal();
+ if ((!aSPFeature && !aSelectedShape.IsNull()) || isSketchExternalFeature) {
+ ObjectPtr aFixedObject =
+ PartSet_Tools::findFixedObjectByExternal(aSelectedShape, aSelectedObject, mySketch);
+ if (aFixedObject)
+ aSelectedObject = aFixedObject;
+ else if (!isSketchExternalFeature) {
+ FeaturePtr aCreatedFeature;
+ aSelectedObject = PartSet_Tools::createFixedObjectByExternal(
+ aGeomShape, aSelectedObject, mySketch, false, aCreatedFeature);
+ }
+ }
+ }
+ // The selection could be a center of an external circular object
+ else if (aFirstValue.get() && (!aFirstValue->interactive().IsNull())) {
+ Handle(PartSet_CenterPrs) aAIS =
+ Handle(PartSet_CenterPrs)::DownCast(aFirstValue->interactive());
+ if (!aAIS.IsNull()) {
+ gp_Pnt aPntComp = aAIS->Component()->Pnt();
+ GeomVertexPtr aVertPtr(new GeomAPI_Vertex(aPntComp.X(), aPntComp.Y(), aPntComp.Z()));
+ aSelectedShape = aVertPtr->impl<TopoDS_Shape>();
+
+ aSelectedObject =
+ PartSet_Tools::findFixedObjectByExternal(aSelectedShape, aAIS->object(), mySketch);
+ if (!aSelectedObject.get())
+ {
+ FeaturePtr aCreatedFeature;
+ aSelectedObject = PartSet_Tools::createFixedByExternalCenter(aAIS->object(), aAIS->edge(),
+ aAIS->centerType(), mySketch, false, aCreatedFeature);
+ }
+ }
+ }
+
+ GeomPnt2dPtr aSelectedPoint = PartSet_Tools::getPnt2d(aView, aSelectedShape, mySketch);
+ if (aSelectedPoint) {
+ // nullify selected object to add reference to attribute instead of its owner
+ aSelectedObject = ObjectPtr();
+ }
+ else {
+ aSelectedPoint = PartSet_Tools::getPnt2d(theEvent, theWindow, mySketch);
+ setValueState(Stored); // in case of edge selection, Apply state should also be updated
+ }
+ if (aSelectedObject)
+ fillRefAttribute(aSelectedObject);
+ else
+ fillRefAttribute(aSelectedPoint, aFirstValue);
+
+ // next pole of B-spline
+ createNextPoint();
+}
+
+void PartSet_WidgetBSplinePoints::mouseMoved(ModuleBase_IViewWindow* theWindow, QMouseEvent* theEvent)
+{
+ PartSet_Module* aModule = dynamic_cast<PartSet_Module*>(myWorkshop->module());
+
+ if (myFinished || isEditingMode() || aModule->sketchReentranceMgr()->isInternalEditActive())
+ return;
+
+ gp_Pnt aPoint = PartSet_Tools::convertClickToPoint(theEvent->pos(), theWindow->v3dView());
+
+ double aX = 0, aY = 0;
+ PartSet_Tools::convertTo2D(aPoint, mySketch, theWindow->v3dView(), aX, aY);
+ if (myState != ModifiedInViewer)
+ storeCurentValue();
+ // we need to block the value state change
+ bool isBlocked = blockValueState(true);
+ setPoint(aX, aY);
+ blockValueState(isBlocked);
+ setValueState(ModifiedInViewer);
+}
+
+bool PartSet_WidgetBSplinePoints::processEscape()
+{
+ bool isProcessed = !isEditingMode();
+ if (isProcessed) {
+ // remove widgets corrsponding to the last pole/weight of B-spline
+ removeLastPoint();
+ myFinished = true;
+
+ emit focusOutWidget(this);
+ }
+ return isProcessed;
+}
+
+bool PartSet_WidgetBSplinePoints::useSelectedShapes() const
+{
+ return true;
+}
+
+AttributeRefAttrListPtr PartSet_WidgetBSplinePoints::attributeRefAttrList() const
+{
+ if (myRefAttribute.empty())
+ return AttributeRefAttrListPtr();
+
+ AttributePtr anAttributeRef = feature()->attribute(myRefAttribute);
+ if (!anAttributeRef.get())
+ return AttributeRefAttrListPtr();
+
+ return std::dynamic_pointer_cast<ModelAPI_AttributeRefAttrList>(anAttributeRef);
+}
+
+void PartSet_WidgetBSplinePoints::fillRefAttribute(GeomPnt2dPtr theClickedPoint,
+ const std::shared_ptr<ModuleBase_ViewerPrs>& theValue)
+{
+ AttributeRefAttrListPtr aRefAttrList = attributeRefAttrList();
+ if (!aRefAttrList.get())
+ return;
+
+ FeaturePtr aFeature = feature();
+ std::string anAttribute = attributeID();
+
+ if (aFeature.get()) {
+ AttributePoint2DPtr aClickedFeaturePoint =
+ PartSet_WidgetPoint2D::findFirstEqualPointInSketch(mySketch, aFeature, theClickedPoint);
+ if (aClickedFeaturePoint.get())
+ aRefAttrList->append(aClickedFeaturePoint);
+ else
+ fillRefAttribute(theValue);
+ }
+}
+
+void PartSet_WidgetBSplinePoints::fillRefAttribute(const ModuleBase_ViewerPrsPtr& theValue)
+{
+ ObjectPtr anObject;
+ if (theValue)
+ anObject = getGeomSelection(theValue);
+ fillRefAttribute(anObject);
+}
+
+void PartSet_WidgetBSplinePoints::fillRefAttribute(const ObjectPtr& theObject)
+{
+ AttributeRefAttrListPtr aRefAttrList = attributeRefAttrList();
+ if (aRefAttrList.get())
+ aRefAttrList->append(theObject);
+}
+
+ObjectPtr PartSet_WidgetBSplinePoints::getGeomSelection(const ModuleBase_ViewerPrsPtr& theValue)
+{
+ ObjectPtr anObject;
+ GeomShapePtr aShape;
+ ModuleBase_ISelection* aSelection = myWorkshop->selection();
+ anObject = aSelection->getResult(theValue);
+ aShape = aSelection->getShape(theValue);
+ myExternalObjectMgr->getGeomSelection(theValue, anObject, aShape, myWorkshop, sketch(), true);
+
+ return anObject;
+}
--- /dev/null
+// Copyright (C) 2019-2020 CEA/DEN, EDF R&D
+//
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2.1 of the License, or (at your option) any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+//
+// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
+//
+
+#ifndef PartSet_WidgetBSplinePoints_H
+#define PartSet_WidgetBSplinePoints_H
+
+#include "PartSet.h"
+#include "PartSet_MouseProcessor.h"
+
+#include <ModuleBase_ModelWidget.h>
+
+#include <QObject>
+
+class GeomAPI_Pnt2d;
+class ModelAPI_CompositeFeature;
+class ModuleBase_LabelValue;
+class PartSet_ExternalObjectsMgr;
+class QGroupBox;
+
+/**\class PartSet_WidgetBSplinePoints
+ * \ingroup Modules
+ * \brief Implementation of model widget to provide widget to input a list of 2D poles
+ * of B-spline curve in association with weights
+ * In XML can be defined as following:
+ * \code
+ * <sketch-bspline_selector id="poles" weights="weights"/>
+ * \endcode
+ */
+class PARTSET_EXPORT PartSet_WidgetBSplinePoints : public ModuleBase_ModelWidget,
+ public PartSet_MouseProcessor
+{
+Q_OBJECT
+public:
+ /// Constructor
+ /// \param theParent the parent object
+ /// \param theWorkshop a current workshop
+ /// \param theData the widget configuation. The attribute of the model widget is obtained from
+ PartSet_WidgetBSplinePoints(QWidget* theParent, ModuleBase_IWorkshop* theWorkshop,
+ const Config_WidgetAPI* theData);
+ /// Destructor
+ virtual ~PartSet_WidgetBSplinePoints();
+
+ /// Fills given container with selection modes if the widget has it
+ /// \param [out] theModuleSelectionModes module additional modes, -1 means all default modes
+ /// \param theModes [out] a container of modes
+ virtual void selectionModes(int& theModuleSelectionModes, QIntList& theModes);
+
+ /// Checks if the selection presentation is valid in widget
+ /// \param theValue a selected presentation in the view
+ /// \return a boolean value
+ virtual bool isValidSelectionCustom(const std::shared_ptr<ModuleBase_ViewerPrs>& theValue);
+
+ /// Checks all attribute validators returns valid. It tries on the given 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
+ /// \param theAttribute the attribute
+ /// \return a boolean value
+ bool isValidSelectionForAttribute_(const std::shared_ptr<ModuleBase_ViewerPrs>& theValue,
+ const std::shared_ptr<ModelAPI_Attribute>& theAttribute);
+
+ /// Fills the attribute with the value of the selected owner
+ /// \param thePrs a selected owner
+ bool setSelectionCustom(const std::shared_ptr<ModuleBase_ViewerPrs>& theValue);
+
+ /// Returns list of widget controls
+ /// \return a control list
+ virtual QList<QWidget*> getControls() const;
+
+ /// The methiod called when widget is deactivated
+ virtual void deactivate();
+
+ /// \returns the sketch instance
+ std::shared_ptr<ModelAPI_CompositeFeature> sketch() const { return mySketch; }
+
+ /// Set sketch instance
+ void setSketch(std::shared_ptr<ModelAPI_CompositeFeature> theSketch) { mySketch = theSketch; }
+
+ /// Fill the widget values by given point
+ /// \param theX the X coordinate
+ /// \param theY the Y coordinate
+ /// \returns True in case of success
+ bool setPoint(double theX, double theY);
+
+ /// Returns true if the event is processed.
+ virtual bool processEscape();
+
+ /// Returns true if the attribute can be changed using the selected shapes in the viewer
+ /// and creating a coincidence constraint to them. This control use them.
+ virtual bool useSelectedShapes() const;
+
+ /// 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);
+
+protected:
+ /// Saves the internal parameters to the given feature
+ /// \return True in success
+ virtual bool storeValueCustom();
+
+ /// Restore value from attribute data to the widget's control
+ virtual bool restoreValueCustom();
+
+ /// Store current value in cashed value
+ void storeCurentValue();
+
+ /// Restore cashed value in the model attribute
+ /// \return boolean state if the restored feature shoud be hidden
+ bool restoreCurentValue();
+
+ /// Fills the widget with default values
+ /// \return true if the widget current value is reset
+ virtual bool resetCustom();
+
+private:
+ /// Create labels for the next B-spline point
+ void createNextPoint();
+ /// Remove labels for the last B-spline point
+ void removeLastPoint();
+
+ /// Save B-spline poles and weights to corresponding attributes
+ void storePolesAndWeights() const;
+
+ /// Returns attribute reference if the key is defined in XML definition of this control
+ /// \return found attribute or null
+ std::shared_ptr<ModelAPI_AttributeRefAttrList> attributeRefAttrList() const;
+
+ void fillRefAttribute(const std::shared_ptr<ModuleBase_ViewerPrs>& theValue);
+ void fillRefAttribute(std::shared_ptr<GeomAPI_Pnt2d> theClickedPoint,
+ const std::shared_ptr<ModuleBase_ViewerPrs>& theValue);
+ void fillRefAttribute(const ObjectPtr& theObject);
+
+ ObjectPtr getGeomSelection(const std::shared_ptr<ModuleBase_ViewerPrs>& theValue);
+
+protected:
+ ModuleBase_IWorkshop* myWorkshop; ///< workshop
+
+private:
+ QGroupBox* myGroupBox; ///< the parent group box for all intenal widgets
+ std::vector<ModuleBase_LabelValue*> myXSpin; ///< the label for the X coordinate
+ std::vector<ModuleBase_LabelValue*> myYSpin; ///< the label for the Y coordinate
+ std::vector<ModuleBase_LabelValue*> myWeightSpin; ///< the label for the weight
+ PartSet_ExternalObjectsMgr* myExternalObjectMgr; ///< reference to external objects manager
+
+ /// value used as selection in mouse release method
+ std::shared_ptr<ModuleBase_ViewerPrs> myPreSelected;
+
+ /// it is important during restart operation
+ CompositeFeaturePtr mySketch;
+
+ std::string myRefAttribute; /// if not empty, coincidences are not set but attribute is filled
+
+ bool myValueIsCashed; /// boolean state if the value is cashed during value state change
+ bool myIsFeatureVisibleInCash; /// boolean value if the feature was visible when cash if filled
+ std::vector<double> myXValueInCash; /// the cashed X value during value state change
+ std::vector<double> myYValueInCash; /// the cashed Y value during value state change
+ std::vector<double> myWeightInCash; /// the cached Weight value during valude state change
+
+ std::string myWeightsAttr;
+
+ int myPointIndex; /// index of the changing point
+
+ bool myFinished; /// \c true if building the B-spline is finished (escape pressed)
+};
+
+#endif
GeomShapePtr aShape = theValue->shape();
if (aShape.get() && !aShape->isNull()) {
Handle(V3d_View) aView = myWorkshop->viewer()->activeView();
- double aX = 0, aY = 0;
const TopoDS_Shape& aTDShape = aShape->impl<TopoDS_Shape>();
- if (getPoint2d(aView, aTDShape, aX, aY)) {
- fillRefAttribute(aX, aY, theValue);
+ GeomPnt2dPtr aPnt = PartSet_Tools::getPnt2d(aView, aTDShape, mySketch);
+ if (aPnt) {
+ fillRefAttribute(aPnt->x(), aPnt->y(), theValue);
isDone = true;
}
else if (aTDShape.ShapeType() == TopAbs_EDGE) {
GeomShapePtr aShape = aValue->shape();
if (aShape.get() && !aShape->isNull()) {
Handle(V3d_View) aView = myWorkshop->viewer()->activeView();
- double aX = 0, aY = 0;
const TopoDS_Shape& aTDShape = aShape->impl<TopoDS_Shape>();
- if (getPoint2d(aView, aTDShape, aX, aY)) {
- isDone = setPoint(aX, aY);
- setConstraintToPoint(aX, aY, aValue);
+ GeomPnt2dPtr aPnt = PartSet_Tools::getPnt2d(aView, aTDShape, mySketch);
+ if (aPnt) {
+ isDone = setPoint(aPnt->x(), aPnt->y());
+ setConstraintToPoint(aPnt->x(), aPnt->y(), aValue);
}
}
}
ModuleBase_ModelWidget::deactivate();
}
-bool PartSet_WidgetPoint2D::getPoint2d(const Handle(V3d_View)& theView,
- const TopoDS_Shape& theShape,
- double& theX, double& theY) const
-{
- if (!theShape.IsNull()) {
- if (theShape.ShapeType() == TopAbs_VERTEX) {
- const TopoDS_Vertex& aVertex = TopoDS::Vertex(theShape);
- if (!aVertex.IsNull()) {
- // A case when point is taken from existing vertex
- gp_Pnt aPoint = BRep_Tool::Pnt(aVertex);
- PartSet_Tools::convertTo2D(aPoint, mySketch, theView, theX, theY);
- return true;
- }
- }
- }
- return false;
-}
-
bool PartSet_WidgetPoint2D::setConstraintToPoint(double theClickedX, double theClickedY,
const std::shared_ptr<ModuleBase_ViewerPrs>& theValue)
{
}
}
if (anExternal) {
+ GeomPnt2dPtr aPnt = PartSet_Tools::getPnt2d(aView, aShape, mySketch);
double aX = 0, aY = 0;
- if (getPoint2d(aView, aShape, aX, aY) && isFeatureContainsPoint(myFeature, aX, aY)) {
+ if (aPnt) {
+ aX = aPnt->x();
+ aY = aPnt->y();
+ }
+ if (aPnt && isFeatureContainsPoint(myFeature, aX, aY)) {
// do not create a constraint to the point, which already used by the feature
// if the feature contains the point, focus is not switched
setPoint(aX, aY);
}
else {
- if (getPoint2d(aView, aShape, aX, aY))
+ if (aPnt)
setPoint(aX, aY);
else {
if (aShape.ShapeType() == TopAbs_EDGE) {
}
}
if (!anExternal) {
- double aX = 0, aY = 0;
bool isProcessed = false;
- if (getPoint2d(aView, aShape, aX, aY) && isFeatureContainsPoint(myFeature, aX, aY)) {
+ GeomPnt2dPtr aPnt = PartSet_Tools::getPnt2d(aView, aShape, mySketch);
+ if (aPnt && isFeatureContainsPoint(myFeature, aPnt->x(), aPnt->y())) {
// when the point is selected, the coordinates of the point should be set into the attribute
// if the feature contains the point, focus is not switched
- setPoint(aX, aY);
+ setPoint(aPnt->x(), aPnt->y());
}
else {
+ double aX = 0, aY = 0;
bool anOrphanPoint = isOrphanPoint(aSelectedFeature, mySketch, aX, aY);
// do not set a coincidence constraint in the attribute if the feature contains a point
// with the same coordinates. It is important for line creation in order to do not set
// the same constraints for the same points, oterwise the result line has zero length.
bool isAuxiliaryFeature = false;
- if (getPoint2d(aView, aShape, aX, aY)) {
+ if (aPnt) {
+ aX = aPnt->x();
+ aY = aPnt->y();
setPoint(aX, aY);
setConstraintToPoint(aX, aY, aFirstValue);
}
// external objects e.g. selection of trihedron axis when input end arc point
updateObject(feature());
- double aX = 0, aY = 0;
- if (getPoint2d(aView, aShape, aX, aY)) {
+ GeomPnt2dPtr aPnt = PartSet_Tools::getPnt2d(aView, aShape, mySketch);
+ if (aPnt) {
// do not create a constraint to the point, which already used by the feature
// if the feature contains the point, focus is not switched
- setPoint(aX, aY);
+ setPoint(aPnt->x(), aPnt->y());
}
emit vertexSelected(); // it stops the reentrant operation
emit focusOutWidget(this);
virtual void initializeValueByActivate();
private:
- /// Returns point 2d from selected vertex
- /// \param theView a view window
- /// \param theShape a vertex shape
- /// \param theX an output value of X coordinate
- /// \param theY an output value of Y coordinate
- bool getPoint2d(const Handle(V3d_View)& theView, const TopoDS_Shape& theShape,
- double& theX, double& theY) const;
-
/// Creates constrains of the clicked point
/// \param theClickedX the horizontal coordnate of the point
/// \param theClickedY the vertical coordnate of the point
/// \return true if succed
bool setConstraintToObject(const ObjectPtr& theObject);
+public:
/// Returns if the feature is an orphan point, circle or an arc. Returns true if it
/// has no a coincident to other lines. It processes point, circle and arc features
/// In circle an arc features, only centers are processed, for other points, it returns
const FeaturePtr& theSkipFeature,
const std::shared_ptr<GeomAPI_Pnt2d>& thePoint);
+private:
/// Returns attribute reference if the key is defined in XML definition of this control
/// \return found attribute or null
std::shared_ptr<ModelAPI_AttributeRefAttr> attributeRefAttr() const;
SET(PROJECT_HEADERS
SketchPlugin.h
SketchPlugin_Arc.h
+ SketchPlugin_BSpline.h
SketchPlugin_Circle.h
SketchPlugin_Constraint.h
SketchPlugin_ConstraintAngle.h
SketchPlugin_Line.h
SketchPlugin_MacroArc.h
SketchPlugin_MacroArcReentrantMessage.h
+ SketchPlugin_MacroBSpline.h
SketchPlugin_MacroCircle.h
SketchPlugin_MacroEllipse.h
SketchPlugin_MacroEllipticArc.h
SET(PROJECT_SOURCES
SketchPlugin_Arc.cpp
+ SketchPlugin_BSpline.cpp
SketchPlugin_Circle.cpp
SketchPlugin_Constraint.cpp
SketchPlugin_ConstraintAngle.cpp
SketchPlugin_IntersectionPoint.cpp
SketchPlugin_Line.cpp
SketchPlugin_MacroArc.cpp
+ SketchPlugin_MacroBSpline.cpp
SketchPlugin_MacroCircle.cpp
SketchPlugin_MacroEllipse.cpp
SketchPlugin_MacroEllipticArc.cpp
--- /dev/null
+// Copyright (C) 2019-2020 CEA/DEN, EDF R&D
+//
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2.1 of the License, or (at your option) any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+//
+// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
+//
+
+#include <SketchPlugin_BSpline.h>
+#include <SketchPlugin_Sketch.h>
+
+#include <GeomAlgoAPI_EdgeBuilder.h>
+
+////#include <GeomAPI_Dir2d.h>
+////#include <GeomAPI_Edge.h>
+////#include <GeomAPI_Ellipse.h>
+////#include <GeomAPI_Ellipse2d.h>
+#include <GeomAPI_Pnt2d.h>
+////#include <GeomAPI_XY.h>
+
+#include <GeomDataAPI_Point2DArray.h>
+
+#include <ModelAPI_AttributeDoubleArray.h>
+#include <ModelAPI_ResultConstruction.h>
+#include <ModelAPI_Session.h>
+#include <ModelAPI_Validator.h>
+
+////#include <cmath>
+////
+////static const double tolerance = 1e-7;
+////static const double paramTolerance = 1.e-4;
+////static const double PI = 3.141592653589793238463;
+
+
+SketchPlugin_BSpline::SketchPlugin_BSpline()
+ : SketchPlugin_SketchEntity()
+{
+}
+
+void SketchPlugin_BSpline::initDerivedClassAttributes()
+{
+ data()->addAttribute(POLES_ID(), GeomDataAPI_Point2DArray::typeId());
+ data()->addAttribute(WEIGHTS_ID(), ModelAPI_AttributeDoubleArray::typeId());
+
+ data()->addAttribute(EXTERNAL_ID(), ModelAPI_AttributeSelection::typeId());
+ ModelAPI_Session::get()->validators()->registerNotObligatory(getKind(), EXTERNAL_ID());
+}
+
+void SketchPlugin_BSpline::execute()
+{
+ SketchPlugin_Sketch* aSketch = sketch();
+ if(!aSketch) {
+ return;
+ }
+
+ AttributePoint2DArrayPtr aPolesArray =
+ std::dynamic_pointer_cast<GeomDataAPI_Point2DArray>(attribute(POLES_ID()));
+ AttributeDoubleArrayPtr aWeightsArray = data()->realArray(WEIGHTS_ID());
+
+ // convert poles to 3D
+ std::vector<GeomPointPtr> aPoles3D;
+ aPoles3D.reserve(aPolesArray->size());
+ for (int anIndex = 0; anIndex < aPolesArray->size(); ++anIndex) {
+ GeomPnt2dPtr aPole = aPolesArray->pnt(anIndex);
+ aPoles3D.push_back(aSketch->to3D(aPole->x(), aPole->y()));
+ }
+ // collect weights
+ std::vector<double> aWeights;
+ aWeights.reserve(aWeightsArray->size());
+ for (int anIndex = 0; anIndex < aWeightsArray->size(); ++anIndex)
+ aWeights.push_back(aWeightsArray->value(anIndex));
+
+ // create result non-periodic B-spline curve
+ GeomShapePtr anEdge = GeomAlgoAPI_EdgeBuilder::bspline(aPoles3D, aWeights, false);
+
+ ResultConstructionPtr aResult = document()->createConstruction(data(), 0);
+ aResult->setShape(anEdge);
+ aResult->setIsInHistory(false);
+ setResult(aResult, 0);
+}
+
+bool SketchPlugin_BSpline::isFixed() {
+ return data()->selection(EXTERNAL_ID())->context().get() != NULL;
+}
+
+void SketchPlugin_BSpline::attributeChanged(const std::string& theID) {
+ // the second condition for unability to move external segments anywhere
+ if (theID == EXTERNAL_ID() || isFixed()) {
+ std::shared_ptr<GeomAPI_Shape> aSelection = data()->selection(EXTERNAL_ID())->value();
+ if (!aSelection) {
+ // empty shape in selection shows that the shape is equal to context
+ ResultPtr anExtRes = selection(EXTERNAL_ID())->context();
+ if (anExtRes)
+ aSelection = anExtRes->shape();
+ }
+//// // update arguments due to the selection value
+//// if (aSelection && !aSelection->isNull() && aSelection->isEdge()) {
+//// std::shared_ptr<GeomAPI_Edge> anEdge(new GeomAPI_Edge(aSelection));
+//// std::shared_ptr<GeomAPI_Ellipse> anEllipse = anEdge->ellipse();
+////
+//// bool aWasBlocked = data()->blockSendAttributeUpdated(true);
+//// std::shared_ptr<GeomDataAPI_Point2D> aCenterAttr =
+//// std::dynamic_pointer_cast<GeomDataAPI_Point2D>(attribute(CENTER_ID()));
+//// aCenterAttr->setValue(sketch()->to2D(anEllipse->center()));
+////
+//// std::shared_ptr<GeomDataAPI_Point2D> aFocusAttr =
+//// std::dynamic_pointer_cast<GeomDataAPI_Point2D>(attribute(FIRST_FOCUS_ID()));
+//// aFocusAttr->setValue(sketch()->to2D(anEllipse->firstFocus()));
+////
+//// std::shared_ptr<GeomDataAPI_Point2D> aStartAttr =
+//// std::dynamic_pointer_cast<GeomDataAPI_Point2D>(attribute(START_POINT_ID()));
+//// aStartAttr->setValue(sketch()->to2D(anEdge->firstPoint()));
+////
+//// std::shared_ptr<GeomDataAPI_Point2D> aEndAttr =
+//// std::dynamic_pointer_cast<GeomDataAPI_Point2D>(attribute(END_POINT_ID()));
+//// aEndAttr->setValue(sketch()->to2D(anEdge->lastPoint()));
+////
+//// real(MAJOR_RADIUS_ID())->setValue(anEllipse->majorRadius());
+//// real(MINOR_RADIUS_ID())->setValue(anEllipse->minorRadius());
+////
+//// double aStartParam, aMidParam, aEndParam;
+//// anEllipse->parameter(anEdge->firstPoint(), tolerance, aStartParam);
+//// anEllipse->parameter(anEdge->middlePoint(), tolerance, aMidParam);
+//// anEllipse->parameter(anEdge->lastPoint(), tolerance, aEndParam);
+//// if (aEndParam < aStartParam)
+//// aEndParam += 2.0 * PI;
+//// if (aMidParam < aStartParam)
+//// aMidParam += 2.0 * PI;
+//// boolean(REVERSED_ID())->setValue(aMidParam > aEndParam);
+////
+//// data()->blockSendAttributeUpdated(aWasBlocked, false);
+////
+//// fillCharacteristicPoints();
+//// }
+ }
+//// else if (theID == CENTER_ID() || theID == FIRST_FOCUS_ID() ||
+//// theID == START_POINT_ID() || theID == END_POINT_ID())
+//// fillCharacteristicPoints();
+//// else if (theID == REVERSED_ID() && myParamDelta == 0.0)
+//// myParamDelta = 2.0 * PI;
+}
--- /dev/null
+// Copyright (C) 2019-2020 CEA/DEN, EDF R&D
+//
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2.1 of the License, or (at your option) any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+//
+// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
+//
+
+#ifndef SketchPlugin_BSpline_H_
+#define SketchPlugin_BSpline_H_
+
+#include <SketchPlugin.h>
+#include <SketchPlugin_SketchEntity.h>
+
+/**\class SketchPlugin_BSpline
+ * \ingroup Plugins
+ * \brief Feature for creation of the B-spline curve in the sketch.
+ */
+class SketchPlugin_BSpline : public SketchPlugin_SketchEntity
+{
+public:
+ /// Ellipse feature kind
+ inline static const std::string& ID()
+ {
+ static const std::string ID("SketchBSpline");
+ return ID;
+ }
+
+ /// list of B-spline poles
+ inline static const std::string& POLES_ID()
+ {
+ static const std::string ID("poles");
+ return ID;
+ }
+
+ /// list of B-spline weights
+ inline static const std::string& WEIGHTS_ID()
+ {
+ static const std::string ID("weights");
+ return ID;
+ }
+
+ /// Returns the kind of a feature
+ SKETCHPLUGIN_EXPORT virtual const std::string& getKind()
+ {
+ static std::string MY_KIND = SketchPlugin_BSpline::ID();
+ return MY_KIND;
+ }
+
+ /// Returns true is sketch element is under the rigid constraint
+ SKETCHPLUGIN_EXPORT virtual bool isFixed();
+
+ /// Called on change of any argument-attribute of this object
+ SKETCHPLUGIN_EXPORT virtual void attributeChanged(const std::string& theID);
+
+ /// Creates a new part document if needed
+ SKETCHPLUGIN_EXPORT virtual void execute();
+
+ /// Use plugin manager for features creation
+ SketchPlugin_BSpline();
+
+protected:
+ /// \brief Initializes attributes of derived class.
+ virtual void initDerivedClassAttributes();
+};
+
+#endif
#include "SketchPlugin_ConstraintCoincidenceInternal.h"
+#include <ModelAPI_AttributeInteger.h>
+#include <ModelAPI_Session.h>
+#include <ModelAPI_Validator.h>
+
SketchPlugin_ConstraintCoincidenceInternal::SketchPlugin_ConstraintCoincidenceInternal()
{
}
void SketchPlugin_ConstraintCoincidenceInternal::initAttributes()
{
SketchPlugin_ConstraintCoincidence::initAttributes();
+
+ data()->addAttribute(INDEX_ENTITY_A(), ModelAPI_AttributeInteger::typeId());
+ ModelAPI_Session::get()->validators()->registerNotObligatory(getKind(), INDEX_ENTITY_A());
+
+ data()->addAttribute(INDEX_ENTITY_B(), ModelAPI_AttributeInteger::typeId());
+ ModelAPI_Session::get()->validators()->registerNotObligatory(getKind(), INDEX_ENTITY_B());
}
void SketchPlugin_ConstraintCoincidenceInternal::execute()
class SketchPlugin_ConstraintCoincidenceInternal : public SketchPlugin_ConstraintCoincidence
{
public:
- /// Coincidence constraint kind
+ /// \brief Coincidence constraint kind
inline static const std::string& ID()
{
static const std::string MY_CONSTRAINT_COINCIDENCE_ID("SketchConstraintCoincidenceInternal");
return MY_KIND;
}
- /// Returns the AIS preview
+ /// \brief Index of point in the array if the first attribute is an array
+ inline static const std::string& INDEX_ENTITY_A()
+ {
+ static const std::string MY_INDEX("ConstraintEntityA_Index");
+ return MY_INDEX;
+ }
+ /// \brief Index of point in the array if the second attribute is an array
+ inline static const std::string& INDEX_ENTITY_B()
+ {
+ static const std::string MY_INDEX("ConstraintEntityB_Index");
+ return MY_INDEX;
+ }
+
+ /// \brief Returns the AIS preview
SKETCHPLUGIN_EXPORT virtual AISObjectPtr getAISObject(AISObjectPtr thePrevious);
/// \brief Creates a new part document if needed
--- /dev/null
+// Copyright (C) 2019-2020 CEA/DEN, EDF R&D
+//
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2.1 of the License, or (at your option) any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+//
+// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
+//
+
+#include <SketchPlugin_MacroBSpline.h>
+
+#include <SketchPlugin_BSpline.h>
+#include <SketchPlugin_ConstraintCoincidenceInternal.h>
+#include <SketchPlugin_Line.h>
+#include <SketchPlugin_Point.h>
+#include <SketchPlugin_Tools.h>
+#include <SketchPlugin_Sketch.h>
+
+#include <ModelAPI_AttributeDoubleArray.h>
+#include <ModelAPI_AttributeInteger.h>
+#include <ModelAPI_AttributeRefAttrList.h>
+#include <ModelAPI_Events.h>
+#include <ModelAPI_EventReentrantMessage.h>
+#include <ModelAPI_Session.h>
+#include <ModelAPI_Validator.h>
+
+#include <GeomDataAPI_Point2DArray.h>
+
+#include <GeomAlgoAPI_CompoundBuilder.h>
+#include <GeomAlgoAPI_EdgeBuilder.h>
+#include <GeomAlgoAPI_PointBuilder.h>
+
+#include <sstream>
+
+// Create Point feature coincident with the B-spline pole
+static FeaturePtr createAuxiliaryPole(FeaturePtr theBSpline,
+ AttributePoint2DArrayPtr theBSplinePoles,
+ const int thePoleIndex);
+// Create segment between consequtive B-spline poles
+static void createAuxiliarySegment(FeaturePtr theBSpline,
+ AttributePoint2DArrayPtr theBSplinePoles,
+ const int thePoleIndex1,
+ const int thePoleIndex2);
+// Create internal coincidence constraint with B-spline pole
+static void createInternalConstraint(SketchPlugin_Sketch* theSketch,
+ AttributePtr thePoint,
+ AttributePtr theBSplinePoles,
+ const int thePoleIndex);
+
+
+SketchPlugin_MacroBSpline::SketchPlugin_MacroBSpline()
+ : SketchPlugin_SketchEntity(),
+ myIsPeriodic(false)
+{
+}
+
+void SketchPlugin_MacroBSpline::initAttributes()
+{
+ data()->addAttribute(POLES_ID(), GeomDataAPI_Point2DArray::typeId());
+ data()->addAttribute(WEIGHTS_ID(), ModelAPI_AttributeDoubleArray::typeId());
+
+ data()->addAttribute(REF_POLES_ID(), ModelAPI_AttributeRefAttrList::typeId());
+ ModelAPI_Session::get()->validators()->registerNotObligatory(getKind(), REF_POLES_ID());
+
+ data()->addAttribute(AUXILIARY_ID(), ModelAPI_AttributeBoolean::typeId());
+}
+
+void SketchPlugin_MacroBSpline::execute()
+{
+ FeaturePtr aBSpline = createBSplineFeature();
+
+ std::list<FeaturePtr> aControlPoles;
+ createControlPolygon(aBSpline, aControlPoles);
+ constraintsForPoles(aControlPoles);
+
+ // message to init reentrant operation
+ static Events_ID anId = ModelAPI_EventReentrantMessage::eventId();
+ ReentrantMessagePtr aMessage(new ModelAPI_EventReentrantMessage(anId, this));
+ // set here the last pole to make coincidence with the start point of the next B-spline curve
+ aMessage->setCreatedFeature(aControlPoles.back());
+ Events_Loop::loop()->send(aMessage);
+}
+
+// LCOV_EXCL_START
+std::string SketchPlugin_MacroBSpline::processEvent(
+ const std::shared_ptr<Events_Message>& theMessage)
+{
+ ReentrantMessagePtr aReentrantMessage =
+ std::dynamic_pointer_cast<ModelAPI_EventReentrantMessage>(theMessage);
+ if (aReentrantMessage) {
+ FeaturePtr aCreatedFeature = aReentrantMessage->createdFeature();
+ ObjectPtr anObject = aReentrantMessage->selectedObject();
+ AttributePtr anAttribute = aReentrantMessage->selectedAttribute();
+ std::shared_ptr<GeomAPI_Pnt2d> aClickedPoint = aReentrantMessage->clickedPoint();
+
+ if (aClickedPoint) {
+ // fill points list (it consists of 2 points to make editable the second one)
+ AttributePoint2DArrayPtr aPointArrayAttr =
+ std::dynamic_pointer_cast<GeomDataAPI_Point2DArray>(attribute(POLES_ID()));
+ aPointArrayAttr->setSize(2);
+ aPointArrayAttr->setPnt(0, aClickedPoint);
+ aPointArrayAttr->setPnt(1, aClickedPoint);
+
+ // fill weights
+ AttributeDoubleArrayPtr aWeightsArrayAttr = data()->realArray(WEIGHTS_ID());
+ aWeightsArrayAttr->setSize(2);
+ aWeightsArrayAttr->setValue(0, 1.0);
+ aWeightsArrayAttr->setValue(1, 1.0);
+
+ // fill reference attribute
+ AttributeRefAttrListPtr aRefAttrList =
+ std::dynamic_pointer_cast<ModelAPI_AttributeRefAttrList>(attribute(REF_POLES_ID()));
+ if (anAttribute) {
+ if (!anAttribute->owner() || !anAttribute->owner()->data()->isValid()) {
+ if (aCreatedFeature && anAttribute->id() == SketchPlugin_Point::COORD_ID())
+ anAttribute = aCreatedFeature->attribute(SketchPlugin_Point::COORD_ID());
+ }
+ aRefAttrList->append(anAttribute);
+ }
+ }
+ Events_Loop::loop()->flush(Events_Loop::eventByName(EVENT_OBJECT_UPDATED));
+ }
+ return std::string();
+}
+// LCOV_EXCL_STOP
+
+FeaturePtr SketchPlugin_MacroBSpline::createBSplineFeature()
+{
+ FeaturePtr aBSpline = sketch()->addFeature(SketchPlugin_BSpline::ID());
+
+ AttributePoint2DArrayPtr aPoles = std::dynamic_pointer_cast<GeomDataAPI_Point2DArray>(
+ aBSpline->attribute(SketchPlugin_BSpline::POLES_ID()));
+ AttributePoint2DArrayPtr aPolesMacro =
+ std::dynamic_pointer_cast<GeomDataAPI_Point2DArray>(attribute(POLES_ID()));
+ aPoles->assign(aPolesMacro);
+
+ AttributeDoubleArrayPtr aWeights =
+ aBSpline->data()->realArray(SketchPlugin_BSpline::WEIGHTS_ID());
+ AttributeDoubleArrayPtr aWeightsMacro = data()->realArray(WEIGHTS_ID());
+ int aSize = aWeightsMacro->size();
+ aWeights->setSize(aSize);
+ for (int index = 0; index < aSize; ++index)
+ aWeights->setValue(index, aWeightsMacro->value(index));
+
+ aBSpline->boolean(SketchPlugin_BSpline::AUXILIARY_ID())->setValue(
+ boolean(AUXILIARY_ID())->value());
+
+ aBSpline->execute();
+
+ return aBSpline;
+}
+
+void SketchPlugin_MacroBSpline::createControlPolygon(FeaturePtr theBSpline,
+ std::list<FeaturePtr>& thePoles)
+{
+ AttributePoint2DArrayPtr aPoles = std::dynamic_pointer_cast<GeomDataAPI_Point2DArray>(
+ theBSpline->attribute(SketchPlugin_BSpline::POLES_ID()));
+ int aSize = aPoles->size();
+ // poles
+ for (int index = 0; index < aSize; ++index)
+ thePoles.push_back(createAuxiliaryPole(theBSpline, aPoles, index));
+ // segments
+ for (int index = 1; index < aSize; ++index)
+ createAuxiliarySegment(theBSpline, aPoles, index - 1, index);
+}
+
+void SketchPlugin_MacroBSpline::constraintsForPoles(const std::list<FeaturePtr>& thePoles)
+{
+ AttributeRefAttrListPtr aRefAttrList = data()->refattrlist(REF_POLES_ID());
+ std::list<std::pair<ObjectPtr, AttributePtr> > aList;
+ if (aRefAttrList)
+ aList = aRefAttrList->list();
+
+ SketchPlugin_Sketch* aSketch = sketch();
+
+ std::list<std::pair<ObjectPtr, AttributePtr> >::iterator aLIt = aList.begin();
+ std::list<FeaturePtr>::const_iterator aPIt = thePoles.begin();
+ for (; aLIt != aList.end() && aPIt != thePoles.end(); ++aPIt, ++aLIt) {
+ // firstly, check the attribute (in this case the object will be not empty too)
+ if (aLIt->second) {
+ SketchPlugin_Tools::createConstraintAttrAttr(aSketch,
+ SketchPlugin_ConstraintCoincidence::ID(),
+ (*aPIt)->attribute(SketchPlugin_Point::COORD_ID()), aLIt->second);
+ }
+ // now add coincidence with the result
+ else if (aLIt->first) {
+ SketchPlugin_Tools::createConstraintAttrObject(aSketch,
+ SketchPlugin_ConstraintCoincidence::ID(),
+ (*aPIt)->attribute(SketchPlugin_Point::COORD_ID()), aLIt->first);
+ }
+ }
+}
+
+AISObjectPtr SketchPlugin_MacroBSpline::getAISObject(AISObjectPtr thePrevious)
+{
+ SketchPlugin_Sketch* aSketch = sketch();
+ if (!aSketch)
+ return AISObjectPtr();
+
+ AttributePoint2DArrayPtr aPolesArray =
+ std::dynamic_pointer_cast<GeomDataAPI_Point2DArray>(attribute(POLES_ID()));
+ AttributeDoubleArrayPtr aWeightsArray = data()->realArray(WEIGHTS_ID());
+
+ std::list<GeomShapePtr> aShapes;
+
+ // convert poles to 3D and collect weights
+ std::vector<GeomPointPtr> aPoles3D;
+ aPoles3D.reserve(aPolesArray->size());
+ std::vector<double> aWeights;
+ aWeights.reserve(aWeightsArray->size());
+ for (int anIndex = 0; anIndex < aPolesArray->size(); ++anIndex) {
+ double aWeight = aWeightsArray->value(anIndex);
+ if (aWeight < 1.e-10)
+ continue; // skip poles with zero weights
+
+ aWeights.push_back(aWeight);
+
+ GeomPnt2dPtr aPole = aPolesArray->pnt(anIndex);
+ GeomPointPtr aPole3D = aSketch->to3D(aPole->x(), aPole->y());
+ aPoles3D.push_back(aPole3D);
+ aShapes.push_back(GeomAlgoAPI_PointBuilder::vertex(aPole3D));
+ }
+
+ // create result non-periodic B-spline curve
+ GeomShapePtr anEdge = GeomAlgoAPI_EdgeBuilder::bspline(aPoles3D, aWeights, false);
+ if (!anEdge)
+ return AISObjectPtr();
+
+ aShapes.push_back(anEdge);
+ GeomShapePtr aCompound = GeomAlgoAPI_CompoundBuilder::compound(aShapes);
+
+ AISObjectPtr anAIS = thePrevious;
+ if (!anAIS)
+ anAIS.reset(new GeomAPI_AISObject());
+ anAIS->createShape(aCompound);
+
+ // Modify attributes
+ SketchPlugin_Tools::customizeFeaturePrs(anAIS, boolean(AUXILIARY_ID())->value());
+
+ return anAIS;
+}
+
+
+
+// ========================== Auxiliary functions ===========================================
+
+FeaturePtr createAuxiliaryPole(FeaturePtr theBSpline,
+ AttributePoint2DArrayPtr theBSplinePoles,
+ const int thePoleIndex)
+{
+ SketchPlugin_Sketch* aSketch =
+ std::dynamic_pointer_cast<SketchPlugin_Feature>(theBSpline)->sketch();
+
+ // create child point equal to the B-spline's pole
+ FeaturePtr aPointFeature = aSketch->addFeature(SketchPlugin_Point::ID());
+ aPointFeature->boolean(SketchPlugin_Point::AUXILIARY_ID())->setValue(true);
+ aPointFeature->reference(SketchPlugin_Point::PARENT_ID())->setValue(theBSpline);
+
+ GeomPnt2dPtr aPole = theBSplinePoles->pnt(thePoleIndex);
+
+ AttributePoint2DPtr aCoord = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
+ aPointFeature->attribute(SketchPlugin_Point::COORD_ID()));
+ aCoord->setValue(aPole);
+
+ aPointFeature->execute();
+
+ std::ostringstream aName;
+ aName << theBSpline->name() << "_" << theBSplinePoles->id() << "_" << thePoleIndex;
+ aPointFeature->data()->setName(aName.str());
+ aPointFeature->lastResult()->data()->setName(aName.str());
+
+ // internal constraint to keep position of the point
+ createInternalConstraint(aSketch, aCoord, theBSplinePoles, thePoleIndex);
+
+ return aPointFeature;
+}
+
+void createAuxiliarySegment(FeaturePtr theBSpline,
+ AttributePoint2DArrayPtr theBSplinePoles,
+ const int thePoleIndex1,
+ const int thePoleIndex2)
+{
+ SketchPlugin_Sketch* aSketch =
+ std::dynamic_pointer_cast<SketchPlugin_Feature>(theBSpline)->sketch();
+
+ // create child segment between B-spline poles
+ FeaturePtr aLineFeature = aSketch->addFeature(SketchPlugin_Line::ID());
+ aLineFeature->boolean(SketchPlugin_Point::AUXILIARY_ID())->setValue(true);
+ aLineFeature->reference(SketchPlugin_Point::PARENT_ID())->setValue(theBSpline);
+
+ AttributePoint2DPtr aLineStart = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
+ aLineFeature->attribute(SketchPlugin_Line::START_ID()));
+ aLineStart->setValue(theBSplinePoles->pnt(thePoleIndex1));
+
+ AttributePoint2DPtr aLineEnd = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
+ aLineFeature->attribute(SketchPlugin_Line::END_ID()));
+ aLineEnd->setValue(theBSplinePoles->pnt(thePoleIndex2));
+
+ aLineFeature->execute();
+
+ std::ostringstream aName;
+ aName << theBSpline->name() << "_segment_" << thePoleIndex1 << "_" << thePoleIndex2;
+ aLineFeature->data()->setName(aName.str());
+ aLineFeature->lastResult()->data()->setName(aName.str());
+
+ // internal constraints to keep the segment position
+ createInternalConstraint(aSketch, aLineStart, theBSplinePoles, thePoleIndex1);
+ createInternalConstraint(aSketch, aLineEnd, theBSplinePoles, thePoleIndex2);
+}
+
+void createInternalConstraint(SketchPlugin_Sketch* theSketch,
+ AttributePtr thePoint,
+ AttributePtr theBSplinePoles,
+ const int thePoleIndex)
+{
+ std::shared_ptr<SketchPlugin_ConstraintCoincidenceInternal> aConstraint =
+ std::dynamic_pointer_cast<SketchPlugin_ConstraintCoincidenceInternal>(
+ theSketch->addFeature(SketchPlugin_ConstraintCoincidenceInternal::ID()));
+ aConstraint->refattr(SketchPlugin_Constraint::ENTITY_A())->setAttr(thePoint);
+ aConstraint->refattr(SketchPlugin_Constraint::ENTITY_B())->setAttr(theBSplinePoles);
+ aConstraint->integer(SketchPlugin_ConstraintCoincidenceInternal::INDEX_ENTITY_B())
+ ->setValue(thePoleIndex);
+}
--- /dev/null
+// Copyright (C) 2019-2020 CEA/DEN, EDF R&D
+//
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2.1 of the License, or (at your option) any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+//
+// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
+//
+
+#ifndef SketchPlugin_MacroBSpline_H_
+#define SketchPlugin_MacroBSpline_H_
+
+#include <ModelAPI_IReentrant.h>
+
+#include "SketchPlugin.h"
+
+#include "SketchPlugin_SketchEntity.h"
+
+#include <GeomAPI_IPresentable.h>
+
+class GeomAPI_Circ2d;
+class GeomAPI_Pnt2d;
+
+/**\class SketchPlugin_MacroBSpline
+ * \ingroup Plugins
+ * \brief Feature for creation of the new B-spline in Sketch.
+ */
+class SketchPlugin_MacroBSpline : public SketchPlugin_SketchEntity,
+ public GeomAPI_IPresentable,
+ public ModelAPI_IReentrant
+{
+public:
+ /// B-spline macro feature kind
+ inline static const std::string& ID()
+ {
+ static const std::string ID("SketchMacroBSpline");
+ return ID;
+ }
+
+
+ /// list of B-spline poles
+ inline static const std::string& POLES_ID()
+ {
+ static const std::string ID("poles");
+ return ID;
+ }
+
+ /// list of references of B-spline poles
+ inline static const std::string& REF_POLES_ID()
+ {
+ static const std::string ID("poles_ref");
+ return ID;
+ }
+
+ /// list of B-spline weights
+ inline static const std::string& WEIGHTS_ID()
+ {
+ static const std::string ID("weights");
+ return ID;
+ }
+
+ /// Returns the kind of a feature
+ SKETCHPLUGIN_EXPORT virtual const std::string& getKind()
+ {
+ static std::string MY_KIND = SketchPlugin_MacroBSpline::ID();
+ return MY_KIND;
+ }
+
+ /// \brief Request for initialization of data model of the feature: adding all attributes.
+ SKETCHPLUGIN_EXPORT virtual void initAttributes();
+
+ /// Returns the AIS preview
+ virtual AISObjectPtr getAISObject(AISObjectPtr thePrevious);
+
+ /// Creates a new part document if needed
+ SKETCHPLUGIN_EXPORT virtual void execute();
+
+ /// Reimplemented from ModelAPI_Feature::isMacro().
+ /// \returns true
+ SKETCHPLUGIN_EXPORT virtual bool isMacro() const {return true;};
+
+ SKETCHPLUGIN_EXPORT virtual bool isPreviewNeeded() const {return false;};
+
+ /// Apply information of the message to current object. It fills reference object,
+ /// tangent type and tangent point refence in case of tangent arc
+ virtual std::string processEvent(const std::shared_ptr<Events_Message>& theMessage);
+
+ /// Use plugin manager for features creation
+ SketchPlugin_MacroBSpline();
+
+private:
+ FeaturePtr createBSplineFeature();
+
+ void createControlPolygon(FeaturePtr theBSpline, std::list<FeaturePtr>& thePoles);
+ void constraintsForPoles(const std::list<FeaturePtr>& thePoles);
+
+ bool myIsPeriodic;
+};
+
+#endif
#include <SketchPlugin_IntersectionPoint.h>
#include <SketchPlugin_Circle.h>
#include <SketchPlugin_Arc.h>
+#include <SketchPlugin_BSpline.h>
#include <SketchPlugin_Projection.h>
#include <SketchPlugin_ConstraintAngle.h>
#include <SketchPlugin_ConstraintCoincidence.h>
#include <SketchPlugin_ConstraintTangent.h>
#include <SketchPlugin_ConstraintVertical.h>
#include <SketchPlugin_MacroArc.h>
+#include <SketchPlugin_MacroBSpline.h>
#include <SketchPlugin_MacroCircle.h>
#include <SketchPlugin_MultiRotation.h>
#include <SketchPlugin_MultiTranslation.h>
new SketchPlugin_SketchFeatureValidator);
aFactory->registerValidator("SketchPlugin_MultiRotationAngleValidator",
new SketchPlugin_MultiRotationAngleValidator);
+ aFactory->registerValidator("SketchPlugin_BSplineValidator",
+ new SketchPlugin_BSplineValidator);
// register this plugin
ModelAPI_Session::get()->registerPlugin(this);
return FeaturePtr(new SketchPlugin_Circle);
} else if (theFeatureID == SketchPlugin_Arc::ID()) {
return FeaturePtr(new SketchPlugin_Arc);
+ } else if (theFeatureID == SketchPlugin_BSpline::ID()) {
+ return FeaturePtr(new SketchPlugin_BSpline);
} else if (theFeatureID == SketchPlugin_Projection::ID()) {
return FeaturePtr(new SketchPlugin_Projection);
} else if (theFeatureID == SketchPlugin_ConstraintCoincidence::ID()) {
return FeaturePtr(new SketchPlugin_Trim);
} else if (theFeatureID == SketchPlugin_MacroArc::ID()) {
return FeaturePtr(new SketchPlugin_MacroArc);
+ } else if (theFeatureID == SketchPlugin_MacroBSpline::ID()) {
+ return FeaturePtr(new SketchPlugin_MacroBSpline);
} else if (theFeatureID == SketchPlugin_MacroCircle::ID()) {
return FeaturePtr(new SketchPlugin_MacroCircle);
} else if (theFeatureID == SketchPlugin_Ellipse::ID()) {
aMsg->setState(SketchPlugin_Line::ID(), aHasSketchPlane);
aMsg->setState(SketchPlugin_Circle::ID(), aHasSketchPlane);
aMsg->setState(SketchPlugin_Arc::ID(), aHasSketchPlane);
+ aMsg->setState(SketchPlugin_BSpline::ID(), aHasSketchPlane);
aMsg->setState(SketchPlugin_Ellipse::ID(), aHasSketchPlane);
aMsg->setState(SketchPlugin_EllipticArc::ID(), aHasSketchPlane);
aMsg->setState(SketchPlugin_Projection::ID(), aHasSketchPlane);
aMsg->setState(SketchPlugin_Split::ID(), aHasSketchPlane);
aMsg->setState(SketchPlugin_Trim::ID(), aHasSketchPlane);
aMsg->setState(SketchPlugin_MacroArc::ID(), aHasSketchPlane);
+ aMsg->setState(SketchPlugin_MacroBSpline::ID(), aHasSketchPlane);
aMsg->setState(SketchPlugin_MacroCircle::ID(), aHasSketchPlane);
aMsg->setState(SketchPlugin_MacroEllipse::ID(), aHasSketchPlane);
aMsg->setState(SketchPlugin_MacroEllipticArc::ID(), aHasSketchPlane);
#include <GeomAPI_Lin.h>
#include <GeomAPI_Edge.h>
#include <GeomAPI_Vertex.h>
+
#include <GeomDataAPI_Point2D.h>
+#include <GeomDataAPI_Point2DArray.h>
#include <algorithm>
#include <cmath>
return true;
}
+
+bool SketchPlugin_BSplineValidator::isValid(const AttributePtr& theAttribute,
+ const std::list<std::string>& theArguments,
+ Events_InfoMessage& theError) const
+{
+ AttributePoint2DArrayPtr aPolesArray =
+ std::dynamic_pointer_cast<GeomDataAPI_Point2DArray>(theAttribute);
+ if (!aPolesArray)
+ return false;
+
+ if (aPolesArray->size() < 2) {
+ theError = "Number of B-spline poles should be 2 and more";
+ return false;
+ }
+
+ return true;
+}
Events_InfoMessage& theError) const;
};
+/**\class SketchPlugin_BSplineValidator
+ * \ingroup Validators
+ * \brief Validator for checking poles/weights of B-spline curve.
+ */
+class SketchPlugin_BSplineValidator : public ModelAPI_AttributeValidator
+{
+ //! returns true if attribute is valid
+ //! \param theAttribute the checked attribute
+ //! \param theArguments arguments of the attribute
+ //! \param theError error message
+ virtual bool isValid(const AttributePtr& theAttribute,
+ const std::list<std::string>& theArguments,
+ Events_InfoMessage& theError) const;
+};
+
#endif
nested="SketchPoint SketchIntersectionPoint SketchLine
SketchCircle SketchMacroCircle SketchArc SketchMacroArc
SketchEllipse SketchMacroEllipse SketchEllipticArc SketchMacroEllipticArc
+ SketchBSpline SketchMacroBSpline
SketchRectangle
SketchProjection
SketchConstraintLength SketchConstraintRadius SketchConstraintDistance SketchConstraintDistanceHorizontal SketchConstraintDistanceVertical
</feature>
</group>
+ <group id="Parametric curves">
+ <!-- SketchBSpline is a hidden feature. It is created inside SketchMacroBSpline. -->
+ <feature id="SketchBSpline"
+ title="B-spline"
+ tooltip="Create B-spline curve"
+ icon="icons/Sketch/bspline.png"
+ helpfile="bsplineFeature.html"
+ internal="1">
+ <sketch-bspline_selector id="poles"
+ weights="weights"
+ title="Poles and weights"
+ tooltip="B-spline poles and weights"
+ enable_value="enable_by_preferences">
+ <validator id="SketchPlugin_BSplineValidator"/>
+ </sketch-bspline_selector>
+ <boolvalue id="Auxiliary"
+ label="Auxiliary"
+ default="false"
+ tooltip="Construction element"
+ obligatory="0"
+ change_visual_attributes="true"/>
+ </feature>
+
+ <!-- SketchMacroBSpline -->
+ <feature id="SketchMacroBSpline"
+ title="B-spline"
+ tooltip="Create B-spline curve"
+ icon="icons/Sketch/bspline.png"
+ helpfile="bsplineFeature.html">
+ <sketch-bspline_selector id="poles"
+ weights="weights"
+ reference_attribute="poles_ref"
+ title="Poles and weights"
+ tooltip="B-spline poles and weights"
+ enable_value="enable_by_preferences">
+ <validator id="SketchPlugin_BSplineValidator"/>
+ </sketch-bspline_selector>
+ <boolvalue id="Auxiliary"
+ label="Auxiliary"
+ default="false"
+ tooltip="Construction element"
+ obligatory="0"
+ change_visual_attributes="true"/>
+ </feature>
+ </group>
+
<group id="Segmentation">
<!-- SketchSplit -->
<feature id="SketchSplit" title="Split"
PlaneGCSSolver_EdgeWrapper.h
PlaneGCSSolver_EntityWrapper.h
PlaneGCSSolver_PointWrapper.h
+ PlaneGCSSolver_PointArrayWrapper.h
PlaneGCSSolver_ScalarWrapper.h
+ PlaneGCSSolver_ScalarArrayWrapper.h
PlaneGCSSolver_AngleWrapper.h
PlaneGCSSolver_BooleanWrapper.h
PlaneGCSSolver_Tools.h
PlaneGCSSolver_ConstraintWrapper.cpp
PlaneGCSSolver_EdgeWrapper.cpp
PlaneGCSSolver_PointWrapper.cpp
+ PlaneGCSSolver_PointArrayWrapper.cpp
PlaneGCSSolver_ScalarWrapper.cpp
+ PlaneGCSSolver_ScalarArrayWrapper.cpp
PlaneGCSSolver_AngleWrapper.cpp
PlaneGCSSolver_BooleanWrapper.cpp
PlaneGCSSolver_Tools.cpp
#include <PlaneGCSSolver_AngleWrapper.h>
#include <PlaneGCSSolver_AttributeBuilder.h>
+#include <PlaneGCSSolver_PointArrayWrapper.h>
#include <PlaneGCSSolver_PointWrapper.h>
#include <PlaneGCSSolver_ScalarWrapper.h>
+#include <PlaneGCSSolver_ScalarArrayWrapper.h>
#include <PlaneGCSSolver_BooleanWrapper.h>
+#include <GeomAPI_Pnt2d.h>
#include <GeomDataAPI_Point2D.h>
+#include <GeomDataAPI_Point2DArray.h>
#include <ModelAPI_AttributeDouble.h>
+#include <ModelAPI_AttributeDoubleArray.h>
#include <SketchPlugin_ConstraintAngle.h>
#include <SketchPlugin_MultiRotation.h>
return aWrapper;
}
+static EntityWrapperPtr createScalarArray(const AttributePtr& theAttribute,
+ PlaneGCSSolver_Storage* theStorage)
+{
+ AttributeDoubleArrayPtr anArray =
+ std::dynamic_pointer_cast<ModelAPI_AttributeDoubleArray>(theAttribute);
+ if (!anArray || !anArray->isInitialized())
+ return EntityWrapperPtr();
+
+ int aSize = anArray->size();
+ GCS::VEC_pD aParameters;
+ aParameters.reserve(aSize);
+ for (int index = 0; index < aSize; ++index) {
+ double* aParam = createParameter(theStorage);
+ *aParam = anArray->value(index);
+ aParameters.push_back(aParam);
+ }
+
+ return EntityWrapperPtr(new PlaneGCSSolver_ScalarArrayWrapper(aParameters));
+}
+
+static PointWrapperPtr createPoint(const GeomPnt2dPtr& thePoint, PlaneGCSSolver_Storage* theStorage)
+{
+ GCSPointPtr aNewPoint(new GCS::Point);
+
+ aNewPoint->x = createParameter(theStorage);
+ aNewPoint->y = createParameter(theStorage);
+ if (thePoint) {
+ *(aNewPoint->x) = thePoint->x();
+ *(aNewPoint->y) = thePoint->y();
+ }
+
+ return PointWrapperPtr(new PlaneGCSSolver_PointWrapper(aNewPoint));
+}
+
static EntityWrapperPtr createPoint(const AttributePtr& theAttribute,
PlaneGCSSolver_Storage* theStorage)
{
if (!aPoint2D)
return EntityWrapperPtr();
- GCSPointPtr aNewPoint(new GCS::Point);
+ GeomPnt2dPtr aPnt;
+ if (aPoint2D->isInitialized())
+ aPnt = aPoint2D->pnt();
- aNewPoint->x = createParameter(theStorage);
- aNewPoint->y = createParameter(theStorage);
- if (aPoint2D->isInitialized()) {
- *(aNewPoint->x) = aPoint2D->x();
- *(aNewPoint->y) = aPoint2D->y();
- }
+ return createPoint(aPnt, theStorage);
+}
- return EntityWrapperPtr(new PlaneGCSSolver_PointWrapper(aNewPoint));
+static EntityWrapperPtr createPointArray(const AttributePtr& theAttribute,
+ PlaneGCSSolver_Storage* theStorage)
+{
+ std::shared_ptr<GeomDataAPI_Point2DArray> aPointArray =
+ std::dynamic_pointer_cast<GeomDataAPI_Point2DArray>(theAttribute);
+ if (!aPointArray)
+ return EntityWrapperPtr();
+
+ int aSize = aPointArray->size();
+
+ std::vector<PointWrapperPtr> aPointWrappers;
+ aPointWrappers.reserve(aSize);
+ for (int index = 0; index < aSize; ++index)
+ aPointWrappers.push_back(createPoint(aPointArray->pnt(index), theStorage));
+
+ return EntityWrapperPtr(new PlaneGCSSolver_PointArrayWrapper(aPointWrappers));
}
EntityWrapperPtr PlaneGCSSolver_AttributeBuilder::createAttribute(
aResult = createScalar(theAttribute, myStorage);
if (!aResult)
aResult = createBoolean(theAttribute);
+ if (!aResult)
+ aResult = createPointArray(theAttribute, myStorage);
+ if (!aResult)
+ aResult = createScalarArray(theAttribute, myStorage);
if (aResult && !myStorage)
aResult->setExternal(true);
return aResult;
ENTITY_UNKNOWN = 0,
ENTITY_BOOLEAN,
ENTITY_SCALAR,
+ ENTITY_SCALAR_ARRAY,
ENTITY_ANGLE,
ENTITY_POINT,
+ ENTITY_POINT_ARRAY,
ENTITY_LINE,
ENTITY_CIRCLE,
ENTITY_ARC,
ENTITY_ELLIPSE,
- ENTITY_ELLIPTIC_ARC
+ ENTITY_ELLIPTIC_ARC,
+ ENTITY_BSPLINE
};
/// Types of constraints
#include <PlaneGCSSolver_EdgeWrapper.h>
#include <cmath>
-static bool isLine(const GCSCurvePtr& theEntity)
+template <typename TYPE>
+static bool isCurve(const GCSCurvePtr& theEntity)
{
- return std::dynamic_pointer_cast<GCS::Line>(theEntity).get();
-}
-
-static bool isCircle(const GCSCurvePtr& theEntity)
-{
- return std::dynamic_pointer_cast<GCS::Circle>(theEntity).get();
-}
-
-static bool isArc(const GCSCurvePtr& theEntity)
-{
- return std::dynamic_pointer_cast<GCS::Arc>(theEntity).get();
-}
-
-static bool isEllipse(const GCSCurvePtr& theEntity)
-{
- return std::dynamic_pointer_cast<GCS::Ellipse>(theEntity).get();
-}
-
-static bool isEllipticArc(const GCSCurvePtr& theEntity)
-{
- return std::dynamic_pointer_cast<GCS::ArcOfEllipse>(theEntity).get();
+ return std::dynamic_pointer_cast<TYPE>(theEntity).get();
}
PlaneGCSSolver_EdgeWrapper::PlaneGCSSolver_EdgeWrapper(const GCSCurvePtr theEntity)
: myEntity(theEntity)
{
- if (isLine(myEntity))
+ if (isCurve<GCS::Line>(myEntity))
myType = ENTITY_LINE;
- else if (isArc(myEntity))
+ else if (isCurve<GCS::Arc>(myEntity))
myType = ENTITY_ARC;
- else if (isCircle(myEntity))
+ else if (isCurve<GCS::Circle>(myEntity))
myType = ENTITY_CIRCLE;
- else if (isEllipticArc(myEntity))
+ else if (isCurve<GCS::ArcOfEllipse>(myEntity))
myType = ENTITY_ELLIPTIC_ARC;
- else if (isEllipse(myEntity))
+ else if (isCurve<GCS::Ellipse>(myEntity))
myType = ENTITY_ELLIPSE;
+ else if (isCurve<GCS::BSpline>(myEntity))
+ myType = ENTITY_BSPLINE;
}
static double squareDistance(const GCS::Point& theP1, const GCS::Point& theP2)
#include <PlaneGCSSolver_FeatureBuilder.h>
#include <PlaneGCSSolver_EdgeWrapper.h>
#include <PlaneGCSSolver_PointWrapper.h>
+#include <PlaneGCSSolver_PointArrayWrapper.h>
#include <PlaneGCSSolver_ScalarWrapper.h>
+#include <PlaneGCSSolver_ScalarArrayWrapper.h>
#include <PlaneGCSSolver_BooleanWrapper.h>
#include <PlaneGCSSolver_Tools.h>
#include <SketchPlugin_Arc.h>
+#include <SketchPlugin_BSpline.h>
#include <SketchPlugin_Circle.h>
#include <SketchPlugin_Ellipse.h>
#include <SketchPlugin_EllipticArc.h>
static EntityWrapperPtr createEllipse(const AttributeEntityMap& theAttributes);
static EntityWrapperPtr createEllipticArc(const AttributeEntityMap& theAttributes,
PlaneGCSSolver_Storage* theStorage);
+static EntityWrapperPtr createBSpline(const AttributeEntityMap& theAttributes);
PlaneGCSSolver_FeatureBuilder::PlaneGCSSolver_FeatureBuilder(
// Arc of ellipse
else if (aFeatureKind == SketchPlugin_EllipticArc::ID())
aResult = createEllipticArc(myAttributes, myStorage);
+ // B-spline curve
+ else if (aFeatureKind == SketchPlugin_BSpline::ID())
+ aResult = createBSpline(myAttributes);
// Point (it has low probability to be an attribute of constraint, so it is checked at the end)
else if (aFeatureKind == SketchPlugin_Point::ID() ||
aFeatureKind == SketchPlugin_IntersectionPoint::ID()) {
return anEllipseWrapper;
}
+EntityWrapperPtr createBSpline(const AttributeEntityMap& theAttributes)
+{
+ std::shared_ptr<GCS::BSpline> aNewSpline(new GCS::BSpline);
+
+ aNewSpline->degree = 3;
+ aNewSpline->periodic = false;
+
+ AttributeEntityMap::const_iterator anIt = theAttributes.begin();
+ for (; anIt != theAttributes.end(); ++anIt) {
+ const std::string& anAttrID = anIt->first->id();
+ if (anAttrID == SketchPlugin_BSpline::POLES_ID()) {
+ PointArrayWrapperPtr anArray =
+ std::dynamic_pointer_cast<PlaneGCSSolver_PointArrayWrapper>(anIt->second);
+
+ int aSize = anArray->size();
+ aNewSpline->poles.reserve(aSize);
+ for (int anIndex = 0; anIndex < aSize; ++anIndex)
+ aNewSpline->poles.push_back(*anArray->value(anIndex)->point());
+
+ aNewSpline->start = aNewSpline->poles.front();
+ aNewSpline->end = aNewSpline->poles.back();
+ }
+ else if (anAttrID == SketchPlugin_BSpline::WEIGHTS_ID()) {
+ ScalarArrayWrapperPtr anArray =
+ std::dynamic_pointer_cast<PlaneGCSSolver_ScalarArrayWrapper>(anIt->second);
+ aNewSpline->weights = anArray->array();
+ }
+ }
+
+ return EdgeWrapperPtr(new PlaneGCSSolver_EdgeWrapper(aNewSpline));
+}
+
bool isAttributeApplicable(const std::string& theAttrName, const std::string& theOwnerName)
{
if (theOwnerName == SketchPlugin_Arc::ID()) {
theAttrName == SketchPlugin_EllipticArc::END_POINT_ID() ||
theAttrName == SketchPlugin_EllipticArc::REVERSED_ID();
}
+ else if (theOwnerName == SketchPlugin_BSpline::ID()) {
+ return theAttrName == SketchPlugin_BSpline::POLES_ID() ||
+ theAttrName == SketchPlugin_BSpline::WEIGHTS_ID();
+ }
// suppose that all remaining features are points
return theAttrName == SketchPlugin_Point::COORD_ID();
--- /dev/null
+// Copyright (C) 2019-2020 CEA/DEN, EDF R&D
+//
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2.1 of the License, or (at your option) any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+//
+// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
+//
+
+#include <PlaneGCSSolver_PointArrayWrapper.h>
+
+PlaneGCSSolver_PointArrayWrapper::PlaneGCSSolver_PointArrayWrapper(
+ const std::vector<PointWrapperPtr>& thePoints)
+ : myPoints(thePoints)
+{
+}
--- /dev/null
+// Copyright (C) 2019-2020 CEA/DEN, EDF R&D
+//
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2.1 of the License, or (at your option) any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+//
+// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
+//
+
+#ifndef PlaneGCSSolver_PointArrayWrapper_H_
+#define PlaneGCSSolver_PointArrayWrapper_H_
+
+#include <PlaneGCSSolver_Defs.h>
+#include <PlaneGCSSolver_PointWrapper.h>
+
+/**
+ * Wrapper providing operations with arrays of PlaneGCS points.
+ */
+class PlaneGCSSolver_PointArrayWrapper : public PlaneGCSSolver_EntityWrapper
+{
+public:
+ PlaneGCSSolver_PointArrayWrapper(const std::vector<PointWrapperPtr>& thePoints);
+
+ /// \brief Return wrapper of PlaneGCS point
+ const PointWrapperPtr& value(const int theIndex) const
+ { return myPoints[theIndex]; }
+
+ /// \breif Size of array
+ int size() const { return (int)myPoints.size(); }
+
+ /// \brief Return type of current entity
+ virtual SketchSolver_EntityType type() const
+ { return ENTITY_POINT_ARRAY; }
+
+private:
+ std::vector<PointWrapperPtr> myPoints;
+};
+
+typedef std::shared_ptr<PlaneGCSSolver_PointArrayWrapper> PointArrayWrapperPtr;
+
+#endif
--- /dev/null
+// Copyright (C) 2019-2020 CEA/DEN, EDF R&D
+//
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2.1 of the License, or (at your option) any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+//
+// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
+//
+
+#include <PlaneGCSSolver_ScalarArrayWrapper.h>
+
+PlaneGCSSolver_ScalarArrayWrapper::PlaneGCSSolver_ScalarArrayWrapper(const GCS::VEC_pD& theParam)
+ : myValue(theParam)
+{
+}
--- /dev/null
+// Copyright (C) 2019-2020 CEA/DEN, EDF R&D
+//
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2.1 of the License, or (at your option) any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+//
+// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
+//
+
+#ifndef PlaneGCSSolver_ScalarArrayWrapper_H_
+#define PlaneGCSSolver_ScalarArrayWrapper_H_
+
+#include <PlaneGCSSolver_Defs.h>
+#include <PlaneGCSSolver_EntityWrapper.h>
+
+/**
+ * Wrapper providing operations with array of PlaneGCS scalars.
+ */
+class PlaneGCSSolver_ScalarArrayWrapper : public PlaneGCSSolver_EntityWrapper
+{
+public:
+ PlaneGCSSolver_ScalarArrayWrapper(const GCS::VEC_pD& theParam);
+
+ /// \brief Return array of PlaneGCS parameters
+ const GCS::VEC_pD& array() const { return myValue; }
+
+ /// \brief Return type of current entity
+ virtual SketchSolver_EntityType type() const
+ { return ENTITY_SCALAR_ARRAY; }
+
+protected:
+ GCS::VEC_pD myValue; ///< list of pointers to values provided by the storage
+};
+
+typedef std::shared_ptr<PlaneGCSSolver_ScalarArrayWrapper> ScalarArrayWrapperPtr;
+
+#endif
#include <PlaneGCSSolver_ScalarWrapper.h>
-#include <cmath>
-
PlaneGCSSolver_ScalarWrapper::PlaneGCSSolver_ScalarWrapper(double *const theParam)
: myValue(theParam)
{
#include <PlaneGCSSolver_ConstraintWrapper.h>
#include <PlaneGCSSolver_EdgeWrapper.h>
#include <PlaneGCSSolver_PointWrapper.h>
+#include <PlaneGCSSolver_PointArrayWrapper.h>
+#include <PlaneGCSSolver_ScalarArrayWrapper.h>
#include <PlaneGCSSolver_Tools.h>
#include <PlaneGCSSolver_AttributeBuilder.h>
#include <GeomAPI_Pnt2d.h>
#include <GeomAPI_XY.h>
#include <GeomDataAPI_Point2D.h>
+#include <GeomDataAPI_Point2DArray.h>
+#include <ModelAPI_AttributeDoubleArray.h>
#include <ModelAPI_AttributeRefAttr.h>
#include <SketchPlugin_Ellipse.h>
#include <SketchPlugin_Projection.h>
}
continue;
}
+ std::shared_ptr<GeomDataAPI_Point2DArray> aPointArray =
+ std::dynamic_pointer_cast<GeomDataAPI_Point2DArray>(anIt->first);
+ if (aPointArray) {
+ std::shared_ptr<PlaneGCSSolver_PointArrayWrapper> anArrayWrapper =
+ std::dynamic_pointer_cast<PlaneGCSSolver_PointArrayWrapper>(anIt->second);
+ int aSize = aPointArray->size();
+ for (int anIndex = 0; anIndex < aSize; ++anIndex) {
+ GeomPnt2dPtr anOriginal = aPointArray->pnt(anIndex);
+ GCSPointPtr aGCSPoint = anArrayWrapper->value(anIndex)->point();
+ if (fabs(anOriginal->x() - (*aGCSPoint->x)) > aTol ||
+ fabs(anOriginal->y() - (*aGCSPoint->y)) > aTol) {
+ aPointArray->setPnt(anIndex, *aGCSPoint->x, *aGCSPoint->y);
+ addOwnerToSet(anIt->first, anUpdatedFeatures);
+ }
+ }
+ continue;
+ }
AttributeDoublePtr aScalar = std::dynamic_pointer_cast<ModelAPI_AttributeDouble>(anIt->first);
if (aScalar) {
ScalarWrapperPtr aScalarWrapper =
}
continue;
}
+ AttributeDoubleArrayPtr aRealArray =
+ std::dynamic_pointer_cast<ModelAPI_AttributeDoubleArray>(anIt->first);
+ if (aRealArray) {
+ std::shared_ptr<PlaneGCSSolver_ScalarArrayWrapper> anArrayWrapper =
+ std::dynamic_pointer_cast<PlaneGCSSolver_ScalarArrayWrapper>(anIt->second);
+ int aSize = aRealArray->size();
+ for (int anIndex = 0; anIndex < aSize; ++anIndex) {
+ if (fabs(aRealArray->value(anIndex) - *anArrayWrapper->array()[anIndex]) > aTol) {
+ aRealArray->setValue(anIndex, *anArrayWrapper->array()[anIndex]);
+ addOwnerToSet(anIt->first, anUpdatedFeatures);
+ }
+ }
+ continue;
+ }
}
// notify listeners about features update
new SketchSolver_ConstraintMovement(theMovedAttribute));
}
+std::shared_ptr<SketchSolver_ConstraintMovement> PlaneGCSSolver_Tools::createMovementConstraint(
+ const std::pair<AttributePtr, int>& theMovedPointInArray)
+{
+ return std::shared_ptr<SketchSolver_ConstraintMovement>(
+ new SketchSolver_ConstraintMovement(theMovedPointInArray.first, theMovedPointInArray.second));
+}
+
ConstraintWrapperPtr PlaneGCSSolver_Tools::createConstraint(
/// \brief Creates temporary constraint to fix the attribute after movement
std::shared_ptr<SketchSolver_ConstraintMovement>
createMovementConstraint(AttributePtr theMovedAttribute);
+ /// \brief Creates temporary constraint to fix the point in array after movement
+ std::shared_ptr<SketchSolver_ConstraintMovement>
+ createMovementConstraint(const std::pair<AttributePtr, int>& theMovedPointInArray);
/// \brief Creates new constraint using given parameters
/// \param theConstraint [in] original constraint
SketchSolver_EntityType aType = anEntity->type();
if (aType == ENTITY_UNKNOWN)
continue;
- else if (aType == ENTITY_POINT)
+ else if (aType == ENTITY_POINT || aType == ENTITY_POINT_ARRAY)
theAttributes[aPtInd++] = anEntity; // the point is created
else { // another entity (not a point) is created
if (aEntInd < anInitNbOfAttr)
#include <SketchSolver_ConstraintCoincidence.h>
#include <SketchSolver_Error.h>
+#include <PlaneGCSSolver_PointArrayWrapper.h>
#include <PlaneGCSSolver_Tools.h>
#include <PlaneGCSSolver_UpdateCoincidence.h>
#include <GeomDataAPI_Point2D.h>
+#include <ModelAPI_AttributeInteger.h>
+
#include <SketchPlugin_Arc.h>
#include <SketchPlugin_ConstraintCoincidenceInternal.h>
#include <SketchPlugin_Ellipse.h>
}
}
+static void getPointFromArray(EntityWrapperPtr& theArray,
+ const ConstraintPtr& theConstraint,
+ const std::string& theIndexAttrId)
+{
+ if (theArray && theArray->type() == ENTITY_POINT_ARRAY) {
+ AttributeIntegerPtr anIndexAttr = theConstraint->integer(theIndexAttrId);
+ if (anIndexAttr) {
+ PointArrayWrapperPtr aPointsArray =
+ std::dynamic_pointer_cast<PlaneGCSSolver_PointArrayWrapper>(theArray);
+ theArray = aPointsArray->value(anIndexAttr->value());
+ }
+ }
+}
+
void SketchSolver_ConstraintCoincidence::process()
{
getCoincidentFeatureExtremities(myBaseConstraint, myStorage, myFeatureExtremities);
} else
myErrorMsg = SketchSolver_Error::INCORRECT_ATTRIBUTE();
+
+ // process internal coincidence with a point in the array of points
+ getPointFromArray(theAttributes[0], myBaseConstraint,
+ SketchPlugin_ConstraintCoincidenceInternal::INDEX_ENTITY_A());
+ getPointFromArray(theAttributes[1], myBaseConstraint,
+ SketchPlugin_ConstraintCoincidenceInternal::INDEX_ENTITY_B());
}
void SketchSolver_ConstraintCoincidence::notify(const FeaturePtr& theFeature,
#include <SketchSolver_Manager.h>
#include <PlaneGCSSolver_EdgeWrapper.h>
+#include <PlaneGCSSolver_PointArrayWrapper.h>
#include <PlaneGCSSolver_PointWrapper.h>
#include <SketchPlugin_Arc.h>
{
}
-SketchSolver_ConstraintMovement::SketchSolver_ConstraintMovement(AttributePtr thePoint)
+SketchSolver_ConstraintMovement::SketchSolver_ConstraintMovement(AttributePtr theAttribute,
+ const int thePointIndex)
: SketchSolver_ConstraintFixed(ConstraintPtr()),
- myDraggedPoint(thePoint),
+ myDraggedAttribute(theAttribute),
+ myDraggedPointIndex(thePointIndex),
mySimpleMove(true)
{
- myMovedFeature = ModelAPI_Feature::feature(thePoint->owner());
+ myMovedFeature = ModelAPI_Feature::feature(theAttribute->owner());
}
void SketchSolver_ConstraintMovement::blockEvents(bool isBlocked)
return aConstraint;
}
- EntityWrapperPtr anEntity =
- myDraggedPoint ? myStorage->entity(myDraggedPoint) : myStorage->entity(myMovedFeature);
+ EntityWrapperPtr anEntity = myDraggedAttribute ? myStorage->entity(myDraggedAttribute)
+ : myStorage->entity(myMovedFeature);
if (!anEntity) {
myStorage->update(myMovedFeature, true);
- anEntity =
- myDraggedPoint ? myStorage->entity(myDraggedPoint) : myStorage->entity(myMovedFeature);
+ anEntity = myDraggedAttribute ? myStorage->entity(myDraggedAttribute)
+ : myStorage->entity(myMovedFeature);
if (!anEntity)
return aConstraint;
}
- mySimpleMove = isSimpleMove(myMovedFeature, myDraggedPoint);
+ mySimpleMove = isSimpleMove(myMovedFeature, myDraggedAttribute);
- if (mySimpleMove)
+ if (mySimpleMove) {
+ if (anEntity->type() == ENTITY_POINT_ARRAY) {
+ anEntity = std::dynamic_pointer_cast<PlaneGCSSolver_PointArrayWrapper>(anEntity)
+ ->value(myDraggedPointIndex);
+ }
aConstraint = fixFeature(anEntity);
+ }
else {
- if (myDraggedPoint) // start or end point of arc has been moved
+ if (myDraggedAttribute) // start or end point of arc has been moved
aConstraint = fixArcExtremity(anEntity);
else if (anEntity->type() == ENTITY_CIRCLE || anEntity->type() == ENTITY_ARC) {
// arc or circle has been moved
#ifdef CHANGE_RADIUS_WHILE_MOVE
int aMaxSize = mySimpleMove ? (int)myFixedValues.size() : 2;
#else
- int aMaxSize = myMovedFeature->getKind() == SketchPlugin_Line::ID() && !myDraggedPoint ? 4 : 2;
+ int aMaxSize =
+ myMovedFeature->getKind() == SketchPlugin_Line::ID() && !myDraggedAttribute ? 4 : 2;
#endif
for (int i = 0; i < aMaxSize; ++i)
myFixedValues[i] += aDelta[i % 2];
SketchSolver_ConstraintMovement(FeaturePtr theFeature);
/// Creates movement constraint based on point
- SketchSolver_ConstraintMovement(AttributePtr thePoint);
+ SketchSolver_ConstraintMovement(AttributePtr theMovedAttribute, const int thePointIndex = -1);
/// \brief Set coordinates of the start point of the movement
void startPoint(const std::shared_ptr<GeomAPI_Pnt2d>& theStartPoint);
private:
FeaturePtr myMovedFeature; ///< fixed feature (if set, myBaseConstraint should be NULL)
- AttributePtr myDraggedPoint; ///< one of the feature points which has been moved
+ AttributePtr myDraggedAttribute; ///< one of the feature points which has been moved
+ int myDraggedPointIndex; ///< index of the point if the moved attribute is an array
std::shared_ptr<GeomAPI_Pnt2d> myStartPoint; ///< start point of the movement
bool mySimpleMove; ///< simple move, thus all parameters should be increased by movement delta
int theSketchDOF,
bool theEventsBlocked,
Type theFeatureOrPoint,
+ const EntityWrapperPtr& theSolverEntity,
const std::shared_ptr<GeomAPI_Pnt2d>& theFrom,
const std::shared_ptr<GeomAPI_Pnt2d>& theTo)
{
- bool isEntityExists = (theStorage->entity(theFeatureOrPoint).get() != 0);
+ bool isEntityExists = (theSolverEntity.get() != 0);
if (theSketchDOF == 0 && isEntityExists) {
// avoid moving elements of fully constrained sketch
theStorage->refresh();
const std::shared_ptr<GeomAPI_Pnt2d>& theFrom,
const std::shared_ptr<GeomAPI_Pnt2d>& theTo)
{
- SolverConstraintPtr aConstraint =
- move(myStorage, mySketchSolver, myDOF, myIsEventsBlocked, theFeature, theFrom, theTo);
+ EntityWrapperPtr anEntity = myStorage->entity(theFeature);
+ SolverConstraintPtr aConstraint = move(myStorage, mySketchSolver, myDOF, myIsEventsBlocked,
+ theFeature, anEntity, theFrom, theTo);
setTemporary(aConstraint);
return true;
}
bool SketchSolver_Group::movePoint(AttributePtr theAttribute,
+ const int thePointIndex,
const std::shared_ptr<GeomAPI_Pnt2d>& theFrom,
const std::shared_ptr<GeomAPI_Pnt2d>& theTo)
{
- SolverConstraintPtr aConstraint =
- move(myStorage, mySketchSolver, myDOF, myIsEventsBlocked, theAttribute, theFrom, theTo);
+ EntityWrapperPtr anEntity = myStorage->entity(theAttribute);
+ SolverConstraintPtr aConstraint;
+ if (thePointIndex < 0) {
+ aConstraint = move(myStorage, mySketchSolver, myDOF, myIsEventsBlocked,
+ theAttribute, anEntity, theFrom, theTo);
+ }
+ else {
+ aConstraint = move(myStorage, mySketchSolver, myDOF, myIsEventsBlocked,
+ std::pair<AttributePtr, int>(theAttribute, thePointIndex), anEntity,
+ theFrom, theTo);
+ }
setTemporary(aConstraint);
return true;
}
const std::shared_ptr<GeomAPI_Pnt2d>& theTo);
/** \brief Updates the data corresponding the specified point moved in GUI.
* Special kind of Fixed constraints is created.
- * \param[in] thePoint the attribute to be updated
- * \param[in] theFrom start point of the movement
- * \param[in] theTo final point of the movement
+ * \param[in] thePointOrArray the attribute to be updated
+ * \param[in] thePointIndex index of moved point in array
+ * \param[in] theFrom start point of the movement
+ * \param[in] theTo destination point of the movement
* \return \c true, if the attribute is really moved
*/
- bool movePoint(AttributePtr thePoint,
+ bool movePoint(AttributePtr thePointOrArray,
+ const int thePointIndex,
const std::shared_ptr<GeomAPI_Pnt2d>& theFrom,
const std::shared_ptr<GeomAPI_Pnt2d>& theTo);
#include <Events_Loop.h>
#include <GeomDataAPI_Point2D.h>
+#include <GeomDataAPI_Point2DArray.h>
#include <ModelAPI_Events.h>
#include <ModelAPI_ResultConstruction.h>
#include <ModelAPI_Session.h>
}
}
+static void setPoint(AttributePtr theAttribute,
+ const int thePointIndex,
+ const std::shared_ptr<GeomAPI_Pnt2d> theValue)
+{
+ AttributePoint2DPtr aPointAttr = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(theAttribute);
+ AttributePoint2DArrayPtr aPointArrayAttr =
+ std::dynamic_pointer_cast<GeomDataAPI_Point2DArray>(theAttribute);
+ if (aPointAttr)
+ aPointAttr->setValue(theValue);
+ else if (aPointArrayAttr && thePointIndex >= 0)
+ aPointArrayAttr->setPnt(thePointIndex, theValue);
+}
+
// ========================================================
std::dynamic_pointer_cast<ModelAPI_ObjectMovedMessage>(theMessage);
ObjectPtr aMovedObject = aMoveMsg->movedObject();
- std::shared_ptr<GeomDataAPI_Point2D> aMovedPoint =
- std::dynamic_pointer_cast<GeomDataAPI_Point2D>(aMoveMsg->movedAttribute());
+ AttributePtr aMovedAttribute = aMoveMsg->movedAttribute();
+ int aMovedPoint = aMoveMsg->movedPointIndex();
const std::shared_ptr<GeomAPI_Pnt2d>& aFrom = aMoveMsg->originalPosition();
const std::shared_ptr<GeomAPI_Pnt2d>& aTo = aMoveMsg->currentPosition();
std::dynamic_pointer_cast<SketchPlugin_Feature>(aMovedFeature);
if (aSketchFeature && !aSketchFeature->isMacro())
needToResolve = moveFeature(aSketchFeature, aFrom, aTo);
- } else if (aMovedPoint)
- needToResolve = moveAttribute(aMovedPoint, aFrom, aTo);
+ } else if (aMovedAttribute)
+ needToResolve = moveAttribute(aMovedAttribute, aMovedPoint, aFrom, aTo);
} else if (theMessage->eventID() == Events_Loop::loop()->eventByName(EVENT_OBJECT_DELETED)) {
std::shared_ptr<ModelAPI_ObjectDeletedMessage> aDeleteMsg =
// Purpose: move given attribute in appropriate group
// ============================================================================
bool SketchSolver_Manager::moveAttribute(
- const std::shared_ptr<GeomDataAPI_Point2D>& theMovedAttribute,
+ const std::shared_ptr<ModelAPI_Attribute>& theMovedAttribute,
+ const int theMovedPointIndex,
const std::shared_ptr<GeomAPI_Pnt2d>& theFrom,
const std::shared_ptr<GeomAPI_Pnt2d>& theTo)
{
std::dynamic_pointer_cast<SketchPlugin_Constraint>(anOwner);
if (aConstraint)
{
- theMovedAttribute->setValue(theTo);
+ setPoint(theMovedAttribute, theMovedPointIndex, theTo);
Events_Loop::loop()->flush(Events_Loop::eventByName(EVENT_OBJECT_UPDATED));
return true;
}
if (aSketchFeature)
aGroup = findGroup(aSketchFeature);
if (!aGroup) {
- theMovedAttribute->setValue(theTo);
+ setPoint(theMovedAttribute, theMovedPointIndex, theTo);
return false;
}
aGroup->blockEvents(true);
- return aGroup->movePoint(theMovedAttribute, theFrom, theTo);
+ return aGroup->movePoint(theMovedAttribute, theMovedPointIndex, theFrom, theTo);
}
// ============================================================================
const std::shared_ptr<GeomAPI_Pnt2d>& theToPoint);
/** \brief Move feature using its moved attribute
- * \param[in] theMovedAttribute dragged point attribute of sketch feature
- * \param[in] theFromPoint original position of the moved point
- * \param[in] theToPoint prefereble position (current position of the mouse)
+ * \param[in] theMovedAttribute dragged point (array of points) attribute of sketch feature
+ * \param[in] theMovedPointIndex index of dragged point in an array (-1 otherwise)
+ * \param[in] theFromPoint original position of the moved point
+ * \param[in] theToPoint prefereble position (current position of the mouse)
* \return \c true if the attribute owner has been changed successfully
*/
- bool moveAttribute(const std::shared_ptr<GeomDataAPI_Point2D>& theMovedAttribute,
+ bool moveAttribute(const std::shared_ptr<ModelAPI_Attribute>& theMovedAttribute,
+ const int theMovedPointIndex,
const std::shared_ptr<GeomAPI_Pnt2d>& theFromPoint,
const std::shared_ptr<GeomAPI_Pnt2d>& theToPoint);