home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 10 Tools / 10-Tools.zip / ledar34.zip / leda-r-3_4_tar / LEDA-3.4 / src / plane / _polygon.c < prev    next >
C/C++ Source or Header  |  1996-09-03  |  10KB  |  453 lines

  1. /*******************************************************************************
  2. +
  3. +  LEDA 3.4
  4. +
  5. +  _polygon.c
  6. +
  7. +  This file is part of the LEDA research version (LEDA-R) that can be 
  8. +  used free of charge in academic research and teaching. Any commercial
  9. +  use of this software requires a license which is distributed by the
  10. +  LEDA Software GmbH, Postfach 151101, 66041 Saarbruecken, FRG
  11. +  (fax +49 681 31104).
  12. +
  13. +  Copyright (c) 1991-1996  by  Max-Planck-Institut fuer Informatik
  14. +  Im Stadtwald, 66123 Saarbruecken, Germany     
  15. +  All rights reserved.
  16. *******************************************************************************/
  17. #include <LEDA/polygon.h>
  18. #include <LEDA/graph.h>
  19. #include <math.h>
  20. #include <assert.h>
  21.  
  22. extern void SWEEP_SEGMENTS(const list<segment>&,GRAPH<point,segment>&);
  23.  
  24. //------------------------------------------------------------------------------
  25. // polygons
  26. //
  27. // by S. Naeher (1995)
  28. //------------------------------------------------------------------------------
  29.  
  30.  
  31. polygon_rep::polygon_rep(const list<segment>& sl) :  seg_list(sl)
  32. { segment s;
  33.   forall(s,sl) pt_list.append(s.start());
  34.  }
  35.  
  36.  
  37.  
  38. double polygon::compute_area(const list<segment>& seg_list) const
  39. {
  40.  
  41.   if (seg_list.length() < 3) return 0;
  42.  
  43.   list_item it = seg_list.item(1);
  44.   point     p  = seg_list[it].source();
  45.  
  46.   it = seg_list.succ(it);
  47.  
  48.   double    A  = 0;
  49.  
  50.   while (it)
  51.   { segment s = seg_list[it];
  52.     A += ::area(p,s.source(),s.target());
  53.     it = seg_list.succ(it);
  54.    }
  55.  
  56.   return A;
  57. }
  58.  
  59.  
  60. static void check_simplicity(const list<segment>& seg_list)
  61. { GRAPH<point,segment> G;
  62.   SWEEP_SEGMENTS(seg_list,G);
  63.   node v;
  64.   forall_nodes(v,G)
  65.     if (G.degree(v) != 2)
  66.       error_handler(1,"polygon: polygon must be simple");
  67. }
  68.  
  69.  
  70. polygon::polygon(const list<segment>& sl)
  71. { PTR = new polygon_rep(sl); }
  72.  
  73.  
  74. polygon::polygon(const list<point>& pl)
  75.   list<segment> seglist;
  76.  
  77.   for(list_item it = pl.first(); it; it = pl.succ(it))
  78.      seglist.append(segment(pl[it],pl[pl.cyclic_succ(it)]));
  79.  
  80.   if (compute_area(seglist) < 0)
  81.   { // reverse edge list
  82.     seglist.clear();
  83.     for(list_item it = pl.last(); it; it = pl.pred(it))
  84.       seglist.append(segment(pl[it],pl[pl.cyclic_pred(it)]));
  85.    }
  86.   check_simplicity(seglist);
  87.  
  88.   PTR = new polygon_rep(seglist);
  89. }
  90.  
  91.  
  92. polygon polygon::translate(double alpha, double d) const
  93. { list<segment> L;
  94.   segment s;
  95.   forall(s,ptr()->seg_list) L.append(s.translate(alpha,d));
  96.   return polygon(L);
  97. }
  98.  
  99.  
  100. polygon polygon::translate(const vector& v) const
  101. { list<segment> L;
  102.   segment s;
  103.   forall(s,ptr()->seg_list) L.append(s.translate(v));
  104.   return polygon(L);
  105. }
  106.  
  107.  
  108. polygon polygon::rotate(const point& p, double alpha) const
  109. { list<segment> L;
  110.   segment s;
  111.   forall(s,ptr()->seg_list) L.append(s.rotate(p,alpha));
  112.   return polygon(L);
  113. }
  114.  
  115. polygon polygon::rotate(double alpha) const
  116. { return rotate(point(0,0),alpha); }
  117.  
  118.  
  119. polygon polygon::rotate90(const point& p) const
  120. { list<segment> L;
  121.   segment s;
  122.   forall(s,ptr()->seg_list) L.append(s.rotate90(p));
  123.   return polygon(L);
  124. }
  125.  
  126.  
  127. polygon polygon::reflect(const point& p, const point& q) const
  128. { list<segment> L;
  129.   segment s;
  130.   forall(s,ptr()->seg_list) L.append(s.reflect(p,q));
  131.   return polygon(L);
  132. }
  133.  
  134.  
  135. polygon polygon::reflect(const point& p) const
  136. { list<segment> L;
  137.   segment s;
  138.   forall(s,ptr()->seg_list) L.append(s.reflect(p));
  139.   return polygon(L);
  140. }
  141.  
  142.  
  143. bool polygon::inside(const point& p) const
  144. {
  145.   list<segment>& seglist = ptr()->seg_list;
  146.  
  147.   int count = 0;
  148.  
  149.   double px = p.xcoord();
  150.  
  151.   list_item it0 = seglist.first();
  152.   list_item it1 = seglist.first();
  153.  
  154.   double x0 = seglist[it0].xcoord2();
  155.   double x1 = seglist[it1].xcoord2();
  156.  
  157.   list_item it;
  158.  
  159.   forall_items(it,seglist)
  160.   { segment s = seglist[it];
  161.     if (s.xcoord2() < x0) 
  162.     { it0 = it;
  163.       x0 = s.xcoord2();
  164.      }
  165.     if (s.xcoord2() > x1) 
  166.     { it1 = it1;
  167.       x1 = s.xcoord2();
  168.      }
  169.    }
  170.  
  171.   if (px <= x0 || x1 <= px) return false;
  172.  
  173.   while (seglist[it0].xcoord2() <= px) it0 = seglist.cyclic_succ(it0);
  174.  
  175.   it = it0;
  176.   do
  177.   { while (seglist[it].xcoord2() >= px) it = seglist.cyclic_succ(it);
  178.     if (orientation(seglist[it],p) > 0) count++;
  179.     while (seglist[it].xcoord2() <= px) it = seglist.cyclic_succ(it);
  180.     if (orientation(seglist[it],p) < 0) count++;
  181.   } while (it != it0);
  182.  
  183.   return count % 2;
  184.  
  185. }
  186.  
  187.  
  188.  
  189. bool polygon::outside(const point& p) const { return !inside(p); }
  190.  
  191.  
  192. list<point> polygon::intersection(const segment& s) const
  193. { list<point> result;
  194.   segment t;
  195.   point p;
  196.  
  197.   forall(t,ptr()->seg_list) 
  198.     if (s.intersection(t,p))
  199.      if (result.empty()) result.append(p);
  200.      else if (p != result.tail() ) result.append(p);
  201.  
  202.   return result;
  203. }
  204.  
  205.  
  206. list<point> polygon::intersection(const line& l) const
  207. { list<point> result;
  208.   segment t;
  209.   point p;
  210.  
  211.   forall(t,ptr()->seg_list) 
  212.     if (l.intersection(t,p))
  213.      if (result.empty()) result.append(p);
  214.      else if (p != result.tail() ) result.append(p);
  215.  
  216.   return result;
  217. }
  218.  
  219.  
  220. // intersection or union with polygon
  221.  
  222. static bool test_edge(GRAPH<point,segment>& G, edge i1, int mode)
  223.   node v  = G.target(i1);
  224.   edge i2 = G.cyclic_in_succ(i1);
  225.  
  226.   node u1 = G.source(i1);
  227.   node u2 = G.source(i2);
  228.  
  229.   if (i1 == i2) return false;
  230.  
  231.   // parallel edges
  232.   if (u1 == u2) return i1 == G.first_in_edge(v);
  233.  
  234.   edge o1 = G.first_adj_edge(v);
  235.   edge o2 = G.last_adj_edge(v);
  236.  
  237.   // anti-parallel edges
  238.   if (target(o1) == u1 || target(o2) == u1) return false;
  239.  
  240.  
  241.   point p1 = G[o1].target();
  242.   point p2 = G[o2].target();
  243.  
  244.   segment si1 = G[i1];
  245.   segment si2 = G[i2];
  246.  
  247.   if (mode == 0) // intersection
  248.   { if (orientation(si1,si2.source()) > 0)
  249.       return orientation(si1,p1) > 0 && orientation(si2,p1) < 0 && 
  250.              orientation(si1,p2) > 0 && orientation(si2,p2) < 0;
  251.    else
  252.       return (orientation(si1,p1) > 0 || orientation(si2,p1) < 0) && 
  253.              (orientation(si1,p2) > 0 || orientation(si2,p2) < 0);
  254.   }
  255.   else // union
  256.   { if (orientation(si1,si2.source()) < 0)
  257.       return orientation(si1,p1) <= 0 && orientation(si2,p1) >= 0 ||
  258.              orientation(si1,p2) <= 0 && orientation(si2,p2) >= 0;
  259.    else
  260.       return orientation(si1,p1) <= 0 || orientation(si2,p1) >= 0 || 
  261.              orientation(si1,p2) <= 0 || orientation(si2,p2) >= 0;
  262.    }
  263. }
  264.  
  265.  
  266.  
  267. static edge next_edge(GRAPH<point,segment>& G, edge i1, int dir)
  268.   // if dir = +1 turn left
  269.   // if dir = -1 turn right
  270.  
  271.   node v = G.target(i1);
  272.  
  273.   edge o1 = G.first_adj_edge(v);
  274.   edge o2 = G.last_adj_edge(v);
  275.  
  276.   if (o1 == o2) return o1;
  277.  
  278.   node w1 = G.target(o1);
  279.   node w2 = G.target(o2);
  280.  
  281.   if (w1 == w2) return (o1 == G.first_in_edge(w1)) ? o1 : o2;
  282.  
  283.   segment si1 = G[i1];
  284.   segment so1 = G[o1];
  285.   segment so2 = G[o2];
  286.  
  287.   int orient1 = orientation(si1,so1.target());
  288.   int orient2 = orientation(si1,so2.target());
  289.  
  290.   if (orient1 == orient2)
  291.      return (orientation(so1,so2.target()) == dir) ? o2 : o1;
  292.   else
  293.      if (orient1 < orient2)
  294.         return (dir == -1) ? o1 : o2;
  295.      else
  296.         return (dir == -1) ? o2 : o1;
  297. }
  298.  
  299.  
  300.  
  301. list_polygon_ polygon::intersection(const polygon& P) const
  302. {
  303.   list<polygon> result;
  304.   list<segment> seg_list;
  305.   GRAPH<point,segment> G;
  306.  
  307.   segment s;
  308.   forall(s,ptr()->seg_list) seg_list.append(s);
  309.   forall(s,P.ptr()->seg_list) seg_list.append(s);
  310.  
  311.   SWEEP_SEGMENTS(seg_list,G);
  312.  
  313.   bool borders_intersect = false;
  314.  
  315.   node v;
  316.   forall_nodes(v,G) 
  317.   { int deg = G.degree(v);
  318.     assert(deg == 2 || deg == 4);
  319.     if (deg == 4) borders_intersect = true;
  320.    }
  321.     
  322.  
  323.   if ( ! borders_intersect )
  324.   { // no intersections between edges of (*this) and P
  325.  
  326.     // check for inclusion
  327.  
  328.     segment s1 = ptr()->seg_list.head();
  329.     segment s2 = P.ptr()->seg_list.head();
  330.  
  331.     if ( P.inside(s1.start()) ) result.append(*this);
  332.     if ( inside(s2.start()) ) result.append(P);                   
  333.  
  334.     return result;
  335.  
  336.    }
  337.  
  338.   edge_array<bool> marked(G,false);
  339.  
  340.   edge e;
  341.   forall_edges(e,G) 
  342.   { node start = source(e);
  343.     if ( !marked[e] && test_edge(G,e,0) )
  344.     { list<segment> pol;
  345.       do { node v = source(e);
  346.            node w = target(e);
  347.            marked[e] = true;
  348.            pol.append(segment(G[v],G[w]));
  349.            e = next_edge(G,e,+1);
  350.           } while (source(e) != start);
  351.       result.append(polygon(pol));
  352.      }
  353.    }
  354.  
  355.  return result;
  356.  
  357. }
  358.  
  359.  
  360. list_polygon_ polygon::unite(const polygon& P) const
  361. {
  362.   list<polygon> result;
  363.   list<segment> seg_list;
  364.   GRAPH<point,segment> G;
  365.  
  366.   segment s;
  367.   forall(s,ptr()->seg_list) seg_list.append(s);
  368.   forall(s,P.ptr()->seg_list) seg_list.append(s);
  369.  
  370.   SWEEP_SEGMENTS(seg_list,G);
  371.  
  372.   bool borders_intersect = false;
  373.  
  374.   node v;
  375.   forall_nodes(v,G) 
  376.   { int deg = G.degree(v);
  377.     assert(deg == 2 || deg == 4);
  378.     if (deg == 4) borders_intersect = true;
  379.    }
  380.  
  381.   if (!borders_intersect)
  382.   { 
  383.     // check for inclusion
  384.  
  385.     segment s1 = ptr()->seg_list.head();
  386.     segment s2 = P.ptr()->seg_list.head();
  387.  
  388.     if ( ! P.inside(s1.start())) result.append(*this);
  389.     if ( ! inside(s2.start())) result.append(P);                   
  390.  
  391.     return result;
  392.    }
  393.  
  394.   edge_array<bool> marked(G,false);
  395.  
  396.   edge e;
  397.   forall_edges(e,G) 
  398.   { node start = source(e);
  399.     if ( !marked[e] && test_edge(G,e,1) )
  400.     { list<segment> pol;
  401.       do { node v = source(e);
  402.            node w = target(e);
  403.            marked[e] = true;
  404.            pol.append(segment(G[v],G[w]));
  405.            e = next_edge(G,e,-1);
  406.           } while (source(e) != start);
  407.       result.append(polygon(pol));
  408.      }
  409.    }
  410.  
  411.   if (result.length() > 1)
  412.   { // find outer polygon and move it to front of result
  413.  
  414.     list_item it;
  415.     segment s;
  416.     list_item min_it = nil;
  417.     double    min_x = MAXDOUBLE;
  418.  
  419.     forall_items(it,result)
  420.       forall(s,result[it].ptr()->seg_list) 
  421.         if (s.xcoord1() < min_x)
  422.         { min_x = s.xcoord1(); 
  423.           min_it = it;
  424.          }
  425.   
  426.     result.move_to_front(min_it);
  427.   }
  428.  
  429.  return result;
  430. }
  431.  
  432.  
  433.  
  434.  
  435.  
  436.  
  437. ostream& operator<<(ostream& out, const polygon& p) 
  438. { p.vertices().print(out);
  439.   return out << endl;
  440.  } 
  441.  
  442. istream& operator>>(istream& in,  polygon& p) 
  443. { list<point> L; 
  444.   L.read(in,'\n'); 
  445.   p = polygon(L); 
  446.   return in;
  447. }
  448.  
  449.