Notifications
Clear all

[Closed] Mini-challenge #7: Divide bezier spline

…or a combination of these. I like this one better

macroscript subDSpline
category:"splineTools"
tooltip:"subDSpline"
(
try(DestroyDialog divideSpline)catch()
rollout divideSpline "subDSpline" width:244 height:32
(
	spinner spn1 "" type:#integer pos:[8,8] width:50 height:16 across:5 range:[1,1000,0]
	checkbox linear "smooth" checked:false offset:[8,4]
	checkbox closeSpline "o" checked:false offset:[25,4]
	button btnOK "ok" align:#right
	button btnCancel "cancel" align:#right offset:[6,0]
	
	
	local spline, oSpline

	
	fn setLinear state=
	(
		if (spline!=undefined) do
		(
			if state==off then
			(
				for i = 1 to (numknots spline) do
				(
					setKnotType spline 1 i #corner
					updateShape spline
				)
			)
			else
			(
				for i = 1 to (numknots spline) do
				(
					setKnotType spline 1 i #smooth
					updateShape spline
				)
			)

		)
	)
	
	fn clSpline=
	(
		if ((spline!=undefined) and (closeSpline.checked==true)) do (close spline 1; updateShape spline)
	)
	
	
	fn subDSpline tSpline count=
	(
		cLength = curveLength tSpline
		interp = (cLength/count)/cLength

		spline = splineShape name:"sp" wirecolor:green
		spline.vertexticks = on
		addnewSpline spline
		for i = 0 to count do
		(
			pos = interpCurve3D tSpline 1 (interp*i) pathParam:false	
			addKnot spline 1 #corner #curve pos
		)
		setLinear linear.checked
		clSpline()
		updateShape spline
	)

	on divideSpline open do
	(
		if ($!=undefined) do
		(
			max create mode
			oSpline = $
-- 			hide oSpline	
		)
	)
	
	on spn1 buttondown do
	(
	)
	
	on spn1 buttonup do
	(
		if (spline!=undefined and not spline.isdeleted) do spline.vertexticks =  off
	)

	on spn1 changed val do
	(
		if (oSpline!=undefined) do
		(
			if (spline!=undefined and not spline.isdeleted) do delete spline
			subDSpline oSpline val
		)
	)

	on btnOK pressed do
	(
		if (spline!=undefined) do
		(
			select spline
			spline.wirecolor = gray
			delete oSpline
			spline = undefined
		)
		DestroyDialog divideSpline
	)
	
	on btnCancel pressed do
	(
		if (spline!=undefined) do
		(
			delete spline
			spline = undefined
			unhide oSpline
		)
		DestroyDialog divideSpline
	)
	
	on linear changed state do
	(
		setLinear state
	)
	
	on closeSpline changed state do
	(
		clSpline()
	)
)
if $!=undefined do CreateDialog divideSpline style:#(#style_toolwindow) modal:false
)




after I show my solution some people will say: ‘Sure! It’s so easy. I just didn’t want to waste my time…”
Well but some years ago I spent couple days to find this solution. And believe me, it’s not trivial.

OK. theres is the code:


/* test spline */
with redraw off
(
	delete objects
	
	global sp = splineShape name:"sp" wirecolor:orange
	sp.vertexticks = on
	addnewSpline sp
	addKnot sp 1 #corner #curve [0,0,0]
	addKnot sp 1 #corner #curve [100,0,0]
	setknottype sp 1 1 #bezierCorner
	setoutvec sp 1 1 [0,40,0]
	updateShape sp
)
/* the subdivide  function */
fn subdivideSplineEvenly sp index divisions:1 = if iskindof sp SplineShape do
(
	converttosplineshape sp
	step = 1./(divisions+1)
	for k=1 to divisions do
	(
		param = k*step
		p = lengthToPathParam sp index param
		segs = numSegments sp index
		seg = floor(p*segs) + 1
		ps = p*segs - seg + 1
		k = refineSegment sp index seg ps
		resetLengthInterp()
	)
	updateshape sp
)

/* go the test >evenly subdivide 5 times... */
(
	subdivideSplineEvenly sp 1 divisions:5
)

because I didn’t see real interest in this issue, I don’t give any comments and explanation. [b][i]sapienti sat

[/i][/b]

i purposely left some imperfection in my code… could anyone point it out?

Denis, I didn’t have time to dive into your code yet, but from a small experiment that I did with it, it looks like it doesn’t work very well with big numbers.
with divisions = 20 you I can already see the imperfection, and when the numbers are bigger, like divisions = 50 it is obvious.
Am I missing something here?
Edit:
oh, now I see your comment

1 Reply
(@denist)
Joined: 11 months ago

Posts: 0

the first problem was found… so we can add extra parameter to set the number of length interpolation steps… new function has to look:


 fn subdivideSplineEvenly sp index divisions:1 steps:100 = if iskindof sp SplineShape do
 (
 	converttosplineshape sp
 	step = 1./(divisions+1)
 	for k=1 to divisions do
 	(
 		param = k*step
 		p = lengthToPathParam sp index param steps:steps
 		segs = numSegments sp index
 		seg = floor(p*segs) + 1
 		ps = p*segs - seg + 1
 		k = refineSegment sp index seg ps
 		resetLengthInterp()
 	)
 	updateshape sp
 )
 /*
 -- try it 
 subdivideSplineEvenly sp 1 divisions:50 steps:10000
 */
 

but this is not the only one problem …

yesterday, I tried a complicated method,
that for a momment made me think I was close… but no.
I grunted, deleted my attempt, and emptied the recycle bin…

the next has something I thought away from the computer, last night
but I wasn’t considering ‘resetlengthInterp’,
so it would have never worked without seeing denisT code
(still I havent analysed denisT code, yet)


(
	fn divideEven o s segs steps: =
	(
		convertToSplineShape o
		if steps==unsupplied do steps = curveLength o * 5 as integer
		for n = 1. to segs - 1 do if not keyboard.escPressed do
		(
			pa = lengthToPathParam o (n/segs) steps:steps
			pa-= 1./n*(n-1)
			pa*= n
			refineSegment o s n pa
			resetLengthInterp o
		)
		updateShape o
	)
	divideEven $ 1 28
)

I don’t know if it is good enough… but seems to work

1 Reply
(@denist)
Joined: 11 months ago

Posts: 0

i see that you always refine next segment. for multi-segment spline it’s not always true.

let me check, I used your demo in other post…

but if the spline already has segments, you get non even segments. right?

2 Replies
(@denist)
Joined: 11 months ago

Posts: 0

Right. But at least we have cuts in the right places. It’s a different story what to do with old knots. We will decide it later.

(@denist)
Joined: 11 months ago

Posts: 0

usually i make an arbitrary sample. so working on a function you always have to keep in mind its general usage.

aha, that’s interesting…
I’m gonna try…

yeap, that would be the best case, but because of the hurry,
and lack of inborn geniality… :]

.
here’s my second ver. it now allows existing verts:

(
	fn divideEven o s segs steps: =
	(
		convertToSplineShape o
		if steps==unsupplied do steps = curveLength o s * 5 as integer
		for n = 1. to segs - 1 do
		(
			pa = lengthToPathParam o s (n/segs) steps:steps
			prevseg = (FindPathSegAndParam o s pa)[1] - 1
			--prevseg = (ceil (pa / (1./(numSegments o s)))) - 1
			pa = pa /(1.0/(numSegments o s)) - prevseg
			refineSegment o s (prevseg + 1) pa
			resetLengthInterp o
		)
		updateShape o
	)
	divideEven $ 1 22
)


ok… when we have the method we can think about old (original) knots…
what a criterion could be to simply delete a knot?

find the crossing point defined by the 2 adjacent tangents
and move those tangents to 0.5 distance to the cross point…

1 Reply
(@denist)
Joined: 11 months ago

Posts: 0

hmm… it’s not clear for me. again. we are looking for some rules. why some point on spline can be reduced?

Page 2 / 3