The vertices have no clockwise or counter clockwise order. How can I know which is where?
Basically I am looking for a way to sort these grip points based on their counter clockwise connection of open edges. Is this possible?
Hi @dale currently I have only the following script where I would like to use this for, to make holes circular, but have also other ideas in mind where it could be used. It kind of works if the points are enough in the ballpark. The attached model right hole works, the left will fail.
import Rhino
import rhinoscriptsyntax as rs
import scriptcontext as sc
"""
This script planarizes a group of points and organizes them equally spaced in a circle
script by Gijs de Zwart
www.studiogijs.nl
"""
def circularize():
go = Rhino.Input.Custom.GetObject()
go.SetCommandPrompt("Select controlpoints to make circular")
go.GeometryFilter = Rhino.DocObjects.ObjectType.Grip
go.GetMultiple(1, 0)
object_list = Rhino.Collections.TransformObjectList()
object_list.AddObjects(go, True)
#convert grips to list of 3d points
gripPts=[grip.OriginalLocation for grip in object_list.GripArray()]
#fit circle through these points
result, circle = Rhino.Geometry.Circle.TryFitCircleToPoints(gripPts)
if not result:
return
circle = sc.doc.Objects.AddCircle(circle)
#get first grip and match circle seam to this first point
pt_0 = object_list.GripArray()[0].OriginalLocation
param = rs.CurveClosestPoint(circle, pt_0)
rs.CurveSeam(circle,param)
#divide circle
segs= len(go.Objects())
ptlist = rs.DivideCurve(circle, segs)
#return
for i in range(len(ptlist)):
#find index of closest grip point to circle point i
j=Rhino.Collections.Point3dList.ClosestIndexInList(gripPts, ptlist[i])
#select corresponding grip
grip = object_list.GripArray()[j]
#calculate translation vector to circle point
vector_from = grip.OriginalLocation
vector_to = ptlist[i]
dir = rs.VectorSubtract(vector_to, vector_from)
#move grip
xform = Rhino.Geometry.Transform.Translation(dir)
grip.Move(xform)
for owner in object_list.GripOwnerArray():
sc.doc.Objects.GripUpdate(owner, True)
sc.doc.Views.Redraw()
circularize()
import Rhino
import scriptcontext as sc
def test_circularize():
go = Rhino.Input.Custom.GetObject()
go.SetCommandPrompt("Select control points to make circular")
go.GeometryFilter = Rhino.DocObjects.ObjectType.Grip
go.GetMultiple(1, 0)
if go.CommandResult() != Rhino.Commands.Result.Success:
return
object_list = Rhino.Collections.TransformObjectList()
object_list.AddObjects(go, True)
locations = [grip.OriginalLocation for grip in object_list.GripArray()]
result, circle = Rhino.Geometry.Circle.TryFitCircleToPoints(locations)
if not result:
return
curve = Rhino.Geometry.ArcCurve(circle)
for grip in object_list.GripArray():
rc, t = curve.ClosestPoint(grip.OriginalLocation)
if rc:
grip.CurrentLocation = curve.PointAt(t)
for owner in object_list.GripOwnerArray():
sc.doc.Objects.GripUpdate(owner, True)
sc.doc.Views.Redraw()
test_circularize()
Thanks, unfortunately that gives less circular results since the points are just pulled towards their closest point on the circle:
I have another idea, and that is after fitting the circle, to first smooth out the points, then transform them to the circle. Is there a RhinoCommon version of _Smooth on a selection of points to accomplish this?
I know how to make a circle, that’s not the issue, it’s mainly about getting equal spacing between the points.
Your script doesn’t adjust this point spacing.
But my question remains: is there a smooth command equivalent in Rhino Common for a selection of grip objects? In that case I can make my script work more reliably.
I see this will work best with a proper ordering of the input points, but that might be achieved crudely by sorting to closest points in a remaining set of points.
pseudo:
I doubt it will work reliably, in fact the way I am doing it now, searches for closest point already. When points are more or less evenly spaced, closest point works, but you can easily run into a situation where the first closest point is a clockwise and a second is a counterclockwise point, for example if the first point is in the middle of two points that are closer to the first point than all other points. If you then run a polyline through it, it will be a self intersecting polyline, and when smoothing that out, points will in the end ‘swap location’.
Maybe I’m misunderstanding your reply, but
the closest point I’m referring to is to sort the input points where you start with an arbitrary first point and than look for it’s closest neighbor. Next you search the closest to that neighbor excluding the already sorted points.
I see how this can indeed not be reliable in all cases especially with regular grid spaced input.
Yes that’s also how I do the sorting of the points. I run a circle through the points, then choose the first point of the list of points I want to transform and find closest point on the circle, then divide this circle, and for the next point on the divided circle, take the closest point of the subd, and remove that from the list. But here is an image of what I described where it can go wrong. The way I understand your described method is that this won’t make a difference with the way I am doing it now, am I right?
I see, so you would need an additional filtering based on the tangent angle where this with tangent angles close to 180deg are discarded…
That of course not be fail-proof either…
The reason I remembered your quest was that I did some digging to see if somehow the connected mesh edges for the selected grips could easily be retrieved. But I ran into dead ends in RhinoCommon.
Yeah, seems we need to be a bit more patient when it comes to subd Rhino Common access. I hope that for edge-loops (holes) there will eventually be a method to get something like EdgeLeftNeighbor, EdgeRightNeighbor, and similar for grips
I cant do this. My idea is to select the points to approximate the circle, the circle bisects equal points, and then the points moves to the bisection points.