Trace a curve which pass through all of the points.

Questions about the LÖVE API, installing LÖVE and other support related questions go here.
Forum rules
Before you make a thread asking for help, read this.
Post Reply
Pordrack
Prole
Posts: 9
Joined: Tue Sep 04, 2018 5:23 pm

Trace a curve which pass through all of the points.

Post by Pordrack » Sat Jul 20, 2019 8:56 am

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

User avatar
raidho36
Party member
Posts: 1954
Joined: Mon Jun 17, 2013 12:00 pm

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

Post by raidho36 » Sat Jul 20, 2019 8:57 am

That's how bezier curves work, yes. It doesn't look far off to me so you can just keep it that way.

TheHUG
Citizen
Posts: 55
Joined: Sun Apr 01, 2018 4:21 pm

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

Post by TheHUG » Sat Jul 20, 2019 9:11 am

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.

Pordrack
Prole
Posts: 9
Joined: Tue Sep 04, 2018 5:23 pm

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

Post by Pordrack » Sat Jul 20, 2019 9:31 am

The problem is, it can sometime pass through walls because of that.
Last edited by Pordrack on Sat Jul 20, 2019 11:04 am, edited 2 times in total.


User avatar
raidho36
Party member
Posts: 1954
Joined: Mon Jun 17, 2013 12:00 pm

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

Post by raidho36 » Sat Jul 20, 2019 7:32 pm

You can try using centers of bodies as end points and joints as control points.

Pordrack
Prole
Posts: 9
Joined: Tue Sep 04, 2018 5:23 pm

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

Post by Pordrack » Sat Jul 20, 2019 8:15 pm

I did that, and yes, it's better, not perfect, but good enough for me.

User avatar
unixfreak
Citizen
Posts: 77
Joined: Thu Oct 15, 2015 6:25 am
Location: Bristol, UK
Contact:

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

Post by unixfreak » Sat Jul 20, 2019 11:01 pm

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.

User avatar
pgimeno
Party member
Posts: 1909
Joined: Sun Oct 18, 2015 2:58 pm
Location: Valencia, ES

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

Post by pgimeno » Sun Jul 21, 2019 1:15 pm

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:
Attachments
KochanekBartels.png
KochanekBartels.png (12.06 KiB) Viewed 1253 times

Post Reply

Who is online

Users browsing this forum: Bing [Bot] and 12 guests