Еще раз про ускорение удаления объектов

Автор Akew, 25.06.15, 18:23:21

« назад - далее »

0 Пользователи и 1 гость просматривают эту тему.

Akew

Здравствуйте.

Исследую возможности ускорения построения и удаления большого числа элементов вспомогательной геометрии.
Эти вопросы уже рассматривались на форуме, но достаточно ясного ответа, с реальным кодом, никто так и не представил.
Несмотря на некоторый прогресс, я так и не смог понять, как можно ускорить эти процессы.
Если построение мне удалось ускорить, то время удаления, на мой взгляд, остается несоразмерно большим, т.к., если модели строится за считанные секунды или минуты, то удаление соответствующей модели длится в 30-60 раз дольше.
Если при построении модели не происходит никакого движения на экране, то при удалении хорошо видно, как мелькает индикатор прогресса перестроения модели, в правом нижнем углу, а в левом - можно успеть прочитать "Перестроение: Файл:", далее - названия удаляемых элементов геометрии. Причем, если вначале мелькание относительно медленное, то с течением времени оно значительно ускоряется (по-видимому, из-за уменьшающегося числа элементов в данной сборке).
Возможно ли отключить это перестроение модели при удалении элементов вспомогательной геометрии, и индикацию этого процесса?

Одна из рекомендаций на форуме - использовать менеджер выделения (http://forum.ascon.ru/index.php/topic,27354.msg204077.html#msg204077).
Я подключил его, но, по все видимости, неверно сформировал массив VARIANT объектов, которые хочу выделить: выдается ошибка в методе ISelectionManager::Select(). Думаю, что в моем коде где-то не достает звездочки (*) или амперсанда (&), для правильной адресации, - пока не смог разобраться.

В качестве упражнения сформировал массив элементов, которые "ручками" выделяю в сборке, сделал его копию без замыкающего элемента, и выделение элементов по этому массиву, - здесь все работает без замечаний.

И еще, не понятно, какой должен быть второй параметр в методе IApplication::ExecuteKompasCommand( ksCMEditClear, FALSE|TRUE ) для применения операции удаления выделенных объектов?

Итого, у меня три вопроса:
1) Можно ли ускорить непосредственное удаление элементов вспомогательной геометрии так, чтобы время удаления было более соразмерным со временем создания соответствующих элементов?
2) Как сформировать массив VARIANT для выделения элементов в дереве построения посредством метода ISelectionManager::Select()?
3) Какое значение, FALSE или TRUE, нужно применить для второго параметра в методе IApplication::ExecuteKompasCommand( ksCMEditClear, FALSE|TRUE )?

Буду благодарен за любые рекомендации.
Полный код (проект на Visual C++ 2005), который строит и удаляет модели, и выполняет описанное упражнение, прилагаю.
Пояснения - в файле test-delete-geometry.cpp.

Я на Visual C++ не работаю, с кодом не помогу, хотя разработчики пишут именно на нём и поэтому самый полный код в SDK по работе с Компас-3D, именно в разделе Visual C++.
1. Можно.
2. Массив создаёте Вы, в который записываете всё, что нужно выделить и методом ISelectionManager.Select делаете выделение всех необходимых объектов, можно делать по отдельности данным методом, но тогда будут тормоза, т.к. после выделения объекта он должен под светиться, а это означает перерисовка окна, что является основным тормозом системы Windows, если передаётся массив, то перерисовка делается один раз, соответственно одна перерисовка, ноль тормозов.
3. Если Вы имеете понятие, что такое сообщение Windows, то тут всё просто, по факту IApplication.ExecuteKompasCommand - это передача события приложению Компас-3D посредством метода API Windows:
- true - запуск команды через PostMessage - выполняется, когда до него дойдёт очередь;
- false - через SendMessage, выполняется немедленно, т.е. если в очереди сообщений для обработки стоит PostMessage, то посылая SendMessage, сначала будет выполнено SendMessage, а потом PostMessage, даже, если PostMessage пришло первым, но не факт, т.к. процесс не простой.
Нужно передавать обычно SendMessage, но нужно понимать, в какой момент времени сообщение передаётся, т.к. иногда возникают моменты, когда нужно дать приложению сделать работу, от которой будет зависеть его работоспособность и чтобы не было конфликта, нужно передавать PostMessage.

Akew

Sabahs, спасибо за пояснения.

Естественно, я в курсе, что есть примеры в указанном Вами месте, и я их использую. И я понял, как нужно использовать менеджер выделения для моей задачи, но в этих примерах не обнаружил подходящего.
У меня конкретная проблема: по-видимому, я неправильно формирую массив объектов, которые хочу выделить (удалить).
Если у Вас нет примера (кода) на C++, то, если это возможно, пожалуйста, приведите, его на том языке, который у Вас есть, -  я попытаюсь разобраться сам.

Спасибо.

25.06.15, 20:55:08 #3 Последнее редактирование: 25.06.15, 22:22:18 от Sabahs
Почему, все хотят код от меня?
Свой тяжело выложить - проблемный участок, без воды.
Как создать массив:
c:Program FilesASCONKOMPAS-3D V16SDKPascalDelphiStep3_API7_2DStep3_API7_2D_1.pas
c:Program FilesASCONKOMPAS-3D V16SDKC++VisualcStep3_API7_2DStep3_API7_2D.cpp
Смотрим - function NewSafeArray


Посмотрел мельком тот пример, который Вы прикрепили в первом сообщении, сразу, как то внимания на него не обратил.
Вы уже получили массив элементов вспомогательной геометрии, так и передавайте его в ISelectionManager.Select.

Akew

Цитата: Sabahs от 25.06.15, 20:55:08
Почему, все хотят код от меня?
Думаю, потому, что мало вас, "зубров" по API SDK Компас. Однако, поверьте, Вы делаете великое дело, помогая таким новичкам, как я.
По возможности, я стараюсь выкладывать решения своих проблем, которые выносил на на форум, чтобы ими, решениями, могли пользоваться другие, т.е., вношу свой посильный вклад в это общее дело.

Касательно Вашего сообщения:
- В указанных Вами примерах массивы имеют типы long и double, и в свое время я их освоил (еще были строковые). Сейчас мне необходимо создать массив типа IDispatch, - это более сложный тип данных. Вроде бы, я создаю этот массив (сообщения об ошибках отсутствуют), по при попытке задать его в ISelectionManager::Select возникает ошибка.
- Я решил выложить весь проект, чтобы люди могли загрузить его и проверить без дополнительных действий, "прикручивая" мои фрагменты к своей среде.

Прилагаю проблемный фрагмент кода:
//-------------------------------------------------------------------------------
// Удалить элементы вспомогательной геометрии посредством менеджера выделения
// ---
bool delete_all_by_selection_manager( ksDocument3DPtr new_doc,    // Документ, в котором находится удаляемая геометрия
            IDispatchPtr *auxiliary_elements,    // Массив элементов вспомогательной геометрии (формировался синхронно с созданием этих элементов)
            long count_auxiliary_elements        // Размерность массива
        ) {
CString title_dialog; title_dialog.Format( _T( "Функция %s" ), _T( "delete_all_by_selection_manager" ) ); // Заголовок окна сообщений функции
CString tmpstr;

CTime tm_delete = CTime::GetCurrentTime(); // Засечка начала процесса удаления

// 1. Получить меднеджер выделения объектов
IKompasDocument3DPtr kompas_doc3D = MyApplication->ActiveDocument;
if(!kompas_doc3D) {
MessageBox(NULL, _T("*** kompas_doc3D не получен. Выход"), title_dialog, MB_OK);
return false;
}
ISelectionManagerPtr selection_manager = kompas_doc3D->SelectionManager;
if( !selection_manager ) {
MessageBox(NULL, _T("*** selection_manager не создан. Выход"), title_dialog, MB_OK);
return false;
}

// 2. Записать элеиенты вспомогательной геометриии в массив VARIANT
_variant_t selected_objects;
SAFEARRAYBOUND sabNewArray;

sabNewArray.cElements = count_auxiliary_elements;
sabNewArray.lLbound = 0;

SAFEARRAY * pSafe = ::SafeArrayCreate( VT_DISPATCH, 1, &sabNewArray );
if( ! pSafe ) {
MessageBox(NULL, _T("*** pSafe не получен. Выход"), title_dialog, MB_OK);
return false;
}

for ( long i = 0; i < count_auxiliary_elements; i++ ) {
long address[1];
address[0] = i;

IDispatch *obj;
obj = auxiliary_elements[i];

// Работает (Компас не вылетает), но требуемый результат не получается (не отрабатывает selection_manager->Select( &selected_objects ))
HRESULT  hr = ::SafeArrayPutElement( pSafe, address, obj );

// Другие варианты задания адреса объекта, который необходимо записать в VARIANT, но не давшие нужного результата
// HRESULT  hr = ::SafeArrayPutElement( pSafe, address, (void *)obj ); // Работает
// HRESULT  hr = ::SafeArrayPutElement( pSafe, address, (void **)obj ); // Работает
// HRESULT  hr = ::SafeArrayPutElement( pSafe, address, &obj ); // Вылет Компаса
// HRESULT  hr = ::SafeArrayPutElement( pSafe, address, (void **)&obj ); // Вылет Компаса
// HRESULT  hr = ::SafeArrayPutElement( pSafe, address, (void *)&obj ); // Вылет Компаса

if ( FAILED(hr) ) return false;
}

V_VT(&selected_objects) = VT_ARRAY | VT_DISPATCH;
V_ARRAY(&selected_objects) = pSafe;

MessageBox(NULL, _T("Формирование массива завершено успешно"), title_dialog, MB_OK);

// 3. Указать созданный массив как элементы дерева, которые нужно выделить
// !!! Массив selected_objects формируется, но в этом месте выдает ошибку
if(! selection_manager->Select( &selected_objects ) ) {
MessageBox(NULL, _T("Не удалось выполнить selection_manager->Select(). Выход."), title_dialog, MB_OK); return false;
}

MessageBox(NULL, _T("selection_manager->Select выполнен"), title_dialog, MB_OK);

// 4. Выполнить команду удаления выделенных объектов
if(! MyApplication->ExecuteKompasCommand( ksCMEditClear, FALSE ) ) {
tmpstr.Format( _T("Не удалось выполнить MyApplication->ExecuteKompasCommand((). Выход.") );
MessageBox(NULL, tmpstr, title_dialog, MB_OK); return false;
}
MessageBox(NULL, _T("Удаление проведено"), title_dialog, MB_OK);

// 5. Разрешить перестроить дерево и перерисовать окно, чтобы увидеть результат (здесь - пустое окно)
new_doc->treeNeedRebuild = TRUE;
new_doc->windowNeedRebuild = TRUE;

tmpstr.Format( _T("9.1. Удаление проведено за %s"), elapsed_since( tm_delete ) );
MessageBox(NULL, tmpstr, title_dialog, MB_OK);

return true;
}


Цитата: Sabahs от 25.06.15, 20:55:08
Вы уже получили массив элементов вспомогательной геометрии, так и передавайте его в ISelectionManager.Select.
А разве так можно? У меня массив - IDispatch[], а требуется - VARIANT VT_ARRAY | VT_DISPATCH (или VT_DISPATCH, когда выделяемый элемент только один).

Спасибо.

У меня всё проще.
Air2:=VarArrayCreate([0,8],varDispatch);
if(VarType(Air2)=(VT_ARRAY Or VT_DISPATCH))then
begin
    Air2[0]:=Obj4; // Obj = IDispatch
    Air2[1]:=Obj4R;
    Air2[2]:=Obj5;
    Air2[3]:=Obj5R;
    Air2[4]:=Obj6;
    Air2[5]:=Obj6R;
    Air2[6]:=Obj7;
    Air2[7]:=Obj7R;
    Air2[8]:=Obj8;
    SelectionManager.Select(Air2);
end;

Vitalij Lysanov


Есть вариант, на время удаления отключить визуализацию:

Kompas.Visible=False
Kompas.Visible=True