Sketcher: Bezier curves

Here's the place for discussion related to coding in FreeCAD, C++ or Python. Design, interfaces and structures.
Forum rules
Be nice to others! Respect the FreeCAD code of conduct!
jean.thil
Posts: 209
Joined: Tue Jul 28, 2015 7:28 am

Re: Sketcher: Bezier curves

Post by jean.thil »

I am open to new input and discussion
My use of spline is almost limited to replicate the shapes of a background blueprint I try to replicate.
In this order, I prefer to create a spline by clicking on the points I want it to follow. Once it is "almost" there, I like to manipulate controls points rather than interpolation points to smooth the spline or to obtain some wanted tangencies at place. I really enjoy SolidEdge behaviour as described by Normand.
User avatar
Pauvres_honteux
Posts: 728
Joined: Sun Feb 16, 2014 12:05 am
Location: Far side of the moon

Re: Sketcher: Bezier curves

Post by Pauvres_honteux »

Hi abdullah, I'd like to suggest assigning numerical values to the green fields as I started fantasizing of them as being representatives of acceleration.
If my fantacy is true, it would open up for calculation/design of e.g. propellers, road curves, roller coasters, hulls, turbos, water ways, wing cross sections and so on. I.E. in any application where one need/want to control the force/acceleration perpendicular to the direction of travel at any point of the curve.
Preferably I'd like those numerical values to be accessible via/by functions and spread sheet.

I guess you've already read this paper, but for anyone else interested in the math behind:
Jean Gallier and Morgan Kaufmann's
Curves and Surfaces in Geometric Modeling:
Theory and Algorithms

http://www.cis.upenn.edu/~jean/geomcs-v2.pdf

Search for acceleration.
abdullah
Veteran
Posts: 4935
Joined: Sun May 04, 2014 3:16 pm
Contact:

Re: Sketcher: Bezier curves

Post by abdullah »

jean.thil wrote:My use of spline is almost limited to replicate the shapes of a background blueprint I try to replicate.
In this order, I prefer to create a spline by clicking on the points I want it to follow. Once it is "almost" there, I like to manipulate controls points rather than interpolation points to smooth the spline or to obtain some wanted tangencies at place.
I guess those blueprints are "just pictures" in the background. If that is the case then a creation mode that will approximate your entered points makes sense. Then you will have to tweak not only poles, but also knot multiplicities, at least in cases of sharp edges. I take note. Remind me in a month if you do not see it done.
Pauvres_honteux wrote:Hi abdullah, I'd like to suggest assigning numerical values to the green fields as I started fantasizing of them as being representatives of acceleration.
If my fantacy is true, it would open up for calculation/design of e.g. propellers, road curves, roller coasters, hulls, turbos, water ways, wing cross sections and so on. I.E. in any application where one need/want to control the force/acceleration perpendicular to the direction of travel at any point of the curve.
Preferably I'd like those numerical values to be accessible via/by functions and spread sheet.
Hi! What you describe is not a general purpose addition for the sketcher (the goal of the sketcher is that of defining geometry), but an application specific one (design of). Such a tool, makes much more sense as a macro, or if it would become complex, a new workbench. With such a macro (take a look at Chris_G's comb some posts ago), you could show for example the curvature, acceleration, and any other function you want. You can actually see this information while being in the sketcher. I really encourage you to take a look, because, having that comb macro as an example, it is not really difficult to do another one for your particular application.
jean.thil
Posts: 209
Joined: Tue Jul 28, 2015 7:28 am

Re: Sketcher: Bezier curves

Post by jean.thil »

also knot multiplicities, at least in cases of sharp edges
I don't feel it is very important. If you need sharp edges you can just end the nurbs at the edge and create another curve at the same point.
The same goes for surfaces.
In SE and SW I don't think one can modify multiplicity.
Last edited by jean.thil on Sun Feb 26, 2017 8:13 pm, edited 1 time in total.
triplus
Veteran
Posts: 9471
Joined: Mon Dec 12, 2011 4:45 pm

Re: Sketcher: Bezier curves

Post by triplus »

triplus wrote:I am not sure that we want to create a b-spline via knots. But it does indeed make sense to create a b-spline via points on the spline.
What is the difference? Are spline points simply knots or are they something else?
Then you will have to tweak not only poles, but also knot multiplicities, at least in cases of sharp edges.
Yes please!

I am guessing circles (like the weights control) would do it for me for now. User could in addition set the multiplicity with expressions after. ;)

P.S. Both multiplicity/weight circle control could i guess be hidden and set at sensible values by default in the future. That would i guess scale good when new user starts inserting the spline or after an user with a few years of experience starts to mess with splines in Sketcher.
User avatar
Pauvres_honteux
Posts: 728
Joined: Sun Feb 16, 2014 12:05 am
Location: Far side of the moon

Re: Sketcher: Bezier curves

Post by Pauvres_honteux »

@Abdullah, thanks four your pointer!

Created a new thread about it: Acceleration or forces vs Bezier curves 20945
abdullah
Veteran
Posts: 4935
Joined: Sun May 04, 2014 3:16 pm
Contact:

Re: Sketcher: Bezier curves

Post by abdullah »

jean.thil wrote:I don't feel it is very important. If you need sharp edges you can just end the nurbs at the edge and create another curve at the same point.
I see. If you need just positional continuity for sure that makes it. You will have two ways of doing it.
triplus wrote:What is the difference? Are spline points simply knots or are they something else?
A B-Spline is a piecewise complex curve, it is defined by a single curve, aka segment, inbetween two knots. Knots define the "union" between two segments. However, the requirement of a curve approximating a sequence of points is satisfied if the B-Spline is in those points at a given parameter value, it does not need to be the parameter corresponding to a knot.
triplus wrote:Yes please!

I am guessing circles (like the weights control) would do it for me for now. User could in addition set the multiplicity with expressions after. ;)

P.S. Both multiplicity/weight circle control could i guess be hidden and set at sensible values by default in the future. That would i guess scale good when new user starts inserting the spline or after an user with a few years of experience starts to mess with splines in Sketcher.
The knot multiplicities won't be circles. There are several reasons. First it is a discrete value, integer not double. Second, it is not a solver magnitude, as will be handled via tools, not constraints (that is the reason also why the value is in the information layer and not as a constraint). Algorithms for knots insertion/removal (multiplicity increase/decrease) are complicated enough not to be part of a solver.

If I manage to make it right, soon you will see new tools in the bar to increase/decrease a given knot multiplicity.
Pauvres_honteux wrote:@Abdullah, thanks four your pointer!

Created a new thread about it: Acceleration or forces vs Bezier curves 20945
You are welcome. I think something very interesting can come out of there :)
abdullah
Veteran
Posts: 4935
Joined: Sun May 04, 2014 3:16 pm
Contact:

Re: Sketcher: Bezier curves

Post by abdullah »

I think I am hitting an OCC bug (or I can not realise what I am doing wrong so that OCC segfaults).

I have implemented knot multiplicity increase:

https://github.com/abdullahtahiriyo/Fre ... eliverable
bspline_knot_increase_Multiplicity.png
bspline_knot_increase_Multiplicity.png (26.16 KiB) Viewed 2345 times
The BSpline toolbar has a new command, currently shown as X, to increase the multiplicity of a knot, so select the knot, hit the button and degree increases.

Sometimes it just works. Others FreeCAD segfaults.

I would like to explain where I have arrived to debugging. Maybe somebody with a better eye or understanding can help me out here.

The current code to increase the multiplicity is this:

Code: Select all

bool SketchObject::modifyBSplineKnotMultiplicity(int GeoId, int knotIndex, int multiplicityincr)
{
    if (GeoId < 0 || GeoId > getHighestCurveIndex())
        return false;
    
    if (multiplicityincr == 0) // no change in multiplicity
        return true;
    
    const Part::Geometry *geo = getGeometry(GeoId);
    
    if(geo->getTypeId() != Part::GeomBSplineCurve::getClassTypeId())
        return false;
    
    const Part::GeomBSplineCurve *bsp = static_cast<const Part::GeomBSplineCurve *>(geo);
    
    int degree = bsp->getDegree();
    
    if( knotIndex > bsp->countKnots() || knotIndex < 1 ) // knotindex in OCC 1 -> countKnots
        return false;

    Part::GeomBSplineCurve *bspline;

    try {
        int curmult = bsp->getMultiplicity(knotIndex);
        
        if ( (curmult + multiplicityincr) > degree || (curmult + multiplicityincr) < 0) // zero is removing the knot, degree is just positional continuity
            return false;

        const Handle_Geom_BSplineCurve curve = Handle_Geom_BSplineCurve::DownCast(bsp->handle());

        bspline = new Part::GeomBSplineCurve(curve);

        if(multiplicityincr > 0) { // increase multiplicity
            bspline->increaseMultiplicity(knotIndex, curmult + multiplicityincr);
        }
        else { // decrease multiplicity
            bool result = bspline->removeKnot(knotIndex, curmult + multiplicityincr);

            if(!result)
                return false;
        }
    }
    catch (const Base::Exception& e) {
        Base::Console().Error("%s\n", e.what());
        return false;
    }
    
    // we succeeded with the multiplicity modification, so aligment geometry may be invalid/inconsistent for the new bspline
    // If multiplicity is increased, the number of poles is increased. An increase of 1 degree generates one pole extra
    
    if(multiplicityincr > 0) {

        std::vector<Base::Vector3d> poles = bsp->getPoles();
        std::vector<Base::Vector3d> newpoles = bspline->getPoles();
        std::vector<int> prevpole(bsp->countPoles());
        
        for(int i = 0; i < int(poles.size()); i++)
            prevpole[i] = -1;

        int taken = 0;
        for(int j = 0; j < int(poles.size()); j++){
            for(int i = taken; i < int(newpoles.size()); i++){
                if( newpoles[i] == poles[j] ) {
                    prevpole[j] = i;
                    taken++;
                    break;
                }
            }
        }
        
        const std::vector< Sketcher::Constraint * > &cvals = Constraints.getValues();
        
        std::vector< Constraint * > newcVals(cvals);
        
        // modify pole constraints
        for (std::vector< Sketcher::Constraint * >::iterator it= newcVals.begin(); it != newcVals.end(); ++it) {
            if((*it)->Type == Sketcher::InternalAlignment && (*it)->Second == GeoId)
            {
                if((*it)->AlignmentType == Sketcher::BSplineControlPoint && prevpole[(*it)->InternalAlignmentIndex]!=-1) {
                    (*it)->InternalAlignmentIndex = prevpole[(*it)->InternalAlignmentIndex];
                }
            }
        }

        this->Constraints.setValues(newcVals);
    }
    else {
        return false;
    }
    
    // * DOCUMENTING OCC ISSUE
    // When bspline is assigned below in  newVals[GeoId] = bspline, when sketch.cpp updateGeometry executes this:
    //
    // point->setPoint(bsp->pointAtParameter(knots[index]));
    //
    // A segmentation fault is generated:
    //Program received signal SIGSEGV, Segmentation fault.
    //#0 /lib/x86_64-linux-gnu/libc.so.6(+0x36cb0) [0x7f4b933bbcb0]
    //#1  0x7f4b0300ea14 in BSplCLib::BuildCache(double, double, bool, int, TColStd_Array1OfReal const&, TColgp_Array1OfPnt const&, TColStd_Array1OfReal const&, TColgp_Array1OfPnt&, TColStd_Array1OfReal&) from /usr/lib/x86_64-linux-gnu/libTKMath.so.10+0x484
    //#2  0x7f4b033f9582 in Geom_BSplineCurve::ValidateCache(double) from /usr/lib/x86_64-linux-gnu/libTKG3d.so.10+0x202
    //#3  0x7f4b033f2a7e in Geom_BSplineCurve::D0(double, gp_Pnt&) const from /usr/lib/x86_64-linux-gnu/libTKG3d.so.10+0xde
    //#4  0x7f4b033de1b5 in Geom_Curve::Value(double) const from /usr/lib/x86_64-linux-gnu/libTKG3d.so.10+0x25
    //#5  0x7f4b03423d73 in GeomLProp_CurveTool::Value(Handle_Geom_Curve const&, double, gp_Pnt&) from /usr/lib/x86_64-linux-gnu/libTKG3d.so.10+0x13
    //#6  0x7f4b03427175 in GeomLProp_CLProps::SetParameter(double) from /usr/lib/x86_64-linux-gnu/libTKG3d.so.10+0x75
    //#7  0x7f4b0342727d in GeomLProp_CLProps::GeomLProp_CLProps(Handle_Geom_Curve const&, double, int, double) from /usr/lib/x86_64-linux-gnu/libTKG3d.so.10+0xcd
    //#8  0x7f4b11924b53 in Part::GeomCurve::pointAtParameter(double) const from /home/abdullah/github/freecad-build/Mod/Part/Part.so+0xa7
    
    Part::GeomBSplineCurve * tbspline = new  Part::GeomBSplineCurve( bspline->getPoles(), bspline->getWeights(), bspline->getKnots(), bspline->getMultiplicities(),
                                                  bspline->getDegree(), bspline->isPeriodic());

    const std::vector< Part::Geometry * > &vals = getInternalGeometry();
    
    std::vector< Part::Geometry * > newVals(vals);
    
    newVals[GeoId] = tbspline;
    
    Geometry.setValues(newVals);
    Constraints.acceptGeometry(getCompleteGeometry());
    rebuildVertexIndex();
    
    return true;
    
}

First I have coded with newVals[GeoId] = bspline; (see last 5 lines above), which I think should just work fine. Then trying to find a work-around I have created an additional temp GeomBSplineCurve. My impression is that with this temp copy it crashes less, but it must just be an impression.

Still, with both ways it crashes when trying to fix the knots in sketch.cpp (line 2705) :

Code: Select all

                int index = 0;
                for(std::vector<int>::const_iterator it5 = mybsp.knotpointGeoids.begin(); it5 != mybsp.knotpointGeoids.end(); ++it5, index++) {
                    if( *it5 != Constraint::GeoUndef) {
                        if (Geoms[*it5].type == Point) {
                            GeomPoint *point = static_cast<GeomPoint*>(Geoms[*it5].geo);

                            if(point->Construction) {
                                point->setPoint(bsp->pointAtParameter(knots[index]));
                            }
                        }
                    }
                }
that code is what I use to get the point corresponding to the parameter value where the knot lies. Sometimes, I get this exception stack:

Code: Select all

Program received signal SIGSEGV, Segmentation fault.
#0 /lib/x86_64-linux-gnu/libc.so.6(+0x36cb0) [0x7f4b933bbcb0]
#1  0x7f4b0300ea14 in BSplCLib::BuildCache(double, double, bool, int, TColStd_Array1OfReal const&, TColgp_Array1OfPnt const&, TColStd_Array1OfReal const&, TColgp_Array1OfPnt&, TColStd_Array1OfReal&) from /usr/lib/x86_64-linux-gnu/libTKMath.so.10+0x484
#2  0x7f4b033f9582 in Geom_BSplineCurve::ValidateCache(double) from /usr/lib/x86_64-linux-gnu/libTKG3d.so.10+0x202
#3  0x7f4b033f2a7e in Geom_BSplineCurve::D0(double, gp_Pnt&) const from /usr/lib/x86_64-linux-gnu/libTKG3d.so.10+0xde
#4  0x7f4b033de1b5 in Geom_Curve::Value(double) const from /usr/lib/x86_64-linux-gnu/libTKG3d.so.10+0x25
#5  0x7f4b03423d73 in GeomLProp_CurveTool::Value(Handle_Geom_Curve const&, double, gp_Pnt&) from /usr/lib/x86_64-linux-gnu/libTKG3d.so.10+0x13
#6  0x7f4b03427175 in GeomLProp_CLProps::SetParameter(double) from /usr/lib/x86_64-linux-gnu/libTKG3d.so.10+0x75
#7  0x7f4b0342727d in GeomLProp_CLProps::GeomLProp_CLProps(Handle_Geom_Curve const&, double, int, double) from /usr/lib/x86_64-linux-gnu/libTKG3d.so.10+0xcd
#8  0x7f4b11924b53 in Part::GeomCurve::pointAtParameter(double) const from /home/abdullah/github/freecad-build/Mod/Part/Part.so+0xa7
I have googled it coming back to FreeCAD forum when probably in another situation, the issue was notified in the tracker and a fix was provided by the team behind OCC.

I do not have the OCC source, so I can not jump in the debugger to that position (and at this time I do not have space in my hard disk to download it).

It would be great if a helping soul could take a look...

Thanks in advance,
abdullah
triplus
Veteran
Posts: 9471
Joined: Mon Dec 12, 2011 4:45 pm

Re: Sketcher: Bezier curves

Post by triplus »

abdullah wrote:A B-Spline is a piecewise complex curve, it is defined by a single curve, aka segment, inbetween two knots. Knots define the "union" between two segments. However, the requirement of a curve approximating a sequence of points is satisfied if the B-Spline is in those points at a given parameter value, it does not need to be the parameter corresponding to a knot
Thanks for the explanation. Therefore if we would have the ability to insert spline by inserting points. Points would likely end up being knots? And length between the segments would be the same? Solver would need to get involved? As i am guessing it would need to provide the ability for the end user to control the spline with control polygon (as now) or with points or by using any combination between them? That sounds complex indeed!

Maybe a question from another point of view. Separate spline creation method by using points instead of control polygon makes any sense or not?

In addition using any other point on spline and not just the ones corresponding to the knots would be possible too. But i am guessing that would likely be extremely complex task to implement?

Note that i am just thinking out loud. This are not suggestions for what you should implement. I can work with what you already implemented just fine. But in the future i likely will be asking myself such questions and likely i won't be able just to ask such question and expect to get in depth answer in return. ;)
The knot multiplicities won't be circles. There are several reasons. First it is a discrete value, integer not double. Second, it is not a solver magnitude, as will be handled via tools, not constraints (that is the reason also why the value is in the information layer and not as a constraint). Algorithms for knots insertion/removal (multiplicity increase/decrease) are complicated enough not to be part of a solver.
Sounds good.
abdullah
Veteran
Posts: 4935
Joined: Sun May 04, 2014 3:16 pm
Contact:

Re: Sketcher: Bezier curves

Post by abdullah »

triplus wrote:Points would likely end up being knots?
Not really. Knots will be, this new "concept" I invented, "construction points". Construction points are not solver parameters (well there are, there are fixed parameters, but it is easier to think as if they weren't), thus can not be moved by the solver and can not be constrained. They serve different purposes:

1) Avoid extremely complex solver implementations (as for example, moving a knot).
2) Allow selection of a knot for operation via OCC (knot removal, insertion, multiplicity increase/decrease)
3) Simplify any possible future implementation of solver (for example to deal with point on curve, but not taking into account moving of knots)

This does not mean that they are amovable, they are movable via OCC, not movable via the solver. I plan to provide appropriate dragging of knot construction points.
triplus wrote:length between the segments would be the same?
Nothing warranties segments will be the same length. But using knots is an inferior solution as it would require a higher number of segments, which would result in a more difficult to handle bspline.
triplus wrote:Solver would need to get involved?
There are three possibilities:
a) One clicks on the curve to approximate during creation. There are no real points created (just some line for example connecting points). The array of points given by the user is fed into an approximation function of OCC. A BSpline is created as a best fit. You can tweak it (poles, knots, weights, mults...), but nothing guaranties that it will continue fitting the points after tweaking it (solver no required).
b) The same as a), but it is not a creation method, the user inserts points in the sketcher, then selects the points he wants to approximate, a toolbar button is hit that creates a bspline that approximates the points. Same problem as before, you can tweak it, but nothing guaranties fitting after tweaking. As you still have the points (which you can lock), if you fedup of your tweaks you can just select your points and approximate again (solver no required).
c) Not for today, but if/when point on object is implemented, then is like b), but the points are point on object on the BSpline, so it should guarantie interpolation at the point (not necessarily fitting, as fitting may be with a degree of tolerance and point on object does not have any) (solver required).

I am aiming for b) in the short term. If Point on Object is ever implemented, c) should be straight-forward.

I think I have replied to the other points indirectly. If you have more questions let me know.
Post Reply