Okay, I am now getting the correct information from my current algorithm! However, with 700,000 polygons to check, it\'s just way too slow! The previous issue is fixed (My L
[original answer]
I am not C# user, but this should speeds things up a little.
code:
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
}
for the rest of your code, add time measurements to find what exactly slow things down. My guess is on List management ... unnecessary reallocations can slow things considerably.
[edit1]
After some research on random line data I concluded this:
T((N*N-N)/2) which is still O(N*N)
estimate around 35 hours for 700K lines to be processed (unusable)optimized brute force with area subdivision is T((((N/M)^2)-N)/2) - optimizations ~O((N/M)^2) where
N is max of area lines numberM is number of area divisions per any axis
idea is to check only lines crossing some region (divide dataset area to M*M squares/rectangles). For 700K lines is best subdivision to 16x16 areas. Measured times:
0.540s per 32K lines 1.950s per 64K lines 7.000s per 128K lines 27.514s per 256K lines
estimated run time is 3.7 min per 700K lines (for lines at max ~10% length of whole area). I think this is better than yours 19 minutes.
another speed up is possible with use of multi CPU/core
algorithm is fully parallel-isable and for 4 CPU/Cores 3.7min/4 -> 56s or you can port it to GPU ...
My optimized brute force algorithm with area subdivision O((((N/M)^2)-N)/2) - optimizations
(xmin,xmax,ymin,ymax) O(N)M
the best I try for my random datasets 32K-256K lines was M=16cycle through all subdivision area (evenly divided dataset area)
create list of lines crossing actual subdivision area and check intersection for all lines in that list. If do not want duplicate intersections then discard all intersection outside current area
my code (I am using BDS2006 C++ and my own lists so you need to port it to be compatible with your code)
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;iap0.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.bx1p0.p[0]) sz.bx1=l->p0.p[0];
if (sz.by0>l->p0.p[1]) sz.by0=l->p0.p[1];
if (sz.by1p0.p[1]) sz.by1=l->p0.p[1];
if (sz.bx0>l->p1.p[0]) sz.bx0=l->p1.p[0];
if (sz.bx1p1.p[0]) sz.bx1=l->p1.p[0];
if (sz.by0>l->p1.p[1]) sz.by0=l->p1.p[1];
if (sz.by1p1.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;ibx0<=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];iabx1bx0) continue;
if (a->bx0>b->bx1) continue;
if (a->by1by0) 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 (x0bz.bx1) continue;
if (y0bz.by1) continue;
view.pnt.add(p);
}
}
view.redraw=true;
delete lin;
}
Notes:
List 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); adds q to the list at the endx.num=0; clears the listx.allocate(N); allocate space for N items in list to avoid relocationsList<> is view.lin ... contains points p0,p1 each have double p[2] ... x,yList<> is view.pnt ... contains double p[2] ... x,y[Edit2]
In addition I found out that the best performance of above algorithm is when M=12+(N>>15)
M is subdivision areas count per axisN is number of lines to check