AutoCAD & RTree
Imports MyAcAs = Autodesk.AutoCAD.ApplicationServices
Imports Autodesk.AutoCAD.DatabaseServices
Imports Autodesk.AutoCAD.EditorInput
Imports Autodesk.AutoCAD.Geometry
Imports RTree
Public Class MyTable
'Public Shared MinColW As Double = 1
'Public Shared MinRowH As Double = 1
Private vert, horz As List(Of Line) 'Список линий формирующих таблицу
Public Cells(,) As MyCell 'Массив ячеек
Friend wTree As RTree(Of MyCell) 'Дерево для поиска ячеек
Public Enum Orent
Vert ' вертикальна
Horz ' горизонтална
None ' неопределенна
End Enum
Public Shared Function isOrto(wL As Line) As Orent
'Определяем орентацию линии - вертикальна или горизонтална
Dim wValue As Double = wL.Angle / Math.PI
Dim delta As Double = 0.05
wValue = wValue - Math.Truncate(wValue + delta / 2)
If Math.Abs(wValue) <= delta Then
Return Orent.Horz
ElseIf (Math.Abs(wValue) < 0.5 + delta) And (Math.Abs(wValue) > 0.5 - delta) Then
Return Orent.Vert
Else
Return Orent.None
End If
End Function
Private Shared Function CompareByX(l1 As Line, l2 As Line) As Integer
If l1.StartPoint.X > l2.StartPoint.X Then
Return 1
ElseIf l1.StartPoint.X = l2.StartPoint.X Then
Return 0
Else
Return -1
End If
End Function
Private Shared Function CompareByY(l1 As Line, l2 As Line) As Integer
If l1.StartPoint.Y > l2.StartPoint.Y Then
Return 1
ElseIf l1.StartPoint.Y = l2.StartPoint.Y Then
Return 0
Else
Return -1
End If
End Function
Private Shared Function GetSelect(ed As Editor) As ObjectId()
'Получаем от пользователя набор данных для парсинга
Dim PSResult As PromptSelectionResult
Dim wTV() As TypedValue = {New TypedValue(DxfCode.Operator, "")}
Dim wSF As New SelectionFilter(wTV)
PSResult = ed.GetSelection(wSF)
If PSResult.Status = PromptStatus.OK Then
Return PSResult.Value.GetObjectIds()
Else
Return Nothing
End If
End Function
Private Shared Function PolyToLine(pl As Polyline) As List(Of Line)
Dim wList As New List(Of Line)
Dim wL As Line
For i = 0 To pl.NumberOfVertices - 2
wL = New Line(pl.GetPoint3dAt(i), pl.GetPoint3dAt(i + 1))
wList.Add(wL)
Next
Return wList
End Function
Private Sub New(nvert As List(Of Line), nhorz As List(Of Line))
'Формируем "пустую" таблицу из линий
Me.vert = nvert
Me.horz = nhorz
Dim CC, RC As Integer
CC = Me.GetCols()
RC = Me.GetRows()
ReDim Me.Cells(CC, RC)
Me.wTree = New RTree(Of MyCell)()
Dim wLine As Line
Dim nCell As MyCell
For i = 0 To CC - 1
For j = 0 To RC - 1
wLine = Me.GetCellBox(i, j)
nCell = New MyCell(wLine, i, j, "")
Me.Cells(i, j) = nCell
Me.wTree.Add(nCell.GetRectangle, nCell)
Next
Next
End Sub
Public Sub SetValue(wt As DBText)
'Заполняем таблицу
If wt.Bounds IsNot Nothing Then
Dim tExtent As Extents3d = wt.Bounds
Dim X, Y As Double
X = (tExtent.MaxPoint.X + tExtent.MinPoint.X) / 2
Y = (tExtent.MaxPoint.Y + tExtent.MinPoint.Y) / 2
Dim wP As New Point(X, Y, 0)
Dim wList As List(Of MyCell) = Me.wTree.Nearest(wP, wt.Height / 2)
If wList IsNot Nothing Then
If wList.Count > 0 Then wList(0).Value = wt.TextString
End If
End If
End Sub
Public Sub SetValue(wt As MText)
'Заполняем таблицу
If wt.Bounds IsNot Nothing Then
Dim tExtent As Extents3d = wt.Bounds
Dim X, Y As Double
X = (tExtent.MaxPoint.X + tExtent.MinPoint.X) / 2
Y = (tExtent.MaxPoint.Y + tExtent.MinPoint.Y) / 2
Dim wP As New Point(X, Y, 0)
Dim wList As List(Of MyCell) = Me.wTree.Nearest(wP, 1)
If wList IsNot Nothing Then
If wList.Count > 0 Then wList(0).Value = wt.Text
End If
End If
End Sub
Private Shared Function CrTbl(wList As List(Of Line)) As MyTable
'Формируем "пустую" таблицу из линий
Dim nvert, nhorz, overt, ohorz As List(Of Line)
nvert = wList.FindAll(Function(l) isOrto(l) = Orent.Vert)
nvert.Sort(AddressOf CompareByX)
nhorz = wList.FindAll(Function(l) isOrto(l) = Orent.Horz)
nhorz.Sort(AddressOf CompareByY)
'
Dim MinColW, MinRowH As Double
MinColW = Math.Abs(nvert(0).StartPoint.X - nvert(nvert.Count - 1).StartPoint.X) * 0.01
MinRowH = Math.Abs(nhorz(0).StartPoint.Y - nhorz(nhorz.Count - 1).StartPoint.Y) * 0.01
'
Dim ol As Line = Nothing
overt = New List(Of Line)
For Each l In nvert
If ol Is Nothing Then
ol = l
overt.Add(l)
Else
If Math.Abs(l.StartPoint.X - ol.StartPoint.X) > MinColW Then
ol = l
overt.Add(l)
End If
End If
Next
'
ohorz = New List(Of Line)
For Each l In nhorz
If ol Is Nothing Then
ol = l
ohorz.Add(l)
Else
If Math.Abs(l.StartPoint.Y - ol.StartPoint.Y) > MinRowH Then
ol = l
ohorz.Add(l)
End If
End If
Next
Return New MyTable(overt, ohorz)
End Function
Public Shared Function CrTbl(acDoc As MyAcAs.Document) As MyTable
'Создаём таблицу
Dim ed As Editor = acDoc.Editor
Dim objIdArray() As ObjectId = MyTable.GetSelect(ed) 'Получаем от пользователя набор данных для парсинга
If objIdArray IsNot Nothing Then
Dim dbObj As DBObject
Dim wList As New List(Of Line)
Dim wTList As New List(Of DBText)
Dim wMTList As New List(Of MText)
Using tr As Transaction = acDoc.Database.TransactionManager.StartTransaction
Try
For Each objId As ObjectId In objIdArray
dbObj = tr.GetObject(objId, OpenMode.ForRead)
'Сортируем полученные объекты
Select Case True
Case TypeOf dbObj Is Line
wList.Add(dbObj)
Case TypeOf dbObj Is Polyline
wList.AddRange(MyTable.PolyToLine(dbObj))
Case TypeOf dbObj Is DBText
wTList.Add(dbObj)
Case TypeOf dbObj Is MText
wMTList.Add(dbObj)
End Select
Next
tr.Commit()
Catch ex As Exception
ed.WriteMessage(ex.ToString())
tr.Abort()
End Try
End Using
'
Dim wMTbl As MyTable = MyTable.CrTbl(wList)
'Заполняем текстом
For Each wt In wTList
wMTbl.SetValue(wt)
Next
For Each wmt In wMTList
wMTbl.SetValue(wmt)
Next
Return wMTbl
Else
Return Nothing
End If
End Function
Public Function GetCols() As Integer
Return vert.Count - 1
End Function
Public Function GetColW(i As Integer) As Double
Dim res As Double = Math.Abs(vert(i + 1).StartPoint.X - vert(i).StartPoint.X)
If res = 0 Then res = 1 '?!
Return res
End Function
Public Function GetRows() As Integer
Return horz.Count - 1
End Function
Public Function GetRowH(j As Integer) As Double
Dim res As Double = Math.Abs(horz(j + 1).StartPoint.Y - horz(j).StartPoint.Y)
If res = 0 Then res = 1 '?!
Return res
End Function
Public Function GetCellBox(i As Integer, j As Integer) As Line
'Получаем диагональную линию в нужной ячейке (размер)
Dim p1, p2 As Point3d
p1 = New Point3d(vert(i).StartPoint.X, horz(j).StartPoint.Y, 0)
p2 = New Point3d(vert(i + 1).StartPoint.X, horz(j + 1).StartPoint.Y, 0)
Return New Line(p1, p2)
End Function
Public Function CrTbl(ip As Point3d) As Table
'Создаём ACAD-таблицу
Dim res As New Table()
Dim Rs, Cs As Integer
Rs = Me.GetRows()
Cs = Me.GetCols()
res.SetSize(Rs, Cs)
res.Position = ip
For i = 0 To Cs - 1
res.Columns(i).Width = Me.GetColW(i)
For j = 0 To Rs - 1
res.Rows(j).Height = Me.GetRowH(j)
res.Cells(Rs - j - 1, i).TextString = Me.Cells(i, j).Value
Next
Next
res.GenerateLayout() '!?
Return res
End Function
End Class