Best way to cut half slots for a lattice of 15mm mdf?



Rhino V4 or V5

Imagine a criss cross of 15mm thick mdf sheets (90 degrees to each other) , 1 mtr x 0.5 mtr interlocking with half slots in each.

Slots 15.5mm x 250.5mm (0.5 is the required tolerance to ensure fit)

With the lattice already assembled on screen , solids running though each other having just done the extrude from curve, Is there a quick way of doing an intersect and getting these slots to occur ?


(John Brock) #2

Nothing I can think of in native Rhino tools.

I think you could use Grasshopper to build a system that would allow you to do that sort of modeling and change your mind about sizes and spacing.


hey John…

if i understand correctly, steve just want’s to make the slots in a predetermined arrangement of panels and not necessarily in a parametric fashion ? in which case, it’s decently easy to do with the boolean tools and some cutting blocks.

(i think i’d personally use copy/pasting and some scaling operations but it’s probably confusing for me to try to explain it)

Creating half-notch slots in intersecting surfaces
(John Brock) #4

Except he’s looking for a +0.5 tolerance added.
That’s why I suggested Grasshopper.


I’ve been working on a similar goal for doing a form or ‘buck’ that will be used for boat plugs and or molds. Here is a good place to start, Bowerbird for Grasshopper. Pretty mind boggling at first but once you look at the tuts and vids and load the files and follow along with the tuts it sort of falls into place. They labeling and projecting to a cut sheet are a huge timesaver! Great work by TJO. Also search the Grasshopper site for ‘waffle’.

(Pascal Golay) #6

Steve, do your objects fully intersect? I mean, are they exactly the same width, flush at both edges and need to be notched halfway?



Grasshopper seems to me to be more complex than is needed for this task.

Quickest approach is probably to create a pair cutting solids in the shape of the material to be removed. The tolerance can be built into the cutting solids using OffsetSrf to enlarge the cutting solids by the amount of the tolerance 0.5 mm tolerance would mean offsetting the surfaces by 0.25 mm.

If the sheets are equally space and the half slots all at the same height use Array to create copies of the cutting solids pairs. Otherwise use copy and move to put copies of the cutting solids in the required locations.

Then use BooleanDifference with the appropriate sets of cutting solids to trim the mdf sheets.


i did a design which required some slotting and to me, i found it easier if working with single planes (though it might not necessarily help with rectangular objects… with all these curved pieces, it help a lot)… grasshopper may have helped as well but i’m on mac so i don’t have grasshopper :wink:

here’s a quick video showing how you might approach the slots with the specs outlined in the original post…


7 verticals and 6 horizontals from memory, all different shapes in reality of an aircraft tail area but for principle I said 1 x .5 mtr

they are 100mm apart.

not that dissimilar to Jeff’s array, though mine are sort of bottle shaped for the verticals and horizontals are airfoil shape (fin/rudder)
Jeff …the video is a promising start and I truly am gratefuil for you taking time to do that.

videos for such are invaluable and others will also see this now on youtube…great stuff.

I had someone prepared to use a saw and I saw ( :slight_smile: ) a chance to CAD it !
I had thought of create solids then use intersect , either an option in there to widen the intersect by 0.5mm, or explode and offset the slots then join again. …or a boolean with options

To have an option on intersect for such slotting would be great, bet this half slotting gets used quite a bit.



heh…no problem… but videos are time savers.
imagine me trying to type out what I did there :smile:

(Pascal Golay) #11

Hi Steve, I dredged up an old script and tuned it a little- see how this works:

To use the script, extract and save the .rvb file from the attached zip archive, then drag and drop the saved rvb over an open Rhino v5 window. This will load the script, set it up to load on startup in the future and register the alias


that will run the script much like a regular command. An alias can be typed or added to a toolbar button or keyboard shortcut (F-key).

You set a clearance (defaults to .05; zero does not work right now) and then the object to cut, then each of the intersecting objects in turn. I do not know how reliable it is in real life, but it tries to make the notches the same way in the first object- that probably needs more work, but give it a spin.

Notcher (4).zip (3.1 KB)



you gotta start writing all your sweet scripts in Python :smile:

(joking… would be nice to use some of them on mac though)

(Pascal Golay) #13

You’re right, of course - it’s just that this one already existed in RS, I found it under the wood pile by the shed, so I just cleaned it up and made it work in more cases… but, a week or two of conversion time would be nice for a pile of these that I have laying around. I’ll see if I can make this one work in Python… there are many more possibilites of course, so it can probably be made to work better.



heh… yeah, sorry about always being pesky (pesty?) about this mac stuff… I figure if I keep at it, cross platform compatibility with rhino will be standard mindset for most coders in 5 years from now.

it doesn’t really matter though… if rhino for mac stayed exactly how it is right now, I’d still use it as my main drawing tool. :wink:


Hi Pascal
Your Notcher script looks ideal for a job I have - however, when I run it in Rhino 5, I get an error on line 85:
Variable is undefined: 'VecDir’
Do you have an updated version of the script or could you suggest something that could replace it?
The job is to create the templates for forming curved surfaces to - generating the required surfaces and solids isn’t particularly time consuming and being able to add the slots with an offset in Rhino saves a job I currently do in Solidworks.
Any suggestions gratefully received.

(Pascal Golay) #16

Hi Deri, I’ll take a look - hang on a bit.

Notcher.rvb (5.7 KB)

@Deri_Jones - try the one attached here - I think the one above was a mistake…

Any better?



Like a champion! That has saved me a good bit of time, very much appreciated…


WOW, this is an awesome script!! Im trying to turn it into a button for easy access. And Im in way over my head. LOL

I tried:

But what part must of the script must I paste in? Pascal or anyone. :blush: Im really a complete armature.

Also Pascal cant you please write this into a tool for grasshopper?

Script :

Option Explicit
’Script written by Pascal
’Script version Wednesday, May 01, 2013

Rhino.AddStartUpScript Rhino.LastLoadedScriptFile
Rhino.AddAlias “Notcher”, “_NoEcho _-Runscript (Notcher)”

'Cuts two intersecting panels with notches for assembly. No clearance.
'Call Notcher()
Private OldClear

If isEmpty(oldClear) Then
oldClear = 0

End If

Sub Notcher()

Dim P1, P2
Dim aP, aUsed(), n
n = 0

P1 = Rhino.GetObject("Select the first panel.", 16, True, True) 
If isNull(P1) Then Exit Sub

Dim dblClear: dblClear = Rhino.GetReal("Add clearance? Enter 0 for none.", oldClear)
If isNull(dblClear) Then Exit Sub
OldClear = dblClear

		P2 = Rhino.GetObject("Select an intersecting panel to notch. Press Enter when done.", 16, False, True) 
		If isNull(P2) Then Exit Sub
	Loop Until P1 <> P2 And Not IsStringInArray(P2, aUsed, 0)
	Rhino.SelectObject P1
	Rhino.EnableRedraw False
	aP = MakeNotch(array(P1, P2), dblClear)
	P1 = aP(1)
	ReDim Preserve aUsed(n)
	aUsed(n) = aP(0)
	n = n + 1
	Rhino.EnableRedraw True	
Loop Until IsNull(P2)

End Sub

Function MakeNotch(aPanels, dblClear)

Rhino.EnableRedraw False

Dim aInt: aInt = Rhino.IntersectBreps(aPanels(0), aPanels(1))

If Not isArray(aInt) Then
	Rhino.EnableRedraw True
	Exit Function
End If

Dim aExp: aExp = Rhino.ExplodeCurves(aInt, True, True)

Dim aLongest: aLongest = SortCurvesByLength(aExp)

If isArray(aLongest) Then
	Dim Bound: Bound = UBound(aLongest)
	If Bound < 7 Then Exit Function
		Exit Function
End If

Dim longest: longest = aLongest(bound)

Dim MidPlane: MidPlane = rhino.PlanefromNormal(Rhino.CurveMidPoint(longest), Rhino.VectorCreate(Rhino.CurveStartPoint(longest), Rhino.CurveEndPoint(longest)))

'	drawPLaneFrame aPlane, 10

Dim aBB: aBB = Rhino.BoundingBox(AExp, MidPlane)
'	Dim midPlane: midPlane = Rhino.RotatePlane(aPlane, 90, aPlane(2))

Dim aBaseCrv 
ReDim aBaseCrv(Ubound(aLongest)-4)

Dim i
Dim Xform: Xform = Rhino.XformPlanarProjection(MidPLane)
For i = 0 To Ubound(aLongest) - 4
	aBaseCrv(i) = Rhino.TransformObject(aLongest(i), Xform)

Dim sBaseCrv: sBaseCrv = Rhino.JoinCurves(aBaseCrv, True)(0)

Rhino.SimplifyCurve sbaseCrv

If dblClear <> 0 Then
	Dim aOffset: aOffset = Rhino.OffsetCurve(sbaseCrv, Rhino.PointAdd(MidPlane(0), Rhino.VectorScale(MidPlane(1), Rhino.Distance(aBB(0), aBB(6)))), dblClear, MidPlane(3))
End If

Rhino.DeleteObject sbaseCrv
sbaseCrv = aOffset(0)

Dim CutterBase:CutterBase = Rhino.AddPlanarSrf(sBaseCrv)(0)

'Dim Dist: Dist = Rhino.Distance(aBB(0), aBB(6))
'	Dim aBase: aBase = Rhino.CurveMidPoint(longest)
'aPlane(0) = abase
Dim vec1, vec2
'drawPLaneFrame aPlane, 10
midPlane(0) = Rhino.CurveMidPoint(longest)

Vec1 = Rhino.VectorScale(Rhino.VectorCreate(Rhino.CurveEndPoint(longest), MidPlane(0)), 1.25)
vec2 = Rhino.VectorReverse(Vec1)

path1 = Rhino.AddLine(MidPlane(0), Rhino.PointAdd(MidPlane(0), vec2))
path2 = Rhino.AddLine(MidPlane(0), Rhino.PointAdd(MidPlane(0), vec1))
midPlane(0) = AveragePoints(aBB)
Dim testPanel, cutter0, cutter1, Path1, path2

'	Rhino.AddPoint Rhino.PointAdd(MidPlane(0), Vec1)

If Rhino.IsPointInSurface(aPanels(0), Rhino.PointAdd(MidPlane(0), Vec1)) Then

	Cutter1 = Rhino.ExtrudeSurface(CutterBase, path2)
	Cutter0 = Rhino.ExtrudeSurface(CutterBase, path1)
	Cutter0 = Rhino.ExtrudeSurface(CutterBase, path2)
	Cutter1 = Rhino.ExtrudeSurface(CutterBase, path1)
End If
Rhino.DeleteObjects array(Cutterbase, sbaseCrv) 

Dim X, Y
X = Rhino.BooleanDifference(aPanels(1), cutter1, True)(0)
Y = Rhino.BooleanDifference(aPanels(0), cutter0, True)(0)

Rhino.DeleteObjects array(path1, path2)

MakeNotch = array(X, Y)

End Function

Function SortCurvesByLength(aCrvs)

Dim aLen, Bound
Bound = UBound(aCrvs)

ReDim aLen(Ubound(aCrvs))

Dim n
For n = 0 To Bound  
	aLen(n) = Rhino.CurveLength(aCrvs(n))

Dim aSort: aSort = rhino.SortNumbers(aLen)
Dim result, i, j
i = 0
j = 0
ReDim result(Bound)

For i = 0 To Bound
	For j = 0 To bound
		If aLen(i) = aSort(j) Then 
			result(j) = aCrvs(i)
			aSort(j) = 0
			Exit For
		End If

SortCurvesByLength = result

End Function

Public Function GetArrayDim(ByVal arr)
Dim i
If IsArray(arr) Then
For i = 1 To 60
On Error Resume Next
Call UBound(arr, i)
If Err.Number <> 0 Then
GetArrayDim = i - 1
Exit Function
End If
GetArrayDim = i
GetArrayDim = Null
End If

End Function

Function IsStringInArray(item, arr, intCase)
'Non case-sensitive= 0, case-sensitive = 1
IsStringInArray = False
If GetArrayDim(arr) = -1 Or IsEmpty(arr) Then

	Exit Function
End If

Dim sItem
If intCase = 0 Then
	For Each sItem In arr
		If LCase(sItem) = LCase(Item) Then
			IsStringInArray = True
			Exit For
		End If
	For Each sItem In arr
		If sItem = Item Then
			IsStringInArray = True
			Exit For
		End If
End If

End Function

Function AveragePoints(aPts)
'Finds the average coordinates of an array
’of points.

Dim X, Y, Z
Dim i

X = 0
Y = 0
Z = 0

For i=0 To UBound(aPts)
	'add all the X values
	X = X + aPts(i)(0)

	'add all th Y values
	Y = Y + aPts(i)(1)			

	'add all the Z values
	Z = Z + apts(i)(2)

'Divide by the number of points to
'get the average  for each
'create the output array from the 3 averages
AveragePoints = array(X / (UBound(aPts) + 1), Y / (UBound(aPts) + 1), Z / (UBound(aPts) + 1))

End Function

(Pascal Golay) #19

Hi Sean - if you have drag-and-dropped the rvb file onto Rhino, then you just need to type in


at the command line and the script will run. You can put that on a button as well.

Does that work?



Hi Pascal. I loaded it straight away. And have been using it. I want to make a button for it to add to my toolbar, that way I won’t forget about it and also Ill use it much more.

Only thing is I don’t really know how to make a button from a script.

Ive made my own toolbars but not a button before. I’ve drawn out a little bitmap and all for the notch button. . . but when I add the “full script” in the edit toolbar button, well I dont know what part of the script to copy and paste in there.

According to

Must I copy and paste everything or cutout bits like :

** Option Explicit**
’Script written by Pascal
’Script version Wednesday, May 01, 2013

I dont even know if its a python script or not. Would be cool to have a button. . Thanks for your script!