SetPt in Python

What is the simplest way to be able to do an operation similar to Rhino’s SetPt with Python? So picking a 3D curve whose points will be set, and for simplicity it will just be set to a set z value (even better to be a defined amount above the largest existing z value from the curves points. Eventually this would be used for a loft similar to the attached, so the top is planar.

So far I am using CurvePoints but then need to manipulate that list of points.

If you want to set all curves to a specific Z level, you can use a planar transformation in RhinoCommon or rhinoscriptsyntax… No need to work on points. You just need to specify the plane.

Hi @Jonathan_Hutchinson1,

Here is the SetPt command implemented in C#:

SampleCsSetPoint.cs

Perhaps this helps?

– Dale

setpt_bottom = rs.XformPlanarProjection(planebottom)
setptcurve_bottom = rs.TransformObjects(projectedinterior, setpt_bottom, True)
curves_bottom = setptcurve_bottom, projectedinterior 
rs.AddLoftSrf(curves_bottom)

I did something along the projection lines… Then used bounding box points to make a plane, transformed with an arbitrary vector so that the top curve would be set above the bounding box. probably a few too many lines of code still.

Hi @Jonathan_Hutchinson1,

I was thinking something along the lines of this:

import Rhino

class SetPtDir:
    X = 1
    Y = 2
    Z = 4
    All = X | Y | Z

def SetPtTransform(point, dir):
    xform = None
    if point.IsValid:
        xform = Rhino.Geometry.Transform(0)
        if (SetPtDir.X & dir):
            xform[0, 3] = point.X
        else:
            xform[0, 0] = 1.0
        if (SetPtDir.Y & dir):
            xform[1, 3] = point.Y
        else:
            xform[1, 1] = 1.0
        if (SetPtDir.Z & dir):
            xform[2, 3] = point.Z
        else:
            xform[2, 2] = 1.0
        xform[3, 3] = 1.0;
    return xform
    
xform = SetPtTransform(Rhino.Geometry.Point3d(1, 2, 3), SetPtDir.X | SetPtDir.Y)
print(xform)

– Dale

Hi Dale,

Would something similar be able to work in a case like the attached?set_points_example.3dm (143.7 KB)

Two curves with the same structure, the planar curve is a reference. I would want to amend every point location on the 3D Curve to match the XY location of the 2D curve, along matching indexes.

Currently I am trying with the below, but I might be up the wrong tree. I can change the points location, but that isn’t actually reflected in the Rhino document. Currently I’m trying to just set one point, and get that working. Eventually, the aim is to set all points , for a quick and dirty cage edit. Although if the cage edit is still worked out on a point by point basis, then it will probably be quite slow. Ideal scenario is to move the curve points of the MorphControl once, and update the captive object once.

# Match Control Point Locations
# V1.0
# Designed for matching control points of a Control cage to a target location
#Matching XY locations

import rhinoscriptsyntax as rs
import Rhino as rh
import scriptcontext as sc

#My Test Target Location for Setting Point [0]
target_location = rs.CreatePoint(-342,79,52)

#Pick MorphControlType
source_guid = rs.GetObject("Pick Morph Control with points to transform", filter = 131072)
source_object = rs.coercerhinoobject(source_guid)
morphcontrol_curve = source_object.Geometry.Curve

print "Location Before:", morphcontrol_curve.Points [0].Location

points_list = morphcontrol_curve.Points
result = points_list.SetPoint(0, target_location)

if result:
    print "Location was changed behind the curtain"

print "Location After:", morphcontrol_curve.Points [0].Location

#Rhino.Geometry.Transform.Translation() # between each original/offset point

# Rhino.Geometry.Collections.NurbsCurvePointList.SetPoint(0, target_location)
"""
rs.AddPoint(morphcontrol_curve.Points [0].Location)
rs.AddPoint(morphcontrol_curve.Points [1].Location)
"""

# Maybe can just use Replace?
# Maybe transform points? sc.doc.Objects.Transform()
# Eventually match all points on a curve as below
# target = rs.GetObject( "Pick curve to match to", filter = 4 ) ```

Hello - - I think I would turn on the grips for the control and set the grip locations in your script - that will be much more straightforward. (rs.ObjectGripLocation(id, index, location))

# Match Control Point Locations
# V1.0
# Designed for matching control points of a Control cage to a target location
#Matching XY locations

import rhinoscriptsyntax as rs
import Rhino as rh
import scriptcontext as sc

#My Test Target Location for Setting Point [0]
target_location = rs.CreatePoint(-342,79,52)

#Pick MorphControlType
source_guid = rs.GetObject("Pick Morph Control with points to transform", filter = 131072)

rs.EnableObjectGrips(source_guid)
start =  rs.ObjectGripLocation(source_guid, 0)
print "Location Before:", start
if rs.ObjectGripLocation(source_guid, 0, target_location):
    end = rs.ObjectGripLocation(source_guid, 0)
    print "Location after:", end

-Pascal

3 Likes

This works great! I’m sure I ran one of the rs Grip category methods and it wouldn’t work so I just overlooked them.

This is what I was trying to solve. I will try getting it to loop now. There seems to be a problem with a stacked control point on the test point I wanted to move. Perhaps it’s because it is the seam point, presumably not to do with the below result from What

control points: non-rational, count=76 (3 duplicates)

Hello - I’d use rs.ObjectGripLocations(id, locations) and do them all in one go, once the locations are known, otherwise you end up dealing with the deformation for each point that is moved.

-Pascal

Ah yes - I see that too now. Perfect, that’s exactly what I would need, and would be desired.

import rhinoscriptsyntax as rs
import Rhino as rh
import scriptcontext as sc

#Pick MorphControlType
source_guid = rs.GetObject("Pick Morph Control with points to transform", filter = 131072)
target_guid = rs.GetObject("Pick curve to match to", filter = 4)

rs.EnableRedraw(enable=False)
rs.EnableObjectGrips(source_guid)
rs.EnableObjectGrips(target_guid)

start =  rs.ObjectGripLocations(source_guid)
end = rs.ObjectGripLocations(target_guid)

if len(start) == len(end):
    print "Both curves have the same number of points. Okay to proceed."
    rs.ObjectGripLocations(source_guid, end)

rs.EnableRedraw(enable=True)
rs.EnableObjectGrips(source_guid, enable=False)
rs.EnableObjectGrips(target_guid, enable=False)

Well, that was deceptively simple and puts an old challenge to bed for sure anyway. Thank you so much @pascal. Is it best to view a grip as the ‘editable’ version of a point? Whereas the control point isn’t to be touched.

I think when I ran rs.IsCurve on the MorphCntrol and got “False” is the point when I left grips behind. Which was silly, because the hint’s in the name right… ObjectGrips, not CurveGrips.

FYI I did this as an alternative to the Flow command with radii of influence - the results I got with that were just not good enough, even with what I thought was quite clean input. But this alternative could be a big help in the long run.

Hm - that is not a bad way - the thing about grips is they are ephemeral- they are created for the occasion and then go away when they re turned off - so to deal with them at all you need to turn them on. You could have done the control points - that is more elegant, in a way, but as far as I can see so far, while you can deform stuff, moving control points, it is tricky to replace the control that the user sees as well with the new modified one. I’ll poke some more though, I am curious…

-Pascal

Yes - so that explains why if you rs.ObjectGripCount when the control points are ‘off’ you get None then. That’s good to know, thank you for explaining that.

This is what I figured - I was way off thinking I would need Replacement in the end though, I would’ve been surprised if I had hit a dead end.

Even see my mistake :slight_smile: Thankfully I could get access to grip style functions.