home *** CD-ROM | disk | FTP | other *** search
-
- //------------------------------------------------------------------------------
- //
- // Mulmuley's randomized algorithm to compute the intersections of a set of
- // line segments
- //
- // implemented by Bettina Preis
- //
- //------------------------------------------------------------------------------
-
-
- /* 1. read segments
- 2. build frame
- 3. draw vertical attachments through all endpoints
- 4. randomly select segment
- 5. start on a endpoint,
- repeat
- FACE TRAVERSAL
- and
- FACE TRANSITION,
- until other endpoint reached
- 6. repeat 4. and 5., until all segments are processed
- */
-
-
-
- #include <LEDA/list.h>
- #include <LEDA/graph.h>
- #include <LEDA/plane.h>
- #include <LEDA/d_array.h>
- #include <LEDA/window.h>
-
- #define eps 0.00001
-
- window W;
-
- double xmin, xmax, ymin, ymax;
-
- edge frame_e_lower,frame_e_upper;
-
-
- int WAIT = 300;
-
- void DRAW_EDGE(point a, point b, color c = black) { W.draw_edge(a,b,c); }
- void DRAW_EDGE(segment s, color c = black) { W.draw_edge(s,c); }
-
- /*****************************************************************************/
-
- /*
- declared in plane.h:
-
- int compare(point& p1,point& p2)
- {
- int result = compare(p1.xcoord(),p2.xcoord());
- if (result == 0)
- return compare(p1.ycoord(),p2.ycoord());
- else return result;
- }
- */
-
- /*****************************************************************************/
-
- int compare(segment& s1,segment& s2)
- {
- int result = compare(s1.start(),s2.start());
- return result;
- }
-
- /*****************************************************************************/
-
- int cmp_points(point& p1,point& p2)
- { return compare(p1.xcoord(),p2.xcoord()); }
-
- /*****************************************************************************/
-
- declare2(GRAPH,point,segment);
- GRAPH(point,segment) G;
-
- declare2(d_array,point,node);
- d_array(point,node) node_of;
-
- /*****************************************************************************/
-
- struct frame
- {
- point a; // left lower corner
- point b; // right upper corner
- };
-
- frame Fr;
-
- /*****************************************************************************/
-
- node new_node(point p)
- {
- node_of[p] = G.new_node(p);
- return node_of[p];
- }
-
- /*****************************************************************************/
-
- void wait()
- {
- for (int i=1;i<1000*WAIT;i++) {}
- }
-
- /*****************************************************************************/
-
- void frame_max(double wert,char ch)
- {
- // adapt frame frontiers to the read segments
-
- if (ch == 'x')
- {
- if(wert<xmin) xmin=wert;
- else
- if(wert>xmax) xmax=wert;
- }
- else
- {
- if(wert<ymin) ymin=wert;
- else
- if(wert>ymax) ymax=wert;
- }
- }
-
- /*****************************************************************************/
-
- void build_frame(double x1, double x2, double y1, double y2,frame& F)
- {
- // build frame from frame frontiers
- edge edg;
- point p1(x1,y1);
- point p2(x2,y1);
- point p3(x2,y2);
- point p4(x1,y2);
- node kn1 = G.new_node(p1); W.draw_filled_node(x1,y1);
- node kn2 = G.new_node(p2); W.draw_filled_node(x2,y1);
- node kn3 = G.new_node(p3); W.draw_filled_node(x2,y2);
- node kn4 = G.new_node(p4); W.draw_filled_node(x1,y2);
- segment seg = segment(p1,p2);
- frame_e_lower = G.new_edge(kn1, kn2, seg);
- DRAW_EDGE(p1,p2);
- seg = segment(p2,p3);
- edg = G.new_edge(kn2, kn3, seg);
- DRAW_EDGE(p2,p3);
- seg = segment(p3,p4);
- frame_e_upper = G.new_edge(kn3, kn4, seg);
- DRAW_EDGE(p3,p4);
- seg = segment(p4,p1);
- edg = G.new_edge(kn4, kn1, seg);
- DRAW_EDGE(p4,p1);
- F.a = p1;
- F.b = p3;
- }
-
- /*****************************************************************************/
-
- bool vertical(segment seg)
- {
- /* true, if segment vertical
- false, if not */
-
- double diff = seg.xcoord1() - seg.xcoord2();
-
- return (fabs(diff) < eps);
- }
-
- /*****************************************************************************/
-
- void make_vertical_attachment(point pkt,edge e_lower,edge e_upper)
- {
- /* adds the endpoint and the vertical edges from the endpoint to the frame
- and vice versa to the graph
- furthermore, splits the upper and lower frame edges on the points of
- attachment
- */
-
- point p1,p2;
- segment seg;
- node kn,kn1,kn2;
- edge edg;
-
- kn = new_node(pkt);
- W.draw_filled_node(pkt);
-
- p1=point(pkt.xcoord(),Fr.b.ycoord());
- kn1 = G.new_node(p1); // upper node of attachment
- W.draw_filled_node(p1);
-
- p2 = point(pkt.xcoord(),Fr.a.ycoord());
- kn2 = G.new_node(p2); // lower node of attachment
- W.draw_filled_node(p2);
-
-
- // new vertical edges
-
- seg = segment(p1,pkt);
- edg = G.new_edge(kn1,kn,seg);
- DRAW_EDGE(p1,pkt);
-
- seg = segment(pkt,p2);
- edg = G.new_edge(kn,kn2,seg);
- DRAW_EDGE(pkt,p2);
-
- seg = segment(p2,pkt);
- edg = G.new_edge(kn2,kn,seg);
- DRAW_EDGE(p2,pkt);
-
- seg = segment(pkt,p1);
- edg = G.new_edge(kn,kn1,seg);
- DRAW_EDGE(pkt,p1);
-
- wait();
-
- // new upper frame edges :
-
- DRAW_EDGE(G[e_upper],white);
- seg = segment(p1,G[e_upper].end());
- edg = G.new_edge(kn1,G.target(e_upper),seg);
- DRAW_EDGE(p1,G[G.target(e_upper)]);
- seg = segment(G[e_upper].start(),p1);
- edg = G.new_edge(G.source(e_upper),kn1,seg);
- DRAW_EDGE(G[G.source(e_upper)],p1);
- G.del_edge(e_upper);
- frame_e_upper = edg;
-
- wait();
-
- // new lower frame edges :
-
- DRAW_EDGE(G[e_lower],white);
- seg = segment(G[e_lower].start(),p2);
- edg = G.new_edge(G.source(e_lower),kn2,seg);
- DRAW_EDGE(G[G.source(e_lower)],p2);
- seg = segment(p2,G[e_lower].end());
- edg = G.new_edge(kn2,G.target(e_lower),seg);
- DRAW_EDGE(p2,G[G.target(e_lower)]);
- G.del_edge(e_lower);
- frame_e_lower = edg;
-
- wait();
- }
-
- /*****************************************************************************/
-
- void insert_in_edge(node kn,edge edg,edge& f_edge,edge& s_edge)
- {
- /* split edge edg on node kn into two edges f_edge (first edge)
- and s_edge (second edge)
- */
-
- segment f_seg,s_seg;
-
- f_seg = segment(G[G.source(edg)],G[kn]);
- f_edge = G.new_edge(G.source(edg),kn,f_seg);
- DRAW_EDGE(f_seg);
-
- wait();
-
- s_seg = segment(G[kn],G[G.target(edg)]);
- s_edge = G.new_edge(kn,G.target(edg),s_seg);
- DRAW_EDGE(s_seg);
-
- wait();
-
- G.del_edge(edg);
- }
-
- /*****************************************************************************/
-
- point face_traversal(segment seg, edge edg, edge& succ_e, edge& pred_e)
- {
- /* travelling through a face until the intersection
- between the segment and a face border is found
- succ_e is the intersected face border
- pred_e is the predecessor border of succ_edge
- */
-
- point inter;
- double angl;
- double min_angle;
- edge edg2;
-
-
- do
- {
- min_angle = M_PI;
- forall_adj_edges(edg2,G.target(edg))
- {
- // angle between edg2 and edg
- segment s = G[edg2];
- segment t = G[edg];
-
- angl = s.angle(t);
-
- // angl = G[edg2].angle(G[edg]);
-
- if ((angl > -M_PI) && (angl <= min_angle))
- {
- min_angle = angl;
- succ_e = edg2;
- }
- }
- pred_e = edg;
- edg = succ_e;
- }
- while (! seg.intersection(G[succ_e],inter));
- return inter;
- }
-
- /*****************************************************************************/
-
- edge face_transition(segment seg, edge edg)
- {
- /* find next face that must be traversed
- return first border for next face_traversal */
-
- double angl;
- point inter;
- edge succ_edge, edg2;
- edge return_edge = nil;
- edge corner_edge = nil;
- edge act_edge = nil;
-
- do
- {
- succ_edge = nil;
- edg2 = G.first_adj_edge(G.target(edg));
-
- for (;;)
- {
- angl = G[edg2].angle(G[edg]);
- double diff = fabs(angl) - M_PI;
- if (fabs(diff) < eps)
- {
- return_edge = edg2;
- break;
- }
- if (fabs(angl) < eps)
- succ_edge = edg2;
- edg2 = G.adj_succ(edg2);
- }
- edg = succ_edge;
-
- } while (return_edge == nil);
-
- act_edge = return_edge;
-
- while(! seg.intersection(G[act_edge],inter))
- {
- edg2 = G.first_adj_edge(G.target(edg));
- while (edg2 != nil)
- {
- angl = G[edg2].angle(G[act_edge]);
- if (fabs(angl) < eps )
- {
- act_edge = edg2;
- break;
- }
- edg2 = G.adj_succ(edg2);
- }
- }
-
- return act_edge;
- }
-
- /*****************************************************************************/
-
- void delete_edges(list(edge)& e_list)
- {
- // deletes upper vertical attachments
-
- list_item l_it;
- edge edg;
-
- l_it = e_list.first();
-
- while (l_it != nil)
- {
- edg = e_list.del(l_it);
- G.del_edge(edg);
- l_it = e_list.first();
- }
- }
-
- /*****************************************************************************/
- /*****************************************************************************/
-
- list(point) fmul(list(segment)& L)
- {
- /* for all segments : xcoord of first endpoint is smaller then
- xcoord of second endpoint */
-
- double angl;
- point p,p_pred,p_succ,point_of_inter;
- list_item l_it;
- list(point) p_list,inter_p_list;
- list(edge) edg_list;
- segment seg,seg1,seg2;
- node start_node,kn;
- edge start_edge, succ_edge, pred_edge, first_edge, first2_edge, second_edge, second2_edge, edg1, edg2, edg4, edg8;
-
- /* initialisation of xmin, xmax, ymin, ymax (frame frontiers)
- by the first segment */
-
- seg = L.head();
-
- xmin = seg.xcoord1();
- xmax = seg.xcoord2();
-
- double r1 = seg.ycoord1();
- double r2 = seg.ycoord2();
-
- if (r1 < r2)
- {
- ymin = r1;
- ymax = r2;
- }
- else
- {
- ymin = r2;
- ymax = r1;
- }
-
- // expand frame frontiers
- forall(seg,L)
- {
- if (seg.vertical()) error_handler(1,"vertical segment");
-
- frame_max(seg.xcoord1(),'x');
- frame_max(seg.ycoord1(),'y');
- frame_max(seg.xcoord2(),'x');
- frame_max(seg.ycoord2(),'y');
- }
-
-
- // initialisation of the frame
- build_frame(xmin-1,xmax+1,ymin-1,ymax+1,Fr);
-
- wait();
-
- /* make a list of all endpoints */
-
- forall(seg,L)
- {
- p = seg.start();
- l_it = p_list.append(p);
- p = seg.end();
- l_it = p_list.append(p);
- }
-
- // sort endpoints from left to right
- p_list.sort(cmp_points);
-
- // initialisation of the first ("stripped") partition
- forall(p,p_list)
- {
- make_vertical_attachment(p,frame_e_lower,frame_e_upper);
-
- }
-
-
- // algorithm begins
-
- forall(seg,L)
- {
- p = seg.end(); // endpoint to be inserted
-
- start_node = node_of[p];
- start_edge = nil;
- edg8 = G.first_adj_edge(start_node);
- while (edg8 != nil)
- {
- if (G[edg8].ycoord1() < G[edg8].ycoord2())
- {
- start_edge = edg8;
- break;
- }
- else
- edg8 = G.adj_succ(edg8);
- }
-
-
- do
- {
- point_of_inter = face_traversal(seg,start_edge,succ_edge,pred_edge);
-
- if (point_of_inter != seg.start())
- {
-
- kn = G.new_node(point_of_inter);
- W.draw_filled_node(point_of_inter);
- start_edge = nil;
-
- insert_in_edge(kn,succ_edge,first_edge,second_edge);
-
-
- // new edges through face
-
- seg1 = segment(G[start_node],point_of_inter);
- edg1 = G.new_edge(start_node,kn,seg1);
- DRAW_EDGE(seg1);
-
- wait();
-
- seg2 = segment(point_of_inter,G[start_node]);
- edg2 = G.new_edge(kn,start_node,seg2);
- DRAW_EDGE(seg2);
-
- wait();
- }
-
- else
- {
- kn = node_of[seg.start()];
-
- // new edges through face
-
- seg1 = segment(G[start_node],seg.start());
- edg1 = G.new_edge(start_node,kn,seg1);
- DRAW_EDGE(seg1);
-
- wait();
-
- seg2 = segment(point_of_inter,G[start_node]);
- edg2 = G.new_edge(kn,start_node,seg2);
- DRAW_EDGE(seg2);
-
- wait();
- break;
- }
-
- edg4 = face_transition(seg,second_edge);
-
-
- insert_in_edge(kn,edg4,first2_edge,second2_edge);
-
- start_edge = second2_edge;
-
-
- if (vertical(G[start_edge]))
- {
- // cut vertical attachment
-
- angl = G[first_edge].angle(G[pred_edge]);
- if (fabs(angl) > eps)
- {
- if (! node_of.defined(G[G.target(pred_edge)]))
- {
- // delete upper vert_att
-
- edg_list.append(first_edge);
- edg_list.append(second2_edge);
- DRAW_EDGE(G[first_edge],white);
- DRAW_EDGE(G[second2_edge],white);
-
- wait();
- }
- else
- {
- // delete lower vert_att
-
- DRAW_EDGE(G[second_edge],white);
- DRAW_EDGE(G[first2_edge],white);
- G.del_edge(second_edge);
- G.del_edge(first2_edge);
-
- wait();
- }
- }
- else
- {
- // delete lower vert_att
-
- DRAW_EDGE(G[second_edge],white);
- DRAW_EDGE(G[first2_edge],white);
- G.del_edge(second_edge);
- G.del_edge(first2_edge);
- wait();
- }
- }
- else
-
- inter_p_list.append(point_of_inter);
-
- start_node = kn;
-
- } while (start_edge != nil);
-
- delete_edges(edg_list);
- edg_list.clear();
- }
-
-
- G.print();
-
- return inter_p_list;
- }
-
- /*****************************************************************************/
- /*****************************************************************************/
-
- main()
- {
- int input = 0;
- int grid_width = 0;;
- int N = 10;
- string file_name;
-
- double x1,y1,x2,y2;
- point p,q;
- segment seg;
- list(segment) seg_list;
-
- panel P("Line Segment Intersection (Mulmuley)");
-
- P.choice_item("INPUT", input, "mouse","random","file");
-
- P.int_item("GRID", grid_width, 0,100,20);
- P.int_item("#segments",N);
- P.int_item("WAIT",WAIT,0,300);
-
- P.string_item("FILE",file_name);
-
- P.open();
-
- W.init(-1000,1000,-1000,grid_width);
-
-
- /* make a list of line_segments */
-
- switch(input) {
-
-
- case 0: { // mouse
- W.set_line_style(dashed);
-
- while(W >> seg)
- { if (seg.xcoord1() > seg.xcoord2())
- seg=segment(seg.end(),seg.start());
- W.draw_segment(seg);
- seg_list.append(seg);
- }
- W.set_line_style(solid);
- break;
- }
-
-
- case 1: { // random
- W.set_line_style(dashed);
- init_random();
- for(int i=0;i<N;i++)
- { x1 = random(-900,-100);
- y1 = random(-900, 900);
- x2 = random( 100, 900);
- y2 = random(-900, 900);
-
- p = point(x1,y1);
- q = point(x2,y2);
- seg = segment(p,q);
- seg_list.append(seg);
-
- W.draw_segment(seg);
- }
- W.set_line_style(solid);
- break;
- }
-
- case 2: { // file
- file_istream F(file_name);
-
- double x_min=0,x_max=0,y_min=0;
-
- while (F >> x1 >> y1 >> x2 >> y2)
- {
- x_min = Min(x_min,x1);
- x_max = Max(x_max,x2);
- y_min = Min(y_min,y1);
-
- p = point(x1,y1);
- q = point(x2,y2);
- seg = segment(p,q);
- seg_list.append(seg);
- break;
- }
-
- W.init(x_min-1,x_max+1,y_min-1);
- }
-
- }//switch
-
-
-
- W.set_node_width(4);
-
-
- list(point) point_list = fmul(seg_list);
-
- point_list.print("point_list = ");
- W.read_mouse();
-
- W.clear();
-
- forall(seg,seg_list) W.draw_segment(seg);
-
- forall(p,point_list) W.draw_filled_node(p);
-
- W.read_mouse();
-
- }
-
- /*****************************************************************************/
- /*****************************************************************************/
- /*****************************************************************************/
-