Implementacja algorytmu brutalnej siły do ​​wykrywania przecinającego się wielokąta

Początkowo zaimplementowałem algorytm Hoeya-Shamosa, jednak jest on zbyt złożony, aby można go było w przyszłości utrzymać (nie mam w tym nic do powiedzenia) i nie raportował poprawnie, więc zoptymalizowany algorytm brute force jest tym, z czego będę korzystać.

Moje pytanie brzmi: jak mogę zoptymalizować ten kod, aby był użyteczny?

W obecnej postaci mój kod zawiera zagnieżdżoną pętlę for, powtarzającą tę samą listę dwa razy.

EDYCJA: Przekręciłem linie w HashSet i użyłem dwóch pętli foreach ... ogoliłem około 45 sekund skanowania 10.000. To wciąż za mało.

foreach (Line2D g in lines)
{                   
foreach (Line2D h in lines)
{
    if (g.intersectsLine(h))
    {
        return false;
    }
}                  

 } // end 'lines' for each loop

Jeśli wymuszę metodę „intersectsLine ()”, aby zwrócić false (w celach testowych), skanowanie skanowanych 10 000 rekordów trwa nadal 8 sekund (mam 700 000 rekordów). To za długo, więc muszę zoptymalizować ten fragment kodu.

Próbowałem usunąć linie z Listy po porównaniu z wszystkimi innymi liniami, jednak istnieje problem z dokładnością (nie wiem dlaczego), a wzrost prędkości jest ledwo zauważalny.

Oto moja metoda intersectsLine. Znalazłem alternatywne podejścietutaj ale wygląda na to, że będzie wolniejszy przy wszystkich wywołaniach metod i tym podobnych. Obliczanie nachylenia nie wydaje mi się, aby wymagało to zbyt dużej mocy obliczeniowej (popraw mnie, jeśli się mylę?)

public bool intersectsLine(Line2D comparedLine)
{

//tweakLine(comparedLine);
if (this.Equals(comparedLine) ||
    P2.Equals(comparedLine.P1) ||
    P1.Equals(comparedLine.P2))
{
    return false;
}

double firstLineSlopeX, firstLineSlopeY, secondLineSlopeX, secondLineSlopeY;

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

secondLineSlopeX = comparedLine.X2 - comparedLine.X1;
secondLineSlopeY = comparedLine.Y2 - comparedLine.Y1;

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

if (s >= 0 && s <= 1 && t >= 0 && t <= 1)
{
    //console.WriteLine("s = {0}, t = {1}", s, t);
    //console.WriteLine("this: " + this);
    //console.WriteLine("other: " + comparedLine);
    return true;
}

return false; // No collision */

}

EDYTOWAĆ: Głównym wąskim gardłem są duże wielokąty! Wykluczyłem prowadzenie wielokątów z więcej niż 100 liniami i uruchomiłem wszystkie 700 000 + wielokątów w 5:10. Który jest w dopuszczalnym zakresie! Z pewnością istnieje sposób, aby sprawdzić, czy wielobok jest warty obliczenia przed uruchomieniem tego kodu? Mam dostęp do właściwości XMin, Xmax, YMin i YMax, jeśli to pomaga?

Przeprowadził kolejny test, ograniczając wielokąty do poniżej 1000 linii każdy. Trwało to trochę ponad godzinę.

Usunąłem wszystkie ograniczenia wielokątów i działa już 36 godzin ... nadal nie ma wyników.

Mam kilka pomysłów:

-Gdy generuję hashset linii, mam inny zestaw / listę, która ma kandydatów do przecięcia. Dodałbym tylko linie do tej listy, jeśli jest szansa na skrzyżowanie. Ale jak mogę wyeliminować / dodać możliwości? Jeśli są tylko trzy linie, które mogłyby się przecinać z innymi, porównałbym 4000 linii z 3 zamiast z 4000. Tylko to mogłoby spowodować OGROMNĄ różnicę.

-Jeśli ten sam punkt występuje dwukrotnie, z wyjątkiem pierwszego i ostatniego punktu, pomiń uruchamianie zagnieżdżonej pętli for.

Edytować:

Informacje o wielokątach: 700 000 łącznie

Istnieje ponad cztery tysiące wielokątów z 1000 lub więcej punktów

Istnieją 2 wielokąty z 70 000 lub więcej punktów

Myślę, że jest to możliwe, aby uzyskać to do piętnastu minut przy odrobinie kreatywności.

questionAnswers(3)

yourAnswerToTheQuestion