_sweep_segments.c
上传用户:gzelex
上传日期:2007-01-07
资源大小:707k
文件大小:10k
开发平台:

MultiPlatform

  1. /*******************************************************************************
  2. +
  3. +  LEDA-R  3.2.3
  4. +
  5. +  _sweep_segments.c
  6. +
  7. +  Copyright (c) 1995  by  Max-Planck-Institut fuer Informatik
  8. +  Im Stadtwald, 66123 Saarbruecken, Germany     
  9. +  All rights reserved.
  10. *******************************************************************************/
  11. #include <LEDA/graph.h>
  12. #include <LEDA/sortseq.h>
  13. #include <LEDA/p_queue.h>
  14. #include <LEDA/map.h>
  15. #include <LEDA/hash.h>
  16. #include <math.h>
  17. // global variables
  18. static POINT p_sweep;
  19. static int   N;
  20. // geometric primitives
  21. inline int pair(const SEGMENT& p, const SEGMENT& q)
  22. { return  ID_Number(p) * N + ID_Number(q); }
  23. inline int compare(const SEGMENT& s1, const SEGMENT& s2)
  24.   // Precondition: |p_sweep| is identical to the left endpoint of
  25.   // either |s1| or |s2|. This is true since comparisons are only 
  26.   // executed when inserting or looking up new segments.
  27.   if ( identical(p_sweep,s1.start()) )
  28.   { int s = orientation(s2,p_sweep);
  29.     return (s != 0) ?  s : cmp_slopes(s1,s2);
  30.    }
  31.   if ( identical(p_sweep,s2.start()) )
  32.   { int s = orientation(s1,p_sweep);
  33.     return (s != 0) ? -s : cmp_slopes(s1,s2);
  34.    }
  35.   error_handler(1,"internal error in sweep");
  36.   return 0; // never reached
  37. }
  38. static void compute_intersection(sortseq<POINT,seq_item>& X_structure,
  39.                                  sortseq<SEGMENT,seq_item>& Y_structure,
  40.                                  hash<int,seq_item>& inter_dic,
  41.                                  seq_item sit0)
  42. {
  43.   // Given an item |sit0| in the Y-structure compute the point of 
  44.   // intersection with its successor and (if existing) insert it into 
  45.   // the event queue and do all necessary updates.
  46.   seq_item sit1 = Y_structure.succ(sit0);
  47.   SEGMENT  s0   = Y_structure.key(sit0);
  48.   SEGMENT  s1   = Y_structure.key(sit1);
  49.   // |s1| is the successor of |s0| in the Y-structure, hence,
  50.   // |s0| and |s1| intersect right or above of the sweep line
  51.   // iff |(s0.start(),s0.end(),s1.end()| is not a left turn and 
  52.   // |(s1.start(),s1.end(),s0.end()| is not a right turn.
  53.   // In this case we intersect the underlying lines
  54.   
  55.   if (orientation(s0,s1.end()) <= 0 && orientation(s1,s0.end()) >=0 )
  56.   { hash_item it = inter_dic.lookup(pair(s0,s1));
  57.     if (it != nil)
  58.        { Y_structure.change_inf(sit0,inter_dic.inf(it));
  59.          inter_dic.del_item(it);
  60.         }
  61.     else
  62.        { POINT    q;
  63.          s0.intersection_of_lines(s1,q);
  64.          Y_structure.change_inf(sit0, X_structure.insert(q,sit0));
  65.         }
  66.   }
  67. }
  68. void SWEEP_SEGMENTS(const list<SEGMENT>& S, GRAPH<POINT,SEGMENT>& G)
  69. {
  70.   // we use two sorted sequences ...
  71.   sortseq <POINT,seq_item>   X_structure;
  72.   sortseq <SEGMENT,seq_item> Y_structure;
  73.   // two maps ...
  74.   map<SEGMENT,node>    last_node(nil);
  75.   map<SEGMENT,SEGMENT> original;
  76.   hash<int,seq_item>   inter_dic;
  77.   // and a priority queue of segments ordered by their left endpoints
  78.   p_queue<POINT,SEGMENT> seg_queue;
  79.   /* INITIALIZATION
  80.      - clear the output graph.
  81.      - compute an upper bound |Infinity| for the input coordinates 
  82.      - make copies of the input segments such that all segments are 
  83.        oriented from left to right or from bottom to top.
  84.      - insert all endpoints of the new segments into the X-structure
  85.      - exploit the fact that insert operations into the X-structure
  86.        leave previously inserted points unchanged to achieve that
  87.        any pair of endpoints $p$ and $q$ with |p == q| are identical
  88.      - use a map to associate with every segment its original 
  89.      - for every created segment $(p,q)$ insert the pair $(p,(p,q))$ 
  90.        into priority queue |seg_queue|
  91.    */
  92.   G.clear();
  93.   numtype Infinity = 1;
  94.   SEGMENT s;
  95.   forall(s,S) 
  96.   {
  97.     while (fabs(s.xcoord1())>=Infinity || fabs(s.ycoord1())>=Infinity ||
  98.            fabs(s.xcoord2())>=Infinity || fabs(s.ycoord2())>=Infinity)
  99.       Infinity *= 2;
  100.     seq_item it1 = X_structure.insert(s.start(), nil);
  101.     seq_item it2 = X_structure.insert(s.end(), nil);
  102.     if (it1 == it2) continue;  // ignore zero-length segments
  103.     POINT p = X_structure.key(it1);
  104.     POINT q = X_structure.key(it2);
  105.     SEGMENT s1(p,q);
  106.     if (compare(p,q) > 0) s1 = SEGMENT(q,p);
  107.     original[s1] = s;
  108.     seg_queue.insert(s1.start(),s1);
  109.   }
  110.   // insert a lower and an upper sentinel segment to avoid special
  111.   // cases when traversing the Y-structure
  112.   SEGMENT lower_sentinel(-Infinity, -Infinity, Infinity, -Infinity);
  113.   SEGMENT upper_sentinel(-Infinity,  Infinity, Infinity,  Infinity);
  114.   // the sweep begins at the lower left corner
  115.   p_sweep = lower_sentinel.start();
  116.   Y_structure.insert(upper_sentinel,nil);
  117.   Y_structure.insert(lower_sentinel,nil);
  118.   // insert a stopper into |seg_queue| and initialize |next_seg| with
  119.   // the first segment in  the queue
  120.   POINT   p_stop(Infinity,Infinity);
  121.   SEGMENT s_stop(p_stop,p_stop);
  122.   seg_queue.insert(p_stop,s_stop);
  123.   SEGMENT next_seg = seg_queue.inf(seg_queue.find_min());
  124.   N = ID_Number(s_stop);
  125.   // Main Loop
  126.   while (!X_structure.empty()) 
  127.   {
  128.     // move |p_sweep| to next event point and insert a new node
  129.     // into the output graph G
  130.     seq_item event = X_structure.min();
  131.     p_sweep = X_structure.key(event);
  132.     node v = G.new_node(p_sweep);
  133.     // If there is a non-nil item |sit| associated with |event|,
  134.     // |key(sit)| is either an ending or passing segment.
  135.     // We use |sit| as an entry point to compute the bundle of
  136.     // segments ending at or passing through |p_sweep|.
  137.     // In particular, we compute the first (sit_first)| and last
  138.     // (|sit_last|) item of this bundle and the successor (|sit_succ)|)
  139.     // and predecessor (|sit_pred|) items.
  140.     seq_item sit = X_structure.inf(event);
  141.     if (sit == nil)
  142.     { // here we do not know any segments ending or passing through 
  143.       // |p_sweep|. However, |p_sweep| could come to lie on a segment 
  144.       // inserted before. To check this we look up the zero length 
  145.       // segment |(p_sweep,p_sweep)|.
  146.       sit = Y_structure.lookup(SEGMENT(p_sweep,p_sweep));
  147.      }
  148.     seq_item sit_succ  = nil;
  149.     seq_item sit_pred  = nil;
  150.     seq_item sit_first = nil;
  151.     seq_item sit_last  = nil;
  152.     // A value of |nil| for |sit_succ| and |sit_pred| after the 
  153.     // following computation indicates that there are no segments 
  154.     // ending at or passing through |p_sweep|
  155.     if (sit != nil)  // key(sit) is an ending or passing segment
  156.     {
  157.       // first walk up until |sit_succ|
  158.       while (Y_structure.inf(sit) == event) sit = Y_structure.succ(sit);
  159.       sit_succ = Y_structure.succ(sit);
  160.       seq_item xit = Y_structure.inf(sit);
  161.       if (xit != nil) 
  162.       { SEGMENT s1 = Y_structure.key(sit);
  163.         SEGMENT s2 = Y_structure.key(sit_succ);
  164.         inter_dic.insert(pair(s1,s2),xit);
  165.        }
  166.       // walk down until |sit_pred|, construct edges for all segments
  167.       // in the bundle, assign information |nil| to continuing segments,
  168.       // and delete ending segments from the Y_structure
  169.       do { SEGMENT s = Y_structure.key(sit);
  170.            SEGMENT orig = original[s];
  171.            if (s.source() == orig.source())
  172.               G.new_edge(last_node[s], v, orig);
  173.            else
  174.               G.new_edge(v,last_node[s], orig);
  175.        last_node[s] = v;
  176.            if ( identical(p_sweep,s.end()) )  // ending segment
  177.          { seq_item it = Y_structure.pred(sit);
  178.                Y_structure.del_item(sit);
  179.                sit = it; 
  180.               }
  181.            else                               // passing segment
  182.              { Y_structure.change_inf(sit,nil);
  183.                sit = Y_structure.pred(sit); 
  184.               }
  185.           } while (Y_structure.inf(sit) == event);
  186.        sit_pred  = sit;
  187.        sit_first = Y_structure.succ(sit_pred);
  188.        // reverse the bundle of continuing segments (if existing)
  189.        if (sit_first != sit_succ)
  190.        { sit_last = Y_structure.pred(sit_succ);
  191.          Y_structure.reverse_items(sit_first,sit_last);
  192.         }
  193.     }
  194.     // insert all segments starting at |p_sweep|
  195.     while ( identical(p_sweep,next_seg.start()) )
  196.     {
  197.       // insert |next_seg| into the Y-structure and associate the
  198.       // corresponding item with the right endpoint of |next_seg| in
  199.       // the X-structure (already present)
  200.       sit = Y_structure.locate(next_seg);
  201.       SEGMENT seg0 = Y_structure.key(sit);
  202.       if (compare(next_seg, seg0) != 0)
  203.          { // |next_seg| is not collinear with seg0, insert it
  204.            sit = Y_structure.insert_at(sit, next_seg, nil);
  205.            X_structure.insert(next_seg.end(),sit);
  206.            last_node[next_seg] = v;
  207.            if (sit_succ == nil)  
  208.            { // there are only starting segments, compute |sit_succ| 
  209.              // and |sit_pred| using the first inserted segment
  210.            sit_succ = Y_structure.succ(sit);
  211.            sit_pred = Y_structure.pred(sit);
  212.              sit_first = sit_succ;
  213.             }
  214.          }
  215.       else 
  216.         { // |next_seg| and |seg0| are collinear; if |next_seg| is
  217.           // longer insert |(seg0.end(),next_seg.end())| into |seg_queue|
  218.           POINT p = seg0.end();
  219.           POINT q = next_seg.end();
  220.         if (compare(p,q) < 0) seg_queue.insert(p,SEGMENT(p,q));
  221.          }
  222.       // delete minimum and assign new minimum to |next_seg|
  223.       seg_queue.del_min();
  224.       next_seg = seg_queue.inf(seg_queue.find_min());
  225.      }
  226.     // if |sit_pred| still has the value |nil|, there were no ending, 
  227.     // passing or starting segments, i.e., |p_sweep| is an isolated 
  228.     // point. In this case we are done, otherwise we delete the event 
  229.     // associated with |sit_pred| from the X-structure and compute 
  230.     // possible intersections between new neighbors.
  231.     if (sit_pred != nil) 
  232.     {
  233.       // |sit_pred| is no longer adjacent to its former successor we 
  234.       // change its intersection event to |nil| 
  235.       seq_item xit = Y_structure.inf(sit_pred);
  236.       if (xit != nil) 
  237.       { SEGMENT s1 = Y_structure.key(sit_pred);
  238.         SEGMENT s2 = Y_structure.key(sit_first);
  239.         inter_dic.insert(pair(s1,s2),xit);
  240.         Y_structure.change_inf(sit_pred, nil);
  241.        }
  242.       // compute possible intersections between |sit_pred| and its
  243.       // successor and |sit_succ| and its predecessor
  244.       compute_intersection(X_structure, Y_structure, inter_dic, sit_pred);
  245.       sit = Y_structure.pred(sit_succ);
  246.       if (sit != sit_pred)
  247.   compute_intersection(X_structure, Y_structure, inter_dic, sit);
  248.      }
  249.     // finally we delete the current event from the X-structure
  250.     X_structure.del_item(event);
  251.   }
  252. }
  253. void SWEEP_SEGMENTS(const list<SEGMENT>& S, list<POINT>& L)
  254. {
  255.   GRAPH<POINT,SEGMENT> G;
  256.   SWEEP_SEGMENTS(S,G);
  257.   L.clear();
  258.   node v;
  259.   forall_nodes(v,G)
  260.    if (G.degree(v) > 1) L.append(G[v]);
  261. }