Computing Visibility Polygons with LEDA
C. A. Hipke
January 1996
Abstract
In this paper we describe the implementation of the data type visibility polygon in
the context of the LEDA library. The new data type is built as a C++ class that is
derived from the LEDA polygon class. The main part is the description of the algorithm
to compute the visibility polygon.
We are using the CWEB document style to combine documentation and implementation
of our problem.
Contents
1. Introduction . . . . . . . . . . . . . . . . . . . . . . . .
2. Description of the algorithm . . . . . . . . . . . . . . .
3. Starting the algorithm . . . . . . . . . . . . . . . .
4. Moves and modes . . . . . . . . . . . . . . . . . . .
5. Skip mode . . . . . . . . . . . . . . . . . . . . . . .
6. Curl mode . . . . . . . . . . . . . . . . . . . . . . .
7. Normal mode . . . . . . . . . . . . . . . . . . . . .
8. Implementation of the visibility polygon class . . . . . .
9. The framework . . . . . . . . . . . . . . . . . . . .
15. Implementation of the basic procedures . . . . . . .
23. The algorithm for computing the visibility polygon
37. A simple sample program . . . . . . . . . . . . . .
38. Literature . . . . . . . . . . . . . . . . . . . . . . . . . .
1
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
2
3
3
3
4
5
5
8
8
10
14
20
21
1. Introduction.
Imagine a robot driving through an unknown scene. The robot is equipped with a visual sensor
and gets information about the part of the scene that is visible from its current position p. If
the scene is a simple polygon P in the plane, then we have the problem of reporting the part
of P that is visible from p. This part is a star-shaped polygon called the visibility polygon.
P
p
Figure 1: A sample visibility polygon
We will describe and implement an algorithm for computing the visibility polygon of a point
p in a polygon P . The description and implementation is combined using the CWEB package.
This literate programming approach was rst described by Knuth and Levy [3]. See also the
book by Sewell [7] for a more detailed description.
The algorithm for computing the visibility polygon will be embedded in a C++ class vis polygon.
We use the LEDA library and the new data type then is an extension to the functionality
of this library. LEDA supports combinatorial and geometric computing, it has been developed at the Max-Planck-Institut Saarbrucken [5, 8]. Here we are using some of its geometric
functions.
2
2. Description of the algorithm.
In this section we will describe the algorithm for computing the visibility polygon of a point
p inside a simple polygon P .
The rst linear time algorithm for computing the visibility polygon of a point inside a simple
polygon was described by ElGindy and Avis [1]. Lee [4] and later Joe and Simpson [2] have
simplied the algorithm. Our algorithm is loosely connected to the one of Joe and Simpson.
In chapter 8 of the book by O'Rourke [6] also more general visibility algorithms are presented,
for example the visibility polygon of an edge e inside a polygon.
We will describe our algorithm in detail before implementing it, but we do not prove its
correctness formally.
3. Starting the algorithm.
As we want to obtain a linear time algorithm, we will more or less look at the points of the
polygon P sequentially and update the visibility polygon computed so far. We will start with
the point on the boundary of P that is closest to p. If this point is in the middle of a segment
then we will temporarily insert a new vertex there. This point is chosen because we are sure
that it is contained in the visibility polygon.
p
s
Figure 2: Choosing a starting point s
To nd the point closest to p we scan all segments and compute their distance by constructing
the perpendicular. This takes O(n) time.
4. Moves and modes.
In the main loop we will consecutively look at the vertices v of the polygon P in clockwiseorder. We are done if we reach the starting point again. We will call the point under
observation the current point. The rst current point will be the successor of the starting
point. During the loop we maintain a preliminary version V of the visibility polygon that
takes into account only the points considered so far. V grows and shrinks as new points are
added and on the other hand new boundary parts obscure previously visible parts.
The algorithm may be in either of three modes: The normal, skip and curl mode. In normal
mode the current point is inside the preliminary visibility polygon V . In skip and curl mode
i
3
the current point is not visible and the algorithm waits to come back into the area of V . At
rst the algorithm is in normal mode.
p
p
vi?1
vi?1
vi
vi
Figure 3: Forward and backward moves
We keep track of the current turn angle , that is the angle between the segments pv ?1 and
pv . If is positive then we call the current move forward otherwise backward. See gure 3
for details. A rotation angle is obtained by summing up the turn angles. starts with 0
at the starting point.
Backward moves are subdivided furhter into inward and outward moves. A move is called
inward if the segment v ?1 v lies between the segment v ?1 v ?2 and p. Otherwise it is called
outward. Figure 4 shows an example each case.
i
i
i
i
i
p
i
p
vi
vi?1
vi?1
vi
Figure 4: Inward and outward moves
We will now describe the modes and actions of the algorithm in detail.
5. Skip mode.
The skip mode is started by a backward outward move. The predecessor of the current point
is then saved as the skip point s and the current rotation angle as the skip angle. The
algorithm continues looking at the vertices of P until the new segment v ?1 v intersects the
ray from p through s in a point q and the rotation angle is greater than the skip angle. Then
the segment sq is added to V and the algorithm proceeds in normal mode. Note that the skip
mode can only be terminated by a forward move.
The region below sq is called the skip cave.
i
4
i
s
p
q
Figure 5: A part of P is being skipped
6. Curl mode.
The curl mode is entered if after a backward inward move the next move is forward but moves
into the hidden region again. It then saves the segment v q as the curl segment. See gure 6
for an example.
i
q
vi
p
Figure 6: An example for the curl mode
In curl mode the algorithm continues to look at new points of P until a segment v ?1v
intersects the curl segment. This has to be a backward move and the algorithm goes back to
normal mode.
j
j
7. Normal mode.
If the algorithm is in normal mode its action depends on the type of the move to the current
point.
Case 1 Current move is forward
If the last move has also been forward then the current point is visible from p. This
means it is part of the preliminary visibility polygon V and can just be added to it.
But if the last move has been a backward move than the algorithm has to determine
whether the current point v is visible or not. Both cases are possible and shown in
gure 7.
If v is visible then it can be inserted into V . Otherwise the curl mode is entered and
V remains unchanged.
Case 2 Current move is backward outward
i
i
5
vi
vi
p
p
Figure 7: Possible situations after a backward move
Here the current point is not visible from p. The algorithm enters skip mode. It saves
the current rotation angle and sets the skip point to the predecessor of the current
point. This information will be used in the skip mode to determine when the boundary
returns to the visible part.
Case 3 Current move is backward inward
This is the most complicated case because here part of the visibility polygon V may be
hidden by the new segment. In gure 8 for example the segments v1 v2 , v2 v3 , and v3 v4
have to be deleted and new segments v1 q and qv5 have to be inserted.
v4
v3
v5
p
v2
q
v1
Figure 8: A part of V is being deleted
So in this case the algorithm moves backwards through the segments of V and stops if
the ray from p through the current point v intersects with a segment v v +1 in a point
q. During this phase that we call backtracking all segments are deleted and nally two
new segments v q and qv are inserted.
But there is one more problem we have not yet considered. During a backward inward
move the current point could move into a cave that we have skipped previously. Figure 9
shows the situation.
Here the backtracking described above would not work. So before we do the backtracking we rst move backwards through the previous skip points that we will keep in a list.
For each skip point s we test whether the new segment v ?1 v intersects the line through
p and s. If not we nish testing the skip points and do the backtracking. Otherwise we
i
j
j
i
i
6
i
j
v4
p
v3
v5
q1
q2
v1
v2
Figure 9: The current point is inside a skip cave
check if the current point is inside or in front of the cave by looking for an intersection
point between v ?1 v and the cave entry segment sq where q is the point where the skip
mode ended. See gure 10 for an example of both cases.
i
p
i
s
p
q
vi
s
q
vi
Figure 10: The current point is inside or in front of the skip cave
In both cases the algorithm deletes all the segments until it comes to the skip point s
that is considered. If the current point is inside the skip cave then the skip mode is
re-entered with the same skip angle and skip point. In this case no backtracking will
take place. Otherwise the previous skip point in the list is considered. If the end of the
skip point list is reached the normal backtracking phase starts.
The algorithm ends if the starting point has been inspected as current point. Then V is the
visibility polygon of p in P . If the starting point was no vertex and has been temporarily
inserted it is now deleted from V .
It is clear that the algorithm has time complexity O(n) since we look at each point only a
constant number of times. In the backtracking phase points are deleted and thus no point is
inspected in the backtracking phase more than once.
7
8. Implementation of the visibility polygon class.
We will embed the algorithm in a class vis polygon , that is derived from the base class polygon
supplied by LEDA. For dealing with parts of the visibility polygon we will introduce also the
classes vis point and vis segment derived from the respective LEDA classes.
The main diculty with visibility polygons as opposed to polygons is that the segments of
the boundary are divided into two groups: solid segments that correspond to segments | or
parts of segments | of the original polygon, and other segments that are due to visibility
constraints. Therefore the vis segment class will have an additional data eld is solid that
stores if the segment is solid. Similarly in the vis point class a eld next is solid stores the
status of the segment beginning with that point.
The vis polygon class itself will store the information about the solidity of the segments in a
linked list of boolean values. It cannot simply store a list of vis point s because we want it to
be derived from polygon and therefore the additional information has to be kept separately.
The visibility polygon class will be implemented in two les. The rst vis polygon :h holds the
interface description and the second vis polygon :c the real implementation. Furthermore a
sample program tvispoly :c that makes use of the LEDA window input and output is provided.
9. The framework.
Before we will be able to implement the main algorithm, we will rst dene the basic interface of the vis polygon and related classes. All interfaces will be included in the header le
vis polygon.h.
h vis_polygon.h i h Include LEDA headers i
h Dene list types i
h Interface for class vis point i
h Interface for class vis segment i
h Interface for class vis polygon i
9
10
11
12
13
14
10. We will derive our classes from the LEDA classes point , segment and polygon . Thus we
have to include them in our header.
h Include LEDA headers i #include <LEDA/polygon.h>
#include <LEDA/point.h>
#include <LEDA/window.h>
10
This code is used in section 9.
11. We dene new names for the parameterized list classes we use.
8
h Dene list types i #dene list bool list < bool >
#dene list point list < point >
#dene list segment list < segment >
#dene list vis point list < vis point >
#dene list vis segment list < vis segment >
typedef int bool ;
11
This code is used in section 9.
12. As explained above the vis point class has an additional data eld next is solid . Furthermore it will have two constructors with given data and the copy constructor.
h Interface for class vis point i class vis point : public point f
public :
vis point (double x = 0; double y = 0; bool next solid = true );
vis point (const point &p; bool next solid );
vis point (const vis point &vp );
bool next solid ( ) const
12
f
return next is solid ;
g
private :
bool next is solid ;
g;
This code is used in section 9.
13. The interface for the vis segment class is very similar to the previous one.
h Interface for class vis segment i class vis segment : public segment f
public :
vis segment ( );
vis segment (const segment &s; bool solid );
vis segment (const vis segment &vs );
bool solid ( ) const
f
return is solid ;
g
private :
bool is solid ;
g;
13
This code is used in section 9.
9
14. Now we are ready to come to the main part of the header le, the interface for the class
vis polygon . We keep a list of bool values to store the information about the solidity of the
segments. The order of this list corresponds to the order of the list of the vertices in the
polygon class.
h Interface for class vis polygon i class vis polygon : public polygon f
public :
vis polygon ( ): polygon ( ) f g
vis polygon (const polygon &P ; list bool & solid list );
vis polygon (const polygon &P ; const point &p);
void compute (const polygon &P ; const point &p);
list vis point vertices ( );
list vis segment segments ( );
void draw (window & W ; color line color = blue ; color pt color = blue );
private :
list bool solid ;
g;
14
This code is used in section 9.
15. Implementation of the basic procedures.
The implementation of most of the header le is straightforward. The general layout of the
implementation le vis polygon.c looks like this:
h vis_polygon.c i #include "vis_polygon.h"
#include "math.h"
#dene pi M_PI
#dene two pi 2 M_PI
h Auxiliary angle functions i
h Implementation of class vis point i
h Implementation of class vis segment i
h Implementation of class vis polygon i
15
22
16
17
18
16. In the implementation of the class vis point only the constructors have to be dened.
Nothing much is to do.
h Implementation of class vis point i vis point :: vis point (double x; double y; bool next solid ): point (x; y)
16
f
next is solid = next solid ;
g
vis point :: vis point (const point &p; bool next solid ): point (p)
f
g
next is solid = next solid ;
10
vis point :: vis point (const vis point &vp ) : point (vp )
f
g
next is solid = vp :next is solid ;
This code is used in section 15.
17. For the implementation of vis segment again we just have to initialize the new data
eld is solid .
h Implementation of class vis segment i vis segment :: vis segment( ): segment ( )
17
f
is solid = true ;
g
vis segment :: vis segment(const segment &s; bool solid ): segment (s)
f
is solid = solid ;
g
vis segment :: vis segment(const vis segment &vs ) : segment (vs )
f
g
is solid = vs :is solid ;
This code is used in section 15.
18. This was not too dicult, so we come to the main part. The implementation of the
class vis polygon looks like this:
h Implementation of class vis polygon i h Constructors of class vis polygon i
h Main algorithm i
h Methods for obtaining vertices and segments i
h Drawing the visibility polygon i
18
19
23
20
21
This code is used in section 15.
19. For the constructors there is nothing much to do. We have one constructor that builds
a visibility polygon from a polygon and a list of booleans, the solidity information. And
another one that is given a polygon and a point and computes the visibility polygon.
h Constructors of class vis polygon i vis polygon :: vis polygon (const polygon &P ; list bool & solid list ) : polygon (P )
19
f
g
solid = solid list ;
11
vis polygon :: vis polygon (const polygon &P ; const point &p) : polygon ( )
f
g
compute (P ; p);
This code is used in section 18.
20. The vertices and segments functions of the polygon class will be changed to return lists
of vis point s and vis segment s instead of points and segments. In both functions we have
to merge the solid list with the appropriate list returned by the polygon class.
h Methods for obtaining vertices and segments i list vis point vis polygon :: vertices ( )
20
f
list vis point v;
list itemsolid item = solid :rst ( );
point p;
list point pl = polygon :: vertices ( );
forall (p; pl )
f
g
v:append (vis point (p; solid :contents (solid item )));
solid item = solid :succ (solid item );
g
return v;
list vis segment vis polygon :: segments ( )
f
list vis segment s;
list itemsolid item = solid :rst ( );
segment seg ;
list segment sl = polygon :: segments ( );
forall (seg ; sl )
f
g
segment (seg ; solid :contents (solid item )));
solid item = solid :succ (solid item );
s:append (vis
g
return s;
This code is used in section 18.
21. We provide a simple way to draw the entire visibility polygon into a window. The draw
function has two optional arguments, the line and point color. It distinguishes solid and other
segments of the visibility polygon by using solid or dotted line style.
12
h Drawing the visibility polygon i void vis polygon :: draw (window & W ; color line color ; color pt color )
f
21
list vis point vpl = vertices ( );
vis point vp ;
forall (vp ; vpl )
f
g
W :draw point (vp ; pt color );
list vis segment vsl = segments ( );
vis segment vs ;
forall (vs ; vsl )
f
g
g
if (vs :solid ( )) W :set line style (:: solid );
else W :set line style (dotted );
W :draw segment (vs ; line color );
This code is used in section 18.
22. In the main algorithm we will need two functions to handle angles. norm angle shifts
a double value to t into the interval [0; 2]. between checks if the rst of its arguments is
between the second and third on a circle. This is done by a case analysis that assumes all
angles to be in the interval [0; 2].
h Auxiliary angle functions i double norm angle (double value )
22
f
while (value > two pi ) value ?= two pi ;
while (value < 0) value += two pi ;
return value ;
g
bool between (double c; double a; double b)
f
if (a > c)
if (b > c)
if (a > b) return true ;
else return false ;
else return false ;
else if (b < c)
if (a < b) return false ;
else return true ;
else return true ;
g
This code is used in section 15.
13
23. The algorithm for computing the visibility polygon.
We are now able to give the general outline of the main algorithm.
h Main algorithm i void vis polygon :: compute (const polygon &P ; const point &p)
23
f
h Compute nearest point i
h Initialization i
h Main loop i
h Finishing up i
24
25
26
g
27
This code is used in section 18.
24. To compute the nearest point to p we scan all segments of P and compute the nearest
point of the segment and its distance. The nearest point is computed by the perpendicular.
Since we are dealing with segments and not lines we have to check if the perpendicular really
intersects the segment. Otherwise one of the end points is the closest point to p. We only
have to look at one end point because we will test the other one at the next segment.
The variable min in segment will denote if we have to insert the closest point or if it has been
a vertex.
h Compute nearest point i list point pts = P :vertices ( );
list itemcur point it ; min point it ;
double from dist ; perp dist ; min distance = ?1;
bool min in segment ;
point min inner point ;
point from ; to ; q;
forall items (cur point it ; pts ) f
from = pts :contents (cur point it );
if (cur point it pts :last ( )) to = pts :head ( );
else to = pts :contents (pts :succ (cur point it ));
double from dist = p:distance (from );
segment seg (from ; to );
line parallel (p; vector (seg :dx ( ); seg :dy ( ))); = construct perpendicular =
line perp = parallel :rotate (p; pi =2);
if ( line (perp ) : intersection (segment (from ; to ); q) ) perp dist = p:distance (q);
else perp dist = from dist + 1; = ignore it =
if (from dist min distance _ min distance ?1) f
min distance = from dist ;
min point it = cur point it ;
min in segment = false ;
24
g
if (perp dist < min distance ) f
min distance = perp dist ;
14
min point it = cur point it ;
min in segment = true ;
min inner point = q;
g
g
if (min in segment ) f
g
min point it = pts :insert (min inner point ; min point it ; after );
This code is used in section 23.
25. In this section we declare variables for the main loop and initialize some of them. new pts
will contain the points of the preliminary visibility polygon V , new solid will be the solidity
information for V .
h Initialization i list point new pts ;
list < list item > skip its ; = the skip point list =
list point skip end pts ; = and corresponding points q =
list bool new solid ;
list itemskip point it ;
25
enum mode typ f
normal md ; skip md ; curl md
g;
mode typ mode = normal md ;
bool last inward = false ; this inward ;
point cur point ; last point ; last last point ;
segment curl seg ; back seg ;
cur point it = min point it ;
new pts :append (pts :contents (cur point it ));
double rot angle = 0;
double last rot angle ;
double turn angle ; skip angle ;
int points ;
This code is used in section 23.
26. In the main loop we look at all the vertices in counter-clockwise order until the starting
point is reached again. Note that the LEDA polygon class ensures that the vertices are
ordered counter-clockwise.
15
h Main loop i for (points = 1; points pts :size ( ); points ++) f
h Maintain variables i
bool has been in curl = (mode curl md );
h Test if still inside curl i
if (mode =6 curl md )
if (turn angle > pi ) = backward =
f
if (mode =6 skip md ) f
if (has been in curl _ between (fwd angle ; cur angle ; bwd angle ))
h Process inward bend i
else h Process outward bend i
g
g
else = forward =
f
if (last inward ^ between (bwd angle ; fwd angle ; cur angle ))
h Begin new curl i
else if (mode skip md ) f
if (rot angle skip angle ) h Try to end skipping i
g
else if (cur point it =6 min point it ) f
26
28
29
30
34
35
36
g
g
g
new pts :append (cur point );
new solid :append (true );
This code is used in section 23.
27. At the end of the algorithm the visibility polygon has been computed and is contained
in the lists new pts and new solid . If the starting point has been an auxiliary point that we
inserted we now delete it. Then we create a temporary visibility polygon VP made of new pts
and new solid . By assigning VP to this the visibility polygon is changed.
h Finishing up i new solid :append (true );
if (min in segment ) f
new pts :del item (new pts :rst ( ));
new solid :del item (new solid :rst ( ));
27
g
polygon P1 (new pts );
vis polygon VP(P1 ; new solid );
(this ) = VP ;
This code is used in section 23.
16
28. Now we are getting closer to the details of the algorithm. Maintaining the variables is
pretty straightforward. Notice that a turn angle that is larger than signies a turn that
goes backward, i.e. is clockwise.
h Maintain variables i cur point it = pts :cyclic succ (cur point it );
cur point = pts :contents (cur point it );
last point = pts :contents (pts :cyclic pred (cur point it ));
last last point = pts :contents (pts :cyclic pred (pts :cyclic pred (cur point it )));
turn angle = norm angle (segment (p; cur point ):angle ( ) ? segment (p; last point ):angle ( ));
last rot angle = rot angle ;
if (turn angle < pi ) rot angle += turn angle ;
else rot angle ?= two pi ? turn angle ;
double fwd angle = norm angle (segment (last point ; cur point ):angle ( ));
double bwd angle = norm angle (segment (last point ; last last point ):angle ( ));
double cur angle = norm angle (segment (last point ; p):angle ( ));
last inward = this inward ;
this inward = false ;
28
This code is used in section 26.
29. To see if we are still inside a curl we check if the curl seg intersects the segment from
last point to cur point . If this is the case we just got out of the curl and can proceed normally.
h Test if still inside curl i if (mode curl md )
if (curl seg :intersection (segment (last point ; cur point ); q)) mode = normal md ;
29
This code is used in section 26.
30. Processing an inward bend is the most complex function not yet dened. We have to
look through the skip pts list to see if we go back into a skipped cave. After that we may be
either in skip mode or we just have to go back to the last visible segment.
h Process inward bend i f
30
this inward = true ;
segment new seg (last point ; cur point );
bool intersecting = true ;
while (:skip its :empty ( ) ^ intersecting ) f
segment full skip seg (p; skip end pts :tail ( ));
if (new seg :intersection (full skip seg ; q)) f
h Go back to skip cave i
h Test if new point is inside cave i
31
g
g
else intersecting = false ;
32
17
g
if (mode 6= skip md ) h Delete invisible part i
33
This code is used in section 26.
31. In order to go back to the last skip cave we delete points until we reach the point that
is at the last position in the skip its list. Note that the rot angle has to be updated.
h Go back to skip cave i rot angle = last rot angle ;
while (new pts :last ( ) 6= skip its :tail ( )) f
turn angle = norm angle (
segment (p; new pts :contents (new pts :pred (new pts :last ( )))):angle ( ) ?
segment (p; new pts :tail ( )):angle ( ));
if (turn angle < pi ) rot angle += turn angle ;
else rot angle ?= two pi ? turn angle ;
new pts :del item (new pts :last ( ));
new solid :del item (new solid :last ( ));
31
g
last rot angle = rot angle ;
turn angle = norm angle (segment (p; cur point ):angle ( ) ?
segment (p; new pts :tail ( )):angle ( ));
if (turn angle < pi ) rot angle += turn angle ;
else rot angle ?= two pi ? turn angle ;
This code is used in section 30.
32. After going back to the cave we have to decide whether our new point is in front of or
inside the cave. We do so by checking for an intersection with the cave entry segment. If it
is inside the cave we change into skip mode with this skip point, otherwise we delete this skip
point and continue the loop by checking for the next skip point.
h Test if new point is inside cave i segment cave entry (new pts :contents (skip its :tail ( )); skip end pts :tail ( ));
skip end pts :del item (skip end pts :last ( ));
if (new seg :intersection (cave entry ; q)) f
mode = skip md ;
skip point it = skip its :tail ( );
skip angle = last rot angle ;
back seg = segment (pts :contents (skip point it ); cur point );
intersecting = false ; = stop loop =
32
g
else skip its :del item (skip its :last ( ));
This code is used in section 30.
33. If there was no previous skip cave or we are in front of one then deleting points until
we get back to the visible region is appropriate.
18
h Delete invisible part i f
line cur line (p; cur point );
while (:cur line :intersection (segment (new pts :contents (new pts :pred (new pts :last ( )));
new pts :tail ( )); q )) f
33
g
g
new pts :del item (new pts :last ( ));
new solid :del item (new solid :last ( ));
new pts :del item (new pts :last ( ));
new solid :del item (new solid :last ( ));
new pts :append (q);
new solid :append (true );
new pts :append (cur point );
new solid :append (false );
back seg = segment (q; cur point );
This code is used in section 30.
34. The case of an outward bend is much simpler. We just have to get into skip mode.
h Process outward bend i f
34
g
mode = skip md ;
skip point it = new pts :last ( );
skip its :append (skip point it );
skip angle = last rot angle ;
This code is used in section 26.
35. Beginning a new curl is also simple.
h Begin new curl i f
35
g
mode = curl md ;
curl seg = back seg ;
This code is used in section 26.
36. To get out of skip mode we rst check by an intersection if we are really back to the
visible region again. If so, the intersection point is a vertex of the visibility polygon.
h Try to end skipping i f
36
line skip line (p; new pts :contents (skip point it ));
19
if (skip line :intersection (segment (last point ; cur point ); q)) f
new pts :append (q);
new solid :append (false );
if (q 6= cur point ^ cur point it 6= min point it ) f
new pts :append (cur point );
new solid :append (true );
g
g
g
mode = normal md ;
skip end pts :append (q);
This code is used in section 26.
37. A simple sample program.
We will now construct a sample programm tvispoly.c to see our algorithm at work. This
has to be linked with vis polygon.c. We get a simple program that reads in a polygon and
a point in a window and shows the resulting visibility polygon.
h tvispoly.c
37
i
#include "vis_polygon.h"
void main ( )
f
g
polygon P ;
point q;
window W ("tvispoly"); = output the polygons to a LEDA window =
W :init (0; 10; 0);
bool end = false ;
while (:end ) f
W :set line width (1);
W P;
= read polygon =
W P;
W q;
= read point =
W q;
vis polygon V (P ; q); = compute the visibility polygon =
W :set line width (2);
V :draw (W ; blue ; red );
= and draw it =
panel dialog ("Continue");
dialog :text item ("Do you want to draw another polygon?");
dialog :button ("Yes");
dialog :button ("No, quit");
end = (dialog :open ( ) 1);
W :clear ( );
g
20
38. Literature.
References
[1] H. ElGindy and D. Avis. A linear algorithm for computing the visibility polygon from a
point. J. Algorithms, 2:186{197, 1981.
[2] B. Joe and R. B. Simpson. Correction to Lee's visibility polygon algorithm. BIT, 27:458{
473, 1987.
[3] Donald E. Knuth and Silvio Levy. The CWEB system of structured documentation.
manuscript, comes with the CWEB package, 1987.
[4] D. T. Lee. Visibility of a simple polygon. Comput. Vision Graph. Image Process., 22:207{
221, 1983.
[5] Kurt Mehlhorn and Stefan Naher. LEDA: A platform for combinatorial and geometric
computing. Comm. of the ACM, 38(1):96{102, January 1995.
[6] J. O'Rourke. Art Gallery Theorems and Algorithms. Oxford University Press, New York,
NY, 1987.
[7] Wayne Sewell. Weaving a program | Literate programming in WEB. van Nostrand Reinhold, 1989.
[8] Stefan Naher und Christian Uhrig. LEDA manual version 3.0. Technical Report MPI-I93-106, Max-Planck-Institut fur Informatik, Saarbrucken, Germany, 1993.
21
Index
Here is a list of the identiers used, and where they appear. Underlined entries indicate the
place of denition.
forall items : 24.
a: 22.
after : 24.
from : 24.
angle : 28, 31.
from dist : 24.
append : 20, 25, 26, 27, 33, 34, 36.
full skip seg : 30.
fwd angle : 26, 28.
b: 22.
back seg : 25, 32, 33, 35.
has been in curl : 26.
between : 22, 26.
head : 24.
blue : 14, 37.
init : 37.
bool : 11, 12, 13, 14, 16, 17, 22, 24,
insert : 24.
25, 26, 30, 37.
intersecting : 30, 32.
button : 37.
intersection : 24, 29, 30, 32, 33, 36.
bwd angle : 26, 28.
is solid : 8, 13, 17.
c: 22.
last : 24, 31, 32, 33, 34.
last inward : 25, 26, 28.
cave entry : 32.
clear : 37.
last last point : 25, 28.
color : 14, 21.
last point : 25, 28, 29, 30, 36.
last rot angle : 25, 28, 31, 32, 34.
compute : 14, 19, 23.
contents : 20, 24, 25, 28, 31, 32, 33, 36.
line color : 14, 21.
cur angle : 26, 28.
list : 11, 25.
cur line : 33.
list bool : 11, 14, 19, 25.
cur point : 25, 26, 28, 29, 30, 31, 32,
list item : 20, 24, 25.
33, 36.
list point : 11, 20, 24, 25.
cur point it : 24, 25, 26, 28, 36.
list segment : 11, 20.
curl md : 25, 26, 29, 35.
list vis point : 11, 14, 20, 21.
curl seg : 25, 29, 35.
list vis segment : 11, 14, 20, 21.
cyclic pred : 28.
M_PI : 15.
cyclic succ : 28.
main : 37.
del item : 27, 31, 32, 33.
min distance : 24.
dialog : 37.
min in segment : 24, 27.
distance : 24.
min inner point : 24.
dotted : 21.
min point it : 24, 25, 26, 36.
mode : 25, 26, 29, 30, 32, 34, 35, 36.
draw : 14, 21, 37.
draw point : 21.
mode typ : 25.
draw segment : 21.
new pts : 25, 26, 27, 31, 32, 33, 34, 36.
dx : 24.
new seg : 30, 32.
new solid : 25, 26, 27, 31, 33, 36.
dy : 24.
next is solid : 8, 12, 16.
empty : 30.
next solid : 12, 16.
end : 37.
false : 22, 24, 25, 28, 30, 32, 33, 36, 37.
norm angle : 22, 28, 31.
rst : 20, 27.
normal md : 25, 29, 36.
forall : 20, 21.
open : 37.
22
V : 37.
value : 22.
vector : 24.
vertices : 14, 20, 21, 24.
vis point : 8, 11, 12, 16, 20, 21.
vis polygon : 8, 9, 14, 18, 19, 20, 21,
23, 27, 37.
vis segment : 8, 11, 13, 17, 20, 21.
void : 21, 23.
vp : 12, 16, 21.
VP : 27.
vpl : 21.
vs : 13, 17, 21.
vsl : 21.
window : 14, 21, 37.
x: 12, 16.
y: 12, 16.
P : 14, 19, 23.
p: 12, 14, 16, 19, 23.
panel : 37.
parallel : 24.
perp : 24.
perp dist : 24.
pi : 15, 24, 26, 28, 31.
pl : 20.
point : 10, 11, 12, 14, 16, 19, 20, 23,
24, 25, 37.
points : 25, 26.
polygon : 8, 10, 14, 19, 20, 23, 27, 37.
pred : 31, 33.
pt color : 14, 21.
pts : 24, 25, 26, 28, 32.
P1 : 27.
red : 37.
rot angle : 25, 26, 28, 31.
rotate : 24.
s: 13, 17.
seg : 20, 24.
segment : 10, 11, 13, 17, 20, 24, 25, 28,
29, 30, 31, 32, 33, 36.
segments : 14, 20, 21.
set line style : 21.
set line width : 37.
size : 26.
skip angle : 25, 26, 32, 34.
skip end pts : 25, 30, 32, 36.
skip its : 25, 30, 31, 32, 34.
skip line : 36.
skip md : 25, 26, 30, 32, 34.
skip point it : 25, 32, 34, 36.
skip pts : 30.
sl : 20.
solid : 13, 14, 17, 19, 20, 21.
solid item : 20.
solid list : 14, 19.
succ : 20, 24.
tail : 30, 31, 32, 33.
text item : 37.
this inward : 25, 28, 30.
to : 24.
true : 12, 17, 22, 24, 26, 27, 30, 33, 36.
turn angle : 25, 26, 28, 31.
tvispoly : 8.
two pi : 15, 22, 28, 31.
23
List of Renements
h Auxiliary angle functions i
h Begin new curl i
h Compute nearest point i
h Constructors of class vis polygon i
h Dene list types i
h Delete invisible part i
h Drawing the visibility polygon i
h Finishing up i
h Go back to skip cave i
h Implementation of class vis point i
h Implementation of class vis polygon i
h Implementation of class vis segment i
h Include LEDA headers i
h Initialization i
h Interface for class vis point i
h Interface for class vis polygon i
h Interface for class vis segment i
h Main algorithm i
h Main loop i
h Maintain variables i
h Methods for obtaining vertices and segments i
h Process inward bend i
h Process outward bend i
h Test if new point is inside cave i
h Test if still inside curl i
h Try to end skipping i
h tvispoly.c i
h vis_polygon.c i
h vis_polygon.h i
22
35
Used in section 15.
Used in section 26.
24
Used in section 23.
19
11
33
Used in section 30.
21
27
Used in section 18.
Used in section 9.
Used in section 18.
Used in section 23.
31
Used in section 30.
16
10
25
18
Used in section 15.
17
Used in section 15.
Used in section 9.
Used in section 23.
12
Used in section 9.
14
Used in section 9.
13
23
26
Used in section 15.
Used in section 9.
Used in section 18.
Used in section 23.
28
Used in section 26.
20
30
34
Used in section 26.
29
Used in section 26.
32
36
Used in section 18.
Used in section 26.
Used in section 30.
Used in section 26.
37
15
9
24
© Copyright 2026 Paperzz