Download as pdf or txt
Download as pdf or txt
You are on page 1of 14

QUAD-GRAPHS

GUILHERME D. DA FONSECA

Abstract. Quad-trees (and their higher dimension versions) are


widely used to speed up certain operations with solids. When using
quad-trees, the application developer needs to choose a maximum
depth for the tree. Increasing this parameter, improves quality
of approximation, but reduces performance. In this project, we
propose another data-structure, called quad-graph, which, while
being very similar to the quad-trees, represents the solid exactly.
This structure also supports most operations supported by the
quad-trees with very similar algorithms.

1. Introduction
The quad-tree data structure is a tree where all internal nodes have
exactly four children. Each node v is associated with a square Qv and
its children are associated with the four squares obtained by halving
both the horizontal and vertical edges of Qv . We call these four nodes
NW, NE, SW, SE, according to their positions regarding the original
square. The leaves of the tree are associated with a value which describe
some property of the associated square, like its color, being full or
empty, etc. For compactness, a quad-tree is not allowed to have an
internal node where all its descendant leaves are associated with the
same value.
The quad-tree data structure is widely used to store a mapping f :
Q → C of the points inside the square grid Q to a finite set of values
C. Most commonly, C = {empty, full}, but C can also be a larger set,
containing colors, for example. A quad-tree of maximum depth k is a
quad-tree where Q is a grid of 2k by 2k points. A mapping and the
corresponding quad-tree are represented in figure 1.
The quad-tree is a very useful data structure because performing
many useful operations with it is simple and efficient. Some of these
operations are described below. We assume that C = {empty, full}.
(1) Point location: Given a quad-tree corresponding to a mapping
f and the coodinates of a point p, find the value of f (p).
(2) Collision detection: Given two quad-trees, find if there is a pixel
which values full on both quad-trees.
1
2 GUILHERME D. DA FONSECA

NW SE
NE SW

NW SE
NE SW

NW SE NW SE
NE SW
NE SW

Figure 1. Example of a quad-tree with the correspond-


ing mapping. The grid in this example is 8 by 8 and the
quad-tree depth is 3.

(3) Union: Given two quad-trees corresponding to two mapping f1


and f2 , compute the quad-tree corresponding to the mapping f
where f (p) is full if and only if either f1 (p) or f2 (p) is full.
(4) Intersection: Given two quad-trees corresponding to two map-
ping f1 and f2 , compute the quad-tree corresponding to the
mapping f where f (p) is full if and only if both f1 (p) and f2 (p)
is full.
Besides these operations, other natural operations are 90◦ rotations
and flipping. All these operations can be performed in time linear
in the input size. A different kind of operation which is very efficient
with quad-trees is rendering. The rendering operation consists of draw-
ing the mapping in the computer display. The rendering operation is
specially efficient because drawing big rectangles is often faster than
plotting each of its pixels individually.
Quad-trees can also be extended to higher dimensions with no al-
gorithmical differences. In tree dimensions, it is called an oct-tree,
because each internal node has eight children. In d dimensions, we can
talk about (2d )-trees, where each node has 2d children.
In most applications, quad-trees are stored besides another data
structure, which represents the boundaries of the solid, like a winged
edge, for example. The advantage of this approach is that, while the
winged edge stores the complete and exact representation, the quad-
tree provides fast rendering, useful as a preview image, and can speed-
up point-location queries, to identify the cell pointed by the mouse,
for example. In these applications, the quad-tree is built from the
boundary representation.
The weakness of the quad-tree is that it is limited to describing map-
pings whose domains are a finite square grid. In most situations, we
QUAD-GRAPHS 3

actually want to represent a continuous mapping. Normally, we use a


quad-tree to represent an approximation of this continuous mapping,
instead of the exact mapping. But then, we have to face a difficult
trade-of. Using a deeper quad-tree can improve the approximation
quality, but, at the same time, makes the structure less efficient, con-
cerning both space of storage and time complexity of the operations.
An extension of the quad-tree to a domain less restricted than a grid
seems to be a natural and useful structure. In this project, we define
an extension of the quad-tree called quad-graph, which can represent
any bounded rational polygonal mapping (defined below) exactly. The
quad-graph structure is very simple and mostly similar to the quad-
tree structure, except that its directed edges can form cycles. This
structure is mostly intended to be kept together with another structure
like a winged edge, in the same way as the quad-tree. For this reason,
we provide efficient algorithms to convert a mapping from a boundary
description to a quad-graph representation. We also present algorithms
to perform the union and the intersection of two quad-graphs. Other
operations, like point-location, rendering and rotation, can be trivially
performed with algorithms analogous to the ones on quad-trees.
A bounded polygonal mapping f is a mapping defined by a finite
collection of disjoint bounded polygons. The value of f (p), for a point
p, depends only on which polygon p is contained. We assume that if
p lies on the border of a polygon, then f (p) is undefined. We say that
a polygon mapping f is rational if the coordinates of all vertices of
polygons defining f are rational numbers.
In section 2, we define the quad-graph data structure and present
two small examples which illustrate the representational power of the
data structure. In section 3, we explain the divide and conquer algo-
rithm which breaks the problem of constructing a quad-graph in some
simple cases. In section 4, we present the algorithm which solves one
of the simple cases produced by the divide and conquer algorithm. In
section 5, we present two algorithms which compute the union and the
intersection of quad-graphs. This algorithms are used to solve two other
simple cases. In section 6, we summarize the advantages and disadvan-
tages of the quad-graph data structure, compared to the quad-tree data
structure.

2. The Quad-Graph Structure


The main difference between a quad-graph and a quad-tree is that
quad-graphs are allowed to have cycles. A quad-graph is a directed
graph where all non-sink nodes have exactly four out-edges. Each node
4 GUILHERME D. DA FONSECA

NW SE
NE SW

Figure 2. Example of a quad-graph with the corre-


sponding mapping.

v is associated with a square Qv . If Qv is a non-sink node, then its four


out-neighbors are associated with the four squares obtained by halving
both the horizontal and vertical edges of Qv . We call these four out-
neighbor nodes NW, NE, SW, and SE, according to their positions
regarding the original square. The sinks of the graph are associated
with a value which describes some property of the associated square,
like its color, being full or empty, etc. The sinks of a quad-graph are
analogous to the leaves of a quad-tree, while the non-sink nodes of
a quad-graph are analogous to the internal nodes of a quad-tree. A
special vertex of the quad-graph is associated with the original square
which bounds the mapping. This vertex is analogous to the root of a
quad-tree and is the only vertex in the quad-graph which can possibly,
but not necessarily, be a source. We call this vertex the start vertex.
To illustrate the power of the quad-graph structure, we present two
polygonal mappings inside the unit square, with the corresponding
quad-graphs. These mappings cannot be represented exactly by a
quad-tree, but can easily be represented by a quad-graph.
The first one is formed by dividing the unit square with a diagonal
and is represented in figure 2. Its quad-graph is formed the following
way. The start vertex is associated with the original square. Its NE
out-neighbor is empty, while its SW out-neighbor is f ull. Its NW and
SE vertices are exact copies of the original square (except for the scale
and position). Consequently, the quad-graph data structure simply
stores these two nodes as pointers to the start vertex itself.
The second one is mostly one dimensional in nature and is formed
by dividing the square with a vertical line at one third of the edge
length. It is represented in figure 3. The start vertex is associated
with the original square. Its NE and SE out-neighbors are empty. Its
QUAD-GRAPHS 5

NW SE
SW NE

NW
SE
SW

NE

1/3

Figure 3. Another example of a quad-graph with the


corresponding mapping.

NW and SW out-neighbors are neither f ull, nor empty, nor copies of


any previously seen squares. Consequently, we create a new vertex for
them. Notice that, as these two squares are identical, we only need one
additional vertex. The NW and SW out-neighbors of this new vertex
are f ull. Besides that, the NE and SE out-neighbors are identical to
the start vertex. This way, we can store them implicitly as pointers to
the start vertex.

3. Divide and Conquer Algorithm


We need to prove that all bounded polygonal mappings have a cor-
responding finite quad-graph. In order to do that, we present an algo-
rithm which constructs such quad-graph from the mapping. We assume
that the given bounded polygonal mapping is represented by a set of
closed polygons and each polygon is represented by a list of vertices.
Each vertex has two rational coordinates. The input of our algorithm is
a mapping M . To standardize our explanations, we assume that M is
bounded by the positive unit square, that is, the square with opposite
corners (0, 0) and (1, 1) in the Cartesian plane.
It is easy to compute the quad-graph for some trivial mappings. For
example, if M is completely empty or full, the solution is straightfor-
ward. Our divide and conquer algorithm simplifies the problem and
solves it recursively, until we get to a “simple” case. We define five
simple cases below. Some examples of the three former cases are illus-
trated in figure 5.
(1) The mapping M represents two half-planes divided by a line.
(2) Them mapping M represents the intersection of two mappings
in case (1).
6 GUILHERME D. DA FONSECA

Figure 4. A polygonal mapping divided recursively di-


vided in four squares until it becomes case (1), (2) or
(3).

(1) (2a) (2b) (3a) (3b)

Figure 5. Some mappings M where: (1) M maps a


halfplane, (2a) and (2b) M maps the intersection of two
half-planes, and (3a) and (3b) M maps the union of two
half planes.

(3) Them mapping M represents the union of two mappings in case


(1).
(4) The mapping M is empty.
(5) The mapping M is f ull.
If M is not in one of the five cases above, then we call our algorithm
recursively for the four squares obtained by dividing M , clipping the
mapping accordingly. An example of this divide step is represented in
figure 4. Notice that, when implementing the algorithm, the squares
must also be scaled (by a factor of two) and translated to fit in the unit
square. Proceeding this way, we only need to solve the five cases above
directly. Cases (4) and (5) are trivial. In the following paragraphs, we
explain how to deal with case (1). To deal with cases (2) and (3), we
present two algorithms which compute the union and the intersection
of two given quad-graphs. Cases (2) and (3) can be solved as the union
or intersection of the appropriate halfplanes.

4. Algorithm for Case (1)


In case (1), where the mapping is divided in two halfplanes, we as-
sume that the line l which divides the two halfplanes is defined by
QUAD-GRAPHS 7

Halfplanes(a, b, c1 , c2 )
// Check if l intersects the unit square
if (b ≥ 0 and a + b ≤ 0) or (b < 0 and a + b ≤ 0)
return c1
if (b ≥ 0 and a + b ≥ 1) or (b < 0 and a + b ≥ 1)
return c2
// Check if (a, b, c1 , c2 ) has already been generated
if D.contains((a, b, c1 , c2 ))
return D.get((a, b, c1 , c2 ))
// Create a new node and solve the problem recursively
n ← new node
n.N W ← Halfplanes(a, 2b − 1, c1 , c2 )
n.N E ← Halfplanes(a, a + 2b − 1, c1 , c2 )
n.SW ← Halfplanes(a, 2b, c1 , c2 )
n.SE ← Halfplanes(a, a + 2b, c1 , c2 )
// Store the new node n with key (a, b, c1 , c2 )
D.add(n, (a, b, c1 , c2 ));
return n
Figure 6. Algorithm to compute the quad-graph of the
unit square divided by a line in two halfplanes.

equation y = ax + b. The case where l is a vertical line can be dealt


with using a 90◦ rotation. The algorithm must also be informed of the
colors c1 and c2 of the two half planes, above and below l, respectively.
This way, the input of the algorithm is a quadruple (a, b, c1 , c2 ). The
algorithm uses a data structure D, like a hash table or a binary search
tree to store the nodes it generates and retrieve them quickly using
(a, b, c, d) as a key.
The pseudo-code for this algorithm is in figure 6. The first step of the
algorithm consists of checking if the input line actually intersects the
unity square. If this is the case, then the output is the corresponding
color. Otherwise, the algorithm checks if its input quadruple is already
in D. If this is true, then the algorithm simply returns a pointer to
the corresponding node. If the input did not fit in one of the cases
above, the algorithm creates a new node and calls itself recursively to
determine the four children nodes of it.
It is not hard to prove that this algorithm terminates for any valid in-
put. To prove that, we argue that the number of quadruples (a, b, c1 , c2 )
stored in D is finite. The only value in this quadruple which changes
8 GUILHERME D. DA FONSECA

throughout the algorithm is b. The initial value b0 of b on the first


call to the algorithms is a rational number. Based on the operations
performed on b (integer multiplication and addition, and adding a),
all further values of b on the recursive calls have a denominator not
greater than the denominator of b0 times the denominator of a. Be-
sides that, the value of b is bounded on both sides by the fact that, for
any finite value of a, if b is too large or too small, then the line f (x)
will not intersect the unit square. Consequently, the algorithm always
terminates.
In figures 10, 11, and 12, we present an example of the execution
of this algorithm. We use the algorithm to build a quad-graph for the
two half-planes divided by the line y = −3/4x + 1. These figures show
the algorithm constructing a quad-graph step-by-step.

5. Union and Intersection


To perform unions and intersections, we extend the classical algo-
rithm to perform union and intersections on quad-trees. We need to
change the algorithm to guarantee that it does not compute the in-
tersection the same pair of nodes multiple times. To do that, we use
data structures DU for the union and DI for the intersection. These
structures can be hash tables or binary search trees, for example. The
pseudo-code for the algorithms which compute the union and the in-
tersection of two quad-graphs are represented in figures 7 and 8.
It is clear that these two algorithms terminate in finite time. This
conclusion comes from the fact that the number of nodes stored on their
data structures is at most the number of nodes in G1 times the number
of nodes in G2 . Consequently, any bounded polygonal mapping can be
described exactly by a finite quad-graph.

6. Conclusion
The quad-graph data structure can perform most operations sup-
ported by the quad-tree data structure with very similar and simple
algorithms. For example, the 90◦ rotation algorithm can be performed
through a search in the graph where the pointers for the NW, NE, SW
and SE children are exchanged in a circular order.
The main advantage of the quad-graphs over the quad-trees is that,
when using quad-graphs, it is note necessary to approximate the map-
ping, as shown in figure 9. Besides that, using a deep quad-tree can be
slower and require more space than a quad-graph. That becomes clear
when comparing the two representations in figure 9.
QUAD-GRAPHS 9

Union(G1 , G2 )
// Check if G1 or G2 is empty or f ull
if G1 = f ull or G2 = f ull
return f ull
if G1 = empty
return G2
if G2 = empty
return G1
// Check if (G1 , G2 ) has already been generated
if DU .contains((G1 , G2 ))
return DU .get((G1 , G2 ))
// Create a new node and solve the problem recursively
n ← new node;
n.N W ← Union(G1 .N W , G2 .N W )
n.N E ← Union(G1 .N E, G2 .N E)
n.SW ← Union(G1 .SW , G2 .SW )
n.SE ← Union(G1 .SE, G2 .SE)
// Perform some graph compression
if n.N W = n.N E = n.SW = n.SE = f ull
delete n
return f ull
// Store the new node n with key (G1 , G2 )
DU .add(n, (G1 , G2 ));
return n

Figure 7. Algorithm to compute union of two quad-graphs.

When rendering an image stored in a quad-graph, it is possible to


generated an image as detailed as we want. We can go as deep as the
pixel size in the output device or even deeper for anti-aliasing purposes.
If we want a less detailed rendering we can go less deep and quickly
produce a courser image.
A disadvantage of the quad-graph is that it can use a lot of memory
space in some cases, specially if the coordinates of the vertices are
numbers with a large denominator. It is an open problem to establish
tight bounds on the size of the quad-graph given some properties of the
mapping, like the denominator of the vertices coordinates, the number
of vertices and the slope of the segments.
10 GUILHERME D. DA FONSECA

Intersection(G1 , G2 )
// Check if G1 or G2 is empty or f ull
if G1 = empty or G2 = empty
return empty
if G1 = f ull
return G2
if G2 = f ull
return G1
// Check if (G1 , G2 ) has already been generated
if DI .contains((G1 , G2 ))
return DI .get((G1 , G2 ))
// Create a new node and solve the problem recursively
n ← new node;
n.N W ← Intersection(G1 .N W , G2 .N W )
n.N E ← Intersection(G1 .N E, G2 .N E)
n.SW ← Intersection(G1 .SW , G2 .SW )
n.SE ← Intersection(G1 .SE, G2 .SE)
// Perform some graph compression
if n.N W = n.N E = n.SW = n.SE = empty
delete n
return empty
// Store the new node n with key (G1 , G2 )
DI .add(n, (G1 , G2 ));
return n
Figure 8. Algorithm to compute intersection of two
quad-graphs.

Acknowledgments
The author would like to thank Michael Moran, for the insightfull
discussions and the proof that any bounded polygonal mapping cor-
responds to a finite quad-graph. The author would also like to thank
Leila de Floriani, for numerous suggestions.
QUAD-GRAPHS 11

NW SE
NE SW

NW SE
NE SW

NW SE NW SE
NE SW NE SW

... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ...

Figure 9. A quad-graph compared to a quad-tree.


12 GUILHERME D. DA FONSECA

e: empty 1
f: full
NW SE
NE SW

(-3/4, 1, e, f) (-3/4, 1/4, e, f) (-3/4, 2, e, f) (-3/4, 5/4, e, f)

e: empty 1
f: full
NW SE
NE SW

1/4 (-3/4, 2, e, f) (-3/4, 5/4, e, f)


NW SE
NE SW

(-3/4, -1/2, e, f) (-3/4, -5/4, e, f) (-3/4, 1/2, e, f) (-3/4, -1/4, e, f)

e: empty 1
f: full
NW SE
NE SW

1/4 (-3/4, 2, e, f) (-3/4, 5/4, e, f)


NW SE
NE SW

1/2
NW NE SE
SW

(-3/4, 0, e, f) (-3/4, -3/4, e, f) (-3/4, 1, e, f) (-3/4, 1/4, e, f)

Figure 10. Algorithm computing a quad-graph.


QUAD-GRAPHS 13

e: empty 1
f: full
NW SE
NE SW

1/4 (-3/4, 2, e, f) (-3/4, 5/4, e, f)


NW
NE SW SE

1/2
NW
NE SE
SW

e: empty 1
f: full
NW SE
NE SW

1/4 5/4
SE NW
NW
NE SW
NE SW SE

1/2 (-3/4, 3/2, e, f) (-3/4, 5/2, e, f)


NW
NE SE
(-3/4, 3/4, e, f) (-3/4, 7/4, e, f)
SW

e: empty 1
f: full
NW SE
NE SW

1/4 5/4
SE NW
NW
NE SW
NE SW SE

1/2 3/2 (-3/4, 5/2, e, f)


NW
NE SE
(-3/4, 3/4, e, f) (-3/4, 7/4, e, f)
SW NW SE
NE SW
(-3/4, 2, e, f) (-3/4, 3, e, f)
(-3/4, 5/4, e, f) (-3/4, 1/4, e, f)

Figure 11. Algorithm computing a quad-graph.


14 GUILHERME D. DA FONSECA

e: empty 1
f: full
NW SE
NE SW

1/4 5/4
SE NW
NW
NE SW
SW SE
NE
1/2 3/2 (-3/4, 5/2, e, f)
NW
NE SE
(-3/4, 3/4, e, f) (-3/4, 7/4, e, f)
SW NW NE SE
SW

e: empty 1
f: full
NW SE
NE SW

1/4 5/4
SE NW
NW
NE SW
SW SE
NE
1/2 3/2 (-3/4, 5/2, e, f)
NW 3/4 SE (-3/4, 7/4, e, f)
NE SE
NE
SW NW SE
SW NW (-3/4, 3/4, e, f)
NE SW
(-3/4, 1/2, e, f) (-3/4, 3/2, e, f)
(-3/4, -1/4, e, f)

e: empty 1
f: full
NW SE
NE SW

1/4 5/4
SE NW
NW SE
NE SW
SW
NE
1/2 3/2
NW NW 3/4 SE
NE SE
NE
SW NW SE NE
SW
SW

Figure 12. Algorithm computing a quad-graph.

You might also like