Note that there are some explanatory texts on larger screens.

plurals
  1. PO
    primarykey
    data
    text
    <p><strong>[original answer]</strong></p> <p>I am not <strong>C#</strong> user, but this should speeds things up a little.</p> <ul> <li>less heap trashing</li> <li>do not compute the same thing twice</li> <li>avoid all sub calls if you can (get functions removed)</li> </ul> <p>code:</p> <pre><code>public bool intersectsLine(const Line2D &amp;comparedLine) { if ((X2==comparedLine.X1)&amp;&amp;(Y2==comparedLine.Y1)) return false; if ((X1==comparedLine.X2)&amp;&amp;(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&gt;=0)&amp;&amp;(s&lt;=1)&amp;&amp;(t&gt;=0)&amp;&amp;(t&lt;=1)) return true; return false; // No collision } </code></pre> <p>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.</p> <p><strong>[edit1]</strong></p> <p>After some research on random line data I concluded this:</p> <ol> <li>if too many lines are across the entire area than no optimizations are valid</li> <li>if there are more small lines than there is more speedup for any optimizations</li> <li>brute force is <code>T((N*N-N)/2)</code> which is still <code>O(N*N)</code> estimate around 35 hours for 700K lines to be processed (unusable)</li> <li><p>optimized brute force with area subdivision is <code>T((((N/M)^2)-N)/2)</code> - optimizations <code>~O((N/M)^2)</code> where </p> <ul> <li><code>N</code> is max of area lines number</li> <li><p><code>M</code> is number of area divisions per any axis idea is to check only lines crossing some region (divide dataset area to <code>M*M</code> squares/rectangles). For 700K lines is best subdivision to <code>16x16</code> areas. Measured times: </p> <p>0.540s per 32K lines 1.950s per 64K lines 7.000s per 128K lines 27.514s per 256K lines</p></li> </ul> <p>estimated run time is 3.7 min per 700K lines <strong>(for lines at max ~10% length of whole area)</strong>. I think this is better than yours 19 minutes.</p></li> <li><p>another speed up is possible with use of multi CPU/core </p> <p>algorithm is fully parallel-isable and for 4 CPU/Cores <code>3.7min/4 -&gt; 56s</code> or you can port it to GPU ...</p></li> </ol> <p><strong>My optimized brute force algorithm with area subdivision O((((N/M)^2)-N)/2) - optimizations</strong></p> <ol> <li>get the used area size <code>(xmin,xmax,ymin,ymax)</code> <code>O(N)</code></li> <li>select subdivision <code>M</code> the best I try for my random datasets <code>32K-256K</code> lines was <code>M=16</code></li> <li><p>cycle through all subdivision area (evenly divided dataset area)</p> <p>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</p></li> </ol> <p>my code (I am using <strong>BDS2006 C++</strong> and my own lists so you need to port it to be compatible with your code)</p> <pre><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&lt;_line*&gt; 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&lt;N;ia++,a++,l++) { // line ... if (l-&gt;p0.p[0]&lt;=l-&gt;p1.p[0]) { a-&gt;bx0=l-&gt;p0.p[0]; a-&gt;bx1=l-&gt;p1.p[0]; } else { a-&gt;bx0=l-&gt;p1.p[0]; a-&gt;bx1=l-&gt;p0.p[0]; } if (l-&gt;p0.p[1]&lt;=l-&gt;p1.p[1]) { a-&gt;by0=l-&gt;p0.p[1]; a-&gt;by1=l-&gt;p1.p[1]; } else { a-&gt;by0=l-&gt;p1.p[1]; a-&gt;by1=l-&gt;p0.p[1]; } a-&gt;x0=l-&gt;p0.p[0]; a-&gt;dx=l-&gt;p1.p[0]-l-&gt;p0.p[0]; a-&gt;y0=l-&gt;p0.p[1]; a-&gt;dy=l-&gt;p1.p[1]-l-&gt;p0.p[1]; // global image size for zone subdivision if (!ia) { sz.bx0=l-&gt;p0.p[0]; sz.by0=l-&gt;p0.p[1]; sz.bx1=sz.bx0; sz.by1=sz.by0; } if (sz.bx0&gt;l-&gt;p0.p[0]) sz.bx0=l-&gt;p0.p[0]; if (sz.bx1&lt;l-&gt;p0.p[0]) sz.bx1=l-&gt;p0.p[0]; if (sz.by0&gt;l-&gt;p0.p[1]) sz.by0=l-&gt;p0.p[1]; if (sz.by1&lt;l-&gt;p0.p[1]) sz.by1=l-&gt;p0.p[1]; if (sz.bx0&gt;l-&gt;p1.p[0]) sz.bx0=l-&gt;p1.p[0]; if (sz.bx1&lt;l-&gt;p1.p[0]) sz.bx1=l-&gt;p1.p[0]; if (sz.by0&gt;l-&gt;p1.p[1]) sz.by0=l-&gt;p1.p[1]; if (sz.by1&lt;l-&gt;p1.p[1]) sz.by1=l-&gt;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&lt;M;i++,bz.by0+=sz.by1,bz.by1+=sz.by1) for (bz.bx0=sz.bx0,bz.bx1=sz.bx0+sz.bx1,j=0;j&lt;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&lt;N;ia++,a++) if ((a-&gt;bx0&lt;=bz.bx1)&amp;&amp;(a-&gt;bx1&gt;=bz.bx0)) if ((a-&gt;by0&lt;=bz.by1)&amp;&amp;(a-&gt;by1&gt;=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&lt;zone.num;ia++,a=zone.dat[ia]) for (ib=ia+1,b=zone.dat[ib];ib&lt;zone.num;ib++,b=zone.dat[ib]) { // discart lines with non intersecting bound rectangles if (a-&gt;bx1&lt;b-&gt;bx0) continue; if (a-&gt;bx0&gt;b-&gt;bx1) continue; if (a-&gt;by1&lt;b-&gt;by0) continue; if (a-&gt;by0&gt;b-&gt;by1) continue; // 2D lines a,b intersect ? double x0,y0,x1,y1,t0,t1; // compute intersection t1=divide(a-&gt;dx*(a-&gt;y0-b-&gt;y0)+a-&gt;dy*(b-&gt;x0-a-&gt;x0),(a-&gt;dx*b-&gt;dy)-(b-&gt;dx*a-&gt;dy)); x1=b-&gt;x0+(b-&gt;dx*t1); y1=b-&gt;y0+(b-&gt;dy*t1); if (fabs(a-&gt;dx)&gt;=fabs(a-&gt;dy)) t0=divide(b-&gt;x0-a-&gt;x0+(b-&gt;dx*t1),a-&gt;dx); else t0=divide(b-&gt;y0-a-&gt;y0+(b-&gt;dy*t1),a-&gt;dy); x0=a-&gt;x0+(a-&gt;dx*t0); y0=a-&gt;y0+(a-&gt;dy*t0); // check if intersection exists if (fabs(x1-x0)&gt;zero) continue; if (fabs(y1-y0)&gt;zero) continue; if ((t0&lt;0.0)||(t0&gt;1.0)) continue; if ((t1&lt;0.0)||(t1&gt;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&lt;bz.bx0) continue; if (x0&gt;bz.bx1) continue; if (y0&lt;bz.by0) continue; if (y0&gt;bz.by1) continue; view.pnt.add(p); } } view.redraw=true; delete lin; } </code></pre> <p>Notes:</p> <ol> <li><code>List&lt;T&gt; x;</code> is the same as <code>T x[]</code> with 'unlimited' size <ul> <li><code>x.num;</code> is actual size of <code>x[]</code> in Ts not Bytes !!! <code>index = &lt;0,x.num-1&gt;</code></li> <li><code>x.add(q);</code> adds <code>q</code> to the list at the end</li> <li><code>x.num=0;</code> clears the list</li> <li><code>x.allocate(N);</code> allocate space for <code>N</code> items in list to avoid relocations</li> </ul></li> <li>input <code>List&lt;&gt;</code> is <code>view.lin</code> ... contains points <code>p0,p1</code> each have <code>double p[2]</code> ... <code>x,y</code></li> <li>output <code>List&lt;&gt;</code> is <code>view.pnt</code> ... contains <code>double p[2]</code> ... <code>x,y</code></li> </ol> <p><strong>[Edit2]</strong></p> <p>In addition I found out that the best performance of above algorithm is when <code>M=12+(N&gt;&gt;15)</code></p> <ul> <li><code>M</code> is subdivision areas count per axis</li> <li><code>N</code> is number of lines to check</li> </ul>
    singulars
    1. This table or related slice is empty.
    plurals
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. VO
      singulars
      1. This table or related slice is empty.
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload