There is no Inset function in rhinoscriptsyntax. It doesn’t provide direct methods for insetting faces or insetting a Brep. Most of the functions there are wrappers around RhinoCommon, and this one simply isn’t exposed.
There is no direct Inset method like InsetFace or InsetFaces in RhinoCommon either.
This is a very useful tool, should be available for scripting. Thank you!
I asked ChatGPT to create a grasshopper component for the InsetFaces method.
It takes surfaces or polysurfaces and a list of distances.
Returns the border faces as polysurfaces, Inner faces as surfaces and also the surfaces which couldn’t be inset.
"""Inset faces with optional per-face distances (optimized).
Inputs:
G: Breps (surface or polysurface)
D: distance or list of distances (set D to list access for per-face values)
C: creaseCorners (True/False)
Outputs:
BorderFaces - joined border ring per face
InnerFaces - inner inset faces
NoInset - original faces for which inset failed
"""
import Rhino
import scriptcontext as sc
# Normalize G to list
if G is None:
G_list = []
elif isinstance(G, (list, tuple)):
G_list = list(G)
else:
G_list = [G]
# Normalize D to list of floats
def to_float_list(x):
if x is None:
return []
try:
it = iter(x)
if isinstance(x, (str, bytes)):
return [float(x)]
return [float(v) for v in it]
except TypeError:
return [float(x)]
D_list = to_float_list(D)
BorderFaces = []
InnerFaces = []
NoInset = []
tol = sc.doc.ModelAbsoluteTolerance
angle_tol = sc.doc.ModelAngleToleranceRadians
for g in G_list:
if g is None or not isinstance(g, Rhino.Geometry.Brep):
continue
face_count = g.Faces.Count
if face_count == 0 or not D_list:
continue
# Per-face distance: reuse last value if fewer distances than faces
per_face_dist = [D_list[min(i, len(D_list) - 1)] for i in range(face_count)]
for i in range(face_count):
dist = per_face_dist[i]
face = g.Faces[i]
# Original face (for fallback)
original_face_brep = face.DuplicateFace(True)
# Build single-face brep
face_brep = face.DuplicateFace(True)
if not face_brep:
if original_face_brep:
NoInset.append(original_face_brep)
continue
# Attempt inset
inset = face_brep.InsetFaces(
[0], # only face in this brep
dist,
False, # loose
False, # ignoreSeams
C, # creaseCorners
tol,
angle_tol
)
# If inset failed → report original face
if not inset or inset.Faces.Count == 0:
if original_face_brep:
NoInset.append(original_face_brep)
continue
# ----------------------------------------
# Find inner face by topology:
# inner = face with NO boundary edges
# (all its edges are shared by 2+ faces)
# ----------------------------------------
inner_index = -1
for fi in range(inset.Faces.Count):
f = inset.Faces[fi]
edge_indices = f.AdjacentEdges()
is_inner = True
for ei in edge_indices:
edge = inset.Edges[ei]
# boundary edge if only one adjacent face
if len(edge.AdjacentFaces()) <= 1:
is_inner = False
break
if is_inner:
inner_index = fi
break
if inner_index < 0:
# no clear inner face → treat as fail
if original_face_brep:
NoInset.append(original_face_brep)
continue
# Inner face
inner_face_brep = inset.Faces[inner_index].DuplicateFace(True)
if inner_face_brep:
InnerFaces.append(inner_face_brep)
else:
if original_face_brep:
NoInset.append(original_face_brep)
continue
# Border ring = all other faces, joined
border_parts = []
for fi in range(inset.Faces.Count):
if fi == inner_index:
continue
bf = inset.Faces[fi].DuplicateFace(True)
if bf:
border_parts.append(bf)
if border_parts:
joined = Rhino.Geometry.Brep.JoinBreps(border_parts, tol)
if joined and len(joined) > 0:
BorderFaces.append(joined[0])
else:
# fallback: individual pieces
BorderFaces.extend(border_parts)
else:
# no border faces? treat as fail
if original_face_brep:
NoInset.append(original_face_brep)
@dale is it posssible for InsetFaces to return the inner face of the inset at index zero?
I thought it was already the case but in some tests it was not.
Thanks!