Splitting a surface using rhinoscript and deleting upper surface

Hi,

I am trying to automate a ship hull mesh generation. For this I need to import an IGES file, split it using a plane (xy plane representing water surface), delete the above water surface and keep the under water surface. Then I need to generate a mesh for the under water surface.

I have been able to do following so far:

  1. Importing an IGES file
  2. Creating a plane in xy-plane

Now, I don’t know how can I split the surface in to two. I tried using Rhino. SplitBrep command, but I am unable to provide the required surface and cut plane as a string. Can someone help me with this. Am I in the right direction.

Also, when I import a new model, Rhino asks whether to save the current file or not with a popup dialog box which required manual intervention. For automation, I need this to be handled through the script. How do I do that?

Attaching the IGES file and the code below (Althouh you won’t be able to run the code without manually setting few parameters, e.g. Length, breadth). Thank you for your help.

Function generatePanel()
' Start a new model,
Rhino.Command "-_New n"

'Set document properties
Rhino.Command "-_DocumentProperties u u e n _enter _enter"

'Import IGES file
Dim igesPath
igesPath = "C:\Data\Model.igs"
Rhino.Command "-_Import " & chr(34) & igesPath & chr(34)
Rhino.Command "-_Join"

'Store the surface
Rhino.UnselectAllObjects
Rhino.Command "-_SelPolySrf"
Rhino.Command "-_SelSrf"
Dim surface: surface = Rhino.SelectedObjects

Rhino.UnselectAllObjects

'----------------------------------------------------
'Create water surface panel to split vessel
'----------------------------------------------------
Dim Length : Length = objHull.Item("LengthOnDeck")
Dim	Breadth : Breadth = objHull.Item("BeamOnDeck")


Dim arrOrigin: arrOrigin = Array(-Length, -Breadth, 0)
Dim arrPointX: arrPointX = Array(Length, -Breadth, 0)
Dim arrPointY : arrPointY = Array(Length, Breadth, 0)
Dim arrPlane: arrPlane = Rhino.PlaneFromPoints(arrOrigin, arrPointX, arrPointY)

Dim cutPlane
cutPlane = Rhino.AddPlaneSurface(arrPlane, 2 * Length, 2 * Breadth)

'------------------------------------------------------
'Delete above water hull surface
'------------------------------------------------------
Rhino.UnselectAllObjects

Rhino.SplitBrep surface, cutPlane
Rhino.GetReal("Wait")
'Rhino.Command "-_Split cutPlane "
End Function

Model.igs (36.5 KB)

Well, just a couple of things offhand… this is not all that simple of an operation.

First, the reason you can’t manage with SplitBrep is that it will only split a single Brep (surface or polysurface) at a time, and you are trying to pass an array of all the imported objects.

As IGES does not have any join information, everything comes in as separate surfaces. You probably cannot risk trying to join them up into one object, that will likely fail. So, I would develop a loop that takes each surface and splits it at the waterline, then discards the part above the waterline plane.

To make sure you have a plane big enough to use for splitting, I might try getting their bounding box and make a plane somewhat bigger than that.

Then, run your loop, use SplitBRep to split each surface with the plane. The hardest part is to detect which part to delete from the result of the split. There you would need to get some point on each of the objects and look at the Z coordinate. If it’s positive, it’s above the waterline, so delete it.

Another possibility is to just use Rhino.Command("_Split). That will permit you to split all the imported objects in one go without having to loop. You still need to grab all the resulting parts and figure out which ones to delete as above afterwards.

There are probably other ways to go about this, but that’s my initial logic on how to set this up.

–Mitch

Thank you Mitch. I like the idea of looping for each surface and splitting them using the cut plane. In this way I will ensure all Poly Surfaces and Surfaces both gets splited and I don’t have to join the surfaces.

The cutting plane, I have generated is parametric and will definitely cover the whole ship hull.

At this point, I am however looking for a solution to a simpler question. How do I select the surfaces and store them in a variable array? All the examples I am looking online assumes selecting a surface by clicking as shown below.

 Dim srf : srf = Rhino.GetObject("Select surface", 8, vbTrue)

Can you help me with the script for selecting surfaces from imported iges file and storing them in a variable.

Well, just very quickly… Immediately after you import in the script, if you do the following:

arrObjs=Rhino.LastCreatedObjects()

In theory, all the imported objects will be contained in the array arrObjs…

–Mitch

Thank you Mitch. It worked. Posting my function for generating panel from IGES file using Rhinoscript below.

I wish I knew a better way to call the -_Mesh function, by setting all advanced options as string instead of using keyboard shortcuts like -_Mesh d a a ... etc. Please let me know if there is another way to do that.

Thank you again for your help.

	Function generatePanel()
	
	'-----------------------------------------------------
	'Generate a new model
	'-----------------------------------------------------
	' Start a new model,
	'Rhino.Command "-_New n"
	
	'Set document properties
	'Rhino.Command "-_DocumentProperties u u e n _enter _enter"
	'------------------------------------------------------
	
	
	'------------------------------------------------------
	'Delete everything from workspace
	'------------------------------------------------------
	Call DeleteModelGeometry()
	'------------------------------------------------------
	
	
	'------------------------------------------------------
	'Import IGES file
	'------------------------------------------------------
	Dim igesPath
	igesPath = "C:\Data\Model.igs"
	Rhino.Command "-_Import " & chr(34) & igesPath & chr(34)
	Dim arrHullSrf: arrHullSrf = Rhino.LastCreatedObjects()
	
	'Rhino.GetString("Press any key")
	
	'----------------------------------------------------
	'Create water surface panel to split vessel
	'----------------------------------------------------
	Dim Length : Length = objHull.Item("LengthOnDeck")
	Dim	Breadth : Breadth = objHull.Item("BeamOnDeck")
	

	Dim arrOrigin: arrOrigin = Array(-Length, -Breadth, 0)
	Dim arrPointX: arrPointX = Array(Length, -Breadth, 0)
	Dim arrPointY : arrPointY = Array(Length, Breadth, 0)
	Dim arrPlane: arrPlane = Rhino.PlaneFromPoints(arrOrigin, arrPointX, arrPointY)
	
	Dim cutPlane
	cutPlane = Rhino.AddPlaneSurface(arrPlane, 2 * Length, 2 * Breadth)
	
	'------------------------------------------------------
	'Splitting hull surface
	'------------------------------------------------------
	Rhino.UnselectAllObjects
	
	Dim srfID 'Index for all hull surfaces imported
	
	For Each srfID In arrHullSrf

		'Splitting surface with cutPlane
		Rhino.UnselectAllObjects
		Rhino.SelectObject srfID
		Rhino.Command "-_Split _SelID " & cutPlane & " _enter"

	Next
	Rhino.DeleteObject(cutPlane)
	Rhino.UnselectAllObjects
	
	'---------------------------------------------------
	'Deleting above water hull
	'---------------------------------------------------
	Dim splitSrfID,arrPt,Pt
	
	Rhino.Command "-_SelSrf"
	Rhino.Command "-_SelPolySrf"
	
	
	Dim splitSrf: splitSrf = Rhino.SelectedObjects()
	
	
	For Each splitSrfID In splitSrf
		
		Rhino.UnselectAllObjects
		Rhino.SelectObject splitSrfID
		
		'Creating a point at the centroid of the surface
		arrPt = Rhino.SurfaceAreaCentroid(splitSrfID)
		Pt = arrPt(0)
		'Rhino.AddPoint(Pt)
		
		'Deleting surface of its centroid is above water (Z >=0)
		If Pt(2) >= 0 Then
			Rhino.DeleteObject(splitSrfID)
		End If
		'Rhino.GetString("Press any key")
	Next
	Rhino.UnselectAllObjects
	
	'---------------------------------------------------
	'Paneling under water surfaces
	'---------------------------------------------------
	'Setting mesh parameters
	Dim Angle: Angle = 0
	Dim AspectRatio: AspectRatio = 50
	Dim Distance: Distance = 0
	Dim Density: Density = 0.5
	Dim Grid: Grid = 0
	Dim MaxEdgeLength: MaxEdgeLength = 0.5
	Dim MinEdgeLength: MinEdgeLength = 0.25
	
	
	Rhino.Command "-_SelSrf"
	Rhino.Command "-_SelPolySrf"
	
	Dim uwSrf: uwSrf = Rhino.SelectedObjects()
	
	Dim uwSrfID
		
	For Each uwSrfID In uwSrf
		Rhino.UnselectAllObjects
		Rhino.SelectObject uwSrfID
		
		Rhino.Command "-_Mesh d a " + _
			"a " + CStr(Angle) + " " +_
			"s " + Cstr(AspectRatio) + " " + _
			"d " + CStr(Distance) + " " + _
			"e " + CStr(Density) + " " + _
			"g " + CStr(Grid) + " " + _
			"m " + Cstr(MaxEdgeLength) + " " + _
			"i " + CStr(MinEdgeLength) + " _enter _enter"
		 
		'Rhino.GetString("Press any key")
	Next
	Rhino.UnselectAllObjects
	
	
	'---------------------------------------------------
	'Saving mesh as GDF file
	'---------------------------------------------------	
	Dim gdfPath
	gdfPath = "C:\Data\Model.gdf"
	
	Rhino.Command "-_SelMesh"
	
	Dim uwMesh: uwMesh = Rhino.SelectedObjects()
	
	Rhino.Command "_-Export " & chr(34) & gdfPath & chr(34) & " _enter"

End Function

Sub SelectModelGeometry()
	' Select all surface, polysurface And mesh objects
	Rhino.Command "-_SelSrf"
	Rhino.Command "-_SelPolySrf"
	Rhino.Command "-_SelMesh"
End Sub

Sub DeleteModelGeometry()
	Rhino.Command "-_SelAll"
	Rhino.Command "-_Delete"
End Sub

You can collect all your parameters into a string and feed that to Rhino.Command. It’s easy to keep track of and more readable if you do that in a secondary function. You need to set up your string so that it corresponds with the order in which the parameters are asked for on the command line when running the dash version of the Mesh command. Example below:

Option Explicit
Call TestMeshObjWParams()
Sub TestMeshObjWParams()
    Dim obj
    obj = Rhino.GetObject("Select object to mesh", 8 + 16, True, True)
    If IsNull(obj) Then Exit Sub
    Call Rhino.Command("_-Mesh " & MeshParamString() & "_Enter _Enter", True)
End Sub

Function MeshParamString()
    Dim params
    params = "_DetailedOptions "
    params = params & "_JaggedSeams=_No "
    params = params & "_PackTextures=_No "
    params = params & "_Refine=_Yes "
    params = params & "_SimplePlane=_Yes "
    params = params & "_AdvancedOptions "
    params = params & "_Angle=15 "
    params = params & "_AspectRatio=0 "
    params = params & "_Distance=0.01 "
    params = params & "_Grid=16 "
    params = params & "_MaxEdgeLength=0 "
    params = params & "_MinEdgeLength=0.0001 "
    MeshParamString = params
End Function

Hi Helvetosaur,

I have a similar question:
I have multiple surfaces each one in a different layer, I want to split each surface with each other but retain the original layers the resulting pieces belong to, what is the neatest way to do this?

As you are saying the rs.splitbrep works only with two surfaces at the time, I was trying to select each surface and use rhino command with selection all the others but I don’t think my sintax is correct, also I am duplicationg surfaces

 allfaces = []

for i in range(0,len(allcubes)):
    for j in range(0,len(allcubes[i])):
        allfaces.append(rs.CopyObject(allcubes[i][j],[0,0,0]))
        

for i in range(0,len(allcubes)):
    for j in range(0,len(allcubes[i])):
        rs.SelectObject(allcubes[i][j])
        rs.Command("split")
        rs.SelectObjects(allfaces)
        rs.UnselectAllObjects()