Реализация алгоритма Hoey Shamos на C#

Хорошо, теперь я получаю правильную информацию из моего текущего алгоритма! Однако с 700 000 полигонов для проверки это слишком медленно! Предыдущая проблема исправлена ​​(Мой метод Line2D intersectsWith был неправильным)

Теперь дело за определением моего узкого места! Предполагается, что этот алгоритм будет O (nlog-n), поэтому он должен быть намного быстрее. Мой метод intersectsWith выглядит так, как будто он не может работать быстрее, однако я опубликую его код, если я ошибаюсь.

EDIT: добавлен интерфейс IComparable

Мой метод чтения пересечений отрезков. Часть кода опущена для удобочитаемости.

    public class Line2D : IComparable
    {


    public Line2D(XYPoints p1, XYPoints p2)
    {

    }

    public bool intersectsLine(Line2D comparedLine)
    {

        if ((X2 == comparedLine.X1) && (Y2 == comparedLine.Y1)) return false;
        if ((X1 == comparedLine.X2) && (Y1 == comparedLine.Y2)) return false;

        if (X2 == comparedLine.X1 && Y2 == comparedLine.Y1)
        {
            return false;
        }

        if (X1 == comparedLine.X2 && Y1 == comparedLine.Y2)
        {
            return false;
        }
        double firstLineSlopeX, firstLineSlopeY, secondLineSlopeX, secondLineSlopeY;

        firstLineSlopeX = X2 - X1;
        firstLineSlopeY = Y2 - Y1;

        secondLineSlopeX = comparedLine.getX2() - comparedLine.getX1();
        secondLineSlopeY = comparedLine.getY2() - comparedLine.getY1();

        double s, t;
        s = (-firstLineSlopeY * (X1 - comparedLine.getX1()) + firstLineSlopeX * (getY1() - comparedLine.getY1())) / (-secondLineSlopeX * firstLineSlopeY + firstLineSlopeX * secondLineSlopeY);
        t = (secondLineSlopeX * (getY1() - comparedLine.getY1()) - secondLineSlopeY * (getX1() - comparedLine.getX1())) / (-secondLineSlopeX * firstLineSlopeY + firstLineSlopeX * secondLineSlopeY);

        if (s >= 0 && s <= 1 && t >= 0 && t <= 1)
        {
            return true;
        }

        return false; // No collision 
    }

    int IComparable.CompareTo(object obj)
    {

        //return Y1.GetHashCode();
        Line2D o1 = this;
        Line2D o2 = (Line2D)obj;
        if (o1.getY1() < o2.getY1())
        {
            return -1;
        }
        else if (o1.getY1() > o2.getY2())
        {
            return 1;
        }
        else
        {
            if (o1.getY2() < o2.getY2())
            {
                return -1;
            }
            else if (o1.getY2() > o2.getY2())
            {
                return 1;
            }
            else
            {
                return 0;
            }
        } 
    }


}

Я понимаю, что в большей части реализации моего алгоритма список не самый быстрый для алгоритма, однако мне нужна индексация!:

//Create a new list, sort by Y values.

 List<AlgEvent> SortedList = events.OrderBy(o => o.getY()).ToList();                
 List<Line2D> sweepline = new List<Line2D>();

 for (var g = 0; g < SortedList.Count; g++)
 {
 if (SortedList[g].isStart)
 {
    Line2D nl = SortedList[g].line;
    Line2D above;
    /* Start generating above */
    try
    {
        //grab index in sweepline
        int index = sweepline.IndexOf(nl);
        //add 1 to get above line
        if (index == -1)
        {
            above = null;
        }
        else
        {
            above = sweepline[index + 1];
        }


    }
    catch (ArgumentOutOfRangeException)
    {
        above = null;
    }
    /* End generating above */
    if (above != null)
    {
        if (above.intersectsLine(nl))
        {
            return true;
        }
    }
    Line2D below;
    /* Start generating below */
    try
    {
        //grab index in sweepline
        int index = sweepline.IndexOf(nl);
        //add 1 to get above line
        below = sweepline[index - 1];

    }
    catch (ArgumentOutOfRangeException)
    {

        below = null;

    }
    /* End generating below */
    if (below != null)
    {
        if (below.intersectsLine(nl))
        {
            return true;
        }
    }
    sweepline.Add(nl);
    sweepline = sweepline.OrderBy(o => o.getY1()).ToList();

}
else
{
    Line2D nl = SortedList[g].line;
    Line2D above;
    Line2D below;
    /* Start generating above */
    try
    {
        //grab index in sweepline
        int index = sweepline.IndexOf(nl);
        Console.Out.WriteLine("index:" + index);
        //add 1 to get above line
        above = sweepline[index + 1];

    }
    catch (ArgumentOutOfRangeException)
    {

        above = null;

    }
    /* End generating above */
    /* Start generating below */
    try
    {
        //grab index in sweepline
        int index = sweepline.IndexOf(nl);
        //add 1 to get above line
        below = sweepline[index - 1];

    }
    catch (ArgumentOutOfRangeException)
    {

        below = null;

    }
    /* End generating below */
    sweepline = sweepline.OrderBy(o => o.getY1()).ToList();
    sweepline.Remove(nl);
    if (above != null && below != null)
    {
        if (above.intersectsLine(below))
        {
            return true;
        }
    }
}
Console.WriteLine("");
  }



   } // end numofparts for-loop

   return false;

============================================

ОБНОВЛЕНИЕ: 12 сентября: Реализовали TreeSet из C5, внедрили IComparable в мои классы и еще больше замедлили его? Я все еще индексирую его, если это имеет значение?

http://www.itu.dk/research/c5/

Код с использованием TreeSet:

TreeSet<Line2D> sweepline = new TreeSet<Line2D>();
for (var g = 0; g < SortedList.Count; g++)
{
if (SortedList[g].isStart)
{
    Line2D nl = SortedList[g].line;
    Line2D above;
    /* Start generating above */
    try
    {
        //grab index in sweepline
        int index = sweepline.IndexOf(nl);
        //add 1 to get above line
        above = sweepline[index + 1];

    }
    catch (IndexOutOfRangeException)
    {

        above = null;

    }
    /* End generating above */
    if (above != null)
    {
        if (above.intersectsLine(nl))
        {
            return false;
        }
    }
    Line2D below;
    /* Start generating below */
    try
    {
        //grab index in sweepline
        int index = sweepline.IndexOf(nl);
        //add 1 to get above line
        below = sweepline[index - 1];

    }
    catch (IndexOutOfRangeException)
    {

        below = null;

    }
    /* End generating below */
    if (below != null)
    {
        if (below.intersectsLine(nl))
        {
            return false;
        }
    }
    sweepline.Add(nl);
    //sweepline = sweepline.OrderBy(o => o.getY1()).ToList();

}
else
{
    Line2D nl = SortedList[g].line;
    Line2D above;
    Line2D below;
    /* Start generating above */
    try
    {
        //grab index in sweepline
        int index = sweepline.IndexOf(nl);
        //Console.Out.WriteLine("index:" + index);
        //add 1 to get above line
        above = sweepline[index + 1];

    }
    catch (IndexOutOfRangeException)
    {

        above = null;

    }
    /* End generating above */
    /* Start generating below */
    try
    {
        //grab index in sweepline
        int index = sweepline.IndexOf(nl);
        //add 1 to get above line
        below = sweepline[index - 1];

    }
    catch (IndexOutOfRangeException)
    {

        below = null;

    }
    /* End generating below */
    //sweepline = sweepline.OrderBy(o => o.getY1()).ToList();
    sweepline.Remove(nl);
    if (above != null && below != null)
    {
        if (above.intersectsLine(below))
        {
            return false;
        }
    }
}
//Console.WriteLine("");

}


person Evan Parsons    schedule 29.08.2013    source источник
comment
Есть ли причина, по которой вы не можете реализовать TreeSet на C# самостоятельно?   -  person Zac Howland    schedule 29.08.2013
comment
Таким образом, вы в основном говорите, что я мог бы расширить класс OrderedSet и добавить более высокие и более низкие методы?   -  person Evan Parsons    schedule 29.08.2013
comment
@EvanParsons Я думаю, что Зак говорит реализовать TreeSet с нуля. TreeSet и ему подобные используют структуру данных сбалансированное дерево (например, красно-черное дерево или дерево AVL), но реализовать их непросто. Однако список пропусков — это гораздо более простая структура данных, которая могла бы выполнять эту работу.   -  person john    schedule 29.08.2013
comment
@john: Это правильно, однако реализовать древовидную структуру данных гораздо проще, чем пытаться заставить работать с ней структуру данных, которая не соответствует требованиям алгоритма (квадратная привязка встречается с круглым целым). В то время как список пропуска будет работать (хотя код алгоритма будет немного сложнее написать), упорядоченный набор не будет работать.   -  person Zac Howland    schedule 29.08.2013
comment
Кажется, у меня есть идея. Я собираюсь использовать блок try-catch. Я буду использовать список и использовать indexOf для возврата позиции. Если он возвращает -1 или аргумент вне диапазона списка, я заставлю его возвращать значение null.   -  person Evan Parsons    schedule 29.08.2013
comment
Как правило, вы используете структуру на основе кучи для очереди событий и сбалансированное двоичное дерево поиска для структуры Y. Используемые вами списки замедлят работу. Упомянутая сложность nlogn заключается в использовании этих структур данных, если я правильно помню.   -  person Kshitij Banerjee    schedule 10.09.2013


Ответы (2)


Во-первых, что касается пересечения линий: вам не нужна фактическая точка пересечения, только чтобы знать, пересекаются ли они. См. http://www.geeksforgeeks.org/check-if-two-given-line-segments-intersect/ для алгоритма, который делает именно это.


О реализации List:

В вашей реализации с использованием Lists вы вызываете indexOf на линии развертки, чтобы найти nl. Это ищет развертку от начала до конца. См. раздел List(T).IndexOf. Если бы вы использовали метод BinarySearch, это должно было бы ускорить поиск значительно.

В документации List есть абзац, который называется соображениями производительности. Они призывают вас использовать тип значения, который реализует IEquatable<T> и IComparable<T>. Таким образом, ваш Line2D, вероятно, должен быть struct и реализовывать эти интерфейсы.

Если вы последуете этому совету, извлечение конечной точки из линии развертки должно быть O(log n), что достаточно для ваших целей, а память должна использоваться более эффективно.

Вставка и удаление - это O(n) для списков, потому что базовый массив необходимо перемещать в памяти. SortedSet имеет более быструю вставку и удаление, но я не совсем понимаю, как найти там соседей элемента в O(log n). Кто-нибудь? (См. также Почему SortedSet‹T›.GetViewBetween не является O(log N)?< /а>)


В любом случае, C5 TreeSet должен решить эту проблему.

Я проверил показатели IndexOf и [i] у пользователя guide, и они оба указаны как O(log n). Так что это не должно быть проблемой. Вероятно, все еще несколько быстрее, но не более чем с фиксированным коэффициентом, вызывать конкретные методы для поиска соседей на линии развертки, т.е. Преемник и Predecessor, которые также равны O(log n).

So

[...]
try 
{
    Line2D above = sweepline.Successor(nl);
    if (above.intersectsLine(nl))
    {
        return false;
    }
}
catch (NoSuchItemException ignore) { }
[...]

Мне не нравится, что у них нет метода, который не выбрасывает исключение, так как выбрасывать исключения очень дорого. Ваша линия развертки обычно будет довольно полной, поэтому я думаю, что неудача в поиске будет редкой, и вызов Successor является наиболее эффективным способом. В качестве альтернативы вы можете продолжать вызывать IndexOf, как вы это делаете сейчас, но перед получением [index + 1] проверить, равно ли оно Count минус один, и вообще предотвратить создание исключения:

[...]
int index = sweepline.IndexOf(nl);
if( index < sweepline.Count-1 )
{
    Line2D above = sweepline[index + 1];
    if (above.intersectsLine(nl))
    {
        return false;
    }
}
[...]

Вторая глава руководства описывает равенство и сравнение для коллекций C5. Здесь тоже как минимум надо реализовать IEquatable<T> и IComparable<T>!

Еще одна мысль: вы сообщаете, что скармливаете алгоритму 700000 строк. Не могли бы вы начать с тайминга, например, 1000, 2500, 5000, 10000 строк и посмотреть, как алгоритм масштабируется для случаев, когда они не пересекаются?


О том, как сравнивать линии на развёртке:

Вам нужно найти какое-то естественное упорядочение для Line2D в Sweepline TreeSet, так как метод CompareTo просит вас сравнить один Line2D с другим. Один из Line2D уже находится в наборе деревьев Sweepline, другой только что обнаружен и добавляется.

Ваша линия развертки проходит снизу вверх, я думаю:

List<AlgEvent> SortedList = events.OrderBy(o => o.getY()).ToList();

Sweepline, проходящий через сегменты линии

Итак, предположим, что сегмент S1 был добавлен в TreeSet в событии 1, и мы хотим сравнить его с сегментом S2, который добавляется в событии 2 прямо сейчас.

Отрезки линии могут пересекаться в какой-то точке, что изменит порядок, но алгоритм проверит это сразу после их вставки, в проверках выше и ниже. Если подумать, то, что лучше было бы назвать левым и правым чеком.

В любом случае ... так что проще всего было бы сравнить нижние конечные точки обоих сегментов линии. Слева меньше, справа больше. Однако нам нужно посмотреть на порядок в положении линии развертки, и с тех пор они могли изменить свое положение, как на картинке.

Поэтому нам нужно сравнить нижнюю конечную точку S2 с красной точкой на S1 и посмотреть, находится ли она слева или справа от этой точки. Он лежит слева, поэтому S2 считается меньшим, чем S1.

Обычно все проще: если все S1 лежит слева от нижней конечной точки S2, то S1 меньше, чем S2. Если весь S1 лежит справа от нижней конечной точки S2, S1 больше, чем S2.

Я думаю, вы ищете более безопасную версию интерфейса:

public class Line2D : IComparable<Line2D>

Предполагая два свойства BottomY, самое низкое из двух значений Y, и BottomX, значение X самой низкой конечной точки, несколько проверенная попытка:

int IComparable<Line2D>.CompareTo(Line2D other)
{
    if( BottomY < other.BottomY )
    {
        return -other.CompareTo(this);
    }

    // we're the segment being added to the sweepline
    if( BottomX >= other.X1 && BottomX >= other.X2 )
    {
        return 1;
    }
    if( BottomX <= other.X1 && BottomX <= other.X2 )
    {
        return -1;
    }

    if( other.Y2 == other.Y1 )
    {
        // Scary edge case: horizontal line that we intersect with. Return 0?
        return 0;
    }

    // calculate the X coordinate of the intersection of the other segment
    // with the sweepline
    // double redX = other.X1 + 
    //    (BottomY - other.Y1) * (other.X2 - other.X1) / (other.Y2 - other.Y1);
    //
    // return BottomX.CompareTo(redX);

    // But more efficient, and more along the lines of the orientation comparison:
    return Comparer<Double>.Default.Compare(
        (BottomX - other.X1) * (other.Y2 - other.Y1),
        (BottomY - other.Y1) * (other.X2 - other.X1) );

}
person Community    schedule 15.09.2013
comment
Я мог ограничить данные чтением только 100 000 за раз. Было бы проще и быстрее, чем читать 700 000 за раз, а затем записывать время. - person Evan Parsons; 16.09.2013
comment
Мне трудно реализовать IComparable. Прямо сейчас он возвращает 600 000 недопустимых полигонов. Что определенно неверно. Я обновлю свой исходный пост с исправленным классом Line2D. - person Evan Parsons; 16.09.2013
comment
Я добавил несколько мыслей о том, как сравнивать Line2D. - person flup; 17.09.2013
comment
Я все еще в замешательстве, потребуется некоторое время, чтобы попытаться понять и сообщить, еще раз спасибо! - person Evan Parsons; 17.09.2013
comment
Я думал, что моя линия движется слева направо. Я упорядочил их по Y, так как они встречаются, когда он просматривает L-T-R. Я впервые вижу дно Y, другое дно Y, используемое в этом алгоритме. Я еще не реализовал IEquatable, но переопределил getHashCode и метод Equals. - person Evan Parsons; 17.09.2013
comment
Первоначально я основывал свой код на этом коде (был Java, но С# похож) ok" title="это реализация алгоритма shamos hoey в порядке">codereview.stackexchange.com/questions/69/ - person Evan Parsons; 17.09.2013
comment
Если вы хотите прокрутить слева направо, вам придется сортировать события по значению X, а не по Y, я думаю. И перепишите в leftmostx и y, а не в bottomx и y. Это немного забавно, потому что я только что повернул свою мысленную модель на 90 градусов против часовой стрелки, чтобы приспособиться к направлению вашей линии развертки. :) - person flup; 17.09.2013
comment
давайте продолжим это обсуждение в чате - person flup; 17.09.2013
comment
Эй, флап, SO не разрешает мгновенные сообщения, но не могли бы вы дать мне электронное письмо через evanparsons.net/contact.aspx Я так близко. Я думаю, что проблема сводится к моему IComparable, но я не могу быть в этом уверен. Я ударяю стену на этом. - person Evan Parsons; 18.09.2013

[исходный ответ]

Я не пользователь C#, но это должно немного ускорить работу.

  • меньше мусора в куче
  • не вычисляйте одно и то же дважды
  • избегайте всех подвызовов, если можете (удалить функции)

код:

public bool intersectsLine(const Line2D &comparedLine)
    {
    if ((X2==comparedLine.X1)&&(Y2==comparedLine.Y1)) return false;
    if ((X1==comparedLine.X2)&&(Y1==comparedLine.Y2)) return false;
    double dx1,dy1,dx2,dy2;
    dx1 = X2 - X1;
    dy1 = Y2 - Y1;
    dx2 = comparedLine.X2 - comparedLine.X1;
    dy2 = comparedLine.Y2 - comparedLine.Y1;
    double s,t,ax,ay,b;
    ax=X1-comparedLine.X1;
    ay=Y1-comparedLine.Y1;
    b=1.0/(-(dx2*dy1)+(dx1*dy2));
    s = (-(dy1*ax)+(dx1*ay))*b;
    t = ( (dx2*ay)-(dy2*ax))*b;
    if ((s>=0)&&(s<=1)&&(t>=0)&&(t<=1)) return true;
    return false; // No collision
    }

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

[править1]

После некоторого исследования данных о случайных линиях я пришел к следующему выводу:

  1. если слишком много линий по всей области, то никакие оптимизации недействительны
  2. если мелких строк больше, чем больше ускорение для любых оптимизаций
  3. грубая сила T((N*N-N)/2), что по-прежнему O(N*N) оценивается примерно в 35 часов для обработки 700 тыс. строк (непригодно для использования)
  4. оптимизированная грубая сила с разделением области T((((N/M)^2)-N)/2) - оптимизация ~O((N/M)^2) где

    • N is max of area lines number
    • M - это количество делений области на любую ось. Идея состоит в том, чтобы проверять только линии, пересекающие некоторую область (разделить область набора данных на M*M квадратов/прямоугольников). Для 700 тыс. линий лучше всего разделить на 16x16 областей. Измеренное время:

      0,540 с на 32 тыс. строк 1,950 с на 64 тыс. строк 7,000 с на 128 тыс. строк 27,514 с на 256 тыс. строк

    расчетное время выполнения составляет 3,7 минуты на 700 тыс. строк (для строк максимальной длиной ~10 % от всей площади). Я думаю, что это лучше, чем ваши 19 минут.

  5. другое ускорение возможно при использовании нескольких процессоров/ядер

    алгоритм полностью распараллелен и для 4 процессоров/ядер 3.7min/4 -> 56s или вы можете перенести его на GPU...

Мой оптимизированный алгоритм грубой силы с площадным подразделением O((((N/M)^2)-N)/2) — оптимизация

  1. получить размер используемой области (xmin,xmax,ymin,ymax) O(N)
  2. выберите подразделение M лучшее, что я пробовал для своих случайных наборов данных 32K-256K строк, было M=16
  3. цикл через всю область подразделения (равномерно разделенную область набора данных)

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

мой код (я использую BDS2006 C++ и свои собственные списки, поэтому вам нужно портировать его, чтобы он был совместим с вашим кодом)

void Twin_GLView2D::main_intersect(int M=16)
{
int ia,ib,i,j,N;
double zero=1e-6;
glview2D::_lin *l;
glview2D::_pnt p;

struct _line
    {
    double bx0,by0,bx1,by1;     // bounding rectangle
    double x0,y0,dx,dy;         // precomputed params
    } *lin,*a,*b;

struct _siz
    {
    double bx0,bx1,by0,by1;     // zone bounding rectangle
    } sz,bz;
List<_line*> zone;

// load and precompute lines
N=view.lin.num;
lin=new _line[N];
if (lin==NULL) return;
for (a=lin,l=view.lin.dat,ia=0;ia<N;ia++,a++,l++)
    {
    // line ...
    if (l->p0.p[0]<=l->p1.p[0]) { a->bx0=l->p0.p[0]; a->bx1=l->p1.p[0]; }
    else                        { a->bx0=l->p1.p[0]; a->bx1=l->p0.p[0]; }
    if (l->p0.p[1]<=l->p1.p[1]) { a->by0=l->p0.p[1]; a->by1=l->p1.p[1]; }
    else                        { a->by0=l->p1.p[1]; a->by1=l->p0.p[1]; }
    a->x0=l->p0.p[0]; a->dx=l->p1.p[0]-l->p0.p[0];
    a->y0=l->p0.p[1]; a->dy=l->p1.p[1]-l->p0.p[1];
    // global image size for zone subdivision
    if (!ia)
        {
        sz.bx0=l->p0.p[0];
        sz.by0=l->p0.p[1];
        sz.bx1=sz.bx0;
        sz.by1=sz.by0;
        }
    if (sz.bx0>l->p0.p[0]) sz.bx0=l->p0.p[0];
    if (sz.bx1<l->p0.p[0]) sz.bx1=l->p0.p[0];
    if (sz.by0>l->p0.p[1]) sz.by0=l->p0.p[1];
    if (sz.by1<l->p0.p[1]) sz.by1=l->p0.p[1];
    if (sz.bx0>l->p1.p[0]) sz.bx0=l->p1.p[0];
    if (sz.bx1<l->p1.p[0]) sz.bx1=l->p1.p[0];
    if (sz.by0>l->p1.p[1]) sz.by0=l->p1.p[1];
    if (sz.by1<l->p1.p[1]) sz.by1=l->p1.p[1];
    }
// process lines by zonal subdivision
zone.allocate(N);
view.pnt.num=0; view.pnt.allocate(view.lin.num);
sz.bx1-=sz.bx0; sz.bx1/=double(M);
sz.by1-=sz.by0; sz.by1/=double(M);
for (bz.by0=sz.by0,bz.by1=sz.by0+sz.by1,i=0;i<M;i++,bz.by0+=sz.by1,bz.by1+=sz.by1)
for (bz.bx0=sz.bx0,bz.bx1=sz.bx0+sz.bx1,j=0;j<M;j++,bz.bx0+=sz.bx1,bz.bx1+=sz.bx1)
    {
    // create list of lines for actual zone only
    zone.num=0;         // clear zone list
    for (a=lin,ia=   0;ia<N;ia++,a++)
     if ((a->bx0<=bz.bx1)&&(a->bx1>=bz.bx0))
      if ((a->by0<=bz.by1)&&(a->by1>=bz.by0))
       zone.add(a); // add line to zone list
    // check for intersection within zone only
    // O((((N/M)^2)-N)/2) - optimizations
    for (ia=   0,a=zone.dat[ia];ia<zone.num;ia++,a=zone.dat[ia])
    for (ib=ia+1,b=zone.dat[ib];ib<zone.num;ib++,b=zone.dat[ib])
        {
        // discart lines with non intersecting bound rectangles
        if (a->bx1<b->bx0) continue;
        if (a->bx0>b->bx1) continue;
        if (a->by1<b->by0) continue;
        if (a->by0>b->by1) continue;
        // 2D lines a,b intersect ?
        double x0,y0,x1,y1,t0,t1;
        // compute intersection
        t1=divide(a->dx*(a->y0-b->y0)+a->dy*(b->x0-a->x0),(a->dx*b->dy)-(b->dx*a->dy));
        x1=b->x0+(b->dx*t1);
        y1=b->y0+(b->dy*t1);
        if (fabs(a->dx)>=fabs(a->dy)) t0=divide(b->x0-a->x0+(b->dx*t1),a->dx);
        else                          t0=divide(b->y0-a->y0+(b->dy*t1),a->dy);
        x0=a->x0+(a->dx*t0);
        y0=a->y0+(a->dy*t0);
        // check if intersection exists
        if (fabs(x1-x0)>zero) continue;
        if (fabs(y1-y0)>zero) continue;
        if ((t0<0.0)||(t0>1.0)) continue;
        if ((t1<0.0)||(t1>1.0)) continue;
        // if yes add point
        p.p[0]=x0;
        p.p[1]=y0;
        p.p[2]=0.0;
        // do not add points out of zone (allmost all duplicit points removal)
        if (x0<bz.bx0) continue;
        if (x0>bz.bx1) continue;
        if (y0<bz.by0) continue;
        if (y0>bz.by1) continue;
        view.pnt.add(p);
        }
    }
view.redraw=true;
delete lin;
}

Примечания:

  1. List<T> x; is the same as T x[] with 'unlimited' size
    • x.num; is actual size of x[] in Ts not Bytes !!! index = <0,x.num-1>
    • x.add(q); добавляет q в список в конце
    • x.num=0; очищает список
    • x.allocate(N); выделить место для N элементов в списке, чтобы избежать перемещений
  2. вход List<> равен view.lin ... содержит точки p0,p1 каждая имеет double p[2] ... x,y
  3. вывод List<> равен view.pnt... содержит double p[2]... x,y

[Изменить2]

Кроме того, я обнаружил, что наилучшая производительность вышеприведенного алгоритма достигается, когда M=12+(N>>15)

  • M - количество областей подразделения на ось
  • N количество строк для проверки
person Spektre    schedule 11.09.2013
comment
вы можете быть на что-то для скорости. Предоставленный код не быстрее моего, однако, когда я заставляю свой метод intersectsLine возвращать true или false, он завершается за 19 минут, а не просто истекает время ожидания. Есть ли более быстрый способ определить, произошло ли пересечение? (Точная точка не требуется) - person Evan Parsons; 13.09.2013
comment
трудно сказать, не зная свойств вашего набора данных, ... обычно умная сортировка с изменением порядка и / или удаление неважных данных приводит к значительному увеличению скорости. - person Spektre; 13.09.2013
comment
Можете ли вы опубликовать свой пример набора данных где-нибудь? так что любой может проверить ... его 2D, поэтому экспорт в текстовый файл svg или ASCII будет в порядке. P.S. моя версия intersectsLine не быстрее при выполнении, а в куче мусора и накладных расходах. Так что, если вы измеряете время для одиночного выстрела, большой разницы быть не должно. но если вы зациклите его вызов 10000 раз, вы должны измерить разницу. , также будет интересно увидеть пример желаемого результата. - person Spektre; 16.09.2013
comment
Просто добавил интересную информацию, так что проверьте. (мне нужны точные точки пересечения) единственным недостатком моего алгоритма является то, что если пересечение находится точно на границе области, то оно будет дублироваться). - person Spektre; 16.09.2013
comment
Я собираюсь попробовать ваш метод грубой силы сегодня вечером. Я должен упомянуть, что это 700 000 полигонов с от 5 до 4 500 линий в каждом полигоне. - person Evan Parsons; 23.09.2013
comment
вау, это огромный объем данных, сколько у вас памяти (может быть, у вас проблемы не со скоростью, а с памятью)? Мой алгоритм оптимизирован для использования с линиями (мне нужно, чтобы это было так) для лучшей оптимизации полигонов вы должны сначала проверить только ограничивающие прямоугольники всех полигонов и отбросить все непересекающиеся, что должно немного облегчить все и требования к памяти для этого не большой (мин, макс * количество измерений и флаг пересечения для каждого полигона). - person Spektre; 24.09.2013
comment
Я прочитал 700 000 из двоичного файла, о проблемах с памятью не может быть и речи. - person Evan Parsons; 24.09.2013
comment
ах да, я забыл, что вам не нужны точки пересечения, просто отметьте, если многоугольник пересекается. В моем случае для 700K+ строк таблицы памяти становятся большими. кстати как ваши результаты? если вы можете поделиться одним разреженным/заархивированным набором данных с информацией о формате, я хотел бы попытаться закодировать и протестировать его самостоятельно для удовольствия ( :-) и я думаю, что со временем это будет полезно для меня) конечно, я надеюсь, что архивный файл это не 1гб :) или конфиденциально - person Spektre; 24.09.2013
comment
К сожалению, я не могу поделиться данными, однако я обновил свой код для этого вопроса stackoverflow.com/questions/18386108/ - person Evan Parsons; 24.09.2013