Grasshopper

algorithmic modeling for Rhino

This might be an incredibly simple one.

Im looking to find all the perpendicular points on a curve from a given test point in a vb component.

Essentially, looking for the same result you would get from curve.closestpoint, but for all perpendicular conditions.

Is there a built in method for this?

Thanks,

David

Views: 1241

Replies to This Discussion

There's no out-of-the-box method for this. It is reasonably easy for polylines as you can approach it in a per-segment basis, but even there you need some conditional logic to reject segments without any perpendicular point. For curved curves it becomes quite a bit harder.

--

David Rutten

david@mcneel.com

Thanks David,

Good to know. The solution I'm looking for would be for both non linear curves and polylines. I didnt know if the method that Rhino's perp osnap uses was something accessible through Rhino Common. Looks like an interesting problem to dig deeper into on the weekend.

I think subdividing the curve into smaller elements and testing for perpendicularity is the way to go. You could first divide your curve into polylines using the curve.topolylines method with to determine where there are significant differences in curvature, and subdivide your curve at the kinks. Then do closest points for each segment, and if the vector to the center is perpendicular to the tangent along the curve, include it.

This won't capture all moments, I'm sure (arcs have the potential for infinite perp points), but it should help simplify the problem and focus the sampling on parts of the curve with the greatest variety.

Maybe like this...

Private Sub RunScript(ByVal P As Point3d, ByVal C As Curve, ByVal R As Double, ByRef PP As Object, ByRef PC As Object)

C.Domain = New Interval(0, 1)

Dim Pl As PolylineCurve = C.ToPolyline(0, 1, R, C.GetLength, 5, 0, 0, C.GetLength, True)

Dim t As New List(Of Double)
Dim SubSegs() As Curve = Pl.DuplicateSegments
Dim TestCrvs As New List(Of NurbsCurve)

Dim PerpPts As New List(Of Point3d)

For Each SubSeg As Curve In SubSegs
Dim ts, te As Double
C.ClosestPoint(SubSeg.PointAtStart, ts)
C.ClosestPoint(SubSeg.PointAtEnd, te)
If ts > te Then
TestCrvs.Add(C.ToNurbsCurve(New Interval(ts, 1)))
TestCrvs.Add(C.ToNurbsCurve(New Interval(0, te)))
Else
TestCrvs.Add(C.ToNurbsCurve(New Interval(ts, te)))
End If
Next

For Each TestC As NurbsCurve In TestCrvs
If TestC IsNot Nothing Then
Dim tt As Double
TestC.ClosestPoint(P, tt)
Dim TestP As Point3d = C.PointAt(tt)
If TestC.TangentAt(tt).IsPerpendicularTo(New Vector3d(TestP - P)) Then PerpPts.Add(TestP)
End If
Next

PP = PerpPts
PC = Pl

End Sub

Attachments:

It would be better to test the curve using the SpanCount and the Domain. Basically, you cut the curve domain into -say- 5*spancount subdomains and test each of those for closest-point, you have a sampling that is adaptive to the complexity of the curve.

--

David Rutten

david@mcneel.com

Ah. I am totally unfamiliar with spancount. I was thinking that by breaking the curve up by the tightest angles I'd isolate more bits that had a chance of being perpendicular. I'll look into spancount...sounds interesting.

Well that's easier:

Private Sub RunScript(ByVal P As Point3d, ByVal C As Curve, ByVal At As Double, ByRef PP As Object, ByRef PC As Object)

C.Domain = New Interval(0, 1)
Dim PerpPts As New List(Of Point3d)
Dim TestCrvs As New List(Of NurbsCurve)

At = At * (Math.PI / 180) 'angle tolerance

For SC As Int32 = 0 To C.SpanCount - 1
TestCrvs.Add(C.ToNurbsCurve(C.SpanDomain(SC)))
Next

For Each TestC As NurbsCurve In TestCrvs
If TestC IsNot Nothing Then
Dim tt As Double
TestC.ClosestPoint(P, tt)
Dim TestP As Point3d = C.PointAt(tt)
If TestC.TangentAt(tt).IsPerpendicularTo(New Vector3d(TestP - P), At) Then PerpPts.Add(TestP)
End If
Next

PP = PerpPts
PC = TestCrvs

End Sub

...although I see your point that the spans should probably then also be subdivided

The higher the degree of the curve, the more 'wiggles' a single span can have. The more wiggles, the more potential perpendicular or tangent solutions.

It's probably best to divide all spans into degree+2 or [degree*2] or something pieces. 

Another approach is just to sample the curve at many intervals and only take an accurate look at a segment (irrespective of spans) if the sampling indicates a potential solution. That would probably be somewhat faster, but harder to code.

--

David Rutten

david@mcneel.com

RSS

About

Translate

Search

Photos

  • Add Photos
  • View All

Videos

  • Add Videos
  • View All

© 2024   Created by Scott Davidson.   Powered by

Badges  |  Report an Issue  |  Terms of Service