Приветствую. Дано: - координаты ячейки (или точки) X,Y; - массив диапазонов в виде (X1,X2,Y1,Y2); Нужно определить, принадлежит ли ячейка одному из них, то есть (X1 <= X <= X2) and (Y1 <= Y <= Y2). X,Y занимают по 2 байта, соответственно элемент массива — 8. Вопрос 1й: можно ли как-то определить, верно ли равенство X1 <= X <= X2, если есть R = (X1 << 16) + X2? Вопрос 2й: как оптимизировать то, что вышло с нахрапа: Код (Text): mov edx,X mov eax,Y push ecx ; количество элементов массива xor edi,edi dec edi @@: inc edi cmp edi,[esp] jе @F mov ecx,[esi+edi*8] ; ecx = |х1,х2| ; compare х >= х1 cmp dx,cx jb @В shr ecx,16 ; compare х <= х2 cmp edx,ecx ja @В mov ecx,[esi+edi*8+4] ; ecx = |у1,у2| ; compare у >= у1 cmp ax,cx jb @В shr ecx,16 ; compare у <= у2 cmp eax,ecx ja @В @@: pop eax sub eax,edi ; еах - 0, если не найдено
Для положительных чисел можно обойтись без сдвига: edx=(X+1)<<16+X ecx=(X1<<16)+X2 cmp ecx,edx если X1<=X<=X2, тогда X+1>X1 и в результате сравнения будет установлен флаг переноса(переноса из младших 16 разрядов нет) если X<X1<=X2, тогда флаг переноса установлен не будет если X>X2, то этот вариант отсекается второй проверкой (сравнением X и X2) Данный метод не работает когда X=0FFFFh
Спасибо! Значит, не зря диапазоны так выстроены. 0хFFFF вряд ли будет, слишком уж большое число, хотя теоретически возможно.
Можно несколько ускорить оригинальный код, отсортировав прямоугольники в массиве по площади. Или помещать прямоугольники в массив так, чтобы каждый следующий прямоугольник покрывал максимальную площадь еще не покрытую предыдущими. Или размещать прямоугольники в порядке, чтобы вероятность попадания точки в данный прямоугольник была максимальной при условии, что точка не попала ни в один из предыдущих. Но всё это бесполезно если площадь покрываемая прямоугольниками мала, по отношению к прощади, на которой может оказаться точка. Если прямоугольников много, и они сильно пересекаются, то возможно, что более быстрым методом будет нахождение контура(контуров) покрываемой ими области(областей), и обход его с вычислением угла, который мы опишем вокруг точки: 0 - точка снаружи, 2Pi - точка внутри (алгоритм не помню). Ну и вот метод который может ускорить вычисления при большом количестве прямоугольников, за счёт дополнительного расхода памяти: Заводим 4 массива со структурами, содержащими значения одной из границ (X1, X2, Y1 или Y2) и идентификатор прямоугольника которому принадлежит эта граница. Массивы должны быть упорядоченны по значению границы. Получив (X,Y), двоичным поиском находим в каждом массиве, где начинаются прямоугольники в которые может попасть данная точка. Затем выбираем массив, в котором меньше всего таких прямоугольников и просто проверяем для каждого из них три оставшиеся границы.
Вообще, ячейки — это ячейки таблицы, диапазоны ячеек — объединённые ячейки. Соответственно, диапазоны пересекаться не могут. Практически, объединённых ячеек не много. Ячейки обрабатываются последовательно, думаю, логично будет сдвигать указатель на диапазоны по мере нахождения соответствий (когда X > Ranges[0].X1).
IceStudent > "0хFFFF вряд ли будет, слишком уж большое число, хотя теоретически возможно" Нехилая табличка Если числа не более 0х7FFF (тоже не маленькое число то можно без лишних переходов обойтись - использовать 16-й и 32-й биты как индикаторы переноса (правда предварительная подготовка XY усложняется, зато сравнение с Ranges быстро делается). Для X,Y < 0хFFFF можно без переходов сделать на MMX
Условие типа if (X>=X1)and(Y>=Y1)and(X<=X2)and(Y<=Y2) then можно и так проверить Код (Text): mask dd 00000000h,00000000h,80000000h,80000000h ......... cvtpi2ps xmm0,[XY] shufps xmm0,xmm0,01000100b xorps xmm0,dqword[mask] cmpnltps xmm0,[X1Y1X2Y2] ; X1,Y1,-X2,-Y2 movmskps eax,xmm0 cmp al,15 je @true а если без SSE, то так Код (Text): mov eax,[X] mov edx,eax sub eax,[X1] sub edx,[X2] xor eax,edx mov ecx,[Y] mov edx,ecx sub ecx,[Y1] sub edx,[Y2] xor ecx,edx test ecx,eax jl @true
murder Поправочка: при использовании sub\sub\xor нужно, чтобы одна из границ не принадлежала диапазону, поэтому для проверки X1 <= X <= X2 перед вычитанием нужно добавить inc eax или dec edx