Page 1 of 1

Trace a curve which pass through all of the points.

Posted: Sat Jul 20, 2019 8:56 am
by Pordrack
Hi ! I'm currently coding a game where the player swing using a rope, using love.physics as the physics engine, the rope is made with rectangles jointed together thanks to RevoluteJoint , to render the rope graphically, I wanted to use Bezier Curved, to have a smooth rope , instead of rectangles, so I give all the anchor points to the bezier curve and render it, but I noticed that it doesn't use all the points, it takes some shortcut.

Image

Re: Trace a curve which pass through all of the points.

Posted: Sat Jul 20, 2019 8:57 am
by raidho36
That's how bezier curves work, yes. It doesn't look far off to me so you can just keep it that way.

Re: Trace a curve which pass through all of the points.

Posted: Sat Jul 20, 2019 9:11 am
by TheHUG
Whatever my girlfriend's svg editing software used for it's curves ( which it did call bezier) does pass through all the points, so I was also surprised by this.

I spent some time looking for this, and I didn't find anything. I think you'll need to come up with it yourself. I was thinking of doing it myself but haven't gotten around to it and probably won't for a while.

I expect it'd be some pretty tough math though, and if it's just for rendering then raidho is right - it still looks pretty good.

Re: Trace a curve which pass through all of the points.

Posted: Sat Jul 20, 2019 9:31 am
by Pordrack
The problem is, it can sometime pass through walls because of that.

Re: Trace a curve which pass through all of the points.

Posted: Sat Jul 20, 2019 10:33 am
by grump
Use Catmull-Rom instead of Bezier splines.

Re: Trace a curve which pass through all of the points.

Posted: Sat Jul 20, 2019 7:32 pm
by raidho36
You can try using centers of bodies as end points and joints as control points.

Re: Trace a curve which pass through all of the points.

Posted: Sat Jul 20, 2019 8:15 pm
by Pordrack
I did that, and yes, it's better, not perfect, but good enough for me.

Re: Trace a curve which pass through all of the points.

Posted: Sat Jul 20, 2019 11:01 pm
by unixfreak
Not sure if this is any use, but a while back i was trying to understand the use of moving an object along a bezier curve (typically a rocket/missile), this example that someone fixed for me may be useful in plotting the points along the curve:

https://love2d.org/forums/viewtopic.php ... 10#p211910

May be some other relevant info in that thread also.

Re: Trace a curve which pass through all of the points.

Posted: Sun Jul 21, 2019 1:15 pm
by pgimeno
One method to do what the OP wants with LÖVE is the Kochanek-Bartels method. It works by drawing one Hermite curve between each pair of points.

While the method generates Hermite curves, these can easily be converted to Bézier for them to be drawn with LÖVE. You can adjust tension to the desired value, and leave continuity and bias set to 0. In my experience, a bit of negative tension works better than zero tension (which would produce a Catmull-Rom spline).

To convert a start Hermite vector to the first control point of a cubic Bézier, divide it by 3 and add the start point. To convert an end Hermite vector to the second point of a cubic Bézier, divide it by -3 and add the end point.

For example, if the Hermite curve is given by start and end points p0 and p1, and tangents d0 and d1, the corresponding Bézier control points P0, P1, P2, P3 (where P0 and P3 are the starting and ending point, and P1 and P2 are the control points) are:

P0 = p0
P1 = p0 + d0 / 3
P2 = p1 - d1 / 3
P3 = p1

Edit: Sorry, I previously said "multiply by 3". I misremembered, it should have been "divide by 3".

Edit 2: Simple example follows:

Code: Select all

local bez = love.math.newBezierCurve(0,0, 0,0, 0,0, 0,0)

local function Kochanek_Bartels(t, c, b,
    p0x, p0y, p1x, p1y, p2x, p2y, p3x, p3y)
  local P0x = p1x
  local P0y = p1y
  local P1x = p1x + (  (1-t)*(1+b)*(1+c) * (p1x - p0x)
                     + (1-t)*(1-b)*(1-c) * (p2x - p1x) ) / 6
  local P1y = p1y + (  (1-t)*(1+b)*(1+c) * (p1y - p0y)
                     + (1-t)*(1-b)*(1-c) * (p2y - p1y) ) / 6
  local P2x = p2x - (  (1-t)*(1+b)*(1-c) * (p2x - p1x)
                     + (1-t)*(1-b)*(1+c) * (p3x - p2x) ) / 6
  local P2y = p2y - (  (1-t)*(1+b)*(1-c) * (p2y - p1y)
                     + (1-t)*(1-b)*(1+c) * (p3y - p2y) ) / 6
  local P3x = p2x
  local P3y = p2y
  bez:setControlPoint(1, P0x, P0y)
  bez:setControlPoint(2, P1x, P1y)
  bez:setControlPoint(3, P2x, P2y)
  bez:setControlPoint(4, P3x, P3y)
  love.graphics.line(bez:render())
end

local points = {0, 0, 200, 0, -200, -150, -250, 120, 300, 250}

local tension = -0.6
local continuity = 0
local bias = 0

function love.draw()
  love.graphics.translate(love.graphics.getWidth()/2, love.graphics.getHeight()/2)

  -- Draw dots
  love.graphics.setColor(1, 1, 1, 1)
  for i = 1, #points, 2 do
    love.graphics.circle("fill", points[i], points[i + 1], 5)
  end

  love.graphics.setColor(0, 0.3, 1, 1)
  local len = #points
  local npoints = len / 2
  if npoints >= 3 then
    -- do first segment by repeating first point
    Kochanek_Bartels(tension, continuity, bias,
      points[1], points[2], points[1], points[2],
      points[3], points[4], points[5], points[6])
    -- do middle segments
    for i = 2, npoints - 2 do
      local base = i * 2 - 1
      Kochanek_Bartels(tension, continuity, bias,
        points[base - 2], points[base - 1],
        points[base], points[base + 1],
        points[base + 2], points[base + 3],
        points[base + 4], points[base + 5])
    end
    -- do last segment by repeating last point
    Kochanek_Bartels(tension, continuity, bias,
      points[len - 5], points[len - 4], points[len - 3], points[len - 2],
      points[len - 1], points[len], points[len - 1], points[len])
  elseif npoints == 2 then
    -- just draw a line between the points
    love.graphics.line(points)
  end
end

function love.keypressed(k) return k == "escape" and love.event.quit() end
Snapshot: