Gitter chat: https://gitter.im/FreeCAD-ellipse/community

So, as I wanted to fix sketcher solver, and scaling constraint error functions didn't give good results, I now want to scale the dofs themselves. It seems doable within the current situation. However, since I am thinking too hard about the solver, I decided to try initiate the effort of rewriting the solver.

The primary goal is to have a standalone solver decoupled from Sketcher, ready for 3d assembly solving, and with full python bindings.

So, here we go.

Design goals (i.e., improvements over current solver).

* full python support (one should be able to implement a 2d/3d sketcher fully in python using the solver)

* python-powered constraint support (with inevitable speed problems, of course)

* externally extendable (i.e. no hard-coding of constraint types)

* reentrant solver.

That is, allow create multiple solvers and run them in parallel. That implies no writing to ParameterStore while solving.

* built-in parameter scaling factor support, to eliminate the size-of-sketch magnitude problem

* use DualNumbers in constraint-related math to implicitly compute derivatives

(was DeriVectors, pretty much the same stuff)

* don't evaluate constraint derivatives for parameters the constraint does not depend on, for speed, yet avoid branching.

(by using list of parameters returned by constraints, and stored indexes in lookup tables, we can selectively fill matrix elements with very little overhead)

* support rigid groups of geometry

This is a rough architecture I came up with to fit the goals. I'm open for discussion.

Code: Select all

```
class Parameter
//parameter should always live in ParameterStore
//Py: nothing, accessed via ParameterRef
HParameterStore host
double value
double magnitude = 1.0
int par_index
int masterindex //==par_index, unless the parameter was redirected
std::string name
class ParameterRef
//Py: copy-construct
HParameterStore host
int par_index
Parameter& operator*
class ParameterStore
//py: hosted by PyObject, no constructor on stack
vector<Parameter> parameters
vector<int> redirectionmap (key = index of parameter, value = index of master parameter)
PyObject* self
class HParameterStore
//handle to ParameterStore
//Py: nothing, it's a C++ wrapper around python object
Py::Object store_py
ParameterStore* store
ParameterStore& operator*
class ParameterSet
//list of parameters. e.g., list of unknowns for solver
//py: copy-construct?
smart_ptr vector<ParameterRef> parameters
smart_ptr vector<int> lut //key = parameter index. value = index into the set
operator[] (retrieves the parameter)
PyObject* pyobj
class ParameterValueSet(ParameterSet)
//py: construct around one on stack, with crash potential
Eigen::vectorxD values
Eigen::vector<double> duals //dual parts, for derivative computation
operator[] (retrieves the alternate value, as values[lut[arg->masterindex]] if in set else arg->value())
class Solver:
//py: hosted by PyObject, no constructor on stack
ParameterSet unknowns
Vector<HConstraint> constraints
...and heaps of other stuff
PyObject* self
class HSolver:
Py::Object solver_py
Solver* solver
Solver& operator*
class Constraint
//py: hosted by PyObject, no constructor on stack
PyObject* self
int tag
methods:
vector<ParameterRef> params() //all params the constraint is using
DualNumber error(ParameterValueSet &on)
double maxStep(ParameterValueSet &on, ParameterValueSet &dir, double curstep)
class HConstraint:
Py::Object constraint_py
Constraint* solver
Constraint& operator*
class ParaObject
//base class for all objects built on parameters
//py: copy-construct
ParameterSet pvec //to be filled in by constructors
static makeWithParams(ParameterStore params)
2D:
class DualVector2
class ParaVector2(ParaObject)
class ParaGeom2(ParaObject)
class ParaPoint2(ParaGeom2)
class ParaEdge2(ParaGeom2)
class ParaFullEdge2(ParaEdge)
class ParaTrimmedEdge2(ParaEdge)
class PlacedGeometry(ParaGeom2) //to support rigid blocks, think assembly
class PlacedPoint(PlacedGeometry)
class PlacedEdge(PlacedGeometry)
class ParaCurve2(ParaGeom2)
class ParaLine2(ParaCurve2)
class ParaCircle2(ParaCurve2)
class ParaEllipse2(ParaCurve2)
...
3D:
class DualVector3
class DualRotation
class DualPlacement
class ParaVector3(ParaObject)
class ParaRotation(ParaObject)
class ParaPlacement(ParaObject)
class ParaGeom3(ParaObject)
class PlacedShape(ParaGeom3)
class ParaEdge3(ParaGeom3)
class ParaFullEdge3(ParaEdge3)
class ParaTrimmedEdge3(ParaEdge3)
class ParaCurve3(ParaGeom3)
class ParaLine3(ParaCurve3)
class ParaCircle3(ParaCurve3)
class ParaEllipse3(ParaCurve3)
...
class ParaSurface3(ParaGeom3)
class ParaPlane3(ParaGeom3)
class ParaSphere3(ParaGeom3)
...
Notes:
DualVector, DualRotation, ParaVector2,3, ParaRotation, ParaPlacement etc should support assignment from and to their Base::<> twins
```

* typesystem integration

* add some storage facilities in geometry, constraints and parameters. For example, add a Py::Object data member. And probably it's good to have something for C++ too.

* (super optional) interactive solving support (i.e. manual iteration advancement)

* template constraint implementations for coordinates (e.g., CurveValueX and CurveValueY constraints share the implementation, and just return differences in respective coordinates as error their function)

Tasks (same number = can be done in parallel)

1. Set up new FreeCAD module

2. implement Parameter, ParameterRef, ParameterStore, HParameterStore, ParameterSet, ParameterValueSet

2. implement DualNumber math functions, DualVector2

3. implement ParaVector2,

4. Implement ParaGeom2 and derived, and constraints

4. reimplement solver, taking care to account for parameter scaling

5. Test the solver with python

6. rewrite Sketch.cpp to use the new solver

7. some good testing!

------------

8. implement 3d placement, geometry and constraints

9. use in assembly workbench

Who is brave enough to join this? I feel like I can't lift it all on my own.