Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > C/C++: Системное программирование и WinAPI > Оптимизация выделения


Автор: TGrey 28.1.2010, 15:51
Здравствуйте. Снова вернусь к своему приложению и хочу посоветоваться на счет выделения.
На данный момент выделение происходило только кликом непосредственно по элементу. Что по сути вызывало ряд мат. формул и в случае выполнения условия выделяло объект. Потом же было решено сделать еще прямоугольное выделение, как в виндовсе. Сделать - сделал. Рисуется точечным карандашом прямоугольник. Но вот дальше выделение происходит по старому методу проверкой Х и У координат. Тобишь крутит 2 цикла от меньшего Х к большему и тоже самое по У и так проверяет каждый пиксель. По сути то оно выделяет, все нормально. Но чем больше прямоугольник, тем больше нужно проверить и это сказывается на ЦП. Чем больше я выделяю область тем больше прыгает ЦП. Конечно на секунду, но все равно заметно. А если увеличить еще кол-во объектов, то будет туго.
Может есть предложения, как это можно оптимизировать, ускорить процесс с наименьшей нагрузкой на ЦП.

Пока же вызывается вот эта функция
Код

void TrySelect( int fx, int fy, int sx, int sy )
{
    bool nextel=false, issel=false;
    for(int i=0; i < d.elements.size(); i++)
    {
        for(int y=0; y < d.selected.size(); y++)    //Skip selected
        {
            if( d.elements[i] == d.selected[y] )
            {
                issel = true;
                break;
             }
                
        }

        if( issel )
        {
            issel = false;
            continue;
        }

        for(int k=fx; k<=sx; k++)
        {
            for(int l=fy; l<= sy; l++)
            {
                if( d.elements[i]->OnClick(k, l) == false )
                {
                    if( d.elements[i]->type == 1 && static_cast<IConductor*>(d.elements[i])->NextCond != NULL )
                    {    
                        /**/
                        IConductor *tmp = static_cast<IConductor*>(d.elements[i])->NextCond;
                        do
                        {
                            if( tmp->OnClick(k, l) == true )
                            {
                                nextel = true;
                                break;
                            }
                            tmp = tmp->NextCond;
                        }while( tmp != NULL );
                    }
                }
                else
                {
                    nextel = true;
                }
                if( nextel )
                    break;
            }
            if( nextel )
                break;
        }
        nextel = false;
    }
}


Ну и как я сказал оно так и выходит, если несколько элементов то ЦП до 20-30 прыгает, а если сделать все 10 и больше то и до 90 доходит и несколько секунд надо ждать пока разтупит.

Автор: GremlinProg 28.1.2010, 17:22
упрости: для каждой фигуры храни или считай "окаймляющий прямоугольник" - габариты фигуры, по сути,
а при проверке вхождения фигуры в выделение, пересекай оба этих прямоугольника (IntersectRect)

если результатом пересечения будет пустой прямоугольник, значит фигура не входит в выделение, иначе - входит

в случае пересечения, IntersectRect вернет TRUE

Автор: TGrey 28.1.2010, 17:39
То есть вот так? Обрамлять фигуру и вызывать для ВЫДЕЛЕНИЯ и для объекта функцию Пересечения?
А как она внутри работает? Может тоже начинает координаты перебирать?)

Автор: GremlinProg 29.1.2010, 06:39
физически, на холсте можно и не обрамлять, а так, виртуально - все верно рисуешь
Цитата(TGrey @  28.1.2010,  19:39 Найти цитируемый пост)
А как она внутри работает? Может тоже начинает координаты перебирать?)

не начнет: http://www.google.ru/search?q=%D0%B0%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC+%D0%BF%D0%B5%D1%80%D0%B5%D1%81%D0%B5%D1%87%D0%B5%D0%BD%D0%B8%D1%8F+%D0%BF%D1%80%D1%8F%D0%BC%D0%BE%D1%83%D0%B3%D0%BE%D0%BB%D1%8C%D0%BD%D0%B8%D0%BA%D0%BE%D0%B2&btnG=%D0%9F%D0%BE%D0%B8%D1%81%D0%BA
smile

Автор: TGrey 29.1.2010, 13:21
Не ну это понятное дело, что на холсте не буду. Это чтобы полностью быть уверенным, что я верно понял.
Спасибо сейчас попробую и доложу о результатах!

Автор: TGrey 29.1.2010, 14:40
Получилась такая ситуация. Пока прикрепил прямоугольники только к круглым объектам, но результат таков, что память скачет меньше, около 20%, но я посмотрел, что выделения я по прежнему использую функцию OnClick которая делает математические расчеты, что не так плохо, как первый раз, поскольку теперь клик происходит четко по объекту, что сокращает вызов этих функций до кол-ва самих объектов. Но я так подумал, что это бессмысленно, снова рассчитывать клик, сделал еще одну виртуальную функцию Select которая только устанавливает флаги выделения и выполняет функции с расчетом, что выделение произошло 100%. Но память, что-то всеравно до 20% прыгала. Я посмотрел, что при отрисовке выделяющего прямоугольника все сильно моргает. Закоментировав эту часть ЦП держится на 0%. Пока программа не использует задний буффер для прорисовки, поэтому видимо такие глюки.
В общем сам способ помог smile . Спасибо.

Автор: TGrey 29.1.2010, 15:01
Да, наверно поспешил.
user posted image
Провод рисуется изгибами, значит его нужно полностью заключить в прямоугольник.
Вот и получается, что если выделять, как на рисунке синим цветом, то выделение проходит, хоть не должно.

Автор: Earnest 29.1.2010, 21:14
TGrey, разные объекты нужно находить по разному. Общий подход такой: 
1) Хранишь охватывающий прямоугольник для каждого объекта - для ускорения: первая проверка - попадание точки в этот экстентю Или наличие пересечения экстента с прямоугольником выделения.
2) Дальше (если в прямоугольник попали) нужно вызывать функцию, свою для каждого типа объекта, скажем вирт. функция HitTest. Для прямоугольника она тривиальна (собственно, уже выполнена при проверке экстента). Для провода это - поиск пересечения каждого сегмента с прямоугольником. И т.д.

Автор: TGrey 29.1.2010, 21:44
Ну вот я и думаю, что такой способ будет работать только с круглыми объектами, которые даже при повороте не изменяет форму, а остальное нужно искать по пересечениям.
Пойду искать формулы.

Автор: TGrey 30.1.2010, 15:45
В общем решил делать след. образом: Сперва проверять точки на линии, находятся ли они внутри прямоугольника, если так - выделять. Если по точкам ничего не выделило, тогда использую формулы пересечения двух прямых, линии и каждой части прямоугольника. Пока работает и ЦП не грузит.

Автор: GremlinProg 30.1.2010, 20:48
Цитата(TGrey @  30.1.2010,  17:45 Найти цитируемый пост)
В общем решил делать след. образом: Сперва проверять точки на линии, находятся ли они внутри прямоугольника, если так - выделять. Если по точкам ничего не выделило, тогда использую формулы пересечения двух прямых, линии и каждой части прямоугольника. Пока работает и ЦП не грузит.

со сложными объектами работай как с совокупностью простых: ломаная - набор отрезков, вот и работай со всеми ее отрезками,
отрезок же - простой объект

если хоть один отрезок пересекает выделение, значит пересекает и вся ломаная

Автор: TGrey 31.1.2010, 00:30
Да уже именно так и сделал.

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)