программный выбор рамкой

Автор Тема: программный выбор рамкой  (Прочитано 13310 раз)

0 Пользователей и 2 Гостей просматривают эту тему.

Оффлайн Николай ГорловАвтор темы

  • ADN
  • *
  • Сообщений: 238
  • Карма: 34
программный выбор рамкой
« : 20-12-2017, 16:21:27 »
Задача такая: рисовать точки в определенной области. Но перед отрисовкой проверить, есть ли уже в указанных координатах нарисованная точка (из условия - все нужные слои включены). Ну и изначально участок, на котором планируется рисовать много-много :) точек может лежать за пределами видимости экрана.
Вот исходя из этих начальных условий, решить есть ли в указанных координатах точка или нет можно двумя (вот больше не придумал) способами:
1. последовательный перебор всех объектов чертежа в поисках AcDbPoint, ну и если нашли, то проверить координаты.
2. программный выбор рамкой (формируется массив точек вокруг исходной точки и acedSSGet(_T("_cp")... в помощь)

У первого варианта есть один существенный недостаток - чем больше объектов в чертеже, тем больше тратится времени на поиск одной точки (даже если в первый пробег по базе сформировать массив всех известных AcDbPoint, а потом искать чисто в нём)
Второй вариант работает на порядок быстрей (где-то раз в 10-15 на чертеже с большим количеством объектов). НО... не всегда работает, как показала практика. А тестовый пример всегда НЕ работает :)

Итак по поводу тестового примера. Первоначально идет зуммирование рамкой, чтоб вся требуемая область была видна на экране, а потом идет в цикле acedSSGet
Так вот, если зуммирование идет внутри моей команды, причем не важно, вызывается оно через acedCommand или с использованием автокадовского ActiveX, acedSSGet всегда возвращает RTERROR. Если же чертеж отзуммировать как нужно через меню автокада, а потом вызвать мою команду (в которой убрать строчки, отвечающие за зуммирование), то acedSSGet всегда работает правильно.

И вот тут вопрос: это лечится? :) Нужен обязательный зум внутри команды.

PS: тестовый проект прилагается. Тестировал в 2014x64 и в 2017x64. Результат одинаковый. В коде есть оба варианта зума для текстирования

Оффлайн Александр Ривилис

  • Administrator
  • *****
  • Сообщений: 13882
  • Карма: 1787
  • Рыцарь ObjectARX
  • Skype: rivilis
Re: программный выбор рамкой
« Ответ #1 : 20-12-2017, 16:37:38 »
Так вот, если зуммирование идет внутри моей команды, причем не важно, вызывается оно через acedCommand или с использованием автокадовского ActiveX, acedSSGet всегда возвращает RTERROR.
А зуммирование при этом происходит или нет?
Не забывайте про правильное Форматирование кода на форуме
Создание и добавление Autodesk Screencast видео в сообщение на форуме
Если Вы задали вопрос и на форуме появился правильный ответ, то не забудьте про кнопку Решение

Оффлайн Николай ГорловАвтор темы

  • ADN
  • *
  • Сообщений: 238
  • Карма: 34
Re: программный выбор рамкой
« Ответ #2 : 20-12-2017, 16:45:20 »
Цитировать
А зуммирование при этом происходит или нет?
естественно.

Как я тестировал.
вариант 1. вариант с activex (в проекте уже настроен этот вариант)
рисует быстро. зуммирование происходит. под дебагом возврат acedSSGet - RTERROR. команду запускал дважды. получал два набора точек

вариант 2. вариант с acedCommand (в проекте раскоментарить и закоментировать activex вариант)
рисует быстро. зуммирование происходит. под дебагом возврат acedSSGet - RTERROR. команду запускал дважды. получал два набора точек

вариант 3. сохранил чертеж с варианта1 или варианта2, не важно. главное, что область рисования уже отзумирована. удалил оттуда все точки. в проекте закоментировал оба варианта зума. также два запуска команды. рисует медленней (минуты полторы). после двух запусков получил 1 набор точек. под дебагом acedSSGet выдает RTNORM

Оффлайн Александр Ривилис

  • Administrator
  • *****
  • Сообщений: 13882
  • Карма: 1787
  • Рыцарь ObjectARX
  • Skype: rivilis
Re: программный выбор рамкой
« Ответ #3 : 20-12-2017, 16:51:03 »
И привязки отключал?
Не забывайте про правильное Форматирование кода на форуме
Создание и добавление Autodesk Screencast видео в сообщение на форуме
Если Вы задали вопрос и на форуме появился правильный ответ, то не забудьте про кнопку Решение

Оффлайн Николай ГорловАвтор темы

  • ADN
  • *
  • Сообщений: 238
  • Карма: 34
Re: программный выбор рамкой
« Ответ #4 : 20-12-2017, 16:54:08 »
"узел" выключен. чертеж новый. сейчас отключил все. не помогло.
я даже пыль с монитора стряхнул, но на результат это не повлияло :)

Оффлайн Александр Ривилис

  • Administrator
  • *****
  • Сообщений: 13882
  • Карма: 1787
  • Рыцарь ObjectARX
  • Skype: rivilis
Re: программный выбор рамкой
« Ответ #5 : 20-12-2017, 16:55:20 »
Может тогда сделать однократно _Zoom _All и не мучаться?
Не забывайте про правильное Форматирование кода на форуме
Создание и добавление Autodesk Screencast видео в сообщение на форуме
Если Вы задали вопрос и на форуме появился правильный ответ, то не забудьте про кнопку Решение

Оффлайн Николай ГорловАвтор темы

  • ADN
  • *
  • Сообщений: 238
  • Карма: 34
Re: программный выбор рамкой
« Ответ #6 : 20-12-2017, 17:00:21 »
так а зум и делается однократно перед циклом.
Код - C++ [Выбрать]
  1. acedCommandS(RTSTR, _T("_zoom"), RTSTR, _T("_w"), RTSTR, _T("7367820.0,5376960.0"), RTSTR, _T("7371560.0,5371400.0"), 0);
  2. acedCommandS(RTSTR, _T("_zoom"), RTSTR, _T("_s"), RTSTR, _T("0.7X"), 0);

просто потом пользователю б еще и увидеть, что оно нарисовало. тем более, что в новом чертеже _Zoom _All точно не поможет. а в старом чертеже рисование может проходить не внутри уже нарисованных объектов, а где-то за пределами.

Оффлайн Александр Ривилис

  • Administrator
  • *****
  • Сообщений: 13882
  • Карма: 1787
  • Рыцарь ObjectARX
  • Skype: rivilis
Re: программный выбор рамкой
« Ответ #7 : 20-12-2017, 17:00:43 »
Не забывайте про правильное Форматирование кода на форуме
Создание и добавление Autodesk Screencast видео в сообщение на форуме
Если Вы задали вопрос и на форуме появился правильный ответ, то не забудьте про кнопку Решение

Оффлайн Николай ГорловАвтор темы

  • ADN
  • *
  • Сообщений: 238
  • Карма: 34
Re: программный выбор рамкой
« Ответ #8 : 20-12-2017, 17:05:39 »
попробую, но не в зуме проблема, кажись. ведь даже используя вызов автокадовских команд для зуммирования SSGet не работает.

Оффлайн Александр Ривилис

  • Administrator
  • *****
  • Сообщений: 13882
  • Карма: 1787
  • Рыцарь ObjectARX
  • Skype: rivilis
Re: программный выбор рамкой
« Ответ #9 : 20-12-2017, 17:06:58 »
попробую, но не в зуме проблема, кажись. ведь даже используя вызов автокадовских команд для зуммирования SSGet не работает.
Ну а если "_CP" заменить на "_C"?
Не забывайте про правильное Форматирование кода на форуме
Создание и добавление Autodesk Screencast видео в сообщение на форуме
Если Вы задали вопрос и на форуме появился правильный ответ, то не забудьте про кнопку Решение

Оффлайн Николай ГорловАвтор темы

  • ADN
  • *
  • Сообщений: 238
  • Карма: 34
Re: программный выбор рамкой
« Ответ #10 : 20-12-2017, 17:30:34 »
Цитировать
Ну а если "_CP" заменить на "_C"?
проверил с "_W" и с "_С"
Код - C++ [Выбрать]
  1. /*AcGePoint3dArray pts1 = SelectCrossingPolygonLEps(pt, eps); // восьмиугольник вокруг точки. точки в UCS
  2. if (!pts1.first().isEqualTo(pts1.last())) pts1.append(pts1.first()); // замыкаем первую область
  3. struct resbuf *pointlist1;
  4. pointlist1 = pointsToResbuf(pts1);
  5. int resFind = acedSSGet(_T("_CP"), pointlist1, NULL, &lookAt, ent1); //RTNORM - не было зумма, RTERROR - был зум внутри команды
  6. acutRelRb(pointlist1); // чистим набор точек. больше не нужен
  7. */
  8.        
  9. ads_point pt1, pt2;
  10. pt1[X] = pt.x - eps; pt1[Y] = pt.x - eps; pt1[Z] = 0.0;
  11. pt2[X] = pt.x + eps; pt2[Y] = pt.x + eps; pt2[Z] = 0.0;
  12. acedSSGet(_T("_C"), pt1, pt2, &lookAt, ent1);
  13.  

работают оба варианта. но работают как-то странно, нет постоянства в заполнении прогресса. С каждой новой итерацией это происходит всё медленней и медленней. и под конец практически засыпает прогресс.
вариант с "_W" на холостом ходу в новом чертеже отрабатывает 3 мин. 18 сек.
вариант с "_С" на холостом ходу в новом чертеже отрабатывает 5 мин. 30 сек.

для сравнения, вариант с "_CP", если убрать вызов зума из моей команды отрабатывает за 1мин. 24сек. и прогресс перемещается с завидным постоянством.

Оффлайн Александр Ривилис

  • Administrator
  • *****
  • Сообщений: 13882
  • Карма: 1787
  • Рыцарь ObjectARX
  • Skype: rivilis
Re: программный выбор рамкой
« Ответ #11 : 20-12-2017, 17:46:22 »
для сравнения, вариант с "_CP", если убрать вызов зума из моей команды отрабатывает за 1мин. 24сек. и прогресс перемещается с завидным постоянством.
Похоже он вообще неправильно работает.
ads_point pt1, pt2;
pt1[X] = pt.x - eps; pt1[Y] = pt.x - eps; pt1[Z] = 0.0;
pt2[X] = pt.x + eps; pt2[Y] = pt.x + eps; pt2[Z] = 0.0;
acedSSGet(_T("_C"), pt1, pt2, &lookAt, ent1);
А тут у тебя просто ошибка в коде как мне кажется.  Должно быть как-то так:
Код - C++ [Выбрать]
  1. ads_point pt1, pt2;
  2. pt1[X] = pt.x - eps; pt1[Y] = pt.y - eps; pt1[Z] = 0.0;
  3. pt2[X] = pt.x + eps; pt2[Y] = pt.y + eps; pt2[Z] = 0.0;
  4. acedSSGet(_T("_C"), pt1, pt2, &lookAt, ent1);
Не забывайте про правильное Форматирование кода на форуме
Создание и добавление Autodesk Screencast видео в сообщение на форуме
Если Вы задали вопрос и на форуме появился правильный ответ, то не забудьте про кнопку Решение

Оффлайн Александр Ривилис

  • Administrator
  • *****
  • Сообщений: 13882
  • Карма: 1787
  • Рыцарь ObjectARX
  • Skype: rivilis
Re: программный выбор рамкой
« Ответ #12 : 20-12-2017, 17:57:21 »
Что же касается странностей с прогрессом, тот тут то как раз всё понятно. AutoCAD не успевает обработать свою очередь сообщений. Нужно вызвать вот такую функцию перед очередным вызовом прогрессбара:
Код - C++ [Выбрать]
  1. //////////////////////////////////////////////////////////////////////////
  2. // Эта функция при длительных вычислениях
  3. // позволяет AutoCAD обработать свою очередь сообщений (например, обновить
  4. // содержимое окна редактора, отреагировать на движения мыши и т.д.)
  5. //////////////////////////////////////////////////////////////////////////
  6.  
  7. int OnIdleAcadInternal(void) {
  8.   CWinApp *app = acedGetAcadWinApp();
  9.   // Это главное окно приложения AutoCAD
  10.   CWnd *wnd = app->GetMainWnd ();
  11.   // Создадим свой собственный диспетчерский цикл для обработки
  12.   // сообщений, переданных в AutoCAD. Если появились новые собщения -
  13.   // заставим AutoCAD их обработать.
  14.   MSG msg;  
  15.   // Выкачиваем сообщения из очереди сообщений AutoCAD
  16.   while (::PeekMessage(&msg, wnd->m_hWnd, 0, 0, PM_NOREMOVE))  {
  17.     // Если в очереди сообщений был запрос
  18.     // на завершение AutoCAD - выполним его.
  19.     if (!app->PumpMessage())  {
  20.       ::PostQuitMessage(0);
  21.       break;
  22.     }
  23.   }
  24.  
  25.   LONG lIdle = 0;
  26.   // Позволим MFC выполнить обработку состояния ожидания
  27.   //while (app->OnIdle(lIdle++)&& lIdle < 1000);
  28.   return RSRSLT;
  29. }
Не забывайте про правильное Форматирование кода на форуме
Создание и добавление Autodesk Screencast видео в сообщение на форуме
Если Вы задали вопрос и на форуме появился правильный ответ, то не забудьте про кнопку Решение

Оффлайн Николай ГорловАвтор темы

  • ADN
  • *
  • Сообщений: 238
  • Карма: 34
Re: программный выбор рамкой
« Ответ #13 : 21-12-2017, 12:50:52 »
Цитировать
Нужно вызвать вот такую функцию перед очередным вызовом прогрессбара
у меня такая есть, только с наворотами :). оно еще и прерывать цикл умеет по Esc :):):)
Код - C++ [Выбрать]
  1. int acad_abortCycle(const ACHAR * abortString)
  2. {
  3.         int res = 0;
  4.         CWinApp *app = acedGetAcadWinApp();
  5.         CWnd *wnd = app->GetMainWnd();
  6.         MSG msg;
  7.         while (::PeekMessage(&msg, wnd->m_hWnd, 0, 0, PM_NOREMOVE))
  8.         {
  9.                 if (!app->PumpMessage())
  10.                 {
  11.                         ::PostQuitMessage(0);
  12.                         break;
  13.                 }
  14.         }
  15.         LONG lIdle = 0;
  16.         while (app->OnIdle(lIdle++));
  17.  
  18.         res = acedUsrBrk();
  19.         if (res == 1 && abortString != NULL) acutPrintf(abortString);
  20.         return res;
  21. }
  22.  
а пользоваться так:
Код - C++ [Выбрать]
  1. if (acad_abortCycle(_T("\nИНФО: Отрисовка прервана пользователем...")) == 1)
  2. {
  3.         acedRestoreStatusBar();
  4.         return;
  5. }
  6.  

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


из нее видно, что в новом чертеже автокада acedSSGet  с _С, _CP, _W возвращает RTERROR и время работы для _W и _C увеличивается в разы. но если взять старый чертеж, то варианты _W и _C работают отлично.

из таблички: там где тестировался вариант без зума, значит, что требуемая область уже была видимой на экране.
еще в табличке есть "*". ситуация с ней такая. если в чертеже провести ряд махинаций перед вторым вызовом команды (что-нибудь нарисовать, дважды клацнуть колесиком мышки, командами автокада поменять область видимости... в общем закономерности я не нашел), то команда может сработать, а может и НЕ сработать. Всё зависит от настроения :)

Да, и время работы у всех приблизительно одинаковое. "_CP", как мне кажется, работает чуток дольше чисто из-за того, что приходится строить восьмиугольник, перегонять его в resbuf, а потом еще и чиститься за собой.

Оффлайн Николай ГорловАвтор темы

  • ADN
  • *
  • Сообщений: 238
  • Карма: 34
Re: программный выбор рамкой
« Ответ #14 : 21-12-2017, 15:35:25 »
хм... новая серия тестов. уже только с вариантом "_С"
слегка модернизировал команду. если за проход что-то находит, точка рисуется красным, если не находит - черным. ну и вначале команды идет запрос - нужен зум или нет.

итак. вот такие варианты. выводы будут в конце.
1. новый чертеж. средствами автокада создаю отрезок по координатам 7367820.0,5376960.0 и 7371560.0,5371400.0
 запуск команды. зум нужен. работает 6м 10с. обнаружено 124 объекта, т.е. 124 точки нарисовало красным

2. новый чертеж. копирую отрезок в него с сохранением координат. zoom _e. слегка колесиком мышки уменьшаю масштаб отображения и смещаю отрезок вправо. отрезок полностью виден. запуск команды. зум не нужен. время работы - 0м 39с. обнаружено 222 объекта.

3. новый чертеж. копирую отрезок в него с сохранением координат. zoom _e. слегка колесиком мышки уменьшаю масштаб отображения и прячу линию за пределы экрана. запуск команды. зум нужен. время работы - 0м 33с. обнаружено 124 объекта.

итого в сухом остатке. RTERROR - это нормальный ответ функции acedSSGet (чисто моё умозаключение. в хелпе вообще этот вопрос обошли стороной), если она ничего не находит. обнаружить на самом деле должно было 2 объекта, т.к. сканируется рамкой 0.002x0.002 вокруг исходной точки. но, как показала практика - рамку автокад еще и на текущий масштаб отображения перемножил и мои 0.002x0.002 превращаются.... превращаются 0.002x0.002... короче превращаются они где-то в 3x3 или даже 5x5. и такая рамка захватывает уже лишние точки. дальше, почему в варианте 2 получается больше точек. всё просто - масштаб отображения другой. и 0.002x0.002 превратились, например, в 15x15.

непонятно одно. с какого перепуга время в 1 и 3 настолько сильно отличается. неужто животворящий zoom _e способен привести новый чертеж в нормальное состояние. и почему тогда по умолчанию новый чертеж не находится в этом самом нормальном состоянии? и еще не понятно, с какого перепуга входные точки рамки преобразовались таким диким образом, что рамка увеличилась в разы от заданного размера?


-----------------------------------------------------
добавлено.
переварив эти приколы, решил проверить, как ведет себя "_CP"
вариант1: работает 5м 19с, найдено 2 объекта
вариант2: работает 1м 6с, найдено 2 объекта
вариант3: работает 1м 13с, найдено 2 объекта

т.е. единственный работоспособный вариант в этом случае без танцев с бубном по пересчету размеров окна - _CP, хотя по прежнему время работы в новом чертеже со вставленным отрезком и без zoom _e сильно отличается.


« Последнее редактирование: 21-12-2017, 16:08:34 от Николай Горлов »