}
else { // reset the old array
if (aValuesSize) {
- if (aValuesSize != myArray->Length()) { // old data is not keept, a new array is created
+ if (aValuesSize != myArray->Length()) { // old data is kept in the new array
Handle(TColStd_HArray1OfReal) aNewArray = new TColStd_HArray1OfReal(0, aValuesSize - 1);
+ for (int anIndex = 0; anIndex < aValuesSize && anIndex <= myArray->Upper(); ++anIndex)
+ aNewArray->SetValue(anIndex, myArray->Value(anIndex));
myArray->ChangeArray(aNewArray);
owner()->data()->sendAttributeUpdated(this);
}
}
}
if (aFound) {
- // TODO: add a new pole after found Id
+ // add a new pole after found Id
+ std::ostringstream anActionName;
+ anActionName << SketchPlugin_BSplineBase::ADD_POLE_ACTION_ID() << "#" << aId;
+ if (feature()->customAction(anActionName.str()))
+ updateObject(feature());
restoreValueCustom();
}
//
#include <SketchPlugin_BSplineBase.h>
+
+#include <SketchPlugin_ConstraintCoincidenceInternal.h>
+#include <SketchPlugin_Line.h>
+#include <SketchPlugin_MacroBSpline.h>
#include <SketchPlugin_Sketch.h>
+#include <Events_InfoMessage.h>
+
#include <GeomAlgoAPI_EdgeBuilder.h>
+#include <GeomAPI_BSpline2d.h>
#include <GeomAPI_Pnt2d.h>
#include <GeomDataAPI_Point2D.h>
#include <GeomDataAPI_Point2DArray.h>
+#include <ModelAPI_AttributeDouble.h>
#include <ModelAPI_AttributeDoubleArray.h>
#include <ModelAPI_AttributeIntArray.h>
#include <ModelAPI_AttributeInteger.h>
//// }
}
}
+
+bool SketchPlugin_BSplineBase::customAction(const std::string& theActionId)
+{
+ // parse for the action and an index divided by '#'
+ std::string anAction;
+ int anIndex = -1;
+ size_t pos = theActionId.find('#');
+ if (pos != std::string::npos) {
+ anAction = theActionId.substr(0, pos);
+ anIndex = std::stoi(theActionId.substr(pos + 1));
+ }
+
+ if (anAction == ADD_POLE_ACTION_ID()) {
+ return addPole(anIndex);
+ }
+
+ std::string aMsg = "Error: Feature \"%1\" does not support action \"%2\".";
+ Events_InfoMessage("SketchPlugin_BSplineBase", aMsg).arg(getKind()).arg(anAction).send();
+ return false;
+}
+
+bool SketchPlugin_BSplineBase::addPole(const int theAfter)
+{
+ AttributePoint2DArrayPtr aPolesArray =
+ std::dynamic_pointer_cast<GeomDataAPI_Point2DArray>(attribute(POLES_ID()));
+ AttributeDoubleArrayPtr aWeightsArray = data()->realArray(WEIGHTS_ID());
+
+ int anAfter = (!isPeriodic() && theAfter == aPolesArray->size() - 1) ? theAfter - 1 : theAfter;
+
+ // find internal coincidences applied to the poles with greater indices
+ std::list<AttributeIntegerPtr> aCoincidentPoleIndex;
+ 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())
+ anIndex = aFeature->integer(SketchPlugin_ConstraintCoincidenceInternal::INDEX_ENTITY_A());
+ else if ((*anIt)->id() == SketchPlugin_ConstraintCoincidenceInternal::ENTITY_B())
+ anIndex = aFeature->integer(SketchPlugin_ConstraintCoincidenceInternal::INDEX_ENTITY_B());
+
+ if (anIndex && anIndex->isInitialized()) {
+ if (anIndex->value() > anAfter)
+ aCoincidentPoleIndex.push_back(anIndex);
+ 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()) {
+ hasAuxSegment = true;
+ aCoincidentPoleIndex.push_back(anIndex);
+ }
+ }
+ }
+ }
+ }
+
+ bool aWasBlocked = data()->blockSendAttributeUpdated(true);
+
+ // add new pole and default weight
+ std::list<GeomPnt2dPtr> aPoles;
+ aPolesArray->setSize(aPolesArray->size() + 1);
+ aPolesArray->setPnt(aPolesArray->size() - 1, aPolesArray->pnt(0)); // for periodic spline
+ for (int i = aPolesArray->size() - 2; i > anAfter; --i) {
+ aPoles.push_front(aPolesArray->pnt(i));
+ aPolesArray->setPnt(i + 1, aPoles.front());
+ }
+
+ GeomPnt2dPtr aCurPole = aPolesArray->pnt(anAfter);
+ GeomPnt2dPtr aNextPole = aPolesArray->pnt(anAfter + 1);
+ aPolesArray->setPnt(anAfter + 1, (aCurPole->x() + aNextPole->x()) * 0.5,
+ (aCurPole->y() + aNextPole->y()) * 0.5);
+ for (int i = anAfter + 1; i >= 0; --i)
+ aPoles.push_front(aPolesArray->pnt(i));
+
+ std::list<double> aWeights;
+ for (int i = 0; i < aWeightsArray->size(); ++i) {
+ aWeights.push_back(aWeightsArray->value(i));
+ if (i == anAfter)
+ aWeights.push_back(1.0); // default weight
+ }
+ aWeightsArray->setSize(aWeightsArray->size() + 1);
+ std::list<double>::iterator aWIt = aWeights.begin();
+ for (int i = 0; i < aWeightsArray->size(); ++i, ++aWIt)
+ aWeightsArray->setValue(i, *aWIt);
+
+ // recalculate knots and multiplicities
+ std::shared_ptr<GeomAPI_BSpline2d> aBSplineCurve(
+ new GeomAPI_BSpline2d(aPoles, aWeights, isPeriodic()));
+
+ integer(DEGREE_ID())->setValue(aBSplineCurve->degree());
+
+ AttributeDoubleArrayPtr aKnotsAttr = data()->realArray(SketchPlugin_BSplineBase::KNOTS_ID());
+ std::list<double> aKnots = aBSplineCurve->knots();
+ int aSize = (int)aKnots.size();
+ aKnotsAttr->setSize(aSize);
+ std::list<double>::iterator aKIt = aKnots.begin();
+ for (int index = 0; index < aSize; ++index, ++aKIt)
+ aKnotsAttr->setValue(index, *aKIt);
+
+ AttributeIntArrayPtr aMultsAttr = data()->intArray(SketchPlugin_BSplineBase::MULTS_ID());
+ std::list<int> aMults = aBSplineCurve->mults();
+ aSize = (int)aMults.size();
+ aMultsAttr->setSize(aSize);
+ std::list<int>::iterator aMIt = aMults.begin();
+ for (int index = 0; index < aSize; ++index, ++aMIt)
+ aMultsAttr->setValue(index, *aMIt);
+
+ data()->blockSendAttributeUpdated(aWasBlocked, true);
+
+ // update indices of internal coincidences
+ for (std::list<AttributeIntegerPtr>::iterator aCIt = aCoincidentPoleIndex.begin();
+ aCIt != aCoincidentPoleIndex.end(); ++aCIt)
+ (*aCIt)->setValue((*aCIt)->value() + 1);
+
+ // create auxiliary segment and pole updating the control polygon
+ SketchPlugin_MacroBSpline::createAuxiliaryPole(aPolesArray, anAfter + 1);
+ if (hasAuxSegment)
+ SketchPlugin_MacroBSpline::createAuxiliarySegment(aPolesArray, anAfter, anAfter + 1);
+
+ return true;
+}
return ID;
}
+ /// name for add pole action
+ inline static const std::string& ADD_POLE_ACTION_ID()
+ {
+ static const std::string ID("AddPole");
+ return ID;
+ }
+
/// Returns true is sketch element is under the rigid constraint
SKETCHPLUGIN_EXPORT virtual bool isFixed();
/// Creates a new part document if needed
SKETCHPLUGIN_EXPORT virtual void execute();
+ /// Updates the B-spline curve.
+ /// \param[in] theActionId action key id (in following form: Action#Index)
+ /// \return \c false in case the action not performed.
+ SKETCHPLUGIN_EXPORT virtual bool customAction(const std::string& theActionId);
+
protected:
/// Called from the derived class
SketchPlugin_BSplineBase();
/// \brief Return \c true if the B-spline curve is periodic
virtual bool isPeriodic() const = 0;
+
+ /// Add new pole after the pole with the given index
+ bool addPole(const int theAfter);
};
#endif
#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
+/// Create internal coincidence constraint with B-spline pole
static void createInternalConstraint(SketchPlugin_Sketch* theSketch,
AttributePtr thePoint,
AttributePtr theBSplinePoles,
int aSize = aPoles->size();
// poles
for (int index = 0; index < aSize; ++index)
- thePoles.push_back(createAuxiliaryPole(theBSpline, aPoles, index));
+ thePoles.push_back(createAuxiliaryPole(aPoles, index));
// segments
for (int index = 1; index < aSize; ++index)
- createAuxiliarySegment(theBSpline, aPoles, index - 1, index);
+ createAuxiliarySegment(aPoles, index - 1, index);
if (myIsPeriodic) {
// additional segment to close the control polygon
- createAuxiliarySegment(theBSpline, aPoles, aSize - 1, 0);
+ createAuxiliarySegment(aPoles, aSize - 1, 0);
}
}
// ========================== Auxiliary functions ===========================================
-FeaturePtr createAuxiliaryPole(FeaturePtr theBSpline,
- AttributePoint2DArrayPtr theBSplinePoles,
- const int thePoleIndex)
+FeaturePtr SketchPlugin_MacroBSpline::createAuxiliaryPole(AttributePoint2DArrayPtr theBSplinePoles,
+ const int thePoleIndex)
{
+ FeaturePtr aBSpline = ModelAPI_Feature::feature(theBSplinePoles->owner());
+
SketchPlugin_Sketch* aSketch =
- std::dynamic_pointer_cast<SketchPlugin_Feature>(theBSpline)->sketch();
+ std::dynamic_pointer_cast<SketchPlugin_Feature>(aBSpline)->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);
+ aPointFeature->reference(SketchPlugin_Point::PARENT_ID())->setValue(aBSpline);
GeomPnt2dPtr aPole = theBSplinePoles->pnt(thePoleIndex);
aPointFeature->execute();
std::ostringstream aName;
- aName << theBSpline->name() << "_" << theBSplinePoles->id() << "_" << thePoleIndex;
+ aName << aBSpline->name() << "_" << theBSplinePoles->id() << "_" << thePoleIndex;
aPointFeature->data()->setName(aName.str());
aPointFeature->lastResult()->data()->setName(aName.str());
return aPointFeature;
}
-void createAuxiliarySegment(FeaturePtr theBSpline,
- AttributePoint2DArrayPtr theBSplinePoles,
- const int thePoleIndex1,
- const int thePoleIndex2)
+void SketchPlugin_MacroBSpline::createAuxiliarySegment(AttributePoint2DArrayPtr theBSplinePoles,
+ const int thePoleIndex1,
+ const int thePoleIndex2)
{
+ FeaturePtr aBSpline = ModelAPI_Feature::feature(theBSplinePoles->owner());
+
SketchPlugin_Sketch* aSketch =
- std::dynamic_pointer_cast<SketchPlugin_Feature>(theBSpline)->sketch();
+ std::dynamic_pointer_cast<SketchPlugin_Feature>(aBSpline)->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);
+ aLineFeature->reference(SketchPlugin_Point::PARENT_ID())->setValue(aBSpline);
AttributePoint2DPtr aLineStart = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
aLineFeature->attribute(SketchPlugin_Line::START_ID()));
aLineFeature->execute();
std::ostringstream aName;
- aName << theBSpline->name() << "_segment_" << thePoleIndex1 << "_" << thePoleIndex2;
+ aName << aBSpline->name() << "_segment_" << thePoleIndex1 << "_" << thePoleIndex2;
aLineFeature->data()->setName(aName.str());
aLineFeature->lastResult()->data()->setName(aName.str());
class GeomAPI_Circ2d;
class GeomAPI_Pnt2d;
+class GeomDataAPI_Point2DArray;
+
/**\class SketchPlugin_MacroBSpline
* \ingroup Plugins
* \brief Feature for creation of the new B-spline in Sketch.
void createControlPolygon(FeaturePtr theBSpline, std::list<FeaturePtr>& thePoles);
void constraintsForPoles(const std::list<FeaturePtr>& thePoles);
+ /// Create Point feature coincident with the B-spline pole
+ static FeaturePtr createAuxiliaryPole(std::shared_ptr<GeomDataAPI_Point2DArray> theBSplinePoles,
+ const int thePoleIndex);
+ /// Create segment between consequtive B-spline poles
+ static void createAuxiliarySegment(std::shared_ptr<GeomDataAPI_Point2DArray> theBSplinePoles,
+ const int thePoleIndex1,
+ const int thePoleIndex2);
+ friend class SketchPlugin_BSplineBase;
+
+private:
std::list<double> myKnots;
std::list<int> myMultiplicities;
int myDegree;
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
- aPointsArray.insert(--aPointsArray.end(), createPoint(GeomPnt2dPtr(), myStorage));
+ GeomPnt2dPtr aValue;
+ for (; aPos != aPointsArray.end(); ++aPos) {
+ aValue = anAttribute->pnt(aPos - aPointsArray.begin());
+ if (aValue->distance(PlaneGCSSolver_Tools::point(*aPos)) > tolerance)
+ break;
+ }
+ int aShift = aPos - aPointsArray.begin();
+ aPointsArray.insert(aPos, createPoint(aValue, myStorage));
+ aPos = aPointsArray.begin() + aShift;
}
while (anAttribute->size() < (int)aPointsArray.size()) {
aParamsToRemove = PlaneGCSSolver_Tools::parameters(aWrapper);
std::shared_ptr<PlaneGCSSolver_ScalarArrayWrapper> aNewArray =
std::dynamic_pointer_cast<PlaneGCSSolver_ScalarArrayWrapper>(
- createAttribute(theAttribute));
+ createScalarArray(theAttribute, myStorage));
aWrapper->setArray(aNewArray->array());
isUpdated = true;
}
}
}
}
+
+void SketchSolver_ConstraintCoincidence::adjustConstraint()
+{
+ if (myBaseConstraint->getKind() == SketchPlugin_ConstraintCoincidenceInternal::ID()) {
+ AttributeIntegerPtr anIndexA = myBaseConstraint->integer(
+ SketchPlugin_ConstraintCoincidenceInternal::INDEX_ENTITY_A());
+ AttributeIntegerPtr anIndexB = myBaseConstraint->integer(
+ SketchPlugin_ConstraintCoincidenceInternal::INDEX_ENTITY_B());
+ if ((anIndexA && anIndexA->isInitialized()) ||
+ (anIndexB && anIndexB->isInitialized())) {
+ remove();
+ process();
+ }
+ }
+}
virtual void getAttributes(EntityWrapperPtr& theValue,
std::vector<EntityWrapperPtr>& theAttributes);
+ /// \brief This method is used in derived objects to check consistency of constraint.
+ /// E.g. the distance between line and point may be signed.
+ virtual void adjustConstraint();
+
protected:
bool myInSolver; ///< shows the constraint is added to the solver
EntityWrapperPtr myFeatureExtremities[2]; ///< extremities of a feature, a point is coincident to