theDumper << ")" << std::endl;
}
+static void setCoordinates(const FeaturePtr& theFeature,
+ const std::string& theAttrName,
+ const GeomPnt2dPtr& theCoordinates)
+{
+ AttributePoint2DPtr aPoint =
+ std::dynamic_pointer_cast<GeomDataAPI_Point2D>(theFeature->attribute(theAttrName));
+ aPoint->setValue(theCoordinates);
+}
+
+bool SketchAPI_BSpline::insertPole(const int theIndex,
+ const GeomPnt2dPtr& theCoordinates,
+ const ModelHighAPI_Double& theWeight)
+{
+ std::ostringstream anActionName;
+ anActionName << SketchPlugin_BSplineBase::ADD_POLE_ACTION_ID() << "#" << theIndex;
+ bool isOk = feature()->customAction(anActionName.str());
+ if (isOk) {
+ int anIndex = theIndex + 1;
+ if (feature()->getKind() == SketchPlugin_BSpline::ID() && anIndex + 1 >= poles()->size())
+ anIndex = poles()->size() - 2;
+ // initialize coordinates and weight of new pole
+ poles()->setPnt(anIndex, theCoordinates);
+ weights()->setValue(anIndex, theWeight.value());
+
+ // update coordinates of points of control polygon
+ std::map<int, FeaturePtr> aPoints, aLines;
+ collectAuxiliaryFeatures(feature(), aPoints, aLines);
+ std::map<int, FeaturePtr>::iterator aFound = aPoints.find(anIndex);
+ if (aFound != aPoints.end())
+ setCoordinates(aFound->second, SketchPlugin_Point::COORD_ID(), theCoordinates);
+ aFound = aLines.find(anIndex);
+ if (aFound != aLines.end())
+ setCoordinates(aFound->second, SketchPlugin_Line::START_ID(), theCoordinates);
+ aFound = aLines.find(anIndex - 1);
+ if (aFound != aLines.end())
+ setCoordinates(aFound->second, SketchPlugin_Line::END_ID(), theCoordinates);
+ }
+ return isOk;
+}
+
// =================================================================================================
const std::list<int>& regular = std::list<int>(),
const std::list<int>& auxiliary = std::list<int>()) const;
+ /// Insert new pole after the pole with the given index
+ SKETCHAPI_EXPORT
+ bool insertPole(const int theIndex,
+ const std::shared_ptr<GeomAPI_Pnt2d>& theCoordinates,
+ const ModelHighAPI_Double& theWeight = ModelHighAPI_Double(1.0));
+
/// Dump wrapped feature
SKETCHAPI_EXPORT
virtual void dump(ModelHighAPI_Dumper& theDumper) const;
Test3087_1.py
Test3087_2.py
TestArcBehavior.py
+ TestBSplineAddPole.py
TestChangeSketchPlane1.py
TestChangeSketchPlane2.py
TestChangeSketchPlane3.py
#include <SketchPlugin_ConstraintCoincidenceInternal.h>
#include <SketchPlugin_Line.h>
#include <SketchPlugin_MacroBSpline.h>
+#include <SketchPlugin_Point.h>
#include <SketchPlugin_Sketch.h>
#include <Events_InfoMessage.h>
}
void SketchPlugin_BSplineBase::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();
-//// }
- }
}
bool SketchPlugin_BSplineBase::customAction(const std::string& theActionId)
}
std::string aMsg = "Error: Feature \"%1\" does not support action \"%2\".";
- Events_InfoMessage("SketchPlugin_BSplineBase", aMsg).arg(getKind()).arg(anAction).send();
+ Events_InfoMessage("SketchPlugin_BSplineBase", aMsg).arg(getKind()).arg(theActionId).send();
return false;
}
// find internal coincidences applied to the poles with greater indices
std::list<AttributeIntegerPtr> aCoincidentPoleIndex;
+ std::map<int, FeaturePtr> aControlPoles, aControlSegments;
bool hasAuxSegment = false;
const std::set<AttributePtr>& aRefs = data()->refsToMe();
for (std::set<AttributePtr>::iterator anIt = aRefs.begin(); anIt != aRefs.end(); ++anIt) {
FeaturePtr aFeature = ModelAPI_Feature::feature((*anIt)->owner());
if (aFeature->getKind() == SketchPlugin_ConstraintCoincidenceInternal::ID()) {
AttributeIntegerPtr anIndex;
- if ((*anIt)->id() == SketchPlugin_ConstraintCoincidenceInternal::ENTITY_A())
+ AttributeRefAttrPtr aNonSplinePoint;
+ if ((*anIt)->id() == SketchPlugin_ConstraintCoincidenceInternal::ENTITY_A()) {
anIndex = aFeature->integer(SketchPlugin_ConstraintCoincidenceInternal::INDEX_ENTITY_A());
- else if ((*anIt)->id() == SketchPlugin_ConstraintCoincidenceInternal::ENTITY_B())
+ aNonSplinePoint = aFeature->refattr(SketchPlugin_Constraint::ENTITY_B());
+ }
+ else if ((*anIt)->id() == SketchPlugin_ConstraintCoincidenceInternal::ENTITY_B()) {
anIndex = aFeature->integer(SketchPlugin_ConstraintCoincidenceInternal::INDEX_ENTITY_B());
+ aNonSplinePoint = aFeature->refattr(SketchPlugin_Constraint::ENTITY_A());
+ }
if (anIndex && anIndex->isInitialized()) {
- if (anIndex->value() > anAfter)
+ if (anIndex->value() > anAfter) {
aCoincidentPoleIndex.push_back(anIndex);
+ FeaturePtr aParent = ModelAPI_Feature::feature(aNonSplinePoint->attr()->owner());
+ if (aParent->getKind() == SketchPlugin_Point::ID())
+ aControlPoles[anIndex->value()] = aParent;
+ else if (aParent->getKind() == SketchPlugin_Line::ID() &&
+ aNonSplinePoint->attr()->id() == SketchPlugin_Line::START_ID())
+ aControlSegments[anIndex->value()] = aParent;
+ }
else if (anIndex->value() == anAfter && !hasAuxSegment) {
// check the constrained object is a segment of the control polygon
- const std::string& anOtherAttr =
- (*anIt)->id() == SketchPlugin_ConstraintCoincidenceInternal::ENTITY_A() ?
- SketchPlugin_ConstraintCoincidenceInternal::ENTITY_B() :
- SketchPlugin_ConstraintCoincidenceInternal::ENTITY_A();
- AttributeRefAttrPtr aRefAttr = aFeature->refattr(anOtherAttr);
- if (aRefAttr && !aRefAttr->isObject() &&
- aRefAttr->attr()->id() == SketchPlugin_Line::START_ID()) {
+ if (aNonSplinePoint && !aNonSplinePoint->isObject() &&
+ aNonSplinePoint->attr()->id() == SketchPlugin_Line::START_ID()) {
hasAuxSegment = true;
aCoincidentPoleIndex.push_back(anIndex);
+ aControlSegments[anIndex->value()] =
+ ModelAPI_Feature::feature(aNonSplinePoint->attr()->owner());
}
}
}
if (hasAuxSegment)
SketchPlugin_MacroBSpline::createAuxiliarySegment(aPolesArray, anAfter, anAfter + 1);
+ // update names of features representing control polygon
+ for (std::map<int, FeaturePtr>::iterator anIt = aControlPoles.begin();
+ anIt != aControlPoles.end(); ++anIt) {
+ SketchPlugin_MacroBSpline::assignDefaultNameForAux(anIt->second, aPolesArray, anIt->first + 1);
+ }
+ for (std::map<int, FeaturePtr>::iterator anIt = aControlSegments.begin();
+ anIt != aControlSegments.end(); ++anIt) {
+ SketchPlugin_MacroBSpline::assignDefaultNameForAux(anIt->second, aPolesArray,
+ anIt->first + 1, (anIt->first + 2) % aPolesArray->size());
+ }
+
return true;
}
// ========================== Auxiliary functions ===========================================
+void SketchPlugin_MacroBSpline::assignDefaultNameForAux(FeaturePtr theAuxFeature,
+ AttributePoint2DArrayPtr theBSplinePoles,
+ const int thePoleIndex1,
+ const int thePoleIndex2)
+{
+ FeaturePtr aBSpline = ModelAPI_Feature::feature(theBSplinePoles->owner());
+
+ std::ostringstream aName;
+ aName << aBSpline->name();
+ if (theAuxFeature->getKind() == SketchPlugin_Point::ID())
+ aName << "_" << theBSplinePoles->id() << "_" << thePoleIndex1;
+ else
+ aName << "_segment_" << thePoleIndex1 << "_" << thePoleIndex2;
+
+ theAuxFeature->data()->setName(aName.str());
+ theAuxFeature->lastResult()->data()->setName(aName.str());
+}
+
FeaturePtr SketchPlugin_MacroBSpline::createAuxiliaryPole(AttributePoint2DArrayPtr theBSplinePoles,
const int thePoleIndex)
{
aCoord->setValue(aPole);
aPointFeature->execute();
-
- std::ostringstream aName;
- aName << aBSpline->name() << "_" << theBSplinePoles->id() << "_" << thePoleIndex;
- aPointFeature->data()->setName(aName.str());
- aPointFeature->lastResult()->data()->setName(aName.str());
+ assignDefaultNameForAux(aPointFeature, theBSplinePoles, thePoleIndex);
// internal constraint to keep position of the point
createInternalConstraint(aSketch, aCoord, theBSplinePoles, thePoleIndex);
aLineEnd->setValue(theBSplinePoles->pnt(thePoleIndex2));
aLineFeature->execute();
-
- std::ostringstream aName;
- aName << aBSpline->name() << "_segment_" << thePoleIndex1 << "_" << thePoleIndex2;
- aLineFeature->data()->setName(aName.str());
- aLineFeature->lastResult()->data()->setName(aName.str());
+ assignDefaultNameForAux(aLineFeature, theBSplinePoles, thePoleIndex1, thePoleIndex2);
// internal constraints to keep the segment position
createInternalConstraint(aSketch, aLineStart, theBSplinePoles, thePoleIndex1);
static void createAuxiliarySegment(std::shared_ptr<GeomDataAPI_Point2DArray> theBSplinePoles,
const int thePoleIndex1,
const int thePoleIndex2);
+ /// Set name of auxiliary feature representing the control polygon
+ static void assignDefaultNameForAux(FeaturePtr theAuxFeature,
+ std::shared_ptr<GeomDataAPI_Point2DArray> theBSplinePoles,
+ const int thePoleIndex1,
+ const int thePoleIndex2 = -1);
friend class SketchPlugin_BSplineBase;
private:
--- /dev/null
+# Copyright (C) 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
+#
+
+"""
+ Test for adding a pole to already created B-spline curve
+"""
+
+from salome.shaper import model
+from GeomAPI import *
+import random
+
+TOLERANCE = 1.e-7
+
+def assertSubFeatures(theSketch, theNbPoints, theNbLines, theNbSplines, theNbSplinesP, theNbCoincidences, theNbInternal):
+ model.testNbSubFeatures(theSketch, "SketchPoint", theNbPoints)
+ model.testNbSubFeatures(theSketch, "SketchLine", theNbLines)
+ model.testNbSubFeatures(theSketch, "SketchBSpline", theNbSplines)
+ model.testNbSubFeatures(theSketch, "SketchBSplinePeriodic", theNbSplinesP)
+ model.testNbSubFeatures(theSketch, "SketchConstraintCoincidence", theNbCoincidences)
+ model.testNbSubFeatures(theSketch, "SketchConstraintCoincidenceInternal", theNbInternal)
+
+def assertPoles(thePoles, theReference):
+ assert(thePoles.size() == len(theReference))
+ for ind in range(0, len(theReference)):
+ pole = thePoles.pnt(ind)
+ ref = GeomAPI_Pnt2d(theReference[ind][0], theReference[ind][1])
+ assert(model.distancePointPoint(pole, ref) < TOLERANCE), "Index = {}, pole = ({}, {}), refdata = ({}, {})".format(ind, pole.x(), pole.y(), ref.x(), ref.y())
+
+
+model.begin()
+partSet = model.moduleDocument()
+Part_1 = model.addPart(partSet)
+Part_1_doc = Part_1.document()
+Sketch_1 = model.addSketch(Part_1_doc, model.defaultPlane("XOY"))
+
+SketchBSpline_1_poles = [(-25, 5), (-15, 35), (15, 35), (28, 5)]
+SketchBSpline_1 = Sketch_1.addSpline(poles = SketchBSpline_1_poles)
+[SketchPoint_1, SketchPoint_2, SketchPoint_3, SketchPoint_4] = SketchBSpline_1.controlPoles(auxiliary = [0, 1, 2, 3])
+[SketchLine_1, SketchLine_2, SketchLine_3] = SketchBSpline_1.controlPolygon(auxiliary = [0, 1, 2])
+
+SketchBSplinePeriodic_1_poles = [(-20, -10), (20, -40), (20, -10), (-20, -40)]
+SketchBSplinePeriodic_1 = Sketch_1.addSpline(poles = SketchBSplinePeriodic_1_poles, periodic = True)
+[SketchPoint_5, SketchPoint_6, SketchPoint_7, SketchPoint_8] = SketchBSplinePeriodic_1.controlPoles(auxiliary = [0, 1, 2, 3])
+[SketchLine_4, SketchLine_5, SketchLine_6, SketchLine_7] = SketchBSplinePeriodic_1.controlPolygon(auxiliary = [0, 1, 2, 3])
+model.do()
+
+# check original values
+NBPOINTS = 8
+NBLINES = 7
+NBSPLINES = 1
+NBSPLINESPERIODIC = 1
+NBCOINCIDENCES = 0
+NBINTERNAL = 22
+assertSubFeatures(Sketch_1, NBPOINTS, NBLINES, NBSPLINES, NBSPLINESPERIODIC, NBCOINCIDENCES, NBINTERNAL)
+assertPoles(SketchBSpline_1.poles(), SketchBSpline_1_poles)
+assertPoles(SketchBSplinePeriodic_1.poles(), SketchBSplinePeriodic_1_poles)
+
+# add poles to non-periodic B-spline
+ind = 0
+while ind < len(SketchBSpline_1_poles):
+ x = random.uniform(-25, 25)
+ y = random.uniform(5, 40)
+ SketchBSpline_1.insertPole(ind, GeomAPI_Pnt2d(x, y))
+ if ind + 1 < len(SketchBSpline_1_poles):
+ SketchBSpline_1_poles.insert(ind + 1, (x, y))
+ else:
+ SketchBSpline_1_poles.insert(len(SketchBSpline_1_poles) - 1, (x, y))
+ ind += 2
+ model.do()
+
+ NBPOINTS += 1
+ NBLINES += 1
+ NBINTERNAL += 3
+ assertSubFeatures(Sketch_1, NBPOINTS, NBLINES, NBSPLINES, NBSPLINESPERIODIC, NBCOINCIDENCES, NBINTERNAL)
+ assertPoles(SketchBSpline_1.poles(), SketchBSpline_1_poles)
+
+# add poles to periodic B-spline
+ind = 0
+while ind < len(SketchBSplinePeriodic_1_poles):
+ x = random.uniform(-25, 25)
+ y = random.uniform(-45, -5)
+ SketchBSplinePeriodic_1.insertPole(ind, GeomAPI_Pnt2d(x, y))
+ SketchBSplinePeriodic_1_poles.insert(ind + 1, (x, y))
+ ind += 2
+ model.do()
+
+ NBPOINTS += 1
+ NBLINES += 1
+ NBINTERNAL += 3
+ assertSubFeatures(Sketch_1, NBPOINTS, NBLINES, NBSPLINES, NBSPLINESPERIODIC, NBCOINCIDENCES, NBINTERNAL)
+ assertPoles(SketchBSplinePeriodic_1.poles(), SketchBSplinePeriodic_1_poles)
+
+model.end()
+
+# check error on incorrect action
+model.begin()
+assert(not SketchBSpline_1.feature().customAction("wrong_action"))
+model.end()
+
+#assert(model.checkPythonDump())
std::shared_ptr<GeomDataAPI_Point2DArray> anAttribute =
std::dynamic_pointer_cast<GeomDataAPI_Point2DArray>(theAttribute);
+ std::vector<PointWrapperPtr> aPointsArray = aWrapper->array();
+ std::vector<PointWrapperPtr>::iterator aPos = aPointsArray.begin();
if (aWrapper->size() != anAttribute->size()) {
- std::vector<PointWrapperPtr> aPointsArray = aWrapper->array();
- std::vector<PointWrapperPtr>::iterator aPos = aPointsArray.begin();
while (anAttribute->size() > (int)aPointsArray.size()) {
// add points to the middle of array
GeomPnt2dPtr aValue;
aWrapper->setArray(aPointsArray);
}
+ else {
+ // update coordinates of points
+ for (int anIndex = 0; aPos != aPointsArray.end(); ++aPos, ++anIndex) {
+ const GCSPointPtr& aGCSPoint = (*aPos)->point();
+ GeomPnt2dPtr aCoord = anAttribute->pnt(anIndex);
+ *aGCSPoint->x = aCoord->x();
+ *aGCSPoint->y = aCoord->y();
+ }
+ }
}
else if (theEntity->type() == ENTITY_SCALAR_ARRAY) {
std::shared_ptr<PlaneGCSSolver_ScalarArrayWrapper> aWrapper =