[Sketcher] Allow multiplicity change of B-Spline end knots
The first and last knots (which are often also poles) of a B-Spline are not represented in sketcher as knots, but as end points of the curve. This creates a problem when we want to change the multiplicities of those knots. As a workaround, these points are treated differently. NOTE: While it is technically possible to have end knots in a non-periodic spline with degree <= degree of the curve, `Geom_BSplineCurve::RemoveKnot()` fails for the first and last knots, so we are stuck with this. So, this commit effectively only makes knot multiplicity change possible for periodic splines. For non-periodic splines this commit just changes the confusing "no knot is selected" message to an unhelpful "multiplicity modification failed".
This commit is contained in:
committed by
abdullahtahiriyo
parent
0a02853bb7
commit
61a7654094
@@ -91,6 +91,47 @@ void ShowRestoreInformationLayer(const char * visibleelementname)
|
||||
hGrp->SetBool(visibleelementname, !status);
|
||||
}
|
||||
|
||||
/// For a knot given by (GeoId, PosId) finds the B-Spline and the knot's
|
||||
/// index within it (by OCC numbering).
|
||||
/// Returns true if the entities are found, false otherwise.
|
||||
/// If returns false, `splineGeoId` and `knotIndexOCC` have garbage values.
|
||||
bool findBSplineAndKnotIndex(Sketcher::SketchObject* Obj,
|
||||
int knotGeoId, Sketcher::PointPos knotPosId,
|
||||
int& splineGeoId, int& knotIndexOCC)
|
||||
{
|
||||
for (auto const constraint : Obj->Constraints.getValues()) {
|
||||
if (constraint->Type == Sketcher::InternalAlignment
|
||||
&& constraint->First == knotGeoId
|
||||
&& constraint->AlignmentType == Sketcher::BSplineKnotPoint)
|
||||
{
|
||||
splineGeoId = constraint->Second;
|
||||
knotIndexOCC = constraint->InternalAlignmentIndex + 1;
|
||||
return true; // we have already found our knot.
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: what to do if multiple splines have the same first/last point?
|
||||
const Part::Geometry *geo = Obj->getGeometry(knotGeoId);
|
||||
if (geo->getTypeId() == Part::GeomBSplineCurve::getClassTypeId()) {
|
||||
splineGeoId = knotGeoId;
|
||||
switch (knotPosId) {
|
||||
case Sketcher::PointPos::start:
|
||||
knotIndexOCC = 1;
|
||||
return true;
|
||||
case Sketcher::PointPos::end:
|
||||
knotIndexOCC = static_cast<const Part::GeomBSplineCurve *>(geo)->countKnots();
|
||||
return true;
|
||||
default:
|
||||
// If we reach here something went wrong.
|
||||
// isBsplineKnotOrEndPoint (that we expect is run before) will
|
||||
// only accept spline knotGeoID if knotPosId is start or end.
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// Show/Hide B-spline degree
|
||||
DEF_STD_CMD_A(CmdSketcherBSplineDegree)
|
||||
|
||||
@@ -637,55 +678,48 @@ void CmdSketcherIncreaseKnotMultiplicity::activated(int iMsg)
|
||||
|
||||
openCommand(QT_TRANSLATE_NOOP("Command", "Increase knot multiplicity"));
|
||||
|
||||
bool applied = false;
|
||||
bool notaknot = true;
|
||||
boost::uuids::uuid bsplinetag;
|
||||
|
||||
int GeoId;
|
||||
Sketcher::PointPos PosId;
|
||||
getIdsFromName(SubNames[0], Obj, GeoId, PosId);
|
||||
|
||||
if (isSimpleVertex(Obj, GeoId, PosId)) {
|
||||
const std::vector<Sketcher::Constraint *> &vals = Obj->Constraints.getValues();
|
||||
int splineGeoId;
|
||||
int knotIndexOCC;
|
||||
|
||||
for (std::vector<Sketcher::Constraint *>::const_iterator it= vals.begin(); it != vals.end(); ++it) {
|
||||
if ((*it)->Type == Sketcher::InternalAlignment
|
||||
&& (*it)->First == GeoId
|
||||
&& (*it)->AlignmentType == Sketcher::BSplineKnotPoint)
|
||||
{
|
||||
bsplinetag = Obj->getGeometry((*it)->Second)->getTag();
|
||||
notaknot = false;
|
||||
bool applied = false;
|
||||
bool notaknot = !(isBsplineKnotOrEndPoint(Obj, GeoId, PosId) &&
|
||||
findBSplineAndKnotIndex(Obj, GeoId, PosId, splineGeoId, knotIndexOCC));
|
||||
boost::uuids::uuid bsplinetag;
|
||||
|
||||
try {
|
||||
Gui::cmdAppObjectArgs(selection[0].getObject(),
|
||||
"modifyBSplineKnotMultiplicity(%d, %d, %d) ",
|
||||
(*it)->Second, (*it)->InternalAlignmentIndex + 1, 1);
|
||||
applied = true;
|
||||
if (!notaknot) {
|
||||
bsplinetag = Obj->getGeometry(splineGeoId)->getTag();
|
||||
|
||||
// Warning: GeoId list might have changed
|
||||
// as the consequence of deleting pole circles and
|
||||
// particularly B-spline GeoID might have changed.
|
||||
}
|
||||
catch (const Base::CADKernelError& e) {
|
||||
e.ReportException();
|
||||
if (e.getTranslatable()) {
|
||||
QMessageBox::warning(Gui::getMainWindow(),
|
||||
QObject::tr("CAD Kernel Error"),
|
||||
QObject::tr(e.getMessage().c_str()));
|
||||
}
|
||||
getSelection().clearSelection();
|
||||
}
|
||||
catch (const Base::Exception& e) {
|
||||
e.ReportException();
|
||||
if (e.getTranslatable()) {
|
||||
QMessageBox::warning(Gui::getMainWindow(),
|
||||
QObject::tr("Input Error"),
|
||||
QObject::tr(e.getMessage().c_str()));
|
||||
}
|
||||
getSelection().clearSelection();
|
||||
}
|
||||
break; // we have already found our knot.
|
||||
try {
|
||||
Gui::cmdAppObjectArgs(selection[0].getObject(),
|
||||
"modifyBSplineKnotMultiplicity(%d, %d, %d) ",
|
||||
splineGeoId, knotIndexOCC, 1);
|
||||
applied = true;
|
||||
|
||||
// Warning: GeoId list might have changed
|
||||
// as the consequence of deleting pole circles and
|
||||
// particularly B-spline GeoID might have changed.
|
||||
}
|
||||
catch (const Base::CADKernelError& e) {
|
||||
e.ReportException();
|
||||
if (e.getTranslatable()) {
|
||||
QMessageBox::warning(Gui::getMainWindow(),
|
||||
QObject::tr("CAD Kernel Error"),
|
||||
QObject::tr(e.getMessage().c_str()));
|
||||
}
|
||||
getSelection().clearSelection();
|
||||
}
|
||||
catch (const Base::Exception& e) {
|
||||
e.ReportException();
|
||||
if (e.getTranslatable()) {
|
||||
QMessageBox::warning(Gui::getMainWindow(),
|
||||
QObject::tr("Input Error"),
|
||||
QObject::tr(e.getMessage().c_str()));
|
||||
}
|
||||
getSelection().clearSelection();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -791,42 +825,34 @@ void CmdSketcherDecreaseKnotMultiplicity::activated(int iMsg)
|
||||
|
||||
openCommand(QT_TRANSLATE_NOOP("Command", "Decrease knot multiplicity"));
|
||||
|
||||
bool applied = false;
|
||||
bool notaknot = true;
|
||||
boost::uuids::uuid bsplinetag;
|
||||
|
||||
int GeoId;
|
||||
Sketcher::PointPos PosId;
|
||||
getIdsFromName(SubNames[0], Obj, GeoId, PosId);
|
||||
|
||||
if (isSimpleVertex(Obj, GeoId, PosId))
|
||||
{
|
||||
const std::vector< Sketcher::Constraint * > &vals = Obj->Constraints.getValues();
|
||||
int splineGeoId;
|
||||
int knotIndexOCC;
|
||||
|
||||
for (std::vector< Sketcher::Constraint * >::const_iterator it= vals.begin(); it != vals.end(); ++it) {
|
||||
if ((*it)->Type == Sketcher::InternalAlignment
|
||||
&& (*it)->First == GeoId
|
||||
&& (*it)->AlignmentType == Sketcher::BSplineKnotPoint)
|
||||
{
|
||||
bsplinetag = Obj->getGeometry((*it)->Second)->getTag();
|
||||
notaknot = false;
|
||||
bool applied = false;
|
||||
bool notaknot = !(isBsplineKnotOrEndPoint(Obj, GeoId, PosId) &&
|
||||
findBSplineAndKnotIndex(Obj, GeoId, PosId, splineGeoId, knotIndexOCC));
|
||||
boost::uuids::uuid bsplinetag;
|
||||
|
||||
try {
|
||||
Gui::cmdAppObjectArgs(selection[0].getObject(),
|
||||
"modifyBSplineKnotMultiplicity(%d, %d, %d) ",
|
||||
(*it)->Second, (*it)->InternalAlignmentIndex + 1, -1);
|
||||
applied = true;
|
||||
if (!notaknot) {
|
||||
bsplinetag = Obj->getGeometry(splineGeoId)->getTag();
|
||||
|
||||
// Warning: GeoId list might have changed as the consequence of deleting pole circles and
|
||||
// particularly B-spline GeoID might have changed.
|
||||
}
|
||||
catch (const Base::Exception& e) {
|
||||
QMessageBox::warning(Gui::getMainWindow(), QObject::tr("Error"),
|
||||
QObject::tr(getStrippedPythonExceptionString(e).c_str()));
|
||||
getSelection().clearSelection();
|
||||
}
|
||||
break; // we have already found our knot.
|
||||
}
|
||||
try {
|
||||
Gui::cmdAppObjectArgs(selection[0].getObject(),
|
||||
"modifyBSplineKnotMultiplicity(%d, %d, %d) ",
|
||||
splineGeoId, knotIndexOCC, -1);
|
||||
applied = true;
|
||||
|
||||
// Warning: GeoId list might have changed as the consequence of deleting pole circles and
|
||||
// particularly B-spline GeoID might have changed.
|
||||
}
|
||||
catch (const Base::Exception& e) {
|
||||
QMessageBox::warning(Gui::getMainWindow(), QObject::tr("Error"),
|
||||
QObject::tr(getStrippedPythonExceptionString(e).c_str()));
|
||||
getSelection().clearSelection();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -221,6 +221,21 @@ bool SketcherGui::isBsplineKnot(const Sketcher::SketchObject* Obj, int GeoId)
|
||||
return (gf && gf->getInternalType() == Sketcher::InternalType::BSplineKnotPoint);
|
||||
}
|
||||
|
||||
bool SketcherGui::isBsplineKnotOrEndPoint(const Sketcher::SketchObject* Obj, int GeoId, Sketcher::PointPos PosId)
|
||||
{
|
||||
// check first using geometry facade
|
||||
if (isBsplineKnot(Obj, GeoId))
|
||||
return true;
|
||||
|
||||
const Part::Geometry *geo = Obj->getGeometry(GeoId);
|
||||
// end points of B-Splines are also knots
|
||||
if (geo->getTypeId() == Part::GeomBSplineCurve::getClassTypeId() &&
|
||||
(PosId == Sketcher::PointPos::start || PosId == Sketcher::PointPos::end))
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool SketcherGui::IsPointAlreadyOnCurve(int GeoIdCurve, int GeoIdPoint, Sketcher::PointPos PosIdPoint, Sketcher::SketchObject* Obj)
|
||||
{
|
||||
//This func is a "smartness" behind three-element tangent-, perp.- and angle-via-point.
|
||||
|
||||
@@ -66,7 +66,10 @@ bool inline isEdge(int GeoId, Sketcher::PointPos PosId);
|
||||
|
||||
bool isSimpleVertex(const Sketcher::SketchObject* Obj, int GeoId, Sketcher::PointPos PosId);
|
||||
|
||||
/// Checks if `GeoId` corresponds to a B-Spline knot
|
||||
bool isBsplineKnot(const Sketcher::SketchObject* Obj, int GeoId);
|
||||
/// Checks if the (`GeoId`, `PosId`) pair corresponds to a B-Spline knot, including first and last knots
|
||||
bool isBsplineKnotOrEndPoint(const Sketcher::SketchObject* Obj, int GeoId, Sketcher::PointPos PosId);
|
||||
|
||||
bool IsPointAlreadyOnCurve(int GeoIdCurve, int GeoIdPoint, Sketcher::PointPos PosIdPoint, Sketcher::SketchObject* Obj);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user