Split surface and select surface which has biggest area

Hi everyone!

I am trying to write script which split surface and select surface which has biggest area from splitted surfaces.
Script is following.
But I get error message “‘NoneType’ object is not subscriptable”
Could anyone give me some advice why I am getting this message and how to solve the problem?

splitted=rs.SplitBrep(surface,Obj,False)
base=splitted[0]
baseArea=rs.SurfaceArea(base)[0]
for sur in splitted:
	area=rs.SurfaceArea(sur)[0]
	if area < baseArea:
		rs.DeleteObject(sur)
	else:
		rs.DeleteObject(base)
		baseArea=area	

Thank you in advance.
Katsuya

Perhaps in

rs.SplitBrep() is not returning anything for some reason. I don’t see a check for valid results in splitted in your code.

1 Like

yeah, if i try:

import rhinoscriptsyntax as rs

surface = rs.GetSurfaceObject('select surface')
cutter = rs.GetCurveObject('select curve')

split = rs.SplitBrep(surface, cutter)

…i get this error message:

rs.SplitBrep() wants another Brep (surface or polysurface) as a cutter, not a curve.

If you want to split a Brep with a curve, you’ll either need to script rs.Command("Split") or dive into RhinoCommon and use Rhino.Geometry.BrepFace.SplitBrep([curves],tolerance). Otherwise, you could turn your curve into a surface (by extruding it or something) and use the surface as the cutter in rs.SplitBrep().

–Mitch

2 Likes

how can i use it in:

import rhinoscriptsyntax as rs

surface = rs.GetObject('select surface')
cutter = rs.GetObjects('select curves')

Yes, it gets a bit complicated quickly…

import rhinoscriptsyntax as rs
import scriptcontext as sc
import Rhino

surface_id = rs.GetObject('select surface',8)
cutter_ids = rs.GetObjects('select curves',4)
tol=sc.doc.ModelAbsoluteTolerance

#get the Rhinocommon Brep geometry from the surface object ID
brep=rs.coercebrep(surface_id)
#get all the Rhinocommon curve geometries with a list comprehension
cut_crvs=[rs.coercecurve(cutter_id) for cutter_id in cutter_ids]

#as it is a single surface, you can get the brep's face list and use index 0
# - the brep only has one face...
face=brep.Faces[0]
split_brep=face.Split(cut_crvs,tol)
#if something happened, split_brep will be a joined polysurface
#To have separate surfaces, you need to 'explode' the brep by duplicating all faces
for split_face in split_brep.Faces:
    new_brep=split_face.DuplicateFace(True)
    #add the duplicate face (brep) to the document
    sc.doc.Objects.AddBrep(new_brep)
#redraw the scene
sc.doc.Views.Redraw()

Thank you for this example… I will explore it and I hope understand a part of the gate between rhinoscriptsyntax and rhinocomon…
I don’t know how many methods there is in rhino comon, how can you remember all, do you search every time in the documentation?

with this line you add new breps in Rhino, without, there is no change, but where, in this line, it delete the original surface?

excuse me, but i have another example, and maybe you can explain to me…
in this example:

from Rhino import *
from Rhino.Geometry import *
from Rhino.DocObjects import *
from Rhino.Commands import *
from Rhino.Input import *
from Rhino.Input.Custom import *
from scriptcontext import doc

def RunCommand():

  rc, boundary_obj_refs = RhinoGet.GetMultipleObjects("Select boundary objects", False, ObjectType.AnyObject)
  if rc <> Result.Success:
    return rc
  if boundary_obj_refs == None or boundary_obj_refs.Length == 0:
    return Result.Nothing

  gc = GetObject()
  gc.SetCommandPrompt("Select curve to extend")
  gc.GeometryFilter = ObjectType.Curve
  gc.GeometryAttributeFilter = GeometryAttributeFilter.OpenCurve
  gc.Get()
  if gc.CommandResult() <> Result.Success:
    return gc.CommandResult()
  curve_obj_ref = gc.Object(0)

  curve = curve_obj_ref.Curve()
  if curve == None: return Result.Failure
  b, t = curve.ClosestPoint(curve_obj_ref.SelectionPoint())
  if not b: return Result.Failure
  curve_end = CurveEnd.Start if t <= curve.Domain.Mid else CurveEnd.End

  geometry = [obj.Geometry() for obj in boundary_obj_refs]
  extended_curve = curve.Extend(curve_end, CurveExtensionStyle.Line, geometry)
  if extended_curve <> None and extended_curve.IsValid:
    if not doc.Objects.Replace(curve_obj_ref.ObjectId, extended_curve):
      return Result.Failure
    doc.Views.Redraw()
    return Result.Success
  else:
    RhinoApp.WriteLine("No boundary object was intersected so curve not extended")
    return Result.Nothing

if __name__ == "__main__":
  RunCommand()

there is a line:

extended_curve = curve.Extend(curve_end, CurveExtensionStyle.Line, geometry)

it ask curve_end

I found curve_end = CurveEnd.Start if t <= curve.Domain.Mid else CurveEnd.End that determine curve_end,

but where is the connexion with the curve = curve_obj_ref.Curve()

There are literally thousands. A number of the most common I know because I use them frequently, the others I search for. The RhinoCommon API documentation is sparser and different than the rhinoscriptsyntax, it is aimed at programmers with a certain experience, it also takes some time to know how to read and understand it.

If I think there is a method that might exist, for example for a brep, I start by opening the Rhino.Geometry.Brep class documentations and start looking for a property or method. If you have an idea of the name or part of it, you can also use the search box, but I find that it doesn’t always work that well, it doesn’t find a lot of partial matches.

Correct. RhinoCommon created geometry is virtual until you specifically add it to the document. Scriptcontext is the bridge between RhinoCommon and the active document that allows you to do this.

It doesn’t. To delete the original, you need to do that in another line. You have the object ID because the original was gotten from the document, so you can simply use rs.DeleteObject(obj_id), or, the RhinoCommon equivalent would be sc.doc.Objects.Delete(obj_id,True) - which calls this method:

https://developer.rhino3d.com/api/RhinoCommon/html/M_Rhino_DocObjects_Tables_ObjectTable_Delete_5.htm

excuse me i was thinking it does!

i hope you saw the the post i made durind you were replying…

Yes.

The problem is again that to choose the object, instead of using one of the standard rhinoscriptsyntax methods that always return a GUID, the user interaction is done with RhinoCommon GetObject(). The various RhinoCommon methods GetObject() do not return an object ID directly, rather they return an ‘object reference’ (hence the name …obj_ref). An object reference has properties and methods (like all other RhinoCommon classes), so the object ID can be gotten from the object reference via the property ObjRef.ObjectId; plus the actual geometry extracted via one of the ObjRef methods such as ObjRef.Curve, or more generically ObjRef.Geometry.

https://developer.rhino3d.com/api/RhinoCommon/html/T_Rhino_DocObjects_ObjRef.htm

ARGGGGG!! it’s really crazy!!
i don’t understand! in fact i want to use ExtendOnSurface, so i write this code:

import rhinoscriptsyntax as rs
import Rhino


def Plan(surf):
    Usurfdomain=rs.SurfaceDomain(surf,0)
    Vsurfdomain=rs.SurfaceDomain(surf,1)
    u=(Usurfdomain[0]+Usurfdomain[1])/2
    v=(Vsurfdomain[0]+Vsurfdomain[1])/2
    eval=rs.EvaluateSurface(surf,u,v)
    vect=rs.SurfaceNormal(surf,[u,v])
    plan=rs.PlaneFromNormal(eval,vect)
    return plan
    
    
surf1=rs.GetSurfaceObject('surface 1')
surf2=rs.GetSurfaceObject('surface 2')
inter=rs.PlanePlaneIntersection(Plan(surf1[0]),Plan(surf2[0]))
line=rs.AddLine(inter[0],inter[1])
line=rs.coercecurve(line)
brepFace=rs.coercebrep(surf2[0])

line.ExtendOnSurface(?????????, brepFace.Faces[0])

but i don’t know how i can return the extremity of the line…

if i didn’t use a rhinoCommon GetObjects() i can’t return an end or strat???

you need to enter one of these:

Rhino.Geometry.CurveEnd.Start
Rhino.Geometry.CurveEnd.End
Rhino.Geometry.CurveEnd.Both

Have you checked this?
https://developer.rhino3d.com/api/RhinoCommon/html/T_Rhino_Geometry_CurveEnd.htm

yes i was on it!

so now, it’s that:

newline=line.ExtendOnSurface(Rhino.Geometry.CurveEnd.Both, brepFace.Faces[0])

it return a curve, so I write:

split_brep=brepFace.Split(newline,0.001)

and the message is: Message: expected IEnumerable[Curve], got PolyCurve

You need to import System.Collections.Generic:

from System.Collections.Generic import *

and then:

curves = List[Rhino.Geometry.Curve]([curve.ToNurbsCurve()])
split_brep = brep_face.Split(curves, doc.ModelAbsoluteTolerance)

Not sure that’s necessary in this case as he has a polycurve. BrepFace.Split() wants a list of curves is all, not a single curve, so it should be enough to do the following (I think):

split_brep=brepFace.Split([newline],0.001)
1 Like

return this message:
Message: Multiple targets could match: Split(IEnumerable[Curve], float), Split(IEnumerable[Brep], float)

Yeah, I was afraid you would run into that - I tested it here and the simple making of a list worked on my example but I guess yours is different. Why this happens is a bit difficult to explain, but I’ll try with my limited knowledge…

The problem is what we call ‘overloads’ on certain RhinoCommon functions. Overloaded functions are designed in such a way as to be able to take multiple types of inputs, and they rely on being able to easily distinguish between the different possible inputs to execute the function correctly. If the functions are written well, this does not cause any problems and adds some flexibility. However, in this case, the functions are badly conceived (IMO), and they get confused - so you get the error message that it doesn’t know how to distinguish between a list of curves and a list of breps. As an aside I think this is a bad way to do things, IMO if this kind of confusion is possible, the functions should be separated into something like BrepFace.SplitWithCurve() and BrepFace.SplitWithBrep() etc… so that there is no more confusion possible.

The solution then is as @Mahdiyar posted above, you specifically need to define your list as a list of curves before sending it to the BrepFace.Split method, so that it knows that these are indeed curves. It’s painful, but that is the current state of affairs.

Edit:
There are several ways to do this, the one posted above, but also something like the following:

from System.Collections.Generic import IEnumerable

#...

splits=brep.Split.Overloads[IEnumerable[Rhino.Geometry.Curve],System.Double]([crv], tol)

Again, I find this positively painful, it would be nice if this kind of problem could be avoided by dis-overloading certain problematic methods.

Edit 2:
I maybe should add that this is perhaps only a problem with python as it is a weakly typed language - other languages may be able to infer the type of objects in the list because the list is created/efined as a list of curves for example… Maybe I didn’t get that right though…

1 Like

thank you so much for your time, but i search, and i don’t understand all this part… i think this philosophy is too complicate for me now, i hope i will understand that one day…
i’ll continu to use rs.command () to split what i need…