| Правила | Регистрация | Пользователи | Поиск | Сообщения за день | Все разделы прочитаны |  Справка по форуму | Файлообменник |

Вернуться   Форум DWG.RU > Программное обеспечение > Программирование > .NET > .NET Изобретаем велосипед, или как найти ближайшую вершину полилинии?

.NET Изобретаем велосипед, или как найти ближайшую вершину полилинии?

Ответ
Поиск в этой теме
Непрочитано 05.12.2013, 00:06 #1
.NET Изобретаем велосипед, или как найти ближайшую вершину полилинии?
La Persona
 
Чайник
 
Регистрация: 01.12.2011
Сообщений: 27

Доброго всем времени суток!
Подскажите решение вопроса - есть на полилинии некая точка, которая не является вершиной. Как найти ближайшую к этой точке вершину полилинии?
Либо можно оконкретить вопрос - при расстановке точек на полилинии должна проводиться проверка, чтобы точка находилась не ближе 49 м от любой вершины полилинии.
Сам я пытался сделать такую проверку, сравнивая GetDistAtPoint(tempPt) c расстоянием от начала полилинии до текущей предполагаемой точки. Однако не работает.
Буду признателен за помощь..


Код:
[Выделить все]
Imports System
Imports System.IO
Imports Autodesk.AutoCAD.Runtime
Imports Autodesk.AutoCAD.ApplicationServices
Imports Autodesk.AutoCAD.DatabaseServices
Imports Autodesk.AutoCAD.EditorInput
Imports Autodesk.AutoCAD.Geometry
Imports Autodesk.AutoCAD.GraphicsInterface


Public Class Class1
    <CommandMethod("AddCP")> _
    Public Sub AddCP()


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

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

        Using trAdding As Transaction = dbCurrent.TransactionManager.StartTransaction()

            Dim btTable As BlockTable
            btTable = trAdding.GetObject(dbCurrent.BlockTableId, OpenMode.ForRead)

            Dim acTypValAr(0) As TypedValue
            acTypValAr.SetValue(New TypedValue(DxfCode.Start, "LWPOLYLINE"), 0)


            Dim acSelFtr As SelectionFilter = New SelectionFilter(acTypValAr)

            Dim acSSPromt As PromptSelectionResult = Application.DocumentManager.MdiActiveDocument.Editor.GetSelection(acSelFtr)
            Dim acSSet As SelectionSet = acSSPromt.Value

            For Each acSSObj As SelectedObject In acSSet
                If Not IsDBNull(acSSObj) Then
                    Dim acLwPl As Polyline = TryCast(trAdding.GetObject(acSSObj.ObjectId, OpenMode.ForRead), Polyline)
                    Dim UseLength As Double = 0
                    Dim UseLengthGar As Double = 0
                    Dim InsPt As Point3d
                    Dim btrId As ObjectId
                    Dim btrModelSpace As BlockTableRecord
                    Dim btrRecord As BlockTableRecord
                    Dim brRefBlock As BlockReference
                    Dim arAttr As AttributeReference
                    Dim arAttrK As AttributeReference
                    Dim arAttrLen As AttributeReference
                    Dim adAttr As AttributeDefinition
                    Dim pref As String
                    Dim suff As String
                    Dim koordCP As String
                    Dim acPkTxt As DBText
                    Dim strColl As New Microsoft.VisualBasic.Collection()
                    Dim strCheck As New Microsoft.VisualBasic.Collection()
                    Dim tempColl1 As New Microsoft.VisualBasic.Collection()
                    Dim tempColl2 As New Microsoft.VisualBasic.Collection()
                    Dim i As Integer = 1
                    Dim acCirc As Circle

                    Dim pIntOpts1 As PromptIntegerOptions = New PromptIntegerOptions("")
                    pIntOpts1.Message = vbCrLf & "Минимальное расстояние между контрольными точками: "
                    pIntOpts1.AllowZero = False
                    pIntOpts1.AllowNegative = False
                    Dim pIntRes1 As Integer = Application.DocumentManager.MdiActiveDocument.Editor.GetInteger(pIntOpts1).Value

                    Dim pIntOpts2 As PromptIntegerOptions = New PromptIntegerOptions("")
                    pIntOpts2.Message = vbCrLf & "Максимальное расстояние между контрольными точками: "
                    pIntOpts2.AllowZero = False
                    pIntOpts2.AllowNegative = False
                    Dim pIntRes2 As Integer = Application.DocumentManager.MdiActiveDocument.Editor.GetInteger(pIntOpts2).Value

                    Dim diap As Integer = pIntRes2 - pIntRes1
                    InsPt = acLwPl.GetPointAtDist(UseLength)
                    acCirc = New Circle
                    acCirc.Center = InsPt
                    acCirc.Radius = 1

                    adAttr = New AttributeDefinition()
                    adAttr.Position = InsPt
                    adAttr.Tag = "PIKET"

                    Dim adAttrK As AttributeDefinition = New AttributeDefinition()
                    adAttrK.Position = InsPt
                    adAttrK.Tag = "Position"

                    Dim adAttrLen As AttributeDefinition = New AttributeDefinition()
                    adAttrLen.Position = InsPt
                    adAttrLen.Tag = "Length"

                    btrRecord = New BlockTableRecord()
                    btrRecord.Name = "control_point"
                    btTable.UpgradeOpen()

                    btrId = btTable.Add(btrRecord)
                    trAdding.AddNewlyCreatedDBObject(btrRecord, True)

                    btrRecord.AppendEntity(acCirc)
                    trAdding.AddNewlyCreatedDBObject(acCirc, True)

                    btrRecord.AppendEntity(adAttr)
                    trAdding.AddNewlyCreatedDBObject(adAttr, True)

                    btrRecord.AppendEntity(adAttrK)
                    trAdding.AddNewlyCreatedDBObject(adAttrK, True)

                    btrRecord.AppendEntity(adAttrLen)
                    trAdding.AddNewlyCreatedDBObject(adAttrLen, True)

                    If btTable.Has("ROUTEPOINT") Then
                        Dim btrWayP As BlockTableRecord = trAdding.GetObject(btTable("ROUTEPOINT"), OpenMode.ForRead)
                        Dim btrWayPIds As ObjectIdCollection = btrWayP.GetBlockReferenceIds(True, False)
                        For Each id As ObjectId In btrWayPIds
                            Dim bref As BlockReference = id.GetObject(OpenMode.ForWrite)

                            Dim tempInsPt As Point3d = bref.Position.TransformBy(bref.Ecs.Inverse())
                            Dim tempInsPtWCS As Point3d = tempInsPt.TransformBy(bref.Ecs)
                            Dim zero As Point3d = New Point3d
                            Dim tempPt As Point3d = zero - zero.TransformBy(bref.BlockTransform.Inverse()).GetAsVector()

                            UseLength = acLwPl.GetDistAtPoint(tempPt)
                            strCheck.Add(UseLength)

                            If Fix(UseLength / 100) < 10 Then
                                pref = "0" & Fix(UseLength / 100).ToString
                            Else
                                pref = Fix(UseLength / 100).ToString
                            End If

                            If Fix(UseLength - (Fix(UseLength / 100)) * 100) < 10 Then
                                suff = "0" & Fix(UseLength - (Fix(UseLength / 100)) * 100).ToString
                            Else
                                suff = Fix(UseLength - (Fix(UseLength / 100)) * 100).ToString
                            End If

                            arAttr = New AttributeReference()
                            arAttr.SetAttributeFromBlock(adAttr, bref.BlockTransform)
                            arAttr.TextString = pref & "+" & suff

                            arAttrLen = New AttributeReference()
                            arAttrLen.SetAttributeFromBlock(adAttrLen, bref.BlockTransform)
                            arAttrLen.TextString = UseLength.ToString

                            bref.AttributeCollection.AppendAttribute(arAttr)
                            trAdding.AddNewlyCreatedDBObject(arAttr, True)
                            bref.AttributeCollection.AppendAttribute(arAttrLen)
                            trAdding.AddNewlyCreatedDBObject(arAttrLen, True)

                            acPkTxt = New DBText()
                            acPkTxt.SetDatabaseDefaults()
                            acPkTxt.Position = New Point3d(tempPt.X + 5, tempPt.Y + 5, 0)
                            acPkTxt.TextString = "+" & suff
                            acPkTxt.Height = 5


                            btrModelSpace = trAdding.GetObject(btTable(BlockTableRecord.ModelSpace), OpenMode.ForWrite)
                            btrModelSpace.AppendEntity(acPkTxt)
                            trAdding.AddNewlyCreatedDBObject(acPkTxt, True)

                        Next
                    End If

                    UseLength = 0

                    While UseLength <= acLwPl.Length
                        InsPt = acLwPl.GetPointAtDist(UseLength)

                        For Each lambda As Double In strCheck
                            If Math.Abs(UseLength - lambda) < 49 Then
                                tempColl1.Add(True)
                            End If
                        Next

                        If Not tempColl1.Contains(True) Then

                            If Fix(UseLength / 100) < 10 Then
                                pref = "0" & Fix(UseLength / 100).ToString
                            Else
                                pref = Fix(UseLength / 100).ToString
                            End If

                            If Fix(UseLength - (Fix(UseLength / 100)) * 100) < 10 Then
                                suff = "0" & Fix(UseLength - (Fix(UseLength / 100)) * 100).ToString
                            Else
                                suff = Fix(UseLength - (Fix(UseLength / 100)) * 100).ToString
                            End If

                            acPkTxt = New DBText()
                            acPkTxt.SetDatabaseDefaults()
                            acPkTxt.Position = New Point3d(InsPt.X + 5, InsPt.Y + 5, 0)
                            acPkTxt.TextString = "+" & suff
                            acPkTxt.Height = 5

                            acCirc = New Circle()
                            acCirc.SetDatabaseDefaults()
                            acCirc.Center = InsPt
                            acCirc.Radius = 1

                            koordCP = Fix(InsPt.X).ToString & " " & Fix(InsPt.Y).ToString

                            strColl.Add(i.ToString & "," & Fix(InsPt.X).ToString & "," & Fix(InsPt.Y).ToString)

                            btrModelSpace = trAdding.GetObject(btTable(BlockTableRecord.ModelSpace), OpenMode.ForWrite)
                            btrModelSpace.AppendEntity(acPkTxt)
                            trAdding.AddNewlyCreatedDBObject(acPkTxt, True)

                            btrModelSpace.AppendEntity(acCirc)
                            trAdding.AddNewlyCreatedDBObject(acCirc, True)

                            brRefBlock = New BlockReference(InsPt, btrId)

                            btrModelSpace.AppendEntity(brRefBlock)
                            trAdding.AddNewlyCreatedDBObject(brRefBlock, True)

                            arAttr = New AttributeReference()
                            arAttrK = New AttributeReference()
                            arAttrLen = New AttributeReference()

                            arAttr.SetAttributeFromBlock(adAttr, brRefBlock.BlockTransform)
                            arAttrK.SetAttributeFromBlock(adAttrK, brRefBlock.BlockTransform)
                            arAttrLen.SetAttributeFromBlock(adAttrLen, brRefBlock.BlockTransform)

                            arAttr.TextString = pref & "+" & suff
                            arAttrK.TextString = koordCP
                            arAttrLen.TextString = UseLength.ToString

                            brRefBlock.AttributeCollection.AppendAttribute(arAttr)
                            trAdding.AddNewlyCreatedDBObject(arAttr, True)

                            brRefBlock.AttributeCollection.AppendAttribute(arAttrK)
                            trAdding.AddNewlyCreatedDBObject(arAttrK, True)

                            brRefBlock.AttributeCollection.AppendAttribute(arAttrLen)
                            trAdding.AddNewlyCreatedDBObject(arAttrLen, True)

                        End If
                       
                        UseLength = diap * Rnd() + pIntRes1 + UseLength
                        i = i + 1
                    End While

                    Dim optFlName As PromptStringOptions = New PromptStringOptions("")
                    optFlName.Message = "Укажите имя файла: "
                    Dim strFlName As String = "\" & edCurrent.GetString(optFlName).ToString & ".txt"

                    Dim mydocpath As String = Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments)
                    Dim tmpStr As String
                    Using sw As StreamWriter = New StreamWriter(mydocpath + strFlName, False)
                        For Each tmpStr In strColl
                            sw.WriteLine(tmpStr)
                        Next
                    End Using
                End If
            Next

            trAdding.Commit()
        End Using
    End Sub
End Class
Просмотров: 6207
 
Непрочитано 05.12.2013, 08:48
1 | #2
Boxa

КЖ; C#
 
Регистрация: 03.11.2005
Санкт-Петербург
Сообщений: 2,588


Цитата:
Сообщение от La Persona Посмотреть сообщение
Подскажите решение вопроса - есть на полилинии некая точка, которая не является вершиной. Как найти ближайшую к этой точке вершину полилинии?
1. Найти к какому участку полилинии принадлежит точка (перебираем вершины и считаем расстояние между смежными вершинами и сравниваем с суммой расстояний между заданной точкой и этими же смежными вершинами)
2. найти ближайшую вершину (сравниваем расстояние от точки до вершин участка полилинии и выбираем меньшее)

Примерный код функции поиска расстояний между двумя точками
Код:
[Выделить все]
    Public Function GetLength(ByVal varStart As Point3d, ByVal varEnd As Point3d) As Double
        Dim dblLen As Double
        On Error GoTo Err_Control
        dblLen = Math.Sqrt((varStart.X - varEnd.X) ^ 2 + _
        (varStart.Y - varEnd.Y) ^ 2 + _
        (varStart.Z - varEnd.Z) ^ 2)
        GetLength = dblLen
Exit_here:
        Exit Function
Err_Control:
        'MsgBox Err.Description
    End Function
ЗЫ.
Я думая что пишу ужасный код, но Вы меня превзошли.
Очень рекомендую заняться рефакторингом.
Boxa вне форума  
 
Непрочитано 05.12.2013, 09:09
#3
Кулик Алексей aka kpblc
Moderator

LISP, C# (ACAD 200[9,12,13,14])
 
Регистрация: 25.08.2003
С.-Петербург
Сообщений: 39,787


Я не очень понимаю необходимость первого шага... Одна сторона треугольника всегда будет не больше суммы длин двух других сторон. И еще момент - а как быть с дуговыми сегментами или сглаженными полилиниями?
__________________
Моя библиотека lisp-функций
---
Обращение ко мне - на "ты".
Все, что сказано - личное мнение.
Кулик Алексей aka kpblc вне форума  
 
Непрочитано 05.12.2013, 09:22
#4
Boxa

КЖ; C#
 
Регистрация: 03.11.2005
Санкт-Петербург
Сообщений: 2,588


Цитата:
Сообщение от Кулик Алексей aka kpblc Посмотреть сообщение
Одна сторона треугольника всегда будет не больше суммы длин двух других сторон.

AB= AC+BC - точка лежит на сегменте AB
BD <> BC+DC - точка не лежит на сегменте BD
Последовательно проходя по сегментам находим нужный.

Цитата:
Сообщение от Кулик Алексей aka kpblc Посмотреть сообщение
как быть с дуговыми сегментами или сглаженными полилиниями
Каюсь, забыл про них.
Boxa вне форума  
 
Непрочитано 05.12.2013, 09:28
#5
Кулик Алексей aka kpblc
Moderator

LISP, C# (ACAD 200[9,12,13,14])
 
Регистрация: 25.08.2003
С.-Петербург
Сообщений: 39,787


Понял, умолк Я-то по инерции подумал про реализации на .NET аналогов vlax-curve-getclosestpointto, vlax-curve-getclosestpointtoprojection, vlax-curve-getDistAtPoint и им подобным функциям Мне кажется, где-то подобные вопросы уже мелькали...
---
Добавлено: http://www.theswamp.org/index.php?to...2790#msg492790 - не то?
__________________
Моя библиотека lisp-функций
---
Обращение ко мне - на "ты".
Все, что сказано - личное мнение.
Кулик Алексей aka kpblc вне форума  
 
Автор темы   Непрочитано 05.12.2013, 10:03
#6
La Persona

Чайник
 
Регистрация: 01.12.2011
Сообщений: 27


теперь все работает как часы, всем премного благодарен )

----- добавлено через ~5 мин. -----
Цитата:
Сообщение от Кулик Алексей aka kpblc Посмотреть сообщение
а как быть с дуговыми сегментами или сглаженными полилиниями?
таких, слава богу, нет у меня ))

пытался через GetDistAtPoint сделать, но что-то не срослось у меня с логическими операциями

----- добавлено через ~8 мин. -----
Цитата:
Сообщение от Boxa Посмотреть сообщение
ЗЫ.
Я думая что пишу ужасный код, но Вы меня превзошли.
Очень рекомендую заняться рефакторингом.
Догадываюсь, что мой код ужасен и страшен ) прошу сильно не ругаться - я не программист, главное, чтоб работало ))
La Persona вне форума  
 
Непрочитано 05.12.2013, 10:15
1 | #7
Do$

AutoCAD/Civil3D LISP/C#
 
Регистрация: 15.08.2008
Санкт-Петербург
Сообщений: 1,702
Отправить сообщение для Do$ с помощью Skype™


Можно попробовать по другому. Есть такая вещь, как параметр линии (GetPointAtParam-GetParamAtPoint, GetDistAtParam-GetParamAtDist и т.п.). У полилинии в каждой вершине - целое значение параметра, между ними - дробное. К примеру, я беру точку на полилинии и нахожу ее параметр (GetParamAtPoint), предположим, что он равен 3.56. Это значит, что она лежит между вершинами с параметрами 3.0 и 4.0. Получаем расстояния с помощью GetDistAtParam и вычисляем нужные разности.
__________________
Толковый выбор приходит с опытом, а к нему приводит выбор бестолковый. (The Mechanic)
Do$ вне форума  
 
Непрочитано 05.12.2013, 10:16
#8
Boxa

КЖ; C#
 
Регистрация: 03.11.2005
Санкт-Петербург
Сообщений: 2,588


Рефа́кторинг или реорганизация кода — процесс изменения внутренней структуры программы, не затрагивающий её внешнего поведения и имеющий целью облегчить понимание её работы.

Как пример, вот этот код
Код:
[Выделить все]
 
If Fix(UseLength / 100) < 10 Then
                                pref = "0" & Fix(UseLength / 100).ToString
                            Else
                                pref = Fix(UseLength / 100).ToString
                            End If

                            If Fix(UseLength - (Fix(UseLength / 100)) * 100) < 10 Then
                                suff = "0" & Fix(UseLength - (Fix(UseLength / 100)) * 100).ToString
                            Else
                                suff = Fix(UseLength - (Fix(UseLength / 100)) * 100).ToString
                            End If
Можно заменить на:
Код:
[Выделить все]
pref = Format(Fix(UseLength / 100), "0#")
suff = Format(Fix(UseLength - (Fix(UseLength / 100)) * 100), "0#")
----- добавлено через ~4 мин. -----
Цитата:
Сообщение от Do$ Посмотреть сообщение
Можно попробовать по другому. Есть такая вещь, как параметр линии (GetPointAtParam-GetParamAtPoint, GetDistAtParam-GetParamAtDist и т.п.). У полилинии в каждой вершине - целое значение параметра, между ними - дробное. К примеру, я беру точку на полилинии и нахожу ее параметр (GetParamAtPoint), предположим, что он равен 3.56. Это значит, что она лежит между вершинами с параметрами 3.0 и 4.0. Получаем расстояния с помощью GetDistAtParam и вычисляем нужные разности.
Ух ты! Спасибо буду знать.
Еще одно уточнение, значит ли параметр 3,56, что указанная точка ближе к вершине с параметром 4?
Boxa вне форума  
 
Непрочитано 05.12.2013, 10:24
#9
Александр Ривилис

программист, рыцарь ObjectARX
 
Регистрация: 09.05.2005
Киев
Сообщений: 2,405
Отправить сообщение для Александр Ривилис с помощью Skype™


Цитата:
Сообщение от Boxa Посмотреть сообщение
Еще одно уточнение, значит ли параметр 3,56, что указанная точка ближе к вершине с параметром 4?
Да, т.к. параметр равномерен внутри сегмента.
Александр Ривилис вне форума  
 
Непрочитано 05.12.2013, 10:25
#10
Do$

AutoCAD/Civil3D LISP/C#
 
Регистрация: 15.08.2008
Санкт-Петербург
Сообщений: 1,702
Отправить сообщение для Do$ с помощью Skype™


Цитата:
Сообщение от Boxa Посмотреть сообщение
Еще одно уточнение, значит ли параметр 3,56, что указанная точка ближе к вершине с параметром 4?
На 99% уверен, что да
__________________
Толковый выбор приходит с опытом, а к нему приводит выбор бестолковый. (The Mechanic)
Do$ вне форума  
 
Автор темы   Непрочитано 05.12.2013, 10:25
#11
La Persona

Чайник
 
Регистрация: 01.12.2011
Сообщений: 27


Век живи - век учись... Впервые узнал о функции Format ) А я сижу велосипеды изобретаю..
La Persona вне форума  
 
Непрочитано 05.12.2013, 10:28
#12
Boxa

КЖ; C#
 
Регистрация: 03.11.2005
Санкт-Петербург
Сообщений: 2,588


это значит что для варианта
Цитата:
есть на полилинии некая точка, которая не является вершиной. Как найти ближайшую к этой точке вершину полилинии?
необходимо получить параметр этой точки на полилинии (GetParamAtPoint) и округлить до целого, так просто?
Boxa вне форума  
 
Непрочитано 05.12.2013, 10:37
#13
Кулик Алексей aka kpblc
Moderator

LISP, C# (ACAD 200[9,12,13,14])
 
Регистрация: 25.08.2003
С.-Петербург
Сообщений: 39,787


Boxa, как округлять будешь значение "3,5"?
__________________
Моя библиотека lisp-функций
---
Обращение ко мне - на "ты".
Все, что сказано - личное мнение.
Кулик Алексей aka kpblc вне форума  
 
Непрочитано 05.12.2013, 10:40
#14
Александр Ривилис

программист, рыцарь ObjectARX
 
Регистрация: 09.05.2005
Киев
Сообщений: 2,405
Отправить сообщение для Александр Ривилис с помощью Skype™


Цитата:
Сообщение от Boxa Посмотреть сообщение
необходимо получить параметр этой точки на полилинии (GetParamAtPoint) и округлить до целого, так просто?
Почти. Еще же нужно по округленному параметру получить точку вершины (используя GetPointAtParam)
Только учтите, что всё это хорошо будет работать только:
1. Если точка действительно лежит на полилинии
2. Полилиния несамопересекающаяся в этой точке.

----- добавлено через 34 сек. -----
Цитата:
Сообщение от Кулик Алексей aka kpblc Посмотреть сообщение
Boxa, как округлять будешь значение "3,5"?
По правилам округления.
Александр Ривилис вне форума  
 
Непрочитано 05.12.2013, 10:56
#15
Boxa

КЖ; C#
 
Регистрация: 03.11.2005
Санкт-Петербург
Сообщений: 2,588


Цитата:
Сообщение от Кулик Алексей aka kpblc Посмотреть сообщение
Boxa, как округлять будешь значение "3,5"?
В этом случае точка равноудалена от обоих вершин и ближайшей можно назвать любую.
Так что легко округлю =)
UseLength= Math.Round(UseLength, 0)
Boxa вне форума  
Ответ
Вернуться   Форум DWG.RU > Программное обеспечение > Программирование > .NET > .NET Изобретаем велосипед, или как найти ближайшую вершину полилинии?

Размещение рекламы
Опции темы Поиск в этой теме
Поиск в этой теме:

Расширенный поиск


Похожие темы
Тема Автор Раздел Ответов Последнее сообщение
Lisp найти радиус полилинии julia170895 LISP 2 10.11.2013 11:34
LISP. Как найти точку пересечения полилинии и сплайна или другой полилинии? LastGraff LISP 11 09.09.2011 13:23