Curve offset: Rhino vs Python


#1

Hi all,

I’ve been staring at a script that gives me offset curves on both sides of closed polylines, but just cannot get this to work reliably. It’s based on Mitch’s script (thanks for sharing, Mitch!) from

https://discourse.mcneel.com/t/both-sides-offset-using-ironpython/27792/2

which I simplified a little bit, and added some debug output:

test_OffsetMulticrvs2SidesWEnds.py (2.2 KB)

So I have this Rhino model:

crv_offset.3dm (68.5 KB)

where the troublesome polyline is the red one. Running the script fails to offset. It only produces the 4 small segments, rather than 2 closed polylines.

When I run Explode, Join and SimplifyCrv in Rhino (green polyline), the script works. Automating this with the following RS script:

test_RebuildPlines.py (1.4 KB)

will create a nice, rebuilt pline, but again the offset script does not work.

Please note that offsetting in Rhino works in all 3 cases. Here are the object information, as output by List:

a) original polyline:

Rhino object: curve
DEVELOPER DEBUGGING INFORMATION ONLY
Use the Rhino “What” command.
name: ""
id: B7F52D60-21DE-4d55-847B-749991FBE76A
layer index: 5
render material index: -1 (from layer)
ON_PolyCurve segment count = 11
Segment 1: (63.8746,65.2746)
ON_NurbsCurve dim = 3 is_rat = 0
order = 2 cv_count = 2
Knot Vector ( 2 knots )
index value mult delta
0 63.87464931716093 1
1 65.274613352306119 1 1.4
Control Points 2 non-rational points
index value
CV[ 0] (-13.061572574683822, 11.05095200562722, 11.524653923406049)
CV[ 1] (-13.202995391701705, 12.443754535246295, 11.524653923406049)
Segment 2: (65.2746,70.2407) gap = 0
ON_NurbsCurve dim = 3 is_rat = 0
order = 2 cv_count = 2
Knot Vector ( 2 knots )
index value mult delta
0 65.274613352306119 1
1 70.240710811506062 1 4.966

b) re-built with RS script:

Rhino object: curve
DEVELOPER DEBUGGING INFORMATION ONLY
Use the Rhino “What” command.
name: ""
id: BDA76E7C-B715-48af-B765-7F232F25CD4A
layer index: 7
render material index: -1 (from layer)
ON_PolylineCurve: domain = [95.812,127.749]
point[ 0] = (-4.5265288609232712, 1.6695930881383898, 0), 95.812
point[ 1] = (-4.6679516779411543, 3.0623956177574652, 0), 97.2119
point[ 2] = (-8.8464244950313642, 2.6381446411996645, 0), 102.178
point[ 3] = (-8.8265197546890377, 2.4389353514795058, 0), 109.354
point[ 4] = (-9.0061543652242122, 2.4206960533161119, 0), 116.405
point[ 5] = (-8.9496674831754959, 1.8643461119121181, 0), 117.03
point[ 6] = (-8.8694341040910913, 1.8724923038741164, 0), 117.111
point[ 7] = (-8.6876130084081424, 0.081729033627402359, 0), 118.911
point[ 8] = (-8.7678390209751811, 0.073583589596898591, 0), 118.992
point[ 9] = (-8.7031193679997401, -0.56377138661835069, 0), 121.568
point[10] = (-4.344688850237425, -0.12119837604532258, 0), 125.949
point[11] = (-4.5265288609232712, 1.6695930881383898, 0), 127.749

c) re-built in Rhino

Rhino object: curve
DEVELOPER DEBUGGING INFORMATION ONLY
Use the Rhino “What” command.
name: ""
id: 3FD6A1C0-403C-49d7-96F2-5A8735317540
layer index: 2
render material index: -1 (from layer)
ON_PolylineCurve: domain = [94.012,125.949]
point[ 0] = (-4.5657304788202069, -5.3752072433941045, 0), 94.012
point[ 1] = (-4.8889933065239362, -2.1916132495913168, 0), 97.2119
point[ 2] = (-9.0674661236141461, -2.6158642261491174, 0), 102.178
point[ 3] = (-9.0475613832718196, -2.8150735158692761, 0), 109.354
point[ 4] = (-9.2271959938069941, -2.83331281403267, 0), 116.405
point[ 5] = (-9.1707091117582777, -3.3896627554366638, 0), 117.03
point[ 6] = (-9.0904757326738732, -3.3815165634746656, 0), 117.111
point[ 7] = (-8.9086546369909243, -5.1722798337213796, 0), 118.911
point[ 8] = (-8.988880649557963, -5.1804252777518833, 0), 118.992
point[ 9] = (-8.9241609965825219, -5.8177802539671326, 0), 121.568
point[10] = (-4.5657304788202069, -5.3752072433941045, 0), 125.949

Does anybody have an ideas why this is happening, and how I can fix it?

Many thanks for your thoughts.

I’m on Rhino 5SR12 64-bit


#2

Hi Alex,

it may be is a bug, but i think it all depends on the point which is passed to the rs.OffsetCurve function. With below, it is hard to make it fail:

import rhinoscriptsyntax as rs

def DoSomething():
    
    id = rs.GetObject("Curve to offset", 4, True, False)
    if not id: return
    
    pt = rs.GetPoint("rough pt estimate", None, None, True)
    if not pt: return
    
    rc = rs.OffsetCurve(id, pt,  0.5, normal=None, style=1)
    rc = rs.OffsetCurve(id, pt, -0.5, normal=None, style=1)

DoSomething()    

The only case where it failed here with an offset distance of 0.5 is when i clicked the outer intersection of the two failed lines. In all other cases, it worked. Note that this is a simple example, not doing any error checking or passing the curve’s plane to the offset function.

c.


#3

Thanks for this tip, Clement. I’ve played around with rs.OffsetCurve(), and found it to be much more robust. I use rs.CurveAreaCentroid() of my closed polyline as the direction point. So far, this has worked with all of my test cases.

Have a lovely weekend