I know this topic has been discussed here before and to my belief it never got to a true mathematical approach of a hanging rope.
What I am looking for is a semi realistic simulation of a hanging rope between two points (of different height) and a given rope length. I cannot use physics or MassFX or anything like that, because I will be using it is a live max viewing session and I need things to behave quick and effortless.
Now this rope can be devoid of any physical parameters. I don’t need it to stretch or have elasticity as it is called, but I would like to know the actual lowest point and the way the rope or cable should hang. So basically, I would like to generate a curve with N points, and I would like to calculate the height of said points.
Behaviour of a rope can be described using a Catenary, a mathematical description of a rope. I have giving the formulas for that shape a lot of thought this past week, but the math is beyond me at the moment.
Now I have found two example codes that I have both tried to convert to maxscript with varying result:
http://members.chello.nl/j.beentjes3/Ruud/catfiles/catenary.pdf#page=7&zoom=100,0,0
https://nl.mathworks.com/matlabcentral/fileexchange/38550-catenary-hanging-rope-between-two-points
(see functions and then the catenary function)
I have made a dummy that has a scale_script controller that controls the position of the spline points. These points are calculated using the logic, but somehow my logic isn’t sound.
While the below image looks good it fails to behave as it should when the right point is lower than the left point, and the lenght also isn’t always close to the actual target length.
below is my Maxscript snippet of my logic from the second solution that is giving me the best result so far. I have racked my brain on this for some days now, so if someone could help me with the final stretch that would be very much appreciated.
My question would be, can someone help me with proper logic for a catenary, or perhaps point me in the right direction as I am also not sure what I am doing wrong here.
fn g s d r_length h= 2.0*sinh(s*d/2.0)/s - sqrt(r_length^2.0-h^2.0)
fn dg s d = 2.0*cosh(s*d/2.0)*d/(2.0*s) - 2*sinh(s*d/2.0)/(s^2.0)
fn catenary a b r_length N sagInit = (
-- given two points a=[ax ay] and b=[bx by] in the vertical plane,
-- rope length r_length, and the number of intermediate points N,
-- outputs the coordinates X and Y of the hanging rope from a to b
-- the optional input sagInit initializes the sag parameter for the
-- root-finding procedure.
maxIter = 100 -- maximum number of iterations
minGrad = 1e-10 -- minimum norm of gradient
minVal = 1e-8 -- minimum norm of sag function
stepDec = 0.5 -- factor for decreasing stepsize
minStep = 1e-9 -- minimum step size
minHoriz = 1e-3 -- minumum horizontal distance
if saginit == undefined then (
sag = 1
)
else (
sag = sagInit
)
pointA = a
pointB = b
d = distance pointB [pointA.x,pointA.y,pointB.z]
h = distance pointA [pointA.x,pointA.y,pointB.z]
PointArray = #()
Xdist = pointB.x - pointA.x
Ydist = pointB.y - pointA.z
Zdist = pointB.z - pointA.z
for i=0 to N do
(
P = [PointA.x + ((Xdist/N)*i),pointA.y+((Ydist/N)*i),pointA.z]
append PointArray P
)
-- rope is stretched: straight line
if r_length <= sqrt(d^2+h^2) then (
for i=0 to N do
(
P = PointArray[i+1]
P.z = PointA.z + ((Zdist/N)*i)
PointArray[i+1] = P
)
)
-- find rope sag
else
(
for i= 1 to maxIter do (
val = g sag d r_length h
grad = dg sag h
if (abs val) < minVal or (abs grad) < minGrad then (
break
)
search = -(g sag d r_length h )/(dg sag h)
alpha = 1
sag_new = sag + alpha*search
while sag_new < 0 or (abs(g sag_new d r_length h)) > (abs val) do
(
alpha = stepDec*alpha
if alpha < minStep then
(
break
)
sag_new = sag + alpha*search
)
sag = sag_new
)
Xstep = d/N
-- get location of rope minimum and vertical bias
x_left = 0.5*(log((r_length+h)/(r_length-h))/sag-d)
for i=0 to N do (
X = Xstep*i
x_min = -x_left
bias = pointA.z - cosh(x_left*sag)/sag
Z = cosh((X-x_min)*sag)/sag + bias
P = PointArray[i+1]
P.z = pointA.z + Z
PointArray[i+1] = P
)
)
PointArray
)
a = catenary [0,0,0] [20,0,5] 28 10 1
new_spline = line()
addNewSpline new_spline
for i=1 to a.count do (
addKnot new_spline 1 #smooth #curve a[i]
)
updateshape new_spline