ID:2065230
 
Problem description:

Can someone show me code for drawing a curved line from one image to another?


I want to create a targeting system that dynamically draws a curved line. I imagine this will be done using calculus- tanget lines and all that. This line will represent the distance from one player an object. The object will be a quest item's location.


Consider an example. It is a video of mind mapping software. In it the ovals are the images and the lines in between are the curves.

https://www.youtube.com/watch?v=Gchwi3rb27s (Starts at 00:52)
I'm not sure the best way to draw lines in DM, so someone will have to remark on that separately, but the below should work to get the points you need to draw.

As you can see here there is a general form for a Bézier curve with n points. For simplicity's sake, I'm going to define a Point class as follows.
Point
var
x
y

New(_x, _y)
src.x = _x
src.y = _y

proc
Add(x_, y_)
x += x_
y += y_

Then the BezierCurve function will take a list of Point objects and a "fineness" factor alpha and spit out a list of Point objects to draw a curve between.
proc/Choose(n,k)
// Code for this courtesy of http://www.geeksforgeeks.org/space-and-time-efficient-binomial-coefficient/

var/result = 1

if(k > (n-k))
k = n-k

for(var/i = 0, i < k, ++ i)
result *= n - i
result /= i + 1

return result

proc/BezierCurve(list/Points, alpha)
// Points is a list of /Point objects, while alpha is a "fineness" factor referring to one plus
// the number of points to plot for the final curve. The larger alpha, the finer and smoother-
// looking the curve.

. = list()

var/n = Points.len
for(var/i = 0, i <= alpha, i ++)
var/delta = i * (1/alpha)

var
q = 1
r = (1 - delta)**(n - 1)

Point/Result = new(0,0)

for(var/k = 1, k <= n, k ++)
var
Point/P = Points[k]

binom = Choose(n-1, k-1)

x = P.x * q * r * binom
y = P.y * q * r * binom

Result.Add(x,y)

q *= delta
r /= 1-delta

. += Result

Obviously, there's some simplifications and optimizations that can be done, and it doesn't handle actually drawing the lines, but it's the start.

And as a demonstration, assuming we want to have a Bezier curve with the five points,
  1. (0,0)
  2. (-3,5)
  3. (5,5)
  4. (7,0)
  5. (9,2)

with a "fineness factor" of 50, we get the following curve (with the listed points plotted as well),

Though here I'm using Mathematica to get the curve rather than BYOND.
There is a bezier curve drawing library.

http://www.byond.com/developer/Mightymo/BezierCurves

However, I don't think this is quite what OP is looking for here. It sounds like he wants to draw a line to lead someone from where they currently are, to some point on the map. Kind of like how the Killing Floor games shows you the path to the trader in between waves.

This would take a combination of a pathfinding system to find the path and some particles system to make the shown path look organic ahd fluid.
In response to D4RK3 54B3R
D4RK3 54B3R wrote:
There is a bezier curve drawing library.

http://www.byond.com/developer/Mightymo/BezierCurves

Wow, that code looks even less efficient than mine... It also has a horrendously slow binomial coefficient method. Looks like it's about O(n3), assuming I'm figuring that out correctly (It might be O(n2); I've never really done any complexity stuff). The one I use is linear in k.

However, I don't think this is quite what OP is looking for here.

I only briefly read over it. It mentioned "Bézier Curve" in the description, and that piqued my interest, so I responded to that.
Two ovals. A line connects them. Move one the line updates.
This line is a curve.

I'd be fine if it worked just like a mind mapping software. Simple mind is the best example that comes to mind- no pun intended. http://www.simpleapps.eu/simplemind/
In response to Sir Quizalot
Sir Quizalot wrote:
Two ovals. A line connects them. Move one the line updates.
This line is a curve.

Yes, then this is simply a Bézier curve where the first point provided to the function is the point attached to the first oval, and the final point is the line attached to the second oval. You can choose to add other points if you want to make the line "curvier", as simply two points will produce a line. But you need to figure out how you want to select those other points.
I'm thinking add points on the fly based on distance between the two ovals. Then drawing new lines between new points. Lastly, erasing old lines between past connections. How would this be achieved?
In response to Popisfizzy
Popisfizzy wrote:
D4RK3 54B3R wrote:
There is a bezier curve drawing library.

http://www.byond.com/developer/Mightymo/BezierCurves

Wow, that code looks even less efficient than mine... It also has a horrendously slow binomial coefficient method. Looks like it's about O(n3), assuming I'm figuring that out correctly (It might be O(n2); I've never really done any complexity stuff). The one I use is linear in k.

Yeah, I pointed out those issues to Mightymo at one point. Sad to find out he never addressed them properly. The operations are really not as efficient as they should be.
Come on Lummox JR share some of your expertise. What is Popisfizzy missing? Or are you try to emphasise the use of the library?
I'm saying (in agreement with Pop) that Mightymo's library is flawed, and I wish he had fixed it as he said he would.