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 >
Wrap
C/C++ Source or Header
|
1996-09-03
|
10KB
|
453 lines
/*******************************************************************************
+
+ LEDA 3.4
+
+ _polygon.c
+
+ This file is part of the LEDA research version (LEDA-R) that can be
+ used free of charge in academic research and teaching. Any commercial
+ use of this software requires a license which is distributed by the
+ LEDA Software GmbH, Postfach 151101, 66041 Saarbruecken, FRG
+ (fax +49 681 31104).
+
+ Copyright (c) 1991-1996 by Max-Planck-Institut fuer Informatik
+ Im Stadtwald, 66123 Saarbruecken, Germany
+ All rights reserved.
+
*******************************************************************************/
#include <LEDA/polygon.h>
#include <LEDA/graph.h>
#include <math.h>
#include <assert.h>
extern void SWEEP_SEGMENTS(const list<segment>&,GRAPH<point,segment>&);
//------------------------------------------------------------------------------
// polygons
//
// by S. Naeher (1995)
//------------------------------------------------------------------------------
polygon_rep::polygon_rep(const list<segment>& sl) : seg_list(sl)
{ segment s;
forall(s,sl) pt_list.append(s.start());
}
double polygon::compute_area(const list<segment>& seg_list) const
{
if (seg_list.length() < 3) return 0;
list_item it = seg_list.item(1);
point p = seg_list[it].source();
it = seg_list.succ(it);
double A = 0;
while (it)
{ segment s = seg_list[it];
A += ::area(p,s.source(),s.target());
it = seg_list.succ(it);
}
return A;
}
static void check_simplicity(const list<segment>& seg_list)
{ GRAPH<point,segment> G;
SWEEP_SEGMENTS(seg_list,G);
node v;
forall_nodes(v,G)
if (G.degree(v) != 2)
error_handler(1,"polygon: polygon must be simple");
}
polygon::polygon(const list<segment>& sl)
{ PTR = new polygon_rep(sl); }
polygon::polygon(const list<point>& pl)
{
list<segment> seglist;
for(list_item it = pl.first(); it; it = pl.succ(it))
seglist.append(segment(pl[it],pl[pl.cyclic_succ(it)]));
if (compute_area(seglist) < 0)
{ // reverse edge list
seglist.clear();
for(list_item it = pl.last(); it; it = pl.pred(it))
seglist.append(segment(pl[it],pl[pl.cyclic_pred(it)]));
}
check_simplicity(seglist);
PTR = new polygon_rep(seglist);
}
polygon polygon::translate(double alpha, double d) const
{ list<segment> L;
segment s;
forall(s,ptr()->seg_list) L.append(s.translate(alpha,d));
return polygon(L);
}
polygon polygon::translate(const vector& v) const
{ list<segment> L;
segment s;
forall(s,ptr()->seg_list) L.append(s.translate(v));
return polygon(L);
}
polygon polygon::rotate(const point& p, double alpha) const
{ list<segment> L;
segment s;
forall(s,ptr()->seg_list) L.append(s.rotate(p,alpha));
return polygon(L);
}
polygon polygon::rotate(double alpha) const
{ return rotate(point(0,0),alpha); }
polygon polygon::rotate90(const point& p) const
{ list<segment> L;
segment s;
forall(s,ptr()->seg_list) L.append(s.rotate90(p));
return polygon(L);
}
polygon polygon::reflect(const point& p, const point& q) const
{ list<segment> L;
segment s;
forall(s,ptr()->seg_list) L.append(s.reflect(p,q));
return polygon(L);
}
polygon polygon::reflect(const point& p) const
{ list<segment> L;
segment s;
forall(s,ptr()->seg_list) L.append(s.reflect(p));
return polygon(L);
}
bool polygon::inside(const point& p) const
{
list<segment>& seglist = ptr()->seg_list;
int count = 0;
double px = p.xcoord();
list_item it0 = seglist.first();
list_item it1 = seglist.first();
double x0 = seglist[it0].xcoord2();
double x1 = seglist[it1].xcoord2();
list_item it;
forall_items(it,seglist)
{ segment s = seglist[it];
if (s.xcoord2() < x0)
{ it0 = it;
x0 = s.xcoord2();
}
if (s.xcoord2() > x1)
{ it1 = it1;
x1 = s.xcoord2();
}
}
if (px <= x0 || x1 <= px) return false;
while (seglist[it0].xcoord2() <= px) it0 = seglist.cyclic_succ(it0);
it = it0;
do
{ while (seglist[it].xcoord2() >= px) it = seglist.cyclic_succ(it);
if (orientation(seglist[it],p) > 0) count++;
while (seglist[it].xcoord2() <= px) it = seglist.cyclic_succ(it);
if (orientation(seglist[it],p) < 0) count++;
} while (it != it0);
return count % 2;
}
bool polygon::outside(const point& p) const { return !inside(p); }
list<point> polygon::intersection(const segment& s) const
{ list<point> result;
segment t;
point p;
forall(t,ptr()->seg_list)
if (s.intersection(t,p))
if (result.empty()) result.append(p);
else if (p != result.tail() ) result.append(p);
return result;
}
list<point> polygon::intersection(const line& l) const
{ list<point> result;
segment t;
point p;
forall(t,ptr()->seg_list)
if (l.intersection(t,p))
if (result.empty()) result.append(p);
else if (p != result.tail() ) result.append(p);
return result;
}
// intersection or union with polygon
static bool test_edge(GRAPH<point,segment>& G, edge i1, int mode)
{
node v = G.target(i1);
edge i2 = G.cyclic_in_succ(i1);
node u1 = G.source(i1);
node u2 = G.source(i2);
if (i1 == i2) return false;
// parallel edges
if (u1 == u2) return i1 == G.first_in_edge(v);
edge o1 = G.first_adj_edge(v);
edge o2 = G.last_adj_edge(v);
// anti-parallel edges
if (target(o1) == u1 || target(o2) == u1) return false;
point p1 = G[o1].target();
point p2 = G[o2].target();
segment si1 = G[i1];
segment si2 = G[i2];
if (mode == 0) // intersection
{ if (orientation(si1,si2.source()) > 0)
return orientation(si1,p1) > 0 && orientation(si2,p1) < 0 &&
orientation(si1,p2) > 0 && orientation(si2,p2) < 0;
else
return (orientation(si1,p1) > 0 || orientation(si2,p1) < 0) &&
(orientation(si1,p2) > 0 || orientation(si2,p2) < 0);
}
else // union
{ if (orientation(si1,si2.source()) < 0)
return orientation(si1,p1) <= 0 && orientation(si2,p1) >= 0 ||
orientation(si1,p2) <= 0 && orientation(si2,p2) >= 0;
else
return orientation(si1,p1) <= 0 || orientation(si2,p1) >= 0 ||
orientation(si1,p2) <= 0 || orientation(si2,p2) >= 0;
}
}
static edge next_edge(GRAPH<point,segment>& G, edge i1, int dir)
{
// if dir = +1 turn left
// if dir = -1 turn right
node v = G.target(i1);
edge o1 = G.first_adj_edge(v);
edge o2 = G.last_adj_edge(v);
if (o1 == o2) return o1;
node w1 = G.target(o1);
node w2 = G.target(o2);
if (w1 == w2) return (o1 == G.first_in_edge(w1)) ? o1 : o2;
segment si1 = G[i1];
segment so1 = G[o1];
segment so2 = G[o2];
int orient1 = orientation(si1,so1.target());
int orient2 = orientation(si1,so2.target());
if (orient1 == orient2)
return (orientation(so1,so2.target()) == dir) ? o2 : o1;
else
if (orient1 < orient2)
return (dir == -1) ? o1 : o2;
else
return (dir == -1) ? o2 : o1;
}
list_polygon_ polygon::intersection(const polygon& P) const
{
list<polygon> result;
list<segment> seg_list;
GRAPH<point,segment> G;
segment s;
forall(s,ptr()->seg_list) seg_list.append(s);
forall(s,P.ptr()->seg_list) seg_list.append(s);
SWEEP_SEGMENTS(seg_list,G);
bool borders_intersect = false;
node v;
forall_nodes(v,G)
{ int deg = G.degree(v);
assert(deg == 2 || deg == 4);
if (deg == 4) borders_intersect = true;
}
if ( ! borders_intersect )
{ // no intersections between edges of (*this) and P
// check for inclusion
segment s1 = ptr()->seg_list.head();
segment s2 = P.ptr()->seg_list.head();
if ( P.inside(s1.start()) ) result.append(*this);
if ( inside(s2.start()) ) result.append(P);
return result;
}
edge_array<bool> marked(G,false);
edge e;
forall_edges(e,G)
{ node start = source(e);
if ( !marked[e] && test_edge(G,e,0) )
{ list<segment> pol;
do { node v = source(e);
node w = target(e);
marked[e] = true;
pol.append(segment(G[v],G[w]));
e = next_edge(G,e,+1);
} while (source(e) != start);
result.append(polygon(pol));
}
}
return result;
}
list_polygon_ polygon::unite(const polygon& P) const
{
list<polygon> result;
list<segment> seg_list;
GRAPH<point,segment> G;
segment s;
forall(s,ptr()->seg_list) seg_list.append(s);
forall(s,P.ptr()->seg_list) seg_list.append(s);
SWEEP_SEGMENTS(seg_list,G);
bool borders_intersect = false;
node v;
forall_nodes(v,G)
{ int deg = G.degree(v);
assert(deg == 2 || deg == 4);
if (deg == 4) borders_intersect = true;
}
if (!borders_intersect)
{
// check for inclusion
segment s1 = ptr()->seg_list.head();
segment s2 = P.ptr()->seg_list.head();
if ( ! P.inside(s1.start())) result.append(*this);
if ( ! inside(s2.start())) result.append(P);
return result;
}
edge_array<bool> marked(G,false);
edge e;
forall_edges(e,G)
{ node start = source(e);
if ( !marked[e] && test_edge(G,e,1) )
{ list<segment> pol;
do { node v = source(e);
node w = target(e);
marked[e] = true;
pol.append(segment(G[v],G[w]));
e = next_edge(G,e,-1);
} while (source(e) != start);
result.append(polygon(pol));
}
}
if (result.length() > 1)
{ // find outer polygon and move it to front of result
list_item it;
segment s;
list_item min_it = nil;
double min_x = MAXDOUBLE;
forall_items(it,result)
forall(s,result[it].ptr()->seg_list)
if (s.xcoord1() < min_x)
{ min_x = s.xcoord1();
min_it = it;
}
result.move_to_front(min_it);
}
return result;
}
ostream& operator<<(ostream& out, const polygon& p)
{ p.vertices().print(out);
return out << endl;
}
istream& operator>>(istream& in, polygon& p)
{ list<point> L;
L.read(in,'\n');
p = polygon(L);
return in;
}