您當前的位置:首頁 > 攝影

Cad.Net 重構折線bo函式

作者:由 束夢齋 發表于 攝影時間:2022-12-26

由於CAD自帶Bo函式,在二次開發時無論使用SendCommand方式,還是TraceBoundary函式,其精度都與視口大小掛鉤。測試程式碼如下:

‘測試cad自帶bo命令功能

Public

Sub

botest

()

Dim

acDoc

As

Document

=

Application

DocumentManager

MdiActiveDocument

Dim

acCurDb

As

Database

=

acDoc

Database

Dim

acDocEd

As

Editor

=

Application

DocumentManager

MdiActiveDocument

Editor

Using

acTrans

As

Transaction

=

acCurDb

TransactionManager

StartTransaction

()

Dim

acSSPrompt

As

PromptSelectionResult

acSSPrompt

=

acDocEd

GetSelection

()

Dim

acSSet

=

acSSPrompt

Value

Dim

acpoint

=

acDocEd

GetPoint

“請選擇bo點”

Dim

point

=

acpoint

Value

acDocEd

Command

“-boundary”

“_A”

“_B”

“_N”

acSSet

“”

“_O”

“_P”

“”

point

“”

acTrans

Commit

()

End

Using

End

Sub

若圖面精準,可透過每次使用bo命令時調整視口範圍至需要獲取封閉線的區域來實現精度的最大化。即利用acDocEd。GetCurrentView(),acDocEd。SetCurrentView()進行不斷的視口調整。

但該方法並不優雅,會導致視口的瘋狂亂竄。且當要處理手繪圖,封閉線存在小缺口,需要設定一定容差時,利用原生bo功能容易出現錯誤,導致找漏、找錯封閉區域的狀況。因此,可以編寫單純透過遍歷幾何圖形尋找bo的函式。本文參考了驚驚大佬cad。net bo邊界演算法的相關思路,對純折線情況下尋找封閉區域的演算法進行了vb。net的實現,方法如下:

’Entlist為圖元構成的集合,bopoint為bo點,tk_max_x是射線法在虛擬射線的最右點,

‘可以取消該引數,並透過設定一個極大值的方式進行代替

Public Shared Function boundary(Entlist As ArrayList, bopoint As Point3d, tk_max_x As Double) As Polyline

Dim acDoc As Document = Application。DocumentManager。MdiActiveDocument

Dim acCurDb As Database = acDoc。Database

Dim acDocEd As Editor = Application。DocumentManager。MdiActiveDocument。Editor

Dim FinalBoPline = New Polyline()

Dim NotTrueLine = New Line(bopoint, New Point3d(tk_max_x, bopoint。Y, 0))

Dim cross_dictionary = New Dictionary(Of ObjectId, Dictionary(Of Double, ObjectId))

Dim Linelist = New ArrayList

Using acTrans1 As Transaction = acCurDb。TransactionManager。StartTransaction()

’BlkInt2實現包括自交點在內所有交點全部打斷

Linelist = BlkInt2(Entlist, acTrans1)

‘構造相交矩陣,使行索引線起點與列索引線相交時,值為0,終點相交時,值為1,不相交時,值為2。

Dim cross_arr = New ArrayList()

For CrNum1 = 0 To Linelist。Count - 1

Dim temp_arr = New ArrayList()

For CrNum2 = 0 To Linelist。Count - 1

temp_arr。Add(2)

Next

cross_arr。Add(temp_arr)

Next

Dim k1 = 0

For Each ent As Curve In Linelist

Dim k2 = 0

For Each ent1 As Curve In Linelist

If k1 < k2 Then

If Math。Abs(ent。StartPoint。DistanceTo(ent1。StartPoint)) <= 0。5 Then

cross_arr。Item(k1)。Item(k2) = 0

cross_arr。Item(k2)。Item(k1) = 0

ElseIf Math。Abs(ent。StartPoint。DistanceTo(ent1。EndPoint)) <= 0。5 Then

cross_arr。Item(k1)。Item(k2) = 0

cross_arr。Item(k2)。Item(k1) = 1

ElseIf Math。Abs(ent。EndPoint。DistanceTo(ent1。StartPoint)) <= 0。5 Then

cross_arr。Item(k1)。Item(k2) = 1

cross_arr。Item(k2)。Item(k1) = 0

ElseIf Math。Abs(ent。EndPoint。DistanceTo(ent1。EndPoint)) <= 0。5 Then

cross_arr。Item(k1)。Item(k2) = 1

cross_arr。Item(k2)。Item(k1) = 1

End If

End If

k2 = k2 + 1

Next

k1 = k1 + 1

Next

’獲取備選起點集

Dim temp_list = New Point3dCollection()

Dim Start_dic = New Dictionary(Of Integer, Double)

Dim virtualline As Line = New Line(New Point3d(tk_max_x, bopoint。Y, 0), bopoint)

Dim objectindexlist = New ArrayList()

Dim k3 = 0

For Each ent As Curve In Linelist

objectindexlist。Add(k3)

virtualline。IntersectWith(ent, Intersect。OnBothOperands, temp_list, 0, 0)

If temp_list。Count > 0 Then

Dim temp_dist As Double = bopoint。DistanceTo(temp_list。Item(0))

Start_dic。Add(k3, temp_dist)

temp_list = New Point3dCollection()

End If

k3 = k3 + 1

Next

Dim sorted = From pair In Start_dic

Order By pair。Value

Dim sorted_dic = sorted。ToDictionary(Function(p) p。Key, Function(p) p。Value)

‘起點集獲取完成,進行閉環搜尋,採用深度優先搜尋方式

Dim bopointlist = New ArrayList()

Dim indexlist = New ArrayList()

Dim point_mark As Integer

Dim FisrtPoint = New Point3d()

SearchFirstPoint:

While sorted_dic。Count > 0

Dim currentindex = objectindexlist。IndexOf(sorted_dic。First。Key)

Dim currentline As Line

sorted_dic。Remove(sorted_dic。First。Key)

indexlist。Add(currentindex)

Dim End_angle = lineangle(virtualline, New Line(Linelist。Item(currentindex)。StartPoint, Linelist。Item(currentindex)。EndPoint))

Dim Start_angle = lineangle(virtualline, New Line(Linelist。Item(currentindex)。EndPoint, Linelist。Item(currentindex)。StartPoint))

If Start_angle > End_angle Then

FisrtPoint = Linelist。Item(currentindex)。StartPoint

bopointlist。Add(FisrtPoint)

currentline = New Line(Linelist。Item(currentindex)。StartPoint, Linelist。Item(currentindex)。EndPoint)

point_mark = 0

Else

FisrtPoint = Linelist。Item(currentindex)。EndPoint

bopointlist。Add(FisrtPoint)

currentline = New Line(Linelist。Item(currentindex)。EndPoint, Linelist。Item(currentindex)。StartPoint)

point_mark = 1

End If

SearchPoint:

While True

Dim temp_arr As ArrayList = cross_arr。Item(currentindex)

Dim NextMark = point_mark

If point_mark > 1 Then

GoTo Finished

End If

If Not temp_arr。Contains(point_mark) Then

bopointlist。RemoveAt(bopointlist。Count - 1)

indexlist。RemoveAt(indexlist。Count - 1)

If indexlist。Count < 1 Then

GoTo SearchFirstPoint

Else

currentindex = indexlist。Item(indexlist。Count - 1)

Dim temppoint = Linelist。Item(indexlist。Item(indexlist。Count - 1))。GetClosestPointTo(bopointlist。Item(indexlist。Count - 1), False)

point_mark = Math。Round(Linelist。Item(indexlist。Item(indexlist。Count - 1))。GetParameterAtPoint(temppoint))

If temppoint。DistanceTo(Linelist。Item(indexlist。Item(indexlist。Count - 1))。StartPoint) <= temppoint。DistanceTo(Linelist。Item(indexlist。Item(indexlist。Count - 1))。EndPoint) Then

currentline = New Line(Linelist。Item(indexlist。Item(indexlist。Count - 1))。StartPoint, Linelist。Item(indexlist。Item(indexlist。Count - 1))。EndPoint)

Else

currentline = New Line(Linelist。Item(indexlist。Item(indexlist。Count - 1))。EndPoint, Linelist。Item(indexlist。Item(indexlist。Count - 1))。StartPoint)

End If

GoTo SearchPoint

End If

Else

Dim NextAngle As Double = -1

Dim NextPoint As Point3d

Dim NextIndex As Integer

Dim count_value As Integer = 0

Dim NonArray = New ArrayList()

For Each mark_value In temp_arr

If mark_value = point_mark Then

Dim temppoint As Point3d = Linelist。Item(count_value)。GetClosestPointTo(bopointlist。Item(indexlist。Count - 1), False)

Dim end_para As Integer

Try

Dim t_value = Linelist。Item(count_value)。GetParameterAtPoint(temppoint)

end_para = Linelist。Item(count_value)。EndParam - Math。Round(t_value)

Catch ex As Exception

If temppoint。DistanceTo(Linelist。Item(count_value)。StartPoint) < 0。001 Then

end_para = 1

Else

end_para = 0

End If

End Try

Dim end_point = Linelist。Item(count_value)。GetPointAtParameter(end_para)

Dim C_Angle = lineangle(currentline, New Line(bopointlist。Item(indexlist。Count - 1), end_point))

If C_Angle > NextAngle AndAlso Math。Abs(C_Angle - Math。PI * 2) > 0。01 Then

NextAngle = C_Angle

NextPoint = end_point

NextIndex = count_value

NextMark = end_para

ElseIf C_Angle > NextAngle AndAlso Math。Abs(C_Angle - Math。PI * 2) <= 0。01 Then

NonArray。Add(count_value)

End If

End If

count_value = count_value + 1

Next

point_mark = NextMark

If NonArray。Count > 0 Then

For Each Nonvalue In NonArray

temp_arr。Item(Nonvalue) = 2

Next

End If

temp_arr。Item(NextIndex) = 2

cross_arr。Item(currentindex) = temp_arr

cross_arr。Item(NextIndex)。Item(currentindex) = 2

currentindex = NextIndex

bopointlist。Add(NextPoint)

indexlist。Add(NextIndex)

If NextPoint。DistanceTo(Linelist。Item(currentindex)。StartPoint) <= NextPoint。DistanceTo(Linelist。Item(currentindex)。EndPoint) Then

currentline = New Line(Linelist。Item(currentindex)。StartPoint, Linelist。Item(currentindex)。EndPoint)

Else

currentline = New Line(Linelist。Item(currentindex)。EndPoint, Linelist。Item(currentindex)。StartPoint)

End If

If indexlist。Count > 1 AndAlso NextPoint。DistanceTo(FisrtPoint) < 0。05 Then

GoTo Finished

End If

End If

End While

End While

Finished:

If indexlist。Count < 1 Then

acDocEd。WriteMessage(“不存在封閉區域”)

Else

Dim FinalCount = 0

For Each point As Point3d In bopointlist

FinalBoPline。AddVertexAt(FinalCount, New Point2d(point。X, point。Y), 0, 0, 0)

FinalCount = FinalCount + 1

Next

FinalBoPline。Closed = True

End If

End Using

Return FinalBoPline

End Function

’交點打斷函式

Public Shared Function BlkInt2(ssedge As ArrayList, tr As Transaction) As ArrayList

Dim objpts As Dictionary(Of Curve, List(Of Double))

Dim linelist = New ArrayList()

objpts = New Dictionary(Of Curve, List(Of Double))(ssedge。Count)

‘#Region “邊界與打斷相同(最佳化)”

Dim cvs As Curve() = New Curve(ssedge。Count - 1) {}

For i As Integer = ssedge。Count - 1 To -1 + 1 Step -1

Dim cv As Curve = ssedge(i)

cvs(i) = cv

objpts。Add(cv, New List(Of Double)())

Next

For cur As Integer = cvs。Length - 1 To -1 + 1 Step -1

Dim cv1 As Curve = cvs(cur)

Dim cv1ps As List(Of Double) = objpts(cv1)

For n As Integer = cur To -1 + 1 Step -1

Dim cv2 As Curve = cvs(n)

Dim cv2ps As List(Of Double) = objpts(cv2)

Dim points As New Point3dCollection()

Dim pt1Param, pt2Param As Double

cv1。IntersectWith(cv2, Intersect。OnBothOperands, points, 0, 0)

Dim pt1 = New Point3d()

Dim pt2 = New Point3d()

For Each pt As Point3d In points

pt1 = cv1。GetClosestPointTo(pt, False)

pt1Param = cv1。GetParameterAtPoint(pt1)

If pt1Param > cv1。EndParam Then

cv1ps。Add(cv1。EndParam)

ElseIf pt1Param < 0 Then

cv1ps。Add(0)

Else

cv1ps。Add(cv1。GetParameterAtPoint(pt1))

End If

pt2 = cv2。GetClosestPointTo(pt, False)

pt2Param = cv2。GetParameterAtPoint(pt2)

If pt2Param > cv2。EndParam Then

cv2ps。Add(cv2。EndParam)

ElseIf pt2Param < 0 Then

cv2ps。Add(0)

Else

cv2ps。Add(cv2。GetParameterAtPoint(pt2))

End If

Next

pt1 = cv1。GetClosestPointTo(cv2。StartPoint, False)

If pt1。DistanceTo(cv2。StartPoint) < 0。1 Then

pt1Param = cv1。GetParameterAtPoint(pt1)

If pt1Param > cv1。EndParam Then

cv1ps。Add(cv1。EndParam)

ElseIf pt1Param < 0 Then

cv1ps。Add(0)

Else

cv1ps。Add(cv1。GetParameterAtPoint(pt1))

End If

End If

pt1 = cv1。GetClosestPointTo(cv2。EndPoint, False)

If pt1。DistanceTo(cv2。EndPoint) < 0。1 Then

pt1Param = cv1。GetParameterAtPoint(pt1)

If pt1Param > cv1。EndParam Then

cv1ps。Add(cv1。EndParam)

ElseIf pt1Param < 0 Then

cv1ps。Add(0)

Else

cv1ps。Add(cv1。GetParameterAtPoint(pt1))

End If

End If

pt2 = cv2。GetClosestPointTo(cv1。StartPoint, False)

If pt2。DistanceTo(cv1。StartPoint) < 0。1 Then

pt2Param = cv2。GetParameterAtPoint(pt2)

If pt2Param > cv2。EndParam Then

cv2ps。Add(cv2。EndParam)

ElseIf pt2Param < 0 Then

cv2ps。Add(0)

Else

cv2ps。Add(cv2。GetParameterAtPoint(pt2))

End If

End If

pt2 = cv2。GetClosestPointTo(cv1。EndPoint, False)

If pt2。DistanceTo(cv1。EndPoint) < 0。1 Then

pt2Param = cv2。GetParameterAtPoint(pt2)

If pt2Param > cv2。EndParam Then

cv2ps。Add(cv2。EndParam)

ElseIf pt2Param < 0 Then

cv2ps。Add(0)

Else

cv2ps。Add(cv2。GetParameterAtPoint(pt2))

End If

End If

Next

’#End Region

Next

For Each var As KeyValuePair(Of Curve, List(Of Double)) In objpts

Dim cv As Curve = var。Key

If var。Value。Count = 0 Then

Continue For

End If

If var。Value。Count = 1 AndAlso cv。IsPeriodic AndAlso cv。IsPersistent Then

Continue For

End If

var。Value。Sort()

Dim arrpt As Double() = New Double(var。Value。Count - 1) {}

var。Value。CopyTo(arrpt)

Dim pts As New DoubleCollection(arrpt)

Dim objs As DBObjectCollection = cv。GetSplitCurves(pts)

Dim brkn As Integer = 0

For Each dbobj As DBObject In objs

Dim brks As Curve = DirectCast(dbobj, Curve)

If cv。GetDistanceAtParameter(brks。EndParam) > 0。000001 Then

brkn += 1

linelist。Add(brks)

End If

Next

Next

Return linelist

End Function

標簽: item  NEW  Linelist  dim  add