Тема: Как получить длину линии?
Хочу написать макрос на VBA, суммирующий длины всех выделенных линий и полилиний. и не могу :(
Информационный портал для профессионалов в области САПР
Вы не вошли. Пожалуйста, войдите или зарегистрируйтесь.
Форумы CADUser → Программирование → VBA → Как получить длину линии?
Страницы 1
Чтобы отправить ответ, вы должны войти или зарегистрироваться
Хочу написать макрос на VBA, суммирующий длины всех выделенных линий и полилиний. и не могу :(
Готовыйй вариант не устроит?
http://dwg.ru/dwl/116
Немного не то. Мне нужно свойство или функция, возращающая длину полилинии или линии. Просто одно слово, а не целая готовая программа.
Ну а для полилинии?
для объекта по имени "AcDbLine" это "Length"
для объекта по имени "AcDbArc" это "ArcLength"
для объекта по имени "AcDbPolyline" подобных свойств нет!!!!
А что если полилинию скопировать, взорвать и сложить длины получившихся линий и окружностей?
а затем их удалить.
Но как, при этом, мне отследить все объекты после "взрыва"? Какой командой взорваный объект можно "загнать" в массив получившихся объектов?
Из хелпа
object.Length
object
Line, LightweightPolyline, Polyline, 3dPolyline
The object or objects this property applies to.
Length
object.Explode
возврашхает массив содержашхийй елементы взрываемого обььекта
Public Function PerimeterOb(Ob As AcadEntity) As Double Dim VarTyp As String VarTyp = TypeName(Ob) Select Case VarTyp Case "IAcadLWPolyline": PerimeterOb = PerimeterLWP(Ob) Case "IAcadCircle": PerimeterOb = PerimeterCirc(Ob) Case "IAcadLine": PerimeterOb = PerimeterLine(Ob) Case "IAcadArc": PerimeterOb = PerimeterArc(Ob) Case Else PerimeterOb = 0 End Select End Function Public Function PerimeterLWP(LWP As AcadLWPolyline) As Double Dim vrt As Variant Dim nn As Long, n As Long Dim vP As Double Dim t0(1) As Double, t1(1) As Double, tc(1) As Double Dim kr As Double, lseg As Double vP = 0 On Error Resume Next vrt = LWP.Coordinates If Err Then Err.Clear End If nn = UBound(vrt) For n = 0 To nn - 2 Step 2 t0(0) = vrt(n): t0(1) = vrt(n + 1) kr = LWP.GetBulge(n / 2) t1(0) = vrt(n + 2): t1(1) = vrt(n + 3) vP = vP + LenSegmPL(t0, t1, kr) Next n If LWP.Closed Then t0(0) = vrt(nn - 1): t0(1) = vrt(nn) kr = LWP.GetBulge(Int(nn / 2)) t1(0) = vrt(0): t1(1) = vrt(1) vP = vP + LenSegmPL(t0, t1, kr) End If PerimeterLWP = vP End Function Public Function PerimeterCirc(Cir As AcadCircle) As Double Dim vP As Double vP = 0 On Error Resume Next vP = Cir.Circumference If Err Then Err.Clear End If PerimeterCirc = vP End Function Public Function PerimeterLine(Line As AcadLine) As Double Dim vP As Double vP = 0 On Error Resume Next vP = Line.Length If Err Then Err.Clear End If PerimeterLine = vP End Function Public Function PerimeterArc(Arc As AcadArc) As Double Dim vP As Double vP = 0 On Error Resume Next vP = Arc.ArcLength If Err Then Err.Clear End If PerimeterArc = vP End Function
Да забыл!!! Тут еще используются:
Public Function LenSegmPL( _ ByVal t0 As Variant, ByVal t1 As Variant, ByVal kr As Double, _ Optional ta As Variant, Optional vR As Variant, _ Optional vS As Variant, Optional vTC As Variant) As Double Dim t2(1) As Double, t3 As Variant, tc As Variant Dim t4(1) As Double, t5 As Variant Dim dd As Double, d As Double, d1 As Double, sign As Integer Dim Alfa As Double, beta As Double, Gamma As Double, r As Double dd = Distance(t0, t1) d = dd / 2 d1 = d * kr If Abs(d1) >= Prec Then t2(0) = (t0(0) + t1(0)) / 2 t2(1) = (t0(1) + t1(1)) / 2 Alfa = AngleFromXAxis(t0, t1) d1 = d * (kr * kr - 1) / 2 / kr tc = PolarPoint(t2, Alfa - Pi_2, d1) r = Distance(t0, tc) Gamma = 4 * Atn(kr) sign = Sgn(kr) If Not IsMissing(ta) Then ta = Gamma If Not IsMissing(vR) Then vR = r If Not IsMissing(vS) Then vS = sign If Not IsMissing(vTC) Then vTC = tc LenSegmPL = Abs(Gamma) * r Else LenSegmPL = dd If Not IsMissing(ta) Then ta = Null If Not IsMissing(vR) Then vR = Null If Not IsMissing(vS) Then vS = Null If Not IsMissing(vTC) Then vTC = Null End If End Function Public Function AngleFromXAxis(t0 As Variant, t1 As Variant) Dim x As Double, y As Double x = t1(0) - t0(0): y = t1(1) - t0(1) If x >= Abs(y) Then AngleFromXAxis = Atn(y / x) ElseIf -x >= Abs(y) Then AngleFromXAxis = Pi + Atn(y / x) ElseIf y >= Abs(x) Then AngleFromXAxis = Pi_2 + Atn(-x / y) Else AngleFromXAxis = Pi_3 + Atn(-x / y) End If End Function
Еще функции Distance({}, {}) не хватает!
т.е. я вижу, что она встроенная, но у меня почему то, в VBA Автокаде её нет. Не знаете в чём может быть проблема?
В конечном итоге я обошелся без Distance()
и у меня получилось вот что:
Public Sub LenLine() Dim Obj As AcadEntity Dim SelSet As AcadSelectionSet Dim SumLen As Double Dim A As Long Dim ObjExpl() As AcadEntity On Error GoTo Control 'Ловим ошибку на тот случай, если пользователь нажмет "Esc" Set SelSet = ThisDrawing.SelectionSets.Add("Set") 'Создаем новый набор выбора, например с именем "Set" On Error GoTo 0 SelSet.SelectOnScreen 'Запрос на выбор примитивов If SelSet.Count = 0 Then GoTo Control For Each Obj In SelSet SumLen = SumLen + LenObj(Obj) Next Obj PrintMessage "Сумма длин " & SelSet.Count & " элементов = " & SumLen Control: SelSet.Delete 'Удаляем набор выбора End Sub Private Function LenObj(Obj As AcadEntity) As Double Dim Ln As AcadLine Dim Pl As AcadLWPolyline 'AcadPolyline Dim Ci As AcadArc Dim ObjExpl() As AcadEntity Dim A As Long If Obj.ObjectName = "AcDbLine" Then Set Ln = Obj LenObj = Ln.Length Set Ln = Nothing ElseIf Obj.ObjectName = "AcDbPolyline" Then Set Pl = Obj ObjExpl() = Pl.Explode For A = 0 To UBound(ObjExpl()) - 1 LenObj = LenObj + LenObj(ObjExpl(A)) ObjExpl(A).Delete Next A ObjExpl(A).Delete Set Pl = Nothing ElseIf Obj.ObjectName = "AcDbArc" Then Set Ci = Obj LenObj = LenObj + Ci.ArcLength Set Ci = Nothing Else MsgBox "Объект с именем " & Obj.ObjectName & " не включен в расчет", vbCritical End If 'Obj.Update'Обновляем объект End Function Public Sub PrintMessage(MessageString As String) Dim pEchoVal As Integer pEchoVal = ThisDrawing.GetVariable("CMDECHO") ThisDrawing.SetVariable "CMDECHO", 1 ThisDrawing.Utility.Prompt MessageString ThisDrawing.SetVariable "CMDECHO", pEchoVal End Sub
Прошу прощения, в коде есть ошибка в блоке:
ElseIf Obj.ObjectName = "AcDbPolyline" Then Set Pl = Obj ObjExpl() = Pl.Explode For A = 0 To UBound(ObjExpl()) - 1 LenObj = LenObj + LenObj(ObjExpl(A)) ObjExpl(A).Delete Next A ObjExpl(A).Delete Set Pl = Nothing
заменить на:
ElseIf Obj.ObjectName = "AcDbPolyline" Then Set Pl = Obj ObjExpl() = Pl.Explode For A = 0 To UBound(ObjExpl()) LenObj = LenObj + LenObj(ObjExpl(A)) ObjExpl(A).Delete Next A Set Pl = Nothing
Пользуйтесь!
Прошу прощения!!! У меня интернет не круглосуточный. Я не углядел отсутствие Distance.
Public Function Distance(ByVal t0 As Variant, ByVal t1 As Variant) As Double Distance = Sqr(((t1(0) - t0(0)) ^ 2) + ((t1(1) - t0(1)) ^ 2)) End Function
Это естественно всего лишь корень... Двумерная дистанция. Отмечу еще что использую и вычисление угла своей функцией а не AcadUtility.AngleFromXAxis, т.к. обращение к утилитам вызывает какие-то перемигивания в командной строке и замедляет прохождение больших циклов.
Я конечно же понимаю что мой скриптик довольно простенький и делитанский, но чего огород городить?.
Да и для понимания он лучше подходит.
Sub slozhenie_dlin_liniy() 'скриптик для сложения длин выделенных линий. Dim ssetObj As AcadSelectionSet Dim Items As AcadObject On Error GoTo end_prog Set ssetObj = ThisDrawing.SelectionSets.Add("NABOR1") ssetObj.SelectOnScreen For Each Items In ssetObj dlinna = dlinna + Items.Length Next a_11 = InputBox(" ", " ", dlinna) end_prog: ssetObj.Clear ssetObj.Delete End Sub
> Boxa
А проверить, если ли такой набор? А очистить его перед созданием?
И теперь - у меня в набор попали тексты, многострочные тексты, блоки со скрытыми атрибутами... Кад сказал Goodbye. И все.
Может, только у меня.
Да нет все правильно... никаких проверок нет. просто ты спрашивал как это сделать и я привел простейший вариант. Если так уж критично вставь проверку на наличие свойства ".Length"
(просто у меня линии для суммирования обычно вынесены в отдельный слой и вырубив все остальные я не глядя делаю выборку. На счет наличия такого набора объектов... а зачем проверять? В каждом скрипте название выборки уникально и выборка удаляется после завершения скрипта.)
Просто мне все это не очень надо (проверки), я не пишу законченные программы. вот слобать маленький скриптик для выполнения какой нибудь последовательности операций, это да. ИМХО на написание и отработку всяких условий и красивостей времени уходит больше чем на написание алгоритма того что нужно.
> Boxa
Я спрашивал? Я-то не спрашивал, а указывал на возможные трудности. А они могут быть - достаточно каду всего один раз (в момент работы VBA-макроса) сказать "ква". Или пользователю жать Esc до тех пор, пока клава на полу не окажется. А данный "скрипт" (буду пользоваться твоей терминологией) уже успел запуститься. Вот насчет хранения наборов я не знаю - может, они и хранятся в файле, может, нет. Лучше снести.
И смотри - тебе надо идти, вырубать отдельно слои (или использовать фильтры слоев - тоже песня та еще), а потом запускать на выполнение. Может, проще использовать фильтры?
> kpblc
ну в общем то ты прав во всем...
тока я скрипты для себя пишу и под свой стиль , свою манеру черчения. А если уж приходится делать что то для других, то да приходится вставлять 1001 проверку на правильность введеных данных, работать над удобством пользования скриптом... только все это не относится к скрипту сбацаному за минуту для выполнения какой то операции.
Хочу написать макрос на VBA, суммирующий длины всех выделенных линий и полилиний. и не могу :(
просто я посмотрел что предлагают другие и запостил самый простой скрипт, он не хороший не плохой, он ПРОСТОЙ и дальше человек разобравшись как это работает дополнит его как ему надо.
На этом считаю тему исчерпаной для обсуждения.
ЗЫ. Все что выше ИМХО и я не претендую на истину в последней инстанции.
> Boxa
Ну я надеюсь, я тебя не обидел?
Жалко, что здесь нет механизма подписей - я постоянно забываю добавлять "ИМХО" в конце.
Вот блин. Называется помог!!! Я, вообще-то, начинал на ЛИСПе, поэтому все привычные команды постарался оттуда вынести. Теперь это естественно целый модуль с всякими функциями и вынуть по быстрому со всеми увязками не так-то просто. ПоларПоинт это тоже всего лишь ПоларПоинт двумерный:
Public Function PolarPoint(ByVal t0 As Variant, ByVal ang As Double, _ ByVal Dist As Double, Optional Result) As Variant Dim vVal(2) As Double vVal(0) = t0(0) + Cos(ang) * Dist vVal(1) = t0(1) + Sin(ang) * Dist vVal(2) = 0 PolarPoint = vVal If Not IsMissing(Result) Then Result(0) = vVal(0) Result(1) = vVal(1) End If End Function
В качестве компенсации за такую "помощь" вот ещё функция для определения длины сегмента:
Public Function LenSegmPLWithTangents( _ Xs As Double, Ys As Double, _ Xe As Double, Ye As Double, _ kr As Double, _ sTg As Double, eTg As Double, _ Optional ta As Variant, Optional vR As Variant, _ Optional vS As Variant, Optional vTC As Variant) As Double '''''''''''''''''''''''''''''''''''''''''''''''''''''''''' Dim t0(1) As Double, t1(1) As Double Dim t2(1) As Double, t3 As Variant, tc As Variant Dim t4(1) As Double, t5 As Variant Dim dd As Double, d As Double, d1 As Double, sign As Integer Dim Alfa As Double, beta As Double, Gamma As Double, r As Double 'Если сегмент дуговой, то опциональные переменные будут заполнены: 'ta - полный угол дуги 'vR - радиус 'vS - знак кривизны выпуклости 'vTC - точка центра дуги t0(0) = Xs: t0(1) = Ys t1(0) = Xe: t1(1) = Ye dd = Distance(t0, t1) d = dd / 2 d1 = d * kr If d >= Prec Then If Abs(d1) >= Prec Then t2(0) = (t0(0) + t1(0)) / 2 t2(1) = (t0(1) + t1(1)) / 2 Alfa = AngleFromXAxis(t0, t1) d1 = d * (kr * kr - 1) / 2 / kr tc = PolarPoint(t2, Alfa - Pi_2, d1) r = Distance(t0, tc) Gamma = 4 * Atn(kr) sign = Sgn(kr) sTg = AngleTo_0_2pi(AngleFromXAxis(tc, t0) + sign * Pi_2) eTg = AngleTo_0_2pi(AngleFromXAxis(tc, t1) + sign * Pi_2) If Not IsMissing(ta) Then ta = Gamma If Not IsMissing(vR) Then vR = r If Not IsMissing(vS) Then vS = sign If Not IsMissing(vTC) Then vTC = tc LenSegmPLWithTangents = Abs(Gamma) * r Else sTg = AngleTo_0_2pi(AngleFromXAxis(t0, t1)) eTg = AngleTo_0_2pi(sTg) If Not IsMissing(ta) Then ta = Null If Not IsMissing(vR) Then vR = Null If Not IsMissing(vS) Then vS = Null If Not IsMissing(vTC) Then vTC = Null LenSegmPLWithTangents = dd End If Else LenSegmPLWithTangents = 0 End If End Function
Используется так:
Dim pD As Double, psTg As Double, peTg As Double, pTA, pR, pS, pTC Dim vXs As Double, vYs As Double, vXe As Double, vYe As Double, vBlg As Double ''''''''''''''''''''''''''''''''''' 'Тело цикла 'определяем для сегмента координаты стартовой точки vXs, vYs 'координаты конечной точки vXe, vYe, и кривизну vBlg pD = LenSegmPLWithTangents(vXs, vYs, vXe, vYe, vBlg, psTg, peTg, pTA, pR, pS, pTC) If Abs(pD) <= Prec Then 'короткий сегмент - ничего не делаем else If IsNull(pTC) Then 'Линейный сегмент 'Действия для линейного сегмента Else 'Дуговой сегмент 'Действия для дугового сегмента End If end if '''''''''''''''''''''''''''''''''''
Надеюсь, что теперь ничего не забыл. Ну а если забыл, так допишу. Всего хорошего.
Страницы 1
Чтобы отправить ответ, вы должны войти или зарегистрироваться
Форумы CADUser → Программирование → VBA → Как получить длину линии?
Форум работает на PunBB, при поддержке Informer Technologies, Inc