Notifications
Clear all

[Closed] Evenly divide splines using bezier curves??

I’m wondering what I would need to do in order to take an existing spline, and say “okay, divide this spline into x number of evenly sized segments, and use bezier corners to keep the overall shape of the spline as close to the original as possible.”

I say this fully understanding that it’s probably a lot harder to do than it sounds.

3 Replies
 eek

I havent done much in a while, but i think lengthInterp would probably work well. You could first get the number of knots along the spline, over a range of 1.0 e.g .25, .5, .75. Then use lengthInterp to store the positions along the spline using these percentages into an array. Finally push the knot positions into the stored values.

What would be harder is working out the the bezier tangents correctly if a knot has them. Getting that you’d probably need to get the secant, of the predicted shape and push them into it. Interesting challenge

Hm… is seems like there SHOULD be a way to use existing knots along with their inVec/outVec values to determine what the “average” spline passing through them should use for its own knots/inVec/outVec values?

As for the knots themselves, I’m definitely going to be using LengthInterp(). Using just that should get results at least as good as using the “Normalize Spline” modifier. So that’s a good start. Now I just need to figure out the bezier values.


EDIT:
Taking a closer look at this I came up with the following: if you have 3 bezier-corner knots on a spline, and are looking to get rid of the one in the middle but keep the shape (insofar as is possible), then the following values are what you have to work with as things that define the existing bezier curve:

knot1 pos
knot1 outVec pos

knot2 inVec pos
knot2 position
knot2 outVec pos

knot3 inVec pos
knot3 pos

distance from knot1 pos to knot1 outVec pos
distance from knot1 pos to knot2 inVec pos
distance from knot1 pos to knot2 pos

angle between (line from knot1 pos to knot2 pos) and (line from knot1 pos to knot1 outVec pos)
angle between (line from knot1 pos to knot2 pos) and (line from knot1 pos to knot2 inVec pos)

distance from knot2 pos to knot1 outVec pos
distance from knot2 pos to knot2 inVec pos

angle between (line from knot2 pos to knot1 pos) and (line from knot2 pos to knot1 outVec pos)
angle between (line from knot2 pos to knot1 pos) and (line from knot2 pos to knot2 inVec pos)

distance from knot2 pos to knot2 outVec pos
distance from knot2 pos to knot3 inVec pos
distance from knot2 pos to knot3 pos

angle between (line from knot2 pos to knot3 pos) and (line from knot2 pos to knot2 outVec pos)
angle between (line from knot2 pos to knot3 pos) and (line from knot2 pos to knot3 inVec pos)

distance from knot3 pos to knot2 outVec pos
distance from knot3 pos to knot3 inVec pos

angle between (line from knot3 pos to knot2 pos) and (line from knot3 pos to knot2 outVec pos)
angle between (line from knot3 pos to knot2 pos) and (line from knot3 pos to knot3 inVec pos)

So I was thinking this might be a good starting point…

So lets’ see…

First off, tried experimenting with a simple circle, radius 100 (generic units), converted to an editable spline. I determined that with the 4 knots, the distance of the in and out vectors comes to 55.1786. Obviously, the angle of each bezier “handle” is at 45 degrees to the lines between each knot and its neighbors.

Removing one of the knots, I lengthened each of the neighboring bezier handles to 133.3333. The midpoint of the spline now matches the position of the deleted knot. The angle of the handles are 90 degrees to the newly neighboring knots (or still at 45 degrees to the deleted knot).

Now, I realize that the new length of the adjusted splines is exactly 4/3 the radius of the circle. I’m not sure exactly how to figure the 55.1786 length of the original splines, but the new length is 2.4164 times the original. I tried that ratio with different sized circles and it always gives the desired result, but I am similarly unable to determine the significance of 2.4164.

If anyone who knows more about math can explain some of these things to me, it would be very helpful!

Also, I went ahead and set up a program to collect all of the various values I mentioned in my previous post. Unfortunately, I still don’t really know what to do with them.

array_KnotData = #()
  theShape = $
  
  -- Special thanks to prettyPixel
  fn lineLineAngle pA pB pC pD =
  (
  	local vAB = pB - pA
  	local vCD = pD - pC
  	local angle = acos (dot (normalize vAB) (normalize vCD))
  	
  	if angle < 90.0 then angle else (180.0 - angle)
  )
  
  for s = 1 to numSplines theShape do
  (
  	append array_KnotData #()
  	
  	for k = 1 to numKnots theShape s do
  	(
  		append array_KnotData[s] #()
  		
  		local kPrev, oPrev, iThis
  		local dist_kPoP, dist_kPiT, dist_kPkT, dist_kToP, dist_kTiT
  		local angle_kPoP, angle_kPiT, angle_kToP, angle_kTiT
  	
  		kThis = getKnotPoint	theShape s k -- current knot point
  	
  		local oThis, iNext, kNext
  		local dist_kToT, dist_kTiN, dist_kTkN, dist_kNoT, dist_kNiN
  		local angle_kToT, angle_kTiN, angle_kNoT, angle_kNiN
  	
  		if k > 1 do
  		(
  			kPrev = getKnotPoint theShape s (k - 1) -- previous knot point
  			oPrev = getOutVec theShape s (k - 1) -- outVector of previous knot point
  			iThis = getInVec theShape s k -- inVector of current knot point
  			
  			dist_kPoP = distance kPrev oPrev
  			dist_kPiT = distance kPrev iThis
  			dist_kPkT = distance kPrev kThis
  			dist_kToP = distance kThis oPrev
  			dist_kTiT = distance kThis iThis
  			
  			angle_kPoP = lineLineAngle kPrev oPrev kPrev kThis
  			angle_kPiT = lineLineAngle kPrev iThis kPrev kThis
  			angle_kToP = lineLineAngle kThis oPrev kThis kPrev
  			angle_kTiT = lineLineAngle kThis iThis kThis kPrev
  		)
  
  		if k < (numKnots theShape s) do
  		(		
  			oThis = getOutVec theShape s k  -- outVector of current knot point
  			iNext = getKnotPoint theShape s (k + 1) -- inVector of next knot point
  			kNext = getKnotPoint theShape s (k + 1) -- next knot point
  			
  			dist_kToT = distance kThis oThis
  			dist_kTiN = distance kThis iNext
  			dist_kTkN = distance kThis kNext
  			dist_kNoT = distance kNext oThis
  			dist_kNiN = distance kNext iNext
  			
  			angle_kToT = lineLineAngle kThis oThis kThis kNext
  			angle_kTiN = lineLineAngle kThis iNext kThis kNext
  			angle_kNoT = lineLineAngle kNext oThis kNext kThis
  			angle_kNiN = lineLineAngle kNext iNext kNext kThis
  		)				
  
  		append array_KnotData[s][k] #(kPrev, oPrev, iThis)
  		append array_KnotData[s][k] #(dist_kPoP, dist_kPiT, dist_kPkT, dist_kToP, dist_kTiT)
  		append array_KnotData[s][k] #(angle_kPoP, angle_kPiT, angle_kToP, angle_kTiT)
  		append array_KnotData[s][k] kThis
  		append array_KnotData[s][k] #(oThis, iNext, kNext)
  		append array_KnotData[s][k] #(dist_kToT, dist_kTiN, dist_kTkN, dist_kNoT, dist_kNiN)
  		append array_KnotData[s][k] #(angle_kToT, angle_kTiN, angle_kNoT, angle_kNiN)
  	)
  )
  
  for s = 1 to array_KnotData.count do
  (
  	for k = 1 to array_KnotData[s].count do (format "[%][%]: %
" s k array_KnotData[s][k])
  )