_polygon.c
Upload User: gzelex
Upload Date: 2007-01-07
Package Size: 707k
Code Size: 8k
Development Platform:

MultiPlatform

  1. /*******************************************************************************
  2. +
  3. +  LEDA-R  3.2.3
  4. +
  5. +  _polygon.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/polygon.h>
  12. #include <LEDA/plane_alg.h>
  13. #include <LEDA/map.h>
  14. #include <math.h>
  15. //------------------------------------------------------------------------------
  16. // polygons
  17. //------------------------------------------------------------------------------
  18. ostream& operator<<(ostream& out, const polygon& p) 
  19. { p.vertices().print(out);
  20.   return out << endl;
  21.  } 
  22. istream& operator>>(istream& in,  polygon& p) 
  23. { list<point> L; 
  24.   L.read(in,'n'); 
  25.   p = polygon(L); 
  26.   return in;
  27. }
  28. double polygon::compute_area(const list<segment>& seg_list) const
  29. {
  30.   if (seg_list.length() < 3) return 0;
  31.   list_item it = seg_list.item(1);
  32.   point     p  = seg_list[it].source();
  33.   it = seg_list.succ(it);
  34.   double    A  = 0;
  35.   while (it)
  36.   { segment s = seg_list[it];
  37.     A += ::area(p,s.source(),s.target());
  38.     it = seg_list.succ(it);
  39.    }
  40.   return A;
  41. }
  42. static void check_simplicity(const list<segment>& seg_list)
  43. { GRAPH<point,segment> G;
  44.   SWEEP_SEGMENTS(seg_list,G);
  45.   node v;
  46.   forall_nodes(v,G)
  47.     if (G.degree(v) != 2)
  48.       error_handler(1,"polygon: polygon must be simple");
  49. }
  50. polygon::polygon(const list<point>& pl)
  51.   list<segment> seglist;
  52.   for(list_item it = pl.first(); it; it = pl.succ(it))
  53.     seglist.append(segment(pl[it],pl[pl.cyclic_succ(it)]));
  54.   if (compute_area(seglist) < 0)
  55.   { // reverse edge list
  56.     seglist.clear();
  57.     for(list_item it = pl.last(); it; it = pl.pred(it))
  58.       seglist.append(segment(pl[it],pl[pl.cyclic_pred(it)]));
  59.    }
  60.   check_simplicity(seglist);
  61.   PTR = new polygon_rep(seglist);
  62. }
  63. list<point> polygon::vertices() const
  64. { list<point> result;
  65.   segment s;
  66.   forall(s,ptr()->seg_list) result.append(s.start());
  67.   return result;
  68. }
  69. polygon polygon::translate(double alpha, double d) const
  70. { list<segment> L;
  71.   segment s;
  72.   forall(s,ptr()->seg_list) L.append(s.translate(alpha,d));
  73.   return polygon(L);
  74. }
  75. polygon polygon::translate(const vector& v) const
  76. { list<segment> L;
  77.   segment s;
  78.   forall(s,ptr()->seg_list) L.append(s.translate(v));
  79.   return polygon(L);
  80. }
  81. polygon polygon::rotate(const point& origin, double alpha) const
  82. { list<segment> L;
  83.   segment s;
  84.   forall(s,ptr()->seg_list) L.append(s.rotate(origin,alpha));
  85.   return polygon(L);
  86. }
  87. polygon polygon::rotate(double alpha) const
  88. { return rotate(point(0,0),alpha); }
  89. bool polygon::inside(const point& p) const
  90. {
  91.   list<segment>& seglist = ptr()->seg_list;
  92.   int count = 0;
  93.   double px = p.xcoord();
  94.   list_item it0 = seglist.first();
  95.   list_item it1 = seglist.first();
  96.   double x0 = seglist[it0].xcoord2();
  97.   double x1 = seglist[it1].xcoord2();
  98.   list_item it;
  99.   forall_items(it,seglist)
  100.   { segment s = seglist[it];
  101.     if (s.xcoord2() < x0) 
  102.     { it0 = it;
  103.       x0 = s.xcoord2();
  104.      }
  105.     if (s.xcoord2() > x1) 
  106.     { it1 = it1;
  107.       x1 = s.xcoord2();
  108.      }
  109.    }
  110.   if (px <= x0 || x1 <= px) return false;
  111.   while (seglist[it0].xcoord2() <= px) it0 = seglist.cyclic_succ(it0);
  112.   it = it0;
  113.   do
  114.   { while (seglist[it].xcoord2() >= px) it = seglist.cyclic_succ(it);
  115.     if (orientation(seglist[it],p) > 0) count++;
  116.     while (seglist[it].xcoord2() <= px) it = seglist.cyclic_succ(it);
  117.     if (orientation(seglist[it],p) < 0) count++;
  118.   } while (it != it0);
  119.   return count % 2;
  120. }
  121. bool polygon::outside(const point& p) const { return !inside(p); }
  122. list<point> polygon::intersection(const segment& s) const
  123. { list<point> result;
  124.   segment t;
  125.   point p;
  126.   forall(t,ptr()->seg_list) 
  127.     if (s.intersection(t,p))
  128.      if (result.empty()) result.append(p);
  129.      else if (p != result.tail() ) result.append(p);
  130.   return result;
  131. }
  132. list<point> polygon::intersection(const line& l) const
  133. { list<point> result;
  134.   segment t;
  135.   point p;
  136.   forall(t,ptr()->seg_list) 
  137.     if (l.intersection(t,p))
  138.      if (result.empty()) result.append(p);
  139.      else if (p != result.tail() ) result.append(p);
  140.   return result;
  141. }
  142. // intersection or union with polygon
  143. static bool test_edge(GRAPH<point,segment>& G, edge i1, int mode)
  144. { node v  = G.target(i1);
  145.   edge i2 = G.cyclic_in_succ(i1);
  146.   if (i1 == i2) return false;
  147.   edge o1 = G.first_adj_edge(v);
  148.   edge o2 = G.last_adj_edge(v);
  149.   point p1 = G[o1].target();
  150.   point p2 = G[o2].target();
  151.   segment si1 = G[i1];
  152.   segment si2 = G[i2];
  153.   if (mode == 0) // intersection
  154.   { if (orientation(si1,si2.source()) > 0)
  155.       return orientation(si1,p1) > 0 && orientation(si2,p1) < 0 && 
  156.              orientation(si1,p2) > 0 && orientation(si2,p2) < 0;
  157.    else
  158.       return (orientation(si1,p1) > 0 || orientation(si2,p1) < 0) && 
  159.              (orientation(si1,p2) > 0 || orientation(si2,p2) < 0);
  160.   }
  161.   else // union
  162.   { if (orientation(si1,si2.source()) < 0)
  163.       return orientation(si1,p1) < 0 && orientation(si2,p1) > 0 && 
  164.              orientation(si1,p2) < 0 && orientation(si2,p2) > 0;
  165.    else
  166.       return (orientation(si1,p1) < 0 || orientation(si2,p1) > 0) && 
  167.              (orientation(si1,p2) < 0 || orientation(si2,p2) > 0);
  168.    }
  169. }
  170. static edge next_edge(GRAPH<point,segment>& G, edge i1, int dir)
  171.   // if dir = +1 turn left
  172.   // if dir = -1 turn right
  173.   node v = G.target(i1);
  174.   edge o1 = G.first_adj_edge(v);
  175.   edge o2 = G.last_adj_edge(v);
  176.   segment si1 = G[i1];
  177.   segment so1 = G[o1];
  178.   segment so2 = G[o2];
  179.   if (o2 == nil) return o1;
  180.   int orient1 = orientation(si1,so1.target());
  181.   int orient2 = orientation(si1,so2.target());
  182.   if (orient1 == orient2)
  183.      return (orientation(so1,so2.target()) == dir) ? o2 : o1;
  184.   else
  185.      return (orient1 - orient2 == dir) ? o1 : o2;
  186. }
  187. list_polygon_ polygon::intersection(const polygon& P) const
  188. {
  189.   list<polygon> result;
  190.   list<segment> seg_list;
  191.   GRAPH<point,segment> G;
  192.   segment s;
  193.   forall(s,ptr()->seg_list) seg_list.append(s);
  194.   forall(s,P.ptr()->seg_list) seg_list.append(s);
  195.   SWEEP_SEGMENTS(seg_list,G);
  196.   bool borders_intersect = false;
  197.   node v;
  198.   forall_nodes(v,G) 
  199.     if (degree(v) > 2) 
  200.     { borders_intersect = true;
  201.       break;
  202.      }
  203.   if ( ! borders_intersect )
  204.   { // no intersections between edges of (*this) and P
  205.     // check for inclusion
  206.     segment s1 = ptr()->seg_list.head();
  207.     segment s2 = P.ptr()->seg_list.head();
  208.     if ( P.inside(s1.start()) ) result.append(*this);
  209.     if ( inside(s2.start()) ) result.append(P);                   
  210.     return result;
  211.    }
  212.   edge_array<bool> marked(G,false);
  213.   edge e;
  214.   forall_edges(e,G) 
  215.     if ( ! marked[e] && test_edge(G,e,0) )
  216.     { list<segment> pol;
  217.       edge start = e;
  218.       do { node v = source(e);
  219.            node w = target(e);
  220.            pol.append(segment(G[v],G[w]));
  221.            marked[e] = true;
  222.            e = next_edge(G,e,+1);
  223.           } while (e != start);
  224.       result.append(polygon(pol));
  225.      }
  226.  return result;
  227. }
  228. list_polygon_ polygon::unite(const polygon& P) const
  229. {
  230.   list<polygon> result;
  231.   list<segment> seg_list;
  232.   GRAPH<point,segment> G;
  233.   segment s;
  234.   forall(s,ptr()->seg_list) seg_list.append(s);
  235.   forall(s,P.ptr()->seg_list) seg_list.append(s);
  236.   SWEEP_SEGMENTS(seg_list,G);
  237.   if (G.number_of_nodes() == size() + P.size())
  238.   { // no intersections between edges of (*this) and P
  239.     // check for inclusion
  240.     segment s1 = ptr()->seg_list.head();
  241.     segment s2 = P.ptr()->seg_list.head();
  242.     if ( ! P.inside(s1.start())) result.append(*this);
  243.     if ( ! inside(s2.start())) result.append(P);                   
  244.     return result;
  245.    }
  246.   edge_array<bool> marked(G,false);
  247.   edge e;
  248.   forall_edges(e,G) 
  249.     if ( ! marked[e] && test_edge(G,e,1) )
  250.     { list<segment> pol;
  251.       edge start = e;
  252.       do { node v = source(e);
  253.            node w = target(e);
  254.            pol.append(segment(G[v],G[w]));
  255.            marked[e] = true;
  256.            e = next_edge(G,e,-1);
  257.           } while (e != start);
  258.       result.append(polygon(pol));
  259.      }
  260.  return result;
  261. }