Notifications
Clear all

[Closed] [SOLVED] Hanging rope (catenary)

Yes, real effective! Thanks again, hopefully I can play with it today a little

I noticed there was a small issue with the code above. The catenary worked splendid on the x plane, but was looking off in the y plane. (moving one of the helpers to the same x value as the other)

I added a small portion of code to the catenary function to account for this. Basically I’m just looking at the caterary in the x plane and then translate the calculated positions to the plane between the two points.
(see top and bottom of the function)

Thanks to you I now have a perfect and quick catenary:

fn catenary pt0 pt1 extent count &sag:1 max_iterations:100 =
(
	--build local coordsys for flat approach
	xMax = distance pt0 [pt1.x,pt1.y,pt0.z]
	zMax = pt1.z - pt0.z
	
	oldpt0 = pt0
	oldpt1 = pt1
	
	
	pt0 = [0,0,0]
	pt1 = [xMax,0,zMax] / extent
	
	len = 1.0
	
	fn interp s len d h = 
	( 
		2 * _sinh(s*d/2)/s - sqrt(len*len - h*h)
	)
	fn deriv s len d h = 
	(
		2 * _cosh(s*d/2)*d/(2*s) - 2 * _sinh(s*d/2)/(s*s)
	)

	max_iterations			-- maximum number of iterations
	min_grad	 	= 1e-10	-- minimum norm of gradient
	min_val	 		= 1e-8	-- minimum norm of sag function
	step_size 		= 0.5	-- factor for decreasing step_size
	min_step	 	= 1e-9	-- minimum step size
		
	if pt0.x > pt1.x do swap pt1 pt0
	
	d = pt1.x - pt0.x
	h = pt1.z - pt0.z
	
	pts = makePointTab count pt0 pt1
	
	ptx = #()
	pty = #()
	ptz = #()
	
	compPoint3Tab pts ptx pty ptz
	
	if len > sqrt(d*d + h*h) do -- rope is not stretched: straight line
	(
		-- find rope sag
		end = off
		for i=1 to max_iterations while not end do
		(
			val	= interp sag len d h
			grad = deriv sag len d h
			
			end = abs(val) < min_val or abs(grad) < min_grad
			
			if not end do
			(
				search	= -(interp sag len d h)/(deriv sag len d h)
				
				alpha = 1
				_sag = sag + alpha*search
				
				out = false
				while (_sag < 0 or abs(interp _sag len d h) > abs(val)) and not out do
				(
					alpha *= step_size
					if not (out = alpha < min_step) do
					(
						_sag = sag + alpha*search
					)
				)
				
				sag = _sag
			)
		)
		
		-- get location of rope minimum and vertical bias
		x_left = 0.5 * (log((len + h)/(len - h))/sag - d)
		x_min = pt0.x - x_left
		
		_bias = pt0.z - _cosh(x_left * sag)/sag
		
		ptz	= #()
		for x in ptx do append ptz (_cosh((x - x_min)*sag)/sag + _bias)
	)
	
	--scale back to original values
	pts = combPoint3Tab ptx pty ptz scale:extent

	--recalculate in actual 3d plane
	for i=1 to pts.count do 
	(
		pt = pts[i]
		horFactor = pt.x / xMax
		
		pt.x = oldPt0.x + ((oldPt1.x - oldpt0.x) * horFactor)
		pt.y = oldPt0.y + ((oldPt1.y - oldpt0.y) * horFactor)
		pt.z = oldPt0.z + pt.z
		
		pts[i] = pt
	)
	pts
)

I also tried and successfully got a parabola to work but the sharpness at the bottom of the curve was bothering me. Now I have the ‘real’ thing at least. I also figured out what I was doing wrong in my own catenary function. I was superclose but the normalizing and properly setting the bias was where I was off. Thanks again man

Page 2 / 2