#include <SketchPlugin_MacroBSpline.h>
#include <SketchPlugin_BSpline.h>
+#include <SketchPlugin_BSplinePeriodic.h>
#include <SketchPlugin_ConstraintCoincidenceInternal.h>
#include <SketchPlugin_Line.h>
#include <SketchPlugin_Point.h>
#include <GeomAlgoAPI_EdgeBuilder.h>
#include <GeomAlgoAPI_PointBuilder.h>
+#include <GeomAPI_BSpline2d.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
+/// Create internal coincidence constraint with B-spline pole
static void createInternalConstraint(SketchPlugin_Sketch* theSketch,
AttributePtr thePoint,
AttributePtr theBSplinePoles,
SketchPlugin_MacroBSpline::SketchPlugin_MacroBSpline()
: SketchPlugin_SketchEntity(),
+ myDegree(3),
myIsPeriodic(false)
{
}
+SketchPlugin_MacroBSpline::SketchPlugin_MacroBSpline(bool isPeriodic)
+ : SketchPlugin_SketchEntity(),
+ myDegree(3),
+ myIsPeriodic(isPeriodic)
+{
+}
+
void SketchPlugin_MacroBSpline::initAttributes()
{
data()->addAttribute(POLES_ID(), GeomDataAPI_Point2DArray::typeId());
data()->addAttribute(REF_POLES_ID(), ModelAPI_AttributeRefAttrList::typeId());
ModelAPI_Session::get()->validators()->registerNotObligatory(getKind(), REF_POLES_ID());
+ data()->addAttribute(CONTROL_POLYGON_ID(), ModelAPI_AttributeBoolean::typeId());
+
data()->addAttribute(AUXILIARY_ID(), ModelAPI_AttributeBoolean::typeId());
}
{
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);
+ if (boolean(CONTROL_POLYGON_ID())->value()) {
+ 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
FeaturePtr SketchPlugin_MacroBSpline::createBSplineFeature()
{
- FeaturePtr aBSpline = sketch()->addFeature(SketchPlugin_BSpline::ID());
+ if (myKnots.empty() || myMultiplicities.empty())
+ getAISObject(AISObjectPtr()); // fill B-spline parameters
+
+ FeaturePtr aBSpline = sketch()->addFeature(
+ myIsPeriodic ? SketchPlugin_BSplinePeriodic::ID() : SketchPlugin_BSpline::ID());
+
+ aBSpline->integer(SketchPlugin_BSplineBase::DEGREE_ID())->setValue(myDegree);
AttributePoint2DArrayPtr aPoles = std::dynamic_pointer_cast<GeomDataAPI_Point2DArray>(
- aBSpline->attribute(SketchPlugin_BSpline::POLES_ID()));
+ aBSpline->attribute(SketchPlugin_BSplineBase::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());
+ aBSpline->data()->realArray(SketchPlugin_BSplineBase::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(
+ AttributeDoubleArrayPtr aKnots =
+ aBSpline->data()->realArray(SketchPlugin_BSplineBase::KNOTS_ID());
+ aSize = (int)myKnots.size();
+ aKnots->setSize(aSize);
+ std::list<double>::iterator aKIt = myKnots.begin();
+ for (int index = 0; index < aSize; ++index, ++aKIt)
+ aKnots->setValue(index, *aKIt);
+
+ AttributeIntArrayPtr aMults = aBSpline->data()->intArray(SketchPlugin_BSplineBase::MULTS_ID());
+ aSize = (int)myMultiplicities.size();
+ aMults->setSize(aSize);
+ std::list<int>::iterator aMIt = myMultiplicities.begin();
+ for (int index = 0; index < aSize; ++index, ++aMIt)
+ aMults->setValue(index, *aMIt);
+
+ if (!myIsPeriodic) {
+ AttributePoint2DPtr aStartPoint = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
+ aBSpline->attribute(SketchPlugin_BSpline::START_ID()));
+ aStartPoint->setValue(aPoles->pnt(0));
+
+ AttributePoint2DPtr aEndPoint = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
+ aBSpline->attribute(SketchPlugin_BSpline::END_ID()));
+ aEndPoint->setValue(aPoles->pnt(aPoles->size() - 1));
+ }
+
+ aBSpline->boolean(SketchPlugin_SketchEntity::AUXILIARY_ID())->setValue(
boolean(AUXILIARY_ID())->value());
aBSpline->execute();
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(aPoles, aSize - 1, 0);
+ }
}
void SketchPlugin_MacroBSpline::constraintsForPoles(const std::list<FeaturePtr>& thePoles)
std::dynamic_pointer_cast<GeomDataAPI_Point2DArray>(attribute(POLES_ID()));
AttributeDoubleArrayPtr aWeightsArray = data()->realArray(WEIGHTS_ID());
+ if (aPolesArray->size() < 2)
+ return AISObjectPtr();
+
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());
+ // convert poles to vertices and collect weights
+ std::list<GeomPnt2dPtr> aPoles2D;
+ std::list<double> aWeights;
for (int anIndex = 0; anIndex < aPolesArray->size(); ++anIndex) {
double aWeight = aWeightsArray->value(anIndex);
if (aWeight < 1.e-10)
aWeights.push_back(aWeight);
GeomPnt2dPtr aPole = aPolesArray->pnt(anIndex);
+ aPoles2D.push_back(aPole);
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);
+ std::shared_ptr<GeomAPI_BSpline2d> aBSplineCurve;
+ try {
+ aBSplineCurve.reset(new GeomAPI_BSpline2d(aPoles2D, aWeights, myIsPeriodic));
+ } catch (...) {
+ // cannot build a B-spline curve
+ return AISObjectPtr();
+ }
+ GeomShapePtr anEdge =
+ GeomAlgoAPI_EdgeBuilder::bsplineOnPlane(aSketch->coordinatePlane(), aBSplineCurve);
if (!anEdge)
return AISObjectPtr();
+ // store transient parameters of B-spline curve
+ myDegree = aBSplineCurve->degree();
+ myKnots = aBSplineCurve->knots();
+ myMultiplicities = aBSplineCurve->mults();
+
aShapes.push_back(anEdge);
GeomShapePtr aCompound = GeomAlgoAPI_CompoundBuilder::compound(aShapes);
// ========================== Auxiliary functions ===========================================
-FeaturePtr createAuxiliaryPole(FeaturePtr theBSpline,
- AttributePoint2DArrayPtr theBSplinePoles,
- const int thePoleIndex)
+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)
{
+ 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);
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());
+ assignDefaultNameForAux(aPointFeature, theBSplinePoles, thePoleIndex);
// 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)
+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()));
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());
+ assignDefaultNameForAux(aLineFeature, theBSplinePoles, thePoleIndex1, thePoleIndex2);
// internal constraints to keep the segment position
createInternalConstraint(aSketch, aLineStart, theBSplinePoles, thePoleIndex1);