Have a look at the file in attachment. When I use the UnrollSrf command I get a flat polysurface with smooth edges. When I use RhinoCommons UnrollSurface I get a surface with ugly jaggered edges. How can I achieve the result from the UnrollSrf command using Rhinocommon?
it uses the Absolute tolerance of your document which is 0.1 millimeters. You can either lower it under Document Properties > Units or set it in the function call:
import rhinoscriptsyntax as rs
obj_id = rs.GetObject("Surface to unroll", 8, True, False)
if obj_id:
rc = rs.UnrollSurface(obj_id, False, None, 0.00001)
Hi @clement. Can you specify what uses Absolute tolerance?
When I use the document tolerance (0.1 mm) for rs.UnrollSurface I get the same crappy result with deviations of 1-1.5 mm and UnrollSurface command take the document units automatically and I get a smooth result? Why does this differ so much?
import rhinoscriptsyntax as rs
obj = rs.GetObject()
tol = rs.UnitAbsoluteTolerance()
rs.UnrollSurface(obj,False,None,tol)
It also like the UnrollSrf command creates a polysurface. How does one achieve that with rs.UnrollSurface?
Hi @siemen, my guess is that the _UnrollSrf command either does some tolerance reduction on itâs own and since itâs not merging the results as rs.UnrollSurface does, itâs outcome looks better. Probably the wobble you see is caused by the merging, iâm not sure.
@dale, can you look at this and explain why the results are wobbly, even with tight tolerances ?
It seems that the _UnrollSrf command has more going on behind the scenes.
This code produces the same results as the _UnrollSrf command. (Note: Iâm using a GhPython component in grasshopper)
# input x type hint set to Brep
import Rhino
doc = Rhino.RhinoDoc.ActiveDoc
x.Faces.SplitFacesAtTangents()
for face in x.Faces:
face.ShrinkFace(Rhino.Geometry.BrepFace.ShrinkDisableSide.ShrinkAllSides)
unroll = Rhino.Geometry.Unroller(x)
unroll.AbsoluteTolerance = doc.ModelAbsoluteTolerance
unroll.RelativeTolerance = doc.ModelRelativeTolerance
breps, curves, points, dots = unroll.PerformUnroll()
a = Rhino.Geometry.Brep.JoinBreps(breps, doc.ModelAbsoluteTolerance)
unroll_srf.gh (9.9 KB - Your geometry is internalized in this file)
I reused your code to make it work outside of Grasshopper as below (a bit of a quick fix, I know). But Iâm still getting issues with unrolling which the UnrollSrf command doesnât get. See the example part I have below. Would be great if somebody from McNeel could help out here. @dale
import Rhino
import rhinoscriptsyntax as rs
obj = rs.GetObject()
brep = rs.coercebrep(obj)
brep.Faces.SplitFacesAtTangents()
for face in brep.Faces:
face.ShrinkFace(Rhino.Geometry.BrepFace.ShrinkDisableSide.ShrinkAllSides)
unroll = Rhino.Geometry.Unroller(brep)
unroll.AbsoluteTolerance = Rhino.RhinoDoc.ActiveDoc.ModelAbsoluteTolerance
unroll.RelativeTolerance = Rhino.RhinoDoc.ActiveDoc.ModelRelativeTolerance
breps, curves, points, dots = unroll.PerformUnroll()
a = Rhino.Geometry.Brep.JoinBreps(breps, Rhino.RhinoDoc.ActiveDoc.ModelAbsoluteTolerance)
for i in a:
Rhino.RhinoDoc.ActiveDoc.Objects.AddBrep(i)
rs.Redraw()
Iâve tried a couple of things and made some observations.
Your original surface has an area of 4830641.3, whereas the unrolled, green one has 4831059.05 and the red one 4831058.85, which means that both procedures actually donât unroll your surface super faithfully. I guess the unrolling of surfaces with non-zero Gaussian curvature is always somewhat of a guessing game, since they are not really developable in the traditional sense.
Furthermore, since youâre dealing with a doubly-curved surface, whose Gaussian curvature is not 0 and it thus is not developable, you probably shouldnât use UnrollSrf.
It used to be exclusively for developable surfaces, which might be why Smash seems to get called in the background by the Rhino.Geometry.Unroller(). It must detect that youâre dealing with an unrollable surface and chose to well smash it instead?
Simply try Smash in Rhino. It yields the same result as your unrolled, red surface.
Instead of Smash, you could use the more modern Squish command, which is also available for scripting in the API.
It will always remain somewhat of a guessing game and playing around with tolerances though, unless you come up with some sort of algorithm that does that for you and searches for an optimal result by for instance area. Squish wants to stretch and/or compress your surface to make it unrollable. Itâs a matter of finding the right settings and tolerance for the least deviation in area.
Thanks a lot for your findings & insights @diff-arch
I realize that unrolling a surface with curvature in both directions creates something which is impossible to flatten without knowing the technical properties of the material it will be made of.
My tool copies the UnrollSurface command and adds some automation features to it. So Iâd like it to copy what the UnrollSurface command does. Would be great if anybody could provide an example of how this is set up. Or at least an answer from McNeel that this is not possible so I know Iâm not trying to do something that wonât work in RhinoCommon? @dale@pascal
import Rhino
import scriptcontext as sc
def test_unroller():
filter = Rhino.DocObjects.ObjectType.Surface | Rhino.DocObjects.ObjectType.PolysrfFilter
rc, objref = Rhino.Input.RhinoGet.GetOneObject("Select surface or polysurface to unroll", False, filter)
if not objref or rc != Rhino.Commands.Result.Success:
return
brep = objref.Brep()
if not brep:
return
bcopy = brep.DuplicateBrep()
bcopy.Compact()
bcopy.Faces.SplitFacesAtTangents()
for f in bcopy.Faces:
f.RebuildEdges(0.00001, True, True)
for f in bcopy.Faces:
f.ShrinkFace(Rhino.Geometry.BrepFace.ShrinkDisableSide.ShrinkAllSides)
bcopy.CullUnusedSurfaces()
for f in bcopy.Faces:
if f.OrientationIsReversed:
f.UnderlyingSurface().Reverse(1)
unroll = Rhino.Geometry.Unroller(bcopy)
unroll.AbsoluteTolerance = sc.doc.ModelAbsoluteTolerance
unroll.RelativeTolerance = 0.01
out_breps, curves, points, dots = unroll.PerformUnroll()
if out_breps:
for b in out_breps:
sc.doc.Objects.AddBrep(b)
sc.doc.Views.Redraw()
if __name__=="__main__":
test_unroller()
Why do you create a duplicate here to then shrink the faces of the original while you use the duplicate for the unroller? Is that duplicate still linked to the original somehow?
for f in bcopy.Faces:
f.RebuildEdges(0.00001, True, True)
Is there a reason why you used a hard coded value as a tolerance here instead of document tolerance?
Hi again @dale, running into another discrepancy between the UnrollSrf command and rhinocommon implementation. Could you share some insights in the joining process after unrolling as used by the UnrollSrf command?
When I use the JoinBrep method from RhinoCommon with the tolerance used in the RhinoScriptSyntax implementation, as I got explained by Willem in this topic, it doesnât join 1 part of the unrolled surface whereas UnrollSrf returns one single polysurface. I tried on this file using the code below:
import Rhino
import scriptcontext as sc
def test_unroller():
filter = Rhino.DocObjects.ObjectType.Surface | Rhino.DocObjects.ObjectType.PolysrfFilter
rc, objref = Rhino.Input.RhinoGet.GetOneObject("Select surface or polysurface to unroll", False, filter)
if not objref or rc != Rhino.Commands.Result.Success:
return
brep = objref.Brep()
if not brep:
return
bcopy = brep.DuplicateBrep()
bcopy.Compact()
bcopy.Faces.SplitFacesAtTangents()
for f in bcopy.Faces:
f.RebuildEdges(0.00001, True, True)
for f in bcopy.Faces:
f.ShrinkFace(Rhino.Geometry.BrepFace.ShrinkDisableSide.ShrinkAllSides)
bcopy.CullUnusedSurfaces()
for f in bcopy.Faces:
if f.OrientationIsReversed:
f.UnderlyingSurface().Reverse(1)
unroll = Rhino.Geometry.Unroller(bcopy)
unroll.AbsoluteTolerance = sc.doc.ModelAbsoluteTolerance
unroll.RelativeTolerance = 0.01
out_breps, curves, points, dots = unroll.PerformUnroll()
if out_breps:
joinBrep = Rhino.Geometry.Brep.JoinBreps(out_breps,sc.doc.ModelAbsoluteTolerance*2.1)
if joinBrep:
for b in joinBrep:
sc.doc.Objects.AddBrep(b)
sc.doc.Views.Redraw()
if __name__=="__main__":
test_unroller()
if out_breps:
joined_brep = Rhino.Geometry.Brep()
for b in out_breps:
joined_brep.Append(b)
joined_brep.JoinNakedEdges(0.0)
sc.doc.Objects.AddBrep(joined_brep)
sc.doc.Views.Redraw()