======================================== Previous versions relied on a heuristic that proved insufficient for cummulative use of the Block constraint. The effect is that Block constraints stopped blocking, which is a major bug, as it lead to inadvertedly moving geometry that was supposed to be blocked. Fixes: https://forum.freecadweb.org/viewtopic.php?f=13&t=53515&start=30#p461215 (Thanks Chaospilot) Know problems with old block constraint (v0.18): 1. If driving constraints were present, they were ignored if inserted before the block constraint (to avoid redundancy/conflicting). They resulted in Principles of Working of the new block constraint: 1. Handling of the new block constraint is based two processes, a pre-analysis and a post-analysis. Pre-analysis works *before* diagnosing the system in the solver. Post-analysis works *after* diagnosing the system in the solver. 2. Pre-analysis is directed to detect geometries affected *exclusively* by a block constraint. This is important because these geometries can be pre-fixed when creating the solver geometry and constraints before GCS::diagnose() via initSolution() AND because if no other constraint affects the geometry, the geometry parameters won't even appear in the Jacobian of GCS, so they won't be reported as dependent parameters (for which post-analysis would be of no use). 3. Post-analysis is directed to detect Geometries affected *not only* by a block constraint. This is important because pre-fixing these geometries would lead to redundant constraints. The post-analysis, enables to fix just the parameters that fulfil the dependacy groups. 4. Post-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. It must be emphasised that 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. 5. The implementation rationale is as follows: 1) 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 colum may dependent on any amount of previously introduced parameters. 2) Thus the rationale is to 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 systematically leads to the right solution in one iteration. GCS: Change dependency group from std::set to std::vector to prevent reordering of parameters.
573 lines
28 KiB
C++
573 lines
28 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 <App/PropertyStandard.h>
|
|
#include <App/PropertyFile.h>
|
|
#include <Mod/Part/App/Geometry.h>
|
|
#include <Mod/Part/App/TopoShape.h>
|
|
#include "Constraint.h"
|
|
|
|
#include "planegcs/GCS.h"
|
|
|
|
#include <Base/Persistence.h>
|
|
|
|
namespace Sketcher
|
|
{
|
|
|
|
class SketcherExport Sketch :public Base::Persistence
|
|
{
|
|
TYPESYSTEM_HEADER();
|
|
|
|
public:
|
|
Sketch();
|
|
~Sketch();
|
|
|
|
// from base class
|
|
virtual unsigned int getMemSize(void) const;
|
|
virtual void Save(Base::Writer &/*writer*/) const;
|
|
virtual void Restore(Base::XMLReader &/*reader*/);
|
|
|
|
/// solve the actual set up sketch
|
|
int solve(void);
|
|
/// 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(void);
|
|
/** 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(void) 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;
|
|
|
|
void updateExtension(int geoId, std::unique_ptr<Part::GeometryExtension> && ext);
|
|
/// get the geometry as python objects
|
|
Py::Tuple getPyGeometry(void) 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(void) const { return !Conflicting.empty(); }
|
|
inline const std::vector<int> &getConflicting(void) const { return Conflicting; }
|
|
inline bool hasRedundancies(void) const { return !Redundant.empty(); }
|
|
inline const std::vector<int> &getRedundant(void) const { return Redundant; }
|
|
|
|
inline float getSolveTime() const { return SolveTime; }
|
|
|
|
inline bool hasMalformedConstraints(void) const { return malformedConstraints; }
|
|
public:
|
|
std::set < std::pair< int, Sketcher::PointPos>> getDependencyGroup(int geoId, PointPos pos) 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);
|
|
|
|
/** Resets the initialization of a point or curve drag
|
|
*/
|
|
void resetInitMove();
|
|
|
|
/** 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 ¶bolaSegment, 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 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 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 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 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 );
|
|
|
|
//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(void) 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;
|
|
|
|
protected:
|
|
/// container element to store and work with the geometric elements of this sketch
|
|
struct GeoDef {
|
|
GeoDef() : geo(0),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(0)
|
|
, driving(true)
|
|
, value(0)
|
|
, secondvalue(0) {}
|
|
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<double *> pDependentParametersList;
|
|
|
|
std::vector < std::set < std::pair< int, Sketcher::PointPos>>> pDependencyGroups;
|
|
|
|
// this map is intended to convert a parameter (double *) into a GeoId/PointPos pair
|
|
std::map<double *, std::pair<int,Sketcher::PointPos>> 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;
|
|
|
|
bool malformedConstraints;
|
|
|
|
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(void) {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(void);
|
|
bool updateNonDrivingConstraints(void);
|
|
|
|
void calculateDependentParametersElements(void);
|
|
|
|
void clearTemporaryConstraints(void);
|
|
|
|
/// 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 colum may 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 *> ¶ms_to_block) const;
|
|
|
|
/// utility function refactoring fixing the provided parameters and running a new diagnose
|
|
void fixParametersAndDiagnose(std::vector<double *> ¶ms_to_block);
|
|
};
|
|
|
|
} //namespace Part
|
|
|
|
|
|
#endif // SKETCHER_SKETCH_H
|