Geometric Data Structures For Computer Graphics Elmar Langetepe instant download
Geometric Data Structures For Computer Graphics Elmar Langetepe instant download
https://ebookbell.com/product/geometric-data-structures-for-
computer-graphics-elmar-langetepe-46160642
New Geometric Data Structures For Collision Detection And Haptics 1st
Edition Ren Weller Auth
https://ebookbell.com/product/new-geometric-data-structures-for-
collision-detection-and-haptics-1st-edition-ren-weller-auth-4293878
https://ebookbell.com/product/geometric-data-analysis-from-
correspondence-analysis-to-structured-data-analysis-1st-edition-
brigitte-le-roux-2243462
https://ebookbell.com/product/geometric-data-analysis-from-
correspondence-analysis-to-structured-data-analysis-roux-b-997068
https://ebookbell.com/product/geometric-structure-of-highdimensional-
data-and-dimensionality-reduction-english-version-chinese-edition-
wang-jian-zhong-51992598
Geometric Structure Of Highdimensional Data And Dimensionality
Reduction 1st Edition Prof Jianzhong Wang Auth
https://ebookbell.com/product/geometric-structure-of-highdimensional-
data-and-dimensionality-reduction-1st-edition-prof-jianzhong-wang-
auth-4240862
https://ebookbell.com/product/information-geometry-and-population-
genetics-the-mathematical-structure-of-the-wrightfisher-model-julian-
hofrichter-5756400
https://ebookbell.com/product/combinatorial-inference-in-geometric-
data-analysis-brigitte-le-roux-solne-bienaise-jeanluc-durand-10670576
https://ebookbell.com/product/mathematical-principles-of-topological-
and-geometric-data-analysis-1st-edition-joharinad-56340382
https://ebookbell.com/product/handbook-of-variational-methods-for-
nonlinear-geometric-data-1st-edition-grohs-10871212
Geometric Data
Structures for
Computer Graphics
Geometric Data
Structures for
Computer Graphics
Elmar Langetepe
Gabriel Zachmann
A K Peters, Ltd.
Wellesley, Massachusetts
Editorial, Sales, and Customer Service Office
A K Peters, Ltd.
888 Worcester Street, Suite 230
Wellesley, MA 02482
www.akpeters.com
All rights reserved. No part of the material protected by this copyright notice may
be reproduced or utilized in any form, electronic or mechanical, including photo-
copying, recording, or by any information storage and retrieval system, without
written permission from the copyright owner.
T385.L364 2005
006.6–dc22
2005051464
The frontispiece and quote are from Hartmut Böhme’s Albrecht Dürer, Melencolia
I—Im Labyrinth der Deutung, page 50, published by Fischer Taschenbuch Verlag,
Frankfurt.
Printed in India
09 08 07 06 05 10 9 8 7 6 5 4 3 2 1
To Anke Grahn and Birgit Meurer.
Contents
Preface xi
3 BSP Trees 51
3.1 Rendering without a Z-Buffer . . . . . . . . . . . . . . . . . . . . 53
3.2 Representing Objects with BSPs . . . . . . . . . . . . . . . . . . 54
3.3 Boolean Operations . . . . . . . . . . . . . . . . . . . . . . . . . 55
3.4 Construction Heuristics . . . . . . . . . . . . . . . . . . . . . . . 59
vii
viii Contents
5 Distance Fields 85
5.1 Computation and Representation of DFs . . . . . . . . . . . . . . 87
5.2 Applications of DFs . . . . . . . . . . . . . . . . . . . . . . . . . 91
6 Voronoi Diagrams 95
6.1 Definitions and Properties . . . . . . . . . . . . . . . . . . . . . . 96
6.2 Computation . . . . . . . . . . . . . . . . . . . . . . . . . . . . 101
6.3 Generalization of the Voronoi Diagram . . . . . . . . . . . . . . . 110
6.4 Applications of the Voronoi Diagram . . . . . . . . . . . . . . . . 122
6.5 Voronoi Diagrams in Computer Graphics . . . . . . . . . . . . . 133
Bibliography 315
Index 333
Melencolia I, Albrecht Dürer
In recent years, methods from computational geometry have been widely adopted
by the computer graphics community, yielding elegant and efficient algorithms.
This book aims at endowing practitioners in the computer graphics field with a
working knowledge of a wide range of geometric data structures from computa-
tional geometry. It will enable readers to recognize geometric problems and select
the most suitable data structure when developing computer graphics algorithms.
The book will focus on algorithms and data structures that have proven to be
versatile, efficient, fundamental, and easy to implement. Thus practitioners and
researchers will benefit immediately from this book in their everyday work.
Our goal is to familiarize practitioners and researchers in computer graphics
with some very versatile and ubiquitous geometric data structures, enable them to
readily recognize geometric problems during their work, modify the algorithms
to their needs, and hopefully make them curious about further powerful treasures
to be discovered in the area of computational geometry.
In order to achieve these goals in an engaging yet sound manner, the general
concept throughout the book is to present each geometric data structure in the
following way: first, the data strucure will be defined and described in detail; then,
some of its fundamental properties will be highlighted; after that, one or more
computational geometry algorithms based on the data structure will be presented;
and finally, a number of recent, representative, and practically relevant algorithms
from computer graphics will be described in detail, showing the utilization of the
data structure in a creative and enlightening way.
We do not try to provide an exhaustive survey of the topics touched upon
here—this would be far beyond the scope of this book. Neither do we aspire to
present the latest and greatest algorithms for a given problem, for two reasons.
First, the focus is on geometric data structures, and we do not want to obstruct the
view with complicated algorithms. Second, we feel that, for practical purposes, a
good trade-off between simplicity and efficiency is important.
xi
xii Preface
proximity graphs
(Ch. 7)
cialized spatial data structures for moving objects is introduced in Chapter 8 and
discussed by an example. In Chapter 9, we consider the problems of degeneracy
and robustness in geometric computing. finally, in Chapter 10, we introduce a
simple generic scheme for dynamization.
Acknowledgments
We would like to thank Prof. Dr. Reinhard Klein and Prof. Dr. Rolf Klein for their
encouragement and advice during the work. Thanks goes also to Ansgar Grüne,
Tom Kamphans, Adalbert Prokop, Manuel Wedemeier, and Michael Bazanski for
reading some parts of the manuscript. In addition, many thanks go to Jan Klein for
the great collaboration. We are grateful to Alice and Klaus Peters for initiating this
book. And we would like to thank Kevin Jackson-Mead for managing the project
and for his great patience. Part of Zachmann’s work was funded by DFG’s grant
ZA292/1.
1
Quadtrees and
Octrees
In this chapter, we introduce the quadtree and octree structures. Their definition
and complexity, the recursive construction scheme, and a standard application are
presented. Quadtrees and octrees have applications in mesh generation, as shown
in Sections 1.3, 1.4, and 1.5.
1.1. Definition
A quadtree is a tree rooted so that every internal node has four children. Every
node in the tree corresponds to a square. If a node v has children, their corre-
sponding squares are the four quadrants, as shown in Figure 1.1.
Quadtrees can store many kinds of data. We will describe the variant that
stores a set of points and suggest a recursive definition. A simple recursive split-
ting of squares is continued until there is only one point in a square. Let P be a
set of points.
NE NW SW SE
1
2 1. Quadtrees and Octrees
• Otherwise, let QNE , QNW , QSW , and QSE denote the four quadrants. Let
xm id := (x1Q + x2Q )/2 and y m id := (y1Q + y2Q )/2, and define
Theorem 1.1. The depth of a quadtree for a set P of points in the plane is at most
log( s/c) + 32 , where c is the smallest distance between any two points in P , and s
is the side length of the initial square.
The cost of the recursive construction and the complexity of the quadtree de-
pends on the depth of the tree.
Theorem 1.2. A quadtree of depth d that stores a set of n points has O((d + 1)n)
nodes and can be constructed in O((d + 1)n) time.
Due to the degree 4 of the internal nodes, the total number of leaves is one
plus three times the number of internal nodes. Hence, it suffices to bound the
number of internal nodes.
Any internal node v has one or more points inside Q(v). The squares of the
node of a single depth cover the initial square. Therefore, at every depth, we have
at most n internal nodes, which gives the node bound.
1.2. Complexity and Construction 3
The most time-consuming task in one step of the recursive approach is the
distribution of the points. The amount of time spent is linear only in the number
of points and the O((d + 1)n) time bound holds.
The 3D equivalents of quadtrees are octrees. The quadtree construction can be
easily extended to octrees in 3D. The internal nodes of octrees have eight children,
and the children correspond to boxes instead of squares.
Figure 1.3. A terrain (left), a TIN of its height field (middle), and a superposition (right)
[Wahl et al. 04]. (See Color Plate I.)
1.3. Height Field Visualization 5
T-vertices!
4 8
Figure 1.4. In order to use a quadtree for Figure 1.5. A quadtree defines a recur-
defining a height field mesh, it should be sive subdivision scheme yielding a 4-8
balanced. (Courtesy Prof. R. Klein and mesh. The dots denote the newly added
R. Wahl, Bonn University.) vertices. Some vertices have degree 4,
and some have 8 (hence the name).
M is crack-free ⇔
M does not have any T-vertices ⇔
∀(i, j ) ∈ M : (i , j ) ∈ M, where parent(j ) = {i, i }. (1.1)
In other words: you cannot subdivide one triangle alone; you also must subdivide
the one on the other side. During rendering, this means that if you render a vertex,
you also have to render all its ancestors (remember that a vertex has two parents).
Rendering such a mesh generates (conceptually) a single, long list of vertices
that are then fed into the graphics pipeline as a single triangle strip. The pseu-
docode for the algorithm looks like this (simplified):
submesh(i, j )
if error(i) < τ then
return
end if
if Bi outside viewing frustum then
return
end if
submesh( j , c l )
V += p i
submesh( j , c r )
where error(i) is some error measure for vertex i, and Bi is the sphere around
vertex i that completely encloses all descendant triangles.
Note that this algorithm can produce the same vertex multiple times consec-
utively; this is easy to check, of course. In order to produce one strip, the algo-
rithm has to copy older vertices to the current front of the list at places where it
makes a “turn”; again, this is easy to detect, and the interested reader is referred
to [Lindstrom and Pascucci 01].
One can speed up the culling a bit by noticing that if Bi is completely inside
the frustum, we do not need to test the child vertices anymore.
We still need to think about the way we store our terrain subdivision mesh.
Eventually, we will want to store it as a single linear array for two reasons:
• The tree is complete, so it really would not make sense to store it using
pointers.
• We want to map the file that holds the tree into memory as-is (for instance,
with the Unix mmap function), so pointers would not work at all.
1.3. Height Field Visualization 7
red
red
blue
level 0 1 2 3 4
blue
Figure 1.6. The 4-8 subdivision can Figure 1.7. The red quadtree can be
be generated by two interleaved stored in the unused “ghost” nodes of
quadtrees. The solid lines connect the blue quadtree. (See Color Plate III.)
siblings that share a common parent.
(See Color Plate II.)
We should keep in mind, however, that with current architectures, every memory
access that cannot be satisfied by the cache is extremely expensive (this is even
more so with disk accesses, of course).
The simplest way to organize the terrain vertices is a matrix layout. The disad-
vantage is that there is no cache locality at all across the major index. To improve
this, people often introduce some kind of blocking, where each block is stored in a
matrix and all blocks are arranged in matrix order, too. Unfortunately, Lindstrom
and Pascucci [Lindstrom and Pascucci 01] report that this is, at least for terrain
visualization, worse than the simple matrix layout by a factor 10!
Enter quadtrees. They offer the advantage that vertices on the same level are
stored fairly close in memory. The 4-8 subdivision scheme can be viewed as two
quadtrees that are interleaved (see Figure 1.6): we start with the first level of the
“red” quadtree that contains just the one vertex in the middle of the grid, which
is the one that is generated by the 4-8 subdivision with the first step. Next comes
the first level of the “blue” quadtree that contains four vertices, which are the
vertices generated by the second step of the 4-8 subdivision scheme. This process
repeats logically. Note that the blue quadtree is exactly like the red one, except it
is rotated by 45°. When you overlay the red and the blue quadtree, you get exactly
the 4-8 mesh.
Notice that the blue quadtree contains nodes that are outside the terrain grid;
we will call these nodes “ghost nodes.” The nice thing about them is that we can
store the red quadtree in place of these ghost nodes (see Figure 1.7). This reduces
the number of unused elements in the final linear array down to 33%.
During rendering, we need to calculate the indices of the child vertices, given
the three vertices of a triangle. It turns out that by cleverly choosing the indices
of the top-level vertices, this can be done as efficiently as with a matrix layout.
8 1. Quadtrees and Octrees
The interested reader can find more about this topic in [Lindstrom et al. 96,
Lindstrom and Pascucci 01, Balmelli et al. 01, Balmelli et al. 99], and many
others.
physical
space ⊕
⊕ ⊕ ⊕
node cell ⊕
?
⊕
⊕ ⊕
computational
space
⊕
Figure 1.8. A scalar field is often given in Figure 1.9. Cells straddling the isosurface
the form of a curvilinear grid. By doing are triangulated according to a look-up
all calculations in computational space, table. In some cases, several triangu-
we can usually save a lot of computa- lations are possible, which must be re-
tional effort. solved by heuristics.
1.4. Isosurface Generation 9
Notice that in this algorithm, we have used only the 3D array; we have not
used the information about exactly where in space the nodes are (except when
actually producing the triangles). We have, in fact, made a transition from com-
putational space (i.e., the curvilinear grid) to computational space (i.e., the 3D
array). So in the following, we can, without loss of generality, restrict ourselves
to consider only regular grids, that is, 3D arrays.
The question is: how can we improve the exhaustive algorithm? One problem
is that we must not miss any little part of the isosurface. So, we need a data
structure that allows us to discard large parts of the volume where the isosurface
is guaranteed to not be. This calls for octrees.
The idea is to construct a complete octree over the cells of the grid [Wilhelms
and Gelder 90] (for the sake of simplicity, we will assume that the grid’s size is
a power of two). The leaves point to the lower-left node of their associated cell
(see Figure 1.10). Each leaf ν stores the minimum νmin and the maximum νmax
of the eight nodes of the cell. Similarly, each inner node of the octree stores the
minimum/maximum of its eight children.
Observe that an isosurface intersects the volume associated with a node ν
(inner or leaf node) if and only if νmin ≤ t ≤ νmax . This already suggests how the
algorithm works: start with the root and visit recursively all the children where
the condition holds. At the leaves, construct the triangles as usual.
This can be accelerated further by noticing that if the isosurface crosses an
edge of a cell, that edge will be visited exactly four times during the complete
procedure. Therefore, when we visit an edge for the first time, we compute the
vertex of the isosurface on that edge, and store the edge together with the vertex
in a hash table. So, whenever we need a vertex on an edge, we first try to look
up that edge in the hash table. Our observation also allows us to keep the size
of the hash table fairly low. When an edge has been visited for the fourth time,
we know that it cannot be visited anymore; therefore, we remove it from the hash
table.
y x=0 m0 m0
y=0 1
Figure 1.10. Octrees offer a simple way Figure 1.11. Volume data layout should
to compute isosurfaces efficiently.. match the order of traversal of the oc-
tree.
10 1. Quadtrees and Octrees
1.6. 3D Octree
A canonical way to improve any grid-based method is to construct an octree (see
Figure 1.13). Here, the octree leaves store lists of objects (or, rather, pointers to
Figure 1.12. Ray shooting can be imple- Figure 1.13. The same scenario utilizing
mented efficiently with a grid. an octree.
1.6. 3D Octree 11
objects). Since we are dealing now with polygons and other graphical objects, the
leaf rule for the octree construction process must be changed slightly: maximum
depth reached, or only one polygon/object occupies the cell. We can try to better
approximate the geometry of the scene by changing the rule to stop only when
there are no objects in the cell (or the maximum depth is reached).
How do we traverse an octree along a given ray? As in the case of a grid,
we have to make “horizontal” steps, which actually advance along the ray. With
octrees, though, we also need to make “vertical” steps, which traverse the octree
up or down.
All algorithms for ray shooting with octrees can be classified into two classes:
• Bottom-up: this method starts at that leaf in the octree that contains the
origin of the ray; from there, it tries to find that neighbor cell that is stabbed
next by the ray, etc.
• Top-down: this method starts at the root of the octree and tries to recurse
down into exactly those nodes and leaves that are stabbed by the ray.
Here, we will describe a top-down method [Revelles et al. 00]. The idea is
to work only with the ray parameter in order to decide which children of a node
must be visited.
Let the ray be given by
x = p + t d
and a voxel v by
[xl , xh ] × [y l , y h ] × [zl , zh ].
In the following, we will describe the algorithm assuming that all d i > 0; later,
we will show that the algorithm works also for all other cases.
First, observe that if we already have the line parameters of the intersection of
the ray with the borders of a cell, it is trivial to compute the line intervals halfway
in between (see Figure 1.14):
1 l
t mα = (t + t hα ) , α ∈ {x, y, z}. (1.2)
2 α
So, for eight children of a cell, we need to compute only three new line param-
eters. Clearly, the line intersects a cell if and only if max{t li } < min{t hj }. The
algorithm can be outlined as follows:
12 1. Quadtrees and Octrees
t hy
t hx
tm tm l
y > tx
y
tm
x
t lx
t ly tm l
y < tx
Figure 1.14. Line parameters are trivial to Figure 1.15. The sub-cell that must be tra-
compute for children of a node. versed first can be found by simple com-
parisons. Here, only the case t lx > t ly is
depicted.
traverse( v, t l , t h )
compute t m
determine order in which sub-cells are hit by the ray
for all sub-cells v i that are hit do
traverse( v i , t l |t m , t m |t h )
end for
where t l |t m means that we construct the lower boundary for the respective cell by
passing the appropriate components from t l and t m .
To determine the order in which sub-cells should be traversed, we first need to
determine which sub-cell is being hit first by the ray. In 2D, this is accomplished
by two comparisons (see Figure 1.15). Then the comparison of t mx with t my tells
us which cell is next.
In 3D, this takes a little bit more work, but is essentially the same. First, we
determine on which side the ray has been entering the current cell by Table 1.1.
Next, we determine the first sub-cell to be visited by Table 1.2 (see Figure 1.16
for the numbering scheme). The first column is the entering side determined in
the first step. The third column yields the index of the first sub-cell to be visited:
start with an index of zero; if one or both of the conditions of the second column
y 3 7
max{t li } Side
0 6
t lx YZ 5
t ly XZ 2 4
t lz XY z
x
Table 1.1. Determines the entering Figure 1.16. Sub-cells are numbered
side. according to this scheme.
1.7. 5D Octree 13
Table 1.2. Determines the first sub-cell. Table 1.3. Determines the traversal order
of the sub-cells.
hold, then the corresponding bit in the index as indicated by the third column
should be set.
Finally, we can traverse all sub-cells according to Table 1.3, where “ex” means
the exit side of the ray for the current sub-cell.
If the ray direction contains a negative component(s), then we just have to
mirror all tables along the respective axis (axes) conceptually. This can be imple-
mented efficiently by an XOR operation.
1.7. 5D Octree
In the previous, simple algorithm, we still walk along a ray every time we shoot
it into the scene. However, rays are essentially static objects, just like the geom-
etry of the scene! This is the basic observation behind the following algorithm
[Arvo and Kirk 87, Arvo and Kirk 89]. Again, it makes use of octrees to adap-
tively decompose the problem.
The underlying technique is a discretization of rays, which are 5D objects.
Consider a cube enclosing the unit sphere of all directions. We can identify any
ray’s direction with a point on that cube; hence, it is called a direction cube (see
Figure 1.17). The nice thing about it is that we can now perform any hierarchical
partitioning scheme that works in the plane, such as an octree: we just apply the
scheme individually on each side.
Using the direction cube, we can establish a one-to-one mapping between
direction vectors and points on all six sides of the cube, i.e.:
d
u u v + =
v
Figure 1.17. With the direction cube, we Figure 1.18. A uv interval on the direction
can discretize directions and organize cube plus a xyz interval in 3-space yield
them with any hierarchical partitioning a beam.
scheme.
We will denote the coordinates on the cube’s side by u and v. Here, {+x, −x, . . .}
are just some kind of IDs that are used to identify the side of the cube, on which
a point (u, v) lives (we could have used {1, . . . , 6} just as well).
Within a given universe B = [0, 1]3 (we assume it is a box), we can represent
all possibly occurring rays by points in
R = B × [−1, +1]2
(1.3)
× {+x, −x, +y, −y, +z, −z},
which can be implemented conveniently by six copies of 5D boxes.
Returning to our goal, we now build six 5D octrees as follows. Associate
(conceptually) all objects with the root. Partition a node in the octree if there are
too many objects associated with it and the node’s cell is too large. If a node is
partitioned, we must also partition its set of objects and assign each subset to one
of the children.
Observe that each node in the 5D octree defines a beam in 3-space: the xyz-
interval of the first three coordinates of the cell define a box in 3-space, and the
remaining two uv-intervals define a cone in 3-space. Together (more precisely,
taking their Minkowski sum), they define a beam in 3-space that starts at the cell’s
box and extends in the general direction of the cone (see Figure 1.18).
Since we have now defined what a 5D cell of the octree represents, it is almost
trivial to define how objects are assigned to sub-cells: we just compare the bound-
ing volume of each object against the sub-cells’ 3D beam. Note that an object can
be assigned to several sub-cells (just like in regular 3D octrees). The test whether
or not an object intersects a beam could be simplified further by enclosing a beam
with a cone and then checking the objects’ bounding sphere against that cone.
This just increases the number of false positives a bit.
Having computed the six 5D octrees for a given scene, ray tracing through
that octree is almost trivial: map the ray onto a 5D point via the direction cube;
1.7. 5D Octree 15
1 2 3 4
Figure 1.19. By sorting objects within Figure 1.20. By truncating the beam
each 5D leaf, we can often stop check- (or rather, the list of objects), we can
ing ray intersection quite early. save a lot of memory usage of a 5D oc-
tree, while reducing performance only
insignificantly.
start with the root of the octree that is associated with the side of the direction
cube onto which the ray was mapped; find the leaf in that octree that contains the
5D point (i.e., the ray); and check the ray against all objects associated with that
leaf.
By locating a leaf in one of the six 5D octrees, we have discarded all ob-
jects that do not lie in the general direction of the ray. But we can optimize the
algorithm even further.
First of all, we sort all objects associated with a leaf along the dominant axis
of the beam by their minimum (see Figure 1.19). If the minimum coordinate of
an object along the dominant axis is greater than the current intersection point,
then we can stop—all other possible intersection points are farther away.
Second, we can utilize ray coherence as follows. We maintain a cache for
each level in the ray tree that stores the leaves of the 5D octrees that were visited
last time. When following a new ray, we first look into the octree leaf in the cache
to see whether it is contained therein before we start searching for it from the root.
Another trick (which works with other ray acceleration schemes as well) is to
exploit the fact that we do not need to know the first occluder between a point on
a surface and a light source. Any occluder suffices to assert that the point is in
shadow. So, we also keep a cache with each light source, which stores the object
(or a small set) that was an occluder last time.
Finally, we would like to mention a memory optimization technique for 5D
octrees, because they can occupy a lot of memory. It is based on the observation
that within a beam defined by a leaf of the octree, the objects at the back (almost)
never intersect with a ray emanating from that cell (see Figure 1.20). So, we store
16 1. Quadtrees and Octrees
objects with a cell only if they are within a certain distance. Should a ray not hit
any object, we start a new intersection query with another ray that has the same
direction and a starting point just behind that maximum distance. Obviously, we
have to make a trade-off between space and speed here, but when chosen properly,
the cutoff distance should not reduce performance too much, while still saving a
significant amount of memory.
2
Orthogonal Windowing
and Stabbing Queries
In this chapter, we introduce some tree-based geometric data structures for an-
swering windowing and stabbing queries. Such queries are useful in many com-
puter graphics algorithms.
A stabbing query reports all objects that are stabbed by a single object. For a
set of segments S, a typical stabbing query reports all segments that are stabbed
by a single query line l. On the other hand, a windowing query reports all objects
that lie inside a window. For a set of points S, a typical windowing query reports
all points of S inside query box B.
We start with some simple queries and data structures, and then progress to
more sophisticated queries. Furthermore, we present time and space bounds for
construction and queries.
All data structures are considered to be static; that is, we assume that the set
of objects will not change over time and we do not have to consider Insert and
Delete operations. Such operations might be very costly or complicated. For
example, the hierarchical structure of the balanced kd-tree in Section 2.4 requires
a lot of reconstruction effort if new elements are inserted or old elements are
deleted.
For a dynamization, we use the simple and efficient generic dynamization
techniques presented in Chapter 10. We consider simple WeakDelete operations
for all data structures in order to apply the dynamization approach adequately. A
WeakDelete operation marks an object as deleted; the object is not removed from
the memory. After a set of efficient WeakDelete operations, it is necessary to
reconstruct the complete structure; see Chapter 10 for details. The corresponding
running times can be found in Section 10.5.
17
18 2. Orthogonal Windowing and Stabbing Queries
For example, in Figure 2.1, there are seven intervals s1 , s2 , . . . , s7 and a query
value xq . For convenience, the intervals are illustrated by horizontal line seg-
ments si in 2D and the query value is illustrated as a horizontal line xq . The
(interval/point) stabbing query should report the segments s2 , s5 , and s6 . We can
assume that a segment si is represented by the x-coordinate of its left and right
endpoints li and ri , respectively.
We construct a data structure that answers the above query efficiently. The
information of the intervals are stored in a binary tree. Let S denote a set of n
intervals [li , ri ] for i = 1, . . . , n. The binary interval tree is constructed recur-
sively, as shown in the construction sketch. A node of the tree is dedicated to a
median value of the endpoint of all segments. For all segments that contain this
value, there are two lists for checking wether a query value is also covered by
2.1. Interval Trees 19
xq xmed
s1
s2
s3
s4
s5
s6
s7
xmed
ML = {l5 , l6 , l3 }
MR = {r5 , r3 , r6 }
Figure 2.1. An example of the node information in an interval tree. For convenience,
the intervals are represented by 2D line segments. The left and right endpoints li and
ri of the segments si hit by the median xmed are represented in sorted lists ML and
MR , respectively.
those intervals; see Figure 2.1 for an example of the node information. The query
operation will be explained in detail later in this chapter.
The following is the interval tree construction algorithm sketch (see also Al-
gorithm 2.1):
• Let Lmed denote the set of intervals to the left of xmed , let Smed denote the
set of intervals that contain xmed , and let Rmed denote the set of intervals to
the right of xmed ;
20 2. Orthogonal Windowing and Stabbing Queries
• At the root v, store xmed and build a sorted list ML for all left endpoints of
Smed and a sorted list MR for all right endpoints of Smed ;
• Build the interval trees for Lmed and Rmed recursively for the children of v.
Algorithm 2.1 computes the interval tree efficiently, as shown in Lemma 2.1.
Lemma 2.1. The interval tree for a set S of n intervals has size O(n) and can
be constructed in O(n log n) time.
Proof: In a preliminary step, we sort the interval endpoints by li order, by ri order,
and by total (li and ri ) order. Obviously, the depth of the constructed tree is in
O(log n). Let n v denote the number of intervals at node v. Computing the median
takes O(n v ) time using the total order of the interval endpoints. Let m v = | Smed |
for the set of intervals Smed at v. Computing ML and MR from the li and ri order
takes at most O(m v ) time. Since all occurring sets Smed are distinct, this gives
O(n) altogether. Maintaining the li , ri , and total order for the recursive steps
takes O(n v ) time. Altogether, with the recursive steps, we have the recursive cost
function T (n v ) ≤ 2T ( n2v ) + O(n v ). Together with the depth O(log n) of the tree,
we conclude the given result.
Next, we consider the recursive stabbing query operation for a value xq ∈ R
and the root v of the interval tree. The median xmed of node v is used for binary
branching. The node information is used for answering the stabbing query for the
intervals that contain the median.
2.1. Interval Trees 21
– Scan the sorted list ML of the left endpoints in increasing order and
report all stabbed segments. Stop if xq is smaller than the current left
endpoint;
– Scan the sorted list MR of the right endpoints in decreasing order and
report all stabbed segments. Stop if xq is bigger than the current right
endpoint;
For example, assume that there is a stabbing query at a node v as pointed out
in Figure 2.1. Starting from the left with ML , the segments s5 and s6 are reported
since xq lies to the right of l5 and l6 . Then the stabbing query recursively goes on
with Lmed and will find s2 .
Lemma 2.2. An (interval/point) stabbing query with an interval tree for a set S
of n intervals and a value xq ∈ R report all k intervals I of S with xq ∈ I in
O(k + log n) time.
The interval tree was considered in [Edelsbrunner 80] and [McCreight 80].
Note that the interval tree has no direct generalization to higher dimensions, but
can support combined queries; see Section 2.6.
A WeakDelete operation for a segment s (see Chapter 10) can be done in
O(log n) time. We find the corresponding node with s ∈ Smed and mark the
endpoints as deleted in the sorted lists ML and MR .
Let S = {s1 , s2 , . . . , sn } be the set of segments and let E be the sorted set
of x-coordinates of the endpoints. We assume general position; that is, E =
1 Arbitrary query lines l can be handled by application of a transformation matrix; see Section 9.5.3.
2.2. Segment Trees 23
{e 1 , e 2 , . . . , e 2n } with e i < e j for i < j (Section 9.5). For the construction of the
tree, we can split E into 2n + 1 atomic intervals
v1 v2
v3
v4
Figure 2.2. A segment tree for a set of segments. The segment s is minimally covered
by the nodes v 1 , v 2 , v 3 , and v 4 .
24 2. Orthogonal Windowing and Stabbing Queries
– Allocate a node v with two children for the root of the tree;
node represents an elementary interval v.I and, if necessary, its data points. Mini-
mal means that the nodes are chosen as close as possible to the root of the tree; see
Figure 2.2. We store s in each of the associated nodes. More precisely, let v.pred
be the predecessor of v in the interval tree. A segment s = (e j , e k ) represented
by the x-coordinates of the endpoints is stored in a list v.L at v iff v.I ⊆ [e j , e k ]
and (v.pred).I ⊆ [e j , e k ]. Thus, each node represents an elementary interval v.I
and a list of segments v.L; for an example, see Figure 2.3.
The one-dimensional search tree with intervals v.I is built up in O(n log n)
time, as was shown previously. However, we need to show how the segment
partitions are inserted into the tree. This is done by the following recursive insert
procedure, which has to run for every segment s = (e j , e k ).
The following is the sketch of the segment insertion in the one-dimensional
search tree:
• Input: given a line segment s = (e j , e k ) and the root v of the segment tree;
– If the interval [e j , e k ] and the set (v. LeftChild).I overlap, then run
the insert procedure recursively with s and the segment tree
v. LeftChild;
– If the interval [e j , e k ] and the set (v. RightChild).I overlap, then run
the insert procedure recursively with s and the segment tree
v. RightChild.
By inserting every segment into the one-dimensional search tree of the line
segment’s endpoints, we will finally obtain the segment tree. Altogether, Algori-
thm 2.4 constructs the segment tree by using Algorithm 2.5 as a subroutine. Note
that Sx . Extend extends Sx by the dummy elements ∞ and −∞.
Lemma 2.4. The segment tree for n segments can be built in O(n log n) and uses
O(n log n) space.
Proof: The binary tree has depth O(logn) and O(n) nodes. At each level of the
segment tree T , a segment s = (e j , e k ) is stored at most twice. To prove this fact,
let us assume that three nodes u l , u m , and u r of the same level in T contain the
26 2. Orthogonal Windowing and Stabbing Queries
segment s. The intervals of their parents do not overlap. This is because they can
overlap only if a pair of u l , u m , and u r has a common predecessor. In this case,
the segment has to be inserted for the predecessor. If the intervals of the parents
of u l , u m , and u r do not overlap, the intermediate node of u l , u m , and u r must
have a parent whose interval fully contains [e j , e k ]; therefore, s is not inserted at
u m which gives a contradiction. Summing up over all segments and levels, the
segment tree has space O(n log n).
With a similar argument, one can prove that, during the insertion operation,
only four nodes on every level could be visited. Thus a single segment is inserted
in O(log n) time, which gives the overall time bound.
For a stabbing query with a vertical line l, we will proceed as follows. We start
with the x-coordinate lx of the vertical line l and the root node v of a segment tree.
The following is the sketch of the stabbing query with a segment tree:
• Input: given the x-coordinate lx of the vertical line l and the root node v of
a segment tree;
– If lx lies inside (v. LeftChild).I, then start a query with segment tree
v. LeftChild and lx ;
Figure 2.3 shows an example for a segment query. The shaded intervals indi-
cate the query path from the root to the leaf.
Lemma 2.5. A vertical line stabbing query for n segments in the plane can be
answered by a segment tree in time O(k + log n), where k stands for the number
of reported segments.
Proof: Obviously, the tree is traversed with O(log n) steps. The running time
O(k + log n) stems from the cardinality k of the corresponding sets v.L.
The segment tree was first considered in [Bentley 77] and extended to higher
dimensions by several authors; see, for example, [Edelsbrunner and Maurer 81]
and [Vaishnavi and Wood 82].
28 2. Orthogonal Windowing and Stabbing Queries
l
s2 s3 s2
s1 s1 s3 s5
s2 s4
s1 s4 s2
s3
s5
s2
s1
s4
Figure 2.3. The query procedure for a segment tree and a query line l . The shaded
intervals indicate the query path from the root to the leaf. All segments stored at the
corresponding nodes are reported.
Figure 2.4. A stabbing query for a set of bounding boxes can report all polygonal
objects near q .
This stabbing query has many applications in computer graphics. For exam-
ple, objects in the sphere may be approximated by their axis-parallel bounding
box. For every point q, the (bounding box/point) stabbing query will report all
objects that are near q. Figure 2.4 shows a simple example in 2D.
A single d-dimensional box Bi can be defined by a set of d axis-parallel
segments {Si1 , Si2 , . . . , Sid } starting at a unique corner Ci = (Ci1 , Ci2 , . . . , Cid );
see Figure 2.5 for a 2D example. A multi-level segment tree T d with respect to
(x1 , x2 , . . . , xd ), where xi denotes the ith coordinate, is inductively defined.
T1
s1
s12 s4
s42
q
s3 s32
s2 s42
s32
Figure 2.5. Some parts of the multi-level segment tree of four boxes in 2D. The seg-
ment tree T 1 and the relevant trees for the nodes u 1 and u 2 with Lu 1 = {s11 } and
Lu 2 = {s31 , s41 } for the query point q are shown.
30 2. Orthogonal Windowing and Stabbing Queries
• Build a one-dimensional segment tree T 1 for all segments Si1 with respect
to the x1 coordinate;
Proof: First, we sort the segment endpoints with respect to every dimension. The
first segment tree T 1 is built up in O(n log n) time, occupies space O(n log n),
and has O(n) nodes. Next, we construct (d − 1)-dimensional segment trees for
the set v.L of every node v in T 1 . By induction, we can assume that the (d − 1)-
dimensional segment tree for a node v ∈ T 1 with |v.L| segments is computed in
32 2. Orthogonal Windowing and Stabbing Queries
The required space can be measured as follows. The whole structure T d consists
of one-dimensional segment trees T 1 only. In how many trees will a part of the
box Bi appear? In the first tree T 1 , the segment si1 of the box Bi appears in
O(log n) nodes. Therefore, it appears in O(log n) trees Tv(d−1) . In each of these
trees, the segment si2 of the box Bi appears again in O(log n) nodes. Altogether,
segments of Bi appear in
d
logi ∈ O(logd n)
i=1
nodes. Summing up over all n segments gives O(n logd n) entries. By the same
argument, the number of trees is bounded by O(logd n) also, so that the number
of empty nodes is in O(n logd n).
Analogously, a query traverses along O(logd n) nodes. For the first tree T 1 ,
the query traverses O(log n) nodes and therefore O(log n) new queries have to be
considered. Recursively, O(log n) nodes in O(log n) new trees may be traversed.
In the final segment trees, k boxes may also be reported. Altogether
d
logi ∈ O(logd n)
i=1
nodes are visited, and the running time for a query is O(k + logd n).
2.4. Kd-Trees
In general, a windowing query considers a set of objects and a multi-dimensional
window, such as a box. All objects that intersect with the window should be
reported. Thus, one can easily decide which objects are located within a certain
area, one of the classic problems arising in computer graphics.
The kd-tree is a natural generalization of the one-dimensional search tree con-
sidered in the previous section. It can be viewed also as a generalization of
quadtrees. With the help of a kd-tree, one can efficiently answer (point/axis-
parallel box) windowing queries as follows:
• Input: a set of points S in Rd ;
• Query: an axis-parallel d-dimensional box B;
• Output: all points p ∈ S with p ∈ B.
Let D be a set of n points in Rk . For convenience, we assume that for a while
k = 2, and that all x- and y-coordinates are different. If this is not the case, we will
have a so-called degenerate situation, and we can apply the techniques presented
in Section 9.5. Let us further assume that we have decided to split D along the
x-axis, and that we have determined the split value s of the x-coordinates. Then
we split D by the split line x = s into subsets
D <s = {(x, y) ∈ D|x < s},
D >s = {(x, y) ∈ D|x > s}.
We repeat the process recursively with the constructed subsets. For every split
operation, we have to determine the split axis and the split value. The simplest
strategy is to choose the axes in a cyclic manner (i.e., x-, y-, z-axis, etc.)—this is
called a cyclic kd-tree. More precisely, a kd-tree for dimension d is constructed
as follows.
The following is the inductive construction of a kd-tree sketch:
• Input: given a set of points D in dimension d and the split coordinate xi ;
• If D is empty, then return an empty node v;
• Otherwise, allocate a node v for the root of the kd-tree with two children
v. LeftChild and v. RightChild. Choose a split value si with respect to the
chosen coordinate xi . Split the set D into subsets
D <si = {(x1 , . . . , xi , . . . , xn ) ∈ D|xi < s},
D >si = {(x1 , . . . , xi , . . . , xn ) ∈ D|xi > s};
34 2. Orthogonal Windowing and Stabbing Queries
• Recursively, build the kd-trees v. LeftChild and v. RightChild for the set
D <s and D >s with respect to the next coordinate xj , j = (i mod d) + 1,
respectively. Finally, return the node v.
The tree will be built up by KdTreeConstr(D, 1). Thus, we simply obtain
a binary tree. The balance of the tree depends on the choice of the split value in
procedure SplitValue. In case of d = 2, we obtain a 2D kd-tree2 of the point set D;
see Figure 2.6. Each internal node of the tree corresponds to a split line. For every
node v of the kd-tree, we define the rectangle R(v), the region of v, which is the
intersection of half-planes corresponding to the path from the root to v. For the
root r, R(r) is the plane itself; the children of r, say λ and ρ, correspond to two
half-planes R(λ) and R(ρ), and so on. The set of rectangles {R(l)|l is a leaf}
gives a non-overlapping partition of the plane into rectangles. Every R(l) has
exactly one point of D inside. We do not have to store the rectangles explicitly;
they are given by the path from the root to the corresponding node; see Figure 2.6.
For simplicity, we again consider the 2D case. The kd-tree in 2D efficiently
supports range queries of axis-parallel rectangles. If Q is an axis-parallel rectan-
gle, the set of sites v ∈ D with v ∈ Q can be computed as follows. We have to
2 According to [de Berg et al. 00], the term k-d tree was meant as a template to be specialized like
2-d tree, 3-d tree, etc. Today, it is customary to specialize it like 2D kd-tree, etc.
2.4. Kd-Trees 35
Y
i x=5
g x<5 5<x
d
k
y=4 y=5
b y<4 4<y y<5 5<y
f
c x=2 x=3 x=8 x=7
x<3 3<x
x<2
2<x x<8 8<x x<7 7<x
a b d
j
j g
e h y=3 y=2 y=6
y<3 3<y y<2 2<y y<6 6<y
a
e c h f k i
X
Figure 2.6. A 2D kd-tree and a rectangular range query. Each node corresponds
to a split line. Additionally, each node represents a unique rectangular range R(v)
according to the path from the root to the node.
If the condition holds for node v, it will hold also for the predecessor u of v in
the kd-tree since R(v) ⊂ R(u). Thus, we can start searching from the root to the
leaves. Finally, if we reach a leaf of the tree with the given property, we still have
to check whether the data point of the leaf is inside Q.
For general dimension d, every node v implicitly represents an orthogonal
box in dimension d. Analogously, the box is given by the path from the root to v.
For the query operation, we store the current orthogonal box explicitly during the
query process. We obtain the following query procedure.
The following is the d-dimensional axis-parallel query sketch:
• Otherwise, the given Q(v) is split into the regions Q(v. LeftChild) and
Q(v. RightChild) for the left and the right child of v by using the split line
v. Split;
Title: Our Story Book: Jingles, Stories and Rhymes for Little
Folks
Author: Various
Language: English
Profusely Illustrated
NEW YORK
CUPPLES & LEON COMPANY
Copyright, 1916, by
Cupples & Leon Company
CONTENTS
Wideawake Willy.
The Little Old Woman.
Quite an Adventure.
Funny Toys
There Were Seven Froggies of Lee
Tinklebell Tales.
Holiday Time.
The Twins.
The Five Little Frogs.
The Doings of Dickie and Daisy
Follow My Leader.
Bunny and Chick, Or Sulky Sammy.
Doggie and Puss.
Tittle-tattle Tales, Or Fireside Stories.
The Kitkin Family
Wooden Toys.
Tick Tock
Neddy
Silly Billy and the Kittens.
Tony
The Cats and the Cheese, Or, Better Agree Than Go to Law.
The Doll's House to Let.
The Fox That Lost His Tail, Or, Do Not Follow Every Fashion You See.
Mrs. Gamp and Mrs. Puss-cat
The Conceited Golliwog.
Dolly's Name.
The Call to Arms.
To London Town.
A Home in the Wainscot.
We Three
Under the Big Hat, Or, Jackie and Me.
The Naughty Kitten.
The Goose Girl.
Goose-girl.
Waiting For Tea.
The Boy and the Bogie.
Baby's Bunnie.
My First Visit.
Ten Raw Recruits.
The Dog and the Wolf; Or, Be Content With Your Lot.
Castles in the Air.
A Day at the Farm.
Doggie's Woes.
Off to the Front.
Tommy's First Day at School.
Mister Jack-in-the-box.
Hector Protector.
The Muzzle That Fitted Too Much.
In the Farmyard.
Fir Tree Farm.
Pity the Sorrows of a Poor Little Dog.
Too Sure.
Firefly.
What a Mistake.
Charlie's Playthings.
How Pussy Caught Her First Bird.
A Rat Hunt.
Nip and the Pigeons.
Wideawake Willy.
H
is real name was Willy. But because he was always on the look-
out for any fun or mischief, Father and Mother called him
“Wideawake” as well.
One sunny day he and his little friends went out to play cricket.
“I'm going to make a hundred runs!” cried Willy, as he took up the
bat. But when he had made ten, Freddy bowled him out, and the
other boys were glad it was their turn to go in.
In the winter, father made a big slide, and Willy and the boys went
down it as fast as they could go. When he fell half way down, Willy
thought it great fun, and called to his snowman as he glided past,
“Look at me old fellow! Don't you wish you could slide?”
On his birthday he had a party. It was a merry time. They played
“Blind Man's Buff,” and “Puss in the Corner,” and Willy always
managed to catch the little girls by their long curls.
It was spring when Wideawake Willy went exploring. He shot his
Teddy Bear, and tied it up in a scarlet handkerchief, for he knew
explorers ate bears. Then he stuck a long feather in his hat, and
strode gaily down the road. Presently he came to a big house. The
door was open, and a lady asked him to go in. She showed him all
sorts of wonderful things. What he liked best was Chin Chan, the
Chinese boy, whose long pig-tail touched the floor. The lady told
Willy that in China he lived in a boat, and helped his mother look
after the chickens.
After seeing other Chinese people, he went home and told his
mother what strange things he had seen.
The Little Old Woman.
T
here was an old Woman,
And what do you think?
She lived upon nothing but
Victuals and drink;
And though victuals and drink
Were the chief of her diet,
This little Old Woman could never be quiet.
ebookbell.com