Dear Experts,
When I use a large number of texts with this code, I encounter the error: "Subscript out of range."
This code is specifically for extracting details from AutoCAD text and polylines.
When I use a large number of texts with this code, I encounter the error: "Subscript out of range."
This code is specifically for extracting details from AutoCAD text and polylines.
Code:
Option Explicit
Sub ExtractAutoCADData()
' Declare AutoCAD variables
Dim acadApp As Object
Dim acadDoc As Object
Dim acadEnt As Object
Dim acadTxt As Object
Dim acadPline As Object
Dim textCoord As Variant
Dim polylineCoords As Variant
Dim numVertices As Long
Dim i As Long
Dim closestPoint As Variant
Dim minDist As Double
Dim chainage As Double
Dim perpDist As Double
Dim direction As String
' Declare Excel variables
Dim ws As Worksheet
Dim data() As Variant
Dim dataCount As Long
Dim textName As String
' Initialize AutoCAD application
Set acadApp = GetObject(, "AutoCAD.Application")
Set acadDoc = acadApp.ActiveDocument
' Select polyline
Set acadPline = SelectPolyline(acadDoc)
If acadPline Is Nothing Then
MsgBox "No polyline selected!", vbExclamation
Exit Sub
End If
' Get polyline coordinates
polylineCoords = acadPline.Coordinates
numVertices = UBound(polylineCoords) \ 2
' Initialize data array
dataCount = 0
ReDim data(1 To 100, 1 To 6) ' Initial size, will resize if needed
' Iterate through entities in the model space for text
For Each acadEnt In acadDoc.ModelSpace
' Check for text objects
If acadEnt.ObjectName = "AcDbText" Then
Set acadTxt = acadEnt
textName = acadTxt.TextString
textCoord = acadTxt.InsertionPoint
closestPoint = GetClosestPointOnPolyline(polylineCoords, textCoord, minDist, chainage)
perpDist = minDist
direction = GetTextDirection(polylineCoords, textCoord, closestPoint)
If direction = "Left" Then
perpDist = -perpDist
End If
' Store data in array
dataCount = dataCount + 1
If dataCount > UBound(data, 1) Then
ReDim Preserve data(1 To dataCount + 100, 1 To 6)
End If
data(dataCount, 1) = textName
data(dataCount, 2) = textCoord(0)
data(dataCount, 3) = textCoord(1)
data(dataCount, 4) = perpDist
data(dataCount, 5) = chainage
data(dataCount, 6) = direction
End If
Next acadEnt
' Trim the array to the actual size
If dataCount > 0 Then
On Error Resume Next
ReDim Preserve data(1 To dataCount, 1 To 6)
On Error GoTo 0
Else
MsgBox "No text objects found!", vbExclamation
Exit Sub
End If
' Initialize Excel worksheet
Set ws = ThisWorkbook.Sheets("Sheet1")
ws.Cells.Clear ' Clear existing data
ws.Range("A1:F1").Value = Array("Text Name", "X Coord", "Y Coord", "Perpendicular Distance", "Chainage", "Direction")
' Output data to Excel
Dim row As Long
row = 2
For i = 1 To dataCount
ws.Cells(row, 1).Value = data(i, 1)
ws.Cells(row, 2).Value = data(i, 2)
ws.Cells(row, 3).Value = data(i, 3)
ws.Cells(row, 4).Value = data(i, 4)
ws.Cells(row, 5).Value = data(i, 5)
ws.Cells(row, 6).Value = data(i, 6)
row = row + 1
Next i
' Clean up
Set acadApp = Nothing
Set acadDoc = Nothing
Set acadEnt = Nothing
Set acadTxt = Nothing
Set acadPline = Nothing
End Sub
Function SelectPolyline(acadDoc As Object) As Object
Dim acadSelSet As Object
Dim polyline As Object
On Error Resume Next
Set acadSelSet = acadDoc.SelectionSets.item("MySelection")
If Err.Number <> 0 Then
Set acadSelSet = acadDoc.SelectionSets.Add("MySelection")
Else
acadSelSet.Clear
End If
On Error GoTo 0
acadDoc.Utility.Prompt "Select a polyline: "
acadSelSet.SelectOnScreen
If acadSelSet.Count > 0 Then
Set polyline = acadSelSet.item(0)
If polyline.ObjectName = "AcDbPolyline" Then
Set SelectPolyline = polyline
End If
End If
acadSelSet.Delete
End Function
Function GetClosestPointOnPolyline(polylineCoords As Variant, textCoord As Variant, ByRef minDist As Double, ByRef chainage As Double) As Variant
Dim i As Long
Dim segmentStart As Variant
Dim segmentEnd As Variant
Dim testPoint As Variant
Dim dist As Double
Dim totalLength As Double
Dim segmentLength As Double
Dim param As Double
minDist = 1E+30
chainage = 0
totalLength = 0
For i = 0 To UBound(polylineCoords) - 2 Step 2
segmentStart = Array(polylineCoords(i), polylineCoords(i + 1))
segmentEnd = Array(polylineCoords(i + 2), polylineCoords(i + 3))
' Get perpendicular distance from text to line segment
testPoint = GetPerpendicularPoint(segmentStart, segmentEnd, textCoord, param)
dist = Sqr((testPoint(0) - textCoord(0)) ^ 2 + (testPoint(1) - textCoord(1)) ^ 2)
' Update minimum distance and chainage
If dist < minDist Then
minDist = dist
GetClosestPointOnPolyline = testPoint
chainage = totalLength + param * Sqr((segmentEnd(0) - segmentStart(0)) ^ 2 + (segmentEnd(1) - segmentStart(1)) ^ 2)
End If
' Update total length of polyline
segmentLength = Sqr((segmentEnd(0) - segmentStart(0)) ^ 2 + (segmentEnd(1) - segmentStart(1)) ^ 2)
totalLength = totalLength + segmentLength
Next i
End Function
Function GetPerpendicularPoint(segmentStart As Variant, segmentEnd As Variant, textCoord As Variant, ByRef param As Double) As Variant
Dim x1 As Double, y1 As Double, x2 As Double, y2 As Double
Dim px As Double, py As Double
Dim dotProduct As Double
Dim segmentLengthSq As Double
x1 = segmentStart(0)
y1 = segmentStart(1)
x2 = segmentEnd(0)
y2 = segmentEnd(1)
px = textCoord(0)
py = textCoord(1)
segmentLengthSq = (x2 - x1) ^ 2 + (y2 - y1) ^ 2
If segmentLengthSq = 0 Then
GetPerpendicularPoint = segmentStart
param = 0
Exit Function
End If
dotProduct = ((px - x1) * (x2 - x1) + (py - y1) * (y2 - y1)) / segmentLengthSq
param = dotProduct
If param < 0 Then
GetPerpendicularPoint = segmentStart
param = 0
ElseIf param > 1 Then
GetPerpendicularPoint = segmentEnd
param = 1
Else
GetPerpendicularPoint = Array(x1 + param * (x2 - x1), y1 + param * (y2 - y1))
End If
End Function
Function GetTextDirection(polylineCoords As Variant, textCoord As Variant, closestPoint As Variant) As String
Dim segmentStart As Variant
Dim segmentEnd As Variant
Dim i As Long
For i = 0 To UBound(polylineCoords) - 2 Step 2
segmentStart = Array(polylineCoords(i), polylineCoords(i + 1))
segmentEnd = Array(polylineCoords(i + 2), polylineCoords(i + 3))
If (closestPoint(0) >= segmentStart(0) And closestPoint(0) <= segmentEnd(0)) Or (closestPoint(0) <= segmentStart(0) And closestPoint(0) >= segmentEnd(0)) Then
If (closestPoint(1) >= segmentStart(1) And closestPoint(1) <= segmentEnd(1)) Or (closestPoint(1) <= segmentStart(1) And closestPoint(1) >= segmentEnd(1)) Then
If ((segmentEnd(0) - segmentStart(0)) * (textCoord(1) - segmentStart(1)) - (segmentEnd(1) - segmentStart(1)) * (textCoord(0) - segmentStart(0))) > 0 Then
GetTextDirection = "Left"
Else
GetTextDirection = "Right"
End If
Exit Function
End If
End If
Next i
End Function