这是一个Vba方法,比我想象的要难一些,因为我已经有了它的伴侣,在远处得到点。
- Option Explicit
- Const PI As Double = 3.14159265358979
- Sub TestPt()
- Dim oPline As AcadLWPolyline
- Dim Util As AcadUtility
- Dim Varpick As Variant
-
- Set Util = ThisDrawing.Utility
- Util.GetEntity oPline, Varpick, "Pick a poly:"
- Varpick = ThisDrawing.Utility.GetPoint(, "Point on poly")
- Debug.Print LengthAtPointOnPoly(oPline, Varpick)
-
- End Sub
- Function LengthAtPointOnPoly(oPline As AcadLWPolyline, Varpick As Variant) As Double
- Dim Dist As Double, TotalDist As Double
- Dim dBulge As Double, seg As Double
- Dim Pt(1) As Double
- Dim C1, C2
- Dim Ct As Integer, i As Long
- Dim Util As AcadUtility
-
- Set Util = ThisDrawing.Utility
- Varpick = Util.TranslateCoordinates(Varpick, acWorld, acOCS, False, oPline.Normal)
- If Not Rd(Varpick(2), oPline.Elevation) Then Exit Function
- Pt(0) = Varpick(0): Pt(1) = Varpick(1)
- Ct = (UBound(oPline.Coordinates) - 1) / 2
- If oPline.Closed = True Then Ct = Ct + 1
- ReDim Coords(Ct) As Variant
- For i = 0 To Ct - 1
- Coords(i) = oPline.Coordinate(i)
- Next
- If oPline.Closed = True Then
- Coords(Ct) = oPline.Coordinate(0)
- Else
- Coords(Ct) = oPline.Coordinate(Ct)
- End If
-
- For i = 0 To Ct - 1
- C1 = Coords(i)
- C2 = Coords(i + 1)
- dBulge = oPline.GetBulge(i)
- seg = Length(C1, C2)
- If dBulge = 0 Then
- If isOnLine(C1, C2, Pt) Then
- TotalDist = TotalDist + Length(C1, Pt)
- Exit For
- Else
- TotalDist = TotalDist + seg
- If i = Ct - 1 Then TotalDist = 0
- End If
- Else
- If isPtonArc(C1, C2, Pt, dBulge, seg, Dist) Then
- TotalDist = TotalDist + Dist
- Exit For
- Else
- TotalDist = TotalDist + polyarclength(dBulge, seg)
- If i = Ct - 1 Then TotalDist = 0
- End If
-
- End If
- Next i
- LengthAtPointOnPoly = TotalDist
-
- End Function
- Private Function isPtonArc(C1 As Variant, C2 As Variant, Pt As Variant, _
- dBulge As Double, seg As Double, Dist As Double) As Boolean
- Dim Rad As Double
- Dim X As Double, Y As Double
- Dim deltaX As Double, deltaY As Double
- Dim Slope As Double, Invertslope As Double
- Dim dLength As Double, AngX As Double
- Dim CenPt(1) As Double
- Dim bOnArc As Boolean
- Dim iLeft As Integer
-
- 'IncludedAng = Atn(dBulge) * 4 'converting bulge to angle in radians
- Rad = seg / (2 * Sin(2 * Atn(dBulge)))
- 'find the midpoint
- X = (C1(0) + C2(0)) / 2
- Y = (C1(1) + C2(1)) / 2
- deltaX = C2(0) - C1(0)
- deltaY = C2(1) - C1(1)
- 'Convert floating point to zero
- If Rd(deltaX, 0) Then deltaX = 0
- If Rd(deltaY, 0) Then deltaY = 0
-
- 'The height of the curve is dBulge * 0.5 * seg
- 'dist is the length from the midpoint to the center
- Dist = Rad - dBulge * 0.5 * seg
-
- 'If Abs(dBulge) > 1 Then Dist = -Dist
-
- If deltaY >= 0 Then
- If deltaX 0 Then
- Dist = -Dist
- End If
- Else
- If deltaX = 0 Then
- Dist = -Dist
- End If
- End If
-
- If deltaY = 0 Then 'Line p1,p2 is horizontal
- CenPt(0) = X
- CenPt(1) = Y - Dist
- ElseIf deltaX = 0 Then 'Line p1,p2 is vertical
- CenPt(0) = X - Dist
- CenPt(1) = Y
- Else
- Slope = deltaY / deltaX
- Invertslope = -1 / Slope
- 'Invert slope for perpendicular bisector
- 'X = X1 + distance / dLength * DX
- 'proving for DeltaX=1 in slope direction
- 'slope=DeltaY / 1 => DeltaY=slope
- dLength = Sqr(Invertslope ^ 2 + 1)
- CenPt(0) = X + (Dist / dLength) '* 1
|