Files
create/src/Mod/Sketcher/App/Sketch.h
Ajinkya Dahale 65b4dd10ae [Sketcher] Expose general tangency with B-splines to Sketcher
The following commits were squashed into this

[Sketcher] Handle some corner cases in AngleViaPoint

[Sketcher] Avoid redundant constraints with B-splines...

When involving tangent, perpendicular and angle constraints.

[Sketcher] Add pre-commit changes

[Sketcher] Do not allow 2-selection tangent with B-spline

Also...

[Sketcher] Report error when using direct tangency with B-splines

[Sketcher] Fix malformed constraint when B-spline is selected second

To clarify, this means the second curve selected. The position of the point in
selection order does not matter in angle-via-point.

[Sketcher] Fix wrong number for B-Spline tangent on redundancy

[Sketcher] Remove existing point-on-object in some redundant cases

Particularly when point constrained on a B-spline is being used for
tangent, perpendicular or angle via point with the same B-spline.

[Sketcher] Fix direction issue with B-spline tangents.

Without these changes the solver might try to "twist" the B-spline to make the
angle between curves be 0 instead of PI (which may be closer to the initial shape).
2024-02-08 20:04:28 +05:30

813 lines
34 KiB
C++

/***************************************************************************
* Copyright (c) 2010 Jürgen Riegel <juergen.riegel@web.de> *
* *
* This file is part of the FreeCAD CAx development system. *
* *
* This library is free software; you can redistribute it and/or *
* modify it under the terms of the GNU Library General Public *
* License as published by the Free Software Foundation; either *
* version 2 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 Library General Public License for more details. *
* *
* You should have received a copy of the GNU Library General Public *
* License along with this library; see the file COPYING.LIB. If not, *
* write to the Free Software Foundation, Inc., 59 Temple Place, *
* Suite 330, Boston, MA 02111-1307, USA *
* *
***************************************************************************/
#ifndef SKETCHER_SKETCH_H
#define SKETCHER_SKETCH_H
#include <Base/Persistence.h>
#include <CXX/Objects.hxx>
#include <Mod/Part/App/TopoShape.h>
#include "Constraint.h"
#include "GeoList.h"
#include "planegcs/GCS.h"
namespace Sketcher
{
// Forward declarations
class SolverGeometryExtension;
class SketcherExport Sketch: public Base::Persistence
{
TYPESYSTEM_HEADER_WITH_OVERRIDE();
public:
Sketch();
~Sketch() override;
// from base class
unsigned int getMemSize() const override;
void Save(Base::Writer& /*writer*/) const override;
void Restore(Base::XMLReader& /*reader*/) override;
/// solve the actual set up sketch
int solve();
/// resets the solver
int resetSolver();
/// get standard (aka fine) solver precision
double getSolverPrecision()
{
return GCSsys.getFinePrecision();
}
/// delete all geometry and constraints, leave an empty sketch
void clear();
/** set the sketch up with geoms and constraints
*
* returns the degree of freedom of a sketch and calculates a list of
* conflicting constraints
*
* 0 degrees of freedom correspond to a fully constrained sketch
* -1 degrees of freedom correspond to an over-constrained sketch
* positive degrees of freedom correspond to an under-constrained sketch
*
* an over-constrained sketch will always contain conflicting constraints
* a fully constrained or under-constrained sketch may contain conflicting
* constraints or may not
*/
int setUpSketch(const std::vector<Part::Geometry*>& GeoList,
const std::vector<Constraint*>& ConstraintList,
int extGeoCount = 0);
/// return the actual geometry of the sketch a TopoShape
Part::TopoShape toShape() const;
/// add unspecified geometry
int addGeometry(const Part::Geometry* geo, bool fixed = false);
/// add unspecified geometry
int addGeometry(const std::vector<Part::Geometry*>& geo, bool fixed = false);
/// add unspecified geometry, where each element's "fixed" status is given by the
/// blockedGeometry array
int addGeometry(const std::vector<Part::Geometry*>& geo,
const std::vector<bool>& blockedGeometry);
/// get boolean list indicating whether the geometry is to be blocked or not
void getBlockedGeometry(std::vector<bool>& blockedGeometry,
std::vector<bool>& unenforceableConstraints,
const std::vector<Constraint*>& ConstraintList) const;
/// returns the actual geometry
std::vector<Part::Geometry*> extractGeometry(bool withConstructionElements = true,
bool withExternalElements = false) const;
GeoListFacade extractGeoListFacade() const;
void updateExtension(int geoId, std::unique_ptr<Part::GeometryExtension>&& ext);
/// get the geometry as python objects
Py::Tuple getPyGeometry() const;
/// retrieves the index of a point
int getPointId(int geoId, PointPos pos) const;
/// retrieves a point
Base::Vector3d getPoint(int geoId, PointPos pos) const;
// Inline methods
inline bool hasConflicts() const
{
return !Conflicting.empty();
}
inline const std::vector<int>& getConflicting() const
{
return Conflicting;
}
inline bool hasRedundancies() const
{
return !Redundant.empty();
}
inline const std::vector<int>& getRedundant() const
{
return Redundant;
}
inline bool hasPartialRedundancies() const
{
return !PartiallyRedundant.empty();
}
inline const std::vector<int>& getPartiallyRedundant() const
{
return PartiallyRedundant;
}
inline float getSolveTime() const
{
return SolveTime;
}
inline bool hasMalformedConstraints() const
{
return !MalformedConstraints.empty();
}
inline const std::vector<int>& getMalformedConstraints() const
{
return MalformedConstraints;
}
public:
std::set<std::pair<int, Sketcher::PointPos>> getDependencyGroup(int geoId, PointPos pos) const;
std::shared_ptr<SolverGeometryExtension> getSolverExtension(int geoId) const;
public:
/** set the datum of a distance or angle constraint to a certain value and solve
* This can cause the solving to fail!
*/
int setDatum(int constrId, double value);
/** initializes a point (or curve) drag by setting the current
* sketch status as a reference
*/
int initMove(int geoId, PointPos pos, bool fine = true);
/** Initializes a B-spline piece drag by setting the current
* sketch status as a reference. Only moves piece around `firstPoint`.
*/
int initBSplinePieceMove(int geoId,
PointPos pos,
const Base::Vector3d& firstPoint,
bool fine = true);
/** Resets the initialization of a point or curve drag
*/
void resetInitMove();
/** Limits a b-spline drag to the segment around `firstPoint`.
*/
int limitBSplineMove(int geoId, PointPos pos, const Base::Vector3d& firstPoint);
/** move this point (or curve) to a new location and solve.
* This will introduce some additional weak constraints expressing
* a condition for satisfying the new point location!
* The relative flag permits moving relatively to the current position
*/
int movePoint(int geoId, PointPos pos, Base::Vector3d toPoint, bool relative = false);
/**
* Sets whether the initial solution should be recalculated while dragging after a certain
* distance from the previous drag point for smoother dragging operation.
*/
bool getRecalculateInitialSolutionWhileMovingPoint() const
{
return RecalculateInitialSolutionWhileMovingPoint;
}
void
setRecalculateInitialSolutionWhileMovingPoint(bool recalculateInitialSolutionWhileMovingPoint)
{
RecalculateInitialSolutionWhileMovingPoint = recalculateInitialSolutionWhileMovingPoint;
}
/// add dedicated geometry
//@{
/// add a point
int addPoint(const Part::GeomPoint& point, bool fixed = false);
/// add an infinite line
int addLine(const Part::GeomLineSegment& line, bool fixed = false);
/// add a line segment
int addLineSegment(const Part::GeomLineSegment& lineSegment, bool fixed = false);
/// add a arc (circle segment)
int addArc(const Part::GeomArcOfCircle& circleSegment, bool fixed = false);
/// add a circle
int addCircle(const Part::GeomCircle& circle, bool fixed = false);
/// add an ellipse
int addEllipse(const Part::GeomEllipse& ellipse, bool fixed = false);
/// add an arc of ellipse
int addArcOfEllipse(const Part::GeomArcOfEllipse& ellipseSegment, bool fixed = false);
/// add an arc of hyperbola
int addArcOfHyperbola(const Part::GeomArcOfHyperbola& hyperbolaSegment, bool fixed = false);
/// add an arc of parabola
int addArcOfParabola(const Part::GeomArcOfParabola& parabolaSegment, bool fixed = false);
/// add a BSpline
int addBSpline(const Part::GeomBSplineCurve& spline, bool fixed = false);
//@}
/// constraints
//@{
/// add all constraints in the list
int addConstraints(const std::vector<Constraint*>& ConstraintList);
/// add all constraints in the list, provided that are enforceable
int addConstraints(const std::vector<Constraint*>& ConstraintList,
const std::vector<bool>& unenforceableConstraints);
/// add one constraint to the sketch
int addConstraint(const Constraint* constraint);
/**
* add a fixed X coordinate constraint to a point
*
* double * value is a pointer to double allocated in the heap, containing the
* constraint value and already inserted into either the FixParameters or
* Parameters array, as the case may be.
*/
int addCoordinateXConstraint(int geoId, PointPos pos, double* value, bool driving = true);
/**
* add a fixed Y coordinate constraint to a point
*
* double * value is a pointer to double allocated in the heap, containing the
* constraint value and already inserted into either the FixParameters or
* Parameters array, as the case may be.
*/
int addCoordinateYConstraint(int geoId, PointPos pos, double* value, bool driving = true);
/**
* add a horizontal distance constraint to two points or line ends
*
* double * value is a pointer to double allocated in the heap, containing the
* constraint value and already inserted into either the FixParameters or
* Parameters array, as the case may be.
*/
int addDistanceXConstraint(int geoId, double* value, bool driving = true);
/**
* add a horizontal distance constraint to two points or line ends
*
* double * value is a pointer to double allocated in the heap, containing the
* constraint value and already inserted into either the FixParameters or
* Parameters array, as the case may be.
*/
int addDistanceXConstraint(int geoId1,
PointPos pos1,
int geoId2,
PointPos pos2,
double* value,
bool driving = true);
/**
* add a vertical distance constraint to two points or line ends
*
* double * value is a pointer to double allocated in the heap, containing the
* constraint value and already inserted into either the FixParameters or
* Parameters array, as the case may be.
*/
int addDistanceYConstraint(int geoId, double* value, bool driving = true);
/**
* add a vertical distance constraint to two points or line ends
*
* double * value is a pointer to double allocated in the heap, containing the
* constraint value and already inserted into either the FixParameters or
* Parameters array, as the case may be.
*/
int addDistanceYConstraint(int geoId1,
PointPos pos1,
int geoId2,
PointPos pos2,
double* value,
bool driving = true);
/// add a horizontal constraint to a geometry
int addHorizontalConstraint(int geoId);
int addHorizontalConstraint(int geoId1, PointPos pos1, int geoId2, PointPos pos2);
/// add a vertical constraint to a geometry
int addVerticalConstraint(int geoId);
int addVerticalConstraint(int geoId1, PointPos pos1, int geoId2, PointPos pos2);
/// add a coincident constraint to two points of two geometries
int addPointCoincidentConstraint(int geoId1, PointPos pos1, int geoId2, PointPos pos2);
/**
* add a length or distance constraint
*
* double * value is a pointer to double allocated in the heap, containing the
* constraint value and already inserted into either the FixParameters or
* Parameters array, as the case may be.
*/
int addDistanceConstraint(int geoId1, double* value, bool driving = true);
/**
* add a length or distance constraint
*
* double * value is a pointer to double allocated in the heap, containing the
* constraint value and already inserted into either the FixParameters or
* Parameters array, as the case may be.
*/
int addDistanceConstraint(int geoId1,
PointPos pos1,
int geoId2,
double* value,
bool driving = true);
/**
* add a length or distance constraint
*
* double * value is a pointer to double allocated in the heap, containing the
* constraint value and already inserted into either the FixParameters or
* Parameters array, as the case may be.
*/
int addDistanceConstraint(int geoId1,
PointPos pos1,
int geoId2,
PointPos pos2,
double* value,
bool driving = true);
/**
* add a length or distance constraint
*
* double * value is a pointer to double allocated in the heap, containing the
* constraint value and already inserted into either the FixParameters or
* Parameters array, as the case may be.
*/
int addDistanceConstraint(int geoId1, int geoId2, double* value, bool driving = true);
/// add a parallel constraint between two lines
int addParallelConstraint(int geoId1, int geoId2);
/// add a perpendicular constraint between two lines
int addPerpendicularConstraint(int geoId1, int geoId2);
/// add a tangency constraint between two geometries
int addTangentConstraint(int geoId1, int geoId2);
int addTangentLineAtBSplineKnotConstraint(int checkedlinegeoId,
int checkedbsplinegeoId,
int checkedknotgeoid);
int addTangentLineEndpointAtBSplineKnotConstraint(int checkedlinegeoId,
PointPos endpointPos,
int checkedbsplinegeoId,
int checkedknotgeoid);
int addAngleAtPointConstraint(int geoId1,
PointPos pos1,
int geoId2,
PointPos pos2,
int geoId3,
PointPos pos3,
double* value,
ConstraintType cTyp,
bool driving = true);
/**
* add a radius constraint on a circle or an arc
*
* double * value is a pointer to double allocated in the heap, containing the
* constraint value and already inserted into either the FixParameters or
* Parameters array, as the case may be.
*/
int addRadiusConstraint(int geoId, double* value, bool driving = true);
/**
* add a radius constraint on a circle or an arc
*
* double * value is a pointer to double allocated in the heap, containing the
* constraint value and already inserted into either the FixParameters or
* Parameters array, as the case may be.
*/
int addDiameterConstraint(int geoId, double* value, bool driving = true);
/**
* add an angle constraint on a line or between two lines
*
* double * value is a pointer to double allocated in the heap, containing the
* constraint value and already inserted into either the FixParameters or
* Parameters array, as the case may be.
*/
int addAngleConstraint(int geoId, double* value, bool driving = true);
/**
* add an angle constraint on a line or between two lines
*
* double * value is a pointer to double allocated in the heap, containing the
* constraint value and already inserted into either the FixParameters or
* Parameters array, as the case may be.
*/
int addAngleConstraint(int geoId1, int geoId2, double* value, bool driving = true);
/**
* add an angle constraint on a line or between two lines
*
* double * value is a pointer to double allocated in the heap, containing the
* constraint value and already inserted into either the FixParameters or
* Parameters array, as the case may be.
*/
int addAngleConstraint(int geoId1,
PointPos pos1,
int geoId2,
PointPos pos2,
double* value,
bool driving = true);
/**
* add angle-via-point constraint between any two curves
*
* double * value is a pointer to double allocated in the heap, containing the
* constraint value and already inserted into either the FixParameters or
* Parameters array, as the case may be.
*/
int addAngleViaPointConstraint(int geoId1,
int geoId2,
int geoId3,
PointPos pos3,
double value,
bool driving = true);
/// add an equal length or radius constraints between two lines or between circles and arcs
int addEqualConstraint(int geoId1, int geoId2);
/// add a point on line constraint
int addPointOnObjectConstraint(int geoId1, PointPos pos1, int geoId2, bool driving = true);
/// add a point on B-spline constraint: needs a parameter
int addPointOnObjectConstraint(int geoId1,
PointPos pos1,
int geoId2,
double* pointparam,
bool driving = true);
/// add a symmetric constraint between two points with respect to a line
int addSymmetricConstraint(int geoId1, PointPos pos1, int geoId2, PointPos pos2, int geoId3);
/// add a symmetric constraint between three points, the last point is in the middle of the
/// first two
int addSymmetricConstraint(int geoId1,
PointPos pos1,
int geoId2,
PointPos pos2,
int geoId3,
PointPos pos3);
/**
* add a snell's law constraint
*
* double * value and double * second are each a pointer to double
* allocated in the heap and already inserted into either the
* FixParameters or Parameters array, as the case may be.
*
* value must contain the constraint value (the ratio of n2/n1)
* second may be initialized to any value, however the solver will
* provide n1 in value and n2 in second.
*/
int addSnellsLawConstraint(int geoIdRay1,
PointPos posRay1,
int geoIdRay2,
PointPos posRay2,
int geoIdBnd,
double* value,
double* second,
bool driving = true);
//@}
/// Internal Alignment constraints
//@{
/// add InternalAlignmentEllipseMajorDiameter to a line and an ellipse
int addInternalAlignmentEllipseMajorDiameter(int geoId1, int geoId2);
int addInternalAlignmentEllipseMinorDiameter(int geoId1, int geoId2);
int addInternalAlignmentEllipseFocus1(int geoId1, int geoId2);
int addInternalAlignmentEllipseFocus2(int geoId1, int geoId2);
/// add InternalAlignmentHyperbolaMajorRadius to a line and a hyperbola
int addInternalAlignmentHyperbolaMajorDiameter(int geoId1, int geoId2);
int addInternalAlignmentHyperbolaMinorDiameter(int geoId1, int geoId2);
int addInternalAlignmentHyperbolaFocus(int geoId1, int geoId2);
int addInternalAlignmentParabolaFocus(int geoId1, int geoId2);
int addInternalAlignmentParabolaFocalDistance(int geoId1, int geoId2);
int addInternalAlignmentBSplineControlPoint(int geoId1, int geoId2, int poleindex);
int addInternalAlignmentKnotPoint(int geoId1, int geoId2, int knotindex);
//@}
public:
// This func is to be used during angle-via-point constraint creation. It calculates
// the angle between geoId1,geoId2 at point px,py. The point should be on both curves,
// otherwise the result will be systematically off (but smoothly approach the correct
// value as the point approaches intersection of curves).
double calculateAngleViaPoint(int geoId1, int geoId2, double px, double py);
double calculateAngleViaParams(int geoId1, int geoId2, double param1, double param2);
// This is to be used for rendering of angle-via-point constraint.
Base::Vector3d calculateNormalAtPoint(int geoIdCurve, double px, double py) const;
// icstr should be the value returned by addXXXXConstraint
// see more info in respective function in GCS.
double calculateConstraintError(int icstr)
{
return GCSsys.calculateConstraintErrorByTag(icstr);
}
/// Returns the size of the Geometry
int getGeometrySize() const
{
return Geoms.size();
}
enum GeoType
{
None = 0,
Point = 1, // 1 Point(start), 2 Parameters(x,y)
Line = 2, // 2 Points(start,end), 4 Parameters(x1,y1,x2,y2)
Arc = 3, // 3 Points(start,end,mid), (4)+5 Parameters((x1,y1,x2,y2),x,y,r,a1,a2)
Circle = 4, // 1 Point(mid), 3 Parameters(x,y,r)
Ellipse = 5, // 1 Point(mid), 5 Parameters(x,y,r1,r2,phi)
// phi=angle xaxis of ellipse with respect of sketch xaxis
ArcOfEllipse = 6,
ArcOfHyperbola = 7,
ArcOfParabola = 8,
BSpline = 9
};
protected:
float SolveTime;
bool RecalculateInitialSolutionWhileMovingPoint;
// regulates a second solve for cases where there result of having update the geometry (e.g. via
// OCCT) needs to be taken into account by the solver (for example to provide the right value of
// non-driving constraints)
bool resolveAfterGeometryUpdated;
protected:
/// container element to store and work with the geometric elements of this sketch
struct GeoDef
{
GeoDef()
: geo(nullptr)
, type(None)
, external(false)
, index(-1)
, startPointId(-1)
, midPointId(-1)
, endPointId(-1)
{}
Part::Geometry* geo; // pointer to the geometry
GeoType type; // type of the geometry
bool external; // flag for external geometries
int index; // index in the corresponding storage vector (Lines, Arcs, Circles, ...)
int startPointId; // index in Points of the start point of this geometry
int midPointId; // index in Points of the start point of this geometry
int endPointId; // index in Points of the end point of this geometry
};
/// container element to store and work with the constraints of this sketch
struct ConstrDef
{
ConstrDef()
: constr(nullptr)
, driving(true)
, value(nullptr)
, secondvalue(nullptr)
{}
Constraint* constr; // pointer to the constraint
bool driving;
double* value;
double* secondvalue; // this is needed for SnellsLaw
};
std::vector<GeoDef> Geoms;
std::vector<ConstrDef> Constrs;
GCS::System GCSsys;
int ConstraintsCounter;
std::vector<int> Conflicting;
std::vector<int> Redundant;
std::vector<int> PartiallyRedundant;
std::vector<int> MalformedConstraints;
std::vector<double*> pDependentParametersList;
// map of geoIds to corresponding solverextensions. This is useful when solved geometry is NOT
// to be assigned to the SketchObject
std::vector<std::shared_ptr<SolverGeometryExtension>> solverExtensions;
// maps a geoid corresponding to an internalgeometry (focus,knot,pole) to the geometry it
// defines (ellipse, hyperbola, B-Spline)
std::map<int, int> internalAlignmentGeometryMap;
std::vector<std::set<std::pair<int, Sketcher::PointPos>>> pDependencyGroups;
// this map is intended to convert a parameter (double *) into a GeoId/PointPos and parameter
// number
std::map<double*, std::tuple<int, Sketcher::PointPos, int>> param2geoelement;
// solving parameters
std::vector<double*> Parameters; // with memory allocation
std::vector<double*> DrivenParameters; // with memory allocation
std::vector<double*> FixParameters; // with memory allocation
std::vector<double> MoveParameters, InitParameters;
std::vector<GCS::Point> Points;
std::vector<GCS::Line> Lines;
std::vector<GCS::Arc> Arcs;
std::vector<GCS::Circle> Circles;
std::vector<GCS::Ellipse> Ellipses;
std::vector<GCS::ArcOfEllipse> ArcsOfEllipse;
std::vector<GCS::ArcOfHyperbola> ArcsOfHyperbola;
std::vector<GCS::ArcOfParabola> ArcsOfParabola;
std::vector<GCS::BSpline> BSplines;
bool isInitMove;
bool isFine;
Base::Vector3d initToPoint;
double moveStep;
public:
GCS::Algorithm defaultSolver;
GCS::Algorithm defaultSolverRedundant;
inline void setDogLegGaussStep(GCS::DogLegGaussStep mode)
{
GCSsys.dogLegGaussStep = mode;
}
inline void setDebugMode(GCS::DebugMode mode)
{
debugMode = mode;
GCSsys.debugMode = mode;
}
inline GCS::DebugMode getDebugMode()
{
return debugMode;
}
inline void setMaxIter(int maxiter)
{
GCSsys.maxIter = maxiter;
}
inline void setMaxIterRedundant(int maxiter)
{
GCSsys.maxIterRedundant = maxiter;
}
inline void setSketchSizeMultiplier(bool mult)
{
GCSsys.sketchSizeMultiplier = mult;
}
inline void setSketchSizeMultiplierRedundant(bool mult)
{
GCSsys.sketchSizeMultiplierRedundant = mult;
}
inline void setConvergence(double conv)
{
GCSsys.convergence = conv;
}
inline void setConvergenceRedundant(double conv)
{
GCSsys.convergenceRedundant = conv;
}
inline void setQRAlgorithm(GCS::QRAlgorithm alg)
{
GCSsys.qrAlgorithm = alg;
}
inline GCS::QRAlgorithm getQRAlgorithm()
{
return GCSsys.qrAlgorithm;
}
inline void setQRPivotThreshold(double val)
{
GCSsys.qrpivotThreshold = val;
}
inline void setLM_eps(double val)
{
GCSsys.LM_eps = val;
}
inline void setLM_eps1(double val)
{
GCSsys.LM_eps1 = val;
}
inline void setLM_tau(double val)
{
GCSsys.LM_tau = val;
}
inline void setDL_tolg(double val)
{
GCSsys.DL_tolg = val;
}
inline void setDL_tolx(double val)
{
GCSsys.DL_tolx = val;
}
inline void setDL_tolf(double val)
{
GCSsys.DL_tolf = val;
}
inline void setLM_epsRedundant(double val)
{
GCSsys.LM_epsRedundant = val;
}
inline void setLM_eps1Redundant(double val)
{
GCSsys.LM_eps1Redundant = val;
}
inline void setLM_tauRedundant(double val)
{
GCSsys.LM_tauRedundant = val;
}
inline void setDL_tolgRedundant(double val)
{
GCSsys.DL_tolgRedundant = val;
}
inline void setDL_tolxRedundant(double val)
{
GCSsys.DL_tolxRedundant = val;
}
inline void setDL_tolfRedundant(double val)
{
GCSsys.DL_tolfRedundant = val;
}
protected:
GCS::DebugMode debugMode;
private:
bool updateGeometry();
bool updateNonDrivingConstraints();
void calculateDependentParametersElements();
void clearTemporaryConstraints();
void buildInternalAlignmentGeometryMap(const std::vector<Constraint*>& constraintList);
int internalSolve(std::string& solvername, int level = 0);
/// checks if the index bounds and converts negative indices to positive
int checkGeoId(int geoId) const;
GCS::Curve* getGCSCurveByGeoId(int geoId);
const GCS::Curve* getGCSCurveByGeoId(int geoId) const;
// Block constraints
/** This function performs a pre-analysis of blocked geometries, separating them into:
*
* 1) onlyblockedGeometry : Geometries affected exclusively by a block constraint.
*
* 2) blockedGeoIds : Geometries affected notonly by a block constraint.
*
* This is important because 1) can be pre-fixed when creating geometry and constraints
* before GCS::diagnose() via initSolution(). This is important because if no other constraint
* affect the geometry, the geometry parameters won't even appear in the Jacobian, and they
* won't be reported as dependent parameters.
*
* On the contrary 2) cannot be pre-fixed because it would lead to redundant constraints and
* requires a post-analysis, see analyseBlockedConstraintDependentParameters, to fix just the
* parameters that fulfil the dependacy groups.
*/
bool analyseBlockedGeometry(const std::vector<Part::Geometry*>& internalGeoList,
const std::vector<Constraint*>& constraintList,
std::vector<bool>& onlyblockedGeometry,
std::vector<int>& blockedGeoIds) const;
/* This function performs a post-analysis of blocked geometries (see analyseBlockedGeometry for
* more detail on the pre-analysis).
*
* Basically identifies which parameters shall be fixed to make geometries having blocking
* constraints fixed, while not leading to redundant/conflicting constraints. These parameters
* must belong to blocked geometry. This is, groups may comprise parameters belonging to blocked
* geometry and parameters belonging to unconstrained geometry. It is licit that the latter
* remain as dependent parameters. The former are referred to as "blockable parameters".
*
* Extending this concept, there may be unsatisfiable groups (because they do not comprise any
* bloackable parameter), and it is the desired outcome NOT to satisfy such groups.
*
* There is not a single combination of fixed parameters from the blockable parameters that
* satisfy all the dependency groups. However:
*
* 1) some combinations do not satisfy all the dependency groups that must be satisfied (e.g.
* fixing one group containing two blockable parameters with a given one may result in another
* group, fixable only by the former, not to be satisfied). This leads, in a subsequent
* diagnosis, to satisfiable unsatisfied groups.
*
* 2) some combinations lead to partially redundant constraints, that the solver will silently
* drop in a subsequent diagnosis, thereby reducing the rank of the system fixing less than it
* should.
*
* Implementation rationale (at this time):
*
* The implementation is on the order of the groups provided by the QR decomposition used to
* reveal the parameters (see System::identifyDependentParameters in GCS). Zeros are made over
* the pilot of the full R matrix of the QR decomposition, which is a top triangular
* matrix.This, together with the permutation matrix, allow to know groups of dependent
* parameters (cols between rank and full size). Each group refers to a new parameter not
* affected by the rank in combination with other free parameters intervening in the rank
* (because of the triangular shape of the R matrix). This results in that each the first column
* between the rank and the full size, may only depend on a number of parameters, while the last
* full size column may be dependent on any amount of previously introduced parameters.
*
* Thus the rationale is: start from the last group (having **potentially** the larger amount of
* parameters) and selecting as blocking for that group the latest blockable parameter. Because
* previous groups do not have access to the last parameter, this can never interfere with
* previous groups. However, because the last parameter may not be a blockable one, there is a
* risk of selecting a parameter common with other group, albeit the probability is reduced and
* probably (I have not demonstrated it though and I am not sure), it leads to the right
* solution in one iteration.
*
*/
bool analyseBlockedConstraintDependentParameters(std::vector<int>& blockedGeoIds,
std::vector<double*>& params_to_block) const;
/// utility function refactoring fixing the provided parameters and running a new diagnose
void fixParametersAndDiagnose(std::vector<double*>& params_to_block);
};
} // namespace Sketcher
#endif // SKETCHER_SKETCH_H