Quad Graphs
Quad Graphs
GUILHERME D. DA FONSECA
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
NW SE
NE SW
NW SE
SW NE
NW
SE
SW
NE
1/3
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.
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
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
... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ...
e: empty 1
f: full
NW SE
NE SW
e: empty 1
f: full
NW SE
NE SW
e: empty 1
f: full
NW SE
NE SW
1/2
NW NE SE
SW
e: empty 1
f: full
NW SE
NE SW
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
e: empty 1
f: full
NW SE
NE SW
1/4 5/4
SE NW
NW
NE SW
NE SW SE
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