3

I'm working on a project with B-Splines in OpenGL.

The B-Spline itself works as far as I can say but I also want to add some weight to my control-points in a range of 1-10 in order to have the spline go closer to points with higher weight.

The problem that I have right now is that when I add some weight to a point the spline always goes way above that point instead of just getting a little bit closer.

Now what I have tried so far is to implement my program the way it is described in this article. The Last topic in this article describes how to implement B-Splines with weight but it doesn't work for me.

This is how I add weight to a control-point.

I create a control-point with a mouseclick and add weight with the value 1 as the third vector parameter

def onMouseButton(win, button, action, mods):
    global degree
    global M
    global currentpoint
    global shift
    global yposition
    shift = 0
        if button == glfw.MOUSE_BUTTON_LEFT:
            if action == glfw.PRESS:
                p = np.array(glfw.get_cursor_pos(win))
                p[0] = (p[0] - WIDTH/2) / (WIDTH/2)
                p[1] = 1 - (p[1] / (HEIGHT/2))
                p = np.append(p, 1.0)
                controlpoints.append(p)

Then I divide a selected controlpoint by its old weight to set it back to 1 and then I multiply the point by its new weight. Currentpoint is the point I have selected to add weight to.

def onMouseMove(win, xpos, ypos):
    global shift
    global currentpoint
    global yposition

    if shift == 1:
        for x in controlpoints:
            if np.array_equal(x, currentpoint):
                weight = yposition - ypos
                if weight >= 10:
                    weight = 10
                if weight <= 1:
                    weight = 1
                x[0] /= x[2]
                x[1] /= x[2]
                x[2] = weight
                x[0] *= x[2]
                x[1] *= x[2]
                calcSpline()

And this is how I try to render the spline For rendering I want to ignore the added weight.

def render():
    weightpoints = []
    for x in controlpoints:
        a = x[0]/x[2]
        b = x[1]/x[2]
        element = [a, b]
        element = np.array(element)
        weightpoints.append(element)
    # draw black control polygon
    draw(GL_LINE_STRIP, weightpoints, [0.0, 0.0, 0.0])
    #draw red control points
    draw(GL_POINTS, weightpoints, [1.0, 0.0, 0.0])
    #draw red control points
    draw(GL_LINE_STRIP, splinepoints, [0.0, 0.0, 1.0])
    # recalculate spline curve
    calcSpline()
    # draw blue bspline deboor points
    draw(GL_POINTS, splinepoints, [0.0, 1.0, 1.0])

def draw(mode, points, color):
    # draws objects
    glPointSize(3)
    glEnable(GL_POINT_SMOOTH)
    glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA)
    glBegin(mode)
    glColor(color[0], color[1], color[2])
    for p in points:
        glVertex2f(p[0], p[1])
    glEnd()

UPDATE

This is how I calculate the spline. The deboor alogrithm and the findR function should be correct scince I have them from a lecture foil.

def calcSpline():
    # calculates spline curve with deboor
    calcKnotVector()
    del splinepoints[:]
    if len(controlpoints) >= degree:
        t = 0
        while t <= knotvector[-1]:
            r = findR(t)
            b = deBoor(controlpoints, knotvector, t, r, degree - 1)
            splinepoints.append(b)
            t += 1 /float(M - 1)
            t -= 0.0000000001

I Expected the Spline to go closer to the selected point but instead it always grows above it.

  • `a = x[0]/x[2]` `b = x[1]/x[2]` `element = [a, b]` - this does not make sense as you will create a simple unweighted B-spline. You should get the exact same result irrespective of the weights you set. You haven't shown the most important part - `calcSpline()`. – Nico Schertler Jul 25 '19 at 21:29
  • @NicoSchertler Thank you for the comment. I will look into that scince this is a part of the code that bothers me the most at the moment. – Manuel Gerhardt Jul 26 '19 at 05:50
  • Since none of the code shows what types will be produced, I am taking a guess. If you have a rational B-spline, you create the spline with 3D control points that include the weight. This will give you 3D spline points. *After* you have these points, you factor out the weight to turn them into 2D points. Also, the `t -= 0.0000000001` looks very suspicious. – Nico Schertler Jul 26 '19 at 15:53
  • The changes you proposed worked but Im still a little bit confused with the way Rational B-splines work. because when you read the article Ive posted under the topic "Extending our implementation to cover rational splines", it says that you have to recover the real curve by unweighting it and throwing away the weight information. Can you maybe explain to me what Ive understood wrong here? I would also like to remove the line with the t -= 0,0000001 but without that line a b-spline with 5 or less controllpoints isnt rendered to the last control point. – Manuel Gerhardt Jul 26 '19 at 19:43
  • It seems you have understood it right. What you are experiencing with the `t` loop are some floating point inaccuracies. A better solution is to iterate using an integer index and calculate `t` from it. – Nico Schertler Jul 26 '19 at 21:13

1 Answers1

1

UPDATE

Thanks to Nico Schertler I got the program running and working. What I did wrong was creating and working with 3D control points including their weight but I factored these points out again, turning my 3D Vectors into 2D points, which was a mistake made by me.

Here is the draw function redone:

def draw(mode, points, color):
    # draws objects
    glPointSize(5)
    glLineWidth(3)
    glEnable(GL_POINT_SMOOTH)
    glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA)
    glBegin(mode)
    glColor(color[0], color[1], color[2])
    for x, y, w in points:
        glVertex2f(x / w, y / w)
    glEnd()

The rest of the code didn't change.

:)