Nodları Birleştirme – VB.NET AutoCAD Araçları Nasıl Yaratılır

Noktaları Birleştir –Ben neden mi bahsediyorum? Bu benim kısa bir süre içerisinde yazmayı planladığım betiğe “script” vermeyi düşündüğüm isim. Bu çok basit bir fikir olmakla birlikte; bana adım adım yeni bir AutoCAD aracı kodu yazma fırsatı sunuyor.

Ön Tasarım

Yeni bir AutoCAD aracı kodu yazmak için,  gereken ilk şey bir fikrinizin olmasıdır. Bu ilk gereklilik çok basit görünmekle birlikte, açık, net bir fikre sahip olmak çok önemlidir. Kod yazma, belirli ve öngörülebilir sonuçlar üreteceği için, neye ulaşmayı amaçladığınız çok önemlidir.

Noktaları Birleştir betiğinin bir seri noktayı veri olarak alan ve bu noktaların her birinden geçen en kısa güzergâhı bir sürekli çizgi “polyline” olarak çizen bir araç olmasını hedefliyorum.

Birinci adım yeni fikir üzerine biraz kafa yormak olacak. Ben “Bu sonuca manüel olarak nasıl ulaşırım?” sorusunu soruyorum.

Şayet noktaları belirli bir şekilde (en kısa güzergâhı ile) birleştirmemiz gerekmeseydi, hiç şüphesiz, birleştirme işlemini aşağıdaki şekildeki gibi sonlandırırdık.

Sekil-1

En uzun güzergâh

Şekilde de görüldüğü üzere bu en uzun güzergâhtır (hattır). Bunun üzerine biraz daha düşündükçe tüm veri noktaları arasındaki mesafeleri hesaplayarak bu mesafelerden en kısa olanını bularak işe başlamak gerektiğini fark ettim. Bu sürekli çizgimiz “polyline” için, bir başlangıç parçası teşkil edecekti ve daha sonra başlangıç ve bitiş noktalarının yakınlığına sürekli çizginin “polyline” tepe noktalarını “vertices” ekleyebilecektim.

Temel olarak, en kısa çizgiyi bulma:

Sekil-2

  1. Adım: En kısa Güzergâh

Daha sonra, ilk çizginin uç noktalarından herhangi birine en yakın noktayı arama:

 Sekil-3

2.    Adım: En kısa ikinci Güzergâh

Tekrar ikinci çizginin uç noktalarından herhangi birine en yakın noktayı arama:

 Sekil-4

3. Adım: En kısa üçüncü Güzergâh

Böylece en kısa güzergâhı bulmuş oluruz.

Projeyi Kurma

Bugüne kadarki tecrübelerim bana gösterdi ki, VBA AutoCAD ile direkt olarak etkileşime girme bakımından en basit ve kolay yoldur. Aynı amaca NET ile ulaşmak için, çok daha karmaşık olan ve daha fazla kod içeren doküman veri tabanı ile etkileşime girmemiz gereklidir.

Ok, ilk olarak projemizi ayarlamak zorundayız. Ben bu ayar işleri için, AutoCAD uygulamalarında kullanmak üzere daha önceden bir şablon hazırlamıştım ve bu şablonu seçtim. .NET’i kullanmak için, projenizi doğru olarak ayarlamak zorundasınız– şayet bu ayarları kolayca yapmak istiyorsanız, dün yayınlamış olduğum VB.NET AutoCAD Şablonu isimli makalemi okumanızı şiddetle tavsiye ediyorum.

Tasarımı Kodlama

Adım 1 – Seçim Yaratma

Projeyi ayarladıktan sonra, uygulamamız içerisinde yapmamız gereken ilk şey daha sonra kullanmak zorunda olacağımız seçim setini yaratmaktır. Biz kullanıcının Nodları Birleştir komutunda kullanılacak olan noktaları seçebilmesini istiyoruz. Aşağıdaki kod ana alt programınıza gider – şayet bazı şeylerin nasıl birleştirildiğine eminolamıyorsanız, üzülmenize gerek yok; – bu kodun tamamını aşağıda sizlere veriyorum.

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

'Kurulum

Dim ed As Editor = Application.DocumentManager.MdiActiveDocument.Editor

'Bizim filitre girişlerimizi Bildirme

Dim values() As TypedValue = {

New TypedValue(DxfCode.Start, "POINT")

}

'Bizim değerlerimizi kullanarak filitre Yaratma

Dim sfilter As New SelectionFilter(values)

Seçim seçeneklerini Ayarlama

Dim SelOpts As New PromptSelectionOptions()

SelOpts.MessageForAdding = "En kısa güzergahı bulmak için, noktaları seçin: "

SelOpts.AllowDuplicates = True

'Seçimi Yapma

Dim res As PromptSelectionResult = ed.GetSelection(SelOpts, sfilter)

'Şayet kullanıcı seçim yapmaktan daha başka bir şey yaparsa (ESC tuşuna basmak gibi), komutu Durdurma

If Not res.Status = PromptStatus.OK Then Return

'Kullanıcının seçimini esas alarak seçim setini Yaratma

Dim ss As Autodesk.AutoCAD.EditorInput.SelectionSet = res.Value

'Daha kolay döngü oluşturabilmek için, seçim setindeki nesnelerin kimliklerinden bir dizi Yaratma

Dim idarray As ObjectId() = ss.GetObjectIds()

Yani ilk olarak Düzenleyici “Editor” olarak bilinen bir nesneye atıfda bulunan ed değişkenini yaratıyoruz. Bu bize daha sonra kullanacağımız birçok faydalı fonksiyona sahiptir.

Daha sonra, kullanıcının seçebileceği şeyleri kısıtlamak için kullanacağımız filitreyi yaratıyoruz. Sonuç olarak, biz kullanıcının sadece AutoCAD noktalarını seçebilmesini sağlamaya çalışıyoruz.

Sonraki adım kullanıcıya seçim yapmasını söylemektir – bununla birlikte, bunu yapabilmek için, öncelikle bazı ayarları yapmalıyız. Kullanıcıya görüntületmek istediğimiz mesaj gibi bazı seçim uyarı seçeneklerini ayarlamak zorundayız. Bu ayarlar tamamlanıp aktive edildikten sonra, bu ayarları içeren SelOpts değişkenini ve düzenleme nesnemiz için GetSelection metodunu çağırmada kullanılacak olan filitremizi içeren sfilter değişkenini kullanabiliriz. Bu kullanıcıya ekran üzerinden istediği nesneyi seçme olanağını sağlayacaktır ve kullanıcının eylem lerinin sonucu bir PromptSelectionResult nesnesi içeren res değişkeninde depolanacaktır.

Kullanıcının yapması muhtemel olan tüm eylemlerine karşı dikkatli olmamız gerekmektedir. Örneğin, kullanıcı herhangi bir zaman Esc tuşuna basabilir. Şayet bu gerçekleşirse, bunu bilmemiz ve başka bir eylem gerçekleştirmemiz gerekecektir. İşte bu kullanıcının eylemi res değişkeni tarafından yakalanacaktır. Kullanıcının bize verdiği veri ne olursa olsun, res.Status değişkenini kullanarak bunu öğrenebiliriz. Şayet res.Status  değişkeni “OK” değerini almışsa, kullanıcının kendisinden beklendiği gibi bir seçim yaptığını anlarız. Şayet daha farklı bir eylem gerçekleşirse (diğer bir değişle res.Status “NOT OK” değerini almışsa), kullanıcının gereken seçimi yapmadığını anlarız ve Return komutu ile alt yordamdan çıkmamız gerekecektir.

Nihayetinde, şayet kullanıcı seçimi yaparsa, bu seçimi bizim için daha kullanılabilir olan – seçim seti biçimine dönüştürmek isteriz. Daha sonra, seçim setindeki seçilmiş olan nesnelerin nesne özelliklerini öğreneceğiz. Bu yol, kodumuz içerisinde daha ilerilerde bize seçilen her bir nesnenin özelliklerini öğrenmemize ve bu özellikleri kullanmamıza olanak sağlayacaktır.

Adım 2 – İşlem Haraketlerini “Transactions” Kullanma

.NET kullanarak AutoCAD için uygulama geliştirme işlem hareketlerindeki değişiklikleri bir dokümana aktarmamızı gerektirmektedir. Çizimimiz içerisinde herhangi bir nesneye herhangi bir değişiklik yapmak için, bir işlem hareketleri nesnesi başlatmamız, çizimimizde değişiklikleri yapmamız, bu değişiklikleri işlem hareketleri nesnesine eklememiz, işlem hareketlerini işlememiz ve daha sonra işlem hareketlerini sonlandırmamız gerekmektedir. Bu iş uzun soluklu olmakla birlikte; aslında işin doğası gereği başarıldığında gurur duymanızı da içermektedir. Örnek verecek olursak, AutoCAD’in UNDO komutu tek tek değişikliklerden ziyade tüm işlem listesini geri alacaktır. Diğer bir örnekte, şayet kodunuzda herhangi bir yerde bir hata varsa (Allah Korusun!!!), tüm işlemler listesi hükümsüz olacak ve yarısı eskisi gibi diğer yarı ise, istenen değişiklikler yarım yapılmış olarak çizilecektir.

Fakat her ne olursa olsun, bir işlemler listesi kullanmak zorundasınız – ve bunun nasıl olacağı işte aşağıdadır:

1

2

3

4

5

6

7

8

9

10

11

12

'Aktif dokümanın veri tabanına bağlantı Yaratma

Dim db As Database = Application.DocumentManager.MdiActiveDocument.Database

'Bir işlem Hareketleri Yönetici Nesnesi Yaratma

Dim tm As Autodesk. AutoCAD.DatabaseServices.TransactionManager = db.TransactionManager

'Bir İşlem Hareketini Başlatma

Dim myT As Transaction = tm.StartTransaction()

YAPILACAK İŞLEM!

'İşlem Hareketini Görevlendirme

myT.Commit()

'İşlem Hareketlerimizi Sonlandırma

myT.Dispose()

Yani, birinci adım aktif dokümanın veri tabanına atıfta bulunan db değişkenini yaratmaktır. Sonrasında, İşlem Hareketleri Yöneticisi veri tabanı “db.TransactionManager” nesnesine atıfta bulunan tm değişkenini yaratırız. Daha sonra ise, sadece İşlem Hareketini Başlat “tm.StartTransaction” nesnesini çağırır ve sonuç İşlem Hareketi nesnesini myT değişkenimizde depolarız. Kolay değil mi?

YAPILACAK İŞLEM!” satırından sonra, sadece İşlem Hareketini görevlendirir ve daha sonra bu İşlem Hareketini sonlandırırız. Şayet herhangi bir değişiklik yaparsanız, bu değişiklikler çiziminizde görülebilir hale geleceklerdir.

Adım 3 – Çizime Değişiklikleri Yaptırma

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

'id Dizisi ile aynı ebatta bir coord Dizisi Yaratma

Dim points(idarray.GetUpperBound(0)) As DBPoint

'DBPoint Nesnelerinin Konumlarını Temsil eden point2d Nesneleri ile Koordinat Dizisini Elde etme

Dim n As Long

For n = 0 To idarray.GetUpperBound(0)

points(n) = tm.GetObject(idarray(n), OpenMode.ForRead, True)

Next

'İki Koordinat arasındaki en kısa Çizgiyi Bulma, Bu çizgiyi temsilen bir Sürekli Çizgi Yaratma ve

Koordinatlar dizisinden bu iki Koordinatı Silme

Dim pl As Polyline = GetShortestLine(points)

Dim TimeToExit As Boolean = False

Do

TimeToExit = AppendPoint(pl, points)

Loop Until TimeToExit

'Sürekli Çizgiyi Model Alana Ekleme

AddToModelSpace(db, myT, pl)

Şayet ilk kod kadar kolay bir kod olacağını düşünüyorduysanız, sizi hayal kırıklığına uğrattığım için üzgünüm… Bu kod bir takım başka fonksiyonları da çağırmaktadır. Bu fonksiyonları ayrı ayrı ele alacağız; fakat çizim içerisinde değişiklik yapmanın ana fikri aşağıdadır:

  • İlk olarak, tüm DBPoints elemanlarının bir listesini alırız. Bunu yapabilmek için, id dizimiz içerisindeki tüm elemanları bir dögü içerisinde ele alırız ve her bir DBPoint nesnesini points() olarak adlandırılan yeni bir diziye ekleriz.
  • Sonra, birbirine en yakın olan iki noktayı buluruz ve bu iki noktayı Sürekli Çizgimizin ilk parçasını yaratmak için, kullanırız. İşte bu GetShortestLine fonksiyonunun yaptığıdır.
  • Daha sonra, mevcut Sürekli Çizgimizin herhangi bir uç noktasına en en yakın noktaytı kullanarak geri kalan noktaları da Sürekli Çizgiye eklemek isteriz. Bu işlemi geride hiç nokta kalmayıncaya dek tekrarlarız.
  • Son olarak, Sürekli Çizgimizi (pl değişkenine aktarmıştık) işlemler listesine ekleriz.

Bu yüksek seviyeli (öncelikli) bir işlemdir. En kısa çizgiyi bulma ve sürekli çizgiye “polyline” nokta ekleme gibi spesifik işleri ana alt yordamdan ayırmak faydalıdır. Bu alt yordamı daha okunabilkir kılacaktır– yüksek seviyeli (öncelikli) işlemleri detaylara boğulmadan görebiliriz.

Adım 4 – En kısa çizgiyi elde etme

Bu kod kesinlikle göründüğü kadar karmaşık değildir.

 

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

Private Function GetShortestLine(ByRef points() As DBPoint) As Polyline

Dim n As Long

Dim m As Long

'Elde edilmesi gereken bilgiler

Dim basePoint As DBPoint

Dim endPoint As DBPoint

Dim shortestDist As Double = 1.0E+300 'Çok büyük bir sayı!

'Nokta çiftlerinin tüm kombinasyonlarını Döngüleme ve En Kısa mesafeye sahip Nokta Çiftini Bulma

For n = 0 To points.GetUpperBound(0)

For m = n + 1 To points.GetUpperBound(0)

Dim tmpDist As Double

tmpDist = points(n).Position.DistanceTo(points(m).Position)

'Şayet bu şimdiye kadarki en kısa mesafe ise, Güncelleme Yapma

If tmpDist < shortestDist Then

shortestDist = tmpDist

basePoint = points(n)

endPoint = points(m)

End If

Next

Next

'En kısa Mesafeyi oluşturan Noktaları Sürekli Çizgiye “Polyline” Ekleme

Dim pl As Polyline = New Polyline

pl.AddVertexAt(0, basePoint.Position.Convert2d(New Plane), 0, 0, 0)

pl.AddVertexAt(1, endPoint.Position.Convert2d(New Plane), 0, 0, 0)

'Tekrar Kullanılmamaları için basePoint ve endPoint değişkenlerinin Değerlerini Noktalar Dizisinden Silme

RemovePoint(points, basePoint)

RemovePoint(points, endPoint)

Return pl

End Function

Temelde, bu fonksiyon noktaları tek tek ele almakta ve o noktanın diğer tüm noktalara olan mesafesini hesaplayarak bu hesap sonuçlarını kıyaslamaktadır. Herhangi iki nokta arasında en kısa mesafeyi oluşturan iterasyon bulunan en kısa mesafe olarak hatırlanacaktır. Bu kodda çalışan ana mekanizma iki For Next döngüsünün kombinasyonudur. Birinci For Next döngüsü n değişkeninin değerini 0 (sıfır) ile noktalar dizisinin eleman sayısı arasında tekrarlamaktadır. Yani şayet 10 nokta varsa, n değişkeni 0 (sıfır) ile 9 arasında değer alacaktır. İkinci For Next döngüsü m değişkeninin değerini n+1 ile noktalar dizisinin eleman sayısı arasında tekrarlamaktadır. Yani, n değişkeninin 0 (sıfır) değerini alması durumunda m değişkeni 1 den 9 a kadar dögü yapacaktır. Buraya kadarki kod sadece yeni karşılaştırmaları yapmamız içindi.– örneğin, aynı nokta oldukları için, points(0) değişkeni ile points(0) değişkenini karşılaştırmak istemeyiz. Bu yüzden, iç döngüyü n+1 değerinden başlatıyoruz. n ve m değişkenlerinin kombinasyonlarının her zaman emsalsiz olmasını ve tüm nokta çiftleri kombinasyonlarını içermesini isteriz. İşte bu For Next döngü çiftinin bize sunduğu imkândır.

For Next döngüleri tamamlandıktan sonra, en kısa mesafeleri yaratan noktaları bulmuş oluruz. Artık yapmamız gereken bu iki noktayı başlangıç ve bitiş noktası olarak kabul eden bir sürekli çizgi “polyline” yaratmaktır. Yani yeni bir sürekli çizgi “polyline” nesnesi yaratacağız ve doğru pozisyonlarda (örneğin, başlangıç noktası basePoint değişkeni için 0 ve bitiş noktası endPoint değişkeni için 1) bu sürekli çizgi “polyline” nesnesine kırılma noktaları “vertices” ekliyeceğiz. Bu işlem iki noktayı birleştiren bir sürekli çizgi “polyline” yaratacaktır.

Son olarak, hali hazırda sürekli çizgimiz “polyline” içinde olan noktaları bir daha kullanmamamız gerektiği için, kullanılan noktaları points() dizisinden silmek isteriz. Bu işi yapabilmek için, başka bir fonksiyon kullanıyoruz.

Adım 5 –VB.NET’deki diziden Öğe Silme

VB.NET’te diziden bir elemanı çıkarmak için yerel bir fonksiyon bulunmamaktadır; Bu yüzden bu işi kendimiz yapmak zorundayız, yani diziden bir elemanı çıkarmak için bir fonksiyon yaratmak zorundayız. Bu fonksiyon oldukça basit bir fikre dayanmaktadır:

Sekil-5 

Yani, 0’dan (sıfırdan) dizinin eleman sayısına kadar olan döngüyü çalıştırıyoruz veçıkartmak istediğimiz elemanın sıra numarasını elde ettiğimiz zaman, bu elemanı dizinin bir sonraki elemanı üzerine yazdırıyoruz ve bu noktadan itibaren sıralı tüm elemanları bir sonraki eleman olarak yazdırmaya devam ediyoruz.

İşte bu işlem için kod aşağıdadır:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

Private Function RemovePoint(ByRef points() As DBPoint, ByRef remPoint As DBPoint) As Boolean

Dim n As Long

Dim newUpperBound As Long = points.GetUpperBound(0) - 1

Dim pointFound As Boolean

' removePoint nesnesi bulunana kadar noktalar dizisinin elemanlarını Yineleme ve daha sonra sonraki Noktaları

geriye İteleme

For n = 0 To newUpperBound

If Not pointFound Then

If points(n) Is remPoint Then

pointFound = True

End If

End If

If pointFound Then

points(n) = points(n + 1)

End If

Next

'Dizinin yeni Ebatını Ayarlama, Dizinin son Elemanını Silme

ReDim Preserve points(newUpperBound)

If newUpperBound = -1 Then

Return True

Else

Return False

End If

End Function

Bu kodda son etap sadecedizinin ebatını önceki ebatından daha kısa olan 1( bir) değerine yeniden düzenlemektir. Bu işlem artık ihtiyaç duyulmayacak olan son değeri kırpıp atacağı için, bu değeri dizinin sondan bir önceki değeri olarak kopyalamamız gerekecektir.

Nihayet, dizinin üst sınırı -1 değerine ulaştığında, dizide artık hiçbir değer kalmamış olacaktır. Bu durumda, daha sonra daha fazla nokta aramayı durdurucu bir anahtar olarak kullanacağımız RemovePoints değişkenini TRUE değeri ile geri döndüreceğiz.

Adım 6 – Noktaları Sürekli Çizginin “Polyline” Sonuna İlave Etme

Çizimimize yaptıracağımız son adım noktaları sürekli çizgimizin “polyline” sonuna eklemek olacaktır. Bu işlem de diğer alt yordam – en yakın noktayı aramak için, noktaları tek tek incelemek ve sonrasında noktayı sürekli çizgiye ekleme alt yordamı – ile benzer prensipte çalışmaktadır. Bu alt yordam sürekli çizgiye “polyline” tek bir nokta ekleyecek ve bu noktayı points() dizisinden çıkartacaktır.

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

Private Function AppendPoint(ByRef pl As Polyline, ByRef points() As DBPoint) As Boolean

Dim startPoint As Point2d = pl.StartPoint.Convert2d(New Plane)

Dim endPoint As Point2d = pl.EndPoint.Convert2d(New Plane)

Dim nearestPoint As String = ""

Dim shortestDist As Double = 1.0E+300 'A very very big number!

Dim remPoint As DBPoint

Dim n As Long

For n = 0 To points.GetUpperBound(0)

Dim targetPoint As Point2d

targetPoint = points(n).Position.Convert2d(New Plane)

Dim tmpDist As Double

tmpDist = startPoint.GetDistanceTo(targetPoint)

If tmpDist < shortestDist Then

shortestDist = tmpDist

nearestPoint = "startpoint"

remPoint = points(n)

End If

tmpDist = endPoint.GetDistanceTo(targetPoint)

If tmpDist < shortestDist Then

shortestDist = tmpDist

nearestPoint = "endpoint"

remPoint = points(n)

End If

Next

Select Case nearestPoint

Case "startpoint"

pl.AddVertexAt(0, remPoint.Position.Convert2d(New Plane), 0, 0, 0)

Case ("endpoint")

pl.AddVertexAt(pl.NumberOfVertices, remPoint.Position.Convert2d(New Plane), 0, 0, 0)

Case Else

Err.Raise(0, , "nearestPoint not set!")

End Select

Return RemovePoint(points, remPoint)

End Function

Daha önce bahsettiğimiz gibi, dizide nokta kalmadığı zaman RemovePoints değişkeni TRUE değerini geri döndürecektir. Bu TRUE veya FALSE sinyali bu fonksiyonu tekrar geri getitecek olup; böylece bu son noktanın eklenip eklenmediğini bilebileceğiz. Bu makalemdeki kodun önceki bölümlerinde bulunan Do – While döngüsüne ve TimeToExit değişkenine bakın.

Adım 7 – Model alana “Model space” Sürekli çizgi “polyline” Ekleme

Son alt yordam sadece elemanları bu elemanların işlemler listesine düzgünce eklenip eklenmediğini de kontrol ederek Model alana eklemektedir:

 

1

2

3

4

5

6

7

8

9

10

Private Sub AddToModelSpace(ByVal db As Database, ByVal myT As Transaction, ByVal ent As Entity)

'Model alan “Model space” Blok Tablo Kaydını Açma

Dim acBT As BlockTable = db.BlockTableId.GetObject(OpenMode.ForRead)

Dim BTR As BlockTableRecord

BTR = acBT(BlockTableRecord.ModelSpace).GetObject(OpenMode.ForWrite)

'Elemanı Model alan “Model space” Blok Tablo Kaydına Ekleme

BTR.AppendEntity(ent)

'Elemanı işlemler Listesine Ekleme

myT.AddNewlyCreatedDBObject(ent, True)

End Sub

Projeyi Derleme

Şayet her şey doğru olarak kodlandıysa, artık projeyi kaydedip; bir dll dosyasına derlemeniz gerekmektedir! Daha sonra bu dll dosyasını AutoCAD’e yüklemek için, ister komut ismini ister alt yordamınızda belirlediğiniz komut ismini girip NETLOAD komutunu kullanabilirsiniz.

Sekil-6

Nodları Birleştir

Kaynak Dosyaları

Aşağıdaki rar dosyası içerisine –sizin projenizde işlerin ters gitme ihtimaline karşı bu proje için tüm kaynak dosyalarını sizler için ekledim. Kullandığım komut ismi JOINTHEDOTS dır.

jointhedots

Kaynak Kod

Ayrıca projenin tüm kaynak kodunuda aşağıda veriyorum:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

72

73

74

75

76

77

78

79

80

81

82

83

84

85

86

87

88

89

90

91

92

93

94

95

96

97

98

99

100

101

102

103

104

105

106

107

108

109

110

111

112

113

114

115

116

117

118

119

120

121

122

123

124

125

126

127

128

129

130

131

132

133

134

135

136

137

138

139

140

141

142

143

144

145

146

147

148

149

150

151

152

153

154

Imports Autodesk.AutoCAD.DatabaseServices

Imports Autodesk.AutoCAD.Runtime

Imports Autodesk.AutoCAD.Geometry

Imports Autodesk.AutoCAD.ApplicationServices

Imports Autodesk.AutoCAD.EditorInput

Imports Autodesk.AutoCAD.Colors

Public Class Class1

<CommandMethod("JoinTheDots")> _

Public Sub JoinTheDots()

'Kurulum

Dim ed As Editor = Application.DocumentManager.MdiActiveDocument.Editor

'Filitre Girişlerimizi Deklare etme

Dim values() As TypedValue = {

New TypedValue(DxfCode.Start, "POINT")

}

'Değerlerimizi kullanarak Filitreyi Yaratma

Dim sfilter As New SelectionFilter(values)

'Seçim seçeneklerini Ayarlama

Dim SelOpts As New PromptSelectionOptions()

SelOpts.MessageForAdding = "En kısa güzergahı bulmak için, Noktaları seçin:"

SelOpts.AllowDuplicates = True

'Seçimi Yapma

Dim res As PromptSelectionResult = ed.GetSelection(SelOpts, sfilter)

'Şayet kullanıcı ( ESC tuşuna basmak gibi) seçim yapmaktan başka bir şey yaparsa, kodu Durduma

If Not res.Status = PromptStatus.OK Then Return

'Create a selection set based on the user's selection

Dim ss As Autodesk.AutoCAD.EditorInput.SelectionSet = res.Value

'Seçim setimi kolayca döngü ile Kontrol edebilmek için, Seçim setinden nesne özelliklerinin dizisini Yaratma

Dim idarray As ObjectId() = ss.GetObjectIds()

'Create a link to the active document's database

Dim db As Database = Application.DocumentManager.MdiActiveDocument.Database

'İşler Yöneticisi Nesnesini Yaratma

Dim tm As Autodesk.AutoCAD.DatabaseServices.TransactionManager = db.TransactionManager

'İşlemler Listesini Başlatma

Dim myT As Transaction = tm.StartTransaction()

'Create a coord array, the same size as the idarray

Dim points(idarray.GetUpperBound(0)) As DBPoint

'point2d Nesneleri ile DBPoint  Nesnelerinin Lokasyonlarını sunan Koordinatlar dizisini Elde etme

Dim n As Long

For n = 0 To idarray.GetUpperBound(0)

points(n) = tm.GetObject(idarray(n), OpenMode.ForRead, True)

Next

'İki Koordinat tarafından teşkil edilen en kısa çizgiyi Bulma, bu çizgiyi referans alarak bir Sürekli Çizgi Yaratma

've bu iki koordinatı Koordinatlar dizisinden Silme

Dim pl As Polyline = GetShortestLine(points)

Dim TimeToExit As Boolean = False

Do

TimeToExit = AppendPoint(pl, points)

Loop Until TimeToExit

'Add the polyline to modelspace

AddToModelSpace(db, myT, pl)

'İşlemler listesini Yapma

myT.Commit()

'İşlemler listemizi Sonlandırma

myT.Dispose()

End Sub

Private Function AppendPoint(ByRef pl As Polyline, ByRef points() As DBPoint) As Boolean

Dim startPoint As Point2d = pl.StartPoint.Convert2d(New Plane)

Dim endPoint As Point2d = pl.EndPoint.Convert2d(New Plane)

Dim nearestPoint As String = ""

Dim shortestDist As Double = 1.0E+300 'A very very big number!

Dim remPoint As DBPoint

 

Dim n As Long

For n = 0 To points.GetUpperBound(0)

Dim targetPoint As Point2d

targetPoint = points(n).Position.Convert2d(New Plane)

Dim tmpDist As Double

tmpDist = startPoint.GetDistanceTo(targetPoint)

If tmpDist < shortestDist Then

shortestDist = tmpDist

nearestPoint = "startpoint"

remPoint = points(n)

End If

tmpDist = endPoint.GetDistanceTo(targetPoint)

If tmpDist < shortestDist Then

shortestDist = tmpDist

nearestPoint = "endpoint"

remPoint = points(n)

End If

Next

Select Case nearestPoint

Case "startpoint"

pl.AddVertexAt(0, remPoint.Position.Convert2d(New Plane), 0, 0, 0)

Case ("endpoint")

pl.AddVertexAt(pl.NumberOfVertices, remPoint.Position.Convert2d(New Plane), 0, 0, 0)

Case Else

Err.Raise(0, , "nearestPoint not set!")

End Select

Return RemovePoint(points, remPoint)

End Function

Private Function GetShortestLine(ByRef points() As DBPoint) As Polyline

Dim n As Long

Dim m As Long

'Info that needs to be captured

Dim basePoint As DBPoint

Dim endPoint As DBPoint

Dim shortestDist As Double = 1.0E+300 'Çok büyük bir sayı!

'Nokta çiftlerinin her kombinasyonunu İnceleme ve en kısa mesafeye sahip nokta çiftini Bulma

For n = 0 To points.GetUpperBound(0)

For m = n + 1 To points.GetUpperBound(0)

Dim tmpDist As Double

tmpDist = points(n).Position.DistanceTo(points(m).Position)

'If this is the shortest distance so far, update

If tmpDist < shortestDist Then

shortestDist = tmpDist

basePoint = points(n)

endPoint = points(m)

End If

Next

Next

'En kısa mesafeyi oluşturan noktaları yeni sürekli çizgiye “polyline” Ekleme

Dim pl As Polyline = New Polyline

pl.AddVertexAt(0, basePoint.Position.Convert2d(New Plane), 0, 0, 0)

pl.AddVertexAt(1, endPoint.Position.Convert2d(New Plane), 0, 0, 0)

'Tekrar kullanılmasınlar diye, basePoint ve endPoint değişkenlerini Noktalar Dizisinden Silme

RemovePoint(points, basePoint)

RemovePoint(points, endPoint)

Return pl

End Function

Private Function RemovePoint(ByRef points() As DBPoint, ByRef remPoint As DBPoint) As Boolean

Dim n As Long

Dim newUpperBound As Long = points.GetUpperBound(0) - 1

Dim pointFound As Boolean

'removePoint değişkeni bulunana kadar noktalar dizisini Yineleme, kalan noktaları dizide aşağı kaydırma

For n = 0 To newUpperBound

If Not pointFound Then

If points(n) Is remPoint Then

pointFound = True

End If

End If

If pointFound Then

points(n) = points(n + 1)

End If

Next

'Dizinin son elemanını atarak dizinin yeni ebatını Ayarlama

ReDim Preserve points(newUpperBound)

If newUpperBound = -1 Then

Return True

Else

Return False

End If

End Function

Private Sub AddToModelSpace(ByVal db As Database, ByVal myT As Transaction, ByVal ent As Entity)

'Open the ModelSpace Block Table Record

Dim acBT As BlockTable = db.BlockTableId.GetObject(OpenMode.ForRead)

Dim BTR As BlockTableRecord

BTR = acBT(BlockTableRecord.ModelSpace).GetObject(OpenMode.ForWrite)

'Elemanı Model alan Blok Tablo Kaydına Ekleme

BTR.AppendEntity(ent)

'Add the entity to the transaction

myT.AddNewlyCreatedDBObject(ent, True)

End Sub

End Class

Bu makalemdeki bilgilerin AutoCAD’de VB.NET kullanımı ile ilgili olarak sizlere faydalı olduğunu umud ediyorum. – inşallah sizlerde vakit kaybetmeksizin kendi araçlarınızı yaratmaya başlarsınız.

Ayrıca, bu şekilde bir kodu yazmak size zor geldiyse, umutsuzluğa düşmeyin. Kod yazmak biraz tecrübe biraz da zaman gerektirmektedir. Benim bu kodu ilk deneyişte mükemmel bir şekilde yazdığımı düşünüyorsanız, TEKRAR DÜŞÜNÜN! Bu kodu yazmam birçok deneme sonucunda sabırla ve ısrarla çalışmam neticesinde mümkün oldu.