(изменено: Александр Ривилис, 17 ноября 2010г. 12:10:04)

Re: Можно ли ускорить выполнение программы VBA

Владимир Линейцев пишет:

Мне как-то сказали, что в ACAD 2011 уже VBA нет, там Net. Это правда?

Не совсем. В AutoCAD 2011 он устанавливается отдельно с сайта Autodesk ( http://usa.autodesk.com/adsk/servlet/it … eID=123112 ). Но очень скоро его не будет совсем.

Владимир Линейцев пишет:

Тяжело ли адаптировать свои программы на Net?

Насколько сложно - не скажу (на VBA и VB.NET я не пишу). Посмотри ролик VBA -> VB.NET по-русски
Есть еще такая утилита для перевода VBA->VB6/VB.NET: http://download.autodesk.com/media/adn/ … verter.zip

Re: Можно ли ускорить выполнение программы VBA

<quote>
Владимир Линейцев пишет:
Тяжело ли адаптировать свои программы на Net?
</quote>
Совсем нет. Только я бы рекомендовал совсем уходить от com api, а пользовать net api.

Re: Можно ли ускорить выполнение программы VBA

Владимир пишет:

Только я бы рекомендовал совсем уходить от com api, а пользовать net api.

Это не всегда возможно. Некоторые методы есть только в COM, а в .NET их не перевели.
И в части функций .NET не работает или работает некорректно. Какие именно функции сейчас уже не вспомню.

Re: Можно ли ускорить выполнение программы VBA

Странно, Microsoft в своем MS Office сохраняет и развивает VBA (VBA 7), а Autodesk отказывается.

(изменено: Александр Ривилис, 17 ноября 2010г. 12:19:46)

Re: Можно ли ускорить выполнение программы VBA

Похоже, что Microsoft в очередной раз изменила свою политику на диаметрально противоположную:
Вот информация с блога одного из сотрудников Microsoft:

While it’s true that VBA isn't supported in the latest version of Office for the Mac and the VBA licensing program did close to new customers last year, we have no plans to remove VBA from future versions of Office for Windows. We understand that VBA is a critical capability for large numbers of our customers; accordingly, there is no plan to remove VBA from future versions of Excel.

Вот информация с сайта Autodesk:

Microsoft made the decision to stop offering VBA distribution licenses to new customers as of July 1, 2007 and they have expressed that there are no plans to provide VBA product enhancements in the future.  As a result of this, though Autodesk will continue to “unofficially” support VBA in its 2011 products, software developers are strongly encouraged to base all future Microsoft Windows based development for AutoCAD based products on the Microsoft .NET Framework (VB .NET, C#, managed C++ etc).

Так что Microsoft пока оставляет VBA в Microsoft Office, но не будет лицензировать (читай: продавать лицензии) сторонним разработчикам (читай: Autodesk)
IMHO.

Re: Можно ли ускорить выполнение программы VBA

Согласно алгоритма Александра Ривилиса начал реализовывать способ двоичного поиска на VBA. По шагам пишу так:
1. нашел в сортированных массивах индексы координат расчетной точки P через двоичный поиск;
2. уменьшая или увеличивая индексы на 1 выполнил 4 проверки по коодинатам и определил нижние и верхние  границы координат в сортированных массивах по X и по Y, в центре которого находится точка P;
3. в двух последовательных циклах определил список точек лежащих внутри границ координат по оси X и по оси Y
4. т.к. получились повторы точек (одна и таже точка находилась в двух разных сорт массивах), то выполнил сортировку индексов точек массива в пункте 3
5. удалил повторения (хотя как раз они и будут находится в квадрате RxR) и точки за пределами круга R

На 25000 точек время выбора составило 8 мин 40 сек. Это пока только чистый выбор без всяких навесков. С навесками напишу попозже.
Как ускорить мой алгоритм? Где у меня не правильно, если сравнить с алгоритмом Александра Ривилиса. Или дело в медленности самого VBA?

Александр Ривилис пишет:

Возможно чуть видоизмененный. Если нужно - выложу завтра кусочек кода на C++.


Александр, выложите пожалуйста кусочек кода с выбором точек.

(изменено: Александр Ривилис, 2 декабря 2010г. 00:38:09)

Re: Можно ли ускорить выполнение программы VBA

Владимир Линейцев пишет:

Александр, выложите пожалуйста кусочек кода с выбором точек.

О! Проснулся! smile Мне теперь нужно будет этот код еще найти...
Пока выложи свой код, а мы его покритикуем.

Владимир Линейцев пишет:

На 25000 точек время выбора составило 8 мин 40 сек.

А твой старый алгоритм сколько на это тратил времени?

(изменено: Владимир Линейцев, 2 декабря 2010г. 01:17:44)

Re: Можно ли ускорить выполнение программы VBA

По поводу навесков и всего остального. С навесками получилось 9 мин 06 сек. Экономия времени на лицо - почти в 7 раз. Раньше этот процесс занимал 62 мин. Это здорово. Но все же...может можно еще быстрее?

Это общий код без сортировки координатных массивов. Массив TrackAll(m)(j) многослойный. Всего слоев KolTrack + 1.

    For m = 0 To KolTrack + 1
        For j = 0 To UBound()
            ' Поиск id точки mj в сортированных массивах координат
            Xsort = Replace(Format(CDbl(TrackAll(m)(j)(1)), "0.000"), ",", "")
            Ysort = Replace(Format(CDbl(TrackAll(m)(j)(2)), "0.000"), ",", "")
            mjFormat = Format(m + j / 1000000, "000.000000")
            Xmj = CDec(Xsort & mjFormat)  ' значение в сортированном массиве по X
            Ymj = CDec(Ysort & mjFormat)  ' значение в сортированном массиве по Y
            idPntX = Find2Id(xSortFull, Xmj)
            idPntY = Find2Id(ySortFull, Ymj)
            ' Определение id точек-соседей в квадрате Rn x Rn вокруг точки mj в сортированных массивах координат
            Rn = 255
            idXmin = 0: idXmax = UBound(xSortFull)
            If idPntX > 0 Then
                idXmin = idPntX - 1
                Do While Xmj - xSortFull(idXmin) < Rn * 1000000
                    idXmin = idXmin - 1
                    If idXmin < 0 Then Exit Do
                Loop
                idXmin = idXmin + 1
            End If
            If idPntX < UBound(xSortFull) Then
                idXmax = idPntX + 1
                Do While xSortFull(idXmax) - Xmj < Rn * 1000000
                    idXmax = idXmax + 1
                    If idXmax > UBound(xSortFull) Then Exit Do
                Loop
                idXmax = idXmax - 1
            End If
            idYmin = 0: idYmax = UBound(ySortFull)
            If idPntY > 0 Then
                idYmin = idPntY - 1
                Do While Ymj - ySortFull(idYmin) < Rn * 1000000
                    idYmin = idYmin - 1
                    If idYmin < 0 Then Exit Do
                Loop
                idYmin = idYmin + 1
            End If
            If idPntY < UBound(ySortFull) Then
                idYmax = idPntY + 1
                Do While ySortFull(idYmax) - Ymj < Rn * 1000000
                    idYmax = idYmax + 1
                    If idYmax > UBound(ySortFull) Then Exit Do
                Loop
                idYmax = idYmax - 1
            End If
            ' Суммирование точек в границах -Rn .. +Rn по обоим координатам в один массив
            ReDim IdPntAll(0)
            For idX = idXmin To idXmax
                idmj = xSortFull(idX) - 1000 * Fix(xSortFull(idX) / 1000)
                ReDim Preserve IdPntAll(idX - idXmin): IdPntAll(UBound(IdPntAll)) = Abs(idmj)
            Next idX
            a = idXmax - idXmin + 1
            For idY = idYmin To idYmax
                idmj = ySortFull(idY) - 1000 * Fix(ySortFull(idY) / 1000)
                ReDim Preserve IdPntAll(a + idY - idYmin): IdPntAll(UBound(IdPntAll)) = Abs(idmj)
            Next idY
            ' Быстрая сортировка точек по пути m
            SList = IdPntAll                 ' формирование массива данных быстрой сортировки SList
            Stack1 = SList                   ' присвоение размерности массиву Stack1
            Call QuickSort(0, UBound(SList)) ' Do the Quicksort - процедура быстрой сортировки (линейный массив)
            IdPntAll = SList
            ' Удаление повторов точек и точек R>Rn
            Temp = IdPntAll
            ReDim IdPntAll(0): i = 0
            For k = 0 To UBound(Temp)
                If k = 0 Then a = Temp(k) - 1 Else a = Temp(k - 1)
                If Temp(k) <> a Then
                    m1 = Int(Temp(k)): j1 = Int(1000000 * (Temp(k) - m1))
                    dX = TrackAll(m1)(j1)(1) - TrackAll(m)(j)(1)
                    dY = TrackAll(m1)(j1)(2) - TrackAll(m)(j)(2)
                    If dX * dX + dY * dY < Rn * Rn And m1 <= KolTrack Then ' проверка внутри круга
                        ReDim Preserve IdPntAll(i): IdPntAll(UBound(IdPntAll)) = Temp(k)
                        i = i + 1
                    End If
                End If
            Next k

        Next j
    Next m

Re: Можно ли ускорить выполнение программы VBA

Сделай таймер, внутри пустой цикл где-нибудь на 1 лям.
Внутрь цикла поставь свой любимый UBound() для какого-нибудь массива .
1. Замерь время.
2. Закомментируй UBound() и снова замерь время

...разница времени сразу должна навести тебя на мысль  ;)

(изменено: Александр Ривилис, 2 декабря 2010г. 09:36:00)

Re: Можно ли ускорить выполнение программы VBA

Обратил внимание, что ты активно используешь ReDim Preserve внутри вложенного цикла. Думаю, что и на ней могут быть существенные потери времени. По этому поводу есть статья The ReDim Preserve Performance Trap с подзаголовком ReDim Preserve as a Performance Killer

Re: Можно ли ускорить выполнение программы VBA

Владимир Линейцев пишет:

' Суммирование точек в границах -Rn .. +Rn по обоим координатам в один массив

Отказался в этом пункте кода от ReDim Preserve, т.к. в этом месте размеры массива определены его границами и получил 9.06-8.15=51 сек экономии времени. От другого ReDim Preserve в пункте "' Удаление повторов точек и точек R>Rn" отказаться видимо нельзя т.к. размеры нового массива заранее неизвестны.

Можно ли численную строку формата "1,000001" разбить на две целые составляющие m1=1 и j1=1 быстрее чем это у меня реализовано в коде
m1 = Int(Temp(k)): j1 = Int(1000000 * (Temp(k) - m1))  ?

Re: Можно ли ускорить выполнение программы VBA

Владимир Линейцев пишет:

От другого ReDim Preserve в пункте "' Удаление повторов точек и точек R>Rn" отказаться видимо нельзя т.к. размеры нового массива заранее неизвестны.

Тут ты не прав. Ты можешь его создать сразу таким размером, чтобы помещались все точки.

Re: Можно ли ускорить выполнение программы VBA

Александр Ривилис пишет:

Ты можешь его создать сразу таким размером, чтобы помещались все точки.

Как это сделать? В одном цикле подсчитать сколько будет элементов в новом массиве, создать массив нужного размера ReDim (0 to N) и в другом цикле его заполнить?

(изменено: Александр Ривилис, 3 декабря 2010г. 11:39:39)

Re: Можно ли ускорить выполнение программы VBA

Владимир Линейцев пишет:

Как это сделать? В одном цикле подсчитать сколько будет элементов в новом массиве, создать массив нужного размера ReDim (0 to N) и в другом цикле его заполнить?

Сделай его величиной равной количеству всех точек (у тебя в данном случае кажется их 25000). Когда подсчитаешь сколько точек действительно в него попадает и внесешь их в массив - уменьшишь размер массива до этого значения (хотя можно и не уменьшать).

Re: Можно ли ускорить выполнение программы VBA

Уменьшить массив можно наверное так ReDim IdPntAll(0 to N-1)?
И еще этот массив мне нужен временно, т.к. на основе его данных будет выполнено разделение точек по слоям. Применительно к железнодорожной тематике: соседи вокруг расчетной точки P - все путевые точки IdPntAll, а слои нового массива IdTrackAll - кол-во путей и кол-во точек в каждом их них. И чтобы построить новый многослойный массив мне наверное потребуется выволнить еще несколько ReDim Preserve, потому как неизвестно сколько будет путей-соседей и сколько в каждом из них точек в радиусе R метров.
Вот этот новый массив соседних путей IdTrackAll будет подгружен в каждую точку P общего массива TrackAll для дальнейшего его использования. Для чего мне это нужно? Чтобы в дальнейшем определить в междупутье каких путей находится точка P, а также определить пикетаж этой точки и расстояние до этих соседних (ближайших) путей.

Re: Можно ли ускорить выполнение программы VBA

Владимир Линейцев пишет:

Уменьшить массив можно наверное так ReDim IdPntAll(0 to N-1)?

Ты меня совсем запутал. Допустим у тебя всего точек N (это все, которые в принципе могут быть соседями). Создаешь массив iArr размером N. Затем вычисляешь реальных соседей и заполняешь последовательно массив iArr от 0 до M-1 (M - количество реальных соседей). После этого ты можешь (при желании) уменьшить массив до M. Т.е.: ReDim iArr(0 to M-1). Как-то так.

Re: Можно ли ускорить выполнение программы VBA

Когда я написал предыдущее свое сообщение, то понял что еще больше могу ускорить процесс своих вычислений, отказавшись от временного массива точек-соседей, т.к. это был всего лишь промежуточный итог, чтобы объяснить свою задачу здесь на форуме. Конечный этап моих поисков - получить не массив точек-соседей, а массив ж.д.путей-соседей вблизи расчетной точки P.

Владимир Линейцев пишет:

Вот этот новый массив соседних путей IdTrackAll будет подгружен в каждую точку P общего массива TrackAll для дальнейшего его использования. Для чего мне это нужно? Чтобы в дальнейшем определить в междупутье каких путей находится точка P, а также определить пикетаж этой точки и расстояние до этих соседних (ближайших) путей.

В результате получил еще получил 8.15-6.02=2.13 сек экономии времени, т.к. убрал некоторые ReDim Preserve и лишние вычисления.
НО... Далее начал наворачивать свою программу.
Хочу добавить сетку координат на чертеж с наперед заданным шагом, как правило, 100 м. Мои 25000 точек - это 40.5 км трассы железной дороги с общим направлением на северо-восток. Так вот, написав простую процедуру рисования координатных крестов, получил сплошное заполнение крестами всего чертежа от Xmin,Ymin до Xmax,Ymax, что как-бы скрыло полезную информацию на чертеже. Это мне не понравилось.
Мне нужно было координатные кресты расположить вблизи трассы железной дороги и опять же не далее чем R метров от главного ж.д.пути (чтобы при удалении группы лишних крестов случайно не удалить еще чего-нибудь с чертежа). Попробовал все кресты в диапазоне от Xmin,Ymin до Xmax,Ymax пропустить через выше созданный алгоритм. Затраты времени около 40 минут, т.к. самих крестов оказалось 188х300=56400 шт. Непреемлемо для меня! Здесь же попробовал поэкспериментировать с ReDim Preserve.

Александр Ривилис пишет:

ты активно используешь ReDim Preserve внутри вложенного цикла. Думаю, что и на ней могут быть существенные потери времени.

Получилось что при формировании массива координатных крестов с ReDim Preserve времени тратилось меньше на 1 секунду.
В конечном счете я нашел правильный алгоритм и для этой задачи, сократив количество крестов до 2200 шт вблизи ж.д. В результате время счета увеличилось на 1.04 мин и составило 6.02+1.04=7.06 мин. Это здОрово! В дальнейшем еще попытаюсь сократить время счета.

Re: Можно ли ускорить выполнение программы VBA

Поколдовал как-то еще над алгоритмом и получил вместо 7.06 мин не более 3-х минут.

Оказалось что конкретное время счета зависит от положения линейного объекта относительно координатных осей. Например, если объект вытянут вдоль одной из осей, то время что-то около 2.20 минут, а если объект расположен под 45 градусов, то время составило примерно 2.45 минут.