VTK Textbook
VTK Textbook
Fourth Edition
Commercial support and consulting is available for this software from Kitware, Inc.
Please visit http://www.kitware.com for more information
or send email to kitware@kitware.com.
© 2006 Kitware, Inc.
http://www.kitware.com
All rights reserved. No part of this book may be reproduced, in any form or by any means,
without the express written permission of the publisher.
The publisher Kitware, Inc. offers discounts on this book when ordered in bulk quantities.
The publisher also produces companion works to this text such as The VTK User’s Guide.
For more information contact Kitware, Inc. at kitware@kitware.com.
You may also order directly from Kitware’s electronic store
at http://www.kitware.com/products.
Contributors to this work include the listed authors as well as the following.
Cover Design: Sébastien Barré
Production Editor: Amy Squillacote
Technical Contributors: World-Wide VTK Developer Community at www.vtk.org.
All product names mentioned herein are the trademarks of their respective owners.
Preface xiii
Acknowledgments xv
Chapter 1 Introduction 1
1.1 What Is Visualization? . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1
Terminology . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1
Examples of Visualization . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2
1.2 Why Visualize? . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3
1.3 Imaging, Computer Graphics, and Visualization . . . . . . . . . . . . . . . . . . . 4
1.4 Origins of Data Visualization . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6
1.5 Purpose of This Book . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 7
1.6 What This Book Is Not . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 7
1.7 Intended Audience . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 7
1.8 How to Use This Book . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 8
1.9 Software Considerations and Example Code . . . . . . . . . . . . . . . . . . . . . . 8
1.10 Chapter-by-Chapter Overview . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 9
Chapter 2 : Object-Oriented Design . . . . . . . . . . . . . . . . . . . . . . . . . . . . 9
Chapter 3 : Computer Graphics Primer . . . . . . . . . . . . . . . . . . . . . . . . . 9
Chapter 4 : The Visualization Pipeline . . . . . . . . . . . . . . . . . . . . . . . . . 10
Chapter 5 : Basic Data Representation . . . . . . . . . . . . . . . . . . . . . . . . . 10
Chapter 6 : Fundamental Algorithms . . . . . . . . . . . . . . . . . . . . . . . . . . 10
Chapter 7 : Advanced Computer Graphics . . . . . . . . . . . . . . . . . . . . . . 10
Chapter 8 : Advanced Data Representation . . . . . . . . . . . . . . . . . . . . . 10
Chapter 9 : Advanced Algorithms . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11
Chapter 10 : Image Processing . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11
Chapter 11 : Visualization on the Web . . . . . . . . . . . . . . . . . . . . . . . . . 11
Chapter 12 : Applications . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11
1.11 Legal Considerations . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11
1.12 Bibliographic Notes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 12
1.13 References . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 12
2.10 References . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 29
2.11 Exercises . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 31
Conditional Execution . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 92
4.5 Memory and Computation Trade-off . . . . . . . . . . . . . . . . . . . . . . . . . . . 92
Static and Dynamic Memory Models . . . . . . . . . . . . . . . . . . . . . . . . . 93
Reference Counting & Garbage Collection . . . . . . . . . . . . . . . . . . . . . 94
4.6 Advanced Visualization Pipeline Models . . . . . . . . . . . . . . . . . . . . . . . . 95
Processing Unknown Dataset Types . . . . . . . . . . . . . . . . . . . . . . . . . . 95
Extending the Data Object Representation . . . . . . . . . . . . . . . . . . . . . 95
Managing Complex Execution Strategies . . . . . . . . . . . . . . . . . . . . . . 96
4.7 Programming Models . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 98
Visualization Models . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 98
Alternative Visual Programming Models . . . . . . . . . . . . . . . . . . . . . . 99
4.8 Data Interface Issues . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 100
Programming Interface . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 100
Application Interface . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 101
4.9 Putting It All Together . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 101
Procedural Language Implementation . . . . . . . . . . . . . . . . . . . . . . . . 102
Pipeline Design and Implementation . . . . . . . . . . . . . . . . . . . . . . . . . 103
Connecting Pipeline Objects . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 105
Pipeline Execution and Information Objects . . . . . . . . . . . . . . . . . . . 108
Flexible Computation / Memory Trade-off . . . . . . . . . . . . . . . . . . . . 110
High-Level Object Design . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 110
Examples . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 111
4.10 Chapter Summary . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 115
4.11 Bibliographic Notes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 116
4.12 References . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 116
4.13 Exercises . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 118
Glossary 483
Index 497
Preface
tion algorithms, we have added several readers and writers, and better support net-based tools such
as Java and VRML. VTK now supports cell attributes, and attributes have been generalized into
data arrays that are labeled as being scalars, vectors, and so on. Parallel processing, both shared-
memory and distributed models, is a major addition. For example, VTK has been used on a large
1024-processor computer at the US National Labs to process nearly a pit-a-pat of data. A suite of
3D widgets is now available in VTK, enabling powerful data interaction techniques. Finally, VTK’s
cross-platform support has greatly improved with the addition of CMake—a very nice tool for
managing the compile process ( http://www.cmake.org ).
The additions of these features required the support of three special contributors to the text:
Lisa Sobierajski Avila, Rick Avila, and C. Charles Law. Rick and Lisa worked hard to create an
object-oriented design for volume rendering, and to insure that the design and software is fully
compatible with the surface-based rendering system. Charles is the principle architect and imple-
mentor for the imaging pipeline. We are proud of the streaming and caching capability of the archi-
tecture: It allows us to handle large data sets despite limited memory resources.
Especially satisfying has been the response from users of the text and software. Not only
have we received a warm welcome from these wonderful people, but many of them have contrib-
uted code, bug fixes, data, and ideas that greatly improved the system. In fact, it would be best to
categorize these people as co-developers rather than users of the system. We would like to encour-
age anyone else who is interested in sharing their ideas, code, or data to contact the VTK user com-
munity at http://www.vtk.org , or one of the authors. We would very much welcome any
contributions you have to make. Contact us at http://www.kitware.com .
Acknowledgments
been instrumental in adding parallel processing support to VTK. An additional special thanks to
Kitware for accepting the challenge of publishing this book.
Many of the bug fixes and improvements found in the second and third editions came from
talented people located around the world. Some of these people are acknowledged in the software
and elsewhere in the text, but most of them have contributed their time, knowledge, code, and data
without regard for recognition and acknowledgment. It is this exchange of ideas and information
with people like this that makes the Visualization Toolkit such a fun and exciting project to work on.
In particular we would like to thank John Biddiscombe, Charl P. Botha, David Gobbi, Tim Hutton,
Dean Inglis, and Prabhu Ramachandran. Thank you very much.
A special thanks to the software and text reviewers who spent their own time to track down
some nasty bugs, provide examples, and offer suggestions and improvements. Thank you Tom Cit-
riniti, Mark Miller, George Petras, Hansong Zhang, Penny Rheingans, Paul Hinker, Richard Ellson,
and Roger Crawfis. We’d also like to mention that Tom Citriniti at Rensselaer, and Penny Rhein-
gans at the University of Mississippi (now at the University of Maryland Baltimore County) were
the first faculty members to teach from early versions of this text. Thank you Penny and Tom for
your feedback and extra effort.
Most importantly we would like to thank our friends and loved ones who supported us
patiently during this project. We know that you shouldered extra load for us. You certainly saw a lot
less of us! But we’re happy to say that we’re back. Thank you.
Chapter 1
Introduction
Terminology
Different terminology is used to describe visualization. Scientific visualization is the formal name
given to the field in computer science that encompasses user interface, data representation and pro-
cessing algorithms, visual representations, and other sensory presentation such as sound or touch
[McCormick87] . The term data visualization is another phrase used to describe visualization. Data
visualization is generally interpreted to be more general than scientific visualization, since it
implies treatment of data sources beyond the sciences and engineering. Such data sources include
financial, marketing, or business data. In addition, the term data visualization is broad enough to
2 Introduction
include application of statistical methods and other standard data analysis techniques
[Rosenblum94] . Another recently emerging term is information visualization . This field endeavors
to visualize abstract information such as hyper-text documents on the World Wide Web, directory/
file structures on a computer, or abstract data structures [InfoVis95] . A major challenge facing infor-
mation visualization researchers is to develop coordinate systems, transformation methods, or
structures that meaningfully organize and represent data.
Another way to classify visualization technology is to examine the context in which the data
exists. If the data is spatial-temporal in nature (up to three spatial coordinates and the time dimen-
sion) then typically methods from scientific visualization are used. If the data exists in higher-
dimensional spaces, or abstract spaces, then methods from information visualization are used. This
distinction is important, because the human perceptual system is highly tuned to space-time rela-
tionships. Data expressed in this coordinate system is inherently understood with little need for
explanation. Visualization of abstract data typically requires extensive explanations as to what is
being viewed. This is not to say that there is no overlap between scientific and information visual-
ization—often the first step in the information visualization process is to project abstract data into
the spatial-temporal domain, and then use the methods of scientific visualization to view the
results. The projection process can be quite complex, involving methods of statistical graphics, data
mining, and other techniques, or it may be as simple as selecting a lower-dimensional subset of the
original data.
In this text we use the term data visualization instead of the more specific terms scientific
visualization or information visualization. We feel that scientific visualization is too narrow a
description of the field, since visualization techniques have moved beyond the scientific domain
and into areas of business, social science, demographics, and information management in general.
We also feel that the term data visualization is broad enough to encompass the term information
visualization.
Examples of Visualization
Perhaps the best definition of visualization is offered by example. In many cases visualization is
influencing peoples’ lives and performing feats that a few years ago would have been unimagin-
able. A prime example of this is its application to modern medicine.
Computer imaging techniques have become an important diagnostic tool in the practice of
modern medicine. These include techniques such as X-ray Computed Tomography (CT) and Mag-
netic Resonance Imaging (MRI). These techniques use a sampling or data acquisition process to
capture information about the internal anatomy of a living patient. This information is in the form
of slice-planes or cross-sectional images of a patient, similar to conventional photographic X-rays.
CT imaging uses many pencil thin X-rays to acquire the data, while MRI combines large magnetic
fields with pulsed radio waves. Sophisticated mathematical techniques are used to reconstruct the
slice-planes. Typically, many such closely spaced slices are gathered together into a volume of data
to complete the study.
As acquired from the imaging system, a slice is a series of numbers representing the attenua-
tion of X-rays (CT) or the relaxation of nuclear spin magnetization (MRI) [Krestel90] . On any given
slice these numbers are arranged in a matrix, or regular array. The amount of data is large, so large
that it is not possible to understand the data in its raw form. However, by assigning to these num-
bers a gray scale value, and then displaying the data on a computer screen, structure emerges. This
1.2 Why Visualize? 3
structure results from the interaction of the human visual system with the spatial organization of the
data and the gray-scale values we have chosen. What the computer represents as a series of num-
bers, we see as a cross section through the human body: skin, bone, and muscle. Even more impres-
sive results are possible when we extend these techniques into three dimensions. Image slices can
be gathered into volumes and the volumes can be processed to reveal complete anatomical struc-
tures. Using modern techniques, we can view the entire brain, skeletal system, and vascular system
on a living patient without interventional surgery. Such capability has revolutionized modern medi-
cal diagnostics, and will increase in importance as imaging and visualization technology matures.
Another everyday application of visualization is in the entertainment industry. Movie and
television producers routinely use computer graphics and visualization to create entire worlds that
we could never visit in our physical bodies. In these cases we are visualizing other worlds as we
imagine them, or past worlds we suppose existed. It’s hard to watch the movies such as Jurassic
Park and Toy Story and not gain a deeper appreciation for the awesome Tyrannosaurus Rex, or to be
charmed by Toy Story ’s heroic Buzz Lightyear.
Morphing is another popular visualization technique widely used in the entertainment indus-
try. Morphing is a smooth blending of one object into another. One common application is to morph
between two faces. Morphing has also been used effectively to illustrate car design changes from
one year to the next. While this may seem like an esoteric application, visualization techniques are
used routinely to present the daily weather report. The use of isovalue, or contour, lines to display
areas of constant temperature, rainfall, and barometric pressure has become a standard tool in the
daily weather report.
Many early uses of visualization were in the engineering and scientific community. From its
inception the computer has been used as a tool to simulate physical processes such as ballistic tra-
jectories, fluid flow, and structural mechanics. As the size of the computer simulations grew, it
became necessary to transform the resulting calculations into pictures. The amount of data over-
whelmed the ability of the human to assimilate and understand it. In fact, pictures were so impor-
tant that early visualizations were created by manually plotting data. Today, we can take advantage
of advances in computer graphics and computer hardware. But, whatever the technology, the appli-
cation of visualization is the same: to display the results of simulations, experiments, measured
data, and fantasy; and to use these pictures to communicate, understand, and entertain.
lived, it is not surprising that certain senses developed to help them survive. As we described earlier
in the example of a 2D MRI scan, visual representations are easier to work with. Not only do we
have strong 2D visual abilities, but also we are adept at integrating different viewpoints and other
visual clues into a mental image of a 3D object or plot. This leads to interactive visualization,
where we can manipulate our viewpoint. Rotating about the object helps to achieve a better under-
standing. Likewise, we have a talent for recognizing temporal changes in an image. Given an ani-
mation consisting of hundreds of frames, we have an uncanny ability to recognize trends and spot
areas of rapid change.
With the introduction of computers and the ability to generate enormous amounts of data,
visualization offers the technology to make the best use of our highly developed visual senses. Cer-
tainly other technologies such as statistical analysis, artificial intelligence, mathematical filtering,
and sampling theory will play a role in large-scale data processing. However, because visualization
directly engages the vision system and human brain, it remains an unequaled technology for under-
standing and communicating data.
Visualization offers significant financial advantages as well. In today’s competitive markets,
computer simulation teamed with visualization can reduce product cost and improve time to mar-
ket. A large cost of product design has been the expense and time required to create and test design
prototypes. Current design methods strive to eliminate these physical prototypes, and replace them
with digital equivalents. This digital prototyping requires the ability to create and manipulate prod-
uct geometry, simulate the design under a variety of operating conditions, develop manufacturing
techniques, demonstrate product maintenance and service procedures, and even train operators on
the proper use of the product before it is built. Visualization plays a role in each case. Already CAD
systems are used routinely to model product geometry and design manufacturing procedures. Visu-
alization enables us to view the geometry, and see special characteristics such as surface curvature.
For instance, analysis techniques such as finite element, finite difference, and boundary element
techniques are used to simulate product performance; and visualization is used to view the results.
Recently, human ergonomics and anthropometry are being analyzed using computer techniques in
combination with visualization [MDHMS] . Three-dimensional graphics and visualization are being
used to create training sequences. Often these are incorporated into a hypertext document or World
Wide Web (WWW) pages. Another practical use of graphics and visualization has been in-flight
simulators. This has been shown to be a significant cost-savings as compared to flying real air-
planes and is an effective training method.
There is confusion surrounding the difference between imaging, computer graphics, and visualiza-
tion. We offer these definitions.
• Imaging , or image processing, is the study of 2D pictures, or images. This includes tech-
niques to transform (e.g., rotate, scale, shear), extract information from, analyze, and enhance
images.
1.3 Imaging, Computer Graphics, and Visualization 5
Data
Figure 1–1 The visualization process. Data from various sources is repeatedly transformed to
extract, derive, and enhance information. The resulting data is mapped to a graphics system for dis-
play.
• Computer graphics is the process of creating images using a computer. This includes both 2D
paint-and-draw techniques as well as more sophisticated 3D drawing (or rendering) tech-
niques.
• Visualization is the process of exploring, transforming, and viewing data as images (or other
sensory forms) to gain understanding and insight into the data.
Based on these definitions we see that there is overlap between these fields. The output of computer
graphics is an image, while the output of visualization is often produced using computer graphics.
Sometimes visualization data is in the form of an image, or we wish to visualize object geometry
using realistic rendering techniques from computer graphics.
Generally speaking we distinguish visualization from computer graphics and image process-
ing in three ways.
1. The dimensionality of data is three dimensions or greater. Many well-known methods are
available for data of two dimensions or less; visualization serves best when applied to data of
higher dimension.
2. Visualization concerns itself with data transformation. That is, information is repeatedly cre-
ated and modified to enhance the meaning of the data.
3. Visualization is naturally interactive, including the human directly in the process of creating,
transforming, and viewing data.
Another perspective is that visualization is an activity that encompasses the process of exploring
and understanding data. This includes both imaging and computer graphics as well as data process-
ing and filtering, user interface methodology, computational techniques, and software design.
Figure1–1 depicts this process.
As this figure illustrates we see that the visualization process focuses on data. In the first step
data is acquired from some source. Next, the data is transformed by various methods, and then
6 Introduction
mapped to a form appropriate for presentation to the user. Finally, the data is rendered or displayed,
completing the process. Often, the process repeats as the data is better understood or new models
are developed. Sometimes the results of the visualization can directly control the generation of the
data. This is often referred to as analysis steering . Analysis steering is an important goal of visual-
ization because it enhances the interactivity of the overall process.
The origin of visualization as a formal discipline dates to the 1987 NSF report Visualization in Sci-
entific Computing [McCormick87] . That report coined the term scientific visualization. Since then
the field has grown rapidly with major conferences, such as IEEE Visualization, becoming well
established. Many large computer graphics conferences, for example ACM SIGGRAPH, devote
large portions of their program to visualization technology.
Of course, data visualization technology had existed for many years before the 1987 report
referenced [Tufte83] . The first practitioners recognized the value of presenting data as images. Early
pictorial data representations were created during the eighteenth century with the arrival of statisti-
cal graphics. It was only with the arrival of the digital computer and the development of the field of
computer graphics, that visualization became a practicable discipline.
The future of data visualization and graphics appears to be explosive. Just a few decades ago,
the field of data visualization did not exist and computer graphics was viewed as an offshoot of the
more formal discipline of computer science. As techniques were created and computer power
increased, engineers, scientists, and other researchers began to use graphics to understand and com-
municate data. At the same time, user interface tools were being developed. These forces have now
converged to the point where we expect computers to adapt to humans rather than the other way
around. As such, computer graphics and data visualization serve as the window into the computer,
and more importantly, into the data that computers manipulate. Now, with the visualization win-
dow, we can extract information from data and analyze, understand, and manage more complex
systems than ever before.
Dr. Fred Brooks, Kenan Professor of Computer Science at the University of North Carolina at
Chapel Hill and recipient of the John von Neumann Medal of the IEEE, puts it another way. At the
award presentation at the ACM SIGGRAPH ’94, Dr. Brooks stated that computer graphics and
visualization offer “intelligence amplification” (IA) as compared to artificial intelligence (AI).
Besides the deeper philosophical issues surrounding this issue (e.g., human before computer), it is a
pragmatic observation. While the long-term goal of AI has been to develop computer systems that
could replace humans in certain applications, the lack of real progress in this area has lead some
researchers to view the role of computers as amplifiers and assistants to humans. In this view, com-
puter graphics and visualization play a significant role, since arguably the most effective human/
computer interface is visual. Recent gains in computer power and memory are only accelerating
this trend, since it is the interface between the human and the computer that often is the obstacle to
the effective application of the computer.
1.5 Purpose of This Book 7
to learn and readily adapted to different data sources. Students can incorporate this software into
their work to display and analyze their results.
if the theory sections were independent of software issues and terminology. Toward the end
of each chapter there are separate implementation or example sections that are implementa-
tion specific. Earlier sections are implementation free.
Documentation . This text contains documentation considered essential to understanding the
software architecture, including object diagrams and condensed object descriptions. More
extensive documentation of object methods and data members is embedded in the software
(in the .h header files) and on CD-ROM or on-line at http://www.vtk.org . In particular,
the Doxygen generated manual pages contain detailed descriptions of class relationships,
methods, and other attributes.
We use a number of conventions in this text. Imported computer code is denoted with a typewriter
font, as are external programs and computer files. To avoid conflict with other C++ class libraries,
all class names in VTK begin with the “ vtk” prefix. Methods are differentiated from variables with
the addition of the “ ()” postfix. (Other conventions are listed in VTK User’s Guide .)
All images in this text have been created using the Visualization Toolkit software and data
found on the included CD-ROM or from the Web site http://www.vtk.org . In addition, every
image has source code (sometimes in C++ and sometimes a Tcl script). We decided against using
images from other researchers because we wanted you to be able to practice visualization with
every example we present. Each computer generated image indicates the originating file. Files end-
ing in .cxx are C++ code, files ending in .tcl are Tcl scripts. Hopefully these examples can serve
as a starting point for you to create your own applications.
To find the example code you will want to search in one of three areas. The standard VTK
distribution includes an VTK/Examples directory where many well-documented examples are
found. The VTK testing directories VTK/*/Testing , for example, VTK/Graphics/Testing/
Tcl , contain some of the example code used in this text. These examples use the data found in the
VTKData distribution. Finally, a separate software distribution, the VTKTextbook distribution,
contains examples and data that do not exist in the standard VTK distribution. The VTK, VTKData,
and VTKTextbook distributions are found on the included CD-ROM and/or on the web site at
http://www.vtk.org .
This chapter discusses some of the problems with developing large and/or complex software sys-
tems and describes how object-oriented design addresses many of these problems. This chapter
defines the key terms used in object-oriented modelling and design and works through a real-world
example. The chapter concludes with a brief look at some object-oriented languages and some of
the issues associated with object-oriented visualization.
Computer graphics is the means by which our visualizations are created. This chapter covers the
fundamental concepts of computer graphics from an application viewpoint. Common graphical
10 Introduction
entities such as cameras, lights, and geometric primitives are described along with some of the
underlying physical equations that govern lighting and image generation. Issues related to currently
available graphics hardware are presented, as they affect how and what we choose to render. Meth-
ods for interacting with data are introduced.
This chapter explains our methodology for transforming raw data into a meaningful representation
that can than be rendered by the graphics system. We introduce the notion of a visualization pipe-
line, which is similar to a data flow diagram from software engineering. The differences between
process objects and data objects are covered, as well as how we resolved issues between perfor-
mance and memory usage. We explain the advantages to a pipeline network topology regarding
execution ordering, result caching, and reference counting.
There are many types of data produced by the variety of fields that apply visualization. This chapter
describes the data objects that we use to represent and access such data. A flexible design is intro-
duced where the programmer can interact with most any type of data using one consistent interface.
The three high level components of data (structure, cells, and data attributes) are introduced, and
their specific subclasses and components are discussed.
Where the preceding chapter deals with data objects, this one introduces process objects. These
objects encompass the algorithms that transform and manipulate data. This chapter looks at com-
monly used techniques for isocontour extraction, scalar generation, color mapping, and vector field
display, among others. The emphasis of this chapter is to provide the reader with a basic under-
standing of the more common and important visualization algorithms.
This chapter covers advanced topics in computer graphics. The chapter begins by introducing trans-
parency and texture mapping, two topics important to the main thrust of the chapter: volume ren-
dering. Volume rendering is a powerful technique to see inside of 3D objects, and is used to
visualize volumetric data. We conclude the chapter with other advanced topics such as stereoscopic
rendering, special camera effects, and 3D widgets.
Part of the function of a data object is to store the data. The first chapter on data representation dis-
cusses this aspect of data objects. This chapter focuses on basic geometric and topological access
methods, and computational operations implemented by the various data objects. The chapter cov-
ers such methods as coordinate transformations for data sets, interpolation functions, derivative cal-
1.11 Legal Considerations 11
culations, topological adjacency operations, and geometric operations such as line intersection and
searching.
This chapter is a continuation of Fundamental Algorithms and covers algorithms that are either
more complex or less widely used. Scalar algorithms such as dividing cubes are covered along with
vector algorithms such as stream ribbons. A large collection of modelling algorithms is discussed,
including triangle strip generation, polygon decimation, feature extraction, and implicit modelling.
We conclude with a look at some visualization algorithms that utilize texture mapping.
While 3D graphics and visualization is the focus of the book, image processing is an important tool
for pre-processing and manipulating data. In this chapter we focus on several important image pro-
cessing algorithms, as well as describe how we use a streaming data representation to process large
datasets.
The Web is one of the best places to share your visualizations. In this chapter we show you how to
write Java-based visualization applications, and how to create VRML (Virtual Reality Modelling
Language) data files for inclusion in your own Web content.
Chapter 12 : Applications
In this chapter we tie the previous chapters together by working through a series of case studies
from a variety of application areas. For each case, we briefly describe the application and what
information we expect to obtain through the use of visualization. Then, we walk through the design
and resulting source code to demonstrate the use of the tools described earlier in the text.
Several registered trademarks are used in this text. UNIX is a trademark of UNIX System
Laboratories. Sun Workstation and XGL are trademarks of Sun Microsystems, Inc. Microsoft, MS,
MS-DOS, and Windows are trademarks of Microsoft Corporation. The X Window System is a
trademark of the Massachusetts Institute of Technology. Starbase and HP are trademarks of
Hewlett-Packard Inc. Silicon Graphics and OpenGL, are trademarks of Silicon Graphics, Inc. Mac-
intosh is a trademark of Apple Computer. RenderMan is a trademark of Pixar.
1.13 References
[Brodlie92]
K. W. Brodlie et al. Scientific Visualization Techniques and Applications . Springer-Verlag, Berlin,
1992.
[BurgerGillies89]
P. Burger and D. Gillies. Interactive Computer Graphics Functional, Procedural and Device-Lev-
el Methods . Addison-Wesley Publishing Company, Reading, MA, 1989.
[Chen93]
P. C. Chen. “A Climate Simulation Case Study.” In Proceedings of Visualization ’93 . pp. 397–401,
IEEE Computer Society Press, Los Alamitos, CA, 1993.
[FoleyVanDam90]
J. D. Foley, A. van Dam, S. K. Feiner, and J. F. Hughes. Computer Graphics Principles and Prac-
tice (2d Ed) . Addison-Wesley, Reading, MA, 1990.
1.13 References 13
[Gallagher95]
R. S. Gallagher (ed). Computer Visualization Graphics Techniques for Scientific and Engineering
Analysis. CRC Press, Boca Raton, FL, 1995.
[Krestel90]
E. Krestel (ed). Imaging Systems for Medical Diagnostics . Siemens-Aktienges, Munich, 1990.
[InfoVis95]
The First Information Visualization Symposium . IEEE Computer Society Press, Los Alamitos,
CA, 1995.
[McCormick87]
B. H. McCormick, T. A. DeFanti, and M. D. Brown. “Visualization in Scientific Computing.” Re-
port of the NSF Advisory Panel on Graphics, Image Processing and Workstations , 1987.
[MDHMS]
McDonnell Douglas Human Modeling System Reference Manual . Report MDC 93K0281. Mc-
Donnell Douglas Corporation, Human Factors Technology, Version 2.1, July 1993.
[Nielson90]
G. M. Nielson and B. Shriver (eds). Visualization in Scientific Computing . IEEE Computer Society
Press, Los Alamitos, CA, 1990.
[NYTimes]
The New York Times Business Day, Tuesday, May 2, 1995.
[Patrikalakis91]
N. M. Patrikalakis (ed). Scientific Visualization of Physical Phenomena. Springer-Verlag, Berlin,
1991.
[Pavlidis82]
T. Pavlidis. Graphics and Image Processing . Computer Science Press, Rockville, MD, 1982.
[Rosenblum94]
L. Rosenblum et al. Scientific Visualization Advances and Challenges. Harcourt Brace & Compa-
ny, London, 1994.
[SmithRanallo89]
H. J. Smith and F. N. Ranallo. A Non-Mathematical Approach to Basic MRI . Medical Physics Pub-
lishing Corporation, Madison, WI, 1989.
[Tufte83]
E. R. Tufte. The Visual Display of Quantitative Information. Graphics Press, Cheshire, CT, 1990.
[Tufte90]
E. R. Tufte. Envisioning Information. Graphics Press, Cheshire, CT, 1990.
[UsersGuide]
W. Schroeder, ed. The VTK User’s Guide . Kitware, Inc. http://www.kitware.com.
[Waters91]
K. Waters and D. Terzopoulos. “Modeling and Animating Faces Using Scanned Data.” Visualiza-
tion and Computer Animation . 2:123–128, 1991.
[Wolberg90]
G. Wolberg. Digital Image Warping . IEEE Computer Society Press, Los Alamitos, CA, 1990.
[Wolff93]
R. S. Wolff and L. Yaeger. Visualization of Natural Phenomena. TELOS, Springer-Verlag, Santa
Clara, CA, 1993.
14 Introduction
Chapter 2
Object-Oriented Design
2.1 Introduction
Today’s software systems try to solve complex, real-world problems. A rigorous software design
and implementation methodology can ease the burden of this complexity. Without such a method-
ology, software developers can find it difficult to meet a system’s specifications. Furthermore, as
specifications change and grow, a software system that does not have a solid, underlying architec-
ture and design will have difficulty adapting to these expanding requirements.
Our visualization system is a good example of complex software that needs to be designed
with extensibility in mind. Data visualization is a rapidly expanding field, with visualization tech-
niques being introduced each year. Any system that hopes to incorporate future innovations must
have an underlying design that supports the addition of new material without a significant impact
on the existing system.
Object-oriented design is a software engineering methodology that deals comfortably with
complexity and provides a framework for later changes and additions. The object-oriented design
process attempts to divide a complex task into small and simple pieces called objects. The objects
16 Object-Oriented Design
are computer abstractions that model physical or abstract pieces of the system being simulated.
Object-oriented design methodologies provide mechanisms to identify the abstractions that exist
within a system and to model the behavior of the objects.
may have the same manufacturer, model, options and colors, but remain two different cars. The real
world distinguishes the two cars by a vehicle identification number. Likewise, programming sys-
tems that deal with multiple entities need an identity mechanism. A pointer to allocated memory or
a variable name in a system-managed symbol table are often used to distinguish objects in a sys-
tem. In a database system, a set of identifier keys (called an n-tuple) identifies an entity in a system.
But, how do object-oriented systems differ from conventional, procedural programming sys-
tems? The major difference is in the way the two approaches treat data abstraction. Conventional
systems limit abstraction to data typing, while object-oriented systems create abstractions for both
the data and the operations that can be applied to the data. In fact, an object-oriented system keeps
the data and operations together in one programming construct called an object. Together, the data
and operations comprise an object’s properties . When an operation is applied to an object, the pro-
gramming language’s dynamic-binding mechanism executes the procedure that is appropriate for
that object. This is not the case in procedure-oriented systems. The programmer must supply logic
to decide which procedure to call. Systems that handle multiple types are often littered with case
statements to select the appropriate procedure for an operation. As new types are added to these
systems, the code that dispatches operations based on data type must be extended to handle the new
type. For example, in a program to display different types of primitives, the following pseudo code
shows how a procedure-oriented system differs from an object-oriented system.
Primitive *aPrim;
...
DrawPrimitive (aPrim)
...
procedure DrawPrimitive (aPrim)
{
if (aPrim->type == TRIANGLE) then DrawTriangle (aPrim)
else if (aPrim->type == SQUARE) then DrawSquare (aPrim)
else if (aPrim->type == CIRCLE) then DrawCircle (aPrim)
...
}
...
aPrim->Draw ();
...
Later in this project’s existence, someone may want to add a new primitive, let’s say a quadratic.
The person assigned with such a formidable task must search the existing system for all occur-
rences of the if statements in the first example and add a test for the new quadratic type. Of course,
a good programmer will have isolated the code in one location, as we have done here, so the task is
easier. Nevertheless, that programmer must first realize that the original programmer was skilled
enough to modularize the drawing code, then find the code (without necessarily knowing the proce-
dure name) and modify the code. To complicate matters, a system built by more than one program-
18 Object-Oriented Design
mer will undoubtedly be under a configuration management system, requiring a check-out, edit,
and check-in cycle.
The object-oriented programmer has an easier task. Consulting the design document that
defines the object properties for a primitive, this programmer adds a draw operation to the quadratic
object. The new primitive is available to the system without changing any existing code! Of course,
this is an oversimplified example. But think about past programs you have written and remember
how hard it was to add a new data type. Were your changes isolated to the new code you added?
Did you have to edit code that you did not write and maybe did not understand? Keep this example
in mind as you read our object-oriented implementation of a data visualization library.
Before describing object-oriented design and programming in more detail, we provide an
observation and prediction. Over the several years that we have designed and implemented soft-
ware using an object-oriented methodology, we have observed that newcomers to the technique
will say, “But this is how I already write programs. My systems are modular; they’re robust; I can
easily add to them.” If you still feel that way after reading this book, do not fault the object-oriented
approach. Rather, we have failed as authors. However, such a negative response is unlikely. In our
experience, users become comfortable with this approach in a short time. Especially when they are
introduced to objects through an existing, well-designed object-oriented system. You will reach the
“aha” stage, after which it will be difficult to begin a software project without looking for the
objects in the problem.
What Is an Object?
An object is an abstraction that models the state and behavior of entities in a system. Abstraction is
a mental process that extracts the essential aspects of a situation for a particular purpose. Entities
are things in the system that have identity. Chairs, airplanes, and cameras are objects that corre-
spond to physical entities in the real world. Binary trees, symbol tables, and ordered collections are
objects that exist only within the world of computer science.
Figure2–1 is an example of the abstraction that occurs when we map the state and behavior
of a system component to an object. Here, the object is a particular type of tree: a pin oak. In this
application we desire to simulate the growth of various types of trees over the course of a season.
For our purpose we have decided that the important state variables are the tree’s age, trunk diame-
ter, height, and habit (i.e., growing form). To capture the behavior of the pin oak we have methods
to simulate growth and seasonal effects corresponding to spring, summer, fall, and winter. There
are also methods (not shown) for setting and getting current state variables.
2.4 Object-Oriented Terminology 19
Age
Height Attributes or instance
abstraction
TrunkDiameter variables
Habit
Figure 2–1 Mapping a real-world object into an object abstraction. The real-world objects are vari-
ous types of trees. One of these objects (a pin oak tree) is mapped into the computer object we call
PinOak .
We call the state of an object its attributes (also called instance variables ) and define its
behavior by the operations that can be applied to it. Attributes have a name, a data type, and a data
value. The data type of an attribute may be a primitive type in the programming language (such as a
char or float in C++), or another object. For example, the vtkTransform object in our visualization
system has an attribute of type vtkMatrix4x4 , another object. vtkMatrix4x4 in turn has attributes
that are an array of primitive values declared as float values in C++.
Operations are functions or transformations that can be applied to an object. Operations
define the behavior of the object. The operations for a particular object are implemented in proce-
dures we call methods .
Together, the attributes and operations of an object comprise its properties . A two-dimen-
sional line graph could have attributes that include an x and y axis, a legend, and a connected set of
points. This graph has methods that draw the graph in a window. It also has methods that let a user
specify the axes, data to draw, and legend to use.
Objects that share the same properties can be grouped using the process of classification . An
object class, usually just called a class, specifies the properties that all objects in the class have. The
class only specifies the names of the properties, not their specific values. Different classes can (and
usually do) have properties with names that exist in other classes. Many classes in our visualization
system have an attribute named Position . Although both a camera and actor in our visualization
system have this attribute, the effect on each is different because they are different classes.
Attribute names are shared by all objects in a given class, but separate storage is allocated for each
object’s attribute values.
When an operation with the same name is applied to objects of different classes we call the
operation polymorphic . For example, our visualization system has an operation named Render()
that can be applied to many different objects. The implementation of an operation for a particular
class is called a method. The print operation for a vtkMatrix4x4 object is implemented in its print
method. That is, there exists code that knows how to print objects of class vtkMatrix4x4 and not
objects of other classes. Objects know which method to use because they are kept within each
object’s data structure. In most systems the code for the methods is shared by all objects in the same
class. Some programming languages, including C++, define a method by combining an operation
name with its argument types. This process is called overloading an operation and is a powerful
20 Object-Oriented Design
technique that permits the same name to be used for logically similar operations. For example, the
class definition below defines three methods for calculating the square of a number. Even though
these methods have the same operation name, they are unique because C++ uses both the operation
name and the operations argument types.
class math
{
float square(float x);
int square(int x);
double square(double x);
}
To use a member of a class for some purpose, we create an instance of the class (the process of
instantiation ). Instance creation establishes the identity of the instance including specifying its ini-
tial state. The instance’s class serves as a template for the instance during creation, defining the
names of each of its attributes and operations. Creation establishes the similarities and differences
between this instance and other instances of the same class. The similarities are the names and type
of its attributes and the methods that implement its operations. The differences are the specific val-
ues of the attributes. The details of how one creates an instance of a class vary from programming
language to programming language. In C++, a program creates an instance using a declarative form
such as
vtkActor aBall;
which creates an object from the program stack, or by applying the new operation
Inheritance
Inheritance is a programming mechanism that simplifies adding new classes to a system when they
differ in small ways from currently existing classes. The notion of inheritance is adopted from the
observation that most systems can be specified using a hierarchical classification system. A fine
example of a classification system is the phyla of life on earth.
Earlier we created an object corresponding to a pin oak tree. The properties of the tree can be
more thoroughly described using inheritance ( Figure2–2 ). The classification shown here is based
on the five kingdom system of Margulis and Schwartz [Margulis88] . In this system, biota is classi-
fied as belonging to one of the five kingdoms Prokaryotae (bacteria), Protoctista (algae, protozoans
and slime molds), Fungi (mushrooms, molds, lichens), Plantae (mosses, ferns, cone-bearing, and
flowering plants), and Animalia (animals with and without backbones). Below this level we have
the classifications division, class, order, family, genus, and species. The figure shows the kingdom,
division, class, genus, and species of the pin oak.
Organizing objects into an inheritance hierarchy provides many benefits. Properties of a gen-
eral classification are also properties of its subclassification. For example, we know that all species
of genus Quercus form acorns. From the software point of view this means any instance variables
2.4 Object-Oriented Terminology 21
Biota
Angiospermophyta division
Dicotyledoneae class
Quercus genus
Palustris species
and methods of a superclass are automatically inherited by its subclass . This allows us to make
changes to a number of objects simultaneously by modifying their superclass. Furthermore, if we
desire to add a new class (say a red oak tree) to the hierarchy we can do so without duplicating
existing functionality. We need only differentiate the new class from the others by adding new
instance variables or overloading existing methods.
The ability to quickly add new classes that are slightly different from currently existing
classes promotes the extensibility of a system. Inheritance can be derived top-down using a process
called specialization , or it can be created bottom-up, combining similar classes during a process
called generalization . The use of inheritance implies a class hierarchy with one or more classes
being the superclasses of one or more subclasses. A subclass inherits the operations and attributes
of its superclasses. In C++, subclasses are called derived classes and superclasses are called base
classes. A subclass can add additional operations and attributes that modify the properties it inher-
ited from its superclasses. Through this inheritance, an object can exhibit its superclass’s behavior
plus any additional behavior it wishes. It can also restrict, or override, operations implemented by
its superclass.
Classes that exist only to act as superclasses for their subclasses are called abstract classes.
Instance creation of an abstract class is generally prohibited. Abstract classes are useful for gather-
ing attributes and methods that all subclasses will use. They can also define protocols for behavior
for their subclasses. This is a powerful use of inheritance that will show up in the design of our
visualization system. Abstract classes can enforce complex sequence, control protocols, and ensure
uniform behavior. They remove the responsibility of complex protocols from the individual sub-
classes and isolate the protocol in the superclass.
An example of a simple plotting package illustrates the power of abstract classes. Consider a
data presentation application that allows for a variety of two-dimensional plotting. This application
must support line charts and horizontal and vertical bar charts. The design process identifies prop-
22 Object-Oriented Design
erties common to all plots including title, axes, and legend. We then create an abstract class called
TwoDPlot to contain these common attributes. Common behavior can also be captured in
TwoDPlot within its plot method:
Method Plot
{
Draw the border
Scale the data
Draw the axes
Draw the data
Draw the title
Draw the legend
}
An abstract class may or may not provide default behavior for each operation. In this example,
default behavior for border and title drawing might be provided. Then subclasses of TwoDPlot
would define their own functions for the other methods. The protocol specification explicitly spells
out what methods a subclass of TwoDPlot should respond to. In the above example, subclasses will
need to define their own methods for drawing the axis, data, and legend. Some subclasses might
use TwoDPlot ’s methods for drawing the border, others might require their own version of this
method. The abstract interface defined in TwoDPlot makes it easier to add new classes of 2D plots
and the resulting subclasses tend to be more uniform and consistent.
Another mechanism, delegation , is useful for isolating and reusing behavior. Using delega-
tion, an object applies operations to one of its attributes that is an object. As an example, in the
Visualization Toolkit the vtkTransform object delegates its Identity() operation to its vtkMatrix4x4
attribute. This instance of vtkMatrix4x4 then performs the operation. There are many more useful
object-oriented concepts, but for the time being we have enough information to describe how we
can use objects to design a system.
tem will have a table, X-ray source, detectors, and gantry. Our visualization system will have mod-
els, isosurfaces, streamlines, and cut planes. During this modelling step, we search the problem
domain for objects, properties, and relationships. Later, during multiple passes through the design,
the model will be expanded.
Modelling is a step in most design processes regardless of whether we are designing a ship,
house, electronics system, or software. Each discipline follows a methodology that uses techniques
specifically created to make the design process efficient and worthwhile. These techniques are so-
called “tools of the trade.” An electrical engineer uses schematics and logic diagrams, an architect
uses drawings and mock-ups, and a ship builder uses scale models. Likewise, software designers
need tools that can help create a model of the system. The software tools should have enough
expressive power to help the software designer evaluate a design against a specification and help
communicate that design to others on the software team.
We use the Object Modeling Technique (OMT) developed at GE by Jim Rumbaugh and his
colleagues [Rumbaugh91] . OMT uses three models to specify an object-oriented design: an object
model, a dynamic model, and a functional model. Each model describes a different aspect of the
system and each has a corresponding diagramming technique that helps us analyze, design, and
implement software systems.
The object model identifies each object in the system, its properties, and its relationships to other
objects in the system. For most software systems, the object model dominates the design. The OMT
graphical technique uses rectangles to depict object classes, and a variety of connectors to depict
inheritance and other object-object relations. Object classes are represented as solid rectangles.
Instances are represented as dotted rectangles. The name of the class or instance occupies the top of
the rectangle. A line separates the class name from the next section that contains the attributes; a
third section describes the methods. Relationships between objects are shown with line segments
connecting the two related objects. In OMT, relationships are called associations and they can have
various cardinalities: one-to-one, one-to-many, and many-to-many. Special associations that repre-
sent containers of other objects are called aggregations. Associations can be labeled with roles.
(Roles are names given to associations and are used to further describe the nature of the associa-
tion.) OMT represents inheritance with a triangle, with the superclass attached to the apex, and sub-
classes attached to the base of the triangle. Figure2–3 shows an object model for locator devices in
a virtual reality system .
The first object in the class hierarchy is locator . This abstract class specifies common
attributes and methods for all locators. The subclasses of locator are locator2D and locator3D . In
the current rendition of this object model, the locator only has one attribute, a device and two meth-
ods, open() and close(). The two subclasses of locator , locator2D and locator3D are also abstract
classes, containing attributes and methods that distinguish them from each other based on their spa-
tial dimensionality. For example, locator3D has an x, y, z position while locator2D has an x, y posi-
tion. Both locators have a locate() method that updates the current position. In the 3D locator class,
locate() also updates the orientation. The subclasses of locator3D include hardware from three dif-
ferent manufacturers: flock, pixsys, and logitek , as well as an articulated positioner abstract class.
The three object classes for the hardware contain methods specific to each device. Each method
knows how to convert the hardware specific codes returned by the device. They know that to be
24 Object-Oriented Design
locator
device
open
close
locator2D
position (x,y)
locator3D locate
position (x,y,z)
orientation
front
up touch screen mouse
angles
linkages position position position
orientation orientation orientation
immersion phantom
Figure 2–3 Object model for locator devices.
position position
orientation orientation
considered a locator3D subclass, they must implement a position and orientation operation that will
provide x, y, z coordinates and three angular rotations that can be composed into a transformation
matrix. The object model also shows us that the articulated locator has angles and linkages . Two
specific articulated locators are immersion and phantom . An object model diagrammed in this fash-
ion serves as a starting point for design and discussion. It reveals common methods and attributes
as well as the distinguishing characteristics of each class.
Later, during implementation, we will convert these object models into software objects. The
particular computer language we choose for implementation will dictate the details of the conver-
sion.
2.5 Object-Oriented Modelling and Design 25
The object model describes the static portion of a system while the dynamic model details the
sequences of events and time dependencies of the system. OMT uses state diagrams to model sys-
tem dynamics. Dynamic models are frequently used to design control systems and user interfaces.
Our visualization system has limited sequence and control aspects, so we will not dwell on state
diagrams. But, if we were designing a user-friendly interface for a digital wristwatch, the state dia-
gram in Figure2–4 would be useful.
Changing Sec- b3
onds
b2
b2
Start
b3 b1
Changing Min- b3
utes
Displaying Time b1
b1 b2
b2 Changing Hours b3
b1 b2,b3
Displaying Date
Changing Sec- b3
b1
onds
b2 b2
b1
b1
Changing Min- b3
utes
Displaying Alarm b1
b1 b2
b2 Changing Hours b3
b3 b3
Toggle Alarm
The ovals in the diagram show a state; the arrows show a transition from one state to another;
and the labels on the arrows show an event that causes the state transition. This example shows
three display states and multiple setting states. The event b1 means button one is pressed. This
watch has three buttons. The diagram shows what happens in each state when any of the three but-
tons is pressed. The diagram clearly shows that b1 is used to move between display modes for time,
date, and alarm. B2 changes from display mode into setting mode or selects the field to change in a
given mode. B3 increments the selected field by one unit. The state diagram also shows what hap-
pens when illegal buttons are pressed. If the watch is displaying time and button 3 is pressed, noth-
ing happens. If button 3 is pressed when the watch is displaying the alarm, the alarm on/off is
toggled.
The functional model shows how data flows through the system and how processes and algorithms
transform the data. It also shows functional dependencies between processes. Exposing these rela-
tionships will affect the associations in the object model. The major components of a data flow dia-
gram (DFD) are data sources, data sinks, and processes. Data sources and sinks are represented as
rectangles. Ellipses show processes. Data stores are shown within two horizontal lines. DFDs are
useful to describe the overall flow in the system. They can also be used to describe any process that
transforms one data representation into another. Processes identified in the DFD during function
modelling may turn up as operations or objects in the object model.
Figure2–5 shows a data flow diagram for a 3D medical imaging system. The diagram shows
the data acquisition on the computed tomography (CT) or magnetic resonance imaging (MRI) scan-
ner. The series of cross-sectional slices provided by the scanner is first processed by image process-
ing filters to enhance features in the gray scale slices. A segment process identifies tissues and
produces labels for the various tissues present in the slices. These labeled slices are then passed
through a surface extraction process to create triangles that lie on the surface of each tissue. The
render process transforms the geometry into an image. Alternatively, the write process stores the
triangles in a file. Later, the triangles can be read and rendered into an image. We defer the decision
whether to make the processes objects or operations until later. Chapter 4 uses DFDs to model the
visualization pipeline.
s
dS li ce
el le
La b
Triangles
T ri
Read
ang
Tr
le s
ian
g le
s
Triangles Triangle
Write File
talk provided not just a language, but also an operating system and programming environment built
with objects. When you use Smalltalk, you live and breathe objects. For the object-oriented purist,
there is no substitute. Smalltalk spin-offs include window systems, workstations, and the desktop
paradigm. Both Apple Computer and Microsoft acknowledge the influence that Smalltalk and
Xerox PARC had on the Macintosh and Windows. Smalltalk was probably conceived 10 years too
early for widespread commercial acceptance. During Smalltalk’s infancy and adolescence, the
complexity of software was much lower than today’s systems. FORTRAN served the scientific and
engineering community, COBOL was the choice for business applications and the computer sci-
ence community embraced C. The use of abstractions was limited to mathematicians and other
abstract thinkers. Programming was considered an art form and programmers concentrated on
clever implementations of algorithms. Each new task often required a new program. Technical pro-
grammers did use numerical libraries for common mathematical operations, but any notions of
common abstractions at a higher level were relatively few.
Don’t underestimate the investment required to design a system. Although object-oriented technol-
ogies have tremendous potential to produce good software designs, these techniques do not guaran-
28 Object-Oriented Design
tee a good design. The visualization system we present in this text has its roots in an animation
[Lorensen89] and visualization system [Schroeder92] that we developed over a 10-year period. The
initial design, which identified 25 classes for computer animation of industrial applications, took
four software professionals 10 months (almost 3.5 person years) to complete. During this design
stage the developers produced zero (!) lines of code. The subsequent implementation took one
month, or ten percent of the effort. This system still serves our visualization group even after 20
other software developers have added over 500 classes to the system. The original 25 classes still
exist in the system today.
As a reader, we hope that you can benefit from our experience in visualization system design.
We have tried to assist you by describing the properties (attributes and methods) of many of the
Visualization Toolkit classes in each chapter’s “Putting It All Together ” section. There are also
included a series of object diagrams generated by the Doxygen documentation system that will give
you a quick overview of object relationships such as superclass and subclass. This documentation
can be found on the CD-ROM or on-line at http://www.vtk.org. In the next chapter we will
also explain the decisions we made to design the VTK object-oriented toolkit.
Parc. In another early object-oriented programming book, [Cox86] describes OO techniques and the
programming language Objective-C. Objective-C is a mix of C and Smalltalk and was used by
Next Computer in the implementation of their operating system and user interface.
There are many texts on object-oriented languages. CLOS [Keene89] describes the Common
List Object System. Eiffel, a strongly typed OO language is described by [Meyer88] . Objective-C
[Cox86] is a weakly typed language.
Since C++ has become a popular programming language, there now many class libraries
available for use in applications. [Gorlen90] describes an extensive class library for collections and
arrays modeled after the Smalltalk classes described in [Goldberg83] . [Stepanov94] and [Musser94]
describe the Standard Template Library, a framework of data structures and algorithms that is now
a part of the ANSI C++ standard. Open Inventor [Inventor] is a C++ library supporting interactive
3D computer graphics. The Insight Segmentation and Registration Toolkit (ITK) is a relatively new
class library often used in combination with VTK [ITK] for medical data processing. VXL is a C++
library for computer vision research and implementation [VXL] . Several mathematical libraries such
as VNL (a part of VXL) and Blitz++ [Blitz] are also available. A wide variety of other C++ toolkits
are available, Google searches [Google] are the best way to find them.
C++ texts abound. The original description by the author of C++ [Stroustrup84] is a must for
any serious C++ programmer. Another book [Ellis90] describes standard extensions to the language.
These days the UML book series—of which [Booch98] and [Rumbaugh98] are quite popular—are
highly recommended resources. Several books on generic programming [Austern99] and STL
[Musser96] are also useful. Check with your colleagues for their favorite C++ book.
To keep in touch with new developments there are conferences, journals, and Web sites. The
strongest technical conference on object-oriented topics is the annual Object-Oriented Program-
ming Systems, Languages, and Applications ( OOPSLA ) conference. This is where researchers in
the field describe, teach and debate the latest techniques in object-oriented technology. The
bimonthly Journal of Object-Oriented Programming (JOOP) published by SIGS Publications, NY,
presents technical papers, columns, and tutorials on the field. Resources on the World Wide Web
include the Usenet newsgroups comp.object and comp.lang.c++ .
2.10 References
[Austern99]
M. H. Austern. Generic Programming and the STL . Addison-Wesley 1999.
ISBN 0-2-1-30956-4.
[Birtwistle79]
G. M. Birtwistle, O. Dahl, B. Myhrhaug, and K. Nygaard. Simula Begin . Chartwell-Bratt Ltd, En-
gland, 1979.
[Blitz]
http://www.oonumerics.org/blitz/.
[Booch91]
G. Booch. Object-Oriented Design with Applications. Benjamin/Cummings Publishing Co., Red-
wood City, CA, 1991.
[Booch98]
G. Booch, I. Jacobson, J. Rumbaugh. The Unified Modeling Language User Guide . Addison-Wes-
ley 1998, ISBN 0201571684.
30 Object-Oriented Design
[Cox86]
B. J. Cox. Object-Oriented Programming: An Evolutionary Approach. Addison-Wesley, Reading,
MA, 1986.
[Ellis90]
M. Ellis and B. Stroustrup. The Annotated C++ Reference Manual . Addison-Wesley, Reading,
MA, 1990.
[Goldberg83]
A. Goldberg, D. Robson. Smalltalk-80: The Language and Its Implementation . Addison-Wesley,
Reading, MA, 1983.
[Goldberg84]
A. Goldberg. Smalltalk-80: The Interactive Programming Environment . Addison-Wesley, Read-
ing, MA, 1984.
[Google]
http://www.google.com .
[Gorlen90]
K. Gorlen, S. Orlow, and P. Plexico. Data Abstraction and Object-Oriented Programming . John
Wiley & Sons, Ltd., Chichester, England, 1990.
[Inventor]
http://oss.sgi.com/projects/inventor/ .
[ITK]
The Insight Software Consortium. http://www.itk.org.
[Keene89]
S. Keene. Object-Oriented Programming in Common Lisp: A Programmer’s Guide to CLOS . Ad-
dison-Wesley, Reading, MA, 1989.
[Lorensen89]
W. E. Lorensen, B. Yamrom. “Object-Oriented Computer Animation.” Proceedings of IEEE NAE-
CON, 2:588-595, Dayton, Ohio, May 1989.
[Margulis88]
L. Margulis and K. V. Schwartz. Five Kingdoms an Illustrated Guide to the Phyla of Life on Earth .
W. H. Freeman & Co., New York, 1988.
[Meyer88]
B. Meyer. Object-Oriented Software Construction . Prentice Hall International, Hertfordshire, En-
gland, 1988.
[Musser94]
D. Musser and A. Stepanov. “Algorithm-Oriented Generic Libraries.” Software Practice and Ex-
perience . 24(7):623–642, July 1994.
[Musser96]
D. R. Musser and A. Saini. STL Tutorial and Reference Guide . Addison-Wesley 1996.
ISBN 0-201-63398-1.
[Rumbaugh91]
J. Rumbaugh, M. Blaha, W. Premerlani, F. Eddy, and W. Lorensen. Object-Oriented Modeling and
Design . Prentice Hall, Englewood Cliffs, NJ, 1991.
[Rumbaugh98]
J. Rumbaugh, G. Booch, and I. Jacobson. The Unified Modeling Language Reference Manual . Ad-
dison-Wesley 1998, ISBN: 020130998X.
2.11 Exercises 31
[Schroeder92]
W. J. Schroeder, W. E. Lorensen, G. Montanaro, and C. Volpe. “Visage: An Object-Oriented Sci-
entific Visualization System.” In Proceedings of Visualization ’92. pp. 219–226, IEEE Computer
Society Press, Los Alamitos, CA, October 1992.
[Stepanov94]
A. Stepanov and M. Lee. The Standard Template Library . ISO Programming Language C++
Project. Doc. No. X3J16/94-0095, WG21/N0482, May 1994.
[Stroustrup84]
B. Stroustrup. The C++ Programming Language . Addison-Wesley, Reading, MA, 1986.
[VXL]
http://vxl.sourceforge.net/.
2.11 Exercises
2.1 Answer the following questions about a program you have written.
a) How much time did you spend on design and implementation?
b) What methodology, if any, did you use?
c) Could you easily extend the system?
d) Could anyone extend the system?
2.2 Identify the major objects and operations for the following applications.
a) An airline reservation system.
b) An adventure game.
c) A 2D plotting package.
d) An automatic teller machine.
2.3 Draw an object diagram for each example in Exercise 2.2.
2.4 Computer animation uses concepts from graphics and movie making. Identify the major
objects and operations in a computer animation system.
2.5 For the animation system in Exercise 2.4, design control and looping objects that will allow
flexible control of the properties of the actors in the system. If we call these control and loop-
ing objects scenes and cues, how would you expect them to look?
2.6 Draw a state diagram for your wristwatch using Figure 2–4 as an example.
2.7 Draw a data flow diagram for calculating the surface area and volume of a sphere and cylin-
der.
32 Object-Oriented Design
Chapter 3
3.1 Introduction
Computer graphics is the process of generating images using computers. We call this process ren-
dering. There are many types of rendering processes, ranging from 2D paint programs to sophisti-
cated 3D techniques. In this chapter we focus on basic 3D techniques for visualization.
We can view rendering as the process of converting graphical data into an image. In data
visualization our goal is to transform data into graphical data, or graphics primitives , that are then
rendered. The goal of our rendering is not so much photo realism as it is information content. We
also strive for interactive graphical displays with which it is possible to directly manipulate the
underlying data. This chapter explains the process of rendering an image from graphical data. We
begin by looking at the way lights, cameras, and objects (or actors) interact in the world around us.
From this foundation we explain how to simulate this process on a computer.
34 Computer Graphics Primer
Figure3–1 presents a simplified view of what happens when we look at an object, in this case a
cube. Rays of light are emitted from a light source in all directions. (In this example we assume that
the light source is the sun.) Some of these rays happen to strike the cube whose surface absorbs
some of the incident light and reflects the rest of it. Some of this reflected light may head towards
us and enter our eyes. If this happens, then we “see” the object. Likewise, some of the light from
the sun will strike the ground and some small percentage of it will be reflected into our eyes.
As you can imagine, the chances of a ray of light traveling from the sun through space to hit a
small object on a relatively small planet are low. This is compounded by the slim odds that the ray
of light will reflect off the object and into our eyes. The only reason we can see is that the sun pro-
duces such an enormous amount of light that it overwhelms the odds. While this may work in real
life, trying to simulate it with a computer can be difficult. Fortunately, there are other ways to look
at this problem.
A common and effective technique for 3D computer graphics is called ray-tracing or ray-
casting . Ray-tracing simulates the interaction of light with objects by following the path of each
light ray. Typically, we follow the ray backwards from the viewer’s eyes and into the world to
determine what the ray strikes. The direction of the ray is in the direction we are looking (i.e., the
view direction) including effects of perspective (if desired). When a ray intersects an object, we can
determine if that point is being lit by our light source. This is done by tracing a ray from the point of
intersection towards the light. If the ray intersects the light, then the point is being lit. If the ray
intersects something else before it gets to the light, then that light will not contribute to illuminating
the point. For multiple light sources we just repeat this process for each light source. The total con-
tributions from all the light sources, plus any ambient scattered light, will determine the total light-
ing or shadow for that point. By following the light’s path backwards, ray tracing only looks at rays
that end up entering the viewer’s eyes. This dramatically reduces the number of rays that must be
computed by a simulation program.
3.1 Introduction 35
Having described ray tracing as a rendering process, it may be surprising that many members
of the graphics community do not use it. This is because ray tracing is a relatively slow image gen-
eration method since it is typically implemented in software. Other graphics techniques have been
developed that generate images using dedicated computer hardware. To understand why this situa-
tion has emerged, it is instructive to briefly examine the taxonomy and history of computer graph-
ics.
Rendering processes can be broken into two categories: image-order and object-order . Ray tracing
is an image-order process. It works by determining what happens to each ray of light, one at a time.
An object-order process works by rendering each object, one at a time. In the above example, an
object-order technique would proceed by first rendering the ground and then the cube.
To look at it another way consider painting a picture of a barn. Using an image-order algo-
rithm you would start at the upper left corner of the canvas and put down a drop of the correct color
paint. (Each paint drop is called a picture element or pixel.) Then you would move a little to the
right and put down another drop of paint. You would continue until you reached the right edge of
the canvas, then you would move down a little and start on the next row. Each time you put down a
drop of paint you make certain it is the correct color for each pixel on the canvas. When you are
done you will have a painting of a barn.
An alternative approach is based on the more natural (at least for many people) object-order
process. We work by painting the different objects in our scene, independent of where the objects
actually are located on the scene. We may paint from back to front, front-to-back, or in arbitrary
order. For example, we could start by painting the sky and then add in the ground. After these two
objects were painted we would then add in the barn. In the image-order process we worked on the
canvas in a very orderly fashion; left to right, top to bottom. With an object-order process we tend
to jump from one part of the canvas to another, depending on what object we are drawing.
The field of computer graphics started out using object-order processes. Much of the early
work was closely tied to the hardware display device, initially a vector display. This was little more
than an oscilloscope, but it encouraged graphical data to be drawn as a series of line segments. As
the original vector displays gave way to the currently ubiquitous raster displays, the notion of repre-
senting graphical data as a series of objects to be drawn was preserved. Much of the early work pio-
neered by Bresenham [Bresenham65] at IBM focused on how to properly convert line segments
into a form that would be suitable for line plotters. The same work was applied to the task of ren-
dering lines onto the raster displays that replaced the oscilloscope. Since then the hardware has
become more powerful and capable of displaying much more complex primitives than lines.
It wasn’t until the early 1980s that a paper by Turner Whitted [Whitted80] prompted many
people to look at rendering from a more physical perspective. Eventually ray tracing became a seri-
ous competitor to the traditional object-order rendering techniques, due in part to the highly realis-
tic images it can produce. Object-order rendering has maintained its popularity because there is a
wealth of graphics hardware designed to quickly render objects. Ray tracing tends to be done with-
out any specialized hardware and therefore is a time-consuming process.
36 Computer Graphics Primer
The discussion to this point in the text has tacitly assumed that when we render an object, we are
viewing the surfaces of objects and their interactions with light. However, common objects such as
clouds, water, and fog, are translucent, or scatter light that passes through them. Such objects can-
not be rendered using a model based exclusively on surface interactions. Instead, we need to con-
sider the changing properties inside the object to properly render them. We refer to these two
rendering models as surface rendering (i.e., render the surfaces of an object) and volume rendering
(i.e., render the surface and interior of an object).
Generally speaking, when we render an object using surface rendering techniques, we mathe-
matically model the object with a surface description such as points, lines, triangles, polygons, or
2D and 3D splines. The interior of the object is not described, or only implicitly represented from
the surface representation (i.e., surface is the boundary of the volume). Although techniques do
exist that allow us to make the surface transparent or translucent, there are still many phenomena
that cannot be simulated using surface rendering techniques alone (e.g., scattering or light emis-
sion). This is particularly true if we are trying to render data interior to an object, such as X-ray
intensity from a CT scan.
Volume rendering techniques allow us to see the inhomogeneity inside objects. In the prior
CT example, we can realistically reproduce X-ray images by considering the intensity values from
both the surface and interior of the data. Although it is premature to describe this process at this
point in the text, you can imagine extending our ray tracing example from the previous section.
Thus rays not only interact with the surface of an object, they also interact with the interior.
In this chapter we focus on surface rendering techniques. While not as powerful as volume
rendering, surface rendering is widely used because it is relatively fast compared to volumetric
techniques, and allows us to create images for a wide variety of data and objects. Chapter 7
describes volume rendering in more detail.
Although the authors would enjoy providing a thorough treatise on computer graphics, such a dis-
course is beyond the scope of this text. Instead we make the distinction between visualization
(exploring, transforming, and mapping data) and computer graphics (mapping and rendering). The
focus will be on the principles and practice of visualization, and not on 3D computer graphics. In
this chapter and Chapter 7 we introduce basic concepts and provide a working knowledge of 3D
computer graphics. For those more interested in this field, we refer you to the texts recommended
in the “Bibliographic Notes ” on page77 at the end of this chapter.
One of the regrets we have regarding this posture is that certain rendering techniques are
essentially visualization techniques. We see this hinted at in the previous paragraph, where we use
the term “mapping” to describe both visualization and computer graphics. There is not currently
and will likely never be a firm distinction between visualization and graphics. For example, many
researchers consider volume rendering to be squarely in the field of visualization because it
addresses one of the most important forms of visualization data. Our distinction is mostly for our
own convenience, and offers us the opportunity to finish this text. We recommend that a serious
student of visualization supplement the material presented here with deeper books on computer
graphics and volume rendering.
3.2 Color 37
3.2 Color
The electromagnetic spectrum visible to humans contains wavelengths ranging from about 400 to
700 nanometers. The light that enters our eyes consists of different intensities of these wavelengths,
an example of which is shown in Figure3–2 . This intensity plot defines the color of the light,
therefore a different plot results in a different color. Unfortunately, we may not notice the difference
since the human eye throws out most of this information. There are three types of color receptors in
the human eye called cones. Each type responds to a subset of the 400 to 700 nanometer wave-
length range as shown in Figure3–3 . Any color we see is encoded by our eyes into these three
overlapping responses. This is a great reduction from the amount of information that actually
comes into our eyes. As a result, the human eye is incapable of recognizing differences in any col-
ors whose intensity curves, when applied to the human eye’s response curves, result in the same
triplet of responses. This also implies that we can store and represent colors in a computer using a
simplified form without the human eye being able to recognize the difference.
The two simplified component systems that we use to describe colors are RGB and HSV
color systems. The RGB system represents colors based on their red, green, and blue intensities.
This can be thought of as a three dimensional space with the axes being red, green, and blue. Some
common colors and their RGB components are shown in Figure3–4 .
The HSV system represents colors based on their hue, saturation, and value. The value com-
ponent is also known as the brightness or intensity component, and represents how much light is in
the color. A value of 0.0 will always give you black and a value of 1.0 will give you something
bright. The hue represents the dominant wavelength of the color and is often illustrated using a cir-
cle as in Figure3–5 . Each location on the circumference of this circle represents a different hue and
38 Computer Graphics Primer
Blue Cone
Red Cone
0.0
400 nm 500 nm 600 nm
Wavelength
Figure 3–3 Relative absorbance of light by the three types of cones in the human
retina [Dartnall83].
can be specified using an angle. When we specify a hue we use the range from zero to one, where
zero corresponds to zero degrees on the hue circle and one corresponds to 360 degrees. The satura-
tion indicates how much of the hue is mixed into the color. For example, we can set the value to
one, which gives us a bright color, and the hue to 0.66, to give us a dominant wavelength of blue.
Now if we set the saturation to one, the color will be a bright primary blue. If we set the saturation
to 0.5, the color will be sky blue, a blue with more white mixed in. If we set the saturation to zero,
this indicates that there is no more of the dominant wavelength (hue) in the color than any other
wavelength. As a result, the final color will be white (regardless of hue value). Figure3–4 lists
HSV values for some common colors.
Green 120
o Yellow 60
o
Cyan 180
o Red 0
o
Blue 240
o Magenta 300
o
Figure 3–5 On the top, circular representation of hue. The other two
images on the bottom are slices through the HSV color space. The first slice
has a value of 1.0, the other has a value of 0.5.
3.3 Lights
One of the major factors controlling the rendering process is the interaction of light with the actors
in the scene. If there are no lights, the resulting image will be black and rather uninformative. To a
great extent it is the interaction between the emitted light and the surface (and in some cases the
interior) of the actors in the scene that defines what we see. Once rays of light interact with the
actors in a scene, we have something for our camera to view.
Of the many different types of lights used in computer graphics, we will discuss the simplest,
the infinitely distant, point light source. This is a simplified model compared to the lights we use at
home and work. The light sources that we are accustomed to typically radiate from a region in
space (a filament in an incandescent bulb, or a light-emitting gas in a fluorescent light). The point
source lighting model assumes that the light is emitted in all directions from a single point in space.
For an infinite light source, we assume that it is positioned infinitely far away from what it is illu-
minating. This is significant because it implies that the incoming rays from such a source will be
parallel to each other. The emissions of a local light source, such as a lamp in a room, are not paral-
lel. Figure3–6 illustrates the differences between a local light source with a finite volume, versus
40 Computer Graphics Primer
Local Infinite
Figure 3–6 Local light source with a finite volume versus an infinite point
light source.
an infinite point light source. The intensity of the light emitted by our infinite light sources also
remains constant as it travels, in contrast to the actual 1/distance 2 relationship physical lights obey.
As you can see this is a great simplification, which later will allow us to use less complex lighting
equations.
R a = Lc × O a (3-1)
where R a is the resulting intensity curve due to ambient lighting, L c is the intensity curve of the
ambient light, and Oa is the color curve of the object. To help keep the equations simple we assume
that all of the direction vectors are normalized (i.e., have a magnitude of one).
Two components of the resulting color depend on direct lighting. Diffuse lighting , which is
also known as Lambertian reflection, takes into account the angle of incidence of the light onto an
object. Figure3–7 shows the image of a cylinder that becomes darker as you move laterally from
its center. The cylinder’s color is constant; the amount of light hitting the surface of the cylinder
changes. At the center, where the incoming light is nearly perpendicular to the surface of the cylin-
der, it receives more rays of light per surface area. As we move towards the side, this drops until
finally the incoming light is parallel to the side of the cylinder and the resulting intensity is zero.
3.4 Surface Properties 41
Figure 3–7 Flat and Gouraud shading. Different shading methods can dramatically improve the
look of an object represented with polygons. On the top, flat shading uses a constant surface normal
across each polygon. On the bottom, Gouraud shading interpolates normals from polygon vertices
to give a smoother look.
The contribution from diffuse lighting is expressed in Equation3-2 and illustrated in Figure3–8 .
where R d is the resulting intensity curve due to diffuse lighting, Lc is the intensity curve for the
light, and Oc is the color curve for the object. Notice that the diffuse light is a function of the rela-
tive angle between incident light vector andL nthe surface normal of the object . As a result
On
diffuse lighting is independent of viewer position.
Specular lighting represents direct reflections of a light source off a shiny object. Figure3–
10 shows a diffusely lit ball with varying specular reflection. The specular intensity (which varies
between the top and bottom rows) controls the intensity of the specular lighting. The specular
power, , Oindicates
sp how shiny an object is, more specifically it indicates how quickly specular
reflections diminish as the reflection angles deviate from a perfect reflection. Higher values indi-
cate a faster dropoff, and therefore a shinier surface. Referring to Figure3–9 , the equation for spec-
ular lighting is
O sp
R s = L c O s []SC× ()– n
(3-3)
S2O
= [] n × ()– L n O n + L n
where C
is nthe direction of projection for the camera and is theSdirection of specular reflection.
42 Computer Graphics Primer
Light
Ln
On
Light Color = L c q
-L n
q = ()
cosO n × –L n
Object Color = O c
Object
Light
Ln
On
q
-L n S
q = ()
cosO n × –Ln
Object
Object Color = O c
We have presented the equations for the different lighting models independently. We can
apply all lighting models simultaneously or in combination. Equation3-4 combines ambient, dif-
fuse and specular lighting into one equation.
Osp
R c = O ai O ac L c – O di O dc L c ()O n × L n + O si Osc L c []SC× ()– n (3-4)
The result is a color at a point on the surface of the object. The constants , O ai O di , and con-
O si
trol the relative amounts of ambient, diffuse and specular lighting for an object. The constants , Oac
O dc , and specify
O sc the colors to be used for each type of lighting. These six constants along
3.5 Cameras 43
Figure 3–10 Effects of specular coefficients. Specular coefficients control the apparent
“shininess” of objects. The top row has a specular intensity value of 0.5; the bottom row 1.0.
Along the horizontal direction the specular power changes. The values (from left to right)
are 5, 10, 20, and 40 ( SpecularSpheres.cxx ).
with the specular power are part of the surface material properties. (Other properties such as trans-
parency will be covered in later sections of the text.) Different combinations of these property val-
ues can simulate dull plastic and polished metal. The equation assumes an infinite point light
source as described in “Lights ” on page39 . However the equation can be easily modified to incor-
porate other types of directional lighting.
3.5 Cameras
We have light sources that are emitting rays of light and actors with surface properties. At every
point on the surface of our actors this interaction results in some composite color (i.e., combined
color from light, object surface, specular, and ambient effects). All we need now to render the scene
is a camera. There are a number of important factors that determine how a 3D scene gets projected
onto a plane to form a 2D image (see Figure3–11 ). These are the position, orientation, and focal
point of the camera, the method of camera projection , and the location of the camera clipping
planes.
The position and focal point of the camera define the location of the camera and where it
points. The vector defined from the camera position to the focal point is called the direction of pro-
jection . The camera image plane is located at the focal point and is typically perpendicular to the
projection vector. The camera orientation is controlled by the position and focal point plus the cam-
era view-up vector. Together these completely define the camera view.
The method of projection controls how the actors are mapped to the image plane. Ortho-
graphic projection is a parallel mapping process. In orthographic projection (or parallel projection)
all rays of light entering the camera are parallel to the projection vector. Perspective projection
44 Computer Graphics Primer
View Up
View Angle
Direction of
Projection
Focal Point
Position
occurs when all light rays go through a common point (i.e., the viewpoint or center of projection).
To apply perspective projection we must specify a perspective angle or camera view angle.
The front and back clipping planes intersect the projection vector, and are usually perpendic-
ular to it. The clipping planes are used to eliminate data either too close to the camera or too far
away. As a result only actors or portions of actors within the clipping planes are (potentially) visi-
ble. Clipping planes are typically perpendicular to the direction of projection. Their locations can
be set using the camera’s clipping range. The location of the planes are measured from the camera’s
position along the direction of projection. The front clipping plane is at the minimum range value,
and the back clipping plane is at the maximum range value. Later on in Chapter 7 , when we discuss
stereo rendering, we will see examples of clipping planes that are not perpendicular to the direction
of projection.
Taken together these camera parameters define a rectangular pyramid, with its apex at the
camera’s position and extending along the direction of projection. The pyramid is truncated at the
top with the front clipping plane and at the bottom by the back clipping plane. The resulting view
frustum defines the region of 3D space visible to the camera.
While a camera can be manipulated by directly setting the attributes mentioned above, there
are some common operations that make the job easier. Figure3–12 and Figure3–13 will help illus-
trate these operations. Changing the azimuth of a camera rotates its position around its view up vec-
tor, centered at the focal point . Think of this as moving the camera to the left or right while always
keeping the distance to the focal point constant. Changing a camera’s elevation rotates its position
around the cross product of its direction of projection and view up centered at the focal point. This
corresponds to moving the camera up and down. To roll the camera, we rotate the view up vector
about the view plane normal. Roll is sometimes called twist.
The next two motions keep the camera’s position constant and instead modify the focal point.
Changing the yaw rotates the focal point about the view up centered at the camera’s position. This
is like an azimuth, except that the focal point moves instead of the position. Changes in pitch rotate
the focal point about the cross product of the direction of projection and view up centered at the
3.5 Cameras 45
Elevation
Focal Point
Roll
Direction
of Projection
Azimuth
View Up
Yaw
Focal Point
Roll
View Plane
Normal
Pitch
camera’s position. Dollying in and out moves the camera’s position along the direction of projec-
tion, either closer or farther from the focal point. This operation is specified as the ratio of its cur-
rent distance to its new distance. A value greater than one will dolly in, while a value less than one
will dolly out. Finally, zooming changes the camera’s view angle, so that more or less of the scene
falls within the view frustum.
Once we have the camera situated, we can generate our 2D image. Some of the rays of light
traveling through our 3D space will pass through the lens on the camera. These rays then strike a
flat surface to produce an image. This effectively projects our 3D scene into a 2D image. The cam-
era’s position and other properties determine which rays of light get captured and projected. More
specifically, only rays of light that intersect the camera’s position, and are within its viewing frus-
tum, will affect the resulting 2D image.
This concludes our brief rendering overview. The light has traveled from its sources to the
actors, where it is reflected and scattered. Some of this light gets captured by the camera and pro-
duces a 2D image. Now we will look at some of the details of this process.
sfo s
a n B’
rm
Model Coordinates Transform
Tr t or
Ac View Coordinates
y-axis
Model B’s
Coordinate System x-axis
-1 1
Display Coordinates -1
You may want to render two different scenes, but display them in the same window. This can be
done by dividing the window into rectangular viewports. Then, each renderer can be told what por-
tion of the window it should use for rendering. The viewport ranges from (0,1) in both the x and y
axis. Similar to the view coordinate system, the z-value in the display coordinate system also repre-
sents depth into the window. The meaning of this z-value will be further described in the section
titled “Z-Buffer ” on page57 .
tive. To include projection effects such as vanishing points we use a special coordinate system
called homogeneous coordinates .
The usual way of representing a point in 3D is the three element Cartesian vector ( x, y, z).
Homogeneous coordinates are represented by a four element vector ( xh, y h, z h, w h ). The conversion
between Cartesian coordinates and homogeneous coordinates is given by:
xh yh zh
x = ------ y = ------ z = ------ (3-5)
wh wh wh
Using homogeneous coordinates we can represent an infinite point by setting w h to zero. This capa-
bility is used by the camera for perspective transformations. The transformations are applied by
using a 44´ transformation matrix . Transformation matrices are widely used in computer graph-
ics because they allow us to perform translation, scaling, and rotation of objects by repeated matrix
33´
multiplication. Not all of these operations can be performed using a matrix.
For example, suppose we wanted to create a transformation matrix that translates a point ( x, y,
z) in Cartesian space by the vector ( tx , ty, tz). We need only construct the translation matrix given by
100t x
010t y (3-6)
TT =
001t z
0001
and then postmultiply it with the homogeneous coordinate (xh, y h , z h, w h). To carry this example
through, we construct the homogeneous coordinate from the Cartesian coordinate ( x, y, z) by setting
w h = 1 to yield .()Then,
,,, to determine the translated point we premultiply
xyz1 ()x'y'z'
,,
the
current position by the transformation matrix to yield
T T the translated coordinate. Substituting
into Equation3-6 we have the result
x' 100t x x
y' = 010t y × y (3-7)
z' 001t z
z
w' 0001 1
Converting back to Cartesian coordinates via Equation3-5 we have the expected solution
x'xt= + x
y'yt= + y (3-8)
z'zt= + z
3.7 Coordinate Transformation 49
The same procedure is used to scale or rotate an object. To scale an object we use the transforma-
tion matrix
s x 000
0s y 00 (3-9)
TS =
00s z 0
0001
where the parameters s x, sy, and sz are scale factors along the x, y, and z axes. Similarly, we can
q
rotate an object around the x axes by angle using the matrix
1000
TR x = 0 cos q – sin q 0 (3-10)
0 sin q cos0q
0001
cos0q sin0q
TR = 0100 (3-11)
y
– sin q 0 cos0q
0001
cos q – sin q 00
T Rz = sin q cos00q (3-12)
0010
0001
Another useful rotation matrix is used to transform one coordinate axes toxy– another
– zcoordi-
nate axes .x'y' To– derive– z' the transformation matrix we assume that the unit axis makes the x'
()q x'x ,, qthe
angles around x'y q
axes
x'z (these are called
xy–direction
– z cosines). Similarly,
the unit axis y' makes the angles and the unit ()qy'xaxis
,, qy'y qy'z the angles
makes z'
()q z'x ,,q z'y q z'z . The resulting rotation matrix is formed by placing the direction cosines along the
rows of the transformation matrix as follows
Rotations occur about the coordinate origin. It is often more convenient to rotate around the center
of the object (or a user-specified point). Assume that we call this point the object’s center . To O c
rotate around weOc must first translate the object from to theOorigin,
c apply rotations, and then
translate the object back to . O c
Transformation matrices can be combined by matrix multiplication to achieve combinations
of translation, rotation, and scaling. It is possible for a single transformation matrix to represent all
types of transformation simultaneously. This matrix is the result of repeated matrix multiplications.
A word of warning: The order of the multiplication is important. For example, multiplying a trans-
lation matrix by a rotation matrix will not yield the same result as multiplying the rotation matrix
by the translation matrix.
Modelling
A major topic in the study of computer graphics is modelling or representing the geometry of phys-
ical objects. Various mathematical techniques have been applied including combinations of points,
lines, polygons, curves, and splines of various forms, and even implicit mathematical functions.
This topic is beyond the scope of the text. The important point here is that there is an underlying
geometric model that specifies what the object’s shape is and where it is located in the model coor-
dinate system.
In data visualization, modelling takes a different role. Instead of directly creating geometry to
represent an object, visualization algorithms compute these forms. Often the geometry is abstract
(like a contour line) and has little relationship to real world geometry. We will see how these mod-
els are computed when we describe visualization algorithms in Chapter 6 and Chapter 9 .
The representation of geometry for data visualization tends to be simple, even though com-
puting the representations is not. These forms are most often primitives like points, lines, and poly-
gons, or visualization data such as volume data. We use simple forms because we desire high
performance and interactive systems. Thus we take advantage of computer hardware (to be covered
in “Graphics Hardware ” on page51 ) or special rendering techniques like volume rendering (see
“Volume Rendering ” on page218 ).
y-axis
Azimuth
Figure 3–15 Actor coordinate system.
x-axis
Elevation
z-axis Roll
previous section on transformation matrices, the order of application of the transformations is not
arbitrary. We have chosen a fixed order based on what we think is natural to users. The order of
transformation is a rotation by O y around the y axis, then by around
Ox the x axis, and finally by
O z around the z axis. This ordering is arbitrary and is based on the standard camera operations.
These operations (in order) are a camera azimuth, followed by an elevation, and then a roll
(Figure3–15 ).
All of these rotations take place around the origin of the actor. Typically this is set to the cen-
ter of its bounding box, but it can be set to any convenient point. There are many different methods
for changing an actor’s orientation. RotateX() , RotateY() , and RotateZ() are common methods that
rotate about their respective axes. Many systems also include a method to rotate about a user-
defined axis. In the Visualization Toolkit the RotateXYZ() method is used to rotate around an arbi-
trary vector passing through the origin.
Raster Devices
The results of computer graphics is pervasive in today’s world—digital images (generated with
computer graphics) may be found on cell phones, displayed on computer monitors, broadcast on
TV, shown at the movie theatre and presented on electronic billboards. All of these, and many
more, display mediums are raster devices. A raster device represents an image using a two dimen-
sional array of picture elements called pixels. For example, the word “hello” can be represented as
an array of pixels. as shown in Figure3–16 . Here the word “hello” is written within a pixel array
52 Computer Graphics Primer
that is twenty-five pixels wide and ten pixels high. Each pixel stores one bit of information,
whether it is black or white. This is how a black and white laser printer works, for each point on the
paper it either prints a black dot or leaves it the color of the paper. Due to hardware limitations, ras-
ter devices such as laser printers and computer monitors do not actually draw accurate square pixels
like those in Figure3–16 . Instead, they tend to be slightly blurred and overlapping. Another hard-
ware limitation of raster devices is their resolution. This is what causes a 300 dpi (dots per inch)
laser printer to produce more detailed output than a nine pin dot matrix printer. A 300 dpi laser
printer has a resolution of 300 pixels per inch compared to roughly 50 dpi for the dot matrix printer.
Color computer monitors typically have a resolution of about 80 pixels per inch, making the
screen a pixel array roughly one thousand pixels in width and height. This results in over one mil-
lion pixels, each with a value that indicates what color it should be. Since the hardware in color
monitors uses the RGB system, it makes sense to use that to describe the colors in the pixels.
Unfortunately, having over one million pixels, each with a red, green, and blue component, can take
up a lot of memory. This is part of what differentiates the variety of graphics hardware on the mar-
ket. Some companies use 24 bits of storage per pixel, others use eight, some advanced systems use
more than 100 bits of storage per pixel. Typically, the more bits per pixel the more accurate the col-
ors will be.
One way to work around color limitations in the graphics hardware is by using a technique
called dithering . Say, for example, that you want to use some different shades of gray, but your
graphics hardware only supports black and white. Dithering lets you approximate shades of gray by
using a mixture of both black and white pixels. In Figure3–17 , seven gray squares are drawn using
a mixture of black and white pixels. From a distance the seven squares look like different shades of
gray even though up close, it’s clear that they are just different mixtures of black and white pixels.
This same technique works just as well for other colors. For example, if your graphics hardware
supports primary blue, primary green, and white but not a pastel sea green, you can approximate
this color by dithering the green, blue, and white that the hardware does support.
3.9 Graphics Hardware 53
Now that we have covered the basics of display hardware, the good news is that you rarely need to
worry about them. Most graphics programming is done using higher-level primitives than individ-
ual pixels. Figure3–18 shows a typical arrangement for a visualization program. At the bottom of
the hierarchy is the display hardware that we already discussed; chances are your programs will not
interact directly with it. The top three layers above the hardware are the layers you may need to be
concerned with.
Many programs take advantage of application libraries as a high-level interface to the graph-
ics capabilities of a system. The Visualization Toolkit accompanying this book is a prime example
of this. It allows you to display a complex object or graph using just a few commands. It is also pos-
sible to interface to a number of different graphics libraries, since different libraries may be sup-
ported on different hardware platforms.
The graphics library and graphics hardware layers both perform similar functions. They are
responsible for taking high-level commands from an application library or program, and executing
them. This makes programming much easier by providing more complex primitives to work with.
Instead of drawing pixels one at a time, we can draw primitives like polygons, triangles, and lines,
without worrying about the details of which pixels are being set to which colors. Figure3–19 illus-
trates some high-level primitives that all mainstream graphics libraries support.
This functionality is broken into two different layers because different machines may have
vastly different graphics hardware. If you write a program that draws a red polygon, either the
graphics library or the graphics hardware must be able to execute that command. On high-end sys-
tems, this may be done in the graphics hardware, on others it will be done by the graphics library in
software. So the same commands can be used with a wide variety of machines, without worrying
about the underlying graphics hardware.
The fundamental building block of the primitives in Figure3–19 is a point (or vertex). A ver-
tex has a position, normal, and color, each of which is a three element vector. The position specifies
where the vertex is located, its normal specifies which direction the vertex is facing, and its color
Your Program
Graphics Hardware
Display Hardware
specifies the vertex’s red, green, and blue components. A polygon is built by connecting a series of
points or vertices as shown in Figure3–20 . You may be wondering why each vertex has a normal,
instead of having just one normal for the entire polygon. A planar polygon can only be facing one
direction regardless of what the normals of its vertices indicate. The reason is that sometimes a
polygon is used as an approximation of something else, like a curve. Figure3–21 shows a top-
down view of a cylinder. As you can see, it’s not really a cylinder but rather a polygonal approxi-
mation of the cylinder drawn in gray. Each vertex is shared by two polygons and the correct normal
for the vertex is not the same as the normal for the polygon. Similar logic explains why each vertex
has a color instead of just having one color for an entire polygon.
When you limit yourself to the types of primitives described above, there are some additional
properties that many graphics systems support. Edge color and edge visibility can be used to high-
light the polygon primitives that make up an actor. Another way to do this is by adjusting the repre-
sentation from surface to wireframe or points. This replaces surfaces such as polygons with either
their boundary edges or points respectively. While this may not make much sense from a physical
perspective, it can help in some illustrations. Using edge visibility when rendering a CAD model
can help to show the different pieces that comprise the model.
Rasterization
At this point in the text we have described how to represent graphics data using rendering primi-
tives, and we have described how to represent images using raster display devices. The question
remains, how do we convert graphics primitives into a raster image? This is the topic we address in
3.9 Graphics Hardware 55
Point1
Point1 position=(1,3,0)
normal= (0,0,1)
color= (.8,.8,.8)
Point2
position=(0,0,0)
normal= (0,0,1)
color= (.8,.8,.8)
Point3
Point2 Point3
position=(2,0,0)
normal= (0,0,1)
color= (.8,.8,.8)
Figure 3–20 An example polygon.
Polygon1
points= (1,2,3)
Polygon Normal
this section. Although a thorough treatise on this topic is beyond the scope of this text, we will do
our best to provide a high-level overview.
The process of converting a geometric representation into a raster image is called rasteriza-
tion or scan conversion . In the description that follows we assume that the graphics primitives are
triangle polygons. This is not as limiting as you might think, because any general polygon can be
tessellated into a set of triangles. Moreover, other surface representations such as splines are usu-
ally tessellated by the graphics system into triangles or polygons. (The method described here is
actually applicable to convex polygons.)
Most of today’s hardware is based on object-order rasterization techniques. As we saw earlier
in this chapter, this means processing our actors in order. And since our actors are represented by
polygon primitives, we process polygons one at a time. So although we describe the processing of
one polygon, bear in mind that many polygons and possibly many actors are processed.
The first step is to transform the polygon using the appropriate transformation matrix. We
also project the polygon to the image plane using either parallel or orthographic projection. Part of
56 Computer Graphics Primer
V0
p0 pn
V1 pi
d i = d i1– + Dd i
V2
Figure 3–22 Rasterizing a convex polygon. Pixels are processed in horizontal spans (or scan-lines) in
the image plane. Data values d i at point pi are interpolated along the edges and then along the scan-line
using delta data values. Typical data values are RGB components of color.
this process involves clipping the polygons. Not only do we use the front and back clipping planes
to clip polygons too close or too far, but we must also clip polygons crossing the boundaries of the
image plane. Clipping polygons that cross the boundary of the view frustum means we have to gen-
erate new polygonal boundaries.
With the polygon clipped and projected to the image plane, we can begin scan-line process-
ing ( Figure3–22 ). The first step identifies the initial scan-line intersected by the projected polygon.
This is found by sorting the vertices’ y values. We then find the two edges joining the vertex on the
left and right sides. Using the slopes of the edges along with the data values we compute delta data
values. These data are typically the R, G, and B color components. Other data values include trans-
parency values and z depth values. (The z values are necessary if we are using a z-buffer, described
in the next section.) The row of pixels within the polygon (i.e., starting at the left and right edges) is
called a span . Data values are interpolated from the edges on either side of the span to compute the
internal pixel values. This process continues span-by-span, until the entire polygon is filled. Note
that as new vertices are encountered, it is necessary to recompute the delta data values.
The shading of the polygon (i.e., color interpolation across the polygon) varies depending on
the actor’s interpolation attribute. There are three possibilities: flat, Gouraud , or Phong shading .
Figure3–7 illustrates the difference between flat and Gouraud interpolation. Flat shading calcu-
lates the color of a polygon by applying the lighting equations to just one normal (typically the sur-
face normal) of the polygon. Gouraud shading calculates the color of a polygon at all of its vertices
using the vertices’ normals and the standard lighting equations. The interior and edges of the poly-
gon are then filled in by applying the scan-line interpolation process. Phong shading is the most
realistic of the three. It calculates a normal at every location on the polygon by interpolating the
vertex normals. These are then used in the lighting equations to determine the resulting pixel col-
3.10 Putting It All Together 57
ors. Both flat and Gouraud shading are commonly used methods. The complexity of Phong shading
has prevented it from being widely supported in hardware.
Z -Buffer
In our earlier description of the rendering process, we followed rays of light from our eye through a
pixel in the image plane to the actors and back to the light source. A nice side effect of ray tracing
is that viewing rays strike the first actor they encounter and ignore any actors that are hidden behind
it. When rendering actors using the polygonal methods described above, we have no such method
of computing which polygons are hidden and which are not. We cannot generally count on the
polygons being ordered correctly. Instead, we can use a number of hidden-surface methods for
polygon rendering.
One method is to sort all of our polygons from back to front
(along the camera’s view vector) and then render them in that order.
This is called the painter’s algorithm or painter’s sort, and has one
major weakness illustrated in Figure3–23 . Regardless of the order in
which we draw these three triangles, we cannot obtain the desired
result, since each triangle is both in front of, and behind, another tri-
angle. There are algorithms that sort and split polygons as necessary
to treat such a situation [Carlson85] . This requires more initial pro-
cessing to perform the sorting and splitting. If the geometric primi-
tives change between images or the camera view changes, then this
Figure 3–23 Problem with
processing must be performed before each render.
Painter’s algorithm.
Another hidden surface algorithm, z-buffering, takes care of
this problem and does not require sorting. Z-buffering takes advantage of the z-value (i.e., depth
value along direction of projection) in the view coordinate system. Before a new pixel is drawn, its
z-value is compared against the current z-value for that pixel location. If the new pixel would be in
front of the current pixel, then it is drawn and the z-value for that pixel location is updated. Other-
wise the current pixel remains and the new pixel is ignored.
Z-buffering has been widely implemented in hardware because of its simplicity and robust-
ness. The downside to z-buffering is that it requires a large amount of memory, called a z-buffer, to
store a z-value of every pixel. Most systems use a z-buffer with a depth of 24 or 32 bits. For a 1000
by 1000 display that translates into three to four megabytes just for the z-buffer. Another problem
with z-buffering is that its accuracy is limited depending on its depth. A 24-bit z-buffer yields a pre-
cision of one part in 16,777,216 over the height of the viewing frustum. This resolution is often
insufficient if objects are close together. If you do run into situations with z-buffering accuracy,
make sure that the front and back clipping planes are as close to the visible geometry as possible.
Instances of vtkRenderWindow
Instances of
vtkRenderer
One or more
vtkLight ’s illuminate
the scene
Instances of vtkActor
vtkMapper defines
vtkProperty defines
actor geometry Figure 3–24 Illustrative diagram
actor surface properties
of graphics objects ( Model.cxx ).
We have discussed many of the objects that play a part in the rendering of a scene. Now it’s time to
put them together into a comprehensive object model for graphics and visualization.
In the Visualization Toolkit there are seven basic objects that we use to render a scene. There
are many more objects behind the scenes, but these seven are the ones we use most frequently. The
objects are listed in the following and illustrated in Figure3–24 .
1. vtkRenderWindow — manages a window on the display device; one or more renderers draw
into an instance of vtkRenderWindow .
2. vtkRenderer — coordinates the rendering process involving lights, cameras, and actors.
3. vtkLight — a source of light to illuminate the scene.
4. vtkCamera — defines the view position, focal point, and other viewing properties of the
scene.
5. vtkActor — represents an object rendered in the scene, including its properties and position
in the world coordinate system. ( Note: vtkActor is a subclass of vtkProp. vtkProp is a more
general form of actor that includes annotation and 2D drawing classes. See “Assemblies and
Other Types of vtkProp ” on page74 for more information.)
6. vtkProperty — defines the appearance properties of an actor including color, transparency,
and lighting properties such as specular and diffuse. Also representational properties like
wireframe and solid surface.
3.10 Putting It All Together 59
7. vtkMapper — the geometric representation for an actor. More than one actor may refer to the
same mapper.
The class vtkRenderWindow ties the rendering process together. It is responsible for managing a
window on the display device. For PCs running Windows, this will be a Microsoft display window,
for Linux and UNIX systems this will be an X window, and on the Mac (OSX) a Quartz window. In
VTK, instances of vtkRenderWindow are device independent. This means that you do not need to
be concerned about what underlying graphics hardware or software is being used, the software
automatically adapts to your computer as instances of vtkRenderWindow are created. (See “Achiev-
ing Device Independence ” on page60 for more information.)
In addition to window management, vtkRenderWindow objects are used to manage renderers
and store graphics specific characteristics of the display window such as size, position, window
title, window depth , and the double buffering flag. The depth of a window indicates how many bits
are allocated per pixel. Double buffering is a technique where a window is logically divided into
two buffers. At any given time one buffer is currently visible to the user. Meanwhile, the second
buffer can be used to draw the next image in an animation. Once the rendering is complete, the two
buffers can be swapped so that the new image is visible. This common technique allows animations
to be displayed without the user seeing the actual rendering of the primitives. High-end graphics
systems perform double buffering in hardware. A typical system would have a rendering window
with a depth of 72 bits. The first 24 bits are used to store the red, green, and blue (RGB) pixel com-
ponents for the front buffer. The next 24 bits store the RGB values for the back buffer. The last 24
bits are used as a z-buffer.
The class vtkRenderer is responsible for coordinating its lights, camera, and actors to produce
an image. Each instance maintains a list of the actors, lights, and an active camera in a particular
scene. At least one actor must be defined, but if lights and a camera are not defined, they will be
created automatically by the renderer. In such a case the actors are centered in the image and the
default camera view is down the z-axis. Instances of the class vtkRenderer also provide methods to
specify the background and ambient lighting colors. Methods are also available to convert to and
from world, view, and display coordinate systems.
One important aspect of a renderer is that it must be associated with an instance of the
vtkRenderWindow class into which it is to draw, and the area in the render window into which it
draws must be defined by a rectangular viewport . The viewport is defined by normalized coordi-
nates (0,1) in both the x and y image coordinate axes. By default, the renderer draws into the full
extent of the rendering window (viewpoint coordinates (0,0,1,1)). It is possible to specify a smaller
viewport. and to have more than one renderer draw into the same rendering window.
Instances of the class vtkLight illuminate the scene. Various instance variables for orienting
and positioning the light are available. It is also possible to turn on/off lights as well as setting their
color. Normally at least one light is “on” to illuminate the scene. If no lights are defined and turned
on, the renderer constructs a light automatically. Lights in VTK can be either positional or infinite.
Positional lights have an associated cone angle and attenuation factors. Infinite lights project light
rays parallel to one another.
Cameras are constructed by the class vtkCamera . Important parameters include camera posi-
tion, focal point, location of front and back clipping planes, view up vector, and field of view. Cam-
eras also have special methods to simplify manipulation as described previously in this chapter.
These include elevation, azimuth, zoom, and roll. Similar to vtkLight , an instance of vtkCamera
will be created automatically by the renderer if none is defined.
60 Computer Graphics Primer
Instances of the class vtkActor represent objects in the scene. In particular, vtkActor com-
bines object properties (color, shading type, etc.), geometric definition, and orientation in the world
coordinate system. This is implemented behind the scenes by maintaining instance variables that
refer to instances of vtkProperty , vtkMapper , and vtkTransform . Normally you need not create
properties or transformations explicitly, since these are automatically created and manipulated
using vtkActor ’s methods. You do need to create an instance of vtkMapper (or one of its sub-
classes). The mapper ties the data visualization pipeline to the graphics device. (We will say more
about the pipeline in the next chapter.)
In VTK, actors are actually subclasses of vtkProp (arbitrary props) and vtkProp3D (those that
can be transformed in 3D space. (The word “prop” is derived from the stage, where a props is an
object in the scene.) There are other subclasses of props and actors with specialized behavior (see
“Assemblies and Other Types of vtkProp ” on page74 for more information). One example is
vtkFollower . Instances of this class always face the active camera. This is useful when designing
signs or text that must be readable from any camera position in the scene.
Instances of the class vtkProperty affect the rendered appearance of an actor. When actors are
created, a property instance is automatically created with them. It is also possible to create property
objects directly and then associate the property object with one or more actors. In this way actors
can share common properties.
Finally, vtkMapper (and its subclasses) defines object geometry and, optionally, vertex col-
ors. In addition, vtkMapper refers to a table of colors (i.e., vtkLookupTable ) that are used to color
the geometry. (We discuss mapping of data to colors in “Color Mapping ” on page163 .) We will
examine the mapping process in more detail in “Mapper Design ” on page195 . For now assume that
vtkMapper is an object that represents geometry and other types of visualization data.
There is another important object, vtkRenderWindowInteractor , that captures events (such as
mouse clicks and mouse motion) for a renderer in the rendering window.
vtkRenderWindowInteractor captures these events and then triggers certain operations like camera
dolly, pan, and rotate, actor picking, into/out of stereo mode, and so on. Instances of this class are
associated with a rendering window using the SetRenderWindow() method.
(a) Inheritance of device classes. (Note: in VTK 4.2 the Starbase and
XGL graphics libraries are no longer supported.)
vtkActor *vtkActor::New()
{
vtkObject* ret = vtkGraphicsFactory::CreateInstance("vtkActor");
return (vtkActor*)ret;
}
(b) Code fragment from vtkActor::New()
if (!strcmp("OpenGL",rl) || !strcmp("Win32OpenGL",rl) ||
!strcmp("CarbonOpenGL",rl) || !strcmp("CocoaOpenGL",rl))
{
if(strcmp(vtkclassname, "vtkActor") == 0)
{
return vtkOpenGLActor::New();
}
Figure 3–25 Achieving device independence using (a) inheritance and object factories (b) and (c).
to create a device dependent instance of vtkActor . The user sees no device dependent code, but in
actuality anActor is a pointer to a device dependent subclass of vtkActor . Figure3–25 (b) is a code
fragment of the constructor method New() which uses VTK’s object factory mechanism. In turn,
the vtkGraphicsFactory (used to instantiate graphical classes) produces the appropriate concrete
subclass when requested to instantiate an actor as shown in Figure3–25 (c).
The use of object factories as implemented using the New() method allows us to create
device independent code that can move from computer to computer and adapt to changing technol-
ogy. For example, if a new graphics library became available, we would only have to create a new
device dependent subclass, and then modify the graphics factory to instantiate the appropriate sub-
class based on environment variables or other system information. This extension would be local-
ized and only done once, and all applications based on these object factories would be
automatically ported without change.
Examples
This section works through some simple applications implemented with VTK graphics objects. The
focus is on the basics: how to create renderers, lights, cameras, and actors. Later chapters tie
together these basic principles to create applications for data visualization.
62 Computer Graphics Primer
Render a Cone. The following C++ code uses most of the objects introduced in this section to cre-
ate an image of a cone. The vtkConeSource generates a polygonal representation of a cone and
vtkPolyDataMapper maps the geometry (in conjunction with the actor) to the underlying graphics
library. (The source code to this example can be found in Cone.cxx . The source code contains
additional documentation as well.)
#include "vtkConeSource.h"
#include "vtkPolyDataMapper.h"
#include "vtkRenderWindow.h"
#include "vtkCamera.h"
#include "vtkActor.h"
#include "vtkRenderer.h"
int i;
for (i = 0; i < 360; ++i)
{
// render the image
renWin->Render();
// rotate the active camera by one degree
ren1->GetActiveCamera()->Azimuth( 1 );
}
cone->Delete();
coneMapper->Delete();
coneActor->Delete();
ren1->Delete();
renWin->Delete();
3.10 Putting It All Together 63
return 0;
}
Some comments about this example. The include files vtk__. h include class definitions for the
objects in VTK necessary to compile this example. We use the constructor New() to create the
objects in this example, and the method Delete() to destroy the objects. In VTK the use of New()
and Delete() is mandatory to insure device independence and properly manage reference counting.
(See VTK User’s Guide for details.) In this example the use of Delete() is really not necessary
because the objects are automatically deleted upon program termination. But generally speaking,
you should always use a Delete() for every invocation of New(). (Future examples will not show
the Delete() methods in the scope of the main() program to conserve space, nor show the required
#include statements.)
The data representing the cone (a set of polygons) in this example is created by linking
together a series of objects into a pipeline (which is the topic of the next chapter). First a polygonal
representation of the cone is created with a vtkConeSource and serves as input to the data mapper
as specified with the SetInput() method . The SetMapper() method associates the mapper’s data
with the coneActor . The next line adds coneActor to the renderer’s list of actors. The cone is ren-
o
dered in a loop running over 360 . Since there are no cameras or lights defined in the above exam-
ple, VTK automatically generates a default light and camera as a convenience to the user. The
camera is accessed through the GetActiveCamera() method, and a one degree azimuth is applied as
shown. Each time a change is made to any objects a Render() method is invoked to produce the cor-
responding image. Once the loop is complete all allocated objects are destroyed and the program
exits.
There are many different types of source objects in VTK similar to vtkConeSource as shown
in Figure3–26 . In the next chapter we will learn more about source and other types of filters.
Events and Observers. A visualization toolkit like VTK is frequently used in interactive applica-
tions or may be required to provide status during operation. In addition, integration with other
packages such as GUI toolkits is a common task. Supporting such features requires a mechanism
64 Computer Graphics Primer
for inserting user functionality into the software. In VTK, the command/observer design pattern
[Gamma95] is used for this purpose.
Fundamental to this design pattern as implemented in VTK is the concept of events . An event
signals that an important operation has occurred in the software. For example, if the user presses
the left mouse button in the render window, VTK will invoke the LeftButtonPressEvent . Observers
are objects that register their interest in a particular event or events. When one of these events is
invoked, the observer receives notification and may perform any valid operation at that point; that
is, execute the command associated with the observer. The benefit of the command/observer design
pattern is that is simple in concept and implementation, yet provides significant power to the user.
However it does require the software implementation to invoke events as it operates.
In the next example, an observer watches for the StartEvent invoked by the renderer just as it
begins the rendering process. The observer in turn executes its associated command which simply
prints out the camera’s current position.
#include "vtkCommand.h"
int i;
for (i = 0; i < 360; ++i)
{
// render the image
renWin->Render();
// rotate the active camera by one degree
ren1->GetActiveCamera()->Azimuth( 1 );
}
cone->Delete();
coneMapper->Delete();
coneActor->Delete();
ren1->Delete();
renWin->Delete();
return 0;
}
The observer is created by deriving from the class vtkCommand. The Execute() method is required
to be implemented by any concrete subclass of vtkCommand (i.e., the method is pure virtual). The
resulting subclass, vtkMyCommand , is instantiated and registered with the renderer instance ren1
using the AddObserver() method. In this case the StartEvent is the observed event.
This simple example does not demonstrate the true power of the command/observer design
pattern. Later in this chapter ( “Interpreted Code ” on page68 ) we will see how this functionality is
used to integrate a simple GUI into VTK. In Chapter 7 three-dimensional interaction widgets will
be introduced ( “3D Widgets and User Interaction ” on page252 ).
Creating Multiple Renderers. The next example is a bit more complex and uses multiple render-
ers that share a single rendering window. We use viewports to define where the renderers should
draw in the render window. (This C++ code can be found in Cone3.cxx .)
ren1->GetActiveCamera()->Azimuth(90);
int i;
for (i = 0; i < 360; ++i)
{
// render the image
renWin->Render();
// rotate the active camera by one degree
ren1->GetActiveCamera()->Azimuth( 1 );
ren2->GetActiveCamera()->Azimuth( 1 );
}
As you can see, much of the code is the same as the previous example. The first difference is that
we create two renderers instead of one. We assign the same actor to both renderers, but set each
renderer’s background to a different color. We set the viewport of the two renderers so that one is
on the left half of the rendering window and the other is on the right. The rendering window’s size
is specified as 600 by 300 pixels, which results in each renderer drawing into a viewport of 300 by
300 pixels.
A good application of multiple renderers is to display different views of the same world as
demonstrated in this example. Here we adjust the first renderer’s camera with a 90 degree azimuth.
We then start a loop that rotates the two cameras around the cone. Figure3–27 shows four frames
from this animation.
Properties and Transformations. The previous examples did not explicitly create property or
transformation objects or apply actor methods that affect these objects. Instead, we accepted default
3.10 Putting It All Together 67
instance variable values. This procedure is typical of VTK applications. Most instance variables
have been preset to generate acceptable results, but methods are always available for you to over-
ride the default values.
This example creates an image of two cones of different colors and specular properties. In
addition, we transform one of the objects to lay next to the other. The C++ source code for this
example can be found in Cone4.cxx .
We set the actor coneActor properties by modifying the property object automatically created by
the actor. This differs from actor coneActor2 , where we create a property directly and then assign it
to the actor. ConeActor2 is moved from its default position by applying the SetPosition() method.
This method affects the transformation matrix that is an instance variable of the actor. The resulting
image is shown in Figure3–28 .
68 Computer Graphics Primer
Introducing vtkRenderWindowInteractor. The previous examples are not interactive. That is, it
is not possible to directly interact with the data without modifying and recompiling the C++ code.
One common type of interaction is to change camera position so that we can view our scene from
different vantage points. In the Visualization Toolkit we have provided a suite of convenient objects
to do this: vtkRenderWindowInteractor, vtkInteractorStyle and their derived classes .
Instances of the class vtkRenderWindowInteractor capture windowing system specific mouse
and keyboard events in the rendering window, and then translate these events into VTK events. For
example, mouse motion in an X11 or Windows application (occurring in a render window) would
be translated by vtkRenderWindowInteractor into VTK’s MouseMoveEvent . Any observers regis-
tered for this event would be notified (see “Events and Observers ” on page63 ). Typically an
instance of vtkInteractorStyle is used in combination with vtkRenderWindowInteractor to define a
behavior associated with particular events. For example, we can perform camera dolly, pan, and
rotation by using different mouse button and motion combinations. The following code fragment
shows how to instantiate and use these objects. This example is the same as our first example with
the addition of the interactor and interactor style. The complete example C++ code is in
Cone5.cxx .
vtkInteractorStyleTrackballCamera *style =
vtkInteractorStyleTrackballCamera::New();
iren->SetInteractorStyle(style);
iren->Initialize();
iren->Start();
After the interactor is created using its New() method, we must tell it what render window to cap-
ture events in using the SetRenderWindow() method. In order to use the interactor we have to ini-
tialize and start the event loop using the Initialize() and Start() methods, which works with the
event loop of the windowing system to begin to catch events. Some of the more useful events
include the “ w” key, which draws all actors in wireframe; the “ s” key, which draws the actors in
surface form; the “ 3” key, which toggles in and out of 3D stereo for those systems that support this;
the “ r” key, which resets camera view; and the “ e” key, which exits the application. In addition, the
mouse buttons rotate, pan, and dolly about the camera’s focal point. Two advanced features are the
“u” key, which executes a user-defined function; and the “ p ” key, which picks the actor under the
mouse pointer.
Interpreted Code. In the previous example we saw how to create an interactor style object in con-
junction with vtkRenderWindowInteractor to enable us to manipulate the camera by mousing in the
render window. Although this provides flexibility and interactivity for a large number of applica-
tions, there are examples throughout this text where we want to modify other parameters. These
parameters range from actor properties, such as color, to the name of an input file. Of course we can
always write or modify C++ code to do this, but in many cases the turn-around time between mak-
ing the change and seeing the result is too long. One way to improve the overall interactivity of the
system is to use an interpreted interface. Interpreted systems allow us to modify objects and imme-
3.10 Putting It All Together 69
diately see the result, without the need to recompile and relink source code. Interpreted languages
also provide many tools, such as GUI (Graphical User Interface) tools, that simplify the creation of
applications.
The Visualization Toolkit has built into its compilation pro-
cess the ability to automatically generate language bindings to the
interpreted languages Tcl, Python, and Java [Ousterhout94] . This Interpreted
so-called wrapping process automatically creates a layer between Wrappers
the C++ VTK library and the interpreter as illustrated in Figure3–
29 . There is a one-to-one mapping between C++ methods and Tcl
functions for most objects and methods in the system. To demon- C++
strate this, the following example repeats the previous C++ exam- Library
ple except that it is implemented with a Tcl script. (The script can
be found in Cone5.tcl .)
Figure 3–29 In VTK the
package require vtk C++ library is automatically
package require vtkinteraction wrapped with the interpreted
languages Tcl, Python, and
vtkConeSource cone Java.
cone SetHeight 3.0
cone SetRadius 1.0
cone SetResolution 10
vtkPolyDataMapper coneMapper
coneMapper SetInputConnection [cone GetOutputPort]
vtkActor coneActor
coneActor SetMapper coneMapper
vtkRenderer ren1
ren1 AddActor coneActor
ren1 SetBackground 0.1 0.2 0.4
vtkRenderWindow renWin
renWin AddRenderer ren1
renWin SetSize 300 300
vtkRenderWindowInteractor iren
iren SetRenderWindow renWin
vtkInteractorStyleTrackballCamera style
iren SetInteractorStyle style
iren Initialize
wm withdraw .
70 Computer Graphics Primer
The example begins by loading some shared libraries defining various VTK classes. Next the stan-
dard visualization pipeline is created from the vtkConeSource and vtkPolyDataMapper . The ren-
dering classes are created exactly the same as with the C++ example. One major addition is an
observer to watch for a UserEvent in the rendering window (by default a “keypress-u”). The
observer triggers the invocation of a Tcl script to raise a Tk interactor GUI widget called
.vtkInteract . This GUI, which allows the direct typing of Tcl statements, is shown in Figure3–
30 and is defined by the Tcl command package require vtkinteraction which was executed
earlier in the script. (Note: Tk is a popular GUI toolkit for interpreted languages and is distributed
as part of Tcl.)
As we can see from this example, the number of lines of code is less for the Tcl example than
for equivalent C++ code. Also, many of the complexities of C++ are hidden using the interpreted
language. Using this user-interface GUI we can create, modify, and delete objects, and modify their
instance variables. The resulting changes appear as soon as a Render() method is applied or mouse
events in the rendering window cause a render to occur. We encourage you to use Tcl (or one of the
other interpreters) for rapid creation of graphics and visualization examples. C++ is best used when
you desire higher performing applications.
Transformation Matrices
and RotateZ() methods are all delegated to Transform . The method SetOrientation() uses
Transform to orient the actor.
The vtkActor class applies transformations in an order that we feel is natural to most users.
As a convenience, we have created instance variables that abstract the transformation matrices. The
()o x,,o y othe
Origin specifies z point that is the center of rotation and scaling. The Position
()p x,, p y p z specifies a final translation of the object. ()r x,,r ythe
Orientation defines rz rota-
tions about the x, y and z axes. Scale defines ()s x,, s y scale
s z factors for the x, y, and z axes. Inter-
nally, the actor uses these instance variables to create the following sequence of transformations
(see Equation3-6 , Equation3-9 , Equation3-13 ).
T T ()xyz
The term denotes ,, the translations in the x, y, and z directions. Recall that we premulti-
ply the transformation matrix times the position vector. This means the transformations are read
from right to left. In other words, Equation3-14 proceeds as follows:
1. Translate the actor to its origin. Scaling and rotation will occur about this point. The initial
translation will be countered by a translation in the opposite direction after scaling and rota-
tions are applied.
2. Scale the geometry.
3. Rotate the actor about the y, then x, and then z axes.
4. Undo the translation of step 1 and move the actor to its final location.
The order of the transformations is important. In VTK the rotations are ordered to what is natural in
most cases. We recommend that you spend some time with the software to learn how these transfor-
mations work with your own data.
Probably the most confusing aspect of transformations are rotations and their effect on the
Orientation instance variable. Generally orientations are not set directly by the user, and most users
will prefer to specify rotations with the RotateX() , RotateY() , and RotateZ() methods. These meth-
ods perform rotations about the x, y, and z axes in an order specified by the user. New rotations are
applied to the right of the rotation transformation. If you need to rotate your actor about a single
axis, the actor will rotate exactly as you expect it will, and the resulting orientation vector will be as
expected. For example, the operation RotateY(20) will produce an orientation of (0,20,0) and a
RotateZ(20) will produce (0,0,20). However, a RotateY(20) followed by a RotateZ(20) will not
produce (0,20,20) but produce an orientation of (6.71771, 18.8817, 18.8817)! This is because the
rotation portion of Equation3-14 is built from the rotation order z, then x, and then y. To verify
this, a RotateZ(20) followed by a RotateY(20) does produce an orientation of (0,20,20). Adding a
third rotation can be even more confusing.
A good rule of thumb is to only use the SetOrientation() method to either reset the orientation
to (0,0,0) or to set just one of the rotations. The RotateX() , RotateY() , and RotateZ() methods are
preferred to SetOrientation() when multiple angles are needed. Remember that these rotations are
applied in reverse order. Figure3–31 illustrates the use of the rotation methods. We turn off the
erase between frames using the render window’s EraseOff() method so we can see the effects of the
rotations. Note that in the fourth image the cow still rotates about her own y axis even though an x
axis rotation preceded the y rotation.
72 Computer Graphics Primer
(a) Six rotations about the x axis. (b) Six rotations about the y axis.
(c) Six rotations about the z axis. (d) First a rotation about the x axis, then
six rotations about the y axis.
Figure 3–31 Rotations of a cow about her axes. In this model, the x axis is from the left to right;
the y axis is from bottom to top; and the z axis emerges from the image. The camera location is the
same in all four images ( rotations.tcl ).
We have seen that VTK hides some of the complexities of matrix transformations by using
instance variables that are more natural than a transformation matrix. But there will be times when
the predefined order of transformations performed by the actor will not be sufficient. vtkActor has
an instance variable UserMatrix that contains a 4 x 4 transformation matrix. This matrix is applied
before the transformation composed by the actor. As you become more comfortable with 4 x 4
transformation matrices you may want to build your own matrix. The object vtkTransform creates
and manipulates these matrices. Unlike an actor, an instance of vtkTransform does not have an
instance variable for position, scale, origin, etc. You control the composition of the matrix directly.
The following statements create an identical 4 x 4 matrix that the actor creates:
myTrans->Translate (-origin[0],-origin[1],-origin[2]);
TT= Ry T S T T ()005
,, (3-15)
vtkActor *cow=vtkActor::New();
cow->SetOrigin(0,0,-5);
cow->RotateY(20);
cow->SetPosition(0,0,5);
TT= T ()0055
,, – ()– T R y T S T T ()005
,, – ()– (3-16)
Canceling the minus signs in the right-most translation matrix and combining the position and ori-
gin translation produce the equivalent transform that we built with vtkTranform . Figure3–32
shows the cow rotating with the specified transformation order. Your preference is a matter of taste
and how comfortable you are with matrix transformations. As you become more skilled (and your
demands are greater) you may prefer to always build your transformations. VTK gives you the
choice.
There is one final and powerful operation that affects an actor’s orientation. You can rotate an
actor about an arbitrary vector positioned at the actor’s origin. This is done with the actor’s (and
transform’s) RotateWXYZ() method. The first argument of the operation specifies the number of
degrees to rotate about the vector specified by the next three arguments. Figure3–33 shows how to
rotate the cow about a vector passing through her nose. At first, we leave the origin at (0,0,0). This
is obviously not what we wanted. The second figure shows the rotation when we change the cow’s
rotation origin to the tip of her nose.
74 Computer Graphics Primer
Figure 3–32 The cow “walking” around the global origin ( walkCow.tcl ).
Figure 3–33 The cow rotating about a vector passing through her nose. (a) With origin (0,0,0).
(b) With origin at (6.1,1.3,.02). ( walkCow.tcl ).
actor-like classes in VTK. As Figure3–34 shows, these classes are arranged into a hierarchy of
vtkProps. (In stage and film terminology, a prop is something that appears or is used on stage.)
Assemblies are formed in VTK by instantiating a vtkAssembly and then adding parts to it. A
part is any instance of vtkProp3D —including other assemblies. This means that assemblies can be
formed into hierarchies (as long as they do not contain self-referencing loops). Assemblies obey the
rules of transformation concatenation illustrated in the previous section (see “Transformation Matri-
ces” on page70 ). Here is an example of how to create a simple assembly hierarchy (from
assembly.tcl ).
vtkSphereSource sphere
vtkPolyDataMapper sphereMapper
sphereMapper SetInputConnection [sphere GetOutputPort]
vtkActor sphereActor
sphereActor SetMapper sphereMapper
sphereActor SetOrigin 2 1 3
sphereActor RotateY 6
sphereActor SetPosition 2.25 0 0
[sphereActor GetProperty] SetColor 1 0 1
vtkCubeSource cube
vtkPolyDataMapper cubeMapper
cubeMapper SetInputConnection [cube GetOutputPort]
vtkActor cubeActor
cubeActor SetMapper cubeMapper
cubeActor SetPosition 0.0 .25 0
[cubeActor GetProperty] SetColor 0 0 1
vtkConeSource cone
vtkPolyDataMapper coneMapper
coneMapper SetInputConnection [cone GetOutputPort]
vtkActor coneActor
coneActor SetMapper coneMapper
coneActor SetPosition 0 0 .25
[coneActor GetProperty] SetColor 0 1 0
vtkCylinderSource cylinder
vtkPolyDataMapper cylinderMapper
cylinderMapper SetInputConnection [cylinder GetOutputPort]
cylinderMapper SetResolveCoincidentTopologyToPolygonOffset
vtkActor cylinderActor
cylinderActor SetMapper cylinderMapper
[cylinderActor GetProperty] SetColor 1 0 0
vtkAssembly assembly
assembly AddPart cylinderActor
assembly AddPart sphereActor
assembly AddPart cubeActor
assembly AddPart coneActor
assembly SetOrigin 5 10 15
76 Computer Graphics Primer
assembly AddPosition 5 0 0
assembly RotateX 15
Note that in this example various actors are added to the assembly with the AddPart() method. The
top-level element of the assembly is the only prop in the hierarchy added to the renderer (with
AddActor() ). Note also that the coneActor appears twice: once as a part of the assembly, and once
as a separate actor added to the renderer with AddActor() . As you might imagine, this means that
the rendering of assemblies requires concatenation of transformation matrices to insure the correct
positioning of each vtkProp3D. Furthermore, hierarchical assemblies require special treatment dur-
ing picking (i.e., graphically selecting props) since a vtkProp can appear more than once in differ-
ent assembly hierarchies. Picking issues are discussed in more detail in “Picking ” on page308 .
As Figure3–34 indicates, there are other types of vtkProp as well. Most of these will be
informally described in the many examples found in this book. In particular, extensive coverage is
given to vtkVolume when we describe volume rendering (see “Volume Rendering ” on page218 ).
model for most users. Lighting models also include effects due to ambient, diffuse, and specular
lighting.
There are four important coordinate systems in computer graphics. The model system is the
3D coordinate system where our geometry is defined. The world system is the global Cartesian sys-
tem. All modeled data is eventually transformed into the world system. The view coordinate system
represents what is visible to the camera. It is a 2D system scaled from (-1,1). The display coordi-
nate system uses actual pixel locations on the computer display.
Homogeneous coordinates are a 4D coordinate system in which we can include the effects of
perspective transformation. Transformation matrices are matrices
44´ that operate on homoge-
neous coordinates. Transformation matrices can represent the effects of translation, scaling, and
rotation of an actor. These matrices can be multiplied together to give combined transformations.
Graphics programming is usually implemented using higher-level graphics libraries and spe-
cialized hardware systems. These dedicated systems offer better performance and easier implemen-
tation of graphics applications. Common techniques implemented in these systems include
dithering and z-buffering. Dithering is a technique to simulate colors by mixing combinations of
available colors . Z-buffering is a technique to perform hidden-line and hidden-surface removal.
The Visualization Toolkit uses a graphics model based on lights, cameras, actors, and render-
ers. The renderers draw into rendering windows. Actor properties are represented by a property
object and their geometry by a mapper object. Taken together, the instantiations of these various
classes form a scene. Interaction with the objects in a scene is facilitated by the
vtkRenderWindowInteractor and vtkInteractorStyle classes. These use the command/observer
design pattern that triggers and responds to events. Users can observe particular events and write
callbacks that can perform arbitrary tasks, easily extending the toolkit for a particular application.
3.13 References
[Bresenham65]
J. E. Bresenham.“Algorithm for Computer Control of a Digital Plotter.” IBM Systems Journal ,
4(1): 25–30, January 1965.
[BurgerGillies89]
P. Burger and D. Gillies. Interactive Compute Graphics Functional, Procedural and Device-Level
Methods . Addison-Wesley, Reading, MA, 1989.
78 Computer Graphics Primer
[Carlson85]
N. R. Carlson. Physiology of Behaviour (3d Edition) . Allyn and Bacon Inc., Newton, MA, 1985.
[Dartnall83]
H. J. A. Dartnall, J. K. Bowmaker, and J. D. Mollon. “Human Visual Pigments: Microspectropho-
tometric Results from the Eyes of Seven Persons.” Proceedings of the Royal Society, London,
1983.
[FoleyVanDam90]
J. D. Foley, A. van Dam, S. K. Feiner, and J. F. Hughes. Computer Graphics Principles and Prac-
tice (2d Edition) . Addison-Wesley, Reading, MA, 1990.
[Fuchs80]
H. Fuchs, Z. M. Kedem, and B. F. Naylor. “On Visible Surface Generation By A Priori Tree Struc-
ture.” Computer Graphics (SIGGRAPH ’80) , 14(3):124–133, 1980.
[Gamma95]
E. Gamma, R. Helm, R. Johnson, J. Vlissides. Design Patterns Elements of Reusable Object-Ori-
ented Software . Addison-Wesley 1995. ISBN0-201-63361-2.
[Ousterhout94]
J. K.Ousterhout. Tcl and the Tk Toolkit. Addison-Wesley Publishing Company, Reading, MA,
1994.
[Watt93]
A. Watt. 3D Computer Graphics (2d Edition) . Addison-Wesley, Reading, MA, 1993.
[Whitted80]
T. Whitted. “An Improved Illumination Model for Shaded Display.” Communications of the ACM ,
23(6):343–349, 1980.
3.14 Exercises
3.1 Estimate the odds of a ray of light being emitted from the sun, traveling to earth and hitting a
one meter square picnic blanket. You can assume that the sun is a point light source that emits
light uniformly in all directions. The approximate distance from the sun to the earth is
150,000,000 km.
a) What are the odds when the sun is directly overhead?
b) What are the odds when the sun is inclined 45 degrees relative to the surface normal of the
picnic blanket?
c) What assumptions or approximations did you make?
3.2 Proceeding from your result of Exercise 3.1 , what are the difficulties in determining the odds
of a ray of light traveling from the sun to hit the picnic blanket and then entering a viewer’s
eye?
3.3 The color cyan can be represented in both the HSV and RGB color spaces as shown in
Figure3–4 . These two representations for cyan do not yield the same wavelength intensity
plots. How do they differ?
3.4 The vtkSphereSource class generates a polygonal model of a sphere. Using the examples at
the end of this chapter as starting points, create a program to display a white sphere. Set the
ambient and diffuse intensities to 0.5. Then add a for-loop to this program that adjusts the
3.14 Exercises 79
ambient and diffuse color of this sphere so that as the loop progresses, the diffuse color goes
from red to blue, and the ambient color goes from blue to green. You might also try adjusting
other lighting parameters such as specular color, ambient, diffuse, and specular intensity.
3.5 Using the vtkSphereSource as described in Exercise 3.4 , create a program to display the
sphere with a light source positioned at (1,1,1). Then extend this program by adding a for-
loop that will adjust the active camera’s clipping range so that increasing portions of the inte-
rior of the sphere can be seen. By increasing the first value of the clipping range, you will be
adjusting the position of the front clipping plane. Once the front clipping plane starts inter-
secting the sphere, you should be able to see inside of it. The default radius of the
vtkSphereSource is 0.5, so make sure that you adjust the clipping range in increments less
than 1.0.
3.6 Modify the program presented in “Render a Cone ” on page62 so that the user can enter in a
world coordinate in homogenous coordinates and the program will print out the resulting dis-
play coordinate. Refer to the reference page for vtkRenderer for some useful methods.
a) Are there any world coordinates that you would expect to be undefined in display coordi-
nates?
b) What happens when the world coordinates are behind the camera?
3.7 Consider rasterizing a ten by ten pixel square. Contrast the approximate difference in the
number of arithmetic operations that would need to be done for the cases where it is flat,
Gouraud, or Phong shaded.
3.8 When using a z-buffer, we must also interpolate the z-values (or depth) when rasterizing a
primitive. Working from Exercise 3.7 , what is the additional burden of computing z-buffer
values while rasterizing our square?
3.9 vtkTransform has a method GetOrientation() that looks at the resulting transformation matrix
built from a series of rotations and provides the single x, y, and z rotations that will reproduce
the matrix. Specify a series of rotations in a variety of orders and request the orientation with
GetOrientation() . Then apply the rotations in the same order that vtkActor does and verify
that the resulting 4 x 4 transformation matrix is the same.
3.10 vtkTransform , by default, applies new transformations at the right of the current transforma-
tion. The method PostMultiply() changes the behavior so that the transformations are applied
to the left.
a) Use vtkTransform to create a transform using a variety of transformation operators includ-
ing Scale() , RotateXYZ() , and Translate() . Then create the same matrix with
PostMultiplyOn() .
b) Applying rotations at the right of a series of transformations in effect rotates the object
about its own coordinate system. Use the rotations.tcl script to verify this. Can you
explain this?
c) Applying rotations at the left of a series of transformations in effect rotates the object about
the world coordinate system. Modify the rotations.tcl script to illustrate this. (Hint: you will
have to create an explicit transform with vtkTransform and set the actor’s transform with
SetUserMatrix() .)
80 Computer Graphics Primer
Chapter 4
4.1 Overview
Visualization transforms data into images that efficiently and accurately convey information about
the data. Thus, visualization addresses the issues of transformation and representation .
Transformation is the process of converting data from its original form into graphics primi-
tives, and eventually into computer images. This is our working definition of the visualization pro-
cess. An example of such a transformation is the process of extracting stock prices and creating an
x-y plot depicting stock price as a function of time.
Representation includes both the internal data structures used to depict the data and the
graphics primitives used to display the data. For example, an array of stock prices and an array of
times are the computational representation of the data, while the x-y plot is the graphical represen-
tation. Visualization transforms a computational form into a graphical form.
82 The Visualization Pipeline
A simple mathematical function for a quadric will clarify these concepts. The function
2 2 2
() ,,
Fxyz = a 0 x + a 1 y ++++++++
a2z a 3 xya 4 yza 5 xza 6 xa 7 ya 8 za 9 (4-1)
The functional model in Figure4–1 (b) illustrates the steps to create the visualization. The oval
blocks indicate operations (processes) we performed on the data, and the rectangular blocks repre-
sent data stores (objects) that represent and provide access to data. Arrows indicate the direction of
data movement. Arrows that point into a block are inputs; data flowing out of a block indicate out-
puts. The blocks also may have local parameters that serve as additional input. Processes that create
data with no input are called data source objects, or simply sources. Processes that consume data
with no output are called sinks (the are also called mappers because these processes map data to a
final image or output). Processes with both an input and an output are called filters .
The functional model shows how data flows through the system. It also describes the depen-
dency of the various parts upon one another. For any given process to execute correctly, all the
inputs must be up to date. This suggests that functional models require a synchronization mecha-
nism to insure that the correct output will be generated.
In the examples that follow we will frequently use a simplified representation of the functional
model to describe visualization processes ( Figure4–1 (c)). We will not explicitly distinguish
between sources, sinks, data stores, and process objects. Sources and sinks are implied based on the
number of inputs or outputs. Sources will be process objects with no input. Sinks will be process
objects with no output. Filters will be process objects with at least one input and one output. Inter-
mediate data stores will not be represented. Instead we will assume that they exist as necessary to
support the data flow. Thus, as Figure4–1 (c) shows, the Lines data store that the Outline object
generates ( Figure4–1 (b)) are combined into the single object Outline . We use oval shapes to repre-
sent objects in the visualization model.
4.1 Overview 83
Sample F(x,y,z)
Point Array
Line Contour
Sample F(x,y,z)
Line Contour
Process
Figure 4–2 Object model design choices. One basic choice is to combine processes and data stores
into a single object. This is the usual object-oriented choice. Another choice creates separate data
objects and process objects.
The functional model describes the flow of data in our visualization, the object model describes
which modules operate on it. But what are the objects in the system? At first glance, we have two
choices ( Figure4–2 ).
The first choice combines data stores (object attributes) with processes (object methods) into
a single object. In the second choice we use separate objects for data stores and processes. There is
actually a third alternative: a hybrid combination of these two choices.
The conventional object-oriented approach (our first choice above) combines data stores and
processes into a single object. This view follows the standard definition that objects contain a data
representation combined with procedures to operate on the data. One advantage of this approach is
that the processes, which are the data visualization algorithms, have complete access to the data
structures, resulting in good computational performance. But this choice suffers from several draw-
backs.
• From a user’s perspective, processes are often viewed as independent of data representation.
In other words, processes are naturally viewed as objects in the system. For example, we
often say we want to “contour” data, meaning creating lines or surfaces corresponding to a
constant data value. To the user it is convenient to have a single contour object to operate on
different data representations.
• We must duplicate algorithm implementation. As in the previous contouring example, if we
bind data stores and processes into a single object, the contour operation must be recreated
for each data type. This results in duplicating code even though the implementations of an
algorithm may be functionally and structurally similar. Modifying such algorithms also
means modifying a large amount of code, since they are implemented across many objects.
• Binding data stores and algorithms together results in complex, data dependent code. Some
algorithms may be much more complex than the data they operate on, with large numbers of
4.2 The Visualization Pipeline 85
instance variables and elaborate data structures. By combining many such algorithms with a
data store, the complexity of the object greatly increases, and the simple meaning of the
object becomes lost.
The second choice separates the data stores and processes. That is, one set of objects represents and
provides access to the data, while another set of objects implements all operations on the data. Our
experience shows that this is natural to users, although it may be considered unconventional to the
object-oriented purist. We also have found that the resulting code is simple, modular, and easy for
developers to understand, maintain, and extend.
One disadvantage to the second choice is that the interface between data representation and
process is more formal. Thus the interface must be carefully designed to insure good performance
and flexibility. Another disadvantage is that strong separation of data and process results in dupli-
cate code. That is, we may implement operations that duplicate algorithms and that cannot be con-
sidered strictly data access methods. One example of such a situation is computing data derivatives.
This operation is more than simple data access, so strictly speaking it doesn’t belong in the data
object methods. So to compute derivatives we would have to duplicate the code each time we
needed derivatives computed. (Or create a procedural library of functions or macros!)
As a result of these concerns we use the hybrid approach in the Visualization Toolkit . Our
approach is closest to the second choice described above, but we have selected a small set of critical
operations that we implement within the data objects. These operations have been identified based
on our experience implementing visualization algorithms. This effectively combines the first two
choices to receive the maximum benefit and fewest disadvantages of each.
Data Objects
Data objects represent information. Data objects also provide methods to create, access, and delete
this information. Direct modification of the data represented by the data objects is not allowed
except through formal object methods. This capability is reserved for process objects. Additional
methods are also available to obtain characteristic features of the data. This includes determining
the minimum and maximum data values, or determining the size or the number of data values in the
object.
Data objects differ depending upon their internal representation. The internal representation
has significant impact on the access methods to the data, as well as on the storage efficiency or
computational performance of process objects that interact with the data object. Hence, different
data objects may be used to represent the same data depending on demands for efficiency and pro-
cess generality.
86 The Visualization Pipeline
Process Objects
Process objects operate on input data to generate output data. A process object either derives new
data from its inputs, or transforms the input data into a new form. For example, a process object
might derive pressure gradient data from a pressure field or transform the pressure field into con-
stant value pressure contours. The input to a process object includes both one or more data objects
as well as local parameters to control its operation. Local parameters include both instance vari-
ables or associations and references to other objects. For example, the center and radius are local
parameters to control the generation of sphere primitives.
Process objects are further characterized as source objects , filter objects , or mapper objects .
This categorization is based on whether the objects initiate, maintain, or terminate visualization
data flow.
Source objects interface to external data sources or generate data from local parameters.
Source objects that generate data from local parameters are called procedural objects. The previous
example of Figure4–1 uses a procedural object to generate function values for the quadric function
of Equation4-1 . Source objects that interface to external data are called reader objects since the
external file must be read and converted to an internal form. Source objects may also interface to
external data communication ports and devices. Possible examples include simulation or modelling
programs, or data acquisition systems to measure temperature, pressure, or other similar physical
attributes.
Filter objects require one or more input data objects and generate one or more output data
objects. Local parameters control the operation of the process object. Computing weekly stock
market averages, representing a data value as a scaled icon, or performing union set operations on
two input data sources are typical example processes of filter objects.
Mapper objects correspond to the sinks in the functional model. Mapper objects require one
or more input data objects and terminate the visualization pipeline data flow. Usually mapper
objects are used to convert data into graphical primitives, but they may write out data to a file or
interface with another software system or devices. Mapper objects that write data to a computer file
are termed writer objects.
Pipeline Connections
The elements of the pipeline (sources, filters, and mappers) can be connected in a variety of ways to
create visualization networks. However, there are two important issues that arise when we try to
assemble these networks: type and multiplicity .
Type means the form or type of data that process objects take as input or generate as output.
For example, a sphere source object may generate as output a polygonal or faceted representation,
an implicit representation (e.g., parameters of a conic equation), or a set of occupancy values in a
discretized representation of 3D space. Mapper objects might take as input polygonal, triangle strip,
line, or point geometric representations. The input to a process object must be specified correctly
for successful operation.
4.3 Pipeline Topology 87
Input Type
Process Object
Output Type
Figure 4–3 Maintaining compatible data type. (a) Single-type systems require no type checking. (b)
In multiple-type systems only compatible types can be connected together.
There are two general approaches to maintain proper input type. One approach is to design
with type-less or single-type systems. That is, create a single type of data object and create filters
that operate only on this one type ( Figure4–3 (a)). For example, we could design a general DataSet
that represents any form of data that we’re interested in, and the process objects would only input
DataSets and generate DataSets . This approach is simple and elegant, but inflexible. Often, partic-
ularly useful algorithms (i.e., process objects) will operate only on specific types of data and gener-
alizing them results in large inefficiencies in representation or data access. A typical example is a
data object that represents structured data such as pixmaps or 3D volumes. Because the data is
structured it can easily be accessed as planes or lines. However, a general representation will not
include this capability since typically data is not structured.
Another approach to maintain proper input type is to design typed systems ( Figure4–3 (b)).
In typed systems only objects of compatible type are allowed to be connected together. That is,
more than one type is designed, but type checking is performed on the input to insure proper con-
nection. Depending on the particular computer language, type checking can be performed at com-
pile, link, or run time. Although type checking does insure correct input type, this approach often
suffers from an explosion of types. If not careful, the designers of a visualization system may create
too many types, resulting in a fragmented, hard to use and understand system. In addition, the sys-
tem may require a large number of type-converter filters. (Type-converter filters serve only to
transform data from one form to another.) Carried to extremes, excessive type conversion results in
computationally and memory wasteful systems.
The issue of multiplicity deals with the number of input data objects allowed, and the number
of output data objects created during the operation of a process object ( Figure4–4 ). We know that
all filter and mapper objects require at minimum one input data object, but in general these filters
can operate sequentially across a list of input. Some filters may naturally require a specific number
of inputs. A filter implementing boolean operations is one example. Boolean operations such as
union or intersection are implemented on data values two at a time. However, even here more than
two inputs may be defined as a recursive application of the operation to each input.
88 The Visualization Pipeline
Figure 4–4 Multiplicity of input and output. (a) Definition of source, filter, and mapper objects. (b)
Various types of input and output.
We need to distinguish what is meant by multiplicity of output. Most sources and filters gen-
erate a single output. Multiple fan-out occurs when an object generates an output that is used for
input by more than one object. This would occur, for example, when a source object is used to read
a data file, and the resulting data is used to generate a wireframe outline of the data, plus contours
of the data (e.g., Figure4–1 (a)). Multiple output occurs when an object generates two or more out-
put data objects. An example of multiple output is generating x, y, and z components of a gradient
function as distinct data objects. Combinations of multiple fan-out and multiple output are possible.
Loops
In the examples described so far, the visualization networks have been free of cycles. In graph the-
ory these are termed directed, acyclic graphs. However, in some cases it is desirable to introduce
feedback loops into our visualization networks. Feedback loops in a visualization network allow us
to direct the output of a process object upstream to affect its input.
Figure4–5 shows an example of a feedback loop in a visualization network. We seed a
velocity field with an initial set of random points. A probe filter is used to determine the velocity
(and possibly other data) at each point. Each point is then repositioned in the direction of its associ-
ated vector value, possibly using a scale factor to control the magnitude of motion. The process
continues until the points exit the data set or until a maximum iteration count is exceeded.
4.4 Executing the Pipeline 89
Create sample
points
Figure 4–5 Looping in a visualization network. This example implements linear integration. The
sample points are created to initialize the looping process. The output of the integration filter is used in
place of the sample points once the process begins.
We will discuss the control and execution of visualization networks in the next section. How-
ever, suffice it to say that loops can pose special problem in visualization networks depending on
the design of the execution model. The design must insure that the loop does not enter an infinite
loop or nonterminating recursive state. Typically, the number of executions of the loop is limited in
order to view intermediate results. However, it is possible to execute the loop repeatedly to process
data as required.
C G
A B D modified
D E
Figure 4–6 Network execution. Parallel branches need not execute if changes are local
to a particular branch.
without intermediate computation (i.e., data is processed only after the request for data is received).
The demand-driven approach minimizes computation and results in more interactive visualization
networks.
The execution of the network requires synchronization between process objects. We want to
execute a process object only when all of its input objects are up to date. There are generally two
ways to synchronize network execution: explicit or implicit control ( Figure4–7 ).
Explicit Execution
Explicit control means directly tracking the changes to the network, and then directly controlling
the execution of the process objects based on an explicit dependency analysis. The major character-
istic of this approach is that a centralized executive is used to coordinate network execution. This
executive must track changes to the parameters and inputs of each object, including subsequent
changes to the network topology ( Figure4–7 (a)).
The advantage of this approach is that synchronization analysis and update methods are local
to the single executive object. In addition, we can create dependency graphs and perform analysis
of data flow each time output is requested. This capability is particularly important if we wish to
decompose the network for parallel computing or to distribute execution across a network of com-
puters.
The disadvantage of the explicit approach is that each process object becomes dependent
upon the executive, since the executive must be notified of any change. Also, the executive cannot
easily control execution if the network execution is conditional, since whether to execute or not
depends on the local results of one or more process objects. Finally, a centralized executive can cre-
ate non-scalable bottlenecks in parallel computing environments.
The explicit approach may be either demand-driven or event-driven. In the event-driven
approach, the executive is notified whenever a change to an object occurs (typically in response to
a user-interface event), and the network is immediately executed. In the demand-driven approach,
the executive accumulates changes to object inputs and executes the network based on explicit user
4.4 Executing the Pipeline 91
A A
Executive
B B
C D C D
E E
demand.
The explicit approach with a central executive is typical of many commercial visualization
systems such as AVS, Irix Explorer, and IBM Data Explorer. Typically these systems use a visual-
programming interface to construct the visualization network. Often these systems are imple-
mented on parallel computers, and the ability to distribute computation is essential.
Implicit Execution
Implicit control means that a process object executes only if its local input or parameters change
(Figure4–7 (b)). Implicit control is implemented using a two-pass process. First, when output is
requested from a particular object, that object requests input from its input objects. This process is
recursively repeated until source objects are encountered. The source objects then execute if they
have changed or their external inputs have changed. Then the recursion unwinds as each process
object examines its inputs and determines whether to execute. This procedure repeats until the ini-
tial requesting object executes and terminates the process. These two steps are called the update
and execution passes.
Implicit network execution is naturally implemented using demand-driven control. Here net-
work execution occurs only when output data is requested. Implicit network execution may also be
event-driven if we simply request output each time an appropriate event is encountered (such as
92 The Visualization Pipeline
Data Range?
Figure 4–8 Examples of conditional execution. Depending upon range, data is mapped through dif-
ferent color lookup tables.
Conditional Execution
A executes A executes
B executes A B executes
C executes A releases memory
D executes C executes
B releases memory
B A re-executes
B re-executes
A releases memory
D executes
C D B releases memory
B releases memory.
Static model Dynamic model
Figure 4–9 Comparison of static versus dynamic memory models for typical network. Execution
begins when output is requested from objects C and D . In more complex dynamic models, we can pre-
vent B from executing twice by performing a more thorough dependency analysis.
requirements. Data streams on the order of one megabyte to one gigabyte are not uncommon. Many
visualization algorithms are computationally expensive, in part due to input size, but also due to the
inherent algorithm complexity. In order to create applications that have reasonable performance,
most visualization systems have various mechanisms to trade off memory and computation costs.
Memory and computation trade-offs are important performance issues when executing visualiza-
tion networks. In the networks presented thus far, the output of a process object is assumed to be
available to downstream process objects at all times. Thus, network computation is minimized.
However, the computer memory requirement to preserve filter output can be huge. Networks of
only a few objects can tie up extensive computer memory resources.
An alternative approach is to save intermediate results only as long as they are needed by
other objects. Once these objects finish processing, the intermediate result can be discarded. This
approach results in extra computation each time output is requested. The memory resources
required are greatly reduced at the expense of increased computation. Like all trade-offs, the proper
solution depends upon the particular application and the nature of the computer system executing
the visualization network.
We term these two approaches as static and dynamic memory models. In the static model
intermediate data is saved to reduce overall computation. In the dynamic model intermediate data is
discarded when it is no longer needed. The static model serves best when small, variable portions
of the network reexecute, and when the data sizes are manageable by the computer system. The
dynamic model serves best when the data flows are large, or the same part of the network executes
each time. Often, it is desirable to combine both the static and dynamic models into the same net-
work. If an entire leg of the network must execute each time, it makes no sense to store intermedi-
ate results, since they are never reused. On the other hand, we may wish to save an intermediate
result at a branch point in the network, since the data will more likely be reused. A comparison of
the static and dynamic memory model for a specific network is shown in Figure4–9 .
94 The Visualization Pipeline
As this figure shows, the static model executes each process object only once, storing inter-
mediate results. In the dynamic model, each process object releases memory after downstream
objects complete execution. Depending upon the implementation of the dynamic model, process
object B may execute once or twice. If a thorough dependency analysis is performed, process B
will release memory only after both objects C and D execute. In a simpler implementation, object B
will release memory after C and subsequently, D executes.
Another valuable tool to minimize memory cost is to share storage using reference counting. To use
reference counting, we allow more than one process object to refer to the same data object and keep
track of the number of references. For example, assume that we have three objects A, B, and C that
form a portion of a visualization network as shown in Figure4–10 . Also assume that these objects
modify only part of their input data, leaving the data object that specifies x-y-z coordinate position
unchanged. Then to conserve memory resources we can allow the output of each process object to
refer to the single data object representing these points. Data that is changed remains local to each
filter and is not shared. It is only when the reference count goes to zero that the object is deleted.
Garbage collection is an alternative memory management strategy that is not well suited to
visualization applications. The garbage collection process is automatic; it attempts to reclaim mem-
ory used by objects that will never again be accessed by the running application. While convenient
due to its automated nature, in general garbage collection introduces overhead that may inadvert-
ently introduce pauses into software execution at inopportune times (during an interactive process).
Of more concern, however, is that released, unused memory may not be reclaimed by the system
until some time after the last reference to the memory is dropped, and in visualization pipelines this
memory may be too large to leave around for any length of time. That is, in some applications if
memory usage in a filter is not released immediately, downstream filters may not have enough
memory resource available to them to successfully execute.
4.6 Advanced Visualization Pipeline Models 95
metadata is a obvious design, and is compatible with the design described in the previous section.
Examples of metadata include time step information, data ranges or other data characteristics,
acquisition protocols, patient names, and annotation. In an extensible visualization pipeline, a spe-
cific data reader (or other data source) may read such information and associate it with the output
data that it produces. While many filters may ignore the metadata, they can be configured to pass
the information along the pipeline. Alternatively, a pipeline sink (or mapper) may request that spe-
cific metadata be passed through the pipeline so it can be processed appropriately. For example, a
mapper may request annotations, and if available, place them on the final image.
1. Separable. The data must be separable. That is, the data can be broken into pieces. Ideally,
each piece should be coherent in geometry, topology, and/or data structure. The separation of
the data should be simple and efficient. In addition, the algorithms in this architecture must
be able to correctly process pieces of data.
2. Mappable. In order to control the streaming of the data through a pipeline, we must be able
to determine what portion of the input data is required to generate a given portion of the out-
put. This allows us to control the size of the data through the pipeline, and configure the algo-
rithms.
3. Result Invariant. The results should be independent of the number of pieces, and indepen-
4.6 Advanced Visualization Pipeline Models 97
dent of the execution mode (i.e., single- or multi-threaded). This means proper handling of
boundaries and developing algorithms that are multi-thread safe across pieces that may over-
lap on their boundaries.
Separating data into pieces is relatively straightforward if the data is structured, i.e., topologically
regular (see “Types of Datasets ” on page134 ). Such datasets can be topological described by a rect-
angular extent in a regularly x-y-z subdivided cubical domain (see Figure5–7 (a)-(c)). However, if
the data is unstructured (e.g. a mesh of triangles or polygons), then specifying pieces is difficult.
Generally an unstructured extent is defined by grouping adjacent data (e.g., cells) into pieces, and
then addressing each piece using a N of M notation, where N is the n th piece out of a total of M
pieces. The exact organizational structure of a piece is left unspecified and depends on the particu-
lar application and algorithm used to group the data.
To satisfy the third requirement of results invariancy, processing pieces also requires the abil-
ity to generate boundary data, or ghost levels . Boundary information is necessary when information
from the neighbors of a piece is needed to perform a computation. For example, gradient calcula-
tions or boundary analysis (e.g., do I have a cell face neighbor?) require one level of boundary
information. In rare cases, two or more levels are required. Figure4–11 illustrates boundary cells
and points corresponding to the central red piece of the sphere.
Finally, it should be noted that the ability to divide data into pieces for streaming is exactly
the same capability required for data parallel processing. In such methods, data is subdivided and
sent to different processors to be operated on in parallel. Boundary information may also be
required to perform certain computations. Parallel processing has the added complexity that the
data must be communicated to processors (in the case of distributed computing) or mutual exclu-
sion (i.e., mutexing) must be employed to avoid simultaneous write operations. Thus streaming and
parallel processing are complementary technologies used in large data computing.
Complex Execution Strategies. In many cases the simple execution model of Figure4–7 (b) is not
suitable for complex data processing tasks. For example, as discussed in the previous section,
streaming data is a complex execution strategy required when a dataset becomes too large to fit into
memory, or when parallel computing is used. In some cases event-driven (see “Executing the Pipe-
line” on page89 ) or “push” pipelines (i.e., those that receive data and push the data through the
pipeline for processing) may be preferred. Finally, there exist hierarchical data structures such as
multi-block or adaptive mesh refinement (AMR) [Berger84] grids. Processing such datasets in a
pipeline requires hierarchical traversal as filters process each block in the grid (an advanced
research topic in the visualization field and not covered in this edition of the book).
Addressing these requirements implies that the execution model must be extended. Thus we
revisit the object-oriented design in the next section.
Object-Oriented Design Revisited. Figure4–2 illustrates two choices relative to the design of the
visualization object model. The first choice, which was discarded, was to combine data and opera-
tions on the data into a single object, a typical object-oriented design pattern. The second choice,
which was advocated, was to create a design consisting of two classes—data objects and process
objects—which were then combined into visualization pipelines. While this second strategy works
well for simple pipelines, when complex execution strategies are introduced, this design begins to
break down. This is because the execution strategy is necessarily, and implicitly, distributed across
the data objects and process objects; there is no explicit mechanism to implement a particular strat-
98 The Visualization Pipeline
egy. Thus the design is problematic because new strategies cannot be introduced without modifying
the interface to both the data and process objects. Good design demands that the execution strategy
is separated from the data objects and process objects. The benefits of such a design include reduc-
ing the complexity of the data and process objects, encapsulating execution strategies, performing
run-time type checking (see “Processing Unknown Dataset Types ” on page95 ) and even managing
metadata (see “Extending the Data Object Representation ” on page95 ).
The advanced design re-introduces the notion of
Process Object Data Object
an executive (see “Executing the Pipeline ” on page89 ).
However, the design differs from that of Figure4–7 . As
that figure illustrated, a single, centralized executive
introduces dependencies into the pipeline that will not
scale as pipeline complexity increases, or in parallel
Executive
processing applications. In the advanced design, we
assume multiple executives, typically one per filter. In
some cases the executive may control multiple filters. Process Object Data Object
This is particularly useful if the filters are interdepen-
dent or complex execution strategies are required. Dif-
ferent classes of executive can implement different Figure 4–12 As the execution model
execution strategies, for example a demand-driven, becomes more complex, execution strate-
gies are separated from the data and pro-
streaming pipeline is one such strategy. Other important cess objects as separate classes.
classes include executives that coordinate the execution
of filters on composite datasets.
Figure4–12 is a high-level view of the executive and its relationship to data and process
objects. In “Pipeline Design and Implementation ” on page103 the design is explored in more detail.
Visualization Models
At the highest level are applications. Visualization applications have finely tailored user-interfaces
that are specific to an application area, e.g., fluid flow visualization. Applications are the easiest to
use, but are the least flexible. It is very difficult or impossible for the user to extend applications
into a new domain because of inherent logistical issues. Commercial turn-key visualization soft-
ware is generally considered to be application software.
At the opposite end of the spectrum are programming libraries. A conventional programming
library is a collection of procedures that operate on a library-specific data structure. Often these
libraries are written in conventional programming languages such as C or FORTRAN. These offer
great flexibility and can be easily combined with other programming tools and techniques. Pro-
gramming libraries can be extended or modified by the addition of user-written code. Unfortu-
nately, the effective use of programming libraries requires skilled programmers. Furthermore, non
4.7 Programming Models 99
graphics/visualization experts cannot easily use programming libraries because there is no notion
of how to fit (or order) the procedures together correctly. These libraries also require extensive syn-
chronization schemes to control execution as input parameters are varied.
Many visualization systems lie between these two extremes. These typically use a visual pro-
gramming approach to construct visualization networks. The basic idea is to provide graphical tools
and libraries of modules or process objects. Modules may be connected subject to input/output type
constraints, using simple graphical layout tools. In addition, user interface tools allow association
of interface widgets with object input parameters. System execution is generally transparent to the
user by way of an internal execution executive.
There are two other graphics and visualization programming models that bear mentioning. These
are scene graphs and the spreadsheet model.
Scene graphs are typically found in 3D graphics systems such as OpenInventor
[Wernecke94] . Scene graphs are acyclic tree-structures that represent objects, or nodes, in an order
defined by the tree layout. The nodes may be geometry (called shape nodes), graphics properties,
transformations, manipulators, lights, cameras, and so forth, that define a complete scene. The par-
ent/child relationship controls how properties and transformations are applied to the nodes as they
are rendered, or how the objects relate to other objects in the scene (e.g., which objects the lights
shine on). Scene graphs are not used to control the execution of a visualization pipeline, rather they
are used to control the rendering process. Scene graphs and visualization pipelines may be used
together in the same application. In such a case the visualization pipeline is the generator of the
shape nodes, and the scene graph controls the rendering of the scene including the shapes.
Scene graphs have found wide use in the graphics community because of their ability to com-
pactly and graphically represent a scene. In addition, scene graphs have been popularized by their
recent use in Web tools such as VRML and Java3D. See Chapter 11 for more information.
Another recently introduced technique for visual programming is the spreadsheet technique
of Levoy [Levoy94] . In the spreadsheet model, we arrange operations on a regular grid similar to the
common electronic accounting spreadsheets. The grid consists of rows and columns of cells, where
each cell is expressed as a computational combination of other cells. The combination is expressed
for each cell by using a simple programming language to add, subtract, or perform other more com-
plex operations. The result of the computation (i.e., a visual output) is displayed in the cell. A
recent extension to the spreadsheet approach is exemplified by VisTrails [Bavoil2005] , a system that
enables interactive multiple-view visualizations by simplifying the creation and maintenance of
visualization pipelines, and by optimizing the execution of the pipelines. VisTrials has the further
benefit that it tracks changes to the visualization pipeline so that it is straightforward to create
extensive design studies.
Although visual programming systems are widely successful, they suffer two drawbacks.
First, they are not as tailored as an application and require extensive programming, albeit visual, to
be so. Second, visual programming is too limited for detailed control, so constructing complex low-
level algorithms and user-interfaces is not feasible. What is required is a visualization system that
provides the “modularity” and automatic execution control of a visual system, and the low-level
programming capability of a programming library. Object-oriented systems have the potential to
provide these capabilities. Carefully crafted object libraries provide the ease of use of visual sys-
100 The Visualization Pipeline
tems with the control of programming libraries. That is a major goal of the Visualization Toolkit
described in this text.
Programming Interface
The most powerful and flexible approach is to directly program your application to read, write, and
process data. There is almost no limit to what you can achieve using this approach. Unfortunately,
in a complex system like VTK this requires a level of expertise that may be beyond your time bud-
get to obtain. (If you are interested in this approach using VTK, you’ll have to become familiar
with the objects in the system. You will also want to refer to the Doxygen-generated manual pages
—on-line at http://www.vtk.org or CD-ROM. The companion text The VTK User’s Guide is
also helpful.)
Typical applications requiring a programming interface are interfacing to data files that are
not currently supported by the system or generating synthetic data (e.g., from a mathematical rela-
tionship) where no data file is available. Also, sometimes it is useful to directly code your data in
the form of a program, and then execute the program to visualize the results. (This is exactly what
many of the VTK examples do.)
In general, programming a complex system such as VTK is a difficult undertaking because of
the initial learning curve. There are, however, simpler ways to interface to data. While skilled
developers may be required to create sophisticated applications, the points of an object-oriented
toolkit like VTK is that it provides many of the pieces required to interface to common data forms.
Thus focusing on those objects that import and export data is a good start towards interfacing with
data. In VTK, these objects are known as readers, writers, importers and exporters.
File Interface (Readers / Writers). In this chapter we saw that readers are source objects, and
writers are mappers. What this means from a practical point of view is that readers will ingest data
from a file, create a data object, and then pass the object down the pipeline for processing. Simi-
larly, writers ingest a data object and then write the data object to a file. Thus, readers and writers
will interface to your data well if VTK supports your format, and you only need to read or write a
single data object. If your data file format is not supported by the system, you will need to interface
to your data via a general programming interface described above. Or, if you wish to interface to a
collection of objects, you will probably want to see whether an exporter or importer object
(described in the next section) exists to support your application.
Examples of readers include vtkSTLReader (read stereo-lithography files) and
vtkBYUReader (read MOVIE.BYU format data files). Similarly the objects vtkSTLWriter and
vtkBYUWriter can be used to write data files. To see which readers and writers are supported by
4.9 Putting It All Together 101
VTK, see the VTK User’s Guide or refer to the Web pages at http://www.vtk.org for the cur-
rent Doxygen manual pages.
File Interface (Importers / Exporters). Importers and exporters are objects in the system that
read or write data files consisting of more than one object. Typically importers and exporters are
used to save or restore an entire scene (i.e., lights, cameras, actors, data, transformations, etc.).
When an importer is executed, it reads one or more files and may create several objects. For exam-
ple, in VTK the vtk3DSImporter imports a 3D Studio file and creates a rendering window, renderer,
lights, cameras, and actors. Similarly, the vtkVRMLExporter creates a VRML file given a VTK
render window. The VRML file contains cameras, lights, actors, geometry, transformations, and the
like, indirectly referred to by the rendering window provided.
In the Visualization Toolkit , there are several importers and exporters. To see which importers
and exporters are supported by VTK, see the VTK User’s Guide . You may also want to check the
Web pages at http://www.vtk.org for the current Doxygen manual pages. If the exporter you
are looking for does not exist, you will have to develop your own using the programming interface.
Figure4–13 shows an image created from a 3D Studio model and saved as a Renderman RIB file.
Application Interface
The majority of users interface to their data by using an existing application. Rather than program-
ming pipelines or writing their own readers and writers, users acquire an application that suits their
particular visualization needs. Then to interface to their data, users simply identify the reader,
writer, importer, and/or exporter that can successfully process it. In some cases, users may have to
modify the program used to generate the data so that it exports it in a standard data format. The
advantage of using existing applications is that the user interface and pipeline are pre-programmed,
insuring that the user can focus on their data, rather than expending the significant resources
required to write visualization programs. The disadvantage of using existing applications is that
necessary features are often missing, and applications typically lack the flexibility that a general
purpose tool can provide.
Selecting the right application is not always simple. The application must support the correct
dataset types, and support suitable rendering devices, for example generating images on large dis-
plays [Humphreys99] or in a Cave [CruzNeira93] environment. In some cases user interaction is
required, and demands on parallel processing or data handling capacities further complicates the
selection. For example, while a general purpose tool like ParaView ( Figure4–14 (a)) can be used to
visualize most types of data, including providing support for large data and parallel computing, a
specialized tool such as VolView ( Figure4–14 (b)) may be better suited for the a particular type
task such as viewing medical data shown in the figure. It is imperative that users have a familiarity
with the visualization process if they are to successfully choose the right application for their data.
iflamigm.3ds
vtk3DSImporter
vtkRIBExporter
importExport.rib
Figure 4–13 Importing and exporting files in VTK. An importer creates a vtkRenderWindow that
describes the scene. Exporters use an instance of vtkRenderWindow to obtain a description of the
scene ( 3dsToRIB.tcl and flamingo.tcl ).
The Visualization Toolkit is implemented in the procedural language C++. Automated wrapping
technology creates language bindings to the Python, Tcl and Java interpretive programming lan-
guages [King03] . The class library contains data objects, filters (i.e., process objects) and executives
to facilitate the construction of visualization applications. A variety of supporting abstract super-
classes are available to derive new objects including data objects and filters. The visualization pipe-
line is designed to connect directly to the graphics subsystem described in the previous chapter.
This connection is via VTK’s mappers, which are the sinks of the pipeline and interface to the
VTK’s actors.
A visual programming interface could be (and has been) implemented using the class library
provided. However, for real-world applications the procedural language implementation provides
several advantages. This includes straightforward implementation of conditional network execution
and looping, ease of interface to other systems, and the ability to create custom applications with
sophisticated graphical user interfaces. The VTK community has created several visual program-
4.9 Putting It All Together 103
(b) ParaView parallel visualization application. (b) VolView volume rendering application.
Figure 4–14 The choice of an appropriate visualization application depends on the type of
dataset(s) it must support, required interaction techniques, rendering capabilities, and support for
large data, including parallel processing. While both applications above are built using the VTK
visualization toolkit, they provide very different user experiences. ParaView (paraview.org) is a
general purpose visualization system that can process large data in a distributed, parallel envi-
ronment (as well as on single processor systems), with the ability to display on a Cave or tiled
display. VolView (volview.com) focuses on volumetric and image data and uses multi-threading
and sophisticated level-of-detail methods to achieve interactive performance.
ming and visualization applications from the toolkit. Many of these are available as open-source
software (e.g., ParaView at paraview.org) or as commercial applications (e.g., VolView at
www.volview.com).
The Visualization Toolkit implements a general execution mechanism. Filters are divided into two
basic parts: algorithm and executive objects. An algorithm object, whose class is derived from
vtkAlgorithm , is responsible for processing information and data. An executive object, whose class
is derived from vtkExecutive , is responsible for telling an algorithm when to execute and what
information and data to process. The executive component of a filter may be created independently
of the algorithm component allowing custom pipeline execution mechanisms without modifying
core VTK classes.
Information and data produced by a filter are stored in one or more output ports. An output
port corresponds to one logical output of the filter. For example, a filter producing a color image
and a corresponding binary mask image would define two output ports, each holding one of the
images. Pipeline-related information is stored in an instance of vtkInformation on each output port.
The data for an output port is stored in an instance of a class derived from vtkDataObject .
Information and data consumed by a filter are retrieved through one or more input ports. An
input port corresponds to one logical input of the filter. For example, a glyph filter would define
one input port for the glyph itself and another input port defining the glyph positions. Input ports
store input connections that reference the output ports of other filters; these output ports eventually
provide information and data to the filter. Each input connection provides one data object and its
corresponding information obtained from the output port to which the connection is made. Since
connections are stored through logical ports and not in the data flowing through those ports, the
data type need not be known when the connection is made. This is particularly useful when creating
104 The Visualization Pipeline
Figure 4–15 Description of implicit execution process implemented in VTK. The Update()
method is initiated via the Render() method from the actor. Data flows back to the mapper via
the RequestData() method. Arrows connecting filter and data objects indicate direction of the
Update() process.
pipelines whose source is a reader that does not know its output data type until the file is read (see
“Pipeline Connections ” on page86 and “Processing Unknown Dataset Types ” on page95 ).
To understand the execution of the VTK pipeline, it is useful to view the process from several
different vantage points. Note that each of the following figures is not completely accurate, rather
they are presented as depictions whose purpose is to describe the important features of the process.
Figure4–15 shows a simplified description of VTK’s execution process. Generally the exe-
cution of the pipeline is triggered by a mapper’s Render() method invocation, typically in response
to a Render() method invocation on an associated vtkActor (which in turn receives it from the
render window). Next, the Update() method is called on the input to the mapper (resulting in a
cascade of method invocations requesting information and data). Eventually, data must be
computed and returned to the object initiating the request, in this case the mapper. The
RequestData() method actually executes the filter(s) in the pipeline and produces output data. Note
the direction of flow—here we define the direction of data flow as the downstream direction, and
the direction of the Update() invocation the upstream direction.
The next figure, Figure4–16 , shows the relationship between the executive and the algo-
rithm, which are paired to form a filter. This view of the filter is independent of the pipeline and
contains all the information about the interface of the algorithm, namely the number and availabil-
ity of inputs and outputs. Finally Figure4–17 shows the connections between filters. Notice that
the output data object is not directly wired to the input connection. Rather the downstream filters’s
input connection is associated with the upstream filter’s output port. This separation of data object
from the input port means that data type checking can be deferred until run-time, when the consum-
ing filter requests data from the producer of the data. Thus the producer can generate different types
of data (e.g., it is a reader that produces different data types), and as long as the consumer supports
these different data types, the pipeline will execute without error.
4.9 Putting It All Together 105
Algorithm
Input Port Output Port
Information
Input Port Output Port
Information Parameters Information
... ...
Executive
Filter
Figure 4–16 The logical relationship of the algorithm, executive and ports constituting a filter. The
executive is responsible for managing the execution of the algorithm, and coordinating with informa-
tion requests traveling through the pipeline. Ports correspond to logical, distinct inputs and outputs.
This leads us to the method of making connections between filters and data objects to form a visu-
alization pipeline. As is evident from the previous figures, the Visualization Toolkit pipeline archi-
tecture has been designed to support multiple inputs and outputs. In practice, you will find that
most filters and sources actually generate a single output and filters accept a single input. This is
because most algorithms tend to be single input/output in nature. There are exceptions and we will
describe some of these shortly. However, first we would like to provide a brief history lesson rela-
tive to the evolution of VTK’s pipeline architecture. This lesson is instructive because it sheds light
on the evolution of the pipeline design in response to new requirements.
Prior to VTK 5.0. In earlier versions of VTK (i.e., prior to version 5.0), the visualization pipeline
architecture was accurately depicted by Figure4–15 . In this figure, which shows how filters and
data objects were connected to form a visualization network, the input data was represented by the
Input instance variable and was set using the SetInput() method. The output data was represented
by the Output instance variable and was accessed using the GetOutput() method. To connect filters
together, the C++ statement
was typically used with filter1 and filter2 filter objects of compatible type. In this design, compile-
time type checking was performed (i.e., the C++ compiler would enforce proper type.) Obviously,
this meant that correcting filters together producing output of unknown type was problematic. Sev-
eral other issues with this design remained as well, many of which have been alluded to earlier, but
are summarized here to motivate the use of the newer pipeline architecture.
106 The Visualization Pipeline
Data Object
Producer Consumer
Input
Output Port
Connections
Algorithm Output Input Algorithm
Pipeline Pipeline
Information Information
... ...
Executive Executive
Data Object
Another Filter
Figure 4–17 The logical relationship of ports and connections An input port may have more than
one connection associated with it. Multiple connections are possible in certain filters such as the
append filter, where a single logical input port represents all the data to be “appended” together, and
each input is represented by a different connection.
• The older design did not support deferred dataset type checking. It was difficult to support
arbitrary reader types or filters that could produce different types of output.
• The strategy for updating and managing the execution of the pipeline were implicitly embed-
ded in the process objects and data objects. As the strategy became more complex, or needed
to change, this required modifying data and/or process objects.
• In the older design it was difficult to abort pipeline execution during an update pass. Further,
it was not possible to centralize the error checking; each filter had to do some checking
thereby duplicating code.
• Introducing metadata into the pipeline required changing the API to the data and process
objects. It was desirable to support the ability of a reader to add metadata to a data stream and
have a filter in the pipeline retrieve it, without having to modify the API.
For this, and other reasons related to parallel processing, the original VTK pipeline design was
reworked. While the transition was difficult, such changes are often necessary if a software system
is to change and grow with advances in technology.
VTK 5.0 and Beyond. While VTK 5.0 still supports the use of SetInput()/GetOutput(), its use is
discouraged. Rather, the newer pipeline architecture should be used. Referring to Figure4–16 and
Figure4–17 , we use connections and ports to configure VTK’s visualization pipeline:
4.9 Putting It All Together 107
You probably have already guessed how this approach can be extended to multiple inputs and mul-
tiple outputs. Let’s look at some concrete examples.
vtkGlyph3D is an example of a filter that accepts multiple inputs and generates a single out-
put. The inputs to vtkGlyph3D are represented by the Input and Source instance variables. The pur-
pose of vtkGlyph3D is to copy the geometry defined by the data in Source to each point defined by
Input. The geometry is modified according to the Source data values (e.g., scalars and vectors).
(For more information about glyphs see “Glyphs ” on page190 .) To use the vtkGlyph3D object in
C++ code you would do the following:
glyph = vtkGlyph3D::New();
glyph->SetInputConnection(foo->GetOutputPort());
glyph->SetSourceConnection(bar->GetOutputPort());
...
where foo and bar are filters returning the appropriate type of output.
The class vtkExtractVectorComponents is an example of a filter with a single input and mul-
tiple outputs. This filter extracts the three components of a 3D vector into separate scalar compo-
nents. Its three outputs are available on output ports 0, 1, and 2. An example use of the filter
follows:
vz = vtkExtractVectorComponents::New();
foo = vtkDataSetMapper::New();
foo->SetInputConnection(vz->GetOutputPort(2));
...
Several other special objects having multiple inputs or outputs are also available. Some of the more
notable classes are vtkMergeFilter , vtkAppendFilter , and vtkAppendPolyData . These filters com-
bine multiple pipeline streams and generate a single output. Note, however, that while
vtkMergeFilter has multiple input ports (i.e., different logical inputs), vtkAppendFilter has only one
logical input, but presumes multiple connections are made to that one input. This is because in the
case of vtkMergeFilter , each input has a distinct and separate purpose, while in vtkAppendFilter all
the inputs have the same meaning (i.e., just one more input in a list to append together). Here are
some code fragments:
merge = vtkMergeFilter::New();
merge->SetGeometryConnection(foo->GetOutputPort());
merge->SetScalarsConnection(bar->GetOutputPort());
and
append = vtkAppendFilter::New();
append->AddInputConnection(foo->GetOutputPort());
append->AddInputConnection(bar->GetOutputPort());
Notice the use of the method AddInputConnection (). This method adds to the list of connections,
whereas SetInputConnection () clears the list and specifies the single connection to the port.
108 The Visualization Pipeline
Another important filtering class is vtkProbeFilter. This filter takes two inputs. The first input
is the data we wish to probe. The second input supplies a set of points that are used as probe points.
Some process objects take a list of input data. Another interesting filter is the
vtkBooleanStructuredPoints class which performs set operations on volume datasets. The first data
item in the list is used to initialize the set operation. Each subsequent item in the list is combined
with the result of previous operations using a boolean operation specified by the user.
For more details regarding the object design of filters and data objects, please see Chapter 5
and Chapter 6 .
Information Objects. Information objects are the basic containers used throughout the VTK pipe-
line to hold a wide variety of metadata. They are heterogeneous key-to-value maps in which the
type of the key determines the type of the value. The following is an enumeration of the places
information objects are used.
• Pipeline information objects hold information for pipeline execution. They are stored in
instances of vtkExecutive or subclasses and are accessible via the method
vtkExecutive::GetOutputInformation() . There is one pipeline information object per output
port. It contains an entry pointing to the output vtkDataObject on the corresponding port (if it
has been created). The vtkDataObject contains a pointer back to its corresponding pipeline
information object, accessible via vtkDataObject::GetPipelineInformation() . The pipeline
information object also holds information about what will populate the data object when the
filter executes and generates the output. The actual information contained is determined by
the output data type and the execution model in use. Pipeline information objects for input
connections are accessible via the method vtkExecutive::GetInputInformation() , and they are
the pipeline information objects on the output ports to which the input ports are connected.
• Port information objects hold information about the data types produced on output ports and
consumed by input ports. They are stored by instances of vtkAlgorithm . There is one input
port information object per input port and one output port information object per output port.
They are accessible via the methods vtkAlgorithm::GetInputPortInformation() and
vtkAlgorithm::GetOutputPortInformation() . Port information objects are usually created and
populated by subclasses of vtkAlgorithm in order to specify the interface of the filter.
• Request information objects hold information about a specific request being sent to an execu-
tive or algorithm. There is one entry indicating what request is being sent and possibly other
entries giving additional details about the specific request. These information objects are not
accessible via any public method but are passed to ProcessRequest() methods that implement
the requests.
• Data information objects hold information about what is currently stored in a vtkDataObject .
There is one data information object in each data object, accessible via
4.9 Putting It All Together 109
Figure 4–18 Path of a request sent through a pipeline. For example, assume the consumer (at the far right)
needs only a single piece of this data (e.g., piece 1 of 4); also assume that the producer (on the far left) is a
reader that can partition its data into pieces. The consumer passes this request upstream, and it continues
upstream (via executives) until it reaches a producer that can fulfill the request. When the reader algorithm is
asked for a piece of the data, it provides it, and passes the new data back (with the information that it is piece 1
of 4) down the pipeline. It stops when it reaches the consumer who made the request.
Pipeline Execution Models. In VTK, the fundamental pipeline update mechanism is based on the
request . A request is the basic pipeline operation (or "pipeline pass") that generally asks for partic-
ular piece of information to be propagated through the pipeline. An execution model is a set of
requests defined by a specific executive. Refer to Figure4–18 in the following description of the
execution process.
Requests are generated by the executive object of a filter that has been explicitly asked to
update by its algorithm due to some user call. For example, when the Write() method of a writer is
called, the algorithm object asks its executive to update the pipeline, and execute the writer, by call-
ing this->GetExecutive()->Update() . Several requests may be sent through the pipeline in order to
bring it up to date.
A request is implemented as an information object. There is one key of type
vtkInformationRequestKey specifying the request itself. This key is typically defined by the execu-
tive's class. Additional information about the request may also be stored in the request information
object.
110 The Visualization Pipeline
Requests are propagated through the pipeline by the executives of each filter. The
vtkExecutive::ProcessRequest() method is invoked on an executive given the request information
object. This method is implemented by each executive and is responsible for fulfilling the request
as it sees fit. Many requests may be fulfilled for a filter only after it has been fulfilled for the filters
providing its inputs. For these requests the executive will pass the request on to the executives of
these upstream filters and then handle the request itself.
An executive often asks its algorithm object for help in fulfilling a request. It sends the
request to the algorithm object by invoking the vtkAlgorithm::ProcessRequest() method. This
method is implemented by all algorithms and is responsible for handling the request. Input and out-
put pipeline information objects are provided as arguments to the method. The algorithm must han-
dle the request using only its own filter parameter settings and the pipeline information objects
given. An algorithm is not allowed to ask its executive for any additional information. This insures
that the algorithms are independent of the executives.
Figure4–18 shows a typical path taken by a request as it is sent through a pipeline. Typically
the request originates in a consumer at the end of the pipeline. It is sent back through the pipeline
by the executives. Each executive asks its algorithm to help handle the request.
By default, networks constructed using the Visualization Toolkit store intermediate computational
results (i.e., favor computation). However, a single class variable can be set to discard intermediate
data when they are no longer needed (i.e., favor memory). In addition, a local parameter can be set
within each process object to control this trade-off at object level.
This global variable is set as follows. Given the data object O, (or the output of a filter
obtained using O=filter->GetOutput() ), invoke O->SetGlobalReleaseDataFlagOn() to enable data
release. To enable data release for a particular object use O->SetReleaseDataFlagOn(). Appropriate
methods exist to disable memory release as well.
At this point in the text it is premature to describe design details of the various objects making up
the visualization pipeline. However, there are two important classes that affect many of the objects
in the text. These are the classes vtkObject and vtkObjectBase .
vtkObjectBase is the base object for almost all inheritance hierarchies found in VTK.
vtkObjectBase implements data object reference counting (see “Reference Counting & Garbage
Collection ” on page94 ). Subclasses of vtkObjectBase may be shared by other objects, without
duplicating memory. It also defines an API for objects to print information about themselves.
vtkObject is a subclass of vtkObjectBase . It provides methods and instance variables to con-
trol run-time debugging and maintains internal object modification time. In particular, the method
Modified() is used to update the modification time, and the method GetMTime() is used to retrieve
it. vtkObject also provides a framework for the event callbacks that we saw in the previous chapter
(see “Events and Observers ” on page63 ).
Note that we do not always include vtkObject and vtkObjectBase in object diagrams to con-
serve space. Refer to the source code for a definitive statement.
4.9 Putting It All Together 111
vtkSphereSource
vtkElevationFilter
vtkDataSetMapper
Examples
We will now demonstrate some of the features of the visualization pipeline with four examples.
Some of the objects used here will be unfamiliar to you. Please overlook missing details until we
cover the information later in the book. The goal here is to provide a flavor and familiarity with the
software architecture and its use.
Simple Sphere. The first example demonstrates a simple visualization pipeline. A polygonal repre-
sentation of a sphere is created with the source object ( vtkSphereSource ). The sphere is passed
through a filter ( vtkElevationFilter ) that computes the height of each point of the sphere above a
plane. The plane is perpendicular to the z-axis, and passes through the point (0,0,-1). The data is
finally mapped ( vtkDataSetMapper ) through a lookup table. The mapping process converts height
value into colors, and interfaces the sphere geometry to the rendering library. The mapper is
assigned to an actor, and then the actor is displayed. The visualization network, a portion of code,
and output image are shown in Figure4–19 .
The execution of the pipeline occurs implicitly when we render the actor. Each actor asks its
mapper to update itself. The mapper in turn asks its input to update itself. This process continues
until a source object is encountered. Then the source will execute if modified since the last render.
112 The Visualization Pipeline
Then the system walks through the network and executes each object if its input or instance vari-
ables are out of date. When completed, the actor’s mapper is up to date and an image is generated.
Now let’s reexamine the same process of pipeline execution by following method invocation.
The process begins when the actor receives a Render() message from a renderer. The actor in turn
sends a Render() message to its mapper. The mapper begins network execution by asking its input
to update itself via the Update() operation. This causes a cascade of Update() methods as each filter
in turn asks its input to update itself. If branching in the pipeline is present, the update method will
branch as well. Finally, the cascade terminates when a source object is encountered. If the source
object is out of date, it will send itself an RequestData() command. Each filter will send itself an
RequestData() as necessary to bring itself up to date. Finally, the mapper will perform operations to
transform its input into rendering primitives.
In the Visualization Toolkit , the Update() method is public while the RequestData() method is
protected. Thus, you can manually cause network execution to occur by invoking the Update()
operation. This can be useful when you want to set instance variables in the network based on the
results of upstream execution, but do not want the whole network to update. The RequestData()
method is protected because it requires a certain object state to exist. The Update() method insures
that this state exists.
One final note. The indentation of the code serves to indicate where objects are instantiated
and modified. The first line (i.e., the New() operator) is where the object is created. The indented
lines that follow indicate that various operations are being performed on the object. We encourage
you to use a similar indenting scheme in your own work.
Warped Sphere. This example extends the pipeline of the previous example and shows the effects
of type checking on the connectivity of process objects. We add a transform filter
(vtkTransformFilter ) to nonuniformly scale the sphere in the x-y-z directions.
The transform filter only operates on objects with explicit point coordinate representation
(i.e., a subclass of vtkPointSet ). However, the elevation filter generates the more general form
vtkDataSet as output. Hence we cannot connect the transform filter to the elevation filter. But we
can connect the transform filter to the sphere source, and then the elevation filter to the transform
filter. The result is shown in Figure4–20 . (Note: an alternative method is to use vtkCastToConcrete
to perform run-time casting.)
The C++ compiler enforces the proper connections of sources, filters, and mappers. To
decide which objects are compatible, we check the type specification of the SetInput() method. If
the input object returns an output object or a subclass of that type, the two objects are compatible
and may be connected.
Generating Oriented Glyphs. This example demonstrates the use of an object with multiple
inputs. vtkGlyph3D places 3D icons or glyphs (i.e., any polygonal geometry) at every input point.
The icon geometry is specified with the instance variable Source , and the input points are obtained
from the Input instance variable. Each glyph may be oriented and scaled in a variety of ways,
depending upon the input and instance variables. In our example we place cones oriented in the
direction of the point normals ( Figure4–21 ).
The visualization network branches at vtkGlyph3D . If either branch is modified, then this fil-
ter will reexecute. Network updates must branch in both directions, and both branches must be up
4.9 Putting It All Together 113
vtkSphereSource
vtkTransformFilter
vtkElevationFilter
vtkDataSetMapper
Figure 4–20 The addition of a transform filter to the previous example ( StrSph.cxx ).
to date when vtkGlyph3D executes. These requirements are enforced by the Update() method, and
pose no problem to the implicit execution method.
Disappearing Sphere. In our last example we construct a visualization network with a feedback
loop, and show how we can use procedural programming to change the topology of the network.
The network consists of four objects: vtkSphereSource to create an initial polygonal geometry,
114 The Visualization Pipeline
vtkSphereSource vtkConeSource
vtkGlyph3D
vtkPolyDataMapper vtkPolyDataMapper
vtkShrinkFilter to shrink the polygons and create a gap or space between neighbors,
vtkElevationFilter to color the geometry according to height above the x-y plane, and
vtkDataSetMapper to map the data through a lookup table and interface to the rendering library.
The network topology, a portion of the C++ code, and output are shown in Figure4–22 .
After vtkSphereSource generates an initial geometry (in response to a render request), the
input of vtkShrinkFilter is changed to the output of the vtkElevationFilter . Because of the feedback
loop, vtkShrinkFilter will always reexecute. Thus, the behavior of the network is to reexecute each
time a render is performed. Because the shrink filter is reapplied to the same data, the polygons
become smaller and smaller and eventually disappear.
4.10 Chapter Summary 115
vtkSphereSource
vtkShrinkFilter
vtkElevationFilter
vtkDataSetMapper
Figure 4–22 A network with a loop ( LoopShrk.cxx ). VTK 5.0 does not allow you to execute a
looping visualization network; this was possible in previous versions of VTK.
The visualization process is naturally modelled using a combination of functional and object mod-
els. The functional model can be simplified and used to describe visualization networks. The object
model specifies the components of the visualization network.
Visualization networks consist of process objects and data objects. Data objects represent
information; process objects transform the data from one form to another. There are three types of
116 The Visualization Pipeline
process objects — sources have no input and at least one output; filters have at least one input and
output; sinks, or mappers, terminate the visualization network.
The execution of the network can be controlled implicitly or explicitly. Implicit control
means that each object must insure its input is up to date, thereby distributing the control mecha-
nism. Explicit control means that there is a centralized executive to coordinate the execution of
each object.
Many techniques are available to program visualization networks. Direct visual programming
is most common in commercial systems. At a higher level, applications provide tailored but more
rigid interfaces to visualize information. At the lowest level, subroutine or object libraries provide
the greatest flexibility. The Visualization Toolkit contains an object library implemented in C++ for
constructing visualization networks.
4.12 References
[aPE90]
D. S. Dyer. “A Dataflow Toolkit For Visualization.” IEEE Computer Graphics and Applications.
10(4):60–69, July 1990.
[AVS89]
C. Upson, T. Faulhaber Jr., D. Kamins and others. “The Application Visualization System: A
Computational Environment for Scientific Visualization.” IEEE Computer Graphics and Appli-
cations. 9(4):30–42, July 1989.
4.12 References 117
[Bavoil2005]
L. Bavoil, S.P. Callahan, P.J. Crossno, J. Freire, C.E. Scheidegger, C.T. Silva and H.T. Vo. “Vis-
Trails: Enabling Interactive Multiple-View Visualizations.” In Proceedings of IEEE Visualization
2005 . IEEE Computer Society Press, 2005.
[Berger84]
M. Berger and J. Oliger. Adaptive Mesh Refinement for Hyperbolic Partial Differential Equations.
Journal of Computational Physics , 53:484–512, March 1984.
[Charal90]
S. Charalamides. “New Wave Technical Graphics Is Welcome.” DEC USER , August 1990.
[CruzNeira93]
C. Cruz-Neira, D.J. Sandin, and T. DeFanti. “Surround-screen projection-based virtual reality:
The design and implementation of the CAVE.” In Proceedings of SIGGRAPH 93 , pp. 135—142,
August 1993.
[DataExplorer]
Data Explorer Reference Manual . IBM Corp, Armonk, NY, 1991.
[DataVisualizer]
Data Visualizer User Manual . Wavefront Technologies, Santa Barbara, CA, 1990.
[FAST90]
G. V. Bancroft, F. J. Merritt, T. C. Plessell, P. G. Kelaita, R. K. McCabe, and A.Globus. “FAST: A
Multi-Processed Environment for Visualization.” In Proceedings of Visualization ’90 . pp. 14–27,
IEEE Computer Society Press, Los Alamitos, CA, 1990.
[Favre94]
J. M. Favre and J. Hahn. “An Object-Oriented Design for the Visualization of Multi-Variate Data
Objects.” In Proceedings of Visualization ’94 . pp. 319–325, IEEE Computer Society Press, Los
Alamitos, CA, 1994.
[FieldView91]
S. M. Legensky. “Advanced Visualization on Desktop Workstations.” In Proceedings of Visual-
ization ’91 . pp. 372–378, IEEE Computer Society Press, Los Alamitos, CA, 1991.
[Haeberli88]
P. E. Haeberli. “ConMan: A Visual Programming Language for Interactive Graphics.” Computer
Graphics (SIGGRAPH ’88) . 22(4):103–11, 1988.
[Humphreys99]
G. Humphreys and P. Hanrahan. “A Distributed Graphics System for Large Tiled Displays.” In
Proc. IEEE Visualization ’99 , pp. 215–224, IEEE Computer Society Press, October 1999.
[IrisExplorer]
Iris Explorer User’s Guide . Silicon Graphics Inc., Mountain View, CA, 1991.
[King03]
B. King and W. Schroeder. “Automated Wrapping of Complex C++ Code.” C/C++ Users Jour-
nal, January 2003.
[Law99]
C. Charles Law, K. M. Martin, W. J. Schroeder, J. E. Temkin. “A Multi-Threaded Streaming Pipe-
line Architecture for Large Structured Data Sets.” In Proc. of Visualization '99 . IEEE Computer
Society Press, 1999.
[Levoy94]
M. Levoy. “Spreadsheets for Images.” In Proceedings of SIGGRAPH ’94 . pp. 139–146, 1994.
118 The Visualization Pipeline
[Martin2001]
K.M. Martin, B. Geveci, J. Ahrens, C. Law. “Large Scale Data Visualization Using Parallel Data
Streaming.” IEEE Computer Graphics & Applications , 21(4):34–41, July 2001.
[PLOT3D]
P. P. Walatka and P. G. Buning. PLOT3D User’s Manual . NASA Fluid Dynamics Division, 1988.
[Rasure91]
J. Rasure, D. Argiro, T. Sauer, and C. Williams. “A Visual Language and Software Development
Environment for Image Processing.” International Journal of Imaging Systems and Technology .
1991.
[VISAGE92]
W. J. Schroeder, W. E. Lorensen, G. D. Montanaro, and C. R. Volpe. “VISAGE: An Object-Ori-
ented Visualization System.” In Proceedings of Visualization ’92 . pp. 219–226, IEEE Computer
Society Press, Los Alamitos, CA, 1992.
[VISUAL3]
R. Haimes and M. Giles. “VISUAL3: Interactive Unsteady Unstructured 3D Visualization.”
AIAA Report No. AIAA-91-0794. January 1991.
[Wernecke94]
J. Wernecke. The Inventor Mentor . Addison-Wesley Publishing Company, ISBN 0-201-62495-8,
1994.
4.13 Exercises
4.1 Consider the following 2D visualization techniques: x-y plotting, bar charts, and pie charts.
For each technique:
a) Construct functional models.
b) Construct object models.
4.2 A height field is a regular array of 2D points where = () ,
hfxy h is an altitude above the
point (x,y). Height fields are often used to represent terrain data. Design an object-oriented
system to visualize height fields.
a) How would you represent the height field?
b) What methods would you use to access this data?
c) Develop one process object (i.e., visualization technique) to visualize a height field.
Describe the methods used by the object to access and manipulate the height field.
4.3 Describe how you would implement an explicit control mechanism for network execution.
a) How do process objects register their input data with the executive?
b) How is the executive notified of object modification?
c) By what method is the executive notified that network execution is necessary?
d) Describe an approach for network dependency analysis. How does the executive invoke
execution of the process objects?
4.4 Visual programming environments enable the user to construct visualization applications by
graphically connecting process objects.
a) Design a graphical notation to represent process objects, their input and output, and data
flow direction.
b) How would you modify instance variables of process objects (using a graphical tech-
4.13 Exercises 119
nique)?
c) By what mechanism would network execution be initiated?
d) How would you control conditional execution and looping in your network?
e) How would you take advantage of parallel computing?
f) How would you distribute network execution across two or more computers sharing a net-
work connection?
4.5 Place oriented cylinders (instead of cones) on the mace in Figure4–20 . ( Hint: use
vtkCylinderSource .)
4.6 The implicit update method for the visualization network used by VTK is simple to imple-
ment and understand. However, it is prone to a common programming error. What is this
error?
4.7 Experiment with the transformation object in Figure4–20 .
a) Translate the actor with vtkTransform ’s Translate() method.
b) Rotate the actor with the RotateX() , RotateY() , and RotateZ() methods.
c) Scale the actor with the Scale() method.
d) Try combinations of these methods. Does the actor transform in ways that you expect?
4.8 Visualize the following functions. ( Hint: use vtkSampleFunction and refer to Figure4–1 .)
2
() ,,
a) Fxyz = x
() ,,
b) Fxyz = x2y3z1
+ ++
2 2
() ,,
c) Fxyz = x + y – ()cos1z +
120 The Visualization Pipeline
Chapter 5
Compatible tessellations.
5.1 Introduction
To design representational schemes for data we need to know something about the data we might
encounter. We also need to keep in mind design goals, so that we can design efficient data struc-
tures and access methods. The next two sections address these issues.
Since our aim is to visualize data, clearly we need to know something about the character of the
data. This knowledge will help us create useful data models and powerful visualization systems.
Without a clear understanding of the data, we risk designing inflexible and limited visualization
systems. In the following we describe important characteristics of data. These characteristics are
the discrete nature of data, whether it is regular or irregular, and its topological dimension.
122 Basic Data Representation
First, visualization data is discrete . This is because we use digital computers to acquire, ana-
lyze, and represent our data, and typically measure or sample information at a finite number of
points. Hence, all information is necessarily represented in discrete form.
2
Consider visualizing the simple continuous function . Ifyx we= are using a conventional
digital computer, we must discretize this equation to operate on the data it represents (we are ignor-
ing symbolic/analog computers and methods). For example, to plot this equation we would sample
the function in some interval, say (-1,1), and then compute the value y of the function at a series of
discrete points inxxthis
= interval.
i The resulting points (( x 0,y0 ), (x1 ,y1), (x2,y 2), ... (x n,yn )) con-
nect the points with straight line segments. Thus, our (continuous) data is represented by a discrete
sampling.
Because of the discrete character of the data we do not know anything about regions in
between data values. In our previous example, we know that data is generated from the function
2
yx = , but, generally speaking, when we measure and even compute data, we cannot infer data
values between points. This poses a serious problem, because an important visualization activity is
to determine data values at arbitrary positions. For example, we might probe our data and desire
data values even though the probe position does not fall on a known point.
There is an obvious solution to this problem: interpolation. We presume a relationship
between neighboring data values. Often this is a linear function, but we can use quadratic, cubic,
spline, or other interpolation functions. Chapter 8 discusses interpolation functions in greater detail,
but for now suffice it to say that interpolation functions generate data values in between known
points.
A second important characteristic of visualization data is that its structure may be regular or
irregular (alternatively, structured or unstructured ). Regular data has an inherent relationship
between data points. For example, if we sample on an evenly spaced set of points, we do not need
to store all the point coordinates, only the beginning position of the interval, the spacing between
points, and the total number of points. The point positions are then known implicitly, which can be
taken of advantage of to save computer memory.
Data that is not regular is irregular data. The advantage of irregular data is that we can repre-
sent information more densely where it changes quickly and less densely where the change is not so
great. Thus, irregular data allows us to create adaptive representational forms, which can be benefi-
cial given limited computing resources.
Characterizing data as regular or irregular allows us to make useful assumptions about the
data. As we saw a moment ago, we can store regular data more compactly. Typically, we can also
compute with regular data more efficiently relative to irregular data. On the other hand, irregular
data gives us more freedom in representing data and can represent data that has no regular patterns.
2
Finally, data has a topological dimension . In our example , yx the=dimension of the data
is one, since we have the single independent variable x. Data is potentially of any dimension from
0D points, to 1D curves, 2D surfaces, 3D volumes, and even higher dimensional regions.
The dimension of the data is important because it implies appropriate methods for visualiza-
tion and data representation. For example, in 1D we naturally use x-y plots, bar charts, or pie charts,
and store the data as a 1D list of values. For 2D data we might store the data in a matrix, and visu-
alize it with a deformed surface plot (i.e., a height field — see Exercise 4.2).
In this chapter and Chapter 8 , we show how these characteristics: discrete, regular/irregular,
and data dimension, shape our model of visualization data. Keep these features in mind as you read
these chapters.
5.1 Introduction 123
Figure 5–1 The architecture of a dataset. A dataset consists of an organizing structure, with both
topological and geometric properties, and attribute data associated with the structure.
Design Criterion
Visualizing data involves interfacing to external data, mapping into internal form, processing the
data, and generating images on a computer display device. We pose the question: What form or
forms should we use to represent data? Certainly many choices are available to us. The choice of
representation is important because it affects the ability to interface to external data and the perfor-
mance of the overall visualization system. To decide this issue we use the following design criteria:
Compact. Visualization data tends to be large, so we need compact storage schemes to mini-
mize computer memory requirements.
Efficient. Data must be computationally accessible. We want to retrieve and store data in con-
stant time (i.e., independent of data size). This requirement offers us the opportunity to
develop algorithms that are linear, or O(n), in time complexity.
Mappable. There are two types of mappings. First, data representations need to efficiently
map into graphics primitives. This ensures fast, interactive display of our data. Second, we
must be able to easily convert external data into internal visualization data structures. Other-
wise, we suffer the burden of complex conversion processes or inflexible software.
Minimal Coverage. A single data representation cannot efficiently describe all possible data
types. Nor do we want different data representations for every data type we encounter. There-
fore, we need a minimal set of data representations that balances efficiency against the num-
ber of data types.
Simple. A major lesson of applied computation is that simple designs are preferable to com-
plex designs. Simple designs are easier to understand, and therefore, optimize. The value of
simplicity cannot be overemphasized. Many of the algorithms and data representations in this
text assign high priority to this design criterion.
The remainder of this chapter describes common visualization data forms based on these design
criteria. Our basic abstraction is the data object , a general term for the various concrete visualiza-
tion data types which are the subclasses of data object.
124 Basic Data Representation
0 n-1
0
n
1 1
(a) Vertex (b) Polyvertex (c) Line (d) Polyline ( n lines)
2
2 n+1
1 3
3
1 1
0 0 n
2 0
(e) Triangle (f) Triangle strip ( n triangles) (g) Quadrilateral
3
n-2
2 3
n-1 2
xj
xi 1
0 1 1 0
0
(h) Pixel (i) Polygon ( n points) (j) Tetrahedron
6 6 7 2
7
5 4 5
4 1 5
z 0
3 2 3 y
2
x
0 1 0 1 3 4
(k) Hexahedron (l) Voxel (m) Wedge
4 9 8 10
9
11
2 4 3 4
5 7 8
3 6
5 3
2 6 7
2
0
1 1 0 1
0
(n) Pyramid (o) Pentagonal Prism (p) Hexagonal Prism
Figure 5–2 Linear cell types found in VTK. Numbers define ordering of the defining points.
126 Basic Data Representation
Point list
5
7 x-y-z
Definition: 22 x-y-z
Type: hexahedron 21
Connectivity: (8,10,1,6,21,22,5,7) 6
1 x-y-z
8 10 x-y-z
Figure 5–3 Example of a hexahedron cell. The topology is implicitly defined by the
ordering of the point list.
Up() i = { C i :p i Î C i } (5-1)
The importance of “uses” and “use sets” will become evident in Chapter 8 when we explore the
topology of datasets.
Although we define points in three dimensions, cells may vary in topological dimension. Ver-
tices, lines, triangles, and tetrahedron are examples of topologically 0, 1, 2, and 3-D cells, respec-
tively, embedded in three-dimensional geometric space. Cells can also be primary or composite.
Composite cells consist of one or more primary cells, while primary cells cannot be decomposed
into combinations of other primary cell types. A triangle strip, for example, consists of one or more
triangles arranged in compact form. The triangle strip is a composite cell because it can be broken
down into triangles, which are primary cells.
Certainly there are an infinite variety of possible cell types. In the Visualization Toolkit each
cell type has been chosen based on application need. We have seen how some cell types: vertex,
line, polygon, and triangle strip ( Figure3–19 ) are used to represent geometry to the graphics sub-
system or library. Other cell types such as the tetrahedron and hexahedron are common in numeri-
cal simulation. The utility of each cell type will become evident through the practice of
visualization throughout this book. A description of the cell types found in the Visualization Tool-
kit—including their classification as linear, nonlinear, or other—is given in the following sections.
Linear Cells
Linear cells are characterized by linear or constant interpolation functions (see “Interpolation Func-
tions” on page269 for more information). As a result, cells of dimension one or greater are charac-
terized by straight edges. Thus any edge may be characterized by two vertex id’s ( v 1,v 2). The
following are the linear cells currently found in VTK.
Line. The line is a primary one-dimensional cell. It is defined by two points. The direction along
the line is from the first point to the second point.
Polyline. The polyline is a composite one-dimensional cell consisting of one or more connected
lines. The polyline is defined by an ordered list of n+1 points, where n is the number of lines in the
polyline. Each pair of points (i, i+1) defines a line.
Triangle. The triangle is a primary two-dimensional cell. The triangle is defined by a counter-
clockwise ordered list of three points. The order of the points specifies the direction of the surface
normal using the right-hand rule.
Triangle Strip. The triangle strip is a composite two-dimensional cell consisting of one or more tri-
angles. The points defining the triangle strip need not lie in a plane. The triangle strip is defined by
an ordered list of n+2 points, where n is the number of triangles. The ordering of the points is such
()ii1i2
, +defines
that each set of three points with , + a triangle.0in
££
Pixel. The pixel is a primary two-dimensional cell defined by an ordered list of four points. The
cell is topologically equivalent to the quadrilateral with the addition of geometric constraints. Each
edge of the pixel is perpendicular to its adjacent edges, and lies parallel to one of the coordinate
axes x-y-z . Hence, the normal to the pixel is also parallel to one of the coordinate axes.
The ordering of the points defining the pixel is different from the quadrilateral cell. The
points are ordered in the direction of increasing axis coordinate, starting with x, then y, then z. The
pixel is a special case of the quadrilateral and is used to improve computational performance.
One important note is that the definition of the pixel cell given here is different from the usual
definition for a pixel. Normally pixels are thought of as constant-valued “picture-elements” in an
image (see “Graphics Hardware ” on page51 ). The definition given here implies that four picture-
elements form the four corner points of the pixel cell. We normally use the term pixel to describe a
pixel cell, but the meaning of the term will vary depending on context.
Polygon. The polygon is a primary two-dimensional cell. The polygon is defined by an ordered list
of three or more points lying in a plane. The polygon normal is implicitly defined by a counter-
clockwise ordering of its points using the right-hand rule.
The polygon may be nonconvex, but may not have internal loops, and it cannot self-intersect.
The polygon has n edges, where n is the number of points in the polygon.
Voxel. The voxel is a primary three-dimensional cell. The voxel is topologically equivalent to the
hexahedron with additional geometric constraints. Each face of the voxel is perpendicular to one of
the coordinate x-y-z axes. The defining point list is ordered in the direction of increasing coordinate
value as shown in Figure5–2 . The voxel is a special case of the hexahedron and is used to improve
computational performance.
Similar to pixels, our definition of a voxel cell differs from the conventional definition of the
term voxel. Typically, a voxel is referred to as a constant-valued “volume element”. Using our def-
inition, eight volume elements form the eight corner points of the voxel cell. We normally use the
term voxel to describe a voxel cell, but the meaning of the term will vary depending on the context.
Wedge. The wedge is a primary three-dimensional cell consisting of three quadrilateral faces, two
triangular faces, nine edges, and six vertices. The wedge is defined by an ordered list of six points
as shown in Figure5–2 . The faces and edges must not intersect any other faces and edges, and the
wedge must be convex.
Pyramid. The pyramid is a primary three-dimensional cell consisting of one quadrilateral face,
four triangular faces, eight edges, and five vertices. The pyramid is defined by an ordered list of
five points as shown in Figure5–2 . The four points defining the quadrilateral base plane must be
convex; the fifth apex point must not be co-planar with the base points.
Pentagonal Prism. The pentagonal prism is a primary three-dimensional cell consisting of five
quadrilateral faces, two pentagonal faces, fifteen edges, and ten vertices. The pentagonal prism is
defined by an ordered list of ten points as shown in Figure5–2 . The faces and edges must not inter-
sect any other faces and edges and the pentagon must be convex.
Hexagonal Prism. The hexagonal prism is a primary three-dimensional cell consisting of six
quadrilateral faces, two hexagonal faces, eighteen edges, and twelve vertices. The hexagonal prism
is defined by an ordered list of twelve points as shown in Figure5–2 . The faces and edges must not
intersect any other faces and edges and the hexagon must be convex.
Nonlinear Types
It is common in numerical analysis to use nonlinear cells, i.e., cell formulations that use nonlinear
basis functions. These basis functions are generally formed by combinations of polynomials. Non-
linear cells provide more accurate interpolation functions (see “Interpolation Functions ” on
page269 ) and better approximate curved geometry. However, the number of possible nonlinear
basis functions is unlimited, which poses a combinatorial problem to any visualization system (i.e.,
it is not possible to implement all non-linear cell types). To address this problem, VTK takes a dual
approach. First, VTK directly supports nonlinear cell types with quadratic interpolation functions
5.4 Cell Types 129
2
4
0 2
5 1
1 0
3
(a) Quadratic Edge (b) Quadratic Triangle
2 2 2
5 6 6
3 3 5 3 5
8
1 7 1 7 1
4 4 4
0 0 0
(c) Quadratic Linear Quad (d) Quadratic Quad (e) Bi-Quadratic Quad
3
4
9 12 11
2 3 2
81 7 10
7 8
6 5 9
1 6
0
4 0 1
5
(f) Quadratic Tetrahedron (g) Quadratic Pyramid
14 6
7
15 13 25
12 23
4 5 18
19 17 20 22 21 26
3
16 11 2
10 9 24
1
0 8
(h) Quadratic Hexahedron (i) Bi-Quadratic Hexahedron (j) Tri-Quadratic Hexahedron
11 5 11 5 11 5
3 3 3
4 10 4 10 14 17 4 10 14
9 12 9
9 12 8 13 8 16
8 15
2 2 2
0 0 13
0 7 6 7 6 7
6 1 1
1
(k) Quadratic Linear Wedge (l) Quadratic Wedge (m) Bi-Quadratic Wedge
(see Figure5–4 ). Such cells are constructed by adding mid-edge nodes, and occasionally mid-face
and interior nodes, requiring extending the connectivity list to reflect the addition of these extra
entries. Second, VTK has a sophisticated cell adaptor framework, enabling users to interface any
basis function to VTK as long as the basis function can be uniquely characterized in an r-s-t para-
metric coordinates system. (Note: we will describe the cell adaptor framework in more detail in
Chapter 8 .)
One significant difference between linear and nonlinear cells is the way they are rendered and
operated on by various visualization algorithms. Linear cells are readily converted to linear graph-
ics primitives, which are then processed by the graphics library. Nonlinear cells, on the other hand,
do not often have direct support in graphics libraries. (One exception are the family of non-uniform
rational B-splines or NURBS. And even these are generally tessellated by the graphics library into
linear primitives.) Therefore, nonlinear cells must be treated specially by the visualization system.
Some possibilities include:
1. Tessellating nonlinear cells into linear cells and then operating on the linear cells.
2. Develop custom rendering and visualization algorithms to operate directly on nonlinear cells.
3. Program custom rendering operations in the graphics library.
These issues are active topics in visualization research [Schroeder05] . In VTK, tessellation methods
are currently employed since once tessellated, a cell can be processed by existing linear algorithms.
The difficulty with solutions 2) and 3) above is that the effort to create new rendering and visualiza-
tion algorithms is significant, possibly requiring different solutions for each type of nonlinear cell.
Furthermore, it is likely that the performance found in dedicated rendering hardware (e.g., process-
ing linear cells) would far outstrip any software rendering solution for higher order cells. The diffi-
culty with 1) above is that the tessellation must be performed carefully or unacceptable error can be
introduced into visualization. Or, if the cell is over-tessellated, an excessive number of linear prim-
itives will result. Future research points to developing adaptive methods that tessellate on a selected
error metric (please see Chapter 8 for more information).
VTK tessellates nonlinear quadratic cells using a fixed subdivision as shown in Figure5–5 .
This generally works well for quadratic cells due to the lower order of interpolation, and the few
number of points defining the cell.
Quadratic Edge. The quadratic edge is a primary one-dimensional cell. It is defined by three
points. The first two points define the endpoints of the edge; the third point is located in the center
of the edge as shown in Figure5–4 . The direction along the line is from the first point to the second
point.
Quadratic Triangle. The quadratic triangle is a primary two-dimensional cell. It is defined by six
points. The first three points are located at the vertices of the triangle; the next three are located in
the middle of each of the three edges as shown in Figure5–4 .
Quadratic Linear Wedge. The quadratic linear wedge is a primary three-dimensional cell. It is
defined by twelve points. The first six points are located at the vertices of the wedge; the next six
are located in the middle of each of the six edges that belong to a triangle face as shown in
Figure5–4 .
Quadratic Wedge. The quadratic wedge is a primary three-dimensional cell. It is defined by fif-
teen points. The first six points are located at the vertices of the wedge; the next nine are located in
the middle of each of the nine edges as shown in Figure5–4
132 Basic Data Representation
s (n x, n y, n z )
(u,v,w) |n|=1
a 11 a 12 a 13
2D: (u,v) a 21 a 22 a 23
3D: (u,v,w)
s a 31 a 32 a 33
or cells, but sometimes attribute data may be assigned to cell components such as edges or faces.
Attribute data may also be assigned across the entire dataset, or across a group of cells or points.
We refer to this information as attribute data because it is an attribute to the structure of the dataset.
Typical examples include temperature or velocity at a point, mass of a cell, or heat flux into and out
of a cell face.
Attribute data is often categorized into specific types of data. These categories have been cre-
ated in response to common data forms. Visualization algorithms are also categorized according to
the type of data they operate on.
Single-valued functions, such as temperature or pressure, are examples of scalar data, which
is one attribute type. More generally, attribute data can be treated as n-dimensional data arrays. For
example, the single-valued function temperature can be treated as a array, 11´ while velocity can
be treated as a array
31´ of components in the x, y, and z directions. This abstract model for data
attribute can be extended throughout the visualization system. Some systems extend this model to
include the structure of the data. For example, a 3D image dataset (i.e., a volume) can be repre-
sented as a 3D array of data ´ values.
lmn ´ Unstructured data can be represented as a 3D vector
of position, plus an array of connectivity. We refer to this general approach as the hyperdata model
for visualization data (see “Other Data Abstractions ” on page138 ).
In the following sections we describe data attributes using the simpler type-specific model
(Figure5–6 ). We also limit ourselves to three-dimensional structure, since the dataset structure and
graphics are assumed to be three-dimensional.
Scalars
Scalar data is data that is single valued at each location in a dataset. Examples of scalar data are
temperature, pressure, density, elevation, and stock price. Scalar data is the simplest and most com-
mon form of visualization data.
Vectors
Vector data is data with a magnitude and direction. In three dimensions this is represented as a trip-
let of values ( u, v, w ). Examples of vector data include flow velocity, particle trajectory, wind
motion, and gradient function.
Normals
Normals are direction vectors: that is, they are vectors of magnitude | n|=1. Normals are often used
by the graphics system to control the shading of objects. Normals also may be used by some algo-
rithms to control the orientation or generation of cell primitives, such as creating ribbons from ori-
ented lines.
Texture Coordinates
Texture coordinates are used to map a point from Cartesian space into a 1-, 2-, or 3-dimensional
texture space. The texture space is usually referred to as a texture map . Texture maps are regular
arrays of color, intensity, and/or transparency values that provide extra detail to rendered objects.
134 Basic Data Representation
One application of texturing in two dimensions is to “paste” a photograph onto one or more poly-
gons, yielding a detailed image without a large number of graphics primitives. (Texture mapping is
covered in more detail in Chapter 7.)
Tensors
Tensors are complex mathematical generalizations of vectors and matrices. A tensor of rank k can
be considered a k-dimensional table. A tensor of rank 0 is a scalar, rank 1 is a vector, rank 2 is a
matrix, and a tensor of rank 3 is a three-dimensional rectangular array. Tensors of higher rank are k-
dimensional rectangular arrays.
General tensor visualization is an area of current research. Efforts thus far have been focused
33´
on two-dimensional, rank 2 tensors, which are matrices. The most common form of such ten-
sors are the stress and strain tensors, which represent the stress and strain at a point in an object
33´
under load. VTK only treats real-valued, symmetric tensors.
Polygonal Data
We have already seen how graphics libraries are designed to render such geometric primitives as
lines and polygons. These primitives also are frequently generated or consumed by computational
geometry and visualization algorithms. In the Visualization Toolkit , we call this collection of graph-
ics primitives polygonal data . The polygonal dataset consists of vertices, polyvertices, lines,
polylines, polygons, and triangle strips. The topology and geometry of polygonal data is unstruc-
tured, and the cells that compose that dataset vary in topological dimension. The polygonal dataset
forms a bridge between data, algorithms, and high-speed computer graphics.
Vertices, lines, and polygons form a minimal set of primitives to represent 0-, 1-, and 2-
dimensional geometry. We have included polyvertex, polyline, and triangle strip cells for conve-
nience, compactness, and performance. Triangle strips in particular are high-performing primitives.
To represent n triangles with a triangle strip requires just n+2 points, compared to the 3n points for
conventional representations. In addition, many graphics libraries can render triangle strips at
higher speeds than triangle polygons.
5.6 Types of Datasets 135
Figure 5–7 Dataset types. The unstructured grid consists of all cell types.
136 Basic Data Representation
Our minimal selection of cells is based on common application and performance, represent-
ing a subset of the cells available in some graphics libraries. Other types include quadrilateral
meshes, Bezier curves and surfaces, and other spline types such as NURBS (Non-Uniform Rational
B-Splines) [Mortenson85] . Spline surfaces are generally used to accurately model and visualize
geometry. Few visualization algorithms (other than geometry visualization) have been developed
that require spline surfaces.
Image Data
An image dataset is a collection of points and cells arranged on a regular, rectangular lattice. The
rows, columns, and planes of the lattice are parallel to the global x-y-z coordinate system. If the
points and cells are arranged on a plane (i.e., two-dimensional) the dataset is referred to as a pix-
map, bitmap, or image. If the points and cells are arranged as stacked planes (i.e., three-dimen-
sional) the dataset is referred to as a volume. Keep in mind that the term image data refers to
images, volumes, or one-dimensional point arrays collectively. Note that some authors have
referred to image data as uniform grids and structured points. (Structured points was the terminol-
ogy used in earlier versions of VTK.)
Image data consist of line elements (1D), pixels (2D), or voxels (3D). Image data is regular in
both geometry and topology and can be implicitly represented. The representational scheme
requires only data dimensions, an origin point, and the data spacing. The dimension of the data is a
3-vector ()n x ,,n y n z , specifying the number of points in the x, y, and z directions. The origin point
is the position in three-dimensional space of the minimum x-y-z point. Each pixel (2D) or voxel
(3D) in a image dataset is identical in shape, the spacing specifying the length in the x-y-z direc-
tions.
The regular nature of the topology and geometry of the image dataset suggests a natural i-j-k
coordinate system. The number of points in the dataset is n x ´ n y ´ n z while the number of cells is
()n x – 1 ´ ()n y – 1 ´ ()n z – 1 . A particular point or cell can be selected by specifying the three
indices i-j-k. Similarly, a line is defined by specifying two out of three indices, and a plane by spec-
ifying a single index.
The simplicity and compactness of representation are desirable features of image data. It is an
efficient structure to traverse and compute with. For this reason image data is rivaled only by
polygonal data as the most common form of visualization dataset. The major disadvantage with
image data is the so-called “curse of dimensionality.” To obtain greater data resolution we must
increase the dimensions of the dataset. Increasing the dimensions of an image results in an O(n 2)
3
increase in memory requirement, while volumes require an O(n ) increase. Therefore, to resolve a
small feature using image data may require more disk space or computer memory than is available.
Image datasets are often used in imaging and computer graphics. Volumes are frequently gen-
erated from medical imaging technologies such as Computed Tomography (CT) and Magnetic Res-
onance Imaging (MRI). Sometimes volumes are used to sample mathematical functions or
numerical solutions.
Rectilinear Grid
The rectilinear grid dataset is a collection of points and cells arranged on a regular lattice. The
rows, columns, and planes of the lattice are parallel to the global x-y-z coordinate system. While the
5.6 Types of Datasets 137
topology of the dataset is regular, the geometry is only partially regular. That is, the points are
aligned along the coordinate axis, but the spacing between points may vary.
Like the image dataset, rectilinear grids consist of pixels (2D) or voxels (3D). The topology is
represented implicitly by specifying grid dimensions. The geometry is represented by maintaining a
list of separate x, y, and z coordinates. To obtain the coordinates of a particular point, values from
each of the three lists must be appropriately combined.
Structured Grid
A structured grid is a dataset with regular topology and irregular geometry. The grid may be warped
into any configuration in which the cells do not overlap or self-intersect.
The topology of the structured grid is represented implicitly by specifying a 3-vector of
()n x ,,geometry
dimensions . The n y n z is explicitly represented by maintaining an array of point
coordinates. The composing cells of a structured grid are quadrilaterals (2D) or hexahedron (3D).
Like image data, the structured grid has a natural coordinate system that allows us to refer to a par-
ticular point or cell using topological i-j-k coordinates.
Structured grids are commonly found in finite difference analysis. Finite difference is a
numerical analysis technique to approximate the solution to partial differential equations. Typical
applications include fluid flow, heat transfer, and combustion.
Unstructured Points
Unstructured points are points irregularly located in space. There is no topology in an unstructured
point dataset, and the geometry is completely unstructured. The vertex and polyvertex cells are
used to represent unstructured points.
Unstructured points are a simple but important type of dataset. Often data has no inherent
structure, and part of the visualization task is to discover or create it. For example, consider a piston
in a car instrumented with temperature gauges. The number of gauges and their location is chosen
at a finite set of points, resulting in temperature values at “unrelated” (at least in terms of visualiza-
tion topology) positions on the surface of the piston. To visualize the surface temperature, we have
to create an interpolation surface and scheme to fill in intermediate values.
Unstructured points serve to represent such unstructured data. Typically, this data form is
transformed into another more structured form for the purposes of visualization. Algorithms for
transforming unstructured points into other forms are described in “Visualizing Unstructured Points ”
on page355 .
Unstructured Grid
The most general form of dataset is the unstructured grid. Both the topology and geometry are com-
pletely unstructured. Any cell type can be combined in arbitrary combinations in an unstructured
grid. Hence the topology of the cells ranges from 0D (vertex, polyvertex) to 3D (tetrahedron, hexa-
hedron, voxel). In the Visualization Toolkit any dataset type can be expressed as an unstructured
grid. We typically use unstructured grids to represent data only when absolutely necessary, because
this dataset type requires the most memory and computational resources to represent and operate
on.
138 Basic Data Representation
Unstructured grids are found in fields such as finite element analysis, computational geome-
try, and geometric modelling. Finite element analysis is a numerical solution technique for partial
differential equations (PDEs). Applications of finite element analysis include structural design,
vibration, dynamics, and heat transfer. (This compares to finite difference analysis for PDEs. One
advantage of finite element analysis is that the constraint on regular topology is removed. Hence
complex domains can be more easily meshed.)
regular and irregular grids. They refer to their model as the field data model , but their definition of
the word field is different from the AVS model. A field is an object composed of a base and depen-
dent data . Informally, the base is a manifold whose coordinates are the independent variables for
the field, and the dependent data relate the values of dependent variables to the independent vari-
ables of the base. Visualization data consists of field elements that describe the base and dependent
variables over a local region.
• Abstract models are more flexible and capable of representing a wider range of data forms
than concrete models.
• Abstract models lend themselves to compact computer code.
• Concrete models are easier to describe, interface, and implement than abstract models.
• The level of abstraction influences the computer code and/or database interface to the data
model. Abstract models result in abstract code and data representations; concrete models
result in concrete code and data representations.
• The complexity of abstract models can be hidden by creating simpler, application-specific
interfaces. However, this requires extra effort. Concrete models, on the other hand, cannot be
made more abstract by modifying interfaces.
The design of computer systems demands careful attention to the balance between abstract and
concrete systems. Visualization systems, in particular, must be carefully designed because they
interface to other systems and data models. Models that are too abstract can result in confusing
computer code and interfaces, and can be misused because of user misunderstanding. On the other
hand, concrete models are limited in flexibility and capability, but tend to be easier to learn and
apply.
In the design of the Visualization Toolkit , we chose to use a more concrete data model relative
to the AVS and field data models. Our decision was based on the premise that the system was to be
informative as well as functional, and we wanted to clearly demonstrate basic concepts. On the
other hand, VTK’s data model is general enough to support our practice of visualization. Our expe-
rience with users also has shown us that VTK’s data model is easier for the casual visualization user
140 Basic Data Representation
to understand than the more abstract models. If you decide to design your own system, we recom-
mend that you examine other data models. However, we feel that the clarity of code manifested in
the Visualization Toolkit is an example of a well-balanced trade-off between design abstraction and
simplicity.
Because of the size and scope of data, memory must be carefully managed to create efficient visu-
alization systems. In the Visualization Toolkit , we use contiguous data arrays as the basis for most
data structures. Contiguous arrays can be created, deleted, and traversed faster than alternative data
structures, such as linked lists or arrays of pointers to structures. In VTK, we refer to these as data
arrays, and represent them with the class vtkDataArray .
Contiguous arrays also can be easily transmitted across a network, particularly if the informa-
tion in the array is independent of computer memory address. Memory independence avoids the
overhead of mapping information from one memory location to another. Therefore, in VTK we
access information based on an “id”, an integer index into an array-like object. Data arrays are 0-
offset just like C++ arrays. That is, given n data values, we successively access these values using
the ids .()012
,,,, ¼ n1–
An important design decision was to not represent data using arrays of objects (e.g., a sepa-
rate class for cells and/or points). Our experience has shown that such designs severely impact per-
formance due to the cost of construction and deletion. Instead, we focus on designing classes at a
higher level of abstraction. From the perspective of performance, the object-oriented approach
serves best at the application level, not at the level of implementation.
The class vtkFloatArray is an example of a contiguous array. We will use this class to
describe how contiguous arrays are implemented in VTK. As shown in Figure5–8 , the instance
variable Array is a pointer to memory of type float. The allocated length of the array is given by
Size. The array is dynamic, so an attempt to insert data beyond the allocated size automatically gen-
erates a Resize() operation. When resized, the array approximately doubles in size each time. The
5.8 Putting It All Together 141
MaxId field is an integer offset defining the end of inserted data. If no data has been inserted, then
£
MaxId is equal to -1. Otherwise, MaxId is an integer value where . 0MaxIdSize <
vtkObjectBase
vtkObject
vtkDataArray
Figure 5–10 Data array object diagram. vtkDataArray is an abstract base class. Subclasses of
vtkDataArray implement type specific representation and operations. Note: not all concrete
data array subclasses are shown in this diagram.
type to floating-point value, or it may be a complex mapping of data. For example, if our data con-
sists of character strings, we could conceivably create an alphabetical list and map the string into a
location in the list, and then cast the location into a double value.
While this run-time oriented interface is convenient for writing general algorithms that do not
depend on a particular data type, the conversion of native representation to double type is problem-
atic. First, the conversion operation can affect performance adversely, since the data access meth-
ods are called frequently, virtual functions are slower than in-line or non-virtual invocations, and
the cast operator is slow in many cases. Second, a complex type such as double loses precision dur-
ing conversion to double. To remedy these problems, it is possible to access data in its native form
and process it accordingly. In this approach C++ templates are used.
To use templates it is necessary to obtain raw, typed pointers to data, and to know the type of
data. vtkDataArray and its associated subclasses provides this functionality. With this information
it is possible to switch on the type of data into a function templated over that type. A typical code
fragment using this functionality is found in most imaging filters, almost all of which are templated
as follows:
switch (outData->GetScalarType())
{
case VTK_CHAR:
{ typedef char VTK_TT;
func(arg1, arg2, arg3, VTK_TT* arg4, VTK_TT* arg5); }
break;
case VTK_UNSIGNED_CHAR:
{ typedef unsigned char VTK_TT;
func(arg1, arg2, arg3, VTK_TT* arg4, VTK_TT* arg5); }
break;
}
5.8 Putting It All Together 143
In practice this code is simplified using macros, and the static_cast<> C++ operator is used to
perform the cast. Note that the function func is a templated function. The compiler will instantiate
the function for the appropriate type. In most cases all native types are represented in the switch
statement, so func is expanded accordingly.
Using compile-time oriented methods such as templates avoids the need to cast each data
access into a particular type (e.g., double ). While it does complicate the code somewhat and result
in larger object code, it is generally faster than run-time virtual methods. This approach becomes
problematic as the number of types increases. For example, some filters such as
vtkImageShiftScale use doubly nested templates to resolve the potential difference in input and
output types. The code is more complex and much larger than the generic run-time approach.
Data objects are implemented in VTK as an array of vtkDataArrays as shown in Figure5–11 . vtk-
DataObject is an general representation of visualization data. It serves to encapsulate instance vari-
ables and methods for visualization network execution (see previous chapter), as well as
representing data. Internally, data is represented with an instance of the class vtkFieldData . Very
few algorithms directly operate on data objects; rather most algorithms require the specification of
an organizing structure in order to process the data. The dataset specifies that organizing structure
as described in the following section.
Dataset Representation
vtkImageData. The simplest and most compact representation is vtkImageData . Both the dataset
points and cells are represented implicitly by specifying the dimensions, data spacing, and origin.
The dimensions define the topology of the dataset, while the origin and spacing specify the geome-
try. The vtkImageData dataset type can represent 1D line samples, 2D images, and 3D volumes.
(Note: in earlier versions of VTK, vtkImageData was known as vtkStructuredPoints. There are still
remnants of this terminology in the code base.)
There is an implicit ordering of both the points and cells composing vtkImageData . Both the
cells and points are numbered in the direction of increasing x, then y, then z. The total number of
nx ´ ny ´ n z
points is where nx , ny , and nz are the dimensions of vtkImageData . The total number
of cells is .()n x – 1 ´ ()n y – 1 ´ ()n z – 1
vtkPolyData. Unlike vtkImageData and vtkStructuredGrid , the topology of vtkPolyData is not reg-
ular, so both the topology and geometry of the dataset must be explicitly represented. The point
data in vtkPolyData is represented using the vtkPoints class similar to vtkStructuredGrid .
The Visualization Toolkit uses the class vtkCellArray to explicitly represent cell topology.
This class is a list of connectivity for each cell. The structure of the list is a sequence of integer
numbers ( Figure5–12 ). The first number in the list is a count (the number of points in the cell con-
nectivity), and the next series of numbers is the cell connectivity. (Each number in the connectivity
n p1 p2 p3 p4 n p1 p2 p3 n p1 p2 p3
list is an index into an instance of a point coordinate list.) Sequences of count followed by the con-
nectivity list are repeated until each cell is enumerated. Additional information such as the number
of cells in the list and current position in the list (for traversal purposes) is also maintained by
vtkCellArray .
Notice that type information is not directly represented in this structure. Instead, vtkPolyData
maintains four separate lists to vertices, lines, polygons, and triangle strips. The vertex list repre-
sents cells of type vtkVertex and vtkPolyVertex . The lines list represents cells of type vtkLine and
vtkPolyLine . The polygon list represents cells of type vtkTriangle , vtkQuad , and vtkPolygon . The
triangle strip list represents cells of the single type vtkTriangleStrip . As a result, the cell type is
known from the particular list the cell is defined in, plus the number of points that define the cell.
Our design of the vtkPolyData class is based on two important requirements. First, we want
an efficient interface to external graphics libraries. Second, we wish to aggregate cells according to
topology. The four separate lists provide efficient interface because graphics libraries have separate
vertex, line, polygon, and triangle strip primitives. As a result, in VTK no run-time checking is
required to match the different cell types with the appropriate “load primitive” function, since the
type is known from the list in which the primitive resides. The four lists also separate cells into 0-,
1-, and 2-dimensional types. This is useful because visualization algorithms often treat data of
varying topological order differently.
vtkUnstructuredGrid. The dataset type vtkUnstructuredGrid is the most general in terms of its
ability to represent topological and geometric structure. Both points and cells are explicitly repre-
sented using derived classes of vtkPoints and vtkCellArray . The class vtkUnstructuredGrid is simi-
lar to vtkPolyData except that vtkUnstructuredGrid must be capable of representing all cell types,
not just the limited graphics types (i.e., vertices, lines, polygons, and triangle strips) of
vtkPolyData .
Another distinguishing characteristic of vtkUnstructuredGrid is that we represent type infor-
mation differently. In vtkPolyData we categorized cells into four separate lists, thereby representing
cell type indirectly. In vtkUnstructuredGrid we add the additional class vtkCellTypes to represent
cell type explicitly.
The vtkCellTypes is an array of supplemental information. For each cell, an integer flag
defines the cell type. Another variable is used to record the location of the cell definition in the cor-
responding vtkCellArray (Figure5–13 ).
Besides representing cell type, this design also enables random access to cells. Because the
length of a cell connectivity list varies, the vtkCellArray class cannot locate a particular cell with-
out traversing its data structure from the origin. With the added class vtkCellTypes , however, it is
possible to directly access a cell with a single dereference (i.e., using the offset value).
The vtkCellTypes may also be added to the vtkPolyData data representation — and indeed it
has. However, our reasons for this addition are not to represent type explicitly, but rather to provide
random access to the cells and enable many topological operations. We will expand on this idea in
Chapter 8 .
Object Model. The five datasets are implemented as shown in Figure5–14 . As this object diagram
illustrates, these concrete datasets are subclasses of the abstract class vtkDataSet . Two additional
classes are introduced as well. The class vtkStructuredData contributes instance variables and
methods for structured data. vtkStructuredData is not in an inheritance relationship with the
146 Basic Data Representation
x0 n type 0
y0 p1 offset 0
z0 p2 type 1
x1 p3 offset 1
y1 type 2
z1 offset 2
Figure 5–13 The data
structure of the class vtkUn-
structuredGrid. (This is a sub-
set of the complete structure.
See Chapter 8 for complete
details.)
n
xn-1 p1
yn-1 p2 type n-1
zn-1 p3 offset n-1
vtkObject
vtkDataSet
Figure 5–14 Dataset object diagram. The five datasets (shaded) are implemented in VTK.
datasets; rather the structured datasets shown delegate to it in order to implement some of their
methods. (This was done to avoid multiple inheritance.) Subclasses of the class vtkPointSet repre-
sent their points explicitly, that is, through an instance of vtkPoints or its subclasses. vtkPointSet
provides methods and instance variables to manipulate the point data, as well as a general searching
capability to find points and cells. (See “Searching ” on page297 for more information.)
5.8 Putting It All Together 147
vtkCell
vtkPolygon
vtkNonLinearCell vtkTetra vtkPyramid
vtkWedge vtkVoxel
vtkQuadraticTriangle vtkQuadraticHexahedron
Figure 5–15 Object diagram for twenty concrete cell types in VTK. vtkEmptyCell rep-
resents NULL cells. vtkGenericCell can represent any type of cell. Three-dimensional
cells are subclasses of vtkCell3D. Higher order cells are subclasses of vtkNonLinearCell.
Cell Representation
In the Visualization Toolkit each cell type has been implemented by creating specific classes. Each
cell is a subclass of the abstract type vtkCell . Cell topology is represented by a list of ordered point
ids, and cell geometry is represented by a list of point coordinates. The object diagram for vtkCell
and its subclasses is shown in Figure5–15 .
The abstract class vtkCell specifies methods that each cell must implement. These methods
provide a defined interface to the cell’s geometry and topology. Additional methods perform com-
putation on the cell. These methods will be discussed in detail in Chapter 8 .
Data Attributes
Data attributes are associated with the structure of a dataset. The dataset model is built on points
and cells, so it is natural to associate data attributes with points and cells as well. Intermediate
structure features, such as cell edges or faces, are not explicitly represented so we cannot easily
associate data attributes with them.
In VTK data attributes are associated with the points and cells of the dataset. There is no
association of data attributes to intermediate topological features such as triangle edges or hexahe-
dron faces. (Here we refer to data attributes associated with points as point attributes , and data
attributes associated with cells as cell attributes .) Our design choice is based on the following ratio-
nale.
148 Basic Data Representation
• Data acquisition and numerical simulation systems typically measure and/or compute the
results at point locations, or at the center of cells.
• Boundary attribute information (e.g., on faces and edges) can be maintained as cell data
ordered according to the topology of the cell.
• The VTK data model is based on points and cells for reasons of compactness and efficiency.
Representing attribute data on cell boundaries would require expanding this representation to
support a small number of situations requiring direct support of attribute data on cell bound-
aries. If in the future a more complex data structure is required to represent boundary
attribute data, this is best encapsulated into a single class rather than forcing the abstraction
throughout the system.
One difficulty with maintaining both cell data and point data repre- vtkFieldData
sentations is that possible inconsistencies in the data may arise. For
example, if a cell’s scalar value is 0.5, and its points have scalar val-
ues other than 0.5, which is the correct value? Priority schemes can vtkDataSetAttributes
be devised to resolve such situations although the user must recog-
nize that such inconsistencies may exist.
To represent dataset attributes we use the organizing classes
vtkPointData vtkCellData
vtkPointData and vtkCellData, both of which are subclasses of the
class vtkFieldData as shown in Figure5–16 . The class
Figure 5–16 Inheritance
vtkDataSetAttributes serves to coordinate the movement of data hierarchy for representing
from one process object to the next. It provides methods for copy- data set attributes.
ing, interpolating, and moving data between input and output.
Another important feature of vtkDataSetAttributes is that it provides
the ability to assign a data array to represent a particular data attribute. For example, the method
SetScalars() is used to specify which data array is to be treated as the scalars in the field.
There is a one-to-one correspondence between each dataset point and its attribute data. Point
attributes are accessed by way of the point id. For example, to access the scalar value of point id
129 in the dataset instance aDataSet , we use
aDataSet->GetPointData()->GetScalars()->GetTuple(129);
This statement assumes that the scalar data has been defined for this dataset and is non- NULL.
Examples
In the examples that follow we show manual creation and manipulation of datasets. Typically, these
operations are not performed directly by users of VTK. Instead, source objects are used to read data
files or generate data. This is more convenient than the manual techniques shown here and should
be used whenever possible.
Creation of datasets is a two step process. First the geometry and topology of the dataset must
be defined. Depending on the type of dataset, the geometry and topology definition will proceed
differently. Then the point and/or cell attribute data is created and associated with the dataset.
Remember that there is a one-to-one relationship between the attribute data and the points and cells
in the dataset.
5.8 Putting It All Together 149
vtkPolyData
vtkPolyDataMapper
cube->SetPoints(points);
points->Delete();
cube->SetPolys(polys);
polys->Delete();
cube->GetPointData()->SetScalars(scalars);
scalars->Delete();
Create a Polygonal Dataset. In our first example we create a polygonal representation of a cube.
The cube is defined by eight points and six quadrilateral faces. We also create eight scalar values
associated with the eight vertices of the cube. Figure5–17 shows the key C++ code fragments used
to create the data, and the resulting image.
The geometry of the cube is defined using an instance of the class vtkPoints . By default, the
underlying type of vtkPoints is a vtkFloatArray . The topology of the cube (i.e., polygons) is defined
with an instance of the class vtkCellArray . These define the points and polygons of the cube,
respectively. Scalar data is represented by an instance of the class vtkIntArray .
As this example shows, polygonal data is created by constructing pieces (e.g., points, cells,
and point attribute data), and then assembling the pieces to form the complete dataset. If the name
of the instance of vtkPolyData is cube, we can summarize these three steps as follows:
1. Create instance of subclass of vtkPoints to define geometry (i.e., point coordinates). Use the
operator cube->SetPoints() to associate the points with the dataset.
150 Basic Data Representation
2. Create instances of vtkCellArray to define topology for vertices, lines, polygons, and triangle
strips. Use the operators cube->SetVerts() , cube->SetLines() , cube->SetPolys() , and cube-
>SetStrips() to associate the cells with the dataset.
3. Create point and/or attribute data. Every dataset has two fields representing vtkPointData and
vtkCellData . Use the operator pd=cube->GetPointData() to retrieve the pointer to the point
attribute data. Use the operator pd=cube->GetCellData() to retrieve the pointer to the cell
attribute data. Associate the attribute data with the dataset using the operators pd-
>SetScalars() , pd->SetVectors() , pd->SetNormals() , pd->SetTensors() , and pd->SetT-
Coords() (and similar for cell data).
Polygonal data supports the following cell types: vertices, polyvertices, lines, polylines, triangles,
quadrilaterals, polygons, and triangle strips. Point and cell attribute data does not need to be defined
— you can create none, some, or all of the point and cell attributes in any combination.
The most confusing aspect of this example is the Delete() method. To prevent memory leaks
we must use a Delete() method (VTK’s destructor) after every New() method. It is apparent from
the example that the instance’s points , polys, and scalars are referred to by another object (e.g.,
cube). So doesn’t invocation of the Delete() method pose a problem?
The answer is no. Certain data objects in VTK are reference counted to conserve memory
resources (i.e., subclasses of vtkObjectBase ). That means they can be shared between objects. For
most objects the Delete() will invoke the destructor. Reference counted objects act a little differ-
ently. The Delete() method simply decrements the reference count. This may or may not destroy the
object depending on whether it is being used by another object. In this example the points , polys,
and scalars are used by the polygonal dataset cube, so they are not deleted when Delete() is
invoked. They will be freed once we free the dataset cube, that is, when their reference count drops
to zero. (See the VTK User’s Guide for more information about memory management.)
Create an Image Data Dataset. In this example, we create an image dataset (i.e., an instance of
vtkImageData ). The topology of the dataset is defined by specifying the data dimensions. The
geometry is defined by the data spacing and origin. The spacing specifies the length, width, and
height of each voxel. The origin specifies the position in 3D space of the “lower-left” corner of the
data. In our example we set the origin and spacing of the dataset so that its center lies at the origin,
and the bounds of the dataset are (-0.5,0.5, -0.5,0.5, -0.5,0.5).
In this example we create scalar data along with the image data dataset. The scalar values are
computed from the implicit function for a sphere
2 2 2 2
() ,,
Fxyz = ()x + y + z –R (5-2)
You do not need to specify origin and data spacing. By default the data spacing is (1,1,1) in the x-y-
z directions, and the origin is (0,0,0). Thus if the dimensions of the dataset are , the n x ´ n y ´ n z
default length, width, and height of the dataset will be . ()n x – 1 ,,n y – 1 n z – 1
The topological dimension of the dataset is implicitly known from its instance variables. For
example, if any of the dimensions is () n x,,n to
equal y none
z (and the other two are greater than
one), the topological dimension of the dataset is two.
Create a Structured Grid Dataset. In the next example we create a vtkStructuredGrid dataset.
Topology is implicitly defined from the dimensions of the dataset. The geometry is explicitly
defined by providing an object to represent the point coordinates. In this example we use an
instance of vtkPoints and assume that the structured grid is warped according to the equation for a
cylinder
(5-3)
xr= i cos q ,, yr= i sin q zz= i
We arbitrarily choose the number of points in the tangential direction to be thirteen, the number of
points in the radial direction to be eleven, and the number of points in the axis direction to be
´
eleven (i.e., dimensions are ).131111 ´
Vectors are generated tangential to the cylinder and of magnitude proportional to the radius.
To display the data we draw small, oriented lines at each point as shown in Figure5–19 . (This tech-
nique is called a hedgehog . See “Hedgehogs and Oriented Glyphs ” on page173 for more informa-
tion.)
The creation of a structured grid dataset is partially explicit and partially implicit. Geometry
is created explicitly be creating an instance of vtkPoints , while the topology is created implicitly by
specifying dataset dimensions. If the name of the instance of vtkStructuredGrid is sgrid, the follow-
ing three steps are used to create it.
1. Specify the dataset geometry by creating an instance of vtkPoints . Use the operator sgrid-
>SetPoints() to associate the points with the dataset.
2. The dataset topology is specified using the operator sgrid->SetDimensions() . Make sure the
number of points created in item number 1 above is equal to the implied number of points
n x ××n y n z .
3. Create point and/or cell attribute data and associate it with the dataset.
The topological dimension of the dataset is implied by the specified dimensions. For example, if
any of the dimensions (nx, n y , n z) is equal to one, the topological dimension of the dataset is two. If
two of the three dimensions (nx , n y, n z ) are equal to one, the topological dimension of the dataset is
one.
152 Basic Data Representation
vtkImageData
vtkContourFilter
vtkPolyDataMapper
Figure 5–18 Creating a image data dataset. Scalar data is generated from the equation for a sphere.
Volume dimensions are 26 3 (Vol.cxx ).
5.8 Putting It All Together 153
vtkStructuredGrid
vtkHedgehog
vtkPolyDataMapper
Figure 5–19 Creating a structured grid dataset of a semicylinder. Vectors are created whose magni-
tude is proportional to radius and oriented in tangential direction ( SGrid.cxx ).
154 Basic Data Representation
Create a Rectilinear Grid Dataset. A rectilinear grid is regular in topology and semi-regular in
geometry. Similar to a structured grid or image data dataset, topology is implicitly represented by
specifying grid dimensions. Because the grid is axis-aligned but the point coordinates along each
axis may vary, we need three data arrays to represent the geometry of the dataset, one array for each
of the x-y-z axes. Note that the cell types of the rectilinear dataset are pixels and voxels.
For maximum flexibility when creating rectilinear grids, in VTK we use three vtkDataArray
objects to define the axes arrays. This means that different native data type (e.g., unsigned char, int,
float, and so on) can be used for each axes.
To summarize the process of creating an instance of vtkRectilinearGrid , we follow four steps.
In this example (shown in Figure5–20 ), we assume that the name of the vtkRectilinearGrid
instance is rgrid .
1. Create the dataset geometry by creating three instance of vtkDataArray, one for each of the x-
y-z coordinate axes. We will assume that the number of values in each scalar is n x, n y, and nz .
2. Each of the three instances is assigned to the x, y, and z axes using the rgrid -
>SetXCoordinates() , rgrid->SetYCoordinates() , and rgrid->SetZCoordinates() methods,
respectively.
3. The dataset topology is specified using the operator rgrid->SetDimensions() . Make sure the
number of points created in item number 1 above is equal to the implied number of points
n x ××n y n z .
4. Create point and/or cell attribute data and associate it with the dataset.
The topological dimension of the dataset is implied by the specified dimensions. For example, if
any of the dimensions (nx, n y, n z ) is equal to one, the topological dimension of the dataset is two. If
two of the three dimensions (nx , n y, n z) are equal to one, the topological dimension of the dataset is
one.
Create an Unstructured Grid Dataset. Unstructured grid datasets are the most general dataset
type in both topology and geometry. In this example we “artificially” create an unstructured grid
using an instance of vtkUnstructuredGrid ( Figure5–21 ). The grid contains examples of each cell
type except for pixels and voxels. (Pixels and voxels are generally used internally to process image
data datasets. They can be explicitly created and manipulated as long as the required relationship of
point geometry is observed.) Creating the dataset structure requires creating points to define the
geometry and various cells to define the topology. (Note that in the finite element world we would
refer to these as nodes and elements .)
To summarize the process of creating an instance of vtkUnstructuredGrid , we follow five
steps. We assume the name of vtkUnstructuredGrid instance is ugrid.
1. Allocate memory for the dataset. Use the operator ugrid->Allocate() . This operator takes two
optional parameters related to the size of the data. The first is the size of the connectivity list,
and the second is the amount to extend storage (if necessary). As a rule of thumb, use the
number of cells times the average number of points defining each cell for both parameters.
Exact values for these parameters are not important, although the choice may affect perfor-
mance. If you fail to execute this operation before inserting data, the software will break.
5.8 Putting It All Together 155
vtkRectilinearGrid
vtkRectilinearGridGeometryFilter
vtkPolyDataMapper
vtkRectilinearGridGeometryFilter *plane =
vtkRectilinearGridGeometryFilter::New();
plane->SetInput(rgrid);
plane->SetExtent(0,46, 16,16, 0,43);
Figure 5–20 Creating a rectilinear grid dataset. The coordinates along each axis are defined
using an instance of vtkDataArray ( RGrid.cxx ).
156 Basic Data Representation
2. Create an instance of a subclass of vtkPoints to define the dataset geometry. Use the operator
ugrid->SetPoints() to associate the points with the dataset.
3. Create the dataset topology on a cell by cell basis by using the cell insertion operator ugrid-
>InsertNextCell() . There are various flavors of this operator, use the appropriate one.
4. Create point and/or cell attribute data and associate it with the dataset.
5. Complete the creation process by executing the ugrid->Squeeze() operator. This operator
reclaims any extra memory consumed by the data structures. Although this step is not
required, it will return memory resource back to the computer system.
The creation of unstructured grid datasets is somewhat different from the creation of the other
dataset types. This is because of the unstructured nature of the data, and the complex nature of the
internal data structures.
vtkUnstructuredGrid
vtkDataSetMapper
ugrid->SetPoints(points);
points->Delete();
5.11 References
[AVS89]
C. Upson, T. Faulhaber, Jr., D. Kamins, and others. “The Application Visualization System: A
Computational Environment for Scientific Visualization.” IEEE Computer Graphics and Appli-
cations. 9(4):30–42, July 1989.
[Bloomenthal88]
J. Bloomenthal. “Polygonization of Implicit Surfaces.” Computer Aided Geometric Design .
5(4):341–355, November 1988.
158 Basic Data Representation
[Brisson90]
E. Brisson. “Representing Geometric Structures in d-Dimensions: Topology and Order.” ACM
Symposium on Computational Geometry . ACM Press, NY, 1989.
[Gallagher75]
R. H. Gallagher. Finite Element Analysis: Fundamentals. Prentice Hall, Upper Saddle River, NJ,
1975.
[Gelberg90]
L. Gelberg, D. Kamins, D. Parker, and J. Stacks. “Visualization Techniques for Structured and Un-
structured Scientific Data.” SIGGRAPH ’90 Course Notes for State of the Art Data Visualization .
August 1990.
[Haber91]
R. B. Haber, B. Lucas, N. Collins. “A Data Model for Scientific Visualization with Provisions for
Regular and Irregular Grids.” In Proceedings of Visualization ’91 . pp. 298–395, IEEE Computer
Society Press, Los Alamitos, CA, 1991.
[Lapidus82]
L. Lapidus and G. F. Pinder. Numerical Solution of Partial Differential Equations in Science and
Engineering. John Wiley and Sons, New York, 1987.
[Mortenson85]
M. E. Mortenson. Geometric Modeling . John Wiley and Sons, New York, 1985.
[Poluzzi93]
A. Paoluzzi, F. Bernardini, C. Cattani, and V. Ferrucci. “Dimension-Independent Modeling with
Simplicial Complexes.” ACM Transactions on Graphics . 12(1):56–102, 1993.
[Schroeder94]
W. J. Schroeder and B. Yamrom. “A Compact Cell Structure for Scientific Visualization.” SIG-
GRAPH ’93 and ’94 Course Notes for Advanced Techniques for Scientific Visualization .
[Schroeder05]
W. J. Schroeder, F. Bertel, M. Malaterre, D. Thompson, P. P. Pébay, R. O'Bara and S. Tendulkar.
“Framework for Visualizing Higher-Order Basis Functions.” In Proceedings of IEEE Visualiza-
tion 2005 , pp. 43–50, Minneapolis, MN, IEEE Computer Society Press, October 2005.
[VISUAL3]
R. Haimes and M. Giles. “VISUAL3: Interactive Unsteady Unstructured 3D Visualization.”
AIAA Report No. AIAA-91-0794. January 1991.
[Weiler86]
K. J. Weiler. Topological Structures for Geometric Modeling . PhD thesis, Rensselaer Polytechnic
Institute, Troy, NY, May 1986.
[Zienkiewicz87]
O. C. Zienkiewicz and R. L. Taylor. The Finite Element Method, vol. 1 . McGraw-Hill Book Co.,
New York, 4th ed. 1987.
5.12 Exercises
2
5.1 Consider a pixmap of dimensions 100 . Compare the memory requirements to represent this
data using:
a) an image dataset,
b) a structured grid dataset,
5.12 Exercises 159
Fundamental Algorithms
6.1 Introduction
The algorithms that transform data are the heart of data visualization. To describe the various trans-
formations available, we need to categorize algorithms according to the structure and type of trans-
formation. By structure we mean the effects that transformation has on the topology and geometry
of the dataset. By type we mean the type of dataset that the algorithm operates on.
Structural transformations can be classified in four ways, depending on how they affect the
geometry, topology, and attributes of a dataset.
• Geometric transformations alter input geometry but do not change the topology of the
dataset. For example, if we translate, rotate, and/or scale the points of a polygonal dataset, the
162 Fundamental Algorithms
topology does not change, but the point coordinates, and therefore the geometry, does.
• Topological transformations alter input topology but do not change geometry and attribute
data. Converting a dataset type from polygonal data to unstructured grid data, or from image
data to unstructured grid, changes the topology but not the geometry. More often, however,
the geometry changes whenever the topology does, so topological transformation is uncom-
mon.
• Attribute transformations convert data attributes from one form to another, or create new
attributes from the input data. The structure of the dataset remains unaffected. Computing
vector magnitude or creating scalars based on elevation are data attribute transformations.
• Combined transformations change both dataset structure and attribute data. For example,
computing contour lines or surfaces is a combined transformation.
We also may classify algorithms according to the type of data they operate on, or the type of data
they generate. By type, we most often mean the type of attribute data, such as scalars or vectors.
Typical categories include:
• Scalar algorithms operate on scalar data. For example, the generation of contour lines of tem-
perature on a weather map.
• Vector algorithms operate on vector data. Showing oriented arrows of airflow (direction and
magnitude) is an example of vector visualization.
Algorithms also can be classified according to the type of data they process. This is the most com-
mon scheme found in the visualization literature. However, this scheme is not without its problems.
Often the categories overlap, resulting in confusion. For example, a category (not mentioned
above) is volume visualization , which refers to the visualization of volume data (or in our terminol-
ogy, image data). This category was initially created to describe the visualization of scalar data
arranged on a volume, but more recently, vector (and even tensor) data has been visualized on a
volume. Hence, we have to qualify our techniques to volume vector visualization , or other poten-
tially confusing combinations.
In the text that follows, we will use the attribute type classification scheme: scalar, vector,
tensor, and modelling. In cases where the algorithms operate on a particular dataset type, we place
them in the appropriate category according to our best judgment. Be forewarned, though, that alter-
native classification schemes do exist, and may be better suited to describing the true nature of the
algorithm.
6.2 Scalar Algorithms 163
rgb 0
s i < min , i0= rgb 1
rgb 2
s i > max , in1= –
si color
s i – min
in= æö------------------------------
èømax min–
rgb n-1
Most algorithms can be written specifically for a particular dataset type, or more generally, treating
any dataset type. The advantage of a specific algorithm is that it is usually faster than a comparable
general algorithm. (See “Other Data Abstractions” on page138 where we discussed the trade-off
between abstract and concrete forms.) An implementation of a specific algorithm also may be more
memory efficient and its implementation may better reflect the relationship between the algorithm
and the dataset type it operates on.
One example of this is contour surface creation. Algorithms for extracting contour surfaces
were originally developed for volume data, mainly for medical applications. The regularity of vol-
umes lends itself to efficient algorithms. However, the specialization of volume-based algorithms
precludes their use for more general datasets such as structured or unstructured grids. Although the
contour algorithms can be adapted to these other dataset types, they are less efficient than those for
volume datasets.
Our presentation of algorithms favors the more general implementations. In some special
cases we will describe performance improving techniques for particular dataset types. Refer to the
bibliography at the end of each chapter for detailed descriptions of specialized algorithms.
Color Mapping
Color mapping is a common scalar visualization technique that maps scalar data to colors, and dis-
plays the colors on the computer system. The scalar mapping is implemented by indexing into a
color lookup table . Scalar values serve as indices into the lookup table.
164 Fundamental Algorithms
The mapping proceeds as follows. The lookup table holds an array of colors (e.g., red, green,
blue components or other comparable representations). Associated with the table is a minimum and
maximum scalar range (min, max) into which the scalar values are mapped. Scalar values greater
than the maximum range are clamped to the maximum color, scalar values less than the minimum
range are clamped to the minimum color value. Then, for each scalar value si, the index i into the
color table with n entries (and 0-offset) is given by Figure6–1 .
A more general form of the lookup table is called a transfer function . A transfer function is
any expression that maps scalar value into a color specification. For example, Figure6–2 maps
scalar values into separate intensity values for the red, green, and blue color components. We can
also use transfer functions to map scalar data into other information such as local transparency.
(Transfer functions are discussed in more detail in “Transparency and Alpha Values” on page213
and “Volume Rendering” on page218 .) A lookup table is a discrete sampling of a transfer function.
We can create a lookup table from any transfer function by sampling the transfer function at a set of
discrete points.
Color mapping is a one-dimensional visualization technique. It maps one piece of informa-
tion (i.e., a scalar value) into a color specification. However, the display of color information is not
limited to one-dimensional displays. Often we use color information mapped onto 1D, 2D, or 3D
objects. This is a simple way to increase the information content of our visualizations.
The key to color mapping for scalar visualization is to choose the lookup table entries care-
fully. Figure6–3 shows four different lookup tables used to visualize gas density as fluid flows
through a combustion chamber. The first lookup table is grayscale. Grayscale tables often provide
better structural detail to the eye. The other three images in Figure6–3 use different color lookup
tables. The second uses rainbow hues from blue to red. The third uses rainbow hues arranged from
red to blue. The last table uses a table designed to enhance contrast. Careful use of colors can often
enhance important features of a dataset. However, any type of lookup table can exaggerate unim-
portant details or create visual artifacts because of unforeseen interactions between data, color
choice, and human physiology.
Designing lookup tables is as much art as it is science. From a practical point of view, tables
should accentuate important features, while minimizing less important or extraneous details. It is
also desirable to use palettes that inherently contain scaling information. For example, a color rain-
bow scale from blue to red is often used to represent temperature scale, since many people associate
“blue” with cold temperatures, and “red” with hot temperatures. However, even this scale is prob-
lematic: a physicist would say that blue is hotter than red, since hotter objects emit more blue light
Scalar Value
Figure 6–2 Transfer function for color components red, green, and blue as a function of scalar value.
6.2 Scalar Algorithms 165
Figure 6–3 Flow density colored with different lookup tables. Top-left: grayscale; Top-right rainbow
(blue to red); lower-left rainbow (red to blue); lower-right large contrast ( rainbow.tcl ).
(i.e., shorter wavelength) than red. Also, there is no need to limit ourselves to “linear” lookup
tables. Even though the mapping of scalars into colors has been presented as a linear operation
(Figure6–1 ), the table itself need not be linear. That is, tables can be designed to enhance small
variations in scalar value using logarithmic or other schemes.
There is another element to visualization that is the artistic, or aesthetic, quality. Good visual-
izations represent a balance between effective communication of information and aesthetically
pleasing presentation. While it is true in this day of mass media that information is often sacrificed
for the sake of image, improving the comfort level and engaging the human observer more deeply
in the presentation of data improves the effectiveness of communication.
166 Fundamental Algorithms
0 1 1 3 2
1 3 6 6 3
Figure 6–4 Contouring a 2D
3 7 9 7 3 structured grid with contour line
value = 5.
2 7 8 6 2
1 2 3 4 3
Contouring
A natural extension to color mapping is contouring . When we see a surface colored with data val-
ues, the eye often separates similarly colored areas into distinct regions. When we contour data, we
are effectively constructing the boundary between these regions. These boundaries correspond to
contour lines (2D) or surfaces (3D) of constant scalar value.
Examples of 2D contour displays include weather maps annotated with lines of constant tem-
perature (isotherms), or topological maps drawn with lines of constant elevation. Three-dimen-
sional contours are called isosurfaces , and can be approximated by many polygonal primitives.
Examples of isosurfaces include constant medical image intensity corresponding to body tissues
such as skin, bone, or other organs. Other abstract isosurfaces such as surfaces of constant pressure
or temperature in fluid flow also may be created.
Consider the 2D structured grid shown in Figure6–4 . Scalar values are shown next to the
points that define the grid. Contouring always begins by selecting a scalar value, or contour value,
that corresponds to the contour lines or surfaces generated. To generate the contours, some form of
interpolation must be used. This is because we have scalar values at a finite set of points in the
dataset, and our contour value may lie between the point values. Since the most common interpola-
tion technique is linear, we generate points on the contour surface by linear interpolation along the
edges. If an edge has scalar values 10 and 0 at its two end points, and if we are trying to generate a
contour line of value 5, then edge interpolation computes that the contour passes through the mid-
point of the edge.
Once the points on cell edges are generated, we can connect these points into contours using
a few different approaches. One approach detects an edge intersection (i.e., the contour passes
through an edge) and then “tracks” this contour as it moves across cell boundaries. We know that if
a contour edge enters a cell, it must exit a cell as well. The contour is tracked until it closes back on
itself, or exits a dataset boundary. If it is known that only a single contour exists, then the process
stops. Otherwise, every edge in the dataset must be checked to see whether other contour lines
exist.
Another approach uses a divide and conquer technique, treating cells independently. This is
the marching squares algorithm in 2D, and marching cubes [Lorensen87] in 3D. The basic assump-
tion of these techniques is that a contour can only pass through a cell in a finite number of ways. A
case table is constructed that enumerates all possible topological states of a cell, given combina-
tions of scalar values at the cell points. The number of topological states depends on the number of
cell vertices, and the number of inside / outside relationships a vertex can have with respect to the
6.2 Scalar Algorithms 167
contour value. A vertex is considered inside a contour if its scalar value is larger than the scalar
value of the contour line. Vertices with scalar values less than the contour value are said to be out-
side the contour. For example, if a cell has four vertices and each vertex can be either inside or out-
side the contour, there are 2 4 = 16 possible ways that the contour passes through the cell. In the case
table we are not interested in where the contour passes through the cell (e.g., geometric intersec-
tion), just how it passes through the cell (i.e., topology of the contour in the cell).
Figure6–5 shows the sixteen combinations for a square cell. An index into the case table can
be computed by encoding the state of each vertex as a binary digit. For 2D data represented on a
rectangular grid, we can represent the 16 cases with 4 bit index. Once the proper case is selected,
the location of the contour line / cell edge intersection can be calculated using interpolation. The
algorithm processes a cell and then moves, or marches t o the next cell. After all cells are visited, the
contour will be completed. In summary, the marching algorithms proceed as follows:
1. Select a cell.
2. Calculate the inside / outside state of each vertex of the cell.
3. Create an index by storing the binary state of each vertex in a separate bit.
4. Use the index to look up the topological state of the cell in a case table.
5. Calculate the contour location (via interpolation) for each edge in the case table.
This procedure will construct independent geometric primitives in each cell. At the cell boundaries
duplicate vertices and edges may be created. These duplicates can be eliminated by using a special
coincident point-merging operation. Note that interpolation along each edge should be done in the
same direction. If not, numerical round-off will likely cause points to be generated that are not pre-
cisely coincident, and will not merge properly.
There are advantages and disadvantages to both the edge-tracking and marching cubes
approaches. The marching squares algorithm is easy to implement. This is particularly important
when we extend the technique into three dimensions, where isosurface tracking becomes much
more difficult. On the other hand, the algorithm creates disconnected line segments and points, and
the required merging operation requires extra computation resources. The tracking algorithm can
Figure 6–5 Sixteen different marching squares cases. Dark vertices indicate scalar value is above
contour value. Cases 5 and 10 are ambiguous.
168 Fundamental Algorithms
Figure 6–6 Marching cubes cases for 3D isosurface generation. The 256 possible cases have been reduced
to 15 cases using symmetry. Dark vertices are greater than the selected isosurface value.
be implemented to generate a single polyline per contour line, avoiding the need to merge coinci-
dent points.
As mentioned previously, the 3D analogy of marching squares is marching cubes. Here, there
are 256 different combinations of scalar value, given that there are eight points in a cubical cell
8
(i.e., 2 combinations). Figure6–6 shows these combinations reduced to 15 cases by using argu-
6.2 Scalar Algorithms 169
1 2 1 2
4 3 4 3
Isovalue = 2.5
Figure 6–7 Using marching triangles or marching tetrahedra to resolve ambiguous cases on rectan-
gular lattice (only face of cube is shown). Choice of diagonal orientation may result in “bumps” in
contour surface. In 2D, diagonal orientation can be chosen arbitrarily, but in 3D diagonal is con-
strained by neighbor.
ments of symmetry. We use combinations of rotation and mirroring to produce topologically equiv-
alent cases.
An important issue is contouring ambiguity . Careful observation of marching squares cases
numbered 5 and 10 and marching cubes cases numbered 3, 6, 7, 10, 12, and 13 show that there are
configurations where a cell can be contoured in more than one way. (This ambiguity also exists
when using an edge tracking approach to contouring.) Contouring ambiguity arises on a 2D square
or the face of a 3D cube when adjacent edge points are in different states, but diagonal vertices are
in the same state.
In two dimensions, contour ambiguity is simple to treat: for each ambiguous case we imple-
ment one of the two possible cases. The choice for a particular case is independent of all other
choices. Depending on the choice, the contour may either extend or break the current contour as
illustrated in Figure6–8 . Either choice is acceptable since the resulting contour lines will be con-
tinuous and closed (or will end at the dataset boundary).
In three dimensions the problem is more complex. We cannot simply choose an ambiguous
case independent of all other ambiguous cases. For example Figure6–9 shows what happens if we
carelessly implement two cases independent of one another. In this figure we have used the usual
case 3 but replaced case 6 with its complementary case. Complementary cases are formed by
exchanging the “dark” vertices with “light” vertices. (This is equivalent to swapping vertex scalar
value from above the isosurface value to below the isosurface value, and vice versa.) The result of
pairing these two cases is that a hole is left in the isosurface.
Several different approaches have been taken to remedy this problem. One approach tessel-
lates the cubes with tetrahedron, and uses a marching tetrahedra technique . This works because the
marching tetrahedra exhibit no ambiguous cases. Unfortunately, the marching tetrahedra algorithm
generates isosurfaces consisting of more triangles, and the tessellation of a cube with tetrahedra
requires making a choice regarding the orientation of the tetrahedra. This choice may result in arti-
ficial “bumps” in the isosurface because of interpolation along the face diagonals as shown in
Figure6–7 . Another approach evaluates the asymptotic behavior of the surface, and then chooses
the cases to either join or break the contour. Nielson and Hamann [Nielson91] have developed a
technique based on this approach they call the asymptotic decider . It is based on an analysis of the
170 Fundamental Algorithms
Figure 6–8 Choosing a particular contour case will break (a) or join (b) the current contour. Case
shown is marching squares case 10.
Case 3 Case 6c
Figure 6–9 Arbitrarily choosing marching
cubes cases leads to holes in the isosurface.
variation of the scalar variable across an ambiguous face. The analysis determines how the edges of
isosurface polygons should be connected.
A simple and effective solution extends the original 15 marching cubes cases by adding addi-
tional complementary cases. These cases are designed to be compatible with neighboring cases and
prevent the creation of holes in the isosurface. There are six complementary cases required, corre-
sponding to the marching cubes cases 3, 6, 7, 10, 12, and 13. The complementary marching cubes
cases are shown in Figure6–10 .
We can extend the general approach of marching squares and marching cubes to other topo-
logical types. In VTK we use marching lines, triangles, and tetrahedra to contour cells of these
types (or composite cells that are composed of these types). In addition, although we speak of regu-
lar types such as squares and cubes, marching cubes can be applied to any cell type topologically
equivalent to a cube (e.g., hexahedron or noncubical voxel).
Figure6–11 shows four applications of contouring. In Figure6–11 (a) we see 2D contour
lines of CT density value corresponding to different tissue types. These lines were generated using
marching squares. Figure6–11 (b) through Figure6–11 (d) are isosurfaces created by marching
cubes. Figure6–11 (b) is a surface of constant image intensity from a computed tomography (CT)
X-ray imaging system. ( Figure6–11 (a) is a 2D subset of this data.) The intensity level corresponds
to human bone. Figure6–11 (c) is an isosurface of constant flow density. Figure6–11 (d) is an isos-
urface of electron potential of an iron protein molecule. The image shown in Figure6–11 (b) is
6.2 Scalar Algorithms 171
immediately recognizable because of our familiarity with human anatomy. However, for those
practitioners in the fields of computational fluid dynamics and molecular biology, Figure6–11 (c)
and Figure6–11 (d) are equally familiar. As these examples show, methods for contouring are pow-
erful yet general techniques for visualizing data from a variety of fields.
Scalar Generation
The two visualization techniques presented thus far, color mapping and contouring, are simple,
effective methods to display scalar information. It is natural to turn to these techniques first when
visualizing data. However, often our data is not in a form convenient to these techniques. The data
may not be single-valued (i.e., a scalar), or it may be a mathematical or other complex relationship.
That is part of the fun and creative challenge of visualization: We must tap our creative resources to
convert data into a form we can visualize.
For example, consider terrain data. We assume that the data is x-y-z coordinates, where x and
y represent the coordinates in the plane, and z represents the elevation above sea level. Our desired
visualization is to color the terrain according to elevation. This requires creating a colormap — pos-
sibly using white for high altitudes, blue for sea level and below, and various shades of green and
brown corresponding to elevation between sea level and high altitude. We also need scalars to
index into the colormap. The obvious choice here is to extract the z coordinate. That is, scalars are
simply the z-coordinate value.
This example can be made more interesting by generalizing the problem. Although we could
easily create a filter to extract the z-coordinate, we can create a filter that produces elevation scalar
values where the elevation is measured along any axis. Given an oriented line starting at the (low)
point p l (e.g., sea level) and ending at the (high) point ph (e.g., mountain top), we compute the ele-
172 Fundamental Algorithms
Figure 6–11 Contouring examples. (a) Marching squares used to generate contour
lines ( headSlic.tcl ); (b) Marching cubes surface of human bone
(headBone.tcl ); (c) Marching cubes surface of flow density ( combIso.tcl ); (d)
Marching cubes surface of iron-protein ( ironPIso.tcl ).
ph
()p i – p l × ()p h – p l
s i = ---------------------------------------------
si
2
ph – pl pi
pl
vature, or determining distance between points. Scalar generation, when coupled with color map-
ping or contouring, is a simple, yet effective, technique for visualizing many types of data.
A natural vector visualization technique is to draw an oriented, scaled line for each vector
(Figure6–13 (a)). The line begins at the point with which the vector is associated and is oriented in
()v x ,,v y v zthe resulting line must be scaled up
the direction of the vector components . Typically,
or down to control the size of its visual representation. This technique is often referred to as a
hedgehog because of the bristly result.
There are many variations of this technique ( Figure6–13 (b)). Arrows may be added to indi-
cate the direction of the line. The lines may be colored according to vector magnitude, or some
174 Fundamental Algorithms
2D Glyphs
3D Glyphs
Figure 6–13 Vector visualization techniques: (a) oriented lines; (b) using oriented glyphs; (c) com-
plex vector visualization ( complexV.tcl ).
other scalar quantity (e.g., pressure or temperature). Also, instead of using a line, oriented “glyphs”
can be used. By glyph we mean any 2D or 3D geometric representation such as an oriented triangle
or cone.
Care should be used in applying these techniques. In 3D it is often difficult to understand the
position and orientation of a vector because of its projection into a 2D image. Also, using large
numbers of vectors can clutter the display to the point where the visualization becomes meaning-
less. Figure6–13 (c) shows 167,000 3D vectors (using oriented and scaled lines) in the region of
the human carotid artery. The larger vectors lie inside the arteries, the smaller vectors lie outside the
arteries and are randomly oriented (measurement error) but small in magnitude. Clearly the details
of the vector field are not discernible from this image.
Scaling glyphs also poses interesting problems. In what Tufte has termed a “visualization
lie,” [Tufte83] scaling a 2D or 3D glyph results in nonlinear differences in appearance. The surface
area of an object increases with the square of its scale factor, so two vectors differing by a factor of
two in magnitude may appear up to four times different based on surface area. Such scaling issues
are common in data visualization, and great care must be taken to avoiding misleading viewers.
Warping
Vector data is often associated with “motion.” The motion is in the form of velocity or displace-
ment. An effective technique for displaying such vector data is to “warp” or deform geometry
according to the vector field. For example, imagine representing the displacement of a structure
under load by deforming the structure. Or if we are visualizing the flow of fluid, we can create a
flow profile by distorting a straight line inserted perpendicular to the flow.
Figure6–14 shows two examples of vector warping. In the first example the motion of a
vibrating beam is shown. The original undeformed outline is shown in wireframe. The second
example shows warped planes in a structured grid dataset. The planes are warped according to flow
momentum. The relative back and forward flow are clearly visible in the deformation of the planes.
6.3 Vector Algorithms 175
Figure 6–14 Warping geometry to show vector field; (a) Beam displacement ( vib.tcl ); (b) Flow
momentum ( velProf.tcl ).
Typically, we must scale the vector field to control geometric distortion. Too small a distor-
tion may not be visible, while too large a distortion can cause the structure to turn inside out or self-
intersect. In such a case the viewer of the visualization is likely to lose context, and the visualiza-
tion will become ineffective.
Displacement Plots
Vector displacement on the surface of an object can be visualized with displacement plots. A dis-
placement plot shows the motion of an object in the direction perpendicular to its surface. The
object motion is caused by an applied vector field. In a typical application the vector field is a dis-
placement or strain field.
Vector displacement plots draw on the ideas in “Scalar Generation” on page171 . Vectors are
converted to scalars by computing the dot product between the surface normal and vector at each
point ( Figure6–15 (a)). If positive values result, the motion at the point is in the direction of the
surface normal (i.e., positive displacement). Negative values indicate that the motion is opposite
the surface normal (i.e., negative displacement).
A useful application of this technique is the study of vibration. In vibration analysis, we are
interested in the eigenvalues (i.e., natural resonant frequencies) and eigenvectors (i.e., mode
shapes) of a structure. To understand mode shapes we can use displacement plots to indicate
regions of motion. There are special regions in the structure where positive displacement changes
to negative displacement. These are regions of zero displacement. When plotted on the surface of
the structure, these regions appear as the so-called modal lines of vibration. The study of modal
lines has long been an important visualization tool for understanding mode shapes.
176 Fundamental Algorithms
n
v
svn= ×
Figure 6–15 Vector displacement plots. (a) Vector converted to scalar via dot product computation;
(b) Surface plot of vibrating plate. Dark areas show nodal lines. Bright areas show maximum motion
(dispPlot.tcl ).
Figure6–15 (b) shows modal lines for a vibrating rectangular beam. The vibration mode in
this figure is the second torsional mode, clearly indicated by the crossing modal lines. (The aliasing
in the figure is because of the coarseness of the analysis mesh.) To create the figure we combined
the procedure of Figure6–15 (a) with a special lookup table. The lookup table was arranged with
dark areas in the center (i.e., corresponds to zero dot product) and bright areas at the beginning and
end of the table (corresponds to 1 or -1 dot product). As a result, regions of large normal displace-
ment are bright and regions near the modal lines are dark.
Time Animation
Some of the techniques described so far can be thought of as moving a point or object over a small
time step. The hedgehog line is an approximation of a point’s motion over a time period whose
duration is given by the scale factor. In other words, if velocity , then Vx dt ¤ d
the=displace-
ment of a point is
dVt
x = d (6-1)
This suggests an extension to our previous techniques: repeatedly displace points over many time
steps. Figure6–16 shows such an approach. Beginning with a sphere S centered about some point
C, we move S repeatedly to generate the bubbles shown. The eye tends to trace out a path by con-
necting the bubbles, giving the observer a qualitative understanding of the fluid flow in that area.
The bubbles may be displayed as an animation over time (giving the illusion of motion) or as a
multiple exposure sequence (giving the appearance of a path).
6.3 Vector Algorithms 177
Initial position
Instantaneous
velocity Final position
Figure 6–16 Time animation of a point C . Although the spacing between points varies, the time
increment between each point is constant.
Such an approach can be misused. For one thing, the velocity at a point is instantaneous.
Once we move away from the point the velocity is likely to change. Using Equation6-1 above
assumes that the velocity is constant over the entire step. By taking large steps we are likely to jump
over changes in the velocity. Using smaller steps we will end in a different position. Thus the
choice of step size is a critical parameter in constructing accurate visualization of particle paths in a
vector field.
To evaluate Equation6-1 we can express it as an integral:
xt() =
òt Vtd (6-2)
Although this form cannot be solved analytically for most real world data, its solution can be
approximated using numerical integration techniques. Accurate numerical integration is a topic
beyond the scope of this book, but it is known that the accuracy of the integration is a function of
the step size dt. Since the path is an integration throughout the dataset, the accuracy of the cell
interpolation functions, as well as the accuracy of the original vector data, plays an important role
in realizing accurate solutions. No definitive study is yet available that relates cell size or interpola-
tion function characteristics to visualization error. But the lesson is clear: the result of numerical
integration must be examined carefully, especially in regions of large vector field gradient. How-
ever, as with many other visualization algorithms, the insight gained by using vector integration
techniques is qualitatively beneficial, despite the unavoidable numerical errors.
The simplest form of numerical integration is Euler’s method,
x i1+ = x i + V i Dt (6-3)
Figure 6–17 Euler’s integration (b) and Runge-Kutta integration of order 2 (c) applied to uniform
rotational vector field (a). Euler’s method will always diverge.
In this text we will use the Runge-Kutta technique of order 2 [Conte72] . This is given by the
expression
Dt () (6-4)
x i1+ = x i + -----Vi + V i1+
2
1. Improving search procedures. There are two distinct types of searches. Initially, the starting
location of the particle must be determined by a global search procedure. Once the initial
location of the point is determined in the dataset, an incremental search procedure can then be
used. Incremental searching is efficient because the motion of the point is limited within a
single cell, or at most across a cell boundary. Thus, the search space is greatly limited, and the
incremental search is faster relative to the global search.
2. Coordinate transformation. The cost of a coordinate transformation from global to local
coordinates can be reduced if either of the following conditions are true: the local and global
coordinate systems are identical with one another (or vary by x-y-z translation), or if the vec-
tor field is transformed from global space to local coordinate space. The image data coordi-
nate system is an example of a local coordinates which are parallel to global coordinates,
hence global to local coordinate transformation can be greatly accelerated. If the vector field
is transformed into local coordinates (either as a preprocessing step or on a cell-by-cell
basis), then the integration can proceed completely in local space. Once the integration path
is computed, selected points along the path can be transformed into global space for the sake
of visualization.
Streamlines
A natural extension of the previous time animation techniques is to connect the point position xt()
over many time steps. The result is a numerical approximation to a particle trace represented as a
line.
Borrowing terminology from the study of fluid flow, we can define three related line repre-
sentation schemes for vector fields.
sVs,
òt
= with
d = () ,
ssxt (6-5)
Figure 6–18 Flow velocity computed for a small kitchen (top and side view). Forty streamlines start
along the rake positioned under the window. Some eventually travel over the hot stove and are con-
vected upwards ( Kitchen.cxx ).
a straight line. These streamlines clearly show features of the flow field. By releasing many stream-
lines simultaneously we obtain even more information, as the eye tends to assemble nearby stream-
lines into a “global” understanding of flow field features.
Many enhancements of streamline visualization exist. Lines can be colored according to
velocity magnitude to indicate speed of flow. Other scalar quantities such as temperature or pres-
sure also may be used to color the lines. We also may create constant time dashed lines. Each dash
represents a constant time increment. Thus, in areas of high velocity, the length of the dash will be
greater relative to regions of lower velocity. These techniques are illustrated in Figure6–19 for air-
flow around a blunt fin. This example consists of a wall with half a rounded fin projecting into the
fluid flow. (Using arguments of symmetry, only half of the domain was modeled.) Twenty-five
streamlines are released upstream of the fin. The boundary layer effects near the junction of the fin
and wall are clearly evident from the streamlines. In this area, flow recirculation is apparent, as well
as the reduced flow speed.
As we mentioned earlier, tensor visualization is an active area of research. However there are a few
simple techniques that we can use to visualize real 33´symmetric tensors. Such tensors are used
to describe the state of displacement or stress in a 3D material. The stress and strain tensors for an
elastic material are shown in Figure6–20 .
In these tensors the diagonal coefficients are the so-called normal stresses and strains, and the
off-diagonal terms are the shear stresses and strains. Normal stresses and strains act perpendicular
to a specified surface, while shear stresses and strains act tangentially to the surface. Normal stress
is either compression or tension, depending on the sign of the coefficient.
6.4 Tensor Algorithms 181
Figure 6–19 Dashed streamlines around a blunt fin. Each dash is a constant time increment. Fast
moving particles create longer dashes than slower moving particles. The streamlines also are colored
by flow density scalar ( bluntStr.cxx ).
A 33´
real symmetric matrix can be characterized by three vectors in 3D called the eigen-
vectors, and three numbers called the eigenvalues of the matrix. The eigenvectors form a 3D coor-
dinate system whose axes are mutually perpendicular. In some applications, particularly the study
of materials, these axes also are referred to as the principle axes of the tensor and are physically sig-
nificant. For example, if the tensor is a stress tensor, then the principle axes are the directions of
normal stress and no shear stress. Associated with each eigenvector is an eigenvalue. The eigenval-
ues are often physically significant as well. In the study of vibration, eigenvalues correspond to the
resonant frequencies of a structure, and the eigenvectors are the associated mode shapes.
Mathematically we can represent eigenvalues and eigenvectors as follows. Given a matrix A,
the eigenvector and
x eigenvalue must l satisfy the relation
Ax×l = x (6-6)
detA – lI = 0 (6-7)
th
Expanding this equation yields a n degree polynomial in whosel roots are the eigenvalues. Thus,
there are always n eigenvalues, although they may not be distinct. In general, Equation6-7 is not
solved using polynomial root searching because of poor computational performance. (For matrices
of order 3 root searching is acceptable because we can solve for the eigenvalues analytically.) Once
we determine the eigenvalues, we can substitute each into Equation6-7 to solve for the associated
eigenvectors.
We can express the eigenvectors of the system
33´ as
v i = l i e i , with i123
= ,, (6-8)
182 Fundamental Algorithms
¶u æö¶u + ¶v æö¶u + ¶w
s x t xy t xz ¶x èø¶ y ¶ z èø¶ z ¶ x
tyx s y t yz
æö¶u + ¶v ¶v æö¶v + ¶w
t zx t zy s z èø¶ y ¶ z ¶y èø¶ z ¶ y
æö¶u + ¶w æö¶v + ¶w ¶w
èø¶ z ¶ x èø¶ z ¶ y ¶z
Figure 6–20 Stress and strain tensors. Normal stresses in the x-y-z coordinate directions indicated as
d()s x,,s y s z, shear stresses indicated as . Material
t ij displacement represented by u, v, w compo-
nents.
li
with eai unit vector in the direction of the eigenvalue, and the eigenvalues of the system. If we
order eigenvalues such that
l 1 ³³l 2 l3 (6-9)
Tensor Ellipsoids
This leads us to the tensor ellipsoid technique for the visualization of real, symmetric matri-33´
ces. The first step is to extract eigenvalues and eigenvectors as described in the previous section.
Since eigenvectors are known to be orthogonal, the eigenvectors form a local coordinate system.
These axes can be taken as the minor , medium , and major axes of an ellipsoid. Thus, the shape and
orientation of the ellipsoid represent the relative size of the eigenvalues and the orientation of the
eigenvectors.
To form the ellipsoid we begin by positioning a sphere at the tensor location. The sphere is
then rotated around its origin using the eigenvectors, which in the form of Equation6-8 are direc-
tion cosines. The eigenvalues are used to scale the sphere. Using transformation
44´ matrices and
referring to Equation3-6 , Equation3-9 , and Equation3-13 , we form the ellipsoid by transforming
the sphere centered at the origin using the matrix T
(remember to read right-to-left). The eigenvectors can be directly plugged in to create the rotation
matrix, while the point coordinates x-y-z and eigenvalues l 1 ³³l 2 l 3 are inserted into the transla-
tion and scaling matrices. A concatenation of these matrices forms the final transformation matrix
T.
Figure6–21 (a) depicts the tensor ellipsoid technique. In Figure6–21 (b) we show this tech-
nique to visualize material stress near a point load on the surface of a semi-infinite domain. (This is
6.4 Tensor Algorithms 183
x
r
z
(a) Tensor ellipsoid (b) Point load on semiinfinite domain
2 2
P æö3zx
s x = – ------------
æöz
– () – n ç÷---
r ()2r + z
+ x--------------------------
ç÷
------------12 – ------------
2pr
2 èø 3
r èør r + z rr() + z
2
2 2
P æö3zy æöz r y ()2r + z
s y = – ------------ – () – n ç÷---– ------------
ç÷------------12 + --------------------------
2
2pr èø r
3 èør r + z rr() + z 2
3
3Pz
s z = – ------------
5
2pr
P æö3xyz xy2() r + z
txy = t yx = – ------------ – () – n æö
------------12 èø---------------------------
2 èø 3 2
2pr r rr() + z
2
txz = t zx = – 3Pxz
---------------
5
2pr c) Analytic solution
2
3Pyz
tyz = t zy = – ---------------
5
2pr
Figure 6–21 Tensor ellipsoids. (a) Ellipsoid oriented along eigenvalues (i.e., principle axes) of ten-
sor; (b) Pictorial description of Boussinesq’s problem; (c) Analytic results according to Saada.
the so-called Boussinesq’s problem.) From Saada [Saada74] we have the analytic expression for
the stress components in Cartesian coordinates shown in Figure6–21 (c). Note that the z-direction
is defined as the axis originating at the point of application of the force P. The variable is r the dis-
tance from the point of load application to a point x-y-z. The orientation of the x and y axes are in
the plane perpendicular to the z axis. (The rotation in the plane of these axes is unimportant since
the solution is symmetric around the z axis.) (The parameter isnPoisson’s ratio which is a prop-
erty of the material. Poisson’s ratio relates the lateral contraction of a material to axial elongation
under a uniaxial stress condition. See [Saada74] or [Timoshenko70] for more information.)
184 Fundamental Algorithms
Figure 6–22 Tensor visualization techniques; (a) Tensor axes ( TenAxes.tcl) ; (b) Ten-
sor ellipsoids ( TenEllip.tcl ).
In Figure6–22 we visualize the analytical results of Boussinesq’s problem from Saada. The
left-hand portion of the figure shows the results by displaying the scaled and oriented principal axes
of the stress tensor. (These are called tensor axes .) In the right-hand portion we use tensor ellipsoids
to show the same result. Tensor ellipsoids and tensor axes are a form of glyph (see “Glyphs” on
page190 ) specialized to tensor visualization.
A certain amount of care must be taken to visualize this result since there is a stress singular-
ity at the point of contact of the load. In a real application loads are applied over a small area and
not at a single point. Also, plastic behavior prevents stress levels from exceeding a certain point.
The results of the visualization, as with any computer process, are only as good as the underlying
model.
Source Objects
As we have seen in previous examples, source objects begin the visualization pipeline. Source
objects are used to create geometry such as spheres, cones, or cubes to support visualization context
or are used to read in data files. Source objects also may be used to create dataset attributes. Some
examples of source objects and their use are as follows.
6.5 Modelling Algorithms 185
Modelling Simple Geometry. Spheres, cones, cubes, and other simple geometric objects can be
used alone or in combination to model geometry. Often we visualize real-world applications such
as air flow in a room and need to show real-world objects such as furniture, windows, or doors.
Real-world objects often can be represented using these simple geometric representations. These
source objects generate their data procedurally. Alternatively, we may use reader objects to access
geometric data defined in data files. These data files may contain more complex geometry such as
that produced by a 3D CAD (Computer-Aided Design) system.
Supporting Geometry. During the visualization process we may use source objects to create sup-
porting geometry. This may be as simple as three lines to represent a coordinate axis or as complex
as tubes wrapped around line segments to thicken and enhance their appearance. Another common
use is as supplemental input to objects such as streamlines or probe filters. These filters take a sec-
ond input that defines a set of points. For streamlines, the points determine the initial positions for
generating the streamlines. The probe filter uses the points as the position to compute attribute val-
ues such as scalars, vectors, or tensors.
Data Attribute Creation. Source objects can be used as procedures to create data attributes. For
example, we can procedurally create textures and texture coordinates. Another use is to create sca-
lar values over a uniform grid. If the scalar values are generated from a mathematical function, then
we can use the visualization techniques described here to visualize the function. In fact, this leads
us to a very important class of source objects: implicit functions.
Implicit Functions
() ,,
Fxyz = c (6-11)
• Simple geometric description. Implicit functions are convenient tools to describe common
geometric shapes. This includes planes, spheres, cylinders, cones, ellipsoids, and quadrics .
• Region separation. Implicit functions separate 3D Euclidean space into three distinct regions.
These regions are inside, on, and outside the implicit function. These regions are defined as
() ,,
Fxyz < 0 , , Fxyz
() ,, respectively.
and = 0 () ,,
Fxyz >0
• Scalar generation. Implicit functions convert a position in space into a scalar value. That is,
()x i,,y i zai scalar value
given an implicit function we can sample it at a point to generate
ci .
An example of an implicit function is the equation for a sphere of radius R
2 2 2 2
() ,,
Fxyz = x +y +z –R (6-12)
() ,surface
This simple relationship defines the three regions (on Fxyz
the , =of 0the sphere),
() ,,
Fxyz < 0 (inside the sphere), and (outside
() ,, the>sphere).
Fxyz 0 Any point may be clas-
sified inside, on, or outside the sphere simply by evaluating Equation6-12 .
186 Fundamental Algorithms
F>0 F<0
F=0
Figure 6–23 Sampling functions: (a) 2D depiction of sphere sampling; (b) Isosurface of sampled
sphere; (c) Boolean combination of two spheres, a cone, and two planes. (One sphere intersects the
other, the planes clip the cone.) (Refer to sphere.tcl and iceCream.tcl )
Implicit functions have a variety of uses. This includes geometric modelling, selecting data,
and visualizing complex mathematical descriptions.
Modelling Objects. Implicit functions can be used alone or in combination to model geometric
objects. For example, to model a surface described by an implicit function, we sample F on a
dataset and generate an isosurface at a contour value ci. The result is a polygonal representation of
the function. Figure6–23 (b) shows an isosurface for a sphere of radius=1 sampled on a volume.
Note that we can choose nonzero contour values to generate a family of offset surfaces. This is use-
ful for creating blending functions and other special effects.
Implicit functions can be combined to create complex objects using the boolean operators
FGÈ two functions
union, intersection, and difference. The union operation between () ,,
Fxyz
and at ()
Gxyz ,,
a point ()x 0,,value
is the minimum y 0 z0
Figure6–23 (c) shows a combination of simple implicit functions to create an ice-cream cone. The
cone is created by clipping the (infinite) cone function with two planes. The ice cream is con-
structed by performing a difference operation on a larger sphere with a smaller offset sphere to cre-
ate the “bite.” The resulting surface was extracted using surface contouring with isosurface value
0.0.
6.5 Modelling Algorithms 187
(a) Selecting data with implicit function (b) Selecting data with boolean combination
Figure 6–24 Implicit functions used to select data: (a) 2D cells lying in ellipse are selected; (b) Two
ellipsoids combined using the union operation used to select voxels from a volume. Voxels shrunk 50
percent ( extractD.tcl ).
Selecting Data. We can take advantage of the properties of implicit functions to select and cut data.
In particular we will use the region separation property to select data. (We defer the discussion on
cutting to “Cutting” on page191 .)
Selecting or extracting data with an implicit function means choosing cells and points (and
associated attribute data) that lie within a particular region of the function. To determine whether a
point x-y-z lies within a region, we simply evaluate the point and examine the sign of the result. A
cell lies in a region if all its points lie in the region.
Figure6–24 (a) shows a 2D implicit function, here an ellipse, used to select the data (i.e.,
points, cells, and data attributes) contained within it. Boolean combinations also can be used to cre-
ate complex selection regions as illustrated in Figure6–24 (b). Here, two ellipses are used in com-
bination to select voxels within a volume dataset. Note that extracting data often changes the
structure of the dataset. In Figure6–24 the input type is a image data dataset, while the output type
is an unstructured grid dataset.
Figure 6–25 Visualizing a Lorenz strange attractor by integrating the Lorenz equations in a volume.
The number of visits in each voxel is recorded as a scalar function. The surface is extracted via march-
ing cubes using a visit value of 50. The number of integration steps is 10 million, in a volume of
dimensions 200 3 . The surface roughness is caused by the discrete nature of the evaluation function
(Lorenz.cxx ).
A classical strange attractor was developed by Lorenz in 1963 [Lorenz63] . Lorenz developed
a simple model for thermally induced fluid convection in the atmosphere. Convection causes rings
of rotating fluid and can be developed from the general Navier-Stokes partial differential equations
for fluid flow. The Lorenz equations can be expressed in non-dimensional form as
dx = s ()yx–
dt
dy (6-16)
= rxy– – xz
dt
dz
= xy – b z
dt
where x is proportional to the fluid velocity in the fluid ring, y and z measure the fluid temperature
in the plane of the ring, the parameters andsare related
r to the Prandtl number and Raleigh
number, respectively, and isb a geometric factor.
Certainly these equations are not in the implicit form of Equation6-11 , so how do we visual-
ize them? Our solution is to treat the variables x, y, and z as the coordinates of a three-dimensional
space, and integrate Equation6-16 to generate the system “trajectory”, that is, the state of the sys-
tem through time. The integration is carried out within a volume and scalars are created by counting
the number of times each voxel is visited. By integrating long enough, we can create a volume rep-
resenting the “surface” of the strange attractor, Figure6–25 . The surface of the strange attractor is
extracted by using marching cubes and a scalar value specifying the number of visits in a voxel.
6.5 Modelling Algorithms 189
d d
Implicit Modelling
In the previous section we saw how implicit functions, or boolean combinations of implicit func-
tions, could be used to model geometric objects. The basic approach is to evaluate these functions
on a regular array of points, or volume, and then to generate scalar values at each point in the vol-
ume. Then either volume rendering (see “Volume Rendering” on page218 ), or isosurface generation
in combination with surface rendering, is used to display the model.
An extension of this approach, called implicit modeling, is similar to modeling with implicit
functions. The difference lies in the fact that scalars are generated using a distance function instead
of the usual implicit function. The distance function is computed as a Euclidean distance to a set of
generating primitives such as points, lines, or polygons. For example, Figure6–26 shows the dis-
tance functions to a point, line, and triangle. Because distance functions are well-behaved mono-
tonic functions, we can define a series of offset surfaces by specifying different isosurface values,
where the value is the distance to the generating primitive. The isosurfaces form approximations to
the true offset surfaces, but using high volume resolution we can achieve satisfactory results.
Used alone the generating primitives are limited in their ability to model complex geometry.
By using boolean combinations of the primitives, however, complex geometry can be easily mod-
eled. The boolean operations union, intersection, and difference ( Equation6-13 , Equation6-14 ,
and Equation6-15 , respectively) are illustrated in Figure6–27 . Figure6–28 shows the application
of implicit modeling to “thicken” the line segments in the text symbol “HELLO”. The isosurface is
generated on a volume ´ at ´
1104020 a distance offset of 0.25 units. The generating primitives
were combined using the boolean union operator. Although Euclidean distance is always a nonneg-
ative value, it is possible to use a signed distance function for objects that have an outside and an
inside. A negative distance is the negated distance of a point inside the object to the surface of the
object. Using a signed distance function allows us to create offset surfaces that are contained within
the actual surface.
Another interesting feature of implicit modeling is that when isosurfaces are generated, more
than one connected surface can result. These situations occur when the generating primitives form
concave features. Figure6–29 illustrates this situation. If desired, multiple surfaces can be sepa-
rated by using the connectivity algorithm described in “Connectivity” on page373 .
190 Fundamental Algorithms
Figure 6–27 Boolean operations using points and lines as generating primitives.
isodistance
contours
Figure 6–29 Concave
features can result in mul-
tiple contour lines/sur-
faces.
Glyphs
Glyphs, sometimes referred to as icons, are a versatile technique to visualize data of every type. A
glyph is an “object” that is affected by its input data. This object may be geometry, a dataset, or a
graphical image. The glyph may orient, scale, translate, deform, or somehow alter the appearance
of the object in response to data. We have already seen a simple form of glyph: hedgehogs are lines
that are oriented, translated and scaled according to the position and vector value of a point. A vari-
ation of this is to use oriented cones or arrows. (See “Hedgehogs and Oriented Glyphs” on page173
for more information.)
More elaborate glyphs are possible. In one creative visualization technique Chernoff
[Chernoff73] tied data values to an iconic representation of the human face. Eyebrows, nose, mouth,
and other features were modified according to financial data values. This interesting technique built
6.5 Modelling Algorithms 191
on the human capability to recognize facial expression. By tying appropriate data values to facial
characteristics, rapid identification of important data points is possible.
In a sense, glyphs represent the fundamental result of the visualization process. Moreover, all
the visualization techniques we present can be treated as concrete representations of an abstract
glyph class. For example, while hedgehogs are an obvious manifestation of a vector glyph, isosur-
faces can be considered a topologically two-dimensional glyph for scalar data. Delmarcelle and
Hesselink [Delmarcelle95] have developed a unified framework for flow visualization based on
types of glyphs. They classify glyphs according to one of three categories.
• Elementary icons represent their data across the extent of their spatial domain. For example,
an oriented arrow can be used to represent surface normal.
• Local icons represent elementary information plus a local distribution of the values around
the spatial domain. A surface normal vector colored by local curvature is one example of a
local icon, since local data beyond the elementary information is encoded.
• Global icons show the structure of the complete dataset. An isosurface is an example of a
global icon.
This classification scheme can be extended to other visualization techniques such as vector and ten-
sor data, or even to nonvisual forms such as sound or tactile feedback. We have found this classifi-
cation scheme to be helpful when designing visualizations or creating visualization techniques.
Often it gives insight into ways of representing data that can be overlooked.
Figure6–30 is an example of glyphing. Small 3D cones are oriented on a surface to indicate
the direction of the surface normal. A similar approach could be used to show other surface proper-
ties such as curvature or anatomical key-points.
Cutting
Often we want to cut through a dataset with a surface and then display the interpolated data values
on the surface. We refer to this technique as data cutting or simply cutting . The data cutting opera-
tion requires two pieces of information: a definition for the surface and a dataset to cut. We will
192 Fundamental Algorithms
assume that the cutting surface is defined by an implicit function. A typical application of cutting is
to slice through a dataset with a plane, and color map the scalar data and/or warp the plane accord-
ing to vector value.
A property of implicit functions is to convert a position into a scalar value (see “Implicit Func-
tions” on page185 ). We can use this property in combination with a contouring algorithm (e.g.,
marching cubes) to generate cut surfaces. The basic idea is to generate scalars for each point of
each cell of a dataset (using the implicit cut function), and then contour the surface value
() ,,
Fxyz = 0 .
The cutting algorithm proceeds as follows. For each cell, function values are generated by
evaluating for () each
Fxyz ,, cell point. If all the points evaluate positive or negative, then the sur-
face does not cut the cell. However, if the points evaluate positive and negative, then the surface
passes through the cell. We can use the cell contouring operation to generate the isosurface
() ,,
Fxyz = 0 . Data attribute values can then be computed by interpolating along cut edges.
Figure6–31 illustrates a plane cut through a structured grid dataset. The plane passes
through the center of the dataset with normal (–0.287, 0, 0.9579). For comparison purposes a por-
tion of the grid geometry is also shown. The grid geometry is the grid surface k=9 (shown in wire-
frame). A benefit of cut surfaces is that we can view data on (nearly) arbitrary surfaces. Thus, the
structure of the dataset does not constrain how we view the data.
We can easily make multiple planar cuts through a structured grid dataset by specifying mul-
tiple isovalues for the cutting algorithm. Figure6–32 shows 100 cut planes generated perpendicu-
lar to the camera’s view plane normal. Rendering the planes from back to front with an opacity of
0.05 produces a simulation of volume rendering (see “Volume Rendering” on page218 ).
This example illustrates that cutting the volumetric data in a structured grid dataset produced
polygonal cells. Similarly, cutting polygonal data produces lines. Using a single plane equation, we
can extract “contour lines” from a surface model defined with polygons. Figure6–33 shows con-
tours extracted from a surface model of the skin. At each vertex in the surface model we evaluate
the equation of the plane and ()store
Fxyz ,, the= value
c of the function as a scalar value. Cut-
ting the data with 46 isovalues from 1.5 to 136.5 produces contour lines that are 3 units apart.
6.6 Putting It All Together 193
Figure 6–32 100 cut planes with opacity of 0.05. Rendered back-to-front to simulate
volume rendering ( PseudoVolumeRendering.tcl ).
Algorithms are implemented in the Visualization Toolkit as process objects. These objects may be
either sources, filters, or mappers (see “The Visualization Pipeline” on page85 ). In this section we
will describe how these objects are implemented.
Source Design. Source objects have no visualization data for input and one or more outputs,
Figure6–34 . To create a source object, inheritance is used to specify the type of dataset that the
194 Fundamental Algorithms
vtkAlgorithm
vtkSphereSource
vtkPoly DataAlgorithm
vtkPolyData
vtkSphereSource
Figure 6–34 Source object design. Example shown is a source object that creates a polygonal repre-
sentation of a sphere.
process object creates for output. Figure6–34 illustrates this for the concrete source object
vtkSphereSource . This class inherits from vtkPolyDataAlgorithm , indicating that it creates polygo-
nal data on output.
The convenience object vtkPolyDataAlgorithm has been created to simplify subclass deriva-
tion. For example, vtkBYUReader is also of type vtkPolyDataAlgorithm . The major difference
between vtkSphereSource and vtkBYUReader is the implementation of the virtual method
RequestData() . This method actually creates its output data. If you derive a source object you do
not need to make it a subclass of any convenience object (e.g., vtkPolyDataAlgorithm ), but you
should derive it from vtkAlgorithm .
Filter Design. Filter objects have one or more inputs and one or more outputs as shown in
Figure6–35 . (You may also refer to “Pipeline Design and Implementation” on page103 .) To create
a filter object, inheritance is used to specify the type of input and output data objects. Figure6–35
illustrates this for the concrete source object vtkContourFilter (which implements marching cubes
and other contouring techniques). It is worth examining this object diagram in detail since it is the
basis for the architecture of the visualization pipeline.
The superclasses of vtkContourFilter are vtkAlgorithm and vtkPolyDataAlgorithm . The class
vtkPolyDataAlgorithm specifies the type of data vtkContourFilter produces on output (i.e., a
vtkPolyData ). Because this filter should take any subclass of vtkDataSet as input, it must override
its superclasses implementation of the FillInputPortInformation() method to specify this. Note that
inheritance from vtkPolyDataAlgorithm is optional—this functionality could be implemented
directly in vtkContourFilter . This optional superclass is simply a convenience object to make class
derivation a little easier.
What is left for vtkContourFilter to implement is its RequestData() method (as well as con-
structor, print method, and any other methods special to this class). Thus the primary difference
between classes with equivalent inheritance hierarchies is the implementation of the RequestData()
method.
Subclasses of vtkAlgorithm enforce filter input and output type by use of the FillInputPortIn-
formation() and FillOutputPortInformation() methods. By default, its subclass vtkDataSetAlgo-
rithm accepts input type vtkDataSet (or subclasses) and produces a vtkDataSet on output. (The type
6.6 Putting It All Together 195
vtkDataSet
vtkAlgorithm
vtkPolyDataAlgorithm
vtkContourFilter
vtkContourFilter
vtkPolyData
Figure 6–35 Filter object design. The example shown is for an object that receives a general dataset
as input and creates polygonal data on output.
vtkPolyDataMapper vtkDataWriter
vtkPolyDataMapper vtkSTLWriter
Figure 6–36 Mapper object design. Graphics mapper shown (e.g., vtkSTLWriter
vtkPolyDataMapper ) maps polygonal data through graphics
library primitives. Writer shown (e.g., vtkSTLWriter ) writes polyg-
onal data to stereo lithography format.
of the output is determined by the type of the input .) Since vtkDataSet is a base class for all data
types, subclasses of vtkDataSetAlgorithm will accept any type as input. Specialized filters are
derived from other classes. For example, filters that accept polygonal data might be derived from
vtkPolyDataAlgorithm , and filters that accept unstructured grid datasets might be derived from
vtkUnstructuredGridAlgorithm .
We encourage you to examine the source code carefully for a few filter and source objects.
The architecture is simple enough that you can grasp it quickly.
Mapper Design. Mapper objects have one or more inputs and no visualization data output,
Figure6–36 . Two different types of mappers are available in the Visualization Toolkit : graphics
mappers and writers. Graphics mappers interface geometric structure and data attributes to the
graphics library; writers write datasets to disk or other I/O devices.
196 Fundamental Algorithms
Since mappers take datasets as input, type enforcement is required. Each mapper implements
this functionality directly. For example, both classes vtkPolyDataMapper and vtkSTLWriter imple-
ment a SetInput() method to enforce the input to be of type vtkPolyData . Other mappers and writers
enforce input type as appropriate.
Although writers and mappers do not create visualization data, they both have methods simi-
lar to the RequestData() method of the sources and filters. Each subclass of vtkMapper must imple-
ment the Render() method. This method is exchanged by the graphics system actors and its
associated mappers during the rendering process. The effect of the method is to map its input
dataset to the appropriate rendering library/system. Subclasses of the class vtkWriter must imple-
ment the WriteData() method. This method causes the writer to write its input dataset to disk (or
other I/O device).
Color Maps
Color maps are created in the Visualization Toolkit using instances of the class vtkLookupTable .
This class allows you to create a lookup table using HSVA (e.g., hue, saturation, value, and alpha
opacity value) specification. Although we discussed the HSV color system in Chapter 3 , we
haven’t yet defined alpha opacity. We shall do so in Chapter 7 , but until then consider the alpha
value to be the opacity of an object. Alpha values of one indicate that the object is opaque, while
alpha values of zero indicate that the object is transparent.
The procedure for generating lookup table entries is to define pairs of values for HSVA.
These pairs define a linear ramp for hue, saturation, value, and opacity. When the Build() method is
invoked, these linear ramps are used to generate a table with the number of table entries requested.
Alternatively, vtkLookupTable also enables you to load colors directly into the table. Thus, you
build custom tables that cannot be simply expressed as linear ramps of HSVA values.
To demonstrate this procedure, we specify a starting and ending value for each of the compo-
nents of HSVA, then we will create a rainbow lookup table from blue to red by using the following
C++ code.
vtkLookupTable *lut=vtkLookupTable::New();
lut->SetHueRange(0.6667, 0.0);
lut->SetSaturationRange(1.0, 1.0);
lut->SetValueRange(1.0, 1.0);
lut->SetAlphaRange(1.0, 1.0);
lut->SetNumberOfColors(256);
lut->Build();
Since the default values for SaturationRange , ValueRange , AlphaRange , and the number of lookup
table colors are (1,1), (1,1), (1,1), and 256, respectively, we can simplify this process to the follow-
ing
vtkLookupTable *lut=vtkLookupTable::New();
lut->SetHueRange(0.6667, 0.0);
lut->Build();
(The default values for HueRange are (0.0, 0.6667) — a red to blue color table.)
To build a black and white lookup table of 256 entries we use
6.6 Putting It All Together 197
vtkLookupTable *lut=vtkLookupTable::New();
lut->SetHueRange(0.0, 0.0);
lut->SetSaturationRange(0.0, 0.0);
lut->SetValueRange(0.0, 1.0)
In some cases you may want to specify colors directly. You can do this by specifying the number of
colors, building the table, and then inserting new colors. When you insert colors, the RGBA color
description system is used. For example, to create a lookup table of the three colors red, green, and
blue, use the following C++ code.
vtkLookupTable *lut=vtkLookupTable::New();
lut->SetNumberOfColors(3);
lut->Build();
lut->SetTableValue(0, 1.0, 0.0, 0.0, 1.0);
lut->SetTableValue(0, 0.0, 1.0, 0.0, 1.0);
lut->SetTableValue(0, 0.0, 0.0, 1.0, 1.0);
Lookup tables in the Visualization Toolkit are associated with the graphics mappers. Mappers will
automatically create a red to blue lookup table if no table is specified, but if you want to create your
own, use the mapper->SetLookupTable(lut) operation where mapper is an instance of vtkMapper or
its subclasses.
A few final notes on using lookup tables.
• Mappers use their lookup table to map scalar values to colors. If no scalars are present, the
mappers and their lookup tables do not control the color of the object. Instead the vtkProperty
object associated with the vtkActor class does. Use vtkProperty’s method
actor->GetProperty()->SetColor(r,g,b) where r, g, and b are floating-point values specifying
color.
• If you want to prevent scalars from coloring your object, use vtkMapper’s method
mapper->ScalarVisibilityOff() to turn off color mapping. Then the actor’s color will control
the color of the object.
• The scalar range (i.e., the range into which the colors are mapped) is specified with the map-
per. Use the method mapper->SetScalarRange(min, max) .
You can also derive your own lookup table types. Look at vtkLogLookupTable for an example.
This particular lookup table inherits from vtkLookupTable . It performs logarithmic mapping of sca-
lar value to table entry, a useful capability when scalar values span many orders of magnitude.
Implicit Functions
As we have seen, implicit functions can be used for visualizing functions, creating geometry, and
cutting or selecting datasets. VTK includes several implicit functions including a single plane
(vtkPlane ), multiple convex planes ( vtkPlanes ), spheres ( vtkSphere ), cones ( vtkCone ), cylinders
(vtkCylinder ), and the general quadric ( vtkQuadric ). The class vtkImplicitBoolean allows you to
create boolean combinations of these implicit function primitives. Other implicit functions can be
added to VTK by deriving from the abstract base class vtkImplicitFunction .
198 Fundamental Algorithms
vtkImplicitFunction
The existing inheritance hierarchy for implicit functions is shown in Figure6–37 . Subclasses
of vtkImplicitFunction must implement the two methods Evaluate() and Gradient() . The method
Evaluate() returns the value of the function at point ( x,y,z), while the method Gradient() returns the
gradient vector to the function at point ( x,y,z).
Contouring
Scalar contouring is implemented in the Visualization Toolkit with vtkContourFilter . This filter
object accepts as input any dataset type. Thus, vtkContourFilter treats every cell type and each cell
type must provide a method for contouring itself.
Contouring in VTK is implemented using variations of the marching cubes algorithm pre-
sented earlier. That is, a contour case table is associated with each cell type, so each cell will gener-
ate contouring primitives as appropriate. For example, the tetrahedron cell type implements
“marching tetrahedron” and creates triangle primitives, while the triangle cell type implements
“marching triangles” and generates lines segments.
The implication of this arrangement is that vtkContourFilter will generate point, line, and sur-
face contouring primitives depending on the combination of input cell types. Thus vtkContourFilter
is completely general. We have created another contour filter, vtkMarchingCubes , that is specific to
the dataset type image data (in particular, 3D volumes). These two filters allow us to compare (at
least for this one algorithm) the cost of generality.
Recall from “Generality Versus Efficiency” on page163 the issues regarding the trade-offs
between general and specific algorithms. Figure6–38 shows a comparison of CPU times for a vol-
´ resolution.
ume dataset at , 646493
, and ´ ´ volume
12812893
The ´ is a CT 25625693
´ ´
dataset of a human head. Three cases were run. In the first case the vtkMarchingCubes object was
used. The output of this filter is triangles plus point normals. In the second case vtkContourFilter
was run. The output of this filter is just triangles. In the last case vtkContourFilter was combined
with vtkPolyDataNormals (to generate point normals). The output of the combined filters is also
triangles plus point normals.
The execution times are normalized to the smallest dataset using the vtkMarchingCubes
object. The results are clear: The specific object outperforms the general object by a factor of 1.4 to
7, depending on data size and whether normals are computed. The larger differences occur on the
smaller datasets. This is because the ratio of voxel cells containing the isosurface to the total num-
ber of voxels is larger for smaller datasets. (Generally the total number of voxels increases as the
resolution cubed, while the voxels containing the isosurface increase as the resolution squared.) As
a result, more voxels are processed in the smaller datasets relative to the total number of voxels
6.6 Putting It All Together 199
Figure 6–38 The cost of generality. Isosurface generation of three volumes of different sizes are
compared. The results show normalized execution times for two different implementations of the
marching-cubes isosurface algorithm. The specialized filter is vtkMarchingCubes . The general
algorithms are first vtkContourFilter and then in combination with vtkPolyDataNormals .
than in the larger datasets. When the datasets become larger, more voxels are “empty” and are not
processed.
Although these results do not represent all implementations or the behavior of other algo-
rithms, they do point to the cost of generality. Of course, there is a cost to specialization as well.
This cost is typically in programmer time, since the programmer must rewrite code to adapt to new
circumstances and data. Like all trade-offs, resolution of this issue requires knowledge of the appli-
cation.
An example use of vtkContourFilter is shown in Figure6–39 . This example is taken from
Figure4–1 , which is a visualization of a quadric function. The class vtkSampleFunction samples
the implicit quadric function using the vtkQuadric class. Although vtkQuadric does not participate
in the pipeline in terms of data flow, it is used to define and evaluate the quadric function. It is pos-
sible to generate one or more isolines/isosurfaces simultaneously using vtkContourFilter . As
Figure6–39 shows, we use the GenerateValues() method to specify a scalar range, and the number
of contours within this range (including the initial and final scalar values). vtkContourFilter gener-
ates duplicate vertices, so we can use vtkCleanPolyData to remove them. To improve the rendered
appearance of the isosurface, we use vtkPolyDataNormals to create surface normals. (We describe
normal generation in Chapter 9 .)
200 Fundamental Algorithms
vtkQuadric
vtkSampleFunction
vtkContourFilter
vtkPolyDataMapper
// Create outline
vtkOutlineFilter *outline = vtkOutlineFilter::New();
outline->SetInputConnection(sample->GetOutputPort());
vtkPolyDataMapper *outlineMapper = vtkPolyDataMapper::New();
outlineMapper->SetInputConnection(
outline->GetOutputPort());
vtkActor *outlineActor = vtkActor::New();
outlineActor->SetMapper(outlineMapper);
outlineActor->GetProperty()->SetColor(0,0,0);
Figure 6–39 Contouring quadric function. Pipeline topology, C++ code, and resulting image are
shown ( contQuad.cxx ).
6.6 Putting It All Together 201
vtkDataSet vtkPolyData
Input
Source
vtkGlyph3D
Figure 6–40 Data flow into and
out of the vtkGlyph3D class.
vtkPolyData
Cutting
vtkCutter performs cutting of all VTK cell types. The SetValue() and GenerateValues() methods
permit the user to specify which multiple scalar values to use for the cutting. vtkCutter requires an
implicit function that will be evaluated at each point in the dataset. Then each cell is cut using the
cell’s Contour method. Any point attributes are interpolated to the resulting cut vertices. The sort-
ing order for the generated polygonal data can be controlled with the SortBy method. The default
sorting order, SortByValue() , processes cells in the inner loop for each contour value. SortByCell()
processes the cutting value in the inner loop and produces polygonal data that is suitable for back-
to-front rendering (see Figure6–32 ). (The sorting order is useful when rendering with opacity as
discussed in Chapter 7.) Notice the similarity of this filter to the vtkContourFilter . Both of these
objects contour datasets with multiple isovalues. vtkCutter uses an implicit function to calculate
scalar values while vtkContourFilter uses the scalar data associated with the dataset’s point data.
Glyphs
The vtkGlyph3D class provides a simple, yet powerful glyph capability in the Visualization Toolkit .
vtkGlyph3D is an example of an object that takes multiple inputs ( Figure6–40 ). One input, speci-
fied with the SetInputConnection() method, defines a set of points and possible attribute data at
those points. The second input, specified with the SetSourceConnection() method, defines a geom-
etry to be copied to every point in the input dataset. The source is of type vtkPolyData . Hence, any
filter, sequence of filters creating polygonal data, or a polygonal dataset may be used to describe the
glyph’s geometry.
The behavior of an instance of vtkGlyph3D depends on the nature of the input data and the
value of its instance variables. Generally, the input Source geometry will be copied to each point of
the Input dataset. The geometry will be aligned along the input vector data and scaled according to
the magnitude of the vector or the scalar value. In some cases, the point normal is used rather than
the vector. Also, scaling can be turned on or off.
We saw how to use vtkGlyph3D in the example given in Figure4–20 . Cones were used as
the glyph and were located at each point on the sphere, oriented along the sphere’s surface normal.
202 Fundamental Algorithms
vtkPolyDataAlgorithm
Streamlines
Streamlines and particle motion require numerical integration to guide a point through the vector
field. Vector visualization algorithms that we will see in later chapters also require numerical inte-
gration. As a result, we designed an object hierarchy that isolates the numerical integration process
into a single base class. The base class is vtkStreamer and it is responsible for generating a particle
path through a vector field of specified length (expressed as elapsed time). Each derived class of
vtkStreamer takes advantage of this capability to move through the vector field but implements its
own particular representational technique to depict particle motion. Streamlines ( vtkStreamLine )
draw connected lines while particle motion is shown by combining the output of vtkStreamPoints
with the vtkGlyph3D object. Using vtkGlyph3D we can place spheres or oriented objects such as
cones or arrows at points on the particle path created by vtkStreamPoints . The inheritance hierarchy
for vtkStreamer and subclasses is shown in Figure6–41 .
The integration method in vtkStreamer is implemented as a virtual function. Thus it can be
overloaded as necessary. Possible reasons for overloading include implementing an integration
technique of higher or lower accuracy, or creating a technique specialized to a particular dataset
type. For example, the search process in a volume is much faster than it is for other dataset types,
therefore, highly efficient vector integration techniques can be constructed.
The vector integration technique in VTK will accommodate any cell type. Thus, integration
through cells of any topological dimension is possible. If the cells are of topological dimension 2 or
less, the integration process constrains particle motion to the surface (2D) or line (1D). The particle
may only leave a cell by passing through the cell boundary, and traveling to a neighboring cell, or
exiting the dataset.
Abstract Filters
Attribute transformations create or modify data attributes without changing the topology or geome-
try of a dataset. Hence filters that implement attribute transformation (e.g., vtkElevationFilter ) can
accept any dataset type as input, and may generate any dataset type on output. Unfortunately,
because filters must specialize the particular type of data they output, at first glance it appears that
filters that create general dataset types on output are not feasible. This is because the type
vtkDataSet is an abstract type and must be specialized to allow instantiation.
Fortunately, there is a a solution to this dilemma. The solution is to use the “virtual construc-
tor” NewInstance() . Although C++ does not allow virtual constructors, we can simulate it by creat-
ing a special virtual function that constructs a copy of the object that it is invoked on. For example,
6.6 Putting It All Together 203
vtkPolyData
vtkDataSetAlgorithm
Output = Input->NewInstance()
vtkPolyData
Figure 6–42 Depiction of data flow for abstract filter output. The output object type is the same as
the input type.
if this function is applied to a dataset instance of type vtkPolyData , the result will be a copy of that
instance ( Figure6–42 ). (Note that we use reference counting to make copies and avoid duplicating
memory.) The virtual constructor function NewInstance() is implemented in a number of VTK
classes including datasets and cells.
Using the virtual constructor we can construct filters that output abstract data types like
vtkDataSet . We simply apply NewInstance() to the input of the filter. This will then return a pointer
to a concrete object that is the output of the filter. The result is a general filter object that can accept
any dataset type for input and creates the general vtkDataSet type as output. In VTK, this function-
ality has been implemented in the abstract class vtkDataSetAlgorithm .
There are other filters that implement variations of this delegation technique. The class
vtkPointSetAlgorithm is similar to vtkDataSetAlgorithm . This class takes as input any dataset
whose geometry is explicitly defined via an instance of vtkPoints (or subclass), and generates on
output an object of the same type (i.e., vtkPointSet ). The class vtkMergeFilter combines dataset
structure and point attributes from one or more input datasets. For example, you can read multiple
files and combine the geometry/topology from one file with different scalars, vectors, and normals
from other files.
One difficulty using abstract filter types is that the output type may not match with the input
type of a downstream filter. For example, the output of vtkElevationFilter is specified as
vtkDataSet even though the input may be of type vtkPolyData , and we know from the previous dis-
cussion that the actual output type will be vtkPolyData . This difficulty is removed by using the fil-
ter vtkCastToConcrete , which allows you to run-time cast to the appropriate output type. In this
case we would use the GetPolyDataOutput() from vtkCastToConcrete . After checking the validity
of the cast, this method returns a dataset cast to vtkPolyData . Of course, this process requires that
the input to vtkCastToConcrete be set before the output is requested.
204 Fundamental Algorithms
In this example we’ll combine a few different techniques to visualize blood flow in the human
carotid arteries. Our data contains both vectors that represent the velocity of blood and scalars that
are proportional to the magnitude of the velocity (i.e., speed).
We can provide context for the visualization by creating an isosurface of speed. This isosur-
face shows regions of fastest blood flow, and is similar to, but not the same as, the actual surface of
the arteries. However, it provides us with a visual cue to the structure of the arteries.
The first vector visualization technique we’ll use is to generate vector glyphs ( Figure6–43 ).
Unfortunately, we cannot just create glyphs at each point because of the number of points (over
167,000 points). To do so would result in a confusing mess, and the interactive speed would be
poor. Instead, we’ll use two filters to select a subset of the available points. These filters are
vtkThresholdPoints and vtkMaskPoints .
vtkThresholdPoints allows us to extract points that satisfy a certain threshold criterion. In our
example, we choose points whose speed is greater than a specified value. This eliminates a large
number of points, since most points lie outside the arteries and have a small speed value.
The filter vtkMaskPoints allows us to select a subset of the available points. We specify the
subset with the OnRatio instance variable. This instance variable indicates that every OnRatio point
is to be selected. Thus, if the OnRatio is equal to one, all points will be selected, and if the OnRatio
is equal to ten, every tenth point will be selected. This selection can be either uniform or random.
Random point selection is set using the RandomModeOn() and RandomModeOff() methods.
After selecting a subset of the original points, we can use the vtkGlyph3D filter in the usual
way. A cone’s orientation indicates blood flow direction, and its size and color correspond to the
velocity magnitude. Figure6–43 shows the pipeline, sample code, and a resulting image from this
visualization. Note that we’ve implemented the example using the interpreted language Tcl. See
Chapter 11 if you want more information about Tcl.
In the next part of this example we’ll generate streamtubes of blood velocity. Again we use
an isosurface of speed to provide us with context. The starting positions for the streamtubes were
determined by experimenting with the data. Because of the way the data was measured and the res-
olution of the velocity field, many streamers travel outside the artery. This is because the boundary
layer of the blood flow is not captured due to limitations in data resolution. Consequently, as the
blood flows around curves, there is a component of the velocity field that directs the streamtube
outside the artery. As a result it is hard to find starting positions for the streamtubes that yield inter-
esting results. We use the source object vtkPointSource in combination with vtkThresholdPoints to
work around this problem. vtkPointSource generates random points centered around a sphere of a
specified radius. We need only find an approximate position for the starting points of the stream-
tubes and then generate a cloud of random seed points. vtkThresholdPoints is used to cull points
that may be generated outside the regions of high flow velocity.
Figure6–44 shows the pipeline, sample Tcl code, and a resulting image from the visualiza-
tion. Notice that the isosurface is shown in wireframe. This provides context, yet allows us to see
the streamtubes within the isosurface.
6.6 Putting It All Together 205
vtkStructuredPointsReader
vtkThresholdPoints
vtkMaskPoints
vtkConeSource vtkGlyph3D
vtkPolyDataMapper
vtkStructuredPointsReader reader
reader SetFileName "$env(VTK_TEXTBOOK_DATA)/carotid.vtk"
vtkThresholdPoints threshold
threshold SetInputConnection [reader GetOutputPort]
threshold ThresholdByUpper 200
vtkMaskPoints mask
mask SetInputConnection [Threshold GetOutputPort]
mask SetOnRatio 10
vtkConeSource cone
cone SetResolution 3
cone SetHeight 1
cone SetRadius 0.25
vtkGlyph3D cones
cones SetInputConnection [mask GetOutputPort]
cones SetSourceConnection [cone GetOutputPort]
cones SetScaleFactor 0.5
cones SetScaleModeToScaleByVector
vtkLookupTable lut
lut SetHueRange .667 0.0
lut Build
vtkPolyDataMapper vecMapper
vecMapper SetInputConnection [cones GetOutputPort]
vecMapper SetScalarRange 2 10
vecMapper SetLookupTable lut
Figure 6–43 Visualizing blood flow in human carotid arteries. Cone glyphs indicate flow direction
and magnitude. The code fragment shown is from the Tcl script thrshldV.tcl and shows creation
of vector glyphs.
206 Fundamental Algorithms
vtkStructuredPointsReader vtkPointSource
vtkStreamLine vtkThresholdPoints
vtkTubeFilter
vtkPolyDataMapper
vtkStructuredPointsReader reader
reader SetFileName "$env(VTK_TEXTBOOK_DATA)/carotid.vtk"
vtkPointSource source
source SetNumberOfPoints 25
source SetCenter 133.1 116.3 5.0
source SetRadius 2.0
vtkThresholdPoints threshold
threshold SetInputConnection [reader GetOutputPort]
threshold ThresholdByUpper 275
vtkStreamTracer streamers
streamers SetInputConnection [reader GetOutputPort]
streamers SetSourceConnection [source GetOutputPort]
streamers SetMaximumPropagationUnitToTimeUnit
streamers SetMaximumPropagation 100.0
streamers SetInitialIntegrationStepUnitToCellLengthUnit
streamers SetInitialIntegrationStep 0.2
streamers SetTerminalSpeed .1
vtkTubeFilter tubes
tubes SetInputConnection [streamers GetOutputPort]
tubes SetRadius 0.3
tubes SetNumberOfSides 6
tubes SetVaryRadiusToVaryRadiusOff
vtkPolyDataMapper streamerMapper
streamerMapper SetInputConnection [tubes GetOutputPort]
streamerMapper SetScalarRange 2 10
Figure 6–44 Visualizing blood flow in the human carotid arteries. Streamtubes of flow vectors
(streamV.tcl ).
6.7 Chapter Summary 207
Two- and three-dimensional vector plots have been used by computer analysts for many
years [Fuller80] . Streamlines and streamribbons also have been applied to the visualization of com-
plex flows [Volpe89] . Good general references on vector visualization techniques are given in
[Helman90] and [Richter90] .
Tensor visualization techniques are relatively few in number. Most techniques are glyph ori-
ented [Haber90] [deLeeuw93] . We will see a few more techniques in Chapter 9.
Blinn [Blinn82] , Bloomental [Bloomenthal88] [Bloomenthal97] and Wyvill [Wyvill86] have
been important contributors to implicit modeling. Implicit modeling is currently popular in com-
puter graphics for modeling “soft” or “blobby” objects. These techniques are simple, powerful, and
are becoming widely used for advanced computer graphics modeling.
6.9 References
[Abraham85]
R. H. Abraham and Christopher D. Shaw. Dynamics The Geometry of Behavior. Aerial Press, San-
ta Cruz, CA, 1985.
[Blinn82]
J. F. Blinn. “A Generalization of Algebraic Surface Drawing.” ACM Transactions on Graphics .
1(3):235–256, July 1982.
[Bloomenthal88]
J. Bloomenthal. “Polygonization of Implicit Surfaces.” Computer Aided Geometric Design .
5(4):341–355, November 1982.
[Bloomenthal97]
J. Bloomenthal, editor. Introduction to Implicit Surfaces . Morgan Kaufmann Publishers, Inc., San
Francisco, CA., 1997.
[Chernoff73]
H. Chernoff. “Using Faces to Represent Pints in K-Dimensional Space Graphically.” J. American
Statistical Association . 68:361–368, 1973.
[Cline93]
H. Cline, W. Lorensen, and W. Schroeder. “3D Phase Contrast MRI of Cerebral Blood FLow and
Surface Anatomy.” Journal of Computer Assisted Tomography. 17(2):173–177, March/April
1993.
[Conte72]
S. D. Conte and C. de Boor. Elementary Numerical Analysis . McGraw-Hill Book Company, 1972.
[deLeeuw93]
W. C. de Leeuw and J. J. van Wijk. “A Probe for Local Flow Field Visualization.” In Proceedings
of Visualization ’93 . pp. 39–45, IEEE Computer Society Press, Los Alamitos, CA, 1993.
[Delmarcelle95]
T. Delmarcelle and L. Hesselink. “A Unified Framework for Flow Visualization.” In Computer
Visualization Graphics Techniques for Scientific and Engineering Analysis . R. S. Gallagher, ed .
CRC Press, Boca Raton, FL, 1995.
[Durrett87]
H. J. Durrett, ed. Color and the Computer. Academic Press, Boston, MA, 1987.
[Durst88]
M. J. Durst. “Additional Reference to Marching Cubes.” Computer Graphics . 22(2):72–73, 1988.
6.9 References 209
[Fuchs77]
H. Fuchs, Z. M. Kedem, and S. P. Uselton. “Optimal Surface Reconstruction from Planar Con-
tours.” Communications of the ACM . 20(10):693–702, 1977.
[Fuller80]
A. J. Fuller and M.L.X. dosSantos. “Computer Generated Display of 3D Vector Fields.” Computer
Aided Design . 12(2):61–66, 1980.
[Haber90]
R. B. Haber and D. A. McNabb. “Visualization Idioms: A Conceptual Model to Scientific Visual-
ization Systems.” Visualization in Scientific Computing, G. M. Nielson, B. Shriver, L. J. Rosen-
blum, ed. IEEE Computer Society Press, pp. 61–73, 1990.
[Helman90]
J. Helman and L. Hesselink. “Representation and Display of Vector Field Topology in Fluid Flow
Data Sets.” Visualization in Scientific Computing. G. M. Nielson, B. Shriver, L. J. Rosenblum, eds.
IEEE Computer Society Press, pp. 61–73, 1990.
[Livnat96]
Y. Livnat, H. W. Shen, C. R. Johnson. “A Near Optimal Isosurface Extraction Algorithm for Struc-
tured and Unstructured Grids.” IEEE Transactions on Visualization and Computer Graphics . Vol.
2, No. 1, March 1996.
[Lorensen87]
W. E. Lorensen and H. E. Cline. “Marching Cubes: A High Resolution 3D Surface Construction
Algorithm.” Computer Graphics . 21(3):163–169, July 1987.
[Lorenz63]
E. N. Lorenz. “Deterministic Non-Periodic Flow.” Journal of Atmospheric Science . 20:130–141,
1963.
[Montani94]
C. Montani, R. Scateni, and R. Scopigno. “A Modified Look-Up Table for Implicit Disambigua-
tion of Marching Cubes.” Visual Computer . (10):353–355, 1994.
[Moon87]
F. C. Moon. Chaotic Vibrations . Wiley-Interscience, New York, NY, 1987.
[Nielson91]
G. M. Nielson and B. Hamann. “The Asymptotic Decider: Resolving the Ambiguity in Marching
Cubes.” In Proceedings of Visualization ’91 . pp. 83–91, IEEE Computer Society Press, Los Alam-
itos, CA, 1991.
[Rheingans92]
P. Rheingans. “Color, Change, and Control for Quantitative Data Display.” In Proceedings of Vi-
sualization ’92 . pp. 252–259, IEEE Computer Society Press, Los Alamitos, CA, 1992.
[Richter90]
R. Richter, J. B. Vos, A. Bottaro, and S. Gavrilakis. “Visualization of Flow Simulations.” Scientific
Visualization and Graphics Simulation . D. Thalmann editor, pp. 161–171, John Wiley and Sons,
1990.
[Saada74]
A. S. Saada. Elasticity Theory and Applications. Pergamon Press, Inc., New York, NY, 1974.
[Timoshenko70]
S. P. Timoshenko and J. N. Goodier. Theory of Elasticity, 3d Edition . McGraw-Hill Book Compa-
ny, New York, NY, 1970.
210 Fundamental Algorithms
[Tufte83]
E. R. Tufte. The Visual Display of Quantitative Information. Graphics Press, Cheshire, CT, 1990.
[Volpe89]
G. Volpe. “Streamlines and Streamribbons in Aerodynamics.” Technical Report AIAA-89-0140,
27th Aerospace Sciences Meeting, 1989.
[Ware88]
C. Ware. “Color Sequences for Univariate Maps: Theory, Experiments and Principles.” IEEE
Computer Graphics and Applications . 8(5):41–49, 1988.
[Watson92]
D. F. Watson. Contouring: A Guide to the Analysis and Display of Spatial Data . Pergamon Press,
1992.
[Wyszecki82]
G. Wyszecki and W. Stiles. Color Science: Concepts and Methods, Quantitative Data and Formu-
lae. John Wiley and Sons, 1982.
[Wyvill86]
G. Wyvill, C. McPheeters, B. Wyvill. “Data Structure for Soft Objects.” Visual Computer .
2(4):227–234, 1986.
6.10 Exercises
6.1 Sketch contour cases for marching triangles. How many cases are there?
6.2 Sketch contour cases for marching tetrahedron. How many cases are there?
6.3 A common visualization technique is to animate isosurface value. The procedure is to
smoothly vary isosurface value over a specified range.
a) Create an animation sequence for the quadric example ( Figure4–1 ).
b) Create an animation sequence for the head sequence ( Figure6–11 (b)).
6.4 Marching cubes visits each cell during algorithm execution. Many of these cells do not con-
tain the isosurface. Describe a technique to improve the performance of isosurface extraction
by eliminating visits to cells not containing isosurface. ( Hint: use a preprocessing step to ana-
lyze data. Assume that many isosurfaces will be extracted and that the preprocessing step will
not count against execution time.)
6.5 Scan-line rasterization proceeds along horizontal spans in graphics hardware (see “Rasteriza-
tion” on page54 ). Interpolation of color occurs along horizontal spans as well.
a) Show how the orientation of a polygon affects interpolated color.
b) Discuss potential problems caused by orientation dependent viewing of visualizations.
6.6 Write a program to simulate beam vibration. Use the code associated with Figure6–14 (a) as
your starting point.
6.7 Using the filters vtkStreamLine , vtkMaskPoints , and vtkGlyph3D , create a visualization con-
sisting of oriented glyphs along a streamline.
6.8 Visualize the following functions.
() ,,
a) Scalar .Sxyz = sin ()xy , for x,y between 0 and p
6.10 Exercises 211
applications that can benefit from the ability to render objects that transmit light. One important
application of transparency is volume rendering, which we will explore in greater detail later in the
chapter. Another simple example makes objects translucent so that we can see inside of the region
bounded by the surface, as shown in Figure12–4 . As demonstrated in this example, by making the
skin semitransparent, it becomes possible to see the internal organs.
Transparency and its complement, opacity, are often referred to as alpha in computer graph-
ics. For example, a polygon that is 50 percent opaque will have an alpha value of 0.5 on a scale
from zero to one. An alpha value of one represents an opaque object and zero represents a com-
pletely transparent object. Frequently, alpha is specified as a property for the entire actor, but it also
can be done on a vertex basis just like colors. In such cases, the RGB specification of a color is
extended to RGBA where A represents the alpha component. On many graphics cards the frame
buffer can store the alpha value along with the RGB values. More typically, an application will
request storage for only red, green, and blue on the graphics card and use back-to-front blending to
avoid the need for storing alpha.
Unfortunately, having transparent actors introduces some complications into the rendering
process. If you think back to the process of ray tracing, viewing rays are projected from the camera
out into the world, where they intersect the first actor they come to. With an opaque actor, the light-
ing equations are applied and the resulting color is drawn to the screen. With a semitransparent
actor we must solve the lighting equations for this actor, and then continue projecting the ray far-
ther to see if it intersects any other actors. The resulting color is a composite of all the actors it has
intersected. For each surface intersection this can be expressed as Equation7-1 .
RA= s Rs + ()1A– s Rb
GA= sGs + ()1A– s Gb
(7-1)
BA= s Bs + ()1A– s Bb
AA= s + ()1A– s Ab
In this equation subscript s refers to the surface of the actor, while subscript b refers to what is
behind the actor. The term is1A called
– s the transmissivity, and represents the amount of light
that is transmitted through the actor. As an example, consider starting with three polygons colored
red, green, and blue each with a transparency of 0.5. If the red polygon is in the front and the back-
ground is black, the resulting RGBA color will be (0.4, 0.2, 0.1, 0.875) on a scale from zero to one
(Figure7–1 ).
It is important to note that if we switch the ordering of the polygons, the resulting color will
change. This underlies a major technical problem in using transparency. If we ray-trace a scene, we
will intersect the surfaces in a well-defined manner — from front to back. Using this knowledge we
can trace a ray back to the last surface it intersects, and then composite the color by applying
Equation7-1 to all the surfaces in reverse order (i.e., from back to front). In object-order rendering
methods, this compositing is commonly supported in hardware, but unfortunately we are not guar-
anteed to render the polygons in any specific order. Even though our polygons are situated as in
Figure7–1 , the order in which the polygons are rendered might be the blue polygon, followed by
the red, and finally the green polygon. Consequently, the resulting color is incorrect.
If we look at the RGBA value for one pixel we can see the problem. When the blue polygon
is rendered, the frame buffer and z-buffer are empty, so the RGBA quad (0,0,0.8,0.5) is stored along
7.1 Transparency and Alpha Values 215
Polygon Color RGBA (0.8, 0, 0, 0.5) (0, 0.8, 0, 0.5) (0, 0, 0.8, 0.5)
Front
Red Green Blue
Resulting Color (0.4, 0.2, 0.1, 0.875) (0, 0.4, 0.2, 0.75) (0, 0, 0.4, 0.5)
with the its z-buffer value. When the red polygon is rendered, a comparison of its z-value and the
current z-buffer indicates that it is in front of the previous pixel entry. So Equation7-1 is applied
using the frame buffer’s RGBA value. This results in the RGBA value (0.4,0,0.2,0.75) being writ-
ten to the buffer. Now, the green polygon is rendered and the z comparison indicates that it is
behind the current pixel’s value. Again this equation is applied, this time using the frame buffer’s
RGBA value for the surface and the polygon’s values from behind. This results in a final pixel
color of (0.3,0.2, 0.175,0.875), which is different from what we previously calculated. Once the red
and blue polygons have been composited and written to the frame buffer, there is no way to insert
the final green polygon into the middle where it belongs.
One solution to this problem is to sort the polygons from back to front and then render them
in this order. Typically, this must be done in software requiring additional computational overhead.
Sorting also interferes with actor properties (such as specular power), which are typically sent to
the graphics engine just before rendering the actor’s polygons. Once we start mixing up the poly-
gons of different actors, we must make sure that the correct actor properties are set for each poly-
gon rendered.
Another solution is to store more than one set of RGBAZ values in the frame buffer. This is
costly because of the additional memory requirements, and is still limited by the number of
RGBAZ values you can store. Some new techniques use a combination of multiple RGBAZ value
storage and multipass rendering to yield correct results with a minimum performance hit
[Hodges92] .
The second technical problem with rendering transparent objects occurs less frequently, but
can still have disastrous effects. In certain applications, such as volume rendering, it is desirable to
have thousands of polygons with small alpha values. If the RGBA quad is stored in the frame buffer
as four eight-bit values, then the round-off can accumulate over many polygons, resulting in gross
errors in the output image. This may be less of a problem in the future if graphics hardware begins
to store 16 or more bits per component for texture and the frame buffer.
216 Advanced Computer Graphics
Techniques for performing volume rendering using texture mapping hardware will be discussed
later in this chapter.
A fundamental step in the texture mapping process is determining how to map the texture
onto the geometry. To accomplish this, each vertex has an associated texture coordinate in addition
to its position, surface normal, color, and other point attributes. The texture coordinate maps the
vertex into the texture map as shown in Figure7–2 . The texture coordinate system uses the param-
eters (u,v) and (u,v,t) or equivalently ( r,s) or ( r,s,t) for specifying 2D and 3D texture values. Points
between the vertices are linearly interpolated to determine texture map values.
Another approach to texture mapping uses procedural texture definitions instead of a texture
map. In this approach, as geometry is rendered, a procedure is called for each pixel to calculate a
texel value. Instead of using the (u,v,t) texture coordinates to index into an image, they are passed
as arguments to the procedural texture that uses them to calculate its result. This method provides
almost limitless flexibility in the design of a texture; therefore, it is almost impossible to implement
in dedicated hardware. Most commonly, procedural textures are used with software rendering sys-
tems that do not make heavy use of existing graphics hardware.
While texture maps are generally used to add detail to rendered images, there are important
visualization applications.
• Texture maps can be generated procedurally as a function of data. One example is to change
the appearance of a surface based on local data value.
• Texture coordinates can be generated procedurally as a function of data. For example, we can
threshold geometry by creating a special texture map and then setting texture coordinates
based on local data value. The texture map consists of two entries: fully transparent () a = 0
and fully opaque (). aThe= texture
1 coordinate is then set to index into the transparent
portion of the map if the scalar value is less than some threshold, or into the opaque portion
otherwise.
• Texture maps can be animated as a function of time. By choosing a texture map whose inten-
sity varies monotonically from dark to light, and then “moving” the texture along an object,
the object appears to crawl in the direction of the texture map motion. We can use this tech-
218 Advanced Computer Graphics
nique to add apparent motion to things like hedgehogs to show vector magnitude. Figure7–3
is an example of a texture map animation used to simulate vector field motion.
These techniques will be covered in greater detail in Chapter 9 . (See “Texture Algorithms” on
page362 for more information.)
erate images that are nearly identical to those produced by geometric rendering techniques dis-
cussed in earlier chapters. For example, using a ray casting method to produce an isosurface image
is similar, though not truly equivalent, to rendering geometric primitives that were extracted with
the marching cubes contouring technique described in Chapter 6.
The two basic surface rendering approaches described in Chapter 3, image-order and object-
order, apply to volume rendering techniques as well. In an image-order method, rays are cast for
each pixel in the image plane through the volume to compute pixel values, while in an object-order
method the volume is traversed, typically in a front-to-back or back-to-front order, with each voxel
processed to determine its contribution to the image. In addition, there are other volume rendering
techniques that cannot easily be classified as image-order or object-order. For example, a volume
rendering technique may traverse both the image and the volume simultaneously, or the image may
be computed in the frequency domain rather than the spatial domain.
Since volume rendering is typically used to generate images that represent an entire 3D
dataset in a 2D image, several new challenges are introduced. Classification must be performed to
assign color and opacity to regions within the volume, and volumetric illumination models must be
defined to support shading. Furthermore, efficiency and compactness are of great importance due to
the complexity of volume rendering methods and the size of typical volumetric datasets. A geomet-
ric model that consists of one million primitives is generally considered large, while a volumetric
dataset with one million voxels is quite small. Typical volumes contain between ten and several
hundred million voxels, with datasets of a billion or more voxels becoming more common. Clearly
care must be taken when deciding to store auxiliary information at each voxel or to increase the
time required to process each voxel.
Figure 7–4 Image-order volume rendering. High potential iron protein data courtesy
of Scripps Clinic, La Jolla, CA.
ray function often determines the method used to extract values along the ray, we will begin by con-
sidering some of the basic ray function types.
Figure7–5 shows the data value profile of a ray as it passes through 8 bit volumetric data
where the data values can range between 0 and 255. The x-axis of the profile indicates distance
from the view plane while the y-axis represents data value. The results obtained from four different
simple ray functions are shown below the profile. For display purposes we convert the raw result
values to gray scale values using a method similar to the one in the previous example.
The first two ray functions, maximum value and average value, are basic operations on the
scalar values themselves. The third ray function computes the distance along the ray at which a sca-
lar value at or above 30 is first encountered, while the fourth uses an alpha compositing technique,
treating the values along the ray as samples of opacity accumulated per unit distance. Unlike the
first three ray functions, the result of the compositing technique is not a scalar value or distance that
can be represented on the ray profile.
The maximum intensity projection, or MIP, is probably the simplest way to visualize volu-
metric data. This technique is fairly forgiving when it comes to noisy data, and produces images
that provide an intuitive understanding of the underlying data. One problem with this method is that
it is not possible to tell from a still image where the maximum value occurred along the ray. For
example, consider the image of a carotid artery shown in Figure7–6 . We are unable to fully under-
stand the structure of the blood vessels from this still image since we cannot determine whether
some vessel is in front of or behind some other vessel. This problem can be solved by generating a
small sequence of images showing the data rotating, although for parallel camera projections even
this animation will be ambiguous. This is due to the fact that two images generated from cameras
7.4 Image-Order Volume Rendering 221
maximum
value
scalar value
average
value
distance
distance to value 30
Figure 7–5 A ray profile and four example ray functions. MRI head data courtesy of Siemens
Medical Systems, Inc., Iselin, NJ.
222 Advanced Computer Graphics
that view the data from opposite directions will be identical except for a reflection about the Y axis
of the image.
Later in this chapter, during the classification and illumination discussions, we will consider
more complex ray functions. Although the colorful, shaded images produced by the new methods
may contain more information, they may also be more difficult to interpret, and often easier to mis-
interpret, than the simple images of the previous examples. For that reason, it is beneficial to use
multiple techniques to visualize your volumetric data.
A volume is represented as a 3D image dataset where scalar values are defined at the points
of the regular grid, yet in ray casting we often need to sample the volume at arbitrary locations. To
do this we must define an interpolation function that can return a scalar value for any location
between grid points. The simplest interpolation function, which is called zero-order, constant, or
nearest neighbor interpolation, returns the value of the closest grid point. This function defines a
grid of identical rectangular boxes of uniform value centered on grid points, as illustrated in 2D on
the left side of Figure7–7 . In the image on the right we see an example of trilinear interpolation
where the value at some location is defined by using linear interpolation based on distance along
each of the three axes. In general, we refer to the region defined by eight neighboring grid points as
a voxel. In the special case where a discrete algorithm is used in conjunction with nearest neighbor
interpolation, we may instead refer to the constant-valued regions as voxels.
To traverse the data along a ray, we could sample the volume at uniform intervals or we could
traverse a discrete representation of the ray through the volume, examining each voxel encoun-
tered, as illustrated in Figure7–8 . The selection of a method depends upon factors such as the
interpolation technique, the ray function, and the desired trade-off between image accuracy and
speed.
The ray is typically represented in parametric form as
()xyz
,, = ()x 0,,y 0 z 0 + ()abc
,, t (7-2)
where () ,,yorigin
isx 0the 0 z 0 of the ray (either the camera position for perspective viewing trans-
7.4 Image-Order Volume Rendering 223
voxel voxel
g h
c d
(x,y,z) scalar value
scalar value e f
a b
Nearest neighbor region value at (x,y,z) derived from eight sur-
of uniform value rounding scalar values
Figure 7–7 A 2D example of nearest neighbor interpolation (left) and a 3D example of trilinear
interpolation (right).
Figure 7–8 Two basic ray traversal methods for volume rendering.
formations or a pixel on the view plane for parallel viewing transformations), and is the()abc
,,
normalized ray d irection vector. If t1 and t2 represent the distances where the ray enters and exits
the volume respectively, and delta_t indicates the step size, then we can use the following code
fragment to perform uniform distance sampling:
t = t1;
v = undefined ;
while ( t < t2 )
{
x = x0 + a * t;
y = y0 + b * t;
z = z0 + c * t;
v = EvaluateRayFunction( v, t );
224 Advanced Computer Graphics
Figure 7–9 Images generated using a ray casting method with three different step sizes.Vase
data courtesy of SUNY Stony Brook.
t = t + delta_t;
}
One difficulty with the uniform distance sampling method is selecting the step size. If the step size
is too large, then our sampling might miss features in the data, yet if we select a small step size, we
will significantly increase the amount of time required to render the image. This problem is illus-
trated in Figure7–9 using a volumetric dataset with grid points that are one unit apart along the X,
Y, and Z axes. The images were generated using step sizes of 2.0, 1.0, and 0.1 units, where the 0.1
step-size image took nearly 10 times as long to generate as the 1.0 step-size image, which in turn
took twice as long to render as the 2.0 step-size image. A compositing method was used to generate
the images, where the scalar values within the dataset transition sharply from transparent black to
opaque white. If the step size is too large, a banding effect appears in the image highlighting
regions of the volume equidistant from the ray origin along the viewing rays. To reduce this effect
when a larger step size is desired for performance reasons, the origin of each ray can be bumped
forward along the viewing direction by some small random offset, which will produce a more
pleasing image by eliminating the regular pattern of the aliasing.
In some cases it may make more sense to examine each voxel along the ray rather than taking
samples. For example, if we are visualizing our data using a nearest neighbor interpolation method,
then we may be able to implement a more efficient algorithm using discrete ray traversal and inte-
ger arithmetic. Another reason for examining voxels may be to obtain better accuracy on certain ray
functions. We can compute the exact maximum value encountered along a ray within each voxel
when using trilinear interpolation by taking the first derivative of the interpolation function along
the ray and solving the resulting equation to compute the extrema. Similarly, we can find the exact
location along the ray where a selected value is first encountered to produce better images of isov-
alue surfaces within the volume.
7.4 Image-Order Volume Rendering 225
Vertex (8)
Face (6)
base plane
Figure 7–11 Ray casting with templated discrete rays. If the rays originate from the image plane
(left) then voxels are missed in the volume. If instead the rays originate from a base plane of the vol-
ume (right), each voxel is visited exactly once.
base plane of the volume that is most parallel to the image plane, as shown in the right image, then
the rays fit together snugly such that every voxel in the dataset is visited exactly once. The image
will appear warped because it is generated from the base plane, so a final resampling step is
required to project this image back onto the image plane.
Object-order volume rendering methods process samples in the volume based on the organization
of the voxels in the dataset and the current camera parameters. When an alpha compositing method
is used, the voxels must be traversed in either a front-to-back or back-to-front order to obtain cor-
rect results. This process is analogous to sorting translucent polygons before each projection in
order to ensure correct blending. When graphics hardware is employed for compositing, a back-to-
front ordering is typically preferred since it is then possible to perform alpha blending without the
need for alpha bitplanes in the frame buffer. If a software compositing method is used, a front-to-
back ordering is more common since partial image results are more visually meaningful, and can be
used to avoid additional processing when a pixel reaches full opacity. Voxel ordering based on dis-
tance to the view plane is not always necessary since some volume rendering operations, such as
MIP or average, can be processed in any order and still yield correct results.
Figure7–12 illustrates a simple object-order, back-to-front approach to projecting the voxels
in a volume for an orthographic projection. Voxel traversal starts at the voxel that is furthest from
the view plane and then continues progressively to closer voxels until all voxels have been visited.
This is done within a triple nested loop where, from the outer to the inner loop, the planes in the
volume are traversed, the rows in a plane are processed, and finally the voxels along a row are vis-
ited. Figure7–12 shows an ordered labeling of the first seven voxels as the volume is projected.
Processing voxels in this manner does not yield a strict ordering from the furthest to the closest
voxel. However, it is sufficient for orthographic projections since it does ensure that the voxels that
project to a single pixel are processed in the correct order.
7.5 Object-Order Volume Rendering 227
When a voxel is processed, its projected position on the view plane is determined and an
operation is performed at that pixel location using the voxel and image information. This operator
is similar to the ray function used in image-order ray casting techniques. Although this approach to
projecting voxels is both fast and efficient, it often yields image artifacts due to the discrete selec-
tion of the projected image pixel. For instance, as we move the camera closer to the volume in a
perspective projection, neighboring voxels will project to increasingly distant pixels on the view
plane, resulting in distracting “holes” in the image.
A volume rendering technique, called splatting, addresses this problem by distributing the
energy of a voxel across many pixels. Splatting is an object-order volume rendering technique pro-
posed by Westover [Westover90] and, as its name implies, it projects the energy of a voxel onto the
image plane one splat, or footprint, at a time. A kernel with finite extent is placed around each data
sample. The footprint is the projected contribution of this sample onto the image plane, and is com-
puted by integrating the kernel along the viewing direction and storing the results in a 2D footprint
table. Figure7–13 illustrates the projection of a Gaussian kernel onto the image plane that may
then be used as a splatting footprint. For a parallel viewing transform and a spherically symmetric
kernel, the footprint of every voxel is identical except for an image space offset. Therefore, the
evaluation of the footprint table and the image space extent of a sample can be performed once as a
preprocessing step to volume rendering. Splatting is more difficult for perspective volume render-
ing since the image space extent is not identical for all samples. Accurately correcting for perspec-
tive effects in a splatting approach would make the algorithm far less efficient. However, with a
small loss of accuracy we can still use the generic footprint table if we approximate the image plane
extent of an ellipsoid with an ellipse.
There are several important considerations when utilizing a splatting approach for volume
rendering. The type of kernel, the radius of the kernel, and the resolution of the footprint table will
all impact the appearance of the final image. For example, a kernel radius that is smaller than the
distance between neighboring samples may lead to gaps in the image, while a larger radius will lead
to a blurry image. Also, a low resolution footprint table is faster to precompute, but a high resolu-
228 Advanced Computer Graphics
Figure 7–14 Volume rendering using a 2D (left) and 3D (right) texture mapping technique.
tion table allows us to use nearest neighbor sampling for faster rendering times without a signifi-
cant loss in image accuracy.
Texture mapping as described earlier in this chapter was originally developed to provide the
appearance of high surface complexity when rendering geometric surfaces. As texture mapping
methods matured and found their way into standard graphics hardware, researchers began utilizing
these new capabilities to perform volume rendering [Cabral94] . There are two main texture-mapped
volume rendering techniques based on the two main types of texture hardware currently available.
Two-dimensional texture-mapped volume rendering makes use of 2D texture mapping hardware
whereas 3D texture-mapped volume rendering makes use less commonly available 3D texture
mapping graphics hardware.
We can decompose texture-mapped volume rendering into two basic steps. The first is a sam-
pling step where the data samples are extracted from the volume using some form of interpolation.
Depending on the type of texture hardware available, this may be nearest neighbor, bilinear, or tri-
linear interpolation and may be performed exclusively in hardware or through a combination of
both software and hardware techniques. The second step is a blending step where the sampled val-
ues are combined with the current image in the frame buffer. This may be a simple maximum oper-
ator or it may be a more complex alpha compositing operator.
Texture-mapped volume renderers sample and blend a volume to produce an image by pro-
jecting a set of texture-mapped polygons that span the entire volume. In 2D texture-mapped volume
rendering the dataset is decomposed into a set of orthographic slices along the axis of the volume
most parallel to the viewing direction. The basic rendering algorithm consists of a loop over the
orthogonal slices in a back-to-front order, where for each slice, a 2D texture is downloaded into tex-
ture memory. Each slice, which is a rectangular polygon, is projected to show the entire 2D texture.
If neighboring slices are far apart relative to the image size, then it may be necessary to use a soft-
ware bilinear interpolation method to extract additional slices from the volume in order to achieve a
7.5 Object-Order Volume Rendering 229
Figure 7–15 2D texture-mapped volume rendering. The images were generated using three
different mappings of scalar value to opacity. CT data (256x256x225) courtesy of North Carolina
Memorial Hospital.
desired image accuracy. The image on the left side of Figure7–14 illustrates the orthogonal slices
that are rendered using a 2D texture mapping approach. Several example images generated using
2D texture-mapped volume rendering are shown in Figure7–15 .
The performance of this algorithm can be decomposed into the software sampling rate, the
texture download rate, and the texture-mapped polygon scan conversion rate. The software sam-
pling step is required to create the texture image, and is typically dependent on view direction due
to cache locality when accessing volumetric data stored in a linear array. Some implementations
minimize the software sampling cost at the expense of memory by precomputing and saving
images for the three major volume orientations. The texture download rate is the rate at which this
image can be transferred from main memory to texture mapping memory. The scan conversion of
the polygon is usually limited by the rate at which the graphics hardware can process pixels in the
image, or the pixel fill rate. For a given hardware implementation, the download time for a volume
is fixed and will not change based on viewing parameters. However, reducing the relative size of
the projected volume will reduce the number of samples processed by the graphics hardware that,
in turn, will increase volume rendering rates at the expense of image quality.
Unlike 2D hardware, 3D texture hardware is capable of loading and interpolating between
multiple slices in a volume by utilizing 3D interpolation techniques such as trilinear interpolation.
If the texture memory is large enough to hold the entire volume, then the rendering algorithm is
simple. The entire volume is downloaded into texture memory once as a preprocessing step. To ren-
der an image, a set of equally spaced planes along the viewing direction and parallel to the image
plane is clipped against the volume. The resulting polygons, illustrated in the image on the right
side of Figure7–14 , are then projected in back-to-front order with the appropriate 3D texture coor-
dinates.
For large volumes it may not be possible to load the entire volume into 3D texture memory.
The solution to this problem is to break the dataset into small enough subvolumes, or bricks, so that
each brick will fit in texture memory. The bricks must then be processed in back-to-front order
while computing the appropriately clipped polygon vertices inside the bricks. Special care must be
taken to ensure that boundaries between bricks do not result in image artifacts.
230 Advanced Computer Graphics
Figure 7–16 On the left, orthographic rays are cast from the base plane of the volume. In the right
image the volume is sheared such that these rays become perpendicular to the base plane.
Similar to a 2D texture mapping method, the 3D algorithm is limited by both the texture
download and pixel fill rates of the machine. However, 3D texture mapping is superior to the 2D
version in its ability to sample the volume, generally yielding higher quality images with fewer arti-
facts. Since it is capable of performing trilinear interpolation, we are able to sample at any location
within the volume. For instance, a 3D texture mapping algorithm can sample along polygons repre-
senting concentric spheres rather than the more common view-aligned planes.
In theory, a 3D texture-mapped volume renderer and a ray casting volume renderer perform
3
the same computations, have the same complexity, , andOn ()
produce identical images. Both
sample the entire volume using either nearest neighbor or trilinear interpolation, and combine the
samples to form a pixel value using, for example, a maximum value or compositing function.
Therefore, we can view 3D texture mapping and standard ray casting methods as functionally
equivalent. The main advantage to using a texture mapping approach is the ability to utilize rela-
tively fast graphics hardware to perform the sampling and blending operations. However, there are
currently several drawbacks to using graphics hardware for volume rendering. Hardware texture-
mapped volume renderings tend to have more artifacts than software ray casting techniques due to
limited precision within the frame buffer for storing partial results at each pixel during blending. In
addition, only a few ray functions are supported by the hardware, and advanced techniques such as
shading are more difficult to achieve. However, these limitations are beginning to disappear as tex-
ture mapping hardware evolves. Through the use of extensions to the OpenGL standard, per pixel
vectors can be defined allowing for hardware shaded volume texture mapping. Other extensions
have allowed for maximum intensity projections, and deeper framebuffers eliminate artifacts.
quent plane of the volume at consistent locations. Using bilinear interpolation on the 2D planes of
the dataset, we can precompute one set of interpolation weights for each plane. Instead of travers-
ing the volume by evaluating samples along each ray, an object-order traversal method can be used
to visit voxels along each row in each plane in a front-to-back order through the volume. There is a
one-to-one correspondence between samples in a plane of the volume and pixels on the image
plane, making it possible to traverse both the samples and the pixels simultaneously. As in tem-
plated ray casting, a final resampling (warping) operation must be performed to transform the
image from sheared space on the base plane to cartesian space on the image plane.
Shear-warp volume rendering is essentially an efficient variant of ray casting. The correspon-
dence between samples and pixels allows us to take advantage of a standard ray casting technique
known as early ray termination. When we have determined that a pixel has reached full opacity dur-
ing compositing, we no longer need to consider the remaining samples that project onto this pixel
since they do not contribute to the final pixel value. The biggest efficiency improvement in shear-
warp volume rendering comes from run-length encoding the volume. This compression method
removes all empty voxels from the dataset, leaving only voxels that can potentially contribute to the
image. Depending on the classification of the data, it is possible to achieve a greater than 10:1
reduction in voxels. As we step through the compressed volume, the number of voxels skipped due
to run-length encoding also indicates the number of pixels to skip in the image. One drawback to
this method is that it requires three copies of the compressed volume to allow for front-to-back tra-
versal from all view directions. In addition, if we wish to use a perspective viewing transformation
then we may need to traverse all three compressed copies of the volume in order to achieve the cor-
rect traversal order.
Volume rendering can also be performed using the Fourier slice projection theorem
[Totsuka92] that states that if we extract a slice of the volume in the frequency domain that contains
the center and is parallel to the image plane, then the 2D spectrum of that slice is equivalent to the
2D image obtained by taking line integrals through the volume from the pixels on the image plane.
Therefore we can volume render the dataset by extracting the appropriate slice from the 3D Fourier
volume, then computing the 2D inverse Fourier transform of this slice. This allows us to render the
2 3
On() aslog
image in time opposed
n On() by most other volume
to the complexity required
rendering algorithms.
Two problems that must be addressed when implementing a frequency domain volume ren-
derer are the high cost of interpolation when extracting a slice from the Fourier volume, and the
high memory requirements (usually two double precision floating-point values per sample)
required to store the Fourier volume. Although some shading and depth cues can be provided with
this method, occlusion is not possible.
50 50
0 0
1230 CT Value
Figure 7–17 Transfer functions that classify CT densities into material percentages. A simple binary
classification used to define a bone isosurface (left) and a gradual transition from air to muscle to bone
(right) is shown.
the binary step function shown on the left in Figure7–17 . In volume rendering we refer to this
function as a transfer function. A transfer function is responsible for mapping the information at a
voxel location into different values such as material, color, or opacity. The strength of volume ren-
dering is that it can handle transfer functions of much greater complexity than a binary step func-
tion. This is often necessary since datasets contain multiple materials and classification methods
cannot always assign a single material to a sample with 100 percent probability. Using advanced
image segmentation and classification techniques, the single component volume can be processed
into multiple material percentage volumes [Drebin88] . Referring back to our CT example, we can
now specify a material percentage transfer function that defines a gradual transition from air to
muscle, then from muscle to bone, as shown on the right in Figure7–17 .
In addition to material percentage transfer functions, we can define four independent transfer
functions that map scalar values into red, green, blue, and opacity values for each material in the
dataset. For simplicity, these sets of transfer functions are typically preprocessed into one function
each for red, green, blue and opacity at the end of the classification phase. During rendering we
must decide how to perform interpolation to compute the opacity and color at an arbitrary location
in the volume. We could interpolate scalar value then evaluate the transfer functions, or we could
evaluate the transfer functions at the grid points then interpolate the resulting opacities and colors.
These two methods will produce different image results. It is generally considered more accurate to
classify at the grid points then interpolate to obtain color and opacity; although if we interpolate
then classify, the image often appears more pleasing since high frequencies may be removed by the
interpolation.
Classifying a volume based on scalar value alone is often not capable of isolating an object of
interest. A technique introduced by Levoy [Levoy88] adds a gradient magnitude dimension to the
specification of a transfer function. With this technique we can specify an object in the volume
based on a combination of scalar value and the gradient magnitude. This allows us to define an
opacity transfer function that can target voxels with scalar values in a range of densities and gradi-
ents within a range of gradient magnitudes. This is useful for avoiding the selection of homoge-
neous regions in a volume and highlighting fast-changing regions. Figure7–18 shows a CT scan of
7.7 Volume Classification 233
a human foot. The sharp changes in the volume, such as the transition from air to skin and flesh to
bone, are shown. However, the homogeneous regions, such as the internal muscle, are mostly trans-
parent.
If we are using a higher-order interpolation function such as tri-cubic interpolation then we
can analytically compute the gradient vector at any location in the dataset by evaluating the first
derivative of the interpolation function. Although we can use this approach for trilinear interpola-
tion, it may produce undesirable artifacts since trilinear interpolation is not continuous in its first
derivative across voxel boundaries. An alternative approach is to employ a finite differences tech-
nique to approximate the gradient vector:
() + D ,,yz – fxx
fxx () – D ,,yz
g x = ---------------------------------------------------------------------------
2xD
() ,, + D z – fxyy () ,, – D z
g y = fxyy (7-3)
---------------------------------------------------------------------------
2yD
() ,, + D – fxyzz() ,, –D
g z = fxyzz
--------------------------------------------------------------------------
2zD
() ,,
where represents
fxyz ()xyz
,,
the scalar value at location in the dataset according to the
interpolation function, and , ,gand x gare
y the partial
g z derivatives of this function along the , x
z respectively. The magnitude of the gradient at is the()xyz
y , and axes ,,
length of the resulting
()g x ,,vector
vector . This g y g z can also be normalized to produce a unit normal vector. The
choice of , D, xandDyare critical
D z as shown in Figure7–19 . If these values are too small, then
the gradient vector field derived from Equation7-3 may contain high frequencies, yet if these val-
ues are too large we will lose small features in the dataset.
It is often the case that transfer functions based on scalar value and even gradient magnitude
are not capable of fully classifying a volume. Ultrasound data is an example of particularly difficult
data that does not perform well with simple segmentation techniques. While no one technique
exists that is universally applicable, there exists a wide variety of techniques that produce classifi-
234 Advanced Computer Graphics
Figure 7–19 A comparison of shaded images with two different step sizes used during normal
estimation. Confocal microscopy data courtesy of Howard Hughes Medical Institute, SUNY
Stony Brook.
cation information at each sample. For instance, [Kikinis96] provides techniques for classifying the
human brain. In order to properly handle this information a volume renderer must access the origi-
nal volume and a classification volume. The classification volume usually contains material per-
centages for each sample, with a set of color and opacity transfer functions for each material used to
define appearance.
The volume rendered images that we have shown so far in this chapter do not include any lighting
effects. Scientist sometimes prefer to visualize their volumes using these simpler methods because
they fear that adding lighting effects to the image will interfere with their interpretation. For exam-
ple, in a maximum intensity projection, a dark region in the image clearly indicates the lack of high
opacity values in the corresponding region of the volume, while a dark feature in a shaded image
may indicate either low opacity values or values with gradient directions that point away from the
light source.
There are several advantages to lighting that can often justify the additional complexity in the
image. First, consider the fact that volume rendering is a process of creating a 2D image from 3D
data. The person viewing that data would like to be able to understand the 3D structure of the vol-
ume from that image. Of course, if you were to look at a photograph of a skeleton it would be easy
to understand its structure from the 2D representation. The two main clues that you received from
the picture are occlusion and lighting effects. If you were to view a video of the skeleton, you
would receive the additional clue of motion parallax. A static image showing a maximum intensity
projection does not include occlusion or lighting effects, making it difficult to understand structure.
An image generated with a compositing technique does include occlusion, and the compositing ray
7.8 Volumetric Illumination 235
Figure 7–20 A comparison of three volume rendering techniques. A maximum intensity pro-
jection does not include occlusion or shading. A composite image includes occlusion and can
include shading.
function can be modified to include shading as well. A comparison of these three methods is shown
in Figure7–20 for a CT scan of a human foot.
To accurately capture lighting effects, we could use a transport theory illumination model
[Krueger91] that describes the intensity of light arriving
I at a pixel by the path integral along the
ray:
¥ ò
– s a ()s
t
t' + sc ()t' dt'
ò Qt() e
0
It() 0 ,w = dt (7-4)
t0
If we are using camera clipping planes, then andt 0would ¥ be replaced by the distance to the
near clip plane tnear and the distance to the far clip plane tfar respectively. The contribution Qt()
from each sample at a distance alongt w
the ray is attenuated according to how much intensity is
lost on the way from tot due s a ()t'
t 0 to absorption and scattering s sc ()at
. The contribution t' t
can be defined as:
The contribution consists of the amount of light directly emitted by the sample , plus theEt()
amount of light coming from all directions that is scattered by this sample back along the ray. The
w'
fraction of light arriving from the direction w is defined by
that is scattered into the direction
236 Advanced Computer Graphics
r sc compute
the scattering function . To ()w' ® w the light arriving from all directions due to mul-
tiple bounce scattering, we must recursively compute the illumination function.
If scattering is accurately modelled, then basing the ray function on the transport theory illu-
mination model will produce images with realistic lighting effects. Unfortunately, this illumination
model is too complex to evaluate, therefore approximations are necessary for a practical implemen-
tation. One of the simplest approximations is to ignore scattering completely, yielding the follow-
ing intensity equation:
¥ ò
– sa ()t' dt'
t0
It() 0, w =
ò Et() e dt (7-6)
t0
It()a
n, w = ()tn + ()1 – a ()t n It() n1+ , w (7-8)
which is equivalent to the simple compositing method using the over operator that was described
previously. Clearly in this case we have simplified the illumination model to the point that this ray
function does not produce images that appear to be realistic.
If we are visualizing an isosurface within the volumetric data, then we can employ the sur-
face illumination model described in Chapter 3 to capture ambient and diffuse lighting as well as
specular highlights. There are a variety of techniques for estimating the surface normal needed to
evaluate the shading equation. If the image that is produced as a result of volume rendering con-
tains the distance from the view plane to the surface for every pixel, then we can post-process the
image with a 2D gradient estimator to obtain surface normals. The gradient at some pixel ()x p, y p
can be estimated with a central difference technique by:
Figure 7–21 A scene (left) and the corre- continuous curvature regions
sponding depth image (right) used in 2D gra-
dient estimation. Corresponding depth image
The results are normalized to produce a unit normal vector. As with the 3D finite differences gradi-
ent estimator given in Equation7-3 , care must be taken when selecting andD.xTypically, Dy
these values are simply the pixel spacing in andx so that
y neighboring pixel values are used to
estimate the gradient, although larger values can be used to smooth the image.
One problem with the 2D gradient estimation technique described above is that normals are
computed from depth values that may represent disjoint regions in the volume, as shown in
Figure7–21 . This may lead to a blurring of sharp features on the edges of objects. To reduce this
effect, we can locate regions of continuous curvature in the depth image, then estimate the normal
for a pixel using only other pixel values that fall within the same curvature region [Yagel92a] . This
may require reducing our andD x values,
D y or using an off-centered differences technique to esti-
mate the components of the gradient. For example, the component
x of the gradient could be com-
puted with a forward difference:
or a backward difference:
¶Z Zx() p, y p – Zx() p – D x, y p
------= ---------------------------------------------------------------- (7-11)
¶x Dx
Although 2D gradient estimation is not as accurate as the 3D version, it is generally faster and
allows for quick lighting and surface property changes without requiring us to recompute the depth
image. However, if we wish to include shading effects in an image computed with a compositing
technique, we need to estimate gradients at many locations within the volume for each pixel. A 3D
gradient estimation technique is more suitable for this purpose. An illumination equation for com-
positing could be written as:
where the ambient illumination , the I a diffuse illumination , and theI dspecular illumination Is
are computed as in surface shading using the estimated volume gradient in place of the surface nor-
a ()t
mal. In this equation, represents the amount of light reflected per unit length along the ray,
– a ()t the fraction of light transmitted per unit length.
with 1indicating
As in classification, we have to make a decision about whether to directly compute illumina-
tion at an arbitrary location in the volume, or to compute illumination at the grid points and then
interpolate. This is not a difficult decision to make on the basis of accuracy since it is clearly better
to estimate the gradient at the desired location rather than interpolate from neighboring estimations.
On the other hand, if we do interpolate from the grid points then we can precompute the gradients
for the entire dataset once, and use this to increase rendering performance for both classification
and illumination. The main problem is the amount of memory required to store the precomputed
gradients. A naive implementation would store a floating-point value (typically four bytes) per
3
component of the gradient per scalar value. For a dataset with one-byte 256 scalars, this would
increase the storage requirement from 16 Mbytes to 218 Mbytes.
In order to reduce the storage requirements, we could quantize the precomputed gradients by
using some number of bits to represent the magnitude of the vector, and some other number of bits
to encode the direction of the vector. Quantization works well for storing the magnitude of the gra-
dient, but does not provide a good distribution of directions if we simply divide the bits among the
three components of the vector. A better solution is to use the uniform fractal subdivision of an
octahedron into a sphere as the basis of the direction encoding, as shown in Figure7–22 . The top
left image shows the results obtained after the recursive replacement of each triangle with four new
triangles, with a recursion depth of two. The vector directions encoded in this representation are all
directions formed by creating a ray originating at the sphere’s center and passing through a vertex
of the sphere. The remaining images in this figure illustrate how these directions are mapped into
an index. First we push all vertices back onto the original faces of the octahedron, then we flatten
this sphere onto the plane.
z0= Finally, we rotate the resulting grid by . We label45° the vertices
in the grid with indices starting at 0 at the top left vertex and continue across the rows then down
the columns to index 40 at the lower right vertex. These indices represent only half of the encoded
normals because when we flattened the octahedron, we placed two vertices on top of each other on
all but the edge locations. Thus, we can use indices 41 through 81 to represent vectors with a nega-
tive z component. Vertices on the edges represent vectors with out a z component, and although we
could represent them with a single index, using two keeps the indexing scheme more consistent
and, therefore, easier to implement.
The simple example above requires only 82 values to encode the 66 unique vector directions.
If we use an unsigned short to store the encoded direction, then we can use a recursion depth of 6
when generating the vertices. This leads to 16,642 indices representing 16,386 unique directions.
Once the gradients have been encoded for our volume, we need only compute the illumina-
tion once for each possible index and store the results in a table. Since data samples with the same
encoded gradient direction may have different colors, this illumination value represents the portion
of the shading equation that is independent of color. Each scalar value may have separate colors
defined for ambient, diffuse, and specular illumination; therefore, the precomputed illumination is
typically an array of values.
Although using a shading table leads to faster rendering times, there are some limitations to
this method. Only infinite light sources can be supported accurately since positional light sources
would result in different light vectors for data samples with the same gradient due to their different
7.8 Volumetric Illumination 239
positions in the volume. In addition, specular highlights are only captured accurately for ortho-
graphic viewing directions where the view vector does not vary based on sample position. In prac-
tice, positional light sources are often approximated by infinite light sources, and a single view
direction is used for computing specular highlights since the need for fast rendering often out-
weighs the need for accurate illumination.
240 Advanced Computer Graphics
Figure 7–24 Two volumes rendered with both geometric and volumetric techniques. The
Visible Woman CT data is courtesy of The National Library of Medicine.
contained within some set of closed geometric objects. Another approach would be to create an
auxiliary volume with binary scalar values that define a mask indicating which values in the vol-
ume should be considered during rendering.
All of these region of interest methods are fairly simple to implement using an image-order
ray casting approach. As a preprocessing step to ray casting, the ray is clipped against all geometric
region definitions. The ray function is then evaluated only along segments of the ray that are within
the region of interest. The mask values are consulted at each sample to determine if its contribution
should be included or excluded.
For object-order methods we must determine for each sample whether or not it is within the
region of interest before incorporating its contribution into the image. If the underlying graphics
hardware is being utilized for the object- order volume rendering as is the case with a texture map-
ping approach, hardware clipping planes may be available to help support regions of interest.
rendered first, then the semitransparent texture-mapped polygons are blended in a back-to-front
order into the image. If we wish to include semitransparent geometry in the scene, then this geome-
try and the texture-mapped polygons must be sorted before rendering. Similar to a purely geometric
scene, this may involve splitting polygons to obtain a sorted order.
If a software volume rendering approach is used, such as an object-order splatting method or
an image-order ray casting method, opaque geometry can be incorporated into the image by render-
ing the geometry, capturing the results stored in the hardware depth buffer, and then using these
results during the volume rendering phase. For ray casting, we would simply convert the depth
value for a pixel into a distance along the view ray and use this to bound the segment of the ray that
we consider during volume rendering. The final color computed for a pixel during volume render-
ing is then blended with the color produced by geometric rendering using the over operator. In an
object-order method, we must consider the depth of every sample and compare this to the value
stored in the depth buffer at each pixel within the image extent of this sample. We accumulate this
sample’s contribution to the volume rendered image at each pixel only if the sample is in front of
the geometry for that pixel. Finally, the volume rendered image is blended over the geometric
image.
depth images that contain the closest and farthest distance to relevant data for every pixel in the
image. These distances are then used to clip the rays during ray casting.
An alternate space-leaping technique for ray casting involves the use of an auxiliary distance
volume [Zuiderveld92] , with each value indicating the closest distance to a nontransparent sample
in the dataset. These distance values are used to take larger steps in empty regions of the volume
while ensuring that we do not step over any nontransparent features in the volume. Unfortunately,
the distance volume is computationally expensive to compute accurately, requires additional stor-
age, and must be recomputed every time the classification of the volume is modified.
One difficulty with these space-leaping techniques is that they are highly data dependent. On
a largely empty volume with a small amount of coherent data we can speed up volume rendering by
a substantial amount. However, when a dataset is encountered that is entirely made up of high-fre-
quency information such as a typical ultrasound dataset, these techniques break down and will usu-
ally cause rendering times to increase rather than decrease.
given error tolerance is encountered. The contribution of this region of the volume on the image can
be approximated by rendering geometric primitives for the splat [Shirley90] , [Wilhelms91] . Increas-
ing the allowed error will decrease the time required to render the data by allowing larger regions to
be approximated at a higher level in the octree.
When using a texture mapping approach for volume rendering, faster rendering speeds can be
achieved by reducing the number of texture-mapped polygons used to represent the volume. This is
essentially equivalent to reducing the number of samples taken along the ray in an image-order ray
casting method. Also, if texture download rates are a bottleneck, then a reduced resolution version
of the volume can be loaded into texture memory for interaction. This is similar to reducing both
the number of rays cast and the number of samples taken along a ray in an image-order method.
Focal Point
Eye Angle
View Angle
for introducing binocular parallax into renderings. We will refer to the overall process as stereo ren-
dering, since at some point in the process a stereo pair of images is involved.
To generate correct left and right eye images, we need information beyond the camera param-
eters that we introduced in Chapter 3 . The first piece of information we need is the separation dis-
tance between the eyes. The amount of parallax generated can be controlled by adjusting this
distance. We also need to know if the resulting images will be viewed on one or two displays. For
systems that use two displays (and hence two view planes), the parallax can be correctly produced
by performing camera azimuths to reach the left and right eye positions. Head mounted displays
and booms are examples of two display systems. Unfortunately, this doesn’t work as well for sys-
tems that have only one view plane. If you try to display both the left and right views on a single
display, they are forced to share the same view plane as in Figure7–25 . Our earlier camera model
assumed that the view plane was perpendicular to the direction of projection. To handle this non-
perpendicular case, we must translate and shear the camera’s viewing frustum. Hodges provides
some of the details of this operation as well as a good overview on stereo rendering [Hodges92] .
Now let’s look at some of the different methods for presenting stereoscopic images to the
user. Most methods are based on one of two main categories: time multiplexed and time parallel
techniques. Time multiplexed methods work by alternating between the left and right eye images.
Time parallel methods display both images at once in combination with a process to extract left and
right eye views. Some methods can be implemented as either a time multiplexed or a time parallel
technique.
Time multiplexed techniques are most commonly found in single display systems, since they
rely on alternating images. Typically this is combined with a method for also alternating which eye
views the image. One cost-effective time multiplexed technique takes advantage of existing televi-
sion standards such as NTSC and PAL. Both of these standards use interlacing, which means that
first the even lines are drawn on the screen and then the odd. By rendering the left eye image to the
even lines of the screen and the right eye image to the odd, we can generate a stereo video stream
that is suitable for display on a standard television. When this is viewed with both eyes, it appears
246 Advanced Computer Graphics
as one image that keeps jumping from left to right. A special set of glasses must be worn so that
when the left eye image is being displayed, the user’s left eye can see and similarly for the right
eye. The glasses are designed so that each lens consists of a liquid crystal shutter that can either be
transparent or opaque, depending on what voltage is applied to it. By shuttering the glasses at the
same rate as the television is interlacing, we can assure that the correct eye is viewing the correct
image.
There are a couple of disadvantages to this system. The resolutions of NTSC and PAL are
both low compared to a computer monitor. The refresh rate of NTSC (60 Hz) and PAL (50 Hz) pro-
duces a fair amount of flicker, especially when you consider that each eye is updated at half this
rate. Also, this method requires viewing your images on a television, not the monitor connected to
your computer.
To overcome these difficulties, some computer manufacturers offer stereo ready graphics
cards. These systems use liquid crystal shuttered glasses to directly view the computer monitor. To
obtain the alternating stereo images, the left eye image is rendered to the top half of the screen and
the right eye image to the bottom. Then the graphics card enters a special stereo mode where it dou-
bles the refresh rate of the monitor. So a monitor that initially displays both images at 60Hz begins
to alternate between the left and right eye at a rate of 120Hz. This results in each eye getting
updated at 60Hz, with its original horizontal resolution and half of its original vertical resolution.
For this process to work, your application must take up the entire screen while rendering.
Some more recent graphics cards have a left image buffer and a right image buffer for stereo
rendering. While this requires either more memory or a lower resolution, it does provide for stereo
rendering without having to take over the entire screen. For such a card, double buffering combined
with stereo rendering results in quad buffering, which can result in a large number of bits per pixel.
For example: 24 bits for an RGB color, another 24 bits for the back buffer’s color, plus 24 bits for
the z-buffer results in 72 bits per pixel. Now double that for the two different views and you have
144 bits per pixel or 18 megabytes for a 1K by 1K display.
Time parallel techniques display both images at the same time. Headmounted displays and
booms have two separate screens, one for each eye. To generate the two video streams requires
either two graphics cards or one that can generate two separate outputs. The rendering process then
involves just rendering each eye to the correct graphics card or output. Currently, the biggest disad-
vantage to this approach is the cost of the hardware required.
In contrast, SIRDS (Single Image Random Dot Stereograms) require no special hardware.
Both views are displayed in a single image, as in Figure7–26 . To view such an image the user must
focus either in front of, or behind, the image. When the user’s focal point is correct, the two trian-
gular cutouts in the top of the image will appear as one and the image should appear focused. This
works because dot patterns repeat at certain intervals. Here, only the depth information is present in
the resulting image. This is incorporated by changing the interval between patterns just as our ocu-
lar disparity changes with depth.
The next two techniques for stereo rendering can be implemented using either the time paral-
lel or time multiplexed methods. The distinction is slightly blurred because most of the time paral-
lel methods can be multiplexed, though typically there is no advantage to it. Both of these methods
have been used by the movie industry to produce “3D” movies. The first is commonly called red-
blue (or red-green or red-cyan) stereo and requires the user to wear a pair of glasses that filter enter-
ing light. The left eye can only see the image through a red filter, the right through a blue filter. The
rendering process typically involves generating images for the two views, converting their RGB
7.14 Stereo Rendering 247
values into intensity, and then creating a resulting image. This image’s red values are taken from
the left eye image intensities. Likewise the blue values (a mixture of blue and green) are taken from
the right eye image intensities. The resulting image has none of the original hue or saturation, but it
does contain both original images’ intensities. (An additional note: red-green methods are also used
because the human eye is more sensitive to green than blue.) The benefits of this technique are that
the resulting images can be displayed on a monitor, paper, or film, and all one needs to view them is
an inexpensive pair of glasses.
The second technique is similar to the first but it preserves all the color information from the
original images. It separates the different views by using polarized light. Normally, the light we see
has a mixture of polarization angles, but there are lenses that can filter out a subset of these angles.
If we project a color image through a vertical polarizing filter, and then view it through another ver-
tical filter, we will see the original image, just slightly dimmer because we’ve filtered out all the
horizontally polarized light. If we place a horizontal filter and a vertical filter together, all the light
is blocked. Polarized stereo rendering typically projects one eye’s image through a vertical filter
248 Advanced Computer Graphics
and the other through a horizontal filter. The user wears a pair of glasses containing a vertical filter
over one eye and a horizontal filter over the other. This way each eye views the correct image.
All the methods we have discussed for stereo rendering have their advantages and disadvan-
tages, typically revolving around cost and image quality. At the end of this chapter we will look at
an example program that renders stereo images using the red-blue technique.
7.15 Aliasing
At one point or another most computer users have run into aliasing problems. This “stair-stepping”
occurs because we represent continuous surface geometry with discrete pixels. In computer graph-
ics the most common aliasing problem is jagged edges when rendering lines or surface boundaries,
as in Figure7–27 .
The aliasing problem stems from the rasterization process as the graphics system converts
primitives, such as line segments, into pixels on the screen. For example, the quickest way to raster-
ize a line is to use an all or nothing strategy. If the line passes through the pixel, then the pixel is set
to the line’s color; otherwise, it is not altered. As can be seen in Figure7–28 , this results in the
stair-stepped appearance.
There are several techniques for handling aliasing problems, and they are collectively known
as antialiasing techniques. One approach to antialiasing is to change how the graphics system ras-
terizes primitives. Instead of rasterizing a line using an all or nothing approach, we look at how
much of the pixel the line occupies. The resulting color for that pixel is a mixture of its original
color and the line’s color. The ratio of these two colors is determined by the line’s occupancy. This
works especially well when working primarily with wireframe models. A similar approach breaks
each pixel down into smaller subpixels. Primitives are rendered using an all or nothing strategy, but
at subpixel resolutions. Then the subpixels are averaged to determine the resulting pixel’s color.
This tends to require much more memory.
A good result can be obtained by breaking each pixel into 10 subpixels, which requires about
10 times the memory and rendering time. If you don’t have access to hardware subpixel rendering,
you can approximate it by rendering a large image and then scaling it down. Using a program such
7.15 Aliasing 249
Figure 7–28 A one pixel wide line (outlined in gray) draw using a winner take all
approach (left) and a coverage approach (right).
as pnmscale , which does bilinear interpolation, you can take a 1000 by 1000 pixel image and scale
it down to a 500 by 500 antialiased image. If you have a graphics library that can render into mem-
ory instead of the screen, large images such as 6000 by 6000 pixels can be scaled down into high
quality results, still at high resolutions such as 2000 by 2000. This may seem like overkill, but on a
standard 600dpi color printer this would result in a picture just over three inches on a side.
The last method of antialiasing we will look at uses an accumulation buffer to average a few
possibly aliased images together to produce one antialiased result. An accumulation buffer is just a
segment of memory that is set aside for performing image operations and storage. The following
fragment of C++ code illustrates this process.
Instead of using one image with eight subpixels per pixel, we can use eight images without subpix-
els. The antialiasing is achieved by slightly translating the camera’s position and focal point
between each image. The amount of translation should be within one pixel of magnitude and per-
pendicular to the direction of projection. Of course, the camera’s position is specified in world
coordinates not pixels, but Equation7-13 will do the trick. We calculate the new camera position
and focal point (i.e., pnew and fnew ) from the offset to avoid difficulties surrounding the transforma-
tion matrix at the camera’s position.
f new = ()fM WD + Op M DW
O w = f new – f (7-13)
p new = pO+ w
250 Advanced Computer Graphics
Figure 7–29 Three images showing focal depth. The first has no focal depth, the second is focused on
the center object, the third image is focused on the farthest object.
In this equation is
Opthe offset in pixel coordinates, is the O
offset
w in world coordinates, f is the
camera focal point, p is the camera position, and the transformation matrices and M WD M DW
transform from world coordinates to display coordinates and from display coordinates to world
coordinates, respectively.
Figure 7–30 Motion blur. Rapidly moving objects appear blurry when recorded on
film or videotape. To simulate motion blur with a computer camera, multiple images
(or subframes) can be accumulated and averaged. This figure was generated by accu-
mulating 21 subframes.
their position during the small time that the shutter is open. This effect, known as motion blur , can
also be simulated with our camera model ( Figure7–30 ). Instead of rendering one image and dis-
playing it, we render a few subframes that are accumulated, averaged, and finally displayed. This is
similar to the antialiasing and focal depth techniques that we just discussed. In both of those tech-
niques, the camera is jittered while the actors remain fixed in time. To implement motion blur we
don’t jitter the camera; we increment the scene’s time between each subframe. Moving objects or
camera movements will result in differences between each subframe. The resulting image approxi-
mates the effects of photographing moving objects over a finite time.
N N
S S
Figure 7–31 Rotations using an orthogonalized view-up vector (left) and a con-
stant view-up vector (right).
tion method to handle this situation. If the data you are working with has a well-defined up and
down, then it probably makes sense to leave the view-up constant during rotations; otherwise, it
makes sense to keep it orthogonal to the direction of projection.
and the University of Utah’s SCIRUN 3D widgets [Purciful95] , have distinctly different compo-
nents in their widget toolbox. The widget sets vary according to the perceived purpose of the graph-
ical environment in which they exist
3D widgets are a recent addition (see Figure7–32 ) to VTK. In principal, the core functional-
ity is simple: events captured by the vtkRenderWindow are in turn translated into VTK events.
Observers which have registered themselves with the vtkRenderWindow receive these VTK events,
take the appropriate action, and then may either pass the event along to the next observer in the list,
or abort further processing of the event. (Note: observers can be prioritized according to the order
in which they wish to receive events.)
It is the implementation of 3D widgets, that is, what they can do with the events, that makes
them so powerful. As Figure7–32 shows, widgets typically provide a representation in the scene
that can be selected and manipulated. For example, a vtkLineWidget can be used to position a rake
of streamline seed points and represents itself with a thick line (tube) and two spherical end points.
Widgets also may directly manipulate an underlying class—the vtkScalarBarWidget enables the
user to interactively size, orient (horizontal or vertical), and position a vtkScalarBar. Widgets also
provide additional functionality such as managing an internal implicit function or transformation
matrix (e.g., vtkBoxWidget). The following is a list of widgets currently found in VTK and a brief
description of their capabilities .
and dragged to a new position. The vtkLineWidget supports the modifier “Shift” key to lock
motion of the end points along the coordinate x-y-z axes. The initial direction of motion is used to
determine which of the axes the user is moving the end point along. Such attention to detail is
essential to successful widget design and will continue to change as the technology evolves in the
future.
7.19 Putting It All Together 255
This chapter has covered a wide variety of topics. In this section we demonstrate applications of
each topic to some simple problems.
Texture Mapping
Figure7–33 shows the complete source code for a simple texture mapping example. You will
notice that most of the code is similar to what we used in the preceding examples. The key step here
is the creation of a vtkTexture object. This object interfaces between its data input and the texture
mapping functions of the graphics library. The vtkTexture instance is associated with an actor.
More than one texture instance may be shared between multiple actors. For texture mapping to
function properly, texture coordinates must be defined by the actor’s modeller.
One interesting note regarding the vtkTexture object. Instances of this class are mappers that
have an Input instance variable that is updated during each render. The input type is a vtkImage-
Data dataset type. Thus, a visualization pipeline can be constructed to read, process, and/or gener-
ate the texture map. This includes using the object vtkRendererSource , which converts the
renderer’s image into an image data dataset. The input texture map can be either 2D (a pixmap) or
3D (a volume).
A few words of warning when using textures. Some renderers only support 2D texture, or
may not support alpha textures. Also, many rendering systems require that each dimension of the
image dataset is an exact power of two. In VTK, non-power of two textures are automatically con-
verted to power of two at the expense of extra computation.
Volume Rendering
This example focuses on volume rendering. The source code shown in example Figure7–34 begins
by creating the usual objects. Then we use a vtkStructuredPointsReader to read in a volume dataset
for a high potential iron protein. We create a vtkPiecewiseFunction object to map the scalar values
in the volume dataset to opacity, and a vtkColorTransferFunction object to map the scalar values to
color. These two transfer functions are referenced from the vtkVolumeProperty object. In addition,
we use the ShadeOn() method of vtkVolumeProperty to enable shading for this volume, and the
SetInterpolationTypeToLinear() method to request trilinear interpolation. Since we are using a ray
casting approach, we need to create a ray function. In this example we use a
vtkVolumeRayCastCompositeFunction object for this purpose. The output of the reader is given to
the vtkVolumeRayCastMapper as the scalar input, and the SetVolumeRayCastFunction() method is
used to assign the ray function. The vtkVolume object is quite similar to a vtkActor , and the
SetVolumeMapper() and SetVolumeProperty() methods are used just like the SetMapper() and
SetProperty() methods of vtkActor . Finally, we add this volume to the renderer, adjust the camera,
set the desired image update rate and start the interactor.
To produce a maximum intensity projection in Figure7–34 , we would simply change the
type of the ray function to a vtkVolumeRayCastMIPFunction . We could also produce a surface
256 Advanced Computer Graphics
vtkBMPReader bmpReader
bmpReader SetFileName "$VTK_DATA_ROOT/Data/masonry.bmp"
vtkTexture atext
atext SetInputConnection [bmpReader GetOutputPort]
atext InterpolateOn
vtkPlaneSource plane
vtkPolyDataMapper planeMapper
planeMapper SetInputConnection [plane GetOutputPort]
vtkActor planeActor
planeActor SetMapper planeMapper
planeActor SetTexture atext
vtkRenderer ren1
vtkRenderWindow renWin
renWin AddRenderer ren1
vtkRenderWindowInteractor iren
iren SetRenderWindow renWin
Red-Blue Stereo
In our first example, we will be looking at using red-blue stereo rendering. We start off with the
example shown in Figure7–35 , which renders something akin to a mace. Then, in Figure7–35 we
add in red-blue stereo rendering by adding two lines near the bottom that invoke the
StereoRenderOn() and SetStereoType() methods. Once these two methods have been invoked, fur-
ther rendering will be done in stereo. The picture in the upper right corner displays a grayscale ver-
sion of the resulting image.
Motion Blur
In our second example, we show how to simulate motion blur using the Visualization Toolkit . As
shown in Figure7–36 , we begin with our previous example. We then remove the two lines control-
ling stereo rendering and add a few lines to create another mace. We position the first mace in the
top of the rendering window and the second mace at the bottom. We then use the SetSubFrames()
method to start performing subframe accumulation. Here, we will perform 21 renders to produce
the final image. For motion blur to be noticeable, something must be moving, so we set up a loop to
7.19 Putting It All Together 257
# The mapper / ray cast function know how to render the data
vtkVolumeRayCastCompositeFunction compositeFunction
vtkVolumeRayCastMapper volumeMapper
volumeMapper SetVolumeRayCastFunction compositeFunction
volumeMapper SetInputConnection [reader GetOutputPort]
ren1->AddActor(sphereActor);
ren1->AddActor(spikeActor);
ren1->SetBackground(0.2,0.3,0.4);
renWin->SetSize(300,300);
renWin->Render();
ren1->GetActiveCamera()->Zoom(1.4);
renWin->StereoRenderOn();
renWin->SetStereoTypeToRedBlue();
renWin->Render();
rotate the bottom mace by two degrees between each subframe. Over the 21 subframes it will rotate
40 degrees from its initial position. It is important to remember that the resulting image is not dis-
played until the required number of subframes have been rendered.
7.19 Putting It All Together 259
spikeActor2->SetPosition(0,-0.7,0);
sphereActor2->SetPosition(0,-0.7,0);
ren1->AddActor(sphereActor2);
ren1->AddActor(spikeActor2);
// zoom in a little
ren1->GetActiveCamera()->Zoom(1.5);
Figure 7–36 Example of
renWin->SetSubFrames(21);
motion blur ( MotBlur.cxx ).
for (i = 0; i <= 1.0; i = i + 0.05)
{
spikeActor2->RotateY(2);
sphereActor2->RotateY(2);
renWin->Render();
}
iren->Start();
Focal Depth
Now we will change the previous example to illustrate focal depth. First, we change the position of
the bottom mace, moving it farther away from us. Since it is farther away it will appear smaller, so
we scale it by a factor of two to maintain reasonable image size. We then remove the code for ren-
dering the subframes and instead set the number of frames for focal depth rendering. We also set
the camera’s focal point and focal disk to appropriate values. The resulting image and the required
changes to the source code are shown in Figure7–37 .
vtkLineWidget
There are a variety of 3D widgets in VTK all of which function in a similar fashion. 3D widgets are
a subclass of vtkInteractorObserver meaning that they are associated with a vtkRenderWindow and
observe events in the render window (). (Note: vtkInteractorStyle—see “Introducing vtkRenderWin-
dowInteractor” on page68 —is also a subclass of vtkInteractorObserver. The interactor style differs
from a 3D widget in that it does not have a representation in the scene.) The following example
shows the general approach to using a 3D widget using vtkLineWidget as an example (Figure7–
39 ). First the widget is instantiated and then placed. Placing means positioning, scaling, and orient-
ing the widget consistent with the object on which they operate. By default, widgets are enabled
with a “keypress-i” event, but the specific event to enable the widget can be modified.
260 Advanced Computer Graphics
// zoom in a little
ren1->GetActiveCamera()->SetFocalPoint(0,0,0);
ren1->GetActiveCamera()->Zoom(1.8);
ren1->GetActiveCamera()->SetFocalDisk(0.05);
observes
vtkInteractorObserver vtkRenderWindow
vtkLineWidget
Figure 7–38 Partial class hierarchy for 3D widgets. Each 3D widget observes a particular vtkRender-
Window similar to vtkInteractorStyle. Unlike the vtkInteractorStyle which is used to manipulate the
camera, 3D widgets have a representation in the scene that can be directly manipulated. More than one
vtkInteractorObserver can watch a vtkRenderWindow at a given time, so classes like vtkInteractor-
EventRecorder can record an event and pass them on to the next vtkInteractorObserver observing the
vtkRenderWindow.
The widget interfaces with the application through the command/observer event handling
mechanism (see “Events and Observers” on page63 ). 3D widgets invoke several events, the most
important being the StartInteractionEvent, InteractionEvent, and EndInteractionEvent. These
events are typically invoked, for example, on mouse down, mouse move, and mouse up, respec-
tively. In the example shown here, Tcl procedures are tied to the StartInteractionEvent and Interac-
tionEvent using the AddObserver() method to produce streamlines as the widget is manipulated.
Note that the streamline is seeded with a polygonal dataset each time an InteractionEvent is
invoked using the GetPolyData() method. The pipeline update mechanism then automatically exe-
cutes on the next render since the input to the streamline is modified.
7.20 Chapter Summary 261
vtkRungeKutta4 rk4
vtkPolyData seeds
vtkStreamTracer streamer
streamer SetInputConnection \
[reader GetOutputPort]
streamer SetSource seeds
vtkRenderWindowInteractor iren
iren SetRenderWindow renWin
vtkLineWidget lineWidget
lineWidget SetInteractor iren
lineWidget SetInput [reader GetOutput]
lineWidget SetAlignToYAxis
lineWidget PlaceWidget
lineWidget GetPolyData seeds
lineWidget ClampToBoundsOn
lineWidget SetResolution 25
[lineWidget GetLineProperty] SetColor 0 0 0
lineWidget AddObserver StartInteractionEvent
BeginInteraction
lineWidget AddObserver InteractionEvent
GenerateStreamlines
(skipping material...)
Figure 7–39 Using the vtkLineWidget to produce streamtubes in the combustor dataset.
The StartInteractionEvent turns the visibility of the streamlines on; the InteractionEvent
causes the streamlines to regenerate themselves ( LineWidget.tcl ).
For effective visualization of volumetric data, classification and shading are important consider-
ations. Regions of interest may be used to reduce the amount of data visible in an image. Due to the
complexity of volume rendering algorithms, efficiency and methods that allow for interactivity are
critical.
Stereo rendering techniques create two separate views for the right and left eyes. This simu-
lates binocular parallax and allows us to see depth in the image. Time multiplexed techniques alter-
nate left and right eye views in rapid succession. Time parallel techniques display both images at
the same time.
Raster devices often suffer from aliasing effects. Antialiasing techniques are used to mini-
mize the effects of aliasing. These techniques create blended images that soften the boundary of
hard edges.
By using an accumulation buffer we can create interesting effects, including motion blur and
focal blur. In motion blurring we accumulate multiple renders as the actors move. To simulate focal
blur, we jitter the camera position and hold its focal point constant.
Effective visualizations are inherently interactive. Not only are camera manipulation models
required for different types of data, but methods to interact, query, and modify data are essential.
3D widgets are important contributions to this end. They provide intuitive graphical interface to the
data through a representation in the scene that can be easily manipulated. 3D widgets also generate
supplemental information such as implicit functions, output polygonal data, and transformation
matrices that may be applied to objects in the scene.
7.22 References
[Cabral94]
B. Cabral, N. Cam, J. Foran. “Accelerated Volume Rendering and Tomographic Reconstruction
Using Texture Mapping Hardware.” In Proceedings of 1994 Symposium on Volume Visualization .
pp. 91–98, October 1994.
7.22 References 263
[Cignoni96]
P. Cignoni, C. Montani, E. Puppo, R. Scopigno. “Optimal Isosurface Extraction from Irregular
Volume Data.” In Proceedings of 1996 Symposium on Volume Visualization . pp. 31–38, IEEE
Computer Society Press, Los Alamitos, CA, October 1996.
[Drebin88]
R. A. Drebin, L. Carpenter, P. Hanrahan. “Volume Rendering.” Computer Graphics . 22(4):64–75
(Siggraph 1988).
[Hodges92]
L. F. Hodges. “Tutorial: Time-Multiplexed Stereoscopic Computer Graphics.” IEEE Computer
Graphics & Applications . March 1992.
[Kaufman91]
A. Kaufman (ed.). Volume Visualization. IEEE Computer Society Press, Los Alamitos, CA, 1991.
[Kaufman93]
A. Kaufman, R. Yagel, D. Cohen. “Volume Graphics.” IEEE Computer . 26(7):51–64, July 1993.
[Kelly94]
M. Kelly, K. Gould, S. Winner, A. Yen. “Hardware Accelerated Rendering of CSG and Transpar-
ency.” Computer Graphics (SIGGRAPH ’94 ). pp. 177-184.
[Kikinis96]
R. Kikinis, M. Shenton, D. Iosifescu, R. McCarley, P. Saiviroonporn, H. Hokama, A. Robatino,
D. Metcalf, C. Wible, C. Portas, R. Donnino, F. Jolesz. “A Digital Brain Atlas for Surgical Plan-
ning, Model Driven Segmentation and Teaching.” IEEE Transactions on Visualization and Com-
puter Graphics . 2(3), September 1996.
[Krueger91]
W. Krueger. “The Application of Transport Theory to Visualization of 3D Scalar Data Fields.”
Computers in Physics . pp. 397–406, July/August 1994.
[Lacroute94]
P. Lacroute and M. Levoy. “Fast Volume Rendering Using a Shear-Warp Factorization of the
Viewing Transformation.” In Proceedings of SIGGRAPH ’94 . pp. 451-458, Addison-Wesley,
Reading, MA, 1994.
[Laur91]
D. Laur and P. Hanrahan. “Hierarchical Splatting: A Progressive Refinement Algorithm for Vol-
ume Rendering.” In Proceedings of SIGGRAPH ’91 . 25:285–288, 1991.
[Levoy88]
M. Levoy. “Display of Surfaces from Volumetric Data.” IEEE Computer Graphics & Applica-
tions . 8(3), pp. 29–37, May 1988.
[Purciful95]
J.T. Purciful. "Three-Dimensional Widgets for Scientific Visualization and Animation." Masters
Thesis, Dept. of Computer Science, Univ. of Utah, 1995.
[Shirley90]
P. Shirley and A. Tuchman. “A Polygonal Approximation to Direct Volume Rendering.” Comput-
er Graphics . 24(5):63–70, 1990.
[Silva96]
C. Silva, J. S. B. Mitchell, A. E. Kaufman. “Fast Rendering of Irregular Grids.” In Proceedings of
1996 Symposium on Volume Visualization . pp. 15–22, IEEE Computer Society Press, Los Alami-
tos, CA, October 1996.
264 Advanced Computer Graphics
[Sobierajski95]
L. Sobierajski and R. Avila. “A Hardware Acceleration Method for Volumetric Ray Tracing.” In
Proceedings of Visualization ’95 . pp. 27–34, IEEE Computer Society Press, Los Alamitos, CA,
October 1995.
[Totsuka92]
T. Totsuka and M. Levoy. “Frequency Domain Volume Rendering.” Computer Graphics (SIG-
GRAPH ‘93). pp. 271–278, August 1993.
[Wernecke94]
J. Wernecke. The Inventor Mentor . Addison-Wesley, Reading MA,1994.
[Westover90]
L. Westover. “Footprint Evaluation for Volume Rendering.” Computer Graphics (SIGGRAPH
’90). 24(4):36, 1990.
[Wilhelms91]
J. Wilhelms and A. Van Gelder. “A Coherent Projection Approach for Direct Volume Rendering.”
Computer Graphics (SIGGRAPH ’91). 25(4):275–284, 1991.
[Wilhelms96]
J. P. Wilhelms, A. Van Gelder, P. Tarantino, J. Gibbs. “Hierarchical and Parallelizable Direct Vol-
ume Rendering for Irregular and Multiple Grids.” In Proceedings of Visualization ’96 . pp. 73ê80,
IEEE Computer Society Press, Los Alamitos, CA, October 1996.
[Yagel92a]
R. Yagel, D. Cohen, and A. Kaufman. “Normal Estimation in 3D Discrete Space.” The Visual
Computer. pp. 278–291, 1992.
[Yagel92b]
R. Yagel and A. Kaufman. “Template-based Volume Viewing.” In Proceedings of Eurographics
’92. pp. 153–167, September 1992.
[Zeleznik93]
R. C. Zeleznik, K. P. Herndon, D. C. Robbins, N. Huang, T. Meyer, N. Parker, J. F. Hughes. “An
Interactive Toolkit for Constructing 3D Interfaces.” Computer Graphics (Proceedings of Siggraph
‘93). 27(4):81–84. July 1993.
[Zuiderveld92]
K. J. Zuiderveld, A. h. j. Koning, and M. A. Viergever. “Acceleration of Ray-Casting Using 3D
Distance Transforms.” In Proceedings of Visualization and Biomedical Computing, pp. 324–335,
October 1992.
7.23 Exercises
7.1 In astronomy, photographs can be taken that show the movements of the stars over a period
of time by keeping the camera’s shutter open. Without accounting for the rotation of the
earth, these photographs display a swirl of circular arcs all centered about a common point.
Such time lapse photography is essentially capturing motion blur. If we tried to simulate
these images using the motion blur technique described in this chapter, they would look dif-
ferent from the photographs. Why is this? How could you change the simple motion blur
algorithm to correct this?
7.2 In Figure7–25 we show the difference between stereo rendering with two or one view
planes. If you were viewing a rectangle head-on (its surface normal parallel to your direc-
7.23 Exercises 265
tion), what artifacts would be introduced by rendering onto one view plane while using the
equations for two planes?
7.3 On some graphics systems transparent objects are rendered using a technique called screen
door transparency. Basically, every pixel is either completely opaque or completely transpar-
ent. Any value in between is approximated using dithering. So a polygon that was 50 percent
opaque would be rendered by drawing only half of the pixels. What visual artifacts does this
introduce? What blending problems can arise in using such a technique?
7.4 In this chapter we describe a few different techniques for antialiased rendering. One tech-
nique involved rendering a large image and then scaling it down to the desired size using
bilinear interpolation. Another technique involved rendering multiple images at the desired
size using small camera movements and then accumulating them into a final image. When
rendering a model with a surface representation, these two techniques will produce roughly
the same result. When rendering a model with a wireframe representation there will be signif-
icant differences. Why is this?
7.5 You need to create a small image of a volume dataset to include on your web page. The
3 2
dataset contains voxels,
512 and the desired image size is pixels.You 100can use a soft-
ware object-order method that projects each voxel onto the image, or a software ray casting
method that casts one ray for each pixel. Assuming that identical images are created, which
method would you select, and why?
7.6 Two software developers implement volume rendering methods. The first developer uses a
software ray casting approach, while the second uses a graphics hardware texture mapping
approach. The grayscale images are generated and displayed on a workstation with an 8 bit
frame buffer (256 levels of gray). They both use the same interpolation method and the same
compositing scheme, yet the two methods produce different images even though the same
number of samples from identical locations were used to generate the images. Why is this?
7.7 In the classification of some medical dataset, scalar values from 100 to 200 represent skin,
200 to 300 represent muscle and 300 to 400 represent bone. The color transfer functions
define skin as tan, muscle as red, and bone as white. If we interpolate scalar value and then
perform classification, what classification artifacts may appear in the image?
7.8 The normal encoding example illustrated in Figure7–22 produced 82 indices at a recursion
depth of two, which would require seven bits of storage. If we instead use a recursion depth
of three, how many indices are there? How many unique vector directions does this repre-
sent? How many bits of storage does this require?
7.9 Writing an object-order back-to-front projection algorithm is more difficult for a perspective
viewing transformation than a parallel viewing transformation. Explain why this is and draw
a 2D diagram of the volume and the viewing frustum that illustrates the issues.
266 Advanced Computer Graphics
Chapter 8
Adaptive tessellation of
higher-order cells.
polyline
z z
y y
Global Coordinate
(Position) x,y,z x,y,z
x x
The dataset, or local, coordinate system is based on combined topological and geometric coordi-
nates. The topological coordinate is used to identify a particular cell (or possibly a subcell), and the
geometric coordinate is used to identify a particular location within the cell. Together they uniquely
specify a location in the dataset. Here we will use the word “location” to refer to local or dataset
coordinates.
The topological coordinate is an “id”: a unique, nonnegative integer number referring to
either a dataset point or cell. For a composite cell, we use an additional “sub-id” to refer to a partic-
ular primary cell that composes the composite cell. The sub-id is also unique and nonnegative. The
id and sub-id together select a particular primary cell.
To specify a location within the primary cell, we use geometric coordinates. These geometric
coordinates, or parametric coordinates , are coordinates “natural” or canonical to the particular
topology and dimension of a cell.
We can best explain local coordinates by referring to an example. If we consider the polyline
cell type shown in Figure8–1 , we can specify the position of a point by indicating 1) the polyline
cell id, 2) the primary cell (i.e., line) sub-id and 3) the parametric coordinate of the line. Because
the line is one-dimensional, the natural or parametric coordinate is based on the one-dimensional
parameter r. Then any point along the line is given by a linear combination of the two end points of
the line xand
i x i1+
where the parametric coordinate r is constrained between (0,1). In this equation we are assuming
that the sub-id is equal to i.
The number of parametric coordinates corresponds to the topological dimension of the cell.
Three-dimensional cells will be characterized by the three parametric coordinates (r, s, t) . For cells
of topological order less than three, we will ignore the last (3 – n) parametric coordinates, where n
is the topological order of the cell. For convenience and consistency, we also will constrain each
parametric coordinate to range between (0,1).
8.2 Interpolation Functions 269
Every cell type will have its own parametric coordinate system. Later in this chapter we will
describe the parametric coordinate systems in detail. But first we will examine another coordinate
system, the structured coordinate system .
Many dataset types are structured. This includes image data and structured grids. Because of their
inherent structure, they have their own natural coordinate system. This coordinate system is based
on the i-j-k indexing scheme that we touched on in Chapter 5 (see “Image Data” on page136 ).
The structured coordinate system is a natural way to describe components of a structured
dataset. By fixing some indices, and allowing the others to vary within a limited range, we can
specify points, lines, surfaces, and volumes. For example, by fixing the i index i = i 0, and allowing
the j and k indices to range between their minimum and maximum values, we specify a surface. If
we fix three indices, we specify a point, if we fix two indices, we specify a line, and if we allow
three indices to vary, we specify a volume (or sub-volume). The structured coordinate system is
generally used to specify a region of interest (or ROI). The region of interest is an area that we want
to visualize, or to operate on.
There is a simple relationship between the point and cell id of the dataset coordinate system
and the structured coordinate system. To obtain a point id ()ip ,,j p k p
p id given the indices and
dimensions we ()nuse
x,, n y n z
p id = ip + jp n x + k p n x n y (8-2)
Here we’ve taken into account that there are one fewer cells along each topological axes than there
are points.
dr() = ()1r– d 0 + rd 1
r
d1
d0 1-r
r
line
General Form
To interpolate data from the cell points p i to a point p that is inside the cell, we need three pieces of
information:
n1–
dW= å i × di (8-4)
i0=
th
where d is the data value at the interior cell location (r,s,t) , di is the data value at the i cell point,
th
and Wi is a weight at the i cell point. The interpolation weights are functions of the parametric
coordinates Wi = W(r,s,t) . In addition, because we want d = d i when the interior point coincides
with a cell point, we can place additional constraints on the weights
,
W i = 1W j = 0 when pp = i and ij ¹ (8-5)
We also desire the interpolated data value d to be no smaller than the minimum d i and no larger than
the maximum d i. Thus the weights should also satisfy
å W i = 10W
, ££ i 1 (8-6)
The interpolation functions are of a characteristic shape. They reach their maximum value Wi = 1 at
cell point pi, and are zero at all other points. Examining Equation8-1 , we draw Figure8–2 and see
that each interpolation function has the shape of a peaked “hat,” and that interpolation is a linear
combination of these hat functions, scaled by the data value at each point.
8.2 Interpolation Functions 271
r=1
r
p1 W 0 = ()1r–
r=0
W1 = r
p0
Figure 8–3 Parametric coordinate system and interpolation functions for a line.
s=1 p3
p2
W 0 = ()1r– ()1s–
() –
W 1 = r1s
r=0 r=1
W 2 = ()1r– s
W 3 = rs
x2
p0 r
s=0 p1
x1
Figure 8–4 Parametric coordinate system and interpolation functions for a pixel.
p3 s=1 p2
W 0 = ()1r– ()1s–
() –
W 1 = r1s
r=0 r=1
W 2 = rs
x2 r W 3 = ()1r– s
p0 s=0 p1
x1
Figure 8–5 Parametric coordinate system and interpolation functions for a quadrilateral.
Equation8-4 is the general form for cell interpolation. It is used to interpolate any data value
defined at the cell points to any other point within the cell. We have only to define the specific
interpolation functions W i for each cell type.
Specific Forms
Each cell type has its own interpolation functions. The weights Wi are functions of the parametric
coordinates r, s, and t. In this section we will define the parametric coordinate system and interpola-
272 Advanced Data Representation
s
p2
W 0 = 1r– – s
r+s=1
r=0 W1 = r
x2 W2 = s
r
p0 s=0 p1
x1
Figure 8–6 Parametric coordinate system and interpolation functions for a triangle.
s
p4
1 2
æö---
p3 èør
i
W i = --------------------
1 2
p5
x
å æö---
èør
i
p2
x2
ri = p i – x
p0
p1 r
x1
Figure 8–7 Parametric coordinate system and interpolation functions for a polygon.
tion function for each primary cell type. Composite cells use the interpolation functions and para-
metric coordinates of their composing primary cells. The only difference in coordinate system
specification between primary and composite cells is that composite cells use the additional sub-id
to specify a particular primary cell.
8.2 Interpolation Functions 273
p3
s
W 0 = 1r– – s – t
p2
W1 = r
W2 = s
z p0 W3 = t
y
p1 r
x
Figure 8–9 Parametric coordinate system and interpolation functions for a tetrahedron.
() –
W 1 = r1s ()1t–
p4
p5 W 2 = ()1r– () –
s1t
s () –
W 3 = rs1t
p2
W 4 = ()1r– ()1s– t
p3
z r () –
W 5 = r1s t
p0
y p1
W 6 = ()1r– s t
x W 7 = rst
Figure 8–10 Parametric coordinate system and interpolation functions for a voxel.
Vertex. Vertex cells do not require parametric coordinates or interpolation functions since they are
zero-dimensional. The single weighting function is W0 = 1.
Line. Figure8–3 shows the parametric coordinate system and interpolation functions for a line.
The line is described using the single parametric coordinate r.
Pixel. Figure8–4 shows the parametric coordinate system and interpolation functions for a pixel
cell type. The pixel is described using the two parametric coordinates (r,s). Note that the pixel edges
are constrained to lie parallel to the global coordinate axes. These are often referred to as bilinear
interpolation functions.
Quadrilateral. Figure8–5 shows the parametric coordinate system and interpolation functions for
a quadrilateral cell type. The quadrilateral is described using the two parametric coordinates (r,s).
Triangle. Figure8–6 shows the parametric coordinate system and interpolation functions for a tri-
angle cell type. The triangle is characterized using the two parametric coordinates (r,s) .
274 Advanced Data Representation
Figure 8–11 Parametric coordinate system and interpolation functions for a hexahedron.
p4
W 0 = ()1r– – s ()1t–
s
() –
W 1 = r1t
p1
t
() –
W 2 = s1t
p3 p5
p0 W 3 = ()1r– – s t
z W 4 = rt
y W 5 = st
p2
r
x
Figure 8–12 Parametric coordinate system and interpolation functions for a wedge.
Polygon. Figure8–7 shows the parametric coordinate system and interpolation functions for a
polygon cell type. The polygon is characterized using the two parametric coordinates (r,s) . The
parametric coordinate system is defined by creating a rectangle oriented along the first edge of the
polygon. The rectangle also must bound the polygon.
The polygon poses a special problem since we do not know how many vertices define the
polygon. As a result, it is not possible to create general interpolation functions in the fashion of the
previous functions we have seen. Instead, we use a function based on weighted distance squared
from each polygon vertex.
The weighted distance squared interpolation functions work well in practice. However, there
are certain rare cases where points topologically distant from the interior of a polygon have an
undue effect on the polygon interior ( Figure8–8 ). These situations occur only if the polygon is
concave and wraps around on itself.
8.2 Interpolation Functions 275
t
s
p4 W 0 = ()1r– ()1s– ()1t–
p3 () –
W 1 = r1s ()1t–
p2
() –
W 2 = rs1t
W 3 = ()1r– () –
s1t
z
y p0 W4 = t
p1 r
x
Figure 8–13 Parametric coordinate system and interpolation functions for a pyramid.
x = () – y1()
By2
= () y2() – x2() y1()
Cx1
W 0 = – N ()– As + BrC– ()BsAr
– – C ()t1–
= () – x3()
Dx2
() +
W 1 = NDsDrE – ()FsGr
– – H ()t1–
= () y3() – x3() y2()
Ex2
W 2 = – N ()BsAr
– – C ()– Gs – Fr + H ()t1– = () – x4()
Fx0
()–
W 3 = NAs + BrC– ()FsGrH
+ – ()t1– = () – y0()
Gy4
W 4 = – N ()– Gs – Fr + H ()DsDrE
+ – ()t1– = () y4() – x4() y0()
Hx0
()–
W 5 = NAs + BrC– ()BsAr
– –C t
L43
W 6 = – N ()DsDrE
+ – ()FsGrH
+ – t 3 L 12
()
W 7 = NBsAr– – C ()– Gs – Fr + H t 4 2
p¤4
W 8 = – N ()– As + BrC– ()FsGrH
+ – t
()–
W 9 = NGs – Fr + H ()DsDrE
+ – t 0 1
Figure 8–14 Parametric coordinate system and interpolation functions for a pentagonal
prism.
276 Advanced Data Representation
p10
p9
p4 p11 p8 3 1
a = -------
+ ---
p6 4 2
p3
p5
p7 1 3
p2 b = ---+ -------
, ab+ =1
2 4
z
y p0 p1
Figure 8–15 Parametric coordinate system and interpolation functions for a hexagonal prism.
r r=1
() –
W 0 = 2r0.5 ()r1–
r=0 p1
p2 () –
W 1 = 2rr0.5
p0 () –
W 2 = 4r1r
Figure 8–16 Parametric coordinate system and interpolation functions for a quadratic edge.
Tetrahedron. Figure8–9 shows the parametric coordinate system and interpolation functions for a
tetrahedron cell type. The tetrahedron is described using the three parametric coordinates (r,s,t) .
Voxel. Figure8–10 shows the parametric coordinate system and interpolation functions for a voxel
cell type. The voxel is described using the three parametric coordinates (r,s,t). Note that the voxel
edges are constrained to lie parallel to the global coordinate axes. These are often referred to as tri-
linear interpolation functions.
8.2 Interpolation Functions 277
p2 W 0 = ()1r– – s ()21r
() – – s – 1
() –
W 1 = r2r1
p4 () –
W 2 = s2s1
p5
() – – s
W 3 = 4r1r
x2 r W 4 = 4rs
p1
p0 () – – s
W 5 = 4s1r
p3
x1
Figure 8–17 Parametric coordinate system and interpolation functions for a quadratic triangle.
p2 = () ,,,
i0123
p7 W i = 1---()1 + x i x ()x
1 + h i h () i xh+ ih –1
4
p5 i46= () ,
1 2
x2 p0 W i = ---()1 – x ()1 + h i h
p4 2
p1
r i57= () ,
x1 2
W i = 1---()1 – h ()1 + x i x
2
Figure 8–18 Parametric coordinate system and interpolation functions for a quadratic quadrilat-
eral. In VTK parametric coordinates (r,s) run between (0,1), hence the coordinate system shift into
the ()parametric
()xh
, system ranging from (-1,1). Note that and refer toxthe hi
i parametric
coordinates of the ith point.
Hexahedron. Figure8–11 shows the parametric coordinate system and interpolation functions for
a hexahedron cell type. The hexahedron is described using the three parametric coordinates (r,s,t).
Wedge. Figure8–12 shows the parametric coordinate system and interpolation functions for a
wedge cell type. The wedge is described using the three parametric coordinates (r,s,t).
Pyramid. Figure8–13 shows the parametric coordinate system and interpolation functions for a
pyramid cell type. The pyramid is described using the three parametric coordinates (r,s,t).
Pentagonal Prism. Figure8–14 shows the parametric coordinate system and interpolation func-
tions for a pentagonal prism cell type. The pentagonal prism is described using the three parametric
coordinates (r,s,t) .
278 Advanced Data Representation
t u1r= – –s–t
p3
() –
W 0 = u2u1
p9
() –
W 1 = r2r1
p7 s
p8 p2 () –
W 2 = s2s1
p6
() –
W 3 = t2t1
z p0 p5
y
W 4 = 4ur W 7 = 4ut
x p4 W 5 = 4rs W 8 = 4rt
p1 r
W 6 = 4su W 9 = 4st
Figure 8–19 Parametric coordinate system and interpolation functions for a quadratic tetrahe-
dron. In VTK parametric coordinates (r,s,t) run between (0,1), hence the coordinate system shift
into the ()
xhz
,,
parametric system ranging from (-1,1).
p7 1
t p14 p6 x = 2ræö – ---, x i = ± 1
èø 2
p4 p15 p13
h = 2sæö – ---, h i = ± 1
p 12 1
èø 2
p5
p16 p 19
z = 2tæö – ---, z i = ± 1
1
p18 èø 2
p17
p3 s
p 10 = () ,,,,,,,
i01234567
p11 p2
p0 p9 W i = 1---()1 + x i x ()1 + h i h ()x
1 + z i z () i xh+ i hz+ iz –2
8
p8
p1 r = () ,,,
i8101214
1 2
W i = ---()1 – x ()1 + h i h ()1 + z i z
4
= () ,,,
i9111315
z 2
y W i = 1---()1 – h ()1 + x i x ()1 + z i z
4
x = () ,,,
i16171819
2
W i = 1---()1 – z ()1 + x i x ()1 + h i h
4
Figure 8–20 Parametric coordinate system and interpolation functions for a quadratic hexahe-
dron. In VTK parametric coordinates (r,s,t) run between (0,1), hence the coordinate system shift
()xhz
,,
into the parametric xi h i
system ranging from (-1,1). Note that , and refer to the zi
parametric coordinates of the ith point.
8.2 Interpolation Functions 279
() –
W 1 = r1t ()2r2t– –1
p11 p5
p3 () –
W 2 = s1t ()2s2t– –1
p0
p9 p10 p 14 W 3 = ()1r– – s t2t2r–
() – 2s – 1
p 12 p8 p13
p2 () +
W 4 = rt2r2t3 –
p0 p7
p6 () +
W 5 = st2s2t3 –
z p1
y () – – s ()1t–
W 6 = 4r1r
() –
W 7 = 4rs1t
x
() –
W 8 = 4s1t ()1r– – s
() – – s t
W 9 = 4r1r
Figure 8–21 Parametric coordinate system
W 10 = 4rst
and interpolation functions for a quadratic
wedge. () – – s st
W 11 = 41r
() – – s t1t
W 12 = 41r () –
() –
W 13 = 4rt1t
() –
W 14 = 4st1t
Hexagonal Prism. Figure8–15 shows the parametric coordinate system and interpolation func-
tions for a hexagonal prism cell type. The hexagonal prism is described using the three parametric
coordinates (r,s,t) .
Quadratic Edge. Figure8–16 shows the parametric coordinate system and interpolation functions
for a quadratic edge cell type. The quadratic edge is described using the single parametric coordi-
nate r.
Quadratic Triangle. Figure8–17 shows the parametric coordinate system and interpolation func-
tions for a quadratic triangle cell type. The quadratic triangle is described using the two parametric
coordinates (r,s).
Quadratic Quadrilateral. Figure8–18 shows the parametric coordinate system and interpolation
functions for a quadratic quadrilateral cell type. The quadratic quadrilateral is described using the
two parametric coordinates (r,s). Note that because the interpolation functions are most easily
expressed in the interval (-1,1), a coordinate shift is performed to the ()xh
, coordinates defined in
this range. Also, the notation x i and h isi introduced. These are the parametric coordinates at the
ith point.
280 Advanced Data Representation
p4
p 12 1
p11 x = 2ræö
èø 2 , x i ±
– --- = 1
p3
p2
p7 p10 1
p8 h = 2sæö
èø 2 , h i ±
– --- = 1
p9
p6
1
z = 2tæö – ---, z i = ± 1
p0 èø 2
p5 p1
z = () ,,,
i0123
y
W i = 1---()1 + x i x ()1 + h i h ()x
1 + z i z () i xh+ i hz+ iz –2
8
x
i4= ()
W i = 1---z ()1 – z
2
= () ,,,
i5678
2
W i = 1---()1 – x ()1 + h i h ()1 + zi z
4
= () ,,,
i9101112
1 2
W i = ---()1 – z ()1 + x i x ()1 + h i h
4
Figure 8–22 Parametric coordinate system and interpolation functions for a quadratic pyramid. In
VTK parametric coordinates (r,s,t) run between (0,1), hence the coordinate system shift into the
()xhz
,, x i refer
parametric system ranging from (-1,1). Note that , and h i to thez iparametric
coordinates of the ith point.
Quadratic Tetrahedron. Figure8–19 shows the parametric coordinate system and interpolation
functions for a quadratic tetrahedron cell type. The quadratic tetrahedron is described using the
three parametric coordinates (r,s,t).
Quadratic Hexahedron. Figure8–20 shows the parametric coordinate system and interpolation
functions for a quadratic hexahedron cell type. The quadratic hexahedron is described using the
three parametric coordinates (r,s,t). Note that because the interpolation functions are most easily
expressed in the interval (-1,1), a coordinate shift is performed to the ()xhz
,, coordinates defined
in this range. Also, the notation x i , h i and is
z i introduced. These are the parametric coordinates
th
at the i point.
Quadratic Wedge. Figure8–21 shows the parametric coordinate system and interpolation func-
tions for a quadratic wedge cell type. The quadratic wedge is described using the three parametric
coordinate (r,s,t)
8.3 Cell Tessellation 281
Quadratic Pyramid. Figure8–22 shows the parametric coordinate system and interpolation func-
tions for a quadratic pyramid cell type. The quadratic pyramid is described using the three paramet-
ric coordinates (r,s,t). Note that because the interpolation functions are most easily expressed in the
interval (-1,1), a coordinate shift is performed to the ()xhz
,, coordinates system defined in this
range. Also, the notation x i , h i and zisi introduced, these are the parametric coordinate at the ith
point. (The shape functions and derivatives were implemented thanks to the Center For Aerospace
Structures http://www.colorado.edu/engineering/CAS.)
Basic Approach
The basic approach is to dynamically tessellate the cells of the GenericDataSet , and then operate on
the resulting linear tessellation. As expressed in pseudo-code, a typical algorithm looks like this:
It is important not to tessellate the entire dataset all at once, since this may produce excessive
demands on memory resources, and many algorithms visit only a subset of a dataset’s cells. Thus
the pseudo-code above refers to a selection criterion, which varies depending on the nature of the
algorithm. For example, an isocontouring algorithm may check to see whether the cell’s scalar val-
ues span the current isocontour value.
While many tessellation algorithms are possible, those based on edge subdivision are particu-
larly simple. The idea behind the algorithm is simple: each cell edge e is evaluated via an error met-
ric E and may be marked for subdivision if any error measure e i exceeds a corresponding error
T
threshold e i
T
Split edge e if e i > e i , for any e i Î E (8-7)
Based on the cell topology, and the particular edges requiring subdivision, templates are used to
subdivide the cell. This process continues recursively until the error metric is satisfied on all edges.
One advantage of this algorithm is that cells can be tessellated independently. This is because edge
subdivision is a function of one or more error measures that consider only information along the
edge, and does not need to take into account cell information. Therefore no communication across
cell boundaries is required, and the algorithm is well suited for parallel processing and on the fly
tessellation as cells are visited during traversal.
Some templates for cell subdivision are shown in Figure8–24 . Note that in some cases a
choice must be made in terms of which diagonal to select for tessellation (for example, the dashed
line in Figure8–24 (b)). In 2D, this choice can be made arbitrarily , however in 3D the choice must
be consistent with the cell’s face neighbor. In order to preserve the simplicity of the algorithm,
including avoiding inter-cell communication , simple tie-breaking rules for selecting the diagonal
on the faces of 3D cells are adopted. These rules include using the shortest diagonal (measured in
the global coordinate system), or using a topological decider based on selecting the diagonal with
the smallest point id. (A topological decider is necessary when the geometric distance measure is
inconclusive.)
8.3 Cell Tessellation 283
edge 2 edge 1
edge 0
(a) case 001 (b) case 011 (c) case 111
Figure 8–24 Three cases from the subdivision table for a triangle. Filled circles
indicate that the edge is marked for subdivision.
Error Measures
The algorithm described above is adaptive because edge splitting is controlled by local mesh prop-
erties and/or its relation to the view position. Since the goal is to insure that the quality of the tessel-
lation is consistent with the particular requirements of the visualization, we expect the adapted
tessellation to be of better quality as compared to a fixed subdivision with the same number of sim-
plices, or have fewer simplices for tessellations of equal quality.
Our design allows for the definition of multiple error measures. As indicated in Equation8-
7 , the error metric consists of several error measures, each of which evaluates local properties of
the edge against the linear approximation, and compares the measure against a user-specified
threshold. If any measure exceeds the threshold, then the edge is subdivided. These error measures
may evaluate geometric properties, approximation to solution attributes, or error related to the cur-
rent view, among other possibilities. Error measures based on geometry or attributes are indepen-
dent of view and the mesh requires only one initial tessellation.
The following paragraphs describes several error measures that have been found to be useful
in practice. Since the tessellator is designed to process a list of error measures, it is straightforward
to add new ones (by deriving from the GenericSubdivisionErrorMetric class) and/or combine it
with existing error measures.
• Object-Based Geometric Error Measure .
Edge
Referring to Figure8–25 (left), this error
B
measure is the perpendicular distance, d, C m
from the edge center point C to the straight d a
a
line passing through the cell edge vertices ( A
i
and B). Note that d is computed in world D a
coordinates, but C is computed by evaluation
at the parametric center of the edge. The per-
pendicular distance is used rather than the A
distance between C and D because if C lies Figure 8–25 Definition of the geometric
on (AB) but is not coincident with D the error and attribute error measures.
is non-zero, resulting in many useless edge
subdivisions.
284 Advanced Data Representation
• Object-Based Flatness Error Measure . This error measure is the angle a between the chords
(AC) and ( CB) passing through the real mid-point C. As the angle approaches 180° the edge
becomes flat. The threshold is the angle over which the edge is viewed as flat.
• Attribute-Based Error Measure . Referring to Figure8–25 (right), this error measure is the
i
distance between a the linearly interpolated value of an attribute at the midpoint and the
m
actual value of this attribute at the edge midpoint a .
• Image-Based Geometric Error Measure . This error measure is the distance, in pixels,
between the line ( AB) projected in image space to the midpoint C also projected in image
space. Because the computation involves projection through the current camera matrix, this
error measure is view-dependent. As a result, the tessellation may be crude in portions of the
mesh away from the camera. Note that one of the disadvantages of this approach is that tes-
sellation may be required each time the camera is repositioned relative to the mesh.
Advanced Methods
Attentive readers will have noticed that the subdivision scheme described previously may fail to
capture all the features of the higher-order basis. For example, imagine a scalar function across a
triangle where the peak value of the function occurs in the center of the triangle, and the variation
across the edges is zero. The edge subdivision algorithm described previously will not capture the
peak, hence an algorithm such as isocontouring will produce inaccurate results. Linear isocontour-
ing algorithms require that the following conditions are met in order to produce topologically cor-
rect results.
By definition, these conditions are directly related to critical points, since an extremum of a differ-
entiable function over an open domain is necessarily a critical point. Linear meshes assume that all
extrema of the scalar field occur at element vertices, but in general when using a higher-order basis
this is not the case, and extrema can be found interior to a cell.
To address this problem, a pre-triangulation of the basis must be performed. The pre-triangu-
lation must identify all critical points in the interior, on the faces, or on the edge of a cell, and then
insert these points into the triangulation. For example, an initial triangulation based on the vertices
of the higher-order cell can be performed first, followed by insertion into the triangulation using a
method such as Delaunay triangulation or equivalent (see “Triangulation” on page345 ). The pre-tri-
angulation can then be followed by the standard edge-based algorithm presented previously.
n1–
pW= å i ()r 0,,s 0 t 0 pi (8-8)
i0=
where the interpolation weights W i are evaluated at the parametric coordinate ()r 0,,s 0 t 0 .
In the formulation presented here, we have used the same order interpolation functions for
both data and cell geometry. (By order we mean the polynomial degree of the interpolating polyno-
mials.) This is termed iso-parametric interpolation. It is possible to use different interpolation func-
tions for geometry and data. Super-parametric interpolation is used when the order of the
interpolation functions for geometry is greater than those used for data. Sub-parametric interpola-
tion is used when the order of the interpolation functions for geometry is less than those used for
data. Using different interpolation functions is commonly used in numerical analysis techniques
such as the finite element method. We will always use the iso-parametric interpolation for visual-
ization applications.
Global to dataset coordinate transformations are expensive compared to dataset to global transfor-
mations. There are two reasons for this. First, we must identify the particular cell Ci that contains
the global point p. Second, we must solve Equation8-4 for the parametric coordinates of p.
To identify the cell C i means doing some form of searching. A simple but inefficient
approach is to visit every cell in a dataset and determine whether p lies inside any cell. If so, then
we have found the correct cell and stop the search. Otherwise, we check the next cell in the list.
This simple technique is not fast enough for large data. Instead, we use accelerated search
techniques. These are based on spatially organizing structures such as an octree or three-dimen-
sional hash table. The idea is as follows: we create a number of “buckets,” or data place holders,
that are accessed by their location in global space. Inside each bucket we tag all the points or cells
that are partially or completely inside the bucket. Then, to find a particular cell that contains point
p, we find the bucket that contains p, and obtain all the cells associated with the bucket. We then
evaluate inside/outside for this abbreviated cell list to find the single cell containing p. (See
“Searching” on page292 for a more detailed description.)
The second reason that global to dataset coordinate transformation is expensive is because we
must solve the interpolation function for the parametric coordinates of p. Sometimes we can do this
analytically, but in other cases we must solve for the parametric coordinates using numerical tech-
niques.
286 Advanced Data Representation
Consider the interpolation functions for a line ( Figure8–2 ). We can solve this equation
exactly and find that
Similar relations exist for any cell whose interpolation functions are linear combinations of para-
metric coordinates. This includes vertices, lines, triangles, and tetrahedra. The quadrilateral and
hexahedron interpolation functions are nonlinear because they are products of linear expressions
for the parametric coordinates. As a result, we must resort to numerical techniques to compute glo-
bal to dataset coordinate transformations. The interpolation functions for pixels and voxels are non-
linear as well, but because of their special orientation with respect to the x, y, and z coordinate axes,
we can solve them exactly. (We will treat pixel and voxel types in greater depth in “Special Tech-
niques for Image Data” on page295 .)
To solve the interpolation functions for parametric coordinates we must use nonlinear tech-
niques for the solution of a system of equations. A simple and effective technique is Newton’s
method [Conte72] .
To use Newton’s method we begin by defining three functions for the known global coordi-
nate p = p(x,y,z) in terms of the interpolation functions Wi = W i(r,s,t)
()
frst,, = 0xW
= – å i xi
()
grst,, = 0yW
= –å i yi
(8-10)
()
hrst,, = 0zW
= –å i zi
¶f ¶f ¶f
f0f= = 0 + ()rr– 0 +++ ()ss– 0 ()tt– 0 ¼
¶r ¶s ¶t
¶g ¶g ¶g (8-11)
g0g
= = 0 + ()rr– 0 +++ ()ss– 0 ()tt– 0 ¼
¶r ¶s ¶t
¶h ¶h ¶h
h0h
= = 0 + ()rr– 0 +++ ()ss– 0 ()tt– 0 ¼
¶r ¶s ¶t
we can develop an iterative procedure to solve for the parametric coordinates. This yields the gen-
eral form
–1
¶f ¶f ¶f
r i1+ ri ¶ r ¶s ¶t fi
s i1+ = s i – ¶g ¶g ¶g gi (8-12)
¶r ¶s ¶t
t i1+ ti hi
¶h ¶h ¶h
¶r ¶s ¶t
8.5 Computing Derivatives 287
Fortunately, Newton’s method converges quadratically (if it converges) and the interpolation func-
tions that we have presented here are well behaved. In practice, Equation8-12 converges in just a
few iterations.
s1 x'
x1
z
s0
l
y
x0
Figure 8–26 Computing derivatives
x in an 1D line cell.
ds = ()
s 1 – s0
= () 1 – s0
--------------------s (8-13)
dr 1
where si is the data value at point i. In the local coordinate system , which
x' is parallel to the r
coordinate system (that is, it lies along the vector ), the
x 1 –derivative
x0 is
ds ()s 1 – s 0
= -------------------- (8-14)
d x' l
d d d
= × x' (8-15)
dr d x' d r
¤
allows us to compute the derivative using
dx'd
d
= æö
d d
èød r ¤ d r x'
(8-16)
d x'
288 Advanced Data Representation
æö 1
d x' = d ç÷
dr d r ç÷
å W i × x' i ==– x 0 ' + x 1' l (8-17)
èøi0=
which, when combined with Equation8-16 and Equation8-13 for the s derivatives, yields
Equation8-14 .
One final step remains. The derivatives in the x coordinate system must be converted to the
global x-y-z system. We can do this by creating a unit vector asv
()x 1 – x 0
v = ---------------------- (8-18)
x1 – x 0
where xand
0 are xthe
1 locations of the two end points of the line. Then the derivatives in the x, y,
and z directions can be computed by taking the dot products along the axes.
ds = æös---------------
1 – s0
× () ,,
v100
dx èø l
ds s1 – s0
= æö
èø × () ,,
---------------
v010 (8-19)
dy l
ds æös 1 – s 0
× () ,,
= ---------------
v001
d z èø l
To summarize this process, derivatives are computed in the local r-s-t parametric space using cell
interpolation. These are then transformed into a local Cartesian
x'y'– system.
– z' Then, if the
x'y'– – z' system is not aligned with the global coordinate
xy– – z system, another transforma-
tion is required to generate the result.
We can generalize this process to three dimensions. From the chain rule for partial derivatives
¶ ¶ ¶r ¶ ¶s ¶ ¶t
= + +
¶ x ¶r ¶x ¶ s ¶ x ¶t ¶ x
¶ ¶ ¶r ¶ ¶s ¶ ¶t (8-20)
= + +
¶ y ¶r ¶y ¶ s ¶ y ¶t ¶ y
¶ ¶ ¶r ¶ ¶s ¶ ¶t
= + +
¶z ¶ r ¶z ¶ s ¶ z ¶ t ¶ z
or after rearranging
¶ ¶x ¶y ¶z ¶ ¶
¶r ¶r ¶r ¶ r ¶ x ¶x
¶ = ¶x ¶y ¶z ¶ = J ¶ (8-21)
¶s ¶s ¶s ¶ s ¶ y ¶y
¶ ¶x ¶y ¶z ¶ ¶
¶t ¶t ¶t ¶ t ¶ z ¶ z
8.6 Topological Operations 289
Figure 8–27 Manifold and nonmanifold surface topology. If the local neighborhood around a vertex
is topologically a 2D disk (i.e., a small disk can be placed on the surface without tearing or overlap-
ping), then the surface is manifold at that vertex.
The 33´
matrix J is called the Jacobian matrix, and it relates the parametric coordinate deriva-
tives to the global coordinate derivatives. We can rewrite Equation8-21 into more compact form
¶ ¶ (8-22)
= J
¶ ri ¶ xi
and solve for the global derivatives by taking the inverse of the Jacobian matrix
¶ –1 ¶
(8-23)
= J
¶ xi ¶ri
The inverse of the Jacobian always exists as long as there is a one-to-one correspondence between
the parametric and global coordinate systems. This means that for any (r, s, t) coordinate, there cor-
responds only one (x, y, z) coordinate. This holds true for any of the parametric coordinate systems
presented here, as long as pathological conditions such as cell self-intersection or a cell folding in
on itself are avoided. (An example of cell folding is when a quadrilateral becomes nonconvex.)
In our one-dimensional example, the derivatives along the line were constant. However, other
interpolation functions (e.g., Figure8–5 ) may yield non-constant derivatives. Here, the Jacobian is
a function of position in the cell and must be evaluated at a particular ( r, s, t) coordinate value.
There are some simple rules we can use to decide whether a surface or region approximated
with cells is manifold or nonmanifold. In two dimensions, if every edge of a two-dimensional cell
is used by exactly one other cell, than the surface is locally manifold. In three dimensions, if every
face of a three-dimensional cell is used by exactly one other cell, than the region is locally mani-
fold.
We also will use the term simplex on some occasions. A simplex of dimension n is the convex
region defined by a set of n+1 independent points. A vertex, line, triangle, and tetrahedron are sim-
plices of dimension 0, 1, 2, and 3, respectively as shown in Figure8–28 .
Cell Operations
Cell operations return information about the topology of a cell. Typically, we want to know the
topological order of the cell or the topology of the cell boundary.
Given a cell C i of topological dimension d, the cell is (implicitly) composed of boundary
cells of topological order d-1 and lower. For example, a tetrahedron is composed of four two-
dimensional triangles, six one-dimensional edges, and four zero-dimensional vertices. Cell opera-
tions return information about the number of boundary cells of a particular topological dimension,
as well as the ordered list of points that define each bounding cell.
Another useful cell operation returns the closest boundary cell of dimension d-1 given the
parametric coordinates of the cell. This operation ties the geometry to the topology of the cell, as
compared to the parametric coordinate system, which ties the topology to the geometry. The closest
boundary cell operation is implemented by partitioning each cell into various regions, as illustrated
in Figure8–29 . To determine the closest boundary cell we need only to identify the parametric
region that the point lies in, and then return the appropriate boundary cell.
Another useful cell operation is cell decomposition into simplices. Every cell can be decom-
posed into a collection of simplices. By doing so, and by operating on the simplex decomposition
rather than the cell itself, we can create algorithms that are independent of cell type. For example, if
we want to intersect two datasets of varied cell type, without simplex decomposition we would
have to create methods to intersect every possible combination of cells. With simplex decomposi-
tion, we can create a single intersection operation that operates on only the limited set of simplices.
The significant advantage of this approach is that as new cells are added to the visualization system,
only the cell object (including its method for simplex decomposition) must be implemented, and no
other objects need be modified.
8.6 Topological Operations 291
s
p3 edge 2
p2
edge 0: r > s and r < 1 - s
r=
1- edge 1: r > s and r > 1 - s
edge 3 s
edge 1
s
r= edge 2: r < s and r > 1 - s
r
edge 3: r < s and r <1 - s
p0 edge 0 p1
Dataset Operations
Dataset operations return information about the topology of a dataset or topological information
about the adjacency of cells. Typical operations include determining the neighbors of a cell or
returning a list of all cells that use a particular point.
We can formalize the adjacency operations by continuing the discussion of “Cell Types” on
page124 . Adjacency methods are used to obtain information about the neighbors of a cell. A
neighbor of a particular cell C i is simply a cell that shares one or more points in common with C i. A
vertex neighbor is a neighbor that shares one or more vertices. An edge neighbor is a neighbor that
shares one or more edges. A face neighbor is a cell that shares vertices that define one of the faces
of the cell. Note that a face neighbor is also an edge neighbor, and an edge neighbor is also a vertex
neighbor.
The adjacency operators are simple set operations. For a particular cell Ci defined by points
n
() i, P = æö
AC èø Ç Up() i – Ci (8-25)
i1=
The adjacency set represents a variety of useful information. In a manifold object represented by a
polyhedra, for example, each polygon must have exactly one edge neighbor for each of its edges.
Edges that have no neighbors are boundary edges; edges that have more than one edge neighbor
represent nonmanifold topology. Datasets that consist of three-dimensional cells (e.g., unstructured
grids) are topologically consistent only if, for each cell, there is exactly one face neighbor for each
face. Faces that have no neighbors are on the boundary of the dataset. More than one face neighbor
implies that the neighbors are self-intersecting (in 3D space).
292 Advanced Data Representation
8.7 Searching
Searching is an operation to find the cell containing a specified point p, or to locate cells or points
in a region surrounding p. Algorithms requiring this operation include streamline generation, where
we need to find the starting location within a cell; probing, where the data values at a point are
interpolated from the containing cell; or collision detection, where cells in a certain region must be
evaluated for intersection. Sometimes (e.g., image datasets), searching is a simple operation
because of the regularity of data. However, in less structured data, the searching operation is more
complex.
To find the cell containing p, we can use the following naive search procedure. Traverse all
cells in the dataset, finding the one (if any) that contains p. To determine whether a cell contains a
point, the cell interpolation functions are evaluated for the parametric coordinates (r,s,t). If these
coordinates lie within the cell, then p lies in the cell. The basic assumption here is that cells do not
overlap, so that at most a single cell contains the given point p. To determine cells or points lying in
the region surrounding p, we can traverse cells or points to see whether they lie within the region
around p. For example, we can choose to define the region as a sphere centered at p. Then, if a
point or the points composing a cell lie in the sphere, the point or cell is considered to be in the
region surrounding p.
These naive procedures are unacceptable for all but the smallest datasets, since they are of
order O(n) , where n is the number of cells or points. To improve the performance of searching, we
need to introduce supplemental data structures to support spatial searching. Such structures are
well-known and include MIP maps, octrees, kd-trees, and binary sphere trees (see “Bibliographic
Notes” on page315 at the end of this chapter).
The basic idea behind these spatial search structures is that the search space is subdivided
into smaller parts, or buckets. Each bucket contains a list of the points or cells that lie within it.
Buckets are organized in structured fashion so that constant or logarithmic time access to any
bucket is possible. For example, if we assign a portion of 2D Euclidean space into a grid of n by m
buckets, the location of p in a particular bucket can be determined with two subtractions and two
divisions: a constant time access. Similarly, the location of p in a nonuniformly subdivided octree is
determined in logarithmic time, since recursive insertion into octant children is required. Once the
bucket is found, the search is then limited to the points or cells contained within it. In a properly
designed spatial search structure, the number of points or cells in a bucket is a small portion of the
total number of cells and less than a fixed value. Thus, the time to search within a bucket can be
bounded by a fixed constant. The result is that introducing spatial search structures reduces search
times to a maximum O(log n) , or better yet O(n).
We have two options when applying spatial search structures. We may insert points into the
search structure, or we may insert cells, depending on the application. There are advantages and
disadvantages to both approaches. Inserting cells into buckets is not a trivial operation. In general,
cells are arbitrarily oriented and shaped, and will not fit completely into a single bucket. As a result,
cells often span multiple buckets. To reliably determine whether a cell is in a bucket requires geo-
metric intersection tests, a costly operation. Another approach is to use the bounding box of a cell to
decide which bucket(s) a cell belongs in. We only need to intersect the bounding box with a bucket
to determine whether the cell may belong in the bucket. Unfortunately, even though this operation
is generally fast, often cells are associated with buckets even though they may not actually lie
inside them, wasting (in large models) memory resources and extra processing time.
8.8 Cell / Line Intersection 293
p search
structure
Figure 8–30 Using search structure (containing points) to find cells. (a) Points are asso-
ciated with appropriate bucket. Point p is used to index into bucket, and closest point(s) p i
is found. Cells using p i are evaluated for the cell containing p. (b) Sometimes closest
points p i are not used by cells containing p.
Inserting points into a search structure is easier because points can be uniquely placed into a
bucket. Inserting points also allows us to search for both points and cells. Cells can be found by
using p to index into the appropriate bucket. The closest point(s) p i to p are then located. Using the
topological adjacency operator to retrieve the cells using points p i, we can then search these cells
for the cell containing p. This procedure must be used with caution, however, since the closest
points may not be used by the cells containing p (Figure8–30 ).
t=1
t=0
Vertex Line Triangle
• project point onto ray • 3D line intersection • line/plane intersection
• distance to line must be • distance between lines must be • intersection point must lie in
within tolerance within tolerance triangle
• t must lie between [0,1] • s,t must lie between [0,1] • t must lie between [0,1]
Intersection point
(minimum t value)
Figure 8–31 Summary of line/cell intersection operations for nine primitive cell types. Line is
assumed normalized in parametric coordinate t with .0t1££
8.9 Scalars and Colors 295
Y0.30R0.59G0.11B
= + + (8-26)
= ()
YA0.30R0.59G0.11B
+ + (8-27)
Using this abstraction allows us to treat single-valued scalars and scalars consisting of multivalued
colors the same. The end result is that we can mix both types of scalar data into our visualization
networks.
Coordinate Transformation
Given a point p we can find the structured coordinates by performing three division operations
(Figure8–32 ). Taking the integer floor function yields the structured coordinates. Taking the frac-
296 Advanced Data Representation
ifloorxx
= ()() – 0 ¤ ()x 1 – x 0
jflooryy
= ()() – 0 ¤ ()y 1 – y 0
y
kfloorzz
= ()() – 0 ¤ ()z 1 – z 0
rfracxx
= ()() – 0 ¤ ()x 1 – x 0
sfracyy
= ()() – 0 ¤ ()y 1 – y 0
y1
tfraczz
= ()() – 0 ¤ ()z 1 – z 0
x 0, y 0 x1 x
tional part of the result yields the parametric coordinates of the cell. We can then use Equation8-3
to convert to dataset coordinates.
Derivative Computation
Because the image dataset is oriented parallel to the coordinate x, y, and z axes, and because the
spacing of points in each of these directions is regular, finite difference schemes can be used to
compute partial derivatives at the cell points. Referring to Figure8–33 , we see that central differ-
ences can be used in each of the three directions according to the equation:
(Note that at the boundary of the dataset, one-sided differences may be used.) We can use these
equations to compute derivatives within the cell as well. We simply compute the derivatives at each
cell point from Equation8-28 , and then use the cell interpolation functions to compute the deriva-
tive at the point inside the cell.
Topology
Structured datasets lend themselves to efficient topological operations (i.e., both image data and
structured grids). Given a cell id, it is possible to determine vertex, edge, or face neighbors using
8.10 Special Techniques for Image Data 297
Dy
Figure 8–33 Using finite differences to
compute derivatives on image data.
Dx ()x 0 , y 0
simple constant time operations. First, given the cell id in a three-dimensional structured dataset,
we use a combination of division and modulo arithmetic to compute the structured coordinates
iid= modulo n () x –1
= () ¤ () x – 1
jidn modulo n() y – 1 (8-29)
kidn
= ¤ ()() x – 1 ()n y – 1
Face neighbors are determined by incrementing one of the i, j, or k indices. Edge neighbors are
determined by incrementing any two indices, while vertex neighbors are found by incrementing all
three indices. Care must be taken while incrementing to insure that the indices fall in the range
0in£ < () x – 1
0jn£ < () y – 1 (8-30)
£ < () z – 1
0kn
An attempt to index outside these ranges indicates that the neighbor in question does not exist.
Searching
iintxx
= ()() – 0 ¤ ()x 1 – x 0
jintyy
= ()() – ¤ ()y 1 – y 0 (8-31)
0
kintzz
= ()() – 0 ¤ ()z 1 – z 0
298 Advanced Data Representation
In this section we will finish our earlier description of an implementation for unstructured data. We
also define a high-level, abstract interface for cells and datasets. This interface allows us to imple-
ment the general (i.e., dataset specific) algorithms in the Visualization Toolkit . We also describe
implementations for color scalars, searching and picking, and conclude with a series of examples to
demonstrate some of these concepts.
Unstructured Topology
In Chapter 5 we described data representations for the unstructured dataset types vtkPolyData and
vtkUnstructuredGrid . Close examination of this data structure reveals that operations to retrieve
topological adjacency are inefficient. In fact, to implement any operation to retrieve vertex, edge,
or face neighbors requires a search of the cell array, resulting in O(n) time complexity. This is unac-
ceptable for all but the smallest applications, since any algorithm traversing the cell array and
retrieving adjacency information is at a minimum O(n 2 ).
The reason for this inefficiency is that the data representation is a “downward” hierarchy
(Figure8–34 (b)). That is, given a cell we can quickly determine the topological features lower in
the topological hierarchy such as faces, edges, and points. However, given a face, edge, or point we
must search the cell array to determine the owning cells. To improve the efficiency of this data rep-
resentation, we must introduce additional information into the hierarchy that allows “upward” hier-
archy traversal (similar to that shown in Figure8–34 (a)).
The solution to this problem is to extend the unstructured data structure with cell links . The
cell links array is a list of lists of cells that use each point and corresponds to the upward links of
Figure8–34 (c). The cell links array transforms the hierarchical structure of Figure5–13 into a ring
structure. Cells reference their composing points, and points in turn reference the cells that use
them. The full unstructured data structure is shown in Figure8–35 .
The cell links array is in fact an implementation of the use sets of Equation5-1 . We can use
this equation to compute adjacency operation in constant time, if the maximum number of cells
using a point is much smaller than the number of points in a dataset. To see this, we refer to
Equation8-25 and see that the adjacency operations consist of a finite number of set intersections.
Each operation is an intersection of the link lists for each point. If the number of cells in each link
list is “small,” then the intersection operation can be bounded by a fixed constant in time, and the
total operation can be considered a constant time operation.
There are several important characteristics of this data representation.
• The cell links array is an extension of the basic unstructured data representation. As a result,
we can defer the construction of the cell links until they are required. Often the cell links are
never needed and require no computer resources to compute or store.
• Building the cell links is a linear O(n) operation. Each cell is traversed and for every point
that the cell uses, the list of using cells for that point is extended to include the current cell.
Building the cell links is only needed once as an initialization step.
8.11 Putting It All Together 299
Face
Links
Edge
Figure 8–34 Enhancing hierarchical unstructured data representation. (a) Conventional topological
hierarchy for geometric model. (b) Basic unstructured data hierarchy. (c) Full unstructured data hierar-
chy. By introducing upward references from points to cells, the unstructured data hierarchy may be
efficiently traversed in both directions, and is more compact than conventional topological hierarchies.
• The data representation is compact relative to other topology representation schemes (e.g.,
the winged-edge structure and the radial-edge structures [Baumgart74] [Weiler88] ). These
other data structures contain explicit representation of intermediate topology such as edges,
loops, faces, or special adjacency information such as adjacent edges (winged-edge structure)
or extensive “use” descriptions (radial-edge structure). The compactness of representation is
particularly important for visualization, since the data size is typically large.
The unstructured data structure in the Visualization Toolkit is implemented using the four classes
vtkPoints (and subclasses), vtkCellArray , vtkCellTypes , and vtkCellLinks . The building of this data
structure is incremental. At a minimum, the points and cells are represented using vtkPoints and
vtkCellArray . If random access or extra type information is required, then the object vtkCellTypes
is used. If adjacency information is required, an instance of the class vtkCellLinks is created. These
operations are carried out behind the scenes, and generally do not require extra knowledge by the
application programmer.
Abstract Interfaces
With the completion of Chapters 5 and 8, we can summarize the abstract interface for cells,
datasets, and the point data attributes. These pseudo-code descriptions encapsulate the core func-
tionality of the classes vtkDataSet , vtkCell , and vtkPointData , and their subclasses. All algorithms
presented in this text can be implemented using combinations of these methods.
300 Advanced Data Representation
x0 n type 0 nCells 0
y0 p1 offset 0 cells 0
z0 p2 type 1 nCells 1
x1 p3 offset 1 cells 1
y1 type 2 nCells 2
z1 offset 2 cells 2
n
xn-1 p1
yn-1 p2 type m-1 nCells n-1
zn-1 p3 offset m-1 cells n-1
Figure 8–35 Complete unstructured data representation including link lists. There are
m cells and n points. The n structures in the link list are lists of cells that use each vertex.
Each link list is variable in length.
Dataset Abstraction. The dataset is the central data representation in VTK. Datasets are composed
of one or more cells and points. Associated with the points are attribute data consisting of scalars,
vectors, normals, texture coordinates, and tensors.
type = GetDataObjectType()
Return the type of dataset (e.g., vtkPolyData , vtkImageData , vtkStructuredGrid ,
vtkRectilinearGrid , or vtkUnstructuredGrid ).
numPoints = GetNumberOfPoints()
Return the number of points in the dataset.
numCells = GetNumberOfCells()
Return the number of cells in the dataset.
GetPoint(ptId,x)
Given a point id, return the (x,y,z) coordinates of the point.
cell = GetCell(cellId)
Given a cell id, return a pointer to a cell object.
type = GetCellType(cellId)
Return the type of the cell given by cell id.
8.11 Putting It All Together 301
GetCellTypes(types)
Return a list of types of cells that compose the dataset.
cells = GetPointCells(ptId)
Given a point id, return the cells that use this point.
GetCellPoints(cellId, ptIds)
Given a cell id, return the point ids (e.g., connectivity list) defining the cell.
pointData = GetPointData()
Return a pointer to the object maintaining point attribute data. This includes scalars,
vectors, normals, tensors, and texture coordinates, as well as any other data arrays that
the field carries.
cellData = GetCellData()
Return a pointer to the object maintaining cell attribute data. This includes scalars, vec-
tors, normals, tensors, and texture coordinates, as well as any other data arrays that the
field carries.
bounds = GetBounds()
Get the bounding box of the dataset.
length = GetLength()
Return the length of the diagonal of the bounding box of the dataset.
center = GetCenter()
Get the center of the bounding box of the dataset.
range = GetScalarRange()
A convenience method to return the (minimum, maximum) range of the scalar attribute
data associated with the dataset.
dataSet = NewInstance()
Make a copy of the current dataset. A “virtual” constructor. (Typically, reference count-
ing methods are used to copy data.)
CopyStructure(dataSet)
Update the current structure definition (i.e., geometry and topology) with the supplied
dataset.
302 Advanced Data Representation
Cell Abstraction. Cells are the atomic structures of VTK. Cells consist of a topology, defined by a
sequence of ordered point ids, and a geometry, defined by point coordinates. The cell coordinate
consists of a cell id, a subcell id, and a parametric coordinate. The subid specifies a primary cell
that lies within a composite cell such as a triangle strip. Cell edges and faces are defined implicitly
from the topology of the cell.
type = GetCellType()
Return the type of the cell. Must be one of the twelve VTK cell types (or the empty cell
type).
dim = GetCellDimension()
Return the topological definition of the cell.
order = GetInterpolationOrder()
Return the degree of the interpolating polynomial of the cell. (The twelve cell types are
all degree 1; cells added in the future may be of higher-order.)
numberPoints = GetNumberOfPoints()
Return the number of points that define the cell.
points = GetPoints()
Return a list of point ids defining the cell.
numberEdges = GetNumberOfEdges()
Return the number of edges in the cell.
edge = GetEdge(i)
£ <a pointer to a cell that represents an
Given an edge id () return
0inumberEdges
edge of the cell.
numberFaces = GetNumberOfFaces()
Return the number of faces in a cell.
face = GetFace(i)
£ <a pointer to a cell that represents a face
Given an face id () 0inumberFaces
return
of the cell.
inOutStatus = CellBoundary(subId, pcoords, poindIds)
Given a cell subid and parametric coordinates, return a list of point ids that define the
closest boundary face of the cell. Also return whether the point is actually in the cell.
Point and Cell Attribute Abstraction. Point and cell attribute data is information associated with
the points and cells of a dataset. This information consists of scalars, vectors, normals, tensors, and
texture coordinates. There is a one-to-one relationship between the points and cells in a dataset and
its corresponding point and cell attribute data. For example, a point scalar value at location 100 is
associated with point id 100.
Many of the methods described below deal with moving data from the input to the output of a
filter. Since the possibility exists that new types of attribute data could be added in the future, the
304 Advanced Data Representation
details of moving data is hidden as much as possible (i.e., minimize the knowledge that the filter
has about specific attribute types). Thus, generic functions like CopyData() allow for copying data
from the input to the output without knowing what this data is.
CopyScalarsOn() / CopyScalarsOff()
Turn on/off boolean flag controlling copying of scalar data from input to output of fil-
ter.
CopyVectorsOn() / CopyVectorsOff()
Turn on/off boolean flag controlling copying of vector data from input to output of fil-
ter.
CopyNormalsOn() / CopyNormalsOff()
Turn on/off boolean flag controlling copying of normal data from input to output of fil-
ter.
CopyTensorsOn() / CopyTensorsOff()
Turn on/off boolean flag controlling copying of tensor data from input to output of fil-
ter.
CopyTextureCoordsOn() / CopyTextureCoordsOff()
Turn on/off boolean flag controlling copying of texture coordinates data from input to
output of filter.
CopyAllOn() / CopyAllOff()
Turn on/off all boolean flags controlling copying of all attribute data from input to out-
put of filter.
PassData(pointData)
Transfer all point attribute data ( pointData ) to the output according to the copy flags
listed previously.
CopyAllocate(pointData)
Initialize and allocate storage for point-by-point copy process.
CopyData(pointData, fromId, toId)
Given point data and a specific point id, copy the point attribute data ( pointData ) to the
output point.
InterpolateAllocate(pointData)
Initialize and allocate storage for point-by-point interpolation process.
InterpolatePoint(pointData, toId, ptIds, weights)
Given input point data ( pointData ) and a list of points and their interpolation weights,
interpolate data to the specified output point.
InterpolateEdge(pointData, toId, p1, p2, t)
From an edge defined by the two points p1 and p2, interpolate the pointData at the edge
parametric coordinate t and copy the interpolated attribute data to the output point ptId.
NullPoint(int ptId)
Set the data value(s) of the specified output point id to a null value.
8.11 Putting It All Together 305
SetScalars() / GetScalars()
Set / return scalar data. The GetScalars() method may return a NULL value, in which
case the scalars are not defined.
SetVectors() / GetVectors()
Set / return vector data. The GetVectors() method may return a NULL value, in which
case the vectors are not defined.
SetNormals() / GetNormals()
Set / return normal data. The GetNormals() method may return a NULL value, in
which case the normals are not defined.
SetTensors() / GetTensors()
Set / return tensor data. The GetTensors() method may return a NULL value, in which
case the tensors are not defined.
SetTextureCoords() / GetTextureCoords()
Set / return texture coordinate data. The GetTextureCoords() method may return a
NULL value, in which case the texture coordinates are not defined.
The dataset abstraction implemented by VTK provides simple techniques to traverse points and
cells. Sometimes we want to traverse intermediate topology such as edges or faces. For example, to
identify boundary edges in a triangular mesh we must traverse each edge, counting the number of
triangles that use each edge. (Recall that boundary edges are used by just one triangle.) Unfortu-
nately, there is no obvious way to traverse edges. The same problem holds true if we want to
traverse the faces of a dataset containing 3D cells.
A simple solution is to traverse each cell and then obtain the edges (or faces) that compose
the cell. The problem with this approach is that edges and faces are generally used by more than
one cell, resulting in multiple visits to the same face or edge. This may be acceptable in some algo-
rithms, but usually we count on visiting each edge or face only once.
A better solution to this problem is to traverse each cell as before, but only process intermedi-
ate topology if the current cell has the smallest cell id. (The current cell is the cell being visited in
the traversal process.) To determine whether the current cell has the smallest cell id, we obtain all
cells using the intermediate topology. This information can be obtained using the topological adja-
cency operators described earlier (e.g., Equation8-25 ).
To illustrate this process consider visiting the edges of a triangle mesh. We begin by visiting
the first triangle, t, and then its edges. For each edge we determine the adjacent triangle(s) (if any)
that use the edge. If the id of the adjacent triangle(s) is greater than triangle t’s id, or there are no
adjacent triangles, then we know to process the current edge. (Of course the first triangle will
always have the smallest id — but this will change as the traversal proceeds.) We then continue tra-
versing the triangle list for new t’s. In this way all the edges of the mesh will be visited.
306 Advanced Data Representation
Multivalued scalar data, or scalars represented by various color representations, are treated spe-
cially by the Visualization Toolkit . These data arise, for example, when using a color specification
to directly control the color of objects rather than mapping a scalar value through a lookup table.
(See “Color Mapping” on page163 for more information.)
By default, the mapping of scalars into colors proceeds as follows ( vtkMapper and subclasses
are responsible for implementing this behavior):
• If the scalar type is unsigned char with the tuple size ranging between one and four com-
ponents, the data is considered to be color data.
• Any other data type, or data with more than four components, is assumed to represent a scalar
value. In that case the scalars are mapped through a lookup table to produce colors during the
rendering process.
It is possible to force unsigned char data to be mapped through a lookup table. The vtkMapper
method SetColorModeToMapScalars() forces all data—regardless of type—to be mapped through
the lookup table.
Searching
The Visualization Toolkit provides two classes to perform searches for dataset points and cells.
These are vtkPointLocator and vtkCellLocator . (Both of these classes are subclasses of vtkLocator ,
which is an abstract base class for spatial search objects.) vtkPointLocator is used to search for
points and, if used with the topological dataset operator GetPointCells() , to search for cells as well.
vtkCellLocator is used to search for cells.
vtkPointLocator is implemented as a regular grid of buckets (i.e., same topology and geome-
try as an image dataset). The number of buckets can be user-specified, or more conveniently, auto-
matically computed based on the number of dataset points. On average, vtkPointLocator provides
constant time access to points. However, in cases where the point distribution is not uniform, the
number of points in a bucket may vary widely, giving O(n) worst-case behavior. In practice this is
rarely a problem, but adaptive spatial search structures (e.g., an octree) may sometimes be a better
choice.
Determining closest point to a point p using vtkPointLocator (as well as other spatial search
structures) is a three-step process. In the first step, the bucket containing p is found using the appro-
priate insertion scheme. (For vtkPointLocator this is three divisions to determine bucket indices (i,
j, k).) Next, the list of points in this bucket is searched to determine the closest point. However, as
Figure8–36 shows, this may not be the true closest point, since points in neighboring buckets may
be closer. Consequently, a final search of neighboring buckets is necessary. The search distance is a
8.11 Putting It All Together 307
c
Figure 8–36 Determining closest point to p in
vtkPointLocator. Initial search in bucket results in p
point a. Search must extend beyond local bucket as R b
a function of search radius R, resulting in point b. a
å8
i
cell list nP+1 nO =
cell list nP+2 i0=
Level n terminal Terminal
octants Octants number of parents, n P
cell list nO-1 nP = nO – nT
cell list nO
Figure 8–37 Structure of spatial search structure vtkCellLocator. The data structure represents a uni-
formly subdivided octree.
function of the distance to the current closest point. Once all neighbors within this distance are
searched, the closest point is returned.
vtkCellLocator is implemented as a uniformly subdivided octree with some peculiar charac-
teristics ( Figure8–37 ). Conventional octree representations use upward parent and downward chil-
dren pointers to track parent and children octants. Besides the required list of entities (i.e., points or
cells) in each octant, additional information about octant level, center, and size may also be main-
tained. This results in a flexible structure with significant overhead. The overhead is the memory
resources to maintain pointers, plus the cost to allocate and delete memory.
In contrast, vtkCellLocator uses a single array to represent the octree. The array is divided
into two parts. The first part contains a list of parent octants, ordered according to level and octant
308 Advanced Data Representation
vtkAbstractPicker
child number. In the second part are the terminal, or leaf octants. The terminal octants are ordered
on a regular array of buckets, just the same as vtkLocator . The terminal octants contain a list of the
entities inside the octant. The parent octants maintain a value indicating whether the octant is
empty, or whether something is inside it. (Both types of information are represented in the same
portion of the octant structure.) Because the octree is uniformly subdivided, parent-child relation-
ships, as well as octant locations, can be computed quickly using simple division operations.
The advantage of this structure is that memory can be allocated and deleted quickly. In addi-
tion, insertion into the octree is exactly the same as with vtkLocator , and is simpler than conven-
tional octrees. The parent octants provide quick culling capability, since their status (empty or
nonempty) allows us to stop certain types of search operations. On the downside, because the
octree is uniformly subdivided, this structure is wasteful of memory resources if the data is nonuni-
formly distributed.
Our experience with the search structures described here is that they work well for many
types of visualization data. However, if your data is non-uniform, you may want to implement your
own special search classes.
Picking
The Visualization Toolkit provides a variety of classes to perform actor (or vtkProp), point, cell, and
world point picking ( Figure8–38 ). Depending on which picker is used, either software-based geo-
metric intersection or hardware picking is used. The following describes each of the picker types in
detail.
All pickers are subclasses of vtkAbstractPicker which defines the basic pick interface. The
user must specif y a selection point in display coordinates for a specified instance of vtkRenderWin-
dow and invoke the Pick() method. At a minimum, the class must return an x-y-z pick position in
world coordinates. It is possible to limit the pick candidates to a list of vtkProps (the PickList ). The
class also invokes the StartPickEvent, PickEvent, and EndPickEvent events that are invoked prior
to picking, during picking, and after picking, respectively.
Classes that can return information indicating which vtkProp they have picked are subclasses
of vtkAbstractPropPicker. After the pick operation, vtkAbstractPropPicker returns a
vtkAssemblyPath. The assembly path is an ordered list of instances of vtkProp and possibly
associated transformation
4x4 matrices. The path represents a concatenated hierarchy of assembly
8.11 Putting It All Together 309
nodes if an assembly has been defined (see “Assemblies and Other Types of vtkProp” on page74 for
more information about props and assemblies).
The object vtkPicker intersects a ray defined from camera position to a screen (i.e., pixel)
coordinate against the bounding box of all pickable and nontransparent vtkProp3D’s. (A vtkProp is
pickable if its Pickable instance variable is true.) The result of the vtkPicker pick operation is to
return a list of the vtkProp3D’s whose bounding box is intersected. The prop closest to the camera
position is also returned.
The object vtkPointPicker intersects the ray against the points defining each vtkProp3D, and
returns the point coordinate closest to the camera position, as well as the vtkProp3D that the point
belongs to. Since screen resolution prevents precise selection of a point, a tolerance around the ray
must be specified. The tolerance is expressed as a fraction of the rendering window size. (Render-
ing window size is measured across the window diagonal.) Points must lie within this tolerance to
be picked.
The object vtkCellPicker intersects the ray with the cells defining each vtkProp3D, and
returns the point of intersection, as well as the vtkProp3D that the cell belongs to. If you are trying
to select a cell belonging to a particular vtkProp3D, vtkCellPicker is the object to use because it
performs surface (or cell) intersection. Unfortunately, vtkCellPicker is the slowest of the pickers
because of greater computational requirements.
The class vtkWorldPointPicker returns the ( x,y,z) coordinate value of a pick in the rendering
window. To determine this information, it combines the display (x,y) values with the z-buffer depth
values. Of all the pickers this is the fastest, but it cannot determine the actual cell, point or vtkProp
that is selected since it is not a subclass of vtkAbstractPropPicker . (Note: on some systems z-buffer
operations are inoperative and this object will not function properly.)
By default picking is performed with the class vtkPropPicker. This class uses hardware-
accelerated picking—so it is generally faster than software based picking. Unlike the other hard-
ware accelerated class (vtkWorldPointPicker), it returns the instance of vtkProp that was picked as
well as the ( x,y,z) world coordinate value
Figure8–39 summarizes the five concrete picking classes. Picking is built into the
vtkRenderWindowInteractor class using the “ p ” key (see “Introducing vtkRenderWindowInteractor”
on page68 ). By default a vtkPropPicker is created and used, but you are free to specify your own
picker type.
Examples
To conclude this section, we will examine how some of the dataset, cell, and point attribute opera-
tions are used. These operations tend to be used by class developers. You will not need to use them
if you build applications by constructing visualization pipelines with existing filters.
Find Free Edges. In our first example we will take a peek inside the filter
vtkLinearExtrusionFilter . This filter implements the following modelling operation. Given a polyg-
onal mesh, extrude the mesh in a given direction, constructing a “skirt” or “walls” from the free
edges. If the polygonal example is a single square, the result of this operation is a cube. Or, if the
polygonal data consists of a single line, the result of the operation is a quadrilateral. A point will
generate a line as shown in Figure8–40 (a).
310 Advanced Data Representation
(x,y,z)
(x,y,z)
Assembly Path
Figure 8–39 Summary of picking operations. The top three pick classes (a)-(c) use
software ray casting. The bottom two pick classes (d)-(e) use hardware acceleration.
Recall that free edges are edges used by only one polygon. We can determine this information
using the dataset topology operation GetCellEdgeNeigbors() . We use Equation8-25 and the two
points defining the edge of the polygon to determine the adjacency set (i.e., the polygons sharing
this edge). If no other polygon uses this edge, then the edge is extruded to generate a triangle strip.
The C++ pseudo code is as follows.
8.11 Putting It All Together 311
This same approach is used in the vtkRotationalExtrusionFilter ( Figure8–40 (b)). The difference
between these two functions is that the type of motion is rotational as compared to linear
(vtkLinearExtrusionFilter ). These two filters can be used to perform some nifty modelling opera-
tions. Linear extrusion can be used to create bar charts with arbitrary cross sections, or to sweep out
three-dimensional fonts. The rotational extrusion filter can be used to create rotationally symmetric
objects such as bottles or wine glasses. Examples of these techniques are shown in Figure8–41 .
Find Cells. In this example we combine picking and a topological operation to select cells sharing
a common point. Specifically, we use vtkPointPicker and the topological dataset operation
GetPointCells() . Figure8–42 depicts this operation. We have also included a fragment of C++ code
implementing this procedure. Note that this procedure will work for any dataset type, even if the
geometry is implicitly defined (e.g., vtkImageData ).
The most difficult part of this procedure is the picking process. The selection point must be
specified in pixel coordinates. The vtkPointPicker converts these coordinates into world and then
dataset coordinates using the renderer in which the pick occurred. (The renderer uses the transfor-
mation matrix of its active camera to perform coordinate transformation.)
The picking process is conveniently managed in vtkRenderWindowInteractor . This object
allows the specification of functions to execute just before picking and just after picking (i.e.,
“AddObserver StartPickEvent” and “AddObserver EndPickEvent” ). Using this facility we can
define a postpicking function to retrieve the point id and then execute the GetPointCells() opera-
tion. This process is shown in Figure8–42 .
312 Advanced Data Representation
(b) Rotationally symmetric objects (c) Rotation in combination with linear dis-
(bottle.tcl ). placement and radius variation
(spring.tcl ).
Point Probe. In this example we will show how to build a point probe using the dataset and cell
operations described in this chapter. A point probe is defined as follows. Given a (x,y,z) point coor-
dinate, find the cell coordinates (i.e., cell id, subcell id, and parametric coordinates) and the interpo-
lation weights. Once the interpolation weights are found, we can then compute local data values at
(x,y,z) .
The point probe is implemented using the dataset operation FindCell() . This method requires
a point specified in global coordinates (our (x,y,z) value) and a tolerance. The tolerance is often nec-
essary because of numerical precision or when picking near the surface of 3D cells, or on 0D, 1D,
and 2D cells. The FindCell() operation returns the information we require, plus the interpolation
weights of the cell containing our point probe. To determine the data value at our probe point, we
need to retrieve the data values on the cell points. We can then use the interpolation functions of
Equation8-4 to determine the probe scalar value.
Figure8–43 depicts this process and includes C++ code. In the example we use the combus-
tor dataset with the objects vtkCursor3D , vtkProbeFilter , and vtkGlyph3D . The purpose of the cur-
sor is to control the position of the probe point. The class vtkProbeFilter performs the probing
8.11 Putting It All Together 313
sphereActor->SetPosition(picker->GetPickPosition());
if ( picker->GetPointId() >= 0 )
{
cout << “Point id: “ << picker->GetPointId() << “\n”;
cellsActor->VisibilityOn();
plateActor->VisibilityOff();
cells->Initialize();
cells->Allocate(100);
cells->SetPoints(plateOutput->GetPoints());
plateOutput->GetPointCells(picker->GetPointId(), cellIds);
for (i=0; i < cellIds->GetNumberOfIds(); i++)
{
cellId = cellIds->GetId(i);
plateOutput->GetCellPoints(cellId, ptIds);
cells->InsertNextCell(plateOutput->GetCellType(cellId), ptIds);
}
}
else
{
cellsActor->VisibilityOff();
plateActor->VisibilityOn();
}
renWin->Render();
Figure 8–42 Selecting group of cells sharing a common point. (a) Original data. (b) Selected
cells sharing point on corner. Cells shrunk for clarity. The small sphere indicates the selected
point. (c) C++ code fragment in pick routine.
314 Advanced Data Representation
vtkPLOT3DReader vtkStructuredGridOutlineFilter
vtkCursor3D
vtkProbeFilter
vtkConeSource
vtkGlyph3D
//
// Loop over all input points, interpolating source data
//
for (ptId=0; ptId < numPts; ptId++)
{
// Get the xyz coordinate of the point in the input dataset
x = input->GetPoint(ptId);
Figure 8–43 Creating a point probe. Visualization network shown in diagram above. C++ code
shows inner loop of vtkProbeFilter and resulting image for combustor data ( probe.cxx ).
operation just described. (This filter has been generalized so that it can handle more than one input
point.) vtkGlyph3D is used to place an oriented, scaled cone at the cursor focal point. This gives us
visual feedback about the scalar and vector quantities at the probe. Of course, we can extract
numeric values and display them to the user if this is important.
Three important visualization coordinate systems are the world, dataset, and structured coordinate
systems. The world coordinate system is an x-y-z Cartesian three-dimensional space. The dataset
8.13 Bibliographic Notes 315
coordinate system consists of a cell id, subcell id, and parametric coordinates. The structured coor-
dinate system consists of (i,j,k) integer indices into a rectangular topological domain.
Visualization data is generally in discrete form. Interpolation functions are used to obtain data
at points between the known data values. Interpolation functions vary depending on the particular
cell type. The form of the interpolation functions are weighting values located at each of the cells
points. The interpolations functions form the basis for conversion from dataset to global coordi-
nates and vice versa. The interpolation functions also are used to compute data derivatives.
Topological operators provide information about the topology of a cell or dataset. Obtaining
neighboring cells to a particular cell is an important visualization operation. This operation can be
used to determine whether cell boundaries are on the boundary of a dataset or to traverse datasets
on a cell-by-cell basis.
Because of the inherent regularity of image datasets, operations can be efficiently imple-
mented compared to other dataset types. These operations include coordinate transformation, deriv-
ative computation, topological query, and searching.
8.14 References
[Baumgart74]
B. G. Baumgart. “Geometric Modeling for Computer Vision.” Ph.D. thesis, Stanford University,
Palo Alto, CA, 1974.
316 Advanced Data Representation
[Bentley75]
J. L. Bentley. “Multidimensional Binary Search Trees Used for Associative Search.” Communi-
cations of the ACM . 18(9):509–516, 1975.
[Conte72]
S. D. Conte and C. de Boor. Elementary Numerical Analysis . McGraw-Hill Book Company, 1972.
[Cook89]
R. D. Cook, D. S. Malkus, and M. E. Plesha. Concepts and Applications of Finite Element Anal-
ysis. John Wiley and Sons, New York, 1989.
[Gallagher75]
R. H. Gallagher. Finite Element Analysis: Fundamentals. Prentice Hall, Upper Saddle River, NJ,
1975.
[Meagher82]
D. J. Meagher. “Efficient Synthetic Image Generation of Arbitrary 3D Objects.” In Proceedings
of the IEEE Conference on Pattern Recognition and Image Processing . pp. 473–478, 1982.
[Quinlan94]
S. Quinlan. “Efficient Distance Computation Between Non-Convex Objects.” In Proceedings of
IEEE International Conference on Robotics and Automation . 1994.
[Samet90]
H. Samet. Design and Analysis of Spatial Data Structures . Addison-Wesley, Reading, MA, 1990.
[Schroeder06]
W. J. Schroeder, F. Bertel, M. Malaterre, D. Thompson, P. P. Pébay, R. O'Bara and S. Tendulkar.
“Methods and Framework for Visualizing Higher-Order Finite Elements.” IEEE Transactions on
Visualization and Computer Graphics , 12(4):446–460, July/August 2006.
[Shephard88]
M. S. Shephard and P. M. Finnigan. “Toward Automatic Model Generation.” State-of-the-Art Sur-
veys on Computational Mechanics . A. K. Noor and J. T. Oden, eds., ASME, pp. 335–366, 1989.
[Weiler86]
K. J. Weiler. Topological Structures for Geometric Modeling . Ph.D. thesis, Rensselaer Polytechnic
Institute, Troy, NY, May 1986.
[Weiler88]
K. J. Weiler. “The Radial-Edge Structure: A Topological Representation for Non-Manifold Geo-
metric Boundary Representations.” In M. J. Wozny, H. W. McLaughlin, and J. L. Encarnacao,
eds., Geometric Modeling for CAD Applications . pp. 3–36, North Holland, 1988.
[Williams83]
L. Williams. “Pyramidal Parametrics.” Computer Graphics (SIGGRAPH ’83) . 17(3):1–11, 1983.
[Zienkiewicz87]
O. C. Zienkiewicz and R. L. Taylor. The Finite Element Method — Vol. 1 . McGraw Hill Book Co.,
NY, 4th ed., 1987.
8.15 Exercises
8.1 ´ origin
Given a volume of dimensions with
51015 ´ (1.0, 2.0,3.0) and voxel spacing (0.5,
0.5, 1.0).
a) Compute minimum point position.
8.15 Exercises 317
(5,4,3)
(1,2,3) (1,1,0)
(0,0,0) (2,0,0)
(0,0,0) (0,0,0)
(a) (b) (c)
4 6 7
3 9
B
1 A 10
5
2 11
8
(d) (e)
8.2 Compute global coordinates and interpolation weights for the points specified in dataset
coordinates (refer to Figure8–44 (a-d)).
a) Line with . r0.5
=
b) Triangle with . rs, = ()0.250.33
,
,,
c) Voxel with . rst = ()0.250.330.5
,,
8.4 Given the line shown in Figure8–44 (a), if scalar data values are , ()s 0, s 1 = ()0.00.25
,
,,
what are the derivatives in the directions?
xyz
8.5 Refer to Figure8–44 (d) and let the numbers indicate cell ids and the letters indicate point ids.
a) List the cells using point A.
b) List the cells using point B.
()AB
c) List cells using edge . How, does this list correspond to your
answers in parts a) and b) above?
318 Advanced Data Representation
Advanced Algorithms
An isocontour of a tri-quadratic
Lagrange-interpolant. Image courtesy
D. Thompson and P. Pébay Sandia
National Labs.
Dividing Cubes
Dividing cubes is a contouring algorithm similar to marching cubes [Cline88] . Unlike marching
cubes, dividing cubes generates point primitives as compared to triangles (3D) or lines (2D). If the
number of points on the contour surface is large, the rendered appearance of the contour surface
appears “solid.” To achieve this solid appearance, the density of the points must be at or greater
320 Advanced Algorithms
Contour
line
Contour surface
Figure 9–1 Overview of the dividing cubes algorithm. Voxels through which the contour
passes are subdivided into subvoxels at less than screen resolution. If the contour passes
through a subvoxel, a center point is generated.
than screen resolution. (Also, the points must be rendered using the standard lighting and shading
equations used in surface rendering.)
The motivation for dividing cubes is that rendering points is much faster than rendering poly-
gons. This varies depending upon rendering hardware/software. Special purpose hardware has been
developed to render shaded points at high speed. In other systems, greater attention has been placed
on polygon rendering, and the rendering speed differences are not so great. Also, certain geometric
operations such as clipping and merging data are simple operations with points. Comparable opera-
tions with polygons are much more difficult to implement.
One disadvantage of creating contours with dense point clouds is that magnification of the
surface (via camera zooming, for example) reveals the disconnected nature of the surface. Thus, the
point set must be constructed for maximum zoom, or constructed dynamically based on the relative
relationship between the camera and contour.
Although dividing cubes was originally developed for volume datasets, it is possible to adapt
the algorithm to other dataset types by subdividing in parametric coordinates. Our presentation
assumes that we are working with volumes.
Figure9–1 provides an overview of the dividing cubes algorithm. Like other contouring
algorithms, we first choose a contour value. We begin by visiting each voxel and select those
through which the isosurface passes. (The isosurface passes through a voxel when there are scalar
values both above and below the contour value.) We also compute the gradient at each voxel point
for use in computing point normals.
9.1 Scalar Algorithms 321
Contour
line
Contour surface
Figure 9–2 Recursive dividing cubes algorithm. Top half of figure shows algorithm
depicted in two dimensions. Lower half depicts algorithm in three dimensions.
After selecting a voxel that the isosurface passes through, the voxel is subdivided into a regu-
n 1 ´ n 2 ´ nThe
lar grid of subvoxels. 3 number of divisions is controlled by the width of a voxel
w i in combination with screen resolution R. The screen resolution is defined as the distance
between adjacent pixels in world coordinates. We can express the number of divisions along n i the
coordinate axes asx i
wi
n i = ----- (9-1)
R
where the quotient is rounded up to the nearest integer. The scalar values at the subpoints are gener-
ated using the interpolation functions for a voxel (see Figure8–10 ). Then we determine whether
the contour passes through each subvoxel. If it does, we simply generate a point at the center of the
subvoxel and compute its normal using the standard interpolation functions.
An interesting variation on this algorithm is a recursive implementation as shown in
Figure9–2 . Instead of subdividing the voxel directly (i.e., procedurally) into a regular grid we
recursively divide the voxel (similar to octree decomposition). The voxel is subdivided regularly
creating eight subvoxels and 19 new points (12 midedge points, 6 midface points, and 1 midvoxel
point). The scalar values at the new points are interpolated from the original voxel using the tri-
linear interpolation functions. The process repeats for each subvoxel if the isosurface passes
through it. This process continues until the size of the subvoxel is less than or equal to screen reso-
lution. In this case, a point is generated at the center of the subvoxel. The collection of all such
points composes the dividing cubes’ isosurface.
322 Advanced Algorithms
Figure 9–3 Examples of dividing cubes isosurface. The left image consists of 50,078
points, and the right image consists of 2,506,989 points.
The advantage of the recursive implementation is that the subdivision process terminates pre-
maturely in those regions of the voxel where the contour cannot pass. On the other hand, the recur-
sive subdivision requires that the voxel subdivision occurs in powers of two. This can generate far
more points than the procedural implementation.
Figure9–3 shows two examples of dividing cubes isosurfaces. The contour surface on the
left consists of 50,078 points. Because the points are not generated at display resolution, it is possi-
ble to see through the contour surface. The second contour surface on the right is composed of
2,506,989 points. The points are generated at display resolution, and as a result the contour surface
appears solid.
As Figure9–1 and Figure9–2 show, the points generated by dividing cubes do not lie
exactly on the contour surface. We can determine the maximum error by examining the size of the
terminal subvoxels. Assume that a terminal subvoxel is a cube, and that the length of the side of the
cube is given by l. Then the maximum error is half the length of the cube diagonal, or . l32 ¤
Carpet Plots
A common data form is a 2D image dataset with associated scalar data. Carpet plots can visualize
data in this form. A carpet plot is created by warping a 2D surface in the direction of the surface
normal (or possibly some user-defined direction). The amount of warping is controlled by the sca-
lar value, possibly in combination with a scale factor. Carpet plots are similar to the vector dis-
placement plots (see “Displacement Plots ” on page175 ).
Although carpet plots are typically applied to image data, they can be used to visualize
datasets composed of 2D structured grids or 2D unstructured grids. In their basic form carpet plots
can be used to visualize only three variables: two surface position coordinates and a scalar value.
However, it is common to introduce another variable by using color mapping on the surface.
9.1 Scalar Algorithms 323
Figure 9–4 Carpet plots. (a) Visualization of an exponential cosine function. Function
values are indicated by surface displacement. Colors indicate derivative values ( exp-
Cos.cxx ). (b) Carpet plot of combustor flow energy in a structured grid. Colors and
plane displacement represent energy values ( warpComb.tcl ).
Figure9–4 illustrates application of carpet plots. Figure9–4 (a) shows the exponential cosine
function centered at the origin with points located at radius r
–r
Fr() = e cos ()10r (9-2)
The function values are used to warp the surface while the function derivatives are used to color it.
Figure9–4 (b) shows a carpet plot that visualizes flow energy in a structured grid. Both dis-
placement and color are used to show the energy values. Although this figure is similar to
Figure6–14 (b) there are some important differences. Figure6–14 (b) displays vector data whereas
Figure9–4 (b) displays scalar data. Figure9–4 (b) deforms the surface in the direction of surface
normal (or possibly a user-defined direction). The vector data (i.e., vector orientation) controls the
direction of deformation in Figure6–14 (b).
Clipping is a common graphics operation that limits the extent of a polygon so that it does not lie
outside the view frustrum (see “Cameras ” on page43 ). Figure9–5 shows a triangle before and
after clipping with an infinite plane. The clip operation transforms a polygon into a polygon. Clip-
ping can also be a powerful modeling tool. Clipping part of a structure can reveal internal details of
the surface or other parts contained within the surface. Objects can be split into pieces and the
pieces can be individually moved and controlled.
We can do clipping with arbitrary implicit functions using a variation of the “marching”
primitives discussed in “Contouring ” on page166 . We illustrate the technique for triangles.
Recall that marching triangles transforms triangles into lines that approximate a scalar value
called the isovalue. This is accomplished using the inside/outside relationship that each vertex has
324 Advanced Algorithms
Clip
Figure 9–5 Clipping a triangle produces a polygon. The dark line represents an infinite plane.
Cut
with respect to some scalar value. For our purposes here, we use a scalar value that represents the
signed distance of the triangle vertex to a plane. This infinite plane, described by an implicit func-
() ,, space
tion of the form , partitions
Fxyz = ninto
x xn+
twoy infinite
yn+0 z zdhalf
– =
spaces. All points with negative scalar values lie on one side of the plane and all with positive val-
ues lie on the other side. Figure9–6 shows a finite plane represented by a grid of triangles. The
thick line shows the infinite plane defined by F(x,y,z) = x + y + z - c = 0. The cut algorithm
described in “Cutting ” on page191 creates a set of lines using the contour operations specific to
each cell primitive. In this example, the triangle’s contour operator extracts lines that lie on the
intersection of the infinite plane and the triangles that comprise the finite plane. The contour opera-
tion for a triangle uses the eight cases shown in Figure9–7 to contour or “cut” each triangle appro-
priately.
Clipping transforms polygons into polygons. We do clipping with a modified case table for
the triangle that outputs polygons shown in Figure9–8 . In VTK, each polygonal data cell has a dif-
ferent case table to define the clip operation. Applying the clip algorithm to the polygonal data in
Figure9–9 using the same scalar field generated with a plane equation produces a new set of trian-
gles.
Formulating clipping using scalar fields permits more sophisticated operations. Clipping can
use scalar data that is computed or scalar data that is part of a polygonal dataset’s point attributes.
9.1 Scalar Algorithms 325
Figure 9–7 The eight cases for cutting (contouring) a triangle. Black dots show trian-
gle vertices that are “inside” the scalar cutting region. Solid lines show the output of the
cutting operation.
Figure 9–8 The eight cases for clipping a triangle. Black dots show triangle vertices
that are “inside” the scalar clipping region. Shaded regions show the output of the clip
operation.
Clip
Figure9–10 shows a scanned image that is first converted to a quadrilateral mesh with vertex sca-
lar values set to the scanned image intensity. Clipping this quadrilateral mesh with a value equal to
1/2 the maximum intensity of the scanned image produces a polygonal model show in Figure9–10 .
326 Advanced Algorithms
Clip
Figure 9–10 A scanned image clipped with a scalar value of 1/2 its maximum intensity
produces a mixture of quadrilaterals and triangles ( createBFont.tcl ).
In Chapter Chapter 6 we showed how to create simple vector glyphs and how to integrate particles
through a vector field to create streamlines. In this section we extend these concepts to create
streamribbons and streampolygons. In addition, we introduce the concept of vector field topology,
and show how to characterize a vector field using topological constructs.
Streamlines depict particle paths in a vector field. By coloring these lines, or creating local glyphs
(such as dashed lines or oriented cones), we can represent additional scalar and temporal informa-
tion. However, these techniques can convey only elementary information about the vector field.
Local information (e.g., flow rotation or derivatives) and global information (e.g., structure of a
field such as vortex tubes) is not represented. Streamribbons and streamsurfaces are two techniques
used to represent local and global information.
A natural extension of the streamline technique widens the line to create a ribbon. The ribbon
can be constructed by generating two adjacent streamlines and then bridging the lines with a polyg-
onal mesh. This technique works well as long as the streamlines remain relatively close to one
another. If separation occurs, so that the streamlines diverge, the resulting ribbon will not accu-
rately represent the flow, because we expect the surface of the ribbon to be everywhere tangent to
the vector field (i.e., definition of streamline). The ruled surface connecting two widely separated
streamlines does not generally satisfy this requirement.
The streamribbon provides information about important flow parameters: the vector vorticity
and flow divergence. Vorticity w is the measure of rotation of the vector field, expressed as a vector
quantity: a direction (axis of rotation) and magnitude (amount of rotation). Streamwise vorticity W
9.2 Vector Algorithms 327
v×w
W = ------------- (9-3)
v w
The amount of twisting of the streamribbon approximates the streamwise vorticity. Flow diver-
gence is a measure of the “spread” of the flow. The changing width of the streamribbon is propor-
tional to the cross-flow divergence of the flow.
A streamsurface is a collection of an infinite number of streamlines passing through a base
curve. The base curve, or rake, defines the starting points for the streamlines. If the base curve is
closed (e.g., a circle) the surface is closed and a streamtube results. Thus, streamribbons are spe-
cialized types of streamsurfaces with a narrow width compared to length.
Compared to vector icons or streamlines, streamsurfaces provide additional information
about the structure of the vector field. Any point on the streamsurface is tangent to the velocity vec-
tor. Consequently, taking an example from fluid flow, no fluid can pass through the surface.
Streamtubes are then representations of constant mass flux. Streamsurfaces show vector field struc-
ture better than streamlines or vector glyphs because they do not require visual interpolation across
icons.
Streamsurfaces can be computed by generating a set of streamlines from a user-specified
rake. A polygonal mesh is then constructed by connecting adjacent streamlines. One difficulty with
this approach is that local vector field divergence can cause streamlines to separate. Separation can
introduce large errors into the surface, or possibly cause self-intersection, which is not physically
possible.
Another approach to computing streamsurfaces has been taken by Hultquist [Hultquist92] .
The streamsurface is a collection of streamribbons connected along their edges. In this approach,
the computation of the streamlines and tiling of the streamsurface is carried out concurrently. This
allows streamlines to be added or removed as the flow separates or converges. The tiling can also
be controlled to prevent the generation of long, skinny triangles. The surface may also be “torn”,
i.e., ribbons separated, if the divergence of the flow becomes too high.
Stream Polygon
The techniques described so far provide approximate measures of vector field quantities such as
streamwise vorticity and divergence. However, vector fields contain more information than these
techniques can convey. As a result, other techniques have been devised to visualize this informa-
tion. One such technique is the stream polygon [Schroeder91] , which serves as the basis for a num-
ber of advanced vector and tensor visualization methods. The stream polygon is used to visualize
local properties of strain, displacement, and rotation. We begin by describing the effects of a vector
field on the local state of strain.
Nonuniform vector fields give rise to local deformation in the region where they occur. If the
vector field is displacement in a physical medium such as a fluid or a solid, the deformation con-
sists of local strain (i.e., local distortion) and rigid body motion. To mathematically describe the
deformation, we examine a 3D vector at avuvw = () ,, point . Using a
specified = () ,,
xxyz
first order Taylor’s series expansion about , we x can express the local deformation as e ij
328 Advanced Algorithms
e ij = e ij + w ij (9-4)
¶u1 ¶u ¶v 1 æö¶u ¶w
---æö + --- +
¶x 2 èø¶ y ¶ x 2 èø¶ z ¶ x
1 æö¶u ¶v ¶v1 ¶v ¶w
e ij = ---èø + ---æö + (9-5)
2 ¶y ¶x ¶y 2 èø¶ z ¶ y
1 æö¶u ¶w 1 æö¶v ¶w ¶w
---èø + --- +
2 ¶ z ¶ x 2 èø¶ z ¶ y ¶z
The terms on the diagonal of are e ijthe normal components of strain. The off-diagonal terms are
the shear strain. The local rigid-body rotation is given by
1 æö¶u ¶v 1 æö¶u ¶w
0 ---èø – --- –
2 ¶ y ¶ x 2 èø¶ z ¶ x
w ij = 1---æö¶v – ¶u 0 1---æö¶v – ¶w (9-6)
2 èø¶ x ¶ y 2 èø¶ z ¶ y
1---æö¶w – ¶u 1---æö¶w – ¶v 0
2 èø¶ x ¶ z 2 èø¶ y ¶ z
¶w ¶v
–
¶y ¶z
w = ¶u – ¶w (9-8)
¶ z ¶x
¶v ¶u
–
¶x ¶y
For the reader unfamiliar with tensor notation, this presentation is certainly less than complete.
However, the matrices in Equation9-5 and Equation9-6 directly translate into visual form, which
9.2 Vector Algorithms 329
Figure 9–11 Components of local deformation due to vector field. Dotted line shows
initially undeformed object.
will help clarify the concepts presented here. Referring to Figure9–11 , the normal strain, shear
strain, and rigid body motion create distinct deformation modes. These modes combine to produce
the total deformation. Modes of normal strain cause compression or extension in the direction per-
pendicular to a surface, while shear strains cause angular distortions. These strains combined with
rigid body rotation around an axis yield the total strain at a point.
The essence of the stream polygon technique is to show these modes of deformation. A regu-
lar n-sided polygon ( Figure9–12 ) is placed into a vector field at a specified point and then
deformed according to the local strain. The components of strain may be shown separately or in
combination. The orientation of the normal of the polygon is arbitrary. However, it is convenient to
align the normal with the local vector. Then the rigid body rotation about the vector is the stream-
wise vorticity, and the effects of normal and shear strain are in the plane perpendicular to a stream-
line passing through the point.
The stream polygon offers other interesting possibilities. The stream polygon may be swept
along a trajectory, typically a streamline, to generate tubes. The radius of the tube r can be modified
according to some scalar function. One application is to visualize fluid flow. In incompressible
flow with no shear, the radius of the tube can vary according to the scalar function vector magni-
tude. Then the equation
v min
rv() = r max -------------- (9-9)
v
represents an area of constant mass flow. As a result, the tube will thicken as the flow slows and
narrow as the velocity increases. Each of the n sides of the tube can be colored with a different sca-
lar function, although for visual clarity, at most, one or two functions should be used.
330 Advanced Algorithms
y’
v
x
x’
r
Figure 9–12 The stream polygon. (a) Planar view. (b) Aligned with vector. (c) Aligned
along streamline. (d) Sweeping polygon to form tube ( officeTube.tcl) .
The streamtubes generated by the streampolygon and the streamtubes we described in the
previous section are not the same. The streampolygon does not necessarily lie along a streamline. If
it does, the streampolygon represents information at a point, while the streamtube is an approxima-
tion constructed from multiple streamlines. Also, the radial variation in the tubes constructed from
streampolygon sweeps do not necessarily relate to mass flow since the radius in a streampolygon
can be tied to an arbitrary scalar variable.
This is because at the critical point the velocity is zero, and the vector field can be approximated by
a first-order expansion of partial derivatives [Helman91]
¶u ¶u ¶u
u» dx + dy + dz
¶x ¶y ¶z
¶v ¶v ¶v (9-10)
v» dx + dy + dz
¶x ¶y ¶z
¶w ¶w ¶w
w» dx + dy + dz
¶x ¶y ¶z
¶u ¶u ¶u
¶x ¶ y ¶z
uJx
= with
d J = ¶v ¶v ¶v (9-11)
¶x ¶ y ¶z
¶w ¶w ¶w
¶ x ¶y ¶ z
and is referred to as the Jacobian. The behavior of the vector field in the vicinity of a critical point
is characterized by the eigenvalues of . The
J eigenvalues consist of an imaginary and real compo-
nent. The imaginary component describes the rotation of the vector field around the critical point,
while the real part describes the relative attraction or repulsion of the vector field to the critical
point. In two dimensions the critical points are as shown in Figure9–13 .
A number of visualization techniques have been developed to construct vector field topology
from an analysis of critical points. These techniques provide a global understanding of the field,
including points of attachment and detachment and field vortices . Using a fluid flow analogy,
points of attachment and detachment occur on the surface of an object where the tangential compo-
nent of the vector field goes to zero, and the flow is perpendicular to the surface. Thus, streamlines
will begin or end at these points. There is no common definition for a vortex, but generally speak-
ing, vortices are regions of relatively concentrated vorticity (e.g., flow rotation). The study of vorti-
ces is important because they represent areas of energy loss, or can have significant impact on
downstream flow conditions (e.g., trailing vortices behind large aircraft).
One useful visualization technique creates vector field skeletons that divide the vector field
into separate regions. Within each region, the vector field is topologically equivalent to uniform
flow. These skeletons are created by locating critical points, and then connecting the critical points
with streamlines. In 3D vector field analysis this technique can be applied to the surface of objects
to locate lines of flow separation and attachment and other important flow features. Also, in general
3D flow, the regions of uniform flow are separated by surfaces, and creation of 3D flow skeletons is
a current research topic.
Vortex visualization is another area of current research. One technique computes the helicity-
density
332 Advanced Algorithms
Figure 9–13 Critical points in two dimensions. The real part of the eigenvalues ( R 1,
R2 ) of the matrix of first derivatives control the attraction or repulsion of the vector field.
The imaginary part of the eigenvalues ( I1 , I2 ) controls the rotation.
This is a scalar function of the vector dot product between the vorticity and the local vector. Large
positive values of result
H d in right-handed vortices, while large negative values indicate left-
handed vortices. Helicity-density can be conveniently shown using isosurfaces, which gives an
indication for the location and structure of a vortex.
v i = l i e i , with i123
= ,, (9-13)
9.4 Modelling Algorithms 333
l1
l3
l2
Figure 9–14 Creation of hyperstreamlines. An ellipse is swept along a streamline of the eigenfield.
Major/minor axes of the ellipse are controlled by the other two eigenvectors.
where ise i a unit vector in the direction of the eigenvalue, and are theleigenvalues.
i Thus, we
can decompose a real 33´ symmetric tensor field into three vector fields, each field defined by
one of the three eigenvectors described in Equation9-13 . We call these vector fields eigenfields ,
since they are derived from the eigenvectors of the tensor field.
Decomposition of the tensor field in this fashion provides additional insight into visualizing
33´ real symmetric tensors. We can directly use the vector field visualization techniques pre-
sented previously or use variations of them. One such technique is a novel extension of the stream-
polygon technique, the method of hyperstreamlines .
Hyperstreamlines
Hyperstreamlines are constructed by creating a streamline through one of the three eigenfields, and
then sweeping a geometric primitive along the streamline [Delmarcelle93] . Typically, an ellipse is
used as the geometric primitive, where the remaining two eigenvectors define the major and minor
axes of the ellipse ( Figure9–14 ). Sweeping the ellipse along the eigenfield streamline results in a
tubular shape. Another useful generating geometric primitive is a cross. The length and orientation
of the arms of the cross are controlled by two of the eigenvectors. Sweeping the cross results in a
helical shape since the eigenvectors (and therefore cross arms) will rotate in some tensor fields.
Figure9–15 shows an example of hyperstreamlines. The data is from a point load applied to
a semi-infinite domain. Compare this figure to Figure6–22 that used tensor ellipsoids to visualize
the same data. Notice that there is less clutter and more information available from the hyper-
streamline visualization.
Visualizing Geometry
One of the most common applications of visualization is to view geometry. We may have a geomet-
ric representation of a part or complex assembly (perhaps designed on a CAD system) and want to
view the part or assembly before it is manufactured. While viewing geometry is better addressed in
334 Advanced Algorithms
a text on computer graphics, often there is dataset structure we wish to view in the same way. For
example, we may want to see data mapped on a particular portion of the dataset, or view the struc-
ture of the dataset itself (e.g., view a finite element mesh).
Three-dimensional datasets have a surface and interior. Typically we want to visualize the
surface of the dataset or perhaps a portion of the interior. (Note: volume rendering is a different
matter — see “Volume Rendering ” on page218 .) To visualize the dataset we must extract a portion
of the dataset topology/geometry (and associated data) as some form of surface primitives such as
polygons. If the surface of the dataset is opaque, we may also wish to eliminate occluded interior
detail.
We have already seen how structured datasets, such as image data or structured grids, have a
natural i-j-k coordinate system that allow extraction of points, lines, and planes from the interior of
the dataset (see “Structured Coordinate System ” on page269 ). For example, to extract the fifth i-
()i m,,j m
plane from a structured grid of dimensions , we specify thekdata
m extents using
()440j
,,,,, () m – 1 0k () m – 1 (assuming zero-offset addressing).
More generally, we can extract boundary edges and faces from a dataset. A boundary edge is
an 1D cell type (e.g., line or polyline), or the edge of a 2D cell used by only that single cell. Simi-
larly, a boundary face is a 2D cell type (e.g., polygon, triangle strip) or the face of a 3D cell used by
only that single cell ( Figure9–16 ). We can obtain this information using the topological operators
of the previous chapter. Cells of dimensions two or less are extracted as is, while boundary edges
and faces are determined by counting the number of cell neighbors for a particular topological
boundary (i.e., edge or face neighbors). If there are no neighbors, the edge or face is a boundary
edge or face, and is extracted.
Using these techniques we can view the structure of our dataset. However, there are also situ-
ations where we want more control in the selection of the data. We call this data extraction .
Data Extraction
Often we want to extract portions of data from a dataset. This may be because we want to reduce
the size of the data, or because we are interested in visualizing only a portion of it.
9.4 Modelling Algorithms 335
Boundary edges
Interior face
Boundary faces
Interior edges
Figure 9–17 Subsampling data. (a) Structured data can be subsampled by choosing
every nth point. (b) Subsampling unstructured data requires local retriangulation.
Reducing dataset size is an important practical capability, because visualization data size can
be huge. By reducing data size, reductions in computation and memory requirements can be real-
ized. This results in better interactive response.
We also may need to reduce data size in order to visualize the important features of a large
dataset. This can be used to reduce image clutter and improve the effectiveness of the visualization.
Smaller data size also enables the visualization user to navigate through and inspect data more
quickly relative to larger datasets. Next we describe two techniques to extract data. One is based on
geometry extraction , and the other is based on data thresholding , or thresholding .
Geometry Extraction. Geometry extraction selects data based on geometric or topological charac-
teristics. A common extraction technique selects a set of points and cells that lie within a specified
range of ids. A typical example is selecting all cells having ids between 0–100, or all cells using
point ids 250–500. Finite element analysts use this method frequently to isolate the visualization to
just a few key regions.
Another useful technique called spatial extraction , selects dataset structure and associated
data attributes lying within a specified region in space. For example, a point and radius can be used
to select (or deselect) data within an enclosing sphere. Implicit functions are particularly useful
tools for describing these regions. Points that evaluate negative are inside the region, while points
outside the region evaluate positive; thus, cells whose points are all positive are outside the region,
and cells whose points are all negative are inside the region.
336 Advanced Algorithms
Subsampling ( Figure9–17 ) is a method that reduces data size by selecting a subset of the
original data. The subset is specified by choosing a parameter n, specifying that every nth data
point is to be extracted. For example, in structured datasets such as image data and structured grids,
selecting every nth point produces the results shown in Figure9–17 (a).
Subsampling modifies the topology of a dataset. When points or cells are not selected, this
leaves a topological “hole.” Dataset topology must be modified to fill the hole. In structured data,
this is simply a uniform selection across the structured i-j-k coordinates. In unstructured data
(Figure9–17 (b)), the hole must be filled in by using triangulation or other complex tessellation
schemes. Subsampling is not typically performed on unstructured data because of its inherent com-
plexity.
A related technique is data masking . In data masking we select every nth cell that at a mini-
mum leaves one or more topological “holes” in the dataset. Masking also may change the topology
of the dataset, since partial selections of cells from structured datasets can only be represented
using unstructured grids. Masking is typically used to improve interactive performance or to
quickly process portions of data.
Thresholding. Thresholding extracts portions of a dataset data based on attribute values. For
example, we may select all cells having a point with scalar value between (0,1) or all points having
a velocity magnitude greater than 1.0.
Scalar thresholding is easily implemented. The threshold is either a single value that scalar
values are greater than or less than, or a range of values. Cells or points whose associated scalar
values satisfy the threshold criteria can be extracted. Other dataset attribute types such as vectors,
normals, or tensors can be extracted in similar fashion by converting the type to a single scalar
value. For example, vectors can be extracted using vector magnitude, and tensors using matrix
determinate.
A problem with both geometry extraction and thresholding is that the approaches presented
thus far extract “atomic” pieces of data, that is, a complete cell. Sometimes the cell may lie across
the boundary of the threshold. In this case the cell must be clipped (see “Clipping With Scalar Fields ”
on page323 ) and only a portion of the cell is extracted.
Probing
Probing obtains dataset attributes by sampling one dataset (the input) with a set of points (the
probe) as shown in Figure9–18 (a). Probing is also called “resampling.” Examples include probing
an input dataset with a sequence of points along a line, on a plane, or in a volume. The result of the
probing is a new dataset (the output) with the topological and geometric structure of the probe
dataset, and point attributes interpolated from the input dataset. Once the probing operation is com-
pleted, the output dataset can be visualized with any of the appropriate techniques described in this
text.
Figure9–18 (b) illustrates the details of the probing process. For every point in the probe
dataset, the location in the input dataset (i.e., cell, subcell, and parametric coordinates) and interpo-
lation weights are determined. Then the data values from the cell are interpolated to the probe
9.4 Modelling Algorithms 337
Probe Geometry
r
Output
Interpolated Input Data
s
Attributes
Figure
Figure9–189–18Probing
Probing
data.
data.
TheThe
geometry
geometry
of one
of one
dataset
dataset
( ( Probe ) is)used
Probe is used
to extract
to extract
dataset
dataset
attributes
attributes
fromfrom
another
another dataset(Input
dataset (Input
). ).
point. Probe points that are outside the input dataset are assigned a nil (or appropriate) value. This
process repeats for all points in the probe dataset.
Probing can be used to reduce data or to view data in a particular fashion.
• Data is reduced when the probe operation is limited to a subregion of the input dataset, or the
number of probe points is less than the number of input points.
• Data can be viewed in a particular fashion by sampling on specially selected datasets. Using a
probe dataset consisting of a line enables x-y plotting along a line, or using a plane allows
surface color mapping or line contouring.
Probing must be used carefully or errors may be introduced. Under-sampling data in a region can
miss important high-frequency information or localized data variations. Oversampling data, while
not creating error, can give false confidence in the accuracy of the data. Thus the sampling fre-
quency should have a similar density as the input dataset, or if higher density, the visualization
should be carefully annotated as to the original data frequency.
One important application of probing converts irregular or unstructured data to structured
form using a volume of appropriate resolution as a probe to sample the unstructured data. This is
useful if we use volume rendering or other volume visualization techniques to view our data.
338 Advanced Algorithms
10
6 9 12
X
5 X X
2 11 X X
X 8 X
4
1 7
3
Select first triangle Extend strip
Representation:
X X (1,2,4,5,8,9,11,12)
(6,5,10,9)
(4,3,8,7)
X
X
Figure9–19 shows an example of three probes. The probes sample flow density in a struc-
tured grid. The output of the probes is passed through a contour filter to generate contour lines. As
this figure illustrates, we can be selective with the location and extent of the probe, allowing us to
focus on important regions in the data.
Triangle strips are compact representations of triangle polygons as described in “Triangle Strip ” on
page127 . Many rendering libraries include triangle strips as graphics primitives because they are a
high-performance alternative to general polygon rendering.
Visualization and graphics data is often represented with triangles. Marching cubes, for
example, generates thousands and potentially millions of triangles to represent an isosurface. To
achieve greater performance in our visualizations, we can convert triangle polygons into triangle
strips. Or, if data is represented using polygons, we can first triangulate the polygons and then cre-
ate triangle strips.
A simple method to generate triangle strips uses greedy gathering of triangles into a strip
(Figure9–20 ). The method proceeds as follows. An “unmarked” triangle is found to initialize the
strip — unmarked triangles are triangles that have not yet been gathered into a triangle strip. Start-
ing with the initial triangle, the strip may grow in one of three directions, corresponding to the three
edges of the triangle. We choose to grow the strip in the direction of the first unmarked neighbor tri-
angle we encounter. If there are no unmarked neighbors the triangle strip is complete; otherwise,
the strip is extended by adding triangles to the list that satisfy triangle strip topology. The strip is
grown until no unmarked neighbor can be found. Additional strips are then created using the same
9.4 Modelling Algorithms 339
Figure 9–21 Triangle strip examples. (a) Structured triangle mesh consisting of 134
strips each of 390 triangles ( stripF.tcl ). (b) Unstructured triangle mesh consisting of
2227 strips of average length 3.94, longest strip 101 triangles. Images are generated by
displaying every other triangle strip ( uStripeF.tcl ).
Connectivity
Intercell connectivity is a topological property of datasets. Cells are topologically connected when
they share boundary features such as points, edges, or faces ( Figure9–22 ). Connectivity is useful
in a number of modeling applications, particularly when we want to separate out “parts” of a
dataset.
One application of connectivity extracts a meaningful portion of an isosurface. If the isosur-
face is generated from measured data such as an MRI or CT scan, it likely contains “noise” or
unimportant anatomical structure. Using connectivity algorithms, we can separate out the part of
the isosurface that we desire, either by eliminating noise or undesirable anatomical structure.
Figure9–23 is an example where a 2D surface of interest (e.g., an isocontour) is extracted from a
noisy signal.
340 Advanced Algorithms
Desired surface
Connectivity
Noise or undesirable
structure
cubes algorithm for general datasets (which typically will not generate surface normals) and the
stereo lithography file format (does not support point normals). Figure9–24 (a) shows a model
defined from stereo-lithography format. The faceting of the model is clearly evident.
To address this situation we can compute surface normals from the polygonal mesh. A simple
approach follows. First, polygon normals are computed around a common point. These normals are
then averaged at the point, and the normal is renormalized (i.e., ) andn1
associated
= with the
point. This approach works well under two conditions.
1. The orientation of all polygons surrounding the point are consistent as shown in Figure9–
24 (b). A polygon is oriented consistently if the order of defining polygon points is consistent
with its edge neighbors. That is, if polygon p is defined by points (1,2,3), then the polygon
edge neighbor p23 must use the edge (2,3) in the direction (3,2). If not consistent, then the
average point normal may be zero or not accurately represent the orientation of the surface.
This is because the polygon normal is computed from a cross product of the edges formed by
its defining points.
2. The angular difference in surface normals between adjacent polygons is small. Otherwise,
sharp corners or edges will have a washed out appearance when rendered, resulting in an
unsatisfactory image ( Figure9–24 (c)).
To avoid these problems we adopt a more complex polygon normal generation algorithm. This
approach includes steps to insure that polygons are oriented consistently, and an edge-splitting
scheme that duplicates points across sharp edges.
To orient edges consistently we use a recursive neighbor traversal. An initial polygon is
selected and marked “consistent.” For each edge neighbor of the initial polygon, the ordering of the
neighbor polygon points is checked — if not consistent, the ordering is reversed. The neighbor
polygon is then marked “consistent.” This process repeats recursively for each edge neighbor until
all neighbors are marked “consistent”. In some cases there may be more than one connected sur-
face, so that the process may have to be repeated until all polygons are visited.
A similar traversal method splits sharp edges. A sharp edge is an edge shared by two poly-
gons whose normals vary by a user-specified feature angle . The feature angle between two poly-
gons is the angle between their normals ( Figure9–25 (a)). When sharp edges are encountered
during the recursive traversal, the points along the edge are duplicated, effectively disconnecting
the mesh along that edge ( Figure9–25 (b)). Then, when shared polygon normals are computed later
in the process, contributions to the average normal across sharp edges is prevented.
On some computers limitations on recursion depth may become a problem. Polygonal sur-
faces can consist of millions of polygons, resulting in large recursion depth. As a result, the depth
of recursion can be specified by the user. If recursion depth exceeds the specified value, the recur-
sion halts and the polygons on the boundary of the recursion become seeds to begin the process
again.
Figure9–24 (d) shows the result of the advanced normal generation technique with a feature
angle of 60 degrees. Sharp edges are well defined and curved areas lack the faceting evident in the
original model. The figure is shown with Gouraud shading.
342 Advanced Algorithms
Inconsistent
Reference ordering
polygon
Figure 9–24 Surface normal generation. (a) Faceted model without normals.
(b)Polygons must be consistently oriented to accurately compute normals. (c)Sharp edges
are poorly represented using shared normals as shown on the corners of this model. (d)
Normal generation with sharp edges split ( Normals.cxx ).
Decimation
Various data compression techniques have been developed in response to large data size. The
UNIX utilities compress/uncompress and the PC utility zip compress data files. The MPEG
compression algorithm compresses video sequences. These techniques may be loss-less, meaning
9.4 Modelling Algorithms 343
Feature edge
q Duplicated point
Figure 9–25 Computing feature angles (a) and splitting edges (b).
that no data is lost between the compression/decompression steps, or lossy, meaning that data is lost
during compression. The utilities compress/uncompress and zip are loss-less, while MPEG is
lossy.
In graphics, data compression techniques have been developed as well. The subsampling
methods we saw earlier in this chapter are an example of simple data compression techniques for
visualization data. Another emerging area of graphics data compression is polygon reduction tech-
niques.
Polygon reduction techniques reduce the number of polygons required to model an object.
The size of models, in terms of polygon count, has grown tremendously over the last few years.
This is because many models are created using digital measuring devices such as laser scanners or
satellites. These devices can generate data at tremendous rates. For example, a laser digitizer can
generate on the order of 500,000 triangles in a 15-second scan. Visualization algorithms such as
marching cubes also generate large numbers of polygons: one to three million triangles from a 512 3
volume is typical.
One polygon reduction technique is the decimation algorithm [Schroeder92a] . The goal of
the decimation algorithm is to reduce the total number of triangles in a triangle mesh, preserving
the original topology and forming a good approximation to the original geometry. A triangle mesh
is a special form of a polygonal mesh, where each polygon is a triangle. If need be, a polygon mesh
can be converted to a triangle mesh using standard polygon triangulation methods.
Decimation is related to the subsampling technique for unstructured meshes described in
Figure9–17 (b). The differences are that
Classify Vertex
Interior
Simple Complex Boundary Edge Corner
Evaluate Error
Distance to plane Distance to line
Triangulate
Recursive 3D Subdivide with
triangulation split planes
in the neighborhood of the point. The classification yields one of the five categories shown in the
figure: simple, boundary, complex, edge, and corner point. Based on this classification, the second
step uses a local error measure (i.e., the decimation criterion) to determine whether the point can be
deleted. If the criterion is satisfied, the third step deletes the point (along with associated triangles),
and triangulates the resulting hole. A more detailed description of each of these steps and example
applications follow.
Point Classification. The first step of the decimation algorithm characterizes the local geometry
and topology for a given point. The outcome of classification determines whether the vertex is a
potential candidate for deletion, and if it is, which criteria to use.
Each point may be assigned one of five possible classifications: simple, complex, boundary,
interior edge, or corner vertex. Examples of each type are shown in Figure9–26 .
A simple point is surrounded by a complete cycle of triangles, and each edge that uses the
point is used by exactly two triangles. If the edge is not used by two triangles, or if the point is used
by a triangle not in the cycle of triangles, then the point is complex . These are nonmanifold cases.
9.4 Modelling Algorithms 345
A point that is on the boundary of a mesh, that is, within a semicycle of triangles, is a bound-
ary point .
A simple point can be further classified as an interior edge or corner point . These classifica-
tions are based on the local mesh geometry. If the surface normal angle between two adjacent trian-
gles is greater than a specified feature angle , then a feature edge exists (see Figure9–25 (a)). When
a point is used by two feature edges, the point is an interior edge point. If one, three, or more feature
edges use the point, the point is a corner point .
Complex and corner vertices are not deleted from the triangle mesh; all other vertices become
candidates for deletion.
Decimation Criterion. Once we have a candidate point for deletion, we estimate the error that
would result by deleting the point and then replacing it (and its associated triangles) with another
triangulation. There are a number of possible error measures; but the simplest are based on distance
measures of local planarity or local colinearity ( Figure9–26 ).
In the local region surrounding a simple point, the mesh is considered nearly “flat,” since
there are by definition no feature edges. Hence, simple points use an error measure based on dis-
tance to plane. The plane passing through the local region can be computed either using a least-
squares plane or by computing an area-averaged plane.
Points classified as boundary or interior edge are considered to lay on an edge, and use a dis-
tance to edge error measure. That is, we compute the distance that the candidate point is from the
new edge formed during the triangulation process.
A point satisfies the decimation criterion d if its distance measure is less than d. The point can
then be deleted. All triangles using the point are deleted as well, leaving a “hole” in the mesh. This
hole is patched using a local triangulation process.
Triangulation. After deleting a point, the resulting hole must be retriangulated. Although the hole,
defined by a loop of edges, is topologically two dimensional, it is generally non-planar, and there-
fore general purpose 2D triangulation techniques cannot be used. Instead, we use a special recur-
sive 3D divide-and-conquer technique to triangulate the loop.
Triangulation proceeds as follows. An initial split plane is chosen to divide the loop in half
and create two subloops. If all the points in each subloop lie on opposite sides of the plane, then the
split is a valid one. In addition, an aspect ratio check insures that the loop is not too long and
skinny, thereby resulting in needle-like triangles. The aspect ratio is the ratio between the length of
the split line to the minimum distance of a point in the subloop to the split plane. If the candidate
split plane is not valid or does not satisfy the aspect ratio criterion, then another candidate split
plane is evaluated. Once a split plane is found, then the subdivision of each subloop continues
recursively until a subloop consists of three edges. In this case, the subloop generates a triangle and
halts the recursion.
Occasionally, triangulation fails because no split plane can be found. In this case, the candi-
date point is not deleted and the mesh is left in its original state. This poses no problem to the algo-
rithm and decimation continues by visiting the next point in the dataset.
Results. Typical compression rates for the decimation algorithm range from 2:1 to 100:1, with 10:1
a nominal figure for “large” (i.e., 10 5 triangles) datasets. The results vary greatly depending upon
the type of data. CAD models typically reduce the least because these models have many sharp
346 Advanced Algorithms
Figure 9–27 Examples of decimation algorithm. Triangle meshes are shown in wireframe.
edges and other detailed features, and the CAD modellers usually produce minimal triangulations.
Terrain data, especially if relatively flat regions are present, may reduce at rates of 100:1.
Figure9–27 shows two applications of decimation to laser digitized data and to a terrain
model of Honolulu, Hawaii. In both cases the reduction was on the order of 90 percent for a 10:1
compression ratio. Wireframe images are shown to accentuate the density of the polygonal meshes.
The left-hand image in each pair is the original data; the right-hand image is the decimated mesh.
9.4 Modelling Algorithms 347
Notice the gradations in the decimated mesh around features of high curvature. The advantage of
decimation, as compared to subsampling techniques, is that the mesh is adaptively modified to
retain more details in areas of high curvature.
Advanced Techniques. Polygon reduction is an active field of research. Many powerful algo-
rithms beyond the decimation algorithm have been presented (see “Bibliographic Notes ” on
page380 ). Although we cannot cover the field in its entirety in this section, there are two notable
trends worth addressing. First, progressive schemes [Hoppe96] allow incremental transmission and
reconstruction of triangle meshes — this is especially important for Web-based geometry visualiza-
tion. Second, recent algorithms modify the topology of the mesh [He96] [Popovic97] [Schroeder97] .
This feature is essential towards obtaining arbitrary levels of mesh reduction.
A progressive mesh is a series of triangle meshes Mi related by the operations
ˆ = M n ®®®®
()M M
n1–
¼ M
1
M
0
(9-14)
where M and M n represent the mesh at full resolution, and M0 is a simplified base mesh. The criti-
cal characteristic of progressive meshes is that is possible to choose the mesh operations in such a
way to make them invertible. Then the operations can be applied in reverse order (starting with the
base mesh M 0)
0 1 n1– n
M ®®®®
M ¼ M M (9-15)
to obtain a mesh of desired reduction level (assuming that the reduction level is less than the base
mesh M 0).
One such invertible operator is an edge collapse and its inverse is the edge split shown in
Figure9–28 (a). Each collapse of an interior mesh edge results in the elimination of two triangles
(or one triangle if the collapsed vertex is on a boundary). The operation is represented by five val-
ues
where isv sthe vertex to collapse/split, is thev tvertex being collapsed to / split from, and and vl
v r are two additional vertices to the left and right of the split edge. These two vertices in conjunc-
tion with vand
s define
v t the two triangles deleted or added. A represents vertex attribute informa-
tion, which at a minimum contains the coordinates ofx the collapsed / split vertex . (Note: v s in the
context of the decimation algorithm, the edge collapse operator replaces the recursive triangulation
process.)
While progressive meshes allow us to compactly store and transmit triangle meshes, the
problem remains that the size of the base mesh is often larger than desired reduction level. Since in
some applications we wish to realize any given level, we want the base mesh to contain no triangles
ˆ =M n n1– 1 0
()M ®®®®
M ¼ M ()M = MV
() , Æ (9-17)
(some vertices are necessary to initiate the edge split operations). To address this problem, the
invertible edge collapse/split operator — which is topology preserving — is extended with a vertex
split/merge operator. The vertex split/merge operator modifies the topology of the mesh and allows
arbitrary levels of reduction.
348 Advanced Algorithms
Collapse
vr vr
vs Split
vt vt
vl
vl
(a) An edge collapse and split
Split
vr vr
vs
vt
vs Merge
vl
vl
(b) A vertex split and merge
(c) Vertex splits applied to various mesh features.Darker lines indicate feature edges.
Figure 9–28 Progressive mesh operators edge collapse/split and vertex split/merge.
(a) Original model (b) Shortly after splitting (c) Final model
2,624 triangles 157 triangles 4 triangles
vertices are split into separate manifold pieces. In any other type of vertex splitting occurs by arbi-
trarily separating the loop into two pieces. For example, if a simple vertex cannot be deleted
because a valid edge collapse is not available, the loop of triangles will be arbitrarily divided in half
(possibly in a recursive process).
Like the edge collapse/split, the vertex split/merge can also be represented as a compact oper-
ation. A vertex split/merge operation can be represented with four values
0.10
Relaxation Factor
0.05
0.01
25 50 100
Figure 9–30 Mesh smoothing applied to a semicylinder. Lower left image is the original
model. On the x-axis the number of smoothing iterations is modified. On the y-axis the relax-
ation factor is modified.
Mesh Smoothing
Mesh smoothing is a technique that adjusts the point coordinates of a dataset. The purpose of mesh
smoothing is to improve the appearance of a mesh, and/or improve the shape of dataset cells. Dur-
ing smoothing the topology of the dataset is not modified, only the geometry. Applications of mesh
smoothing include improving the appearance of isosurfaces, or as a modelling tool to remove sur-
9.4 Modelling Algorithms 351
p0
Figure 9–31 Mesh
V ij V ij smoothing. (a) Motion
of point. (b) Smoothing
pi pi a point on an edge.
Bold lines indicate
connectivity.
pj p1
(a) (b)
face noise. The appearance of models can be dramatically improved by applying mesh smoothing.
Figure9–30 is an example of smoothing applied to analytic surface (a semicylinder) with a random
surface distortion ( smoothCyl.tcl ).
A simple, yet effective technique is Laplacian smoothing. The Laplacian smoothing equation
for a point at
p iposition is given
x i by
where is x i1the
+ new coordinate position, and are the positions
xj of points “connected” topj
p i , and isl a user-specified weight. Geometrically this relation is depicted in Figure9–31 (a).
Here the vertex ispconnected
i to the surrounding points via edges.p j The equation expresses
that the new position isx i1 offset
+ from the original position plus the xaverage
i vector mul- V ij
tiplied by . l l
Typically, the factor is a small number (e.g., 0.01), and the process is executed
repeatedly (e.g., 50-100 iterations). Notice that the overall effect of smoothing is to reduce the high
frequency surface information. The algorithm will reduce surface curvature and tend to flatten the
surface.
Besides adjusting the number of iterations and smoothing factor, smoothing can be controlled
by modifying the connections between andp iits surrounding points . For example, pj if lies pi
along a fold or sharp edge in the mesh, we may want to only use the two edge end points to com-
pute the smoothing vector , limiting
Vij the motion of along pthe
i edge ( Figure9–31 (b)). We can
also anchor to p i prevent any motion. Anchoring is useful for points that are located on “corners”
or other special features such as nonmanifold attachments. One benefit of anchoring and control-
ling point connectivity is that we can limit the amount of shrinkage in the mesh. It also tends to pro-
duce better overall results. (In Figure9–30 the boundary points of the surface are constrained to
move along the boundary, while the points at sharp corners are anchored.)
Although Laplacian smoothing works well in most cases, there are applications of Laplacian
smoothing that can badly damage the mesh. Large numbers of smoothing iterations, or large
smoothing factors, can cause excessive shrinkage and surface distortion. Some objects, like spheres
or the cylinder shown in Figure9–30 , will lose volume with each iteration, and can even shrink to
a point. In rare cases it is possible for the mesh to pull itself “inside-out.” Situations like this occur
when the average vector moves across pi a mesh boundary, causing some of the attached triangles
to overlap or intersect.
Mesh smoothing is particularly useful when creating models that do not require high accu-
racy. As we have seen, smoothing modifies point coordinates and, therefore, surface geometry. Use
352 Advanced Algorithms
smoothing to improve the appearance of models, but characterize error carefully if you are going to
measure from a smoothed surface. Alternatively, you may want to design your own smoothing
algorithms that better fit the underlying data.
Consider moving an object (e.g., your hand) over some path (e.g., raise your hand). How can we
visualize this motion? The obvious answer is to form a time-animation sequence as the hand is
moved. But what if we wish to statically represent the motion as well as the space that is traversed
by the hand? Then we can use swept surfaces and swept volumes .
A swept volume is the volume of space occupied by an object as it moves through space
along an arbitrary trajectory. A swept surface is the surface of the swept volume. Together, swept
volumes and swept surfaces can statically represent the motion of objects.
Past efforts at creating swept surfaces and volumes have focused on analytical techniques.
The mathematical representation of various 3D geometric primitives (e.g., lines, polygons, splines)
was extended to include a fourth dimension of time (the path). Unfortunately, these approaches
have never been practically successful, partly due to mathematical complexity and partly due to
problem degeneracies.
Degeneracies occur when an n-dimensional object moves in such a way that its representa-
tion becomes (n-1) -dimensional. For example, moving a plane in the direction of its normal,
sweeps out a 3D “cubical” volume. Sweeping the plane in a direction perpendicular to its normal,
however, results in a degenerate condition, since the plane sweeps out a 2D “rectangle.”
Instead of creating swept surfaces analytically, numerical approximation techniques can be
used [Schroeder94] . Implicit modeling provides the basis for an effective technique to visualize
object motion via swept surfaces and volumes. The technique is immune to degeneracies and can
treat any geometric representation for which a distance function can be computed, such as the VTK
cell types.
The technique to generate swept surfaces and volumes using an implicit modeling approach
proceeds as follows. The geometric model, or part, and a path describing the parts motion, or sweep
trajectory ST , must be defined. Then we use the following steps as depicted in Figure9–32 .
1. Generate an implicit model from the part. This results in an implicit representation in the
form of a volume. We call this the implicit model . V I
2. Construct another volume, the workspace volume , that
V Wstrictly bounds as it moves
VI
along the path ST . Then sweep through
VI V W in small steps, , along Dx
by moving ST .
At each step, s, sample with
V I the workspace volume . We use
VW a boolean union opera-
tion to perform the sampling.
3. Extract isosurface, or offset surface(s) from using
V W a contouring algorithm such as
marching cubes.
4. Step 3 may create multiple connected surfaces. If a single surface is desired, use connectivity
to extract the single “largest” surface (in terms of number of triangles). This surface is an
approximation to the swept surface, and the volume it encloses is an approximation to the
swept volume.
9.4 Modelling Algorithms 353
(a) Generate implicit model, V I (b) Sweep implicit model through work-
space volume, V W
ST
There are a few points that require additional explanation. This algorithm uses two volumes, the
implicit model and the workspace volume. Both are implicit models, but the workspace volume is
used to accumulate the part as it moves along the sweep trajectory. In theory, the part could be sam-
pled directly into the workspace volume to create the implicit model of the swept surface. Perfor-
mance issues dictate that the implicit model is sampled into the workspace volume. This is because
it is much faster to sample the implicit model of the part rather than the part itself, since computing
the distance function from a part that may consist of tens of thousands of cells is relatively time-
consuming, compared to sampling the implicit model . V I
Sampling isV Idepicted in Figure9–33 . The sweep trajectory is defined by a series of trans-
formation matrices STt = {}1,,,t2 ¼ t m . As the part moves along ST , interpolation is used to
compute an inbetween transformation matrix t. Sampling is achieved by inverse transforming VW
into the local space of using
VI t. Then, similar to the probe operation described in “Probing ” on
354 Advanced Algorithms
p
d i1+
di d
Dimensions L
DxDxD L/D Dx
e
Transform
t i1+
L L ti
–1
page336 , the points of are
VWtransformed by the inverse of the transformation matrix , and t
used to interpolate the distance values from the implicit model . V I
Because we are dealing with an implicit modeling technique, parts with concave features can
generate multiple surfaces. As discussed in “Connectivity ” on page339 , the connectivity algorithm
is used to separate out the swept surface. This final surface is an approximation to the actual swept
surface, since we are sampling the actual geometric representation on an array of points (i.e., the
implicit model), and then sampling the implicit model on another volume (i.e., the workspace vol-
ume). Also, stepping along the sweep trajectory generates errors proportional to the step size . Dx
These errors can be characterized as follows ( Figure9–34 ). Given a voxel size L/D, where L
is the edge length of the volume, and D is the dimension of the volume (assumed uniform for con-
venience), the maximum sampling error is
3 æö----
L
e £ ------- (9-20)
2 èøD
The error due to stepping, which includes both translation and rotational components, is bounded
by Dx2¤ , where Dx is the maximum displacement of any point on the implicit model at any given
translational step. Combining these terms for sampling both volumes and the error due to stepping,
the total error is
3 æöL I L W Dx
e tot £ -------
------
+ ---------
+ ------- (9-21)
2 èøD I DW 2
where the subscripts I and W refer to the implicit model and workspace volume, respectively.
To show the application of this algorithm, we have generated swept surfaces for the letters
“VTK” and the “mace” model as shown in Figure9–35 . We have purposely chosen a step size to
exaggerate the stepping error. Using more steps would smooth out the surface “bumps” due to step-
ping. Also, the appearance of the surface varies greatly with the selected isosurface value. Larger
values give rounder, smoother surfaces. If you use small values near zero (assuming positive dis-
tance function) the surface may break up. To correct this you need to use a higher resolution work-
9.4 Modelling Algorithms 355
Figure 9–35 Swept surfaces. (a) Swept mace sampled at 25 locations. (b) Swept vtk sam-
pled at 21 locations.
space or compute negative distances. Negative distances are computed during the implicit
modeling step by negating all points inside the original geometry. Negative distances allow us to
use a zero isosurface value or to generate internal offset surfaces. Negative distances can only be
computed for closed (i.e., manifold) objects.
Unstructured point datasets consist of points at irregular positions in 3D space. The relationship
between points is arbitrary. Examples of unstructured point datasets are visualizing temperature
distribution from an array of (arbitrarily) placed thermocouples, or rainfall level measured at scat-
tered positions over a geographic region.
Unlike image data and structured grids, or even unstructured grids, unstructured point dataset
have no topological component relating one point to another. For these reasons unstructured points
are simple to represent but difficult to visualize. They are difficult to visualize because there is no
inherent “structure” to which we can apply our library of visualization techniques. Beyond just dis-
playing points (possibly colored with scalar value, or using oriented vector glyphs) none of the
techniques discussed thus far can be used. Thus, to visualize unstructured points we have to build
structure to which we can apply our visualization techniques.
There are several approaches available to build topological structure given a random set of
points. One common approach samples unstructured points into an image dataset, and then visual-
izes the data using standard volume or surface-based rendering techniques. Another approach cre-
ates n-dimensional triangulations from the unstructured points, thereby creating topological
structure. These and other common techniques are described in the following sections.
356 Advanced Algorithms
Figure 9–36 Splatting techniques depicted in 2D. (a) Injecting points into the image dataset (circular
splats). (b) Visualizing the image dataset via contouring. Any image-based visualization technique
could be used.
where s is a scale factor that multiplies the exponential, f is the exponent scale factor , f0³ r is the
distance between any point and the Gaussian center point (i.e., the splat point) , andrpp= – i R
is the radius of influence of the Gaussian, where . rR£
The Gaussian function ( Figure9–37 (a)) becomes a circle in cross section in two dimensions
(Figure9–37 (b)) and a sphere in three dimensions. Since the value of the function is maximum
when ,r0=
the maximum value is given by the scale factor s. The parameter f controls the rate of
decay of the splat. Scalar values can be used to set the value of s, so that relatively large scalar val-
ues create bigger splats than smaller values.
Splats may be accumulated using the standard implicit modeling boolean operations
(Equation6-13 , Equation6-14 , and Equation6-15 ). That is, we may choose to form a union,
intersection, or difference of the splats. The union and intersection operators are used most fre-
quently.
Another interesting variation modifies the shape of the splat according to a vector quantity
such as surface normal or vector data. Figure9–37 (c) shows an example where the splat shape is
elongated in the direction parallel to a vector. Thus, if we have a set of points and normals, we can
create a polygonal surface by combining splatting with isosurface extraction.
9.4 Modelling Algorithms 357
R
s rxy
v
R z
R
Figure 9–37 Gaussian splatting functions. (a) one-dimensional, (b) 2D spherical, and
(c) 2D elliptical.
= × () –
zvpp i , with v1 =
(9-24)
2 2
r xy = r – z
Figure 9–38 Elliptical splatting. (a) Single elliptical splat with eccentricity E=10 .
Cone shows orientation of vector ( singleSplat.cxx ). ( b) Surface reconstructed
using elliptical splats into 100 3 volume followed by isosurface extraction. Points regu-
larly subsampled and overlayed on original mesh ( splatFace.tcl ).
n
F
å -------------------
pp–
i
2
i1= i
Fp() = -----------------------------
n
(9-25)
å 1
-------------------
2
i1= pp– i
Fp() i = Fmethod
where . Shepard’s i is easy to implement, but has the undesirable property that
limits its usefulness for most practical applications. The interpolation functions generate a local
“flat spot” at each point pi since the derivatives are zero
¶F ¶F ¶F (9-26)
= == 0
¶x ¶y ¶z
As a result, Shepard’s method is overly constrained in the region around each point.
Shepard’s method is an example of a basis function method. That is, the interpolation func-
tion F(p) consists of a sum of functions centered at each data point, p i. Other basis function meth-
ods have been developed as described by Nielson [Nielson91] . They vary in localization of the basis
functions and the sophistication of the interpolation function. Localization of basis functions means
9.4 Modelling Algorithms 359
circumcircle
circumcenters
Figure 9–39 The Delaunay triangulation (a) and Dirichlet tessellation (b). The circumcircle of each
triangle in a Delaunay triangulation contains no other points but the three vertices of the triangle. The
region surrounding each point pi in a Dirichlet tessellation is the set of points closest to pi .
that their effect is isolated to a small region. Examples of more sophisticated basis functions
include quadratic polynomials and cubic splines. Please see the references for more information.
circumcircle
repeat
Figure 9–40 Computing the Delaunay triangulation using technique of Watson and Boyer. Points are
injected into triangulation forming new Delaunay triangulations. In the final step, the initial bounding
points are removed to reveal final triangulation.
Hybrid Techniques. Recent work has focused on combining triangulation and basis function tech-
niques for interpolating 2D bivariate data. The basic idea is as follows. A triangulation of P is con-
structed. Then an interpolating network of curves is defined over the edges of the triangulation.
These curves are constructed with certain minimization properties of interpolating splines. Finally,
the curve network is used to construct a series of triangular basis functions, or surface patches, that
9.4 Modelling Algorithms 361
exhibit continuity in function value, and possibly higher order derivatives. (See [Nielson91] for
more information.)
Multidimensional Visualization
The treatment of multidimensional datasets is an important data visualization issue. Each point in a
dataset is described by an n-dimensional coordinate, where . Heren3³ we assume that each coor-
dinate is an independent variable, and that we wish to visualize a single dependent variable. (Multi-
dimensional visualization of vectors and tensors is an open research area.) An application of
multidimensional data is financial visualization, where we might want to visualize return on invest-
ment as a function of interest rate, initial investment, investment period, and income, to name just a
few possibilities.
There are two fundamental problems that we must address when applying multidimensional
visualization. These are the problems of projection and understanding .
The problem of projection is that in using computer graphics we have two dimensions in
which to present our data, or possibly three or four if we use specialized methods. Using 3D graph-
ics we can give the illusion of three dimensions, or we can use stereo viewing techniques to achieve
three dimensions. We can also use time as a fourth dimension by animating images. However,
except for these limited situations, general n-dimensional data cannot be represented on a 2D com-
puter screen.
The problem of understanding is that humans do not easily comprehend more than three
dimensions, or possibly three dimensions plus time. Thus, even if we could create a technique to
display data of many dimensions, the difficulty in understanding the data would impair the useful-
ness of the technique.
Most multidimensional visualization techniques work with some form of dimension map-
ping, where n dimensions are mapped to three dimensions and then displayed with 3D computer
graphics techniques. The mapping is achieved by fixing all variables except three, and then apply-
ing the visualization techniques described throughout the text to the resulting data. For maximum
benefit, the process of fixing independent variables, mapping to three dimensions, and then gener-
ating visualization must be interactive. This improves the effectiveness of the visualization process,
allowing the user to build an internal model of the data by manipulating different parts of the data.
One novel approach to multidimensional visualization has been proposed by Inselberg and
Dimsdale [Inselberg87] . This approach uses parallel coordinate systems . Instead of plotting points
on orthogonal axes, the ith dimensional coordinate of each point is plotted along separate, parallel
axes. This is shown in Figure9–41 for a five-dimensional point. In parallel coordinate plots, points
appear as lines. As a result, plots of n-dimensional points appear as sequences of line segments that
may intersect or group to form complex fan patterns. In so doing, the human pattern recognition
capability is engaged. Unfortunately, if the number of points becomes large, and the data is not
strongly correlated, the resulting plots can become a solid mass of black, and any data trends are
drowned in the visual display.
Another useful multivariable technique uses glyphs. This technique associates a portion of
the glyph with each variable. Although glyphs cannot generally be designed for arbitrary n-dimen-
sional data, in many applications we can create glyphs to convey the information we are interested
in. Refer to “Glyphs ” on page190 for more information about glyphs.
362 Advanced Algorithms
x1 x2 x3 x4 x5 x1 x2 x3 x4 x5
(a) Plot of five-dimensional point (b) Plot of six points
Figure 9–41 Plotting a five-dimensional point using parallel coordinates. (a) plot of sin-
gle point, (b) plot of many points.
Texture Algorithms
Texturing is a common tool in computer graphics used to introduce detail without the high cost of
graphics primitives. As we suggested in Chapter 7, texture mapping can also be used to visualize
data. We explore a few techniques in the following sections.
Texture Thresholding. We saw earlier how to threshold data based on scalar values (see “Thresh-
olding ” on page336 ). We refer to this approach as geometric thresholding because structural com-
ponents of a dataset (e.g., points and cells) are extracted based on data value. In contrast, we can
use texture mapping techniques to achieve similar results. We call this technique texture threshold-
ing.
Texture thresholding conceals features we do not want to see and accentuates features that we
want to see. There are many variations on this theme. A feature can be concealed by making it
transparent or translucent, by reducing its intensity, or using muted colors. A feature can be accen-
tuated by making it opaque, increasing its intensity, or adding bright color. In the following para-
graphs we describe a technique that combines intensity and transparency.
Texture thresholding requires two pieces of information: a texture map and an index into the
map, or texture coordinate. In the simplest case we can devise a texture map that consists of two
distinct regions as shown in Figure9–42 (a) . The first region is alternatively referred to as “con-
ceal,” “off,” or “outside.” The second region is referred to as “accentuate,” “on,” or “inside.”
(These different labels are used depending upon the particular application.) With this texture map in
hand we can texture threshold by computing an appropriate texture coordinate. Areas that we wish
to accentuate are assigned a coordinate to map into the “accentuate” portion of the texture map.
Areas that we want to conceal are assigned a coordinate to map into the “conceal” portion of the
texture map.
One texture threshold technique uses transparency. We can conceal a region by setting its
alpha opacity value to zero (transparent), and accentuate it by setting the alpha value to one
(opaque). Thus, the texture map consists of two regions: a concealed region with and ana = 0
accentuated region with . Ofa =course,
1 the effect can be softened by using intermediate alpha
values to create translucent images.
An extension of this technique introduces a third region into the texture map: a transition
region ( Figure9–42 (b)). The transition region is the region between the concealed and accentuated
9.4 Modelling Algorithms 363
opacity opacity
transition
accentuate
1 1
accentuate
conceal conceal
0 s 0 s
0 1 0 1
Figure 9–42 1D texture map. (a) In/out map. (b) Addition of transition region to in/out map.
regions. We can use the transition region to draw a border around the accentuated region, further
highlighting the region.
To construct the texture map we use intensity-alpha, or Ia values. The intensity modulates
the underlying color, while the alpha value controls transparency (as described previously). In the
accentuated region, the intensity and opacity values are set high. In the concealed region, the inten-
sity value can be set to any value (if ) orato=a 0lower value (if ). The transition
a ¹ region
0
can use various combinations of and a intensity. A nice combination produces a black, opaque
transition region (i.e., and
I0=). a = 1
To visualize information with the thresholding technique, we must map data to texture coor-
dinates. As we saw previously, we can use scalar values in combination with a threshold specifica-
tion to map data into the concealed, transition, and accentuated regions of the texture map.
Figure9–43 (a) shows an example of texture thresholding applied to scalar data from a simulation
of fluid flow. A scalar threshold iss set
T to show only data with scalar value greater than or equal
to .s T
Another useful texture thresholding application uses implicit functions to map point position
to texture coordinate. This is similar in effect to geometric clipping (see “Clipping With Scalar
Fields ” on page323 ). As we saw in “Implicit Functions ” on page185 , implicit functions naturally
()xyz
,,
map a coordinate value into three regions: , , and () ,,
Fxyz < 0 Fxyz
() ,, = 0
() ,,
Fxyz > 0 ; or equivalently, the concealed, transition, and accentuated regions of the texture
map. Using boolean combinations of implicit functions, we can create complex cuts of our data as
illustrated in Figure9–43 (b). This figure shows two nested spheres. The outer sphere is cut by a
boolean combination of two planes to show the inner sphere.
Boolean Textures. Texture thresholding can be extended into higher dimensions. That is, 2D or 3D
texture coordinates can be used to map two or three data variables into a texture map. One such
technique is boolean textures , a method to clip geometry using a 2D texture map and two implicit
functions [Lorensen93] .
Boolean textures extend texture thresholding for geometric clipping from 1D to 2D. Instead
of using a single implicit function to label regions “in” or “out”, two implicit functions are used.
This results in four different regions corresponding to all possible combinations of “in” and “out.”
364 Advanced Algorithms
(a) Thresholding data with texture (b) Sphere cut with transparent texture
Figure 9–43 Examples of texture thresholding. (a) Using scalar threshold to show values
of flow density on plane above value of 1.5 ( texThresh.tcl ). (b) Boolean combina-
tion of two planes to cut nested spheres ( tcutSph.cxx ).
s
1
in/out out/out
transition
Figure 9–44 2D Boolean texture.
in/in out/in
0
r
0 1
The boolean texture map is modified to reflect this as shown in Figure9–44 . As with 1D texture
thresholding, transition regions can be created to separate the four regions.
The boolean texture map can be created with combinations of intensity and transparency val-
ues to achieve a variety of effects. By combining the four combinations of in/out (i.e., four regions
of Figure9–44 ) with the two combinations of “conceal” and “accentuate,” sixteen different bool-
ean textures are possible. Figure9–45 (a) illustrates these combinations expressed as boolean com-
binations of two implicit functions A and B. The “inside” of the implicit functions is indicated with
subscript i, while the outside is indicated with subscript o. The boolean expressions indicate the
9.4 Modelling Algorithms 365
Æ Ai Ç Bi Ao Ç Bi Bi
Ai Ç Bo Ai ()A o Ç B i È ()A i Ç B o Ai È Bi
Ao Ç Bo ()A i Ç B i È ()A o Ç B o Ao Ao È Bi
Bo Ai È Bo Ao È Bo all
Figure 9–45 Sixteen boolean textures. (a) Sixteen combinations of in/out. (b) Textures applied to
sphere using two elliptical cylinder implicit functions.
366 Advanced Algorithms
16
(a) Simple opaque/transparent (b) Feathered opaque/transparent
variation variation
Figure 9–46 Texture maps for vector animation. Sixteen textures applied in succession
create effect of motion along a vector. (a) Simple map. (b) Varying intensity “feathers”
effect of motion.
regions that we wish to conceal, as shown by open circles. The darkened circles are the regions that
are accentuated. We can see in Figure9–45 (b) the effects of applying these different boolean tex-
tures to a sphere. The implicit functions in this figure are two elliptical cylinders sharing a common
axis, and rotated 90 degrees from one another. In addition, transition regions have been defined
with to
I0=generate the dark cut edges shown. All 16 spheres share the same texture coordi-
nates; only the texture map changes.
Texture Animation. Time-based animation techniques can illustrate motion or temporal data vari-
ations. This process often requires relatively large amounts of computer resource to read, process,
and display the data. Thus, techniques to reduce computer resources are desirable when animating
data.
Texture mapping can be used to animate certain types of data. In these techniques, the data is
not regenerated frame by frame, instead a time-varying texture map is used to change the visual
appearance of the data. An example of this approach is texture animation of vector fields
[Yamrom95] .
As we saw in “Hedgehogs and Oriented Glyphs ” on page173 , vector fields can be repre-
sented as oriented and scaled lines. Texture animation can transform this static representational
scheme into a dynamic representation. The key is to construct a series of 1D texture maps that
when applied rapidly in sequence create the illusion of motion. Figure9–46 (a) shows a series of
sixteen such texture maps. The maps consist of intensity-alpha () values,
Ia A portion of the tex-
I1= is,shown
ture map is set fully opaque with full intensity (). This a =as1the “dark” pat-
tern in Figure9–46 (a). The remainder of the map is set fully transparent with arbitrary intensity
= , asathe
()I1shown = “white”
0 portion. As is evidenced by the figure, the sequence of 16
texture maps scanned top to bottom generate the appearance of motion from left to right. Notice
also how the texture maps are designed to wrap around to form a continuous pattern.
Along with the 1D texture map, the texture coordinate s must also be generated — on a line
this is straightforward. The line origin receives texture coordinate s = 0 , while the line terminus
receives texture coordinate value s = 1 . Any intermediate points (if the vector is a polyline) are
9.5 Putting It All Together 367
parameterized in monotonic fashion in the interval (0,1). Texture coordinates need only be gener-
ated once. Only the texture map is varied to generate the vector animation.
Other effects are possible by modifying the texture map. Figure9–46 (b) shows a texture map
with a repeating sequence of opaque/transparent regions. In each opaque region the intensity is
gradually reduced from left to right. The result is that this tends to “feather” the appearance of the
vector motion. The resulting image is more pleasing to the eye.
Dividing cubes is implemented in VTK w ith the class vtkDividingCubes . It has been specialized to
operate with image datasets. Besides specifying the contour value, you must specify a separation
distance between points (using the method SetDistance() ). If you desire a solid appearance, pick a
distance that is less than or equal to display resolution.
The separation distance controls the accuracy of point generation. It is possible to generate
points that appear to form a solid surface when rendered, but are not accurately located on the con-
tour surface. Although this usually is not an issue when viewing contour surfaces, if the accuracy of
the point positions is important, the distance value must be set smaller. However, this can result in
huge numbers of points. To reduce the number of points, you can use the SetIncrement() method,
which specifies that every nth point is to be generated. Using this approach, you can obtain good
accuracy and control the total number of points. An example where point positions are important is
when the points are used to locate glyphs or as seed points for streamline generation.
The Visualization Toolkit provides other point generation techniques. The source object
vtkPointSource generates a user-specified number of points within a spherical region. The point
positions are random within the sphere. (Note that there is a natural tendency for higher point den-
sity near the center of the sphere because the points are randomly generated along the radius and
f .) q
spherical angles and
Figure9–47 is an example use of vtkPointSource to generate streamlines. The dataset is a
structured grid of dimensions with ´ velocity
212020
flow ´ and a scalar pressure field. The
dataset is a CFD simulation of flow in a small office. As this picture shows, there are a couple of
bookcases, desks, a window, and an inlet and outlet for the ventilation system. On one of the desks
is a small, intense heat source (e.g., a cigarette). In the left image 25 streamlines are started near the
inlet using a vtkPointSource point generator. The second image shows what happens when we
move the point source slightly to the left. By adjusting a single parameter (e.g., the center of the
point source) it is possible to quickly explore our simulation data.
Another convenient object for point generation is the class vtkEdgePoints . vtkEdgePoints
generates points on an isosurface. The points are generated by locating cell edges whose points are
both above and below the isosurface value. Linear interpolation is used to generate the point. Since
vtkEdgePoints operates on any cell type, this filter’s input type is any dataset type (e.g.,
368 Advanced Algorithms
vtkDataSet ). Unlike vtkDividingCubes this filter will not typically generate dense point clouds that
appear solid.
Clipping is implemented in vtkClipPolyData . Each polygonal data primitive implements the opera-
tion in its Clip() method using cases tables derived in a manner similar to that of triangles described
on Page 323. vtkClipPolyData has methods to control whether an implicit function provides the
scalar data or whether the dataset’s scalar data will be used. ComputeScalarDataOn() uses the
implicit function and ComputeScalarDataOff() uses the dataset’s scalar data. Two output polygonal
datasets are produced. These are accessed with GetOutput() and GetClippedOutput() methods.
GetOutput() returns the polygonal data that is “inside” the clipping region while
GetClippedOutput() returns polygonal data that is “outside” the region. (Note that
GenerateClippedOutputOn() must be enabled if you are to get the clipped output.) The meaning of
inside and outside can be reversed using the InsideOutOn() method. Figure9–48 shows a plane of
quadrilaterals clipped with a boolean implicit function.
Until recently, VTK supported clipping only for polygonal data cell types (vertices, polyver-
tices, line, polylines, polygons and triangle strips). Recent additions since VTK version 4.0 support
clipping of 3D cells using an ordered Delaunay triangulation approach.
Swept surfaces can be applied in two interesting ways. First, they can be used as a modelling tool to
create unusual shapes and forms. In this sense, swept surfaces are an advanced implicit modelling
technique. Second, swept surfaces can be used to statically represent object motion. This is an
important visualization technique in itself and has many important applications. One of these appli-
cations is design for maintainability.
When a complex mechanical system like a car engine is designed, it is important to design
proper access to critical engine components. These components, like spark plugs, require higher
levels of service and maintenance. It is important that these components can be easily reached by a
mechanic. We’ve read horror stories of how it is necessary to remove an engine to change a spark
plug. Insuring ready access to critical engine parts prevents situations like this from occurring.
9.5 Putting It All Together 369
vtkSphere vtkCylinder
vtkClipPolyData vtkImplicitBoolean
Output ClippedOutput
vtkPolyDataMapper vtkPolyDataMapper
vtkPlaneSource plane
plane SetResolution 25 25
plane SetOrigin -1 -1 0
plane SetPoint1 1 -1 0
plane SetPoint2 -1 1 0
vtkTransform trSphere
trSphere Identity
trSphere Translate .4 -.4 0
trSphere Inverse
vtkSphere sphere
sphere SetTransform trSphere
sphere SetRadius .5
vtkTransform trCylinder
trCylinder Identity
trCylinder Translate -.4 .4 0
trCylinder RotateZ 30
trCylinder RotateY 60
trCylinder RotateX 90
trCylinder Inverse
vtkCylinder cylinder
cylinder SetTransform trCylinder
cylinder SetRadius .3
vtkImplicitBoolean boolean
boolean AddFunction cylinder
boolean AddFunction sphere
vtkClipPolyData clipper
clipper SetInputConnection [plane GetOutputPort]
clipper SetClipFunction boolean
clipper GenerateClippedOutputOn
clipper GenerateClipScalarsOn
clipper SetValue 0
Figure 9–48 A plane clipped with a sphere and an ellipse. The two transforms place each
implicit function into the appropriate position. Two outputs are generated by the clipper.
(clipSphCyl.tcl ).
370 Advanced Algorithms
Swept surface can assist in the design of part access. We simply define a path to remove the
part (early in the design process), and then generate a swept surface. This surface (sometimes
referred to as a maintenance access solid or MAS) is then placed back into the CAD system. From
this point on, the design of surrounding components such as fuel lines or wiring harnesses must
avoid the MAS. As long as the MAS is not violated, the part can be removed. If the MAS is vio-
lated, a reevaluation of the removal path or redesign of the part or surrounding components is nec-
essary.
Figure9–49 shows how to create a swept surface from a simple geometric representation.
The geometry is simply a line-stroked VTK. The next step is to define a motion path. This path is
defined by creating a list of transformation matrices. Linear interpolation is used to generate inter-
mediate points along the path if necessary.
In Figure9–49 we also see the basic procedure to construct the swept surface. First, we must
construct an implicit representation of the part by using vtkImplictModeller . This is then provided
as input to vtkSweptSurface . It is important that the resolution of the implicit model is greater than
or equal to that of vtkSweptSurface . This will minimize errors when we construct the surface. A
bounding box surrounding the part and its motion can be defined, or it will be computed automati-
cally. For proper results, this box must strictly contain the part as its moves. We also can set the
number of interpolation steps, or allow this to be computed automatically as well. In the figure, we
have chosen a small number to better illustrate the stepping of the algorithm.
Once vtkSweptSurface executes, we extract the swept surface using an isosurfacing algo-
rithm. The isosurface value is an offset distance; thus we can create surfaces that take into account
geometry tolerance. (This is particularly important if we are designing mechanical systems.) The
implementation of the implicit modeller in VTK uses a positive distance function; so the isosurface
value should always be positive. To create swept surfaces of zero and negative value requires a
modification to the implicit modeller.
Multidimensional Visualization
vtkPolyDataReader
vtkImplicitModeller
vtkSweptSurface
vtkContourFilter
vtkSweptSurface sweptSurfaceFilter
sweptSurfaceFilter SetInputConnection [imp GetOutputPort]
sweptSurfaceFilter SetTransforms transforms
sweptSurfaceFilter SetSampleDimensions 100 7040
sweptSurfaceFilter SetModelBounds -4.0 6.0 -1.0 6.0 -1.0 3.5
sweptSurfaceFilter SetMaximumNumberOfInterpolationSteps 20
vtkContourFilter iso
iso SetInputConnection [sweptSurfaceFilter GetOutputPort]
iso SetValue 0 0.33
Figure 9–49 Generating swept surface from line-stroked “vtk”. The class vtkSwept-
Surface was in the Patented directory in VTK 4.4. This directory was removed in
VTK 5.0, and this class is not available in that release.
372 Advanced Algorithms
vtkUnstructuredGrid
vtkGaussianSplatter
vtkContourFilter
vtkPolyDataMapper
Our first step is to choose dependent and independent variables. This choice is essentially a map-
ping from multidimensional data into an unstructured point dataset. In this example we will choose
MONTHLY_PAYMENT , INTEREST_RATE , and LOAN_AMOUNT as our (x, y, z) point coordi-
nates, and TIME_LATE as a scalar value. This maps four of six variables. For now we will ignore
the other two variables.
9.5 Putting It All Together 373
We use vtkGaussianSplatter to perform the splatting operation (i.e., conversion from unstruc-
tured points to volume dataset). This is followed by an isosurface extraction. We splat the data two
times. The first time we splat the entire population. This is to show context and appears as gray/
wireframe in the figure. The second time we splat the data and scale it by the value of
TIME_LATE . As a result, only payments that are late contribute to the second isosurface.
The results of this visualization are interesting. First, we see that there is a strong correlation
between the two independent variables MONTHLY_PAYMENT and LOAN_AMOUNT . (This is
more evident when viewing the data interactively.) We see that the data falls roughly on a plane at a
45 degree angle between these two axes. With a little reflection this is evident: the monthly pay-
ment is strongly a function of loan amount (as well as interest rate and payment period). Second,
we see that there is a clustering of delinquent accounts within the total population. The cluster tends
to grow with larger interest rates and shrink with smaller monthly payments and loan amounts.
Although the relationship with interest rate is expected, the clustering towards smaller monthly
payments is not. Thus our visualization has provided a clue into the data. Further exploration may
reveal the reason(s), or we may perform additional data analysis and acquisition to understand the
phenomena.
One important note about multidimensional visualization. Because we tend to combine vari-
ables in odd ways (e.g., the use of MONTHLY_PAYMENT , INTEREST_RATE , and
LOAN_AMOUNT as (x, y, z) coordinates), normalization of the data is usually required. To nor-
malize data we simply adjust data values to lie between (0,1). Otherwise our data can be badly
skewed and result in poor visualizations.
Connectivity
Many useful visualization algorithms often borrow from other fields. Topological connectivity
analysis is one such technique. This technique is best categorized as a method in computational
geometry, but serves many useful purposes in computer graphics and visualization.
To illustrate the application of connectivity analysis, we will use an MRI dataset generated by
Janet MacFall at the Center for In Vivo Microscopy at Duke University. The dataset is a volume of
dimensions 256 3 and is included on the CD-ROM. The data is of the root system of a small pine
tree. Using the class vtkSliceCubes , an implementation of marching cubes for large volumes, we
generate an initial isosurface represented by 351,118 triangles. (We have placed the file
pine_root.tri on CD-ROM. This is a faster way of manipulating this data. If you have a large
enough computer you can process the volume directly with vtkVolume16Reader and
vtkMarchingCubes .)
Figure9–51 (a) shows the initial dataset. Notice that there are many small, disconnected isos-
urfaces due to noise and isolated moisture in the data. We use vtkConnectivityFilter to remove
these small, disconnected surfaces. Figure9–51 (b) shows the result of applying the filter. Over
50,000 triangles were removed, leaving 299,480 triangles.
The vtkConnectivityFilter is a general filter taking datasets as input, and generating an
unstructured grid as output. It functions by extracting cells that are connected at points (i.e., share
common points). In this example the single largest surface is extracted. It is also possible to specify
cell ids and point ids and extract surfaces connected to these.
374 Advanced Algorithms
vtkMCubesReader
vtkPolyDataConnectivityFilter vtkPolyDataMapper
vtkMCubesReader reader
reader SetFileName \
"$env(VTK_TEXTBOOK_DATA)/pineRoot/pine_root.tri"
vtkPolyDataConnectivityFilter connect
connect SetInputConnection [reader GetOutputPort]
connect SetExtractionModeToLargestRegion
vtkPolyDataMapper isoMapper
isoMapper SetInputConnection [connect GetOutputPort]
isoMapper ScalarVisibilityOff
vtkActor isoActor
isoActor SetMapper isoMapper
eval [isoActor GetProperty] SetColor $raw_sienna
vtkOutlineFilter outline
outline SetInputConnection [reader GetOutputPort]
vtkPolyDataMapper outlineMapper
outlineMapper SetInputPort [outline GetOutputPort]
vtkActor outlineActor
outlineActor SetMapper outlineMapper
Decimation
Decimation is a 3D data compression technique for surfaces represented as triangle meshes. We use
it most often to improve rendering interactive response for large models.
Figure9–52 shows the application of decimation to the data from the pine root example. The
original model of 351,118 triangles is reduced to 81,111 triangles using a combination of decima-
tion and connectivity. The decimation parameters are fairly conservative. Here we see a reduction
of approximately 55 percent.
The most common parameters to adjust in the vtkDecimate filter are the TargetReduction ,
InitialError , ErrorIncrement , MaximumIterations , and InitialFeatureAngle . TargetReduction speci-
fies the compression factor (numbers closer to one represent higher compression). Because of topo-
logical, decimation criterion, aspect ratio, and feature angle constraints this reduction may not be
realized (i.e., TargetReduction is a desired goal, not a guaranteed output). The InitialError and
ErrorIncrement control the decimation criterion. As the filter starts, the decimation criterion is set
to InitialError . Then, for each iteration the decimation criterion is incremented by ErrorIncrement .
The algorithm terminates when either the target reduction is achieved, or the number of iterations
reaches MaximumIterations . The InitialFeatureAngle is used to compute feature edges. Smaller
angles force the algorithm to retain more surface detail.
Other important parameters are the AspectRatio and MaximumSubIterations . AspectRatio
controls the triangulation process. All triangles must satisfy this criterion or the vertex will not be
deleted during decimation. A sub-iteration is an iteration where the decimation criterion is not
incremented. This can be used to coalesce triangles during rapid rates of decimation.
MaximumSubIterations controls the number of sub-iterations. This parameter is typically set to
two.
Texture Clipping
Texture mapping is a powerful visualization technique. Besides adding detail to images with mini-
mal effort, we can perform important viewing and modelling operations. One of these operations is
clipping data to view internal structure.
Figure9–53 is an example of texture clipping using a transparent texture map. The motor
show consists of five complex parts, some of which are hidden by the outer casing. To see the
inside of the motor, we define an implicit clipping function. This function is simply the intersection
of two planes to form a clipping “corner.” The object vtkImplicitTextureCoords is used in combina-
tion with this implicit function to generate texture coordinates. These objects are then rendered with
the appropriate texture map and the internal parts of the motor can be seen.
The texture map consists of three regions (as described previously in the chapter). The con-
cealed region is transparent. The transition region is opaque but with a black (zero intensity) color.
The highlighted region is full intensity and opaque. As can be seen from Figure9–53 , the bound-
aries appear as black borders giving a nice visual effect.
The importance of texture techniques is that we can change the appearance of objects and
even perform modelling operations like clipping with little effort. We need only change the texture
map. This process is much faster relative to the alternative approach of geometric modelling. Also,
376 Advanced Algorithms
vtkMCubesReader vtkPolyDataConnectivityFilter
vtkDecimate vtkPolyDataMapper
vtkMCubesReader reader
reader SetFileName \
"$env(VTK_TEXTBOOK_DATA)/pineRoot/pine_root.tri"
reader FlipNormalsOff
vtkDecimate deci
deci SetInputConnection [reader GetOutputPort]
deci SetTargetReduction 0.9
deci SetAspectRatio 20
deci SetInitialError 0.0005
deci SetErrorIncrement 0.001
deci SetMaximumIterations 6
deci SetInitialFeatureAngle 30
vtkPolyDataConnectivityFilter connect
connect SetInputConnection [deci GetOutputPort]
connect SetExtractionModeToLargestRegion
vtkPolyDataMapper isoMapper
isoMapper SetInputConnection [connect GetOutputPort]
isoMapper ScalarVisibilityOff
Figure 9–52 Applying connectivity and decimation filters to remove noisy isosurfaces and reduce
data size ( deciPineRoot.tcl ). Data is from 256 3 volume data of the root system of a pine tree.
9.5 Putting It All Together 377
vtkBYUReader
vtkPolyDataNormals
vtkImplicitTextureCoords
vtkDataSetMapper
# texture
vtkStructuredPointsReader texReader
texReader SetFileName "$VTK_DATA_ROOT/Data/texThres2.vtk"
vtkTexture texture
texture SetInputConnection [texReader GetOutputPort]
texture InterpolateOff
texture RepeatOff
Figure 9–53 Texture cut used to reveal internal structure of a motor. Two cut planes are used in com-
bination with transparent texture ( motor.tcl ).
378 Advanced Algorithms
hardware support of texture is becoming common. Thus the rendering rate remains high despite the
apparent increase in visual complexity.
Delaunay Triangulation
Delaunay triangulation is used to construct topology from unstructured point data. In two dimen-
sions we generate triangles (i.e., an unstructured grid or polygonal dataset) while in three dimen-
sions we generate tetrahedra (i.e., an unstructured grid). Typical examples of image data include
points measured in space, or a dimensional subset of multidimensional data.
In the example of Figure9–54 we show how to create a 2D Delaunay triangulation from a
field of points. The points are created by generating random x and y coordinate values in the inter-
val ,[]and
01, setting the z-value to a constant value (i.e., the points lie in an x-y plane). The points
are then triangulated, and tubes and sphere glyphs are used to highlight the resulting points and
edges of the triangulation.
One important concern regarding Delaunay triangulations is that the process is numerically
sensitive. Creating triangles with poor aspect ratio (e.g., slivers) can cause the algorithm to break
down. If you have a large number of points to triangulate, you may want to consider randomizing
the point order. This approach tends to generate triangles with better aspect ratio and give better
results. You may also want to consider other implementations of Delaunay triangulation that are
more numerically robust. See [Edelsbrunner94] for an example.
vtkPolyData
vtkDelaunay2D
vtkPolyDataMapper
vtkPolyData profile
profile SetPoints points
# triangulate them
vtkDelaunay2D del
del SetInput profile
del SetTolerance 0.001
vtkPolyDataMapper mapMesh
mapMesh SetInputConnection [del GetOutputPort]
Figure 9–54 Two-dimensional Delaunay triangulation of a random set of points. Points and edges
are shown highlighted with sphere glyphs and tubes ( DelMesh.tcl) . Only the pipeline to generate
triangulation is shown.
selected using thresholding, which selects cells or points that lie within a range of scalar values.
Probing resamples data at a set of points. The probe produces a dataset that has the topology of the
probe with data values from the probed dataset. Generating triangle strips can reduce storage
requirements and improve rendering speeds on some systems. If a dataset has multiple disjoint
structures, a connectivity algorithm can uniquely identify the separate structures. For polygonal
data that does not have vertex normals defined, normal generation algorithms can compute these
values that are suitable for interpolation by Gouraud or Phong shading. Decimation, another data
reduction technique, removes triangles in “flat” regions and fills the resulting gaps with new trian-
gles. Unstructured points present a challenge because the data does not have topology. Splatting
represents each point in the data with a uniform sampling and accumulates these splats using
implicit modelling techniques. Triangulation techniques build topology directly from the unstruc-
tured points.
380 Advanced Algorithms
Multidimensional visualization techniques focus on data that has many scalar data values for
each point. Parallel coordinates is an interesting approach that plots the scalar values for a data
point along a parallel axis. The observer looks for trends and relationships between the lines that
represent each point’s data.
Texture algorithms use texture coordinates and texture maps to select or highlight portions of
a dataset. Texture thresholding assigns texture coordinates based on a scalar value. The scalar value
and texture map determine how a cell or portion of a cell is rendered. Boolean textures extend this
concept to 2D and 3D. Careful design of a boolean texture map permits the “clipping” of geometry
with combinations of implicit surfaces. Texture can also be used to animate vector fields.
9.8 References
[Banks94]
D. C. Banks and B. A. Singer. “Vortex Tubes in Turbulent Flows: Identification, Representation,
Reconstruction.” In Proceedings of Visualization ’94 . pp. 132–139, IEEE Computer Society Press,
Los Alamitos, CA, 1994.
[Bergeron89]
R. D. Bergeron and G. Grinstein. “A Reference Model for the Visualization of Multidimensional
Data.” In Proceedings Eurographics ’89 . pp. 393–399, North Holland, Amsterdam, 1989.
[Bowyer81]
A. Bowyer. “Computing Dirichlet Tessellations.” The Computer Journal . 24(2):162–166, 1981.
[Brill94]
M. Brill, H. Hagen, H-C. Rodrian, W. Djatschin, S. V. Klimenko. “Streamball Techniques for
Flow Visualization.” In Proceedings of Visualization ’94 . pp. 225–231, IEEE Computer Society
Press, Los Alamitos, CA, 1994.
[Cabral93]
B. Cabral and L. Leedom. “Imaging Vector Fields Using Line Integral Convolution.” In Proceed-
ings of SIGGRAPH ’93 , pp. 263–270, Addison-Wesley, Reading, MA, 1993.
[Cline88]
H. E. Cline, W. E. Lorensen, S. Ludke, C. R. Crawford, and B. C. Teeter, “Two Algorithms for the
Three-Dimensional Construction of Tomograms.” Medical Physics . 15(3):320–327, June 1988.
[Crawfis92]
R, Crawfis and N. Max. “Direct Volume Visualization of Three Dimensional Vector Fields.” In
Proceedings 1992 Workshop on Volume Visualization . pp. 55–60, ACM Siggraph, New York,
1992.
[Delmarcelle93]
T. Delmarcelle and L. Hesselink. “Visualizing Second-Order Tensor Fields with Hyperstream-
lines.” IEEE Computer Graphics and Applications . 13(4):25–33, 1993.
[Eck95]
M. Eck, T. DeRose, T. Duchamp, H. Hoppe, M. Lounsbery, W. Stuetzle. “Multiresolution Analy-
sis of Arbitrary Meshes.” In Proceedings SIGGRAPH ’95 . pp. 173–182, Addison-Wesley, Read-
ing, MA, August 1995.
382 Advanced Algorithms
[Edelsbrunner94]
H. Edelsbrunner and E. P. Mucke. “Three-dimensional alpha shapes.” ACM Transactions on
Graphics . 13:43–72, 1994.
[Evans96]
F. Evans, S. Skiena, A. Varshney. “Optimizing Triangle Strips for Fast Rendering.” In Proceedings
of Visualization ’9 6. pp. 319–326, IEEE Computer Society Press, Los Alamitos, CA, 1996.
[Feiner90]
S. Feiner and C. Beshers. “Worlds within Worlds: Metaphors for Exploring n-Dimensional Virtual
Worlds.” In Proceedings UIST ’90 (ACM Symp. on User Interface Software) . pp. 76–83, October,
1990.
[Garland97]
M. Garland and P. Heckbert. “Surface Simplification Using Quadric Error Metrics.” In Proceed-
ings SIGGRAPH ’97 . pp. 209–216, The Association for Computing Machinery, New York, Au-
gust 1997.
[Globus91]
A. Globus, C. Levit, and T. Lasinski. “A Tool for Visualizing the Topology of Three-Dimensional
Vector Fields.” In Proceedings of Visualization ’91 . pp. 33–40, IEEE Computer Society Press, Los
Alamitos, CA, 1991.
[He96]
T. He, L. Hong, A. Varshney, S. Wang. “Controlled Topology Simplification.” IEEE Transactions
on Visualization and Computer Graphics . 2(2):171–184, June 1996.
[Helman91]
J. L. Helman and L. Hesselink. “Visualization of Vector Field Topology in Fluid Flows.” IEEE
Computer Graphics and Applications . 11(3):36–46, 1991.
[Hinker93]
P. Hinker and C. Hansen. “Geometric Optimization.” In Proceedings of Visualization ’93 . pp.
189–195, IEEE Computer Society Press, Los Alamitos, CA, October 1993.
[Hoppe93]
H. Hoppe, T. DeRose, T. Duchamp, J. McDonald, W. Stuetzle. “Mesh Optimization.” In Proceed-
ings of SIGGRAPH ’93. pp. 19–26, August 1993.
[Hoppe96]
H. Hoppe. “Progressive Meshes.” In Proceedings SIGGRAPH ’96 . pp. 96–108, The Association
for Computing Machinery, New York, August 1996.
[Hultquist92]
J. P. M. Hultquist. “Constructing Stream Surfaces in Steady 3-D Vector Fields.” In Proceedings of
Visualization ’92 . pp. 171–178, IEEE Computer Society Press, Los Alamitos, CA, 1992.
[Inselberg87]
A. Inselberg and B. Dimsdale. “Parallel Coordinates for Visualizing Multi-Dimensional Geome-
try.” In Computer Graphics 1987 (Proceedings of CG International ’87 ). pp. 25–44, Springer-
Verlag, 1987.
[Lawson86]
C. L. Lawson. “Properties of n-Dimensional Triangulations.” Computer-Aided Geometric Design .
3:231–246, 1986.
[Lorensen93]
W. Lorensen. “Geometric Clipping with Boolean Textures.” in Proceedings of Visualization ’93 .
pp. 268–274, IEEE Computer Society Press, Los Alamitos, CA, Press, October 1993.
9.8 References 383
[Luebke02]
D. Luebke, M. Reddy, J. Cohen, A. Varshney, B. Watson, R. Huebner. Level of Detail for 3D
Graphics. Morgan Kaufmann 2002. ISBN 1-55860-838-9.
[Max94]
N. Max, R. Crawfis, C. Grant. “Visualizing 3D Vector Fields Near Contour Surfaces.” In Proceed-
ings of Visualization ’94 . pp. 248–255, IEEE Computer Society Press, Los Alamitos, CA, 1994.
[Mihalisin90]
T. Mihalisin, E. Gawlinski, J. Timlin, and J. Schwegler. “Visualizing a Scalar Field on an n-Di-
mensional Lattice.” In Proceedings of Visualization ’90. pp. 255–262, IEEE Computer Society
Press, Los Alamitos, CA, October 1990.
[Nielson91]
G. M. Nielson, T. A. Foley, B. Hamann, D. Lane. “Visualizing and Modeling Scattered Multivari-
ate Data.” IEEE Computer Graphics and Applications . 11(3):47–55, 1991.
[Popovic97]
J. Popovic and H. Hoppe. “Progressive Simplicial Complexes.” In Proceedings SIGGRAPH ’97 .
pp. 217–224, The Association. for Computing Machinery, New York, August 1997.
[Rossignac93]
J. Rossignac and P. Borrel. “Multi-Resolution 3D Approximations for Rendering Complex
Scenes.” In Modeling in Computer Graphics: Methods and Applications . B. Falcidieno and T. Ku-
nii, eds., pp. 455–465, Springer-Verlag Berlin, 1993.
[Schroeder91]
W. Schroeder, C. Volpe, and W. Lorensen. “The Stream Polygon: A Technique for 3D Vector Field
Visualization.” In Proceedings of Visualization ’91 . pp. 126–132, IEEE Computer Society Press,
Los Alamitos, CA, October 1991.
[Schroeder92a]
W. Schroeder, J. Zarge, and W. Lorensen. “Decimation of Triangle Meshes.” Computer Graphics
(SIGGRAPH ’92) . 26(2):65–70, August 1992.
[Schroeder92b]
W. Schroeder, W. Lorensen, G. Montanaro, and C. Volpe. “Visage: An Object-Oriented Scientific
Visualization System.” In Proceedings of Visualization ’92 . pp. 219–226, IEEE Computer Society
Press, Los Alamitos, CA, October 1992.
[Schroeder94]
W. Schroeder, W. Lorensen, and S. Linthicum, “Implicit Modeling of Swept Surfaces and Vol-
umes.” In Proceedings of Visualization ’94 . pp. 40–45, IEEE Computer Society Press, Los Alam-
itos, CA, October 1994.
[Schroeder97]
W. Schroeder. “A Topology Modifying Progressive Decimation Algorithm.” In Proceedings of Vi-
sualization ’97 . IEEE Computer Society Press, Los Alamitos, CA, October 1997.
[Stalling95]
D. Stalling and H-C. Hege. “Fast and Independent Line Integral Convolution.” In Proceedings of
SIGGRAPH ’95 . pp. 249–256, Addison-Wesley, Reading, MA, 1995.
[Turk92]
G. Turk. “Re-Tiling of Polygonal Surfaces.” Computer Graphics (SIGGRAPH ’92) . 26(2):55–64,
July 1992.
[vanWijk93]
J. J. van Wijk. “Flow Visualization with Surface Particles.” IEEE Computer Graphics and Appli-
cations . 13(4):18–24, 1993.
384 Advanced Algorithms
[Wang90]
S-L C. Wang and J. Staudhammer. “Visibility Determination on Projected Grid Surfaces.” IEEE
Computer Graphics and Applications . 10(4):36–43, 1990.
[Watson81]
D. F. Watson. “Computing the n-Dimensional Delaunay Tessellation with Application to Voronoi
Polytopes.” The Computer Journal . 24(2):167–172, 1981.
[Wixom78]
J. Wixom and W. J. Gordon. “On Shepard’s Method of Metric Interpolation to Scattered Bivariate
and Multivariate Data.” Math. Comp . 32:253–264, 1978.
[Yamrom95]
B. Yamrom and K. M. Martin. “Vector Field Animation with Texture Maps.” IEEE Computer
Graphics and Application s. 15(2):22–24, 1995.
9.9 Exercises
9.1 Describe an approach to adapt dividing cubes to other 3D cell types. Can your method be
adapted to 1D and 2D cells?
9.2 Discuss the advantages and disadvantages of representing surfaces with points versus poly-
gons.
9.3 Streamribbons can be constructed by either i) connecting two adjacent streamlines with a sur-
face, or ii) placing a ribbon on the streamline and orienting the surface according to stream-
wise vorticity vector. Discuss the differences in the resulting visualization.
9.4 Write the following programs to visualize velocity flow in the combustor.
a) Use vtkProbeFilter and vtkHedgeHog .
b) Use vtkProbeFilter and vtkStreamLine .
c) Use vtkProbeFilter and vtkWarpVector .
d) Use vtkProbeFilter and vtkVectorNorm .
e) Use vtkProbeFilter and vtkVectorDot .
9.5 Describe a method to extract geometry using an arbitrary dataset. (That is, extract geometry
that lies within the culling dataset.) ( Hint: how would you evaluate in/out of points?)
9.6 The filter vtkPolyDataNormals is often used in combination with the filters
vtkSmoothPolyData and vtkContourFilter to generate smooth isosurfaces.
a) Write a class to combine these three filters into one filter. Can you
eliminate intermediate storage?
b) How much error does vtkSmoothPolyData introduce into the
isosurface? Can you think of a way to limit the error?
c) What is the difference between the surface normals created by
vtkMarchingCubes and vtkPolyDataNormals ?
9.7 Assume that we have a database consisting of interest rate R, monthly payment P, monthly
income I, and days payment is late L.
a) If are,, all sampled regularly, how would you visualize this data?
RPI
b) If all data is irregularly sampled, list three methods to visualize it.
9.9 Exercises 385
9.8 Why do you think triangle strips are often faster to render than general polygons?
9.9 The normal generation technique described in this chapter creates consistently oriented sur-
face normals.
a) Do the normals point inside or outside of a closed surface?
b) Describe a technique to orient normals so that they point out of a closed surface.
c) Can surface normals be used to eliminate visible triangles prior to
rendering? ( Hint: what is the relationship between camera view and surface normal?)
9.10 Describe a technique to partially threshold a cell (i.e., to cut a cell as necessary to satisfy
threshold criterion). Can an approach similar to marching cubes be used?
9.11 The class vtkRendererSource allows us to use the rendered image as a texture map (or image
data dataset). Write a program to construct iterated textures, that is textures that consist of
repeated images. Can the same image be generated using texture coordinates?
9.12 Describe how you would modify the decimation algorithm to treat general polygons.
9.13 Several examples in the text (e.g., deciFran.tcl and deciHawa.tcl ) use the class
vtkDecimate . Modify these examples to use the topology modifying progressive decimation
algorithm (implemented in vtkDecimatePro ). How much greater reduction can you achieve?
386 Advanced Algorithms
Chapter 10
Image Processing
10.1 Introduction
Image processing has been a mainstay of computing since the advent of the digital computer. Early
efforts focused on improving image content for human interpretation. More recently image pro-
cessing has been utilized by practitioners of computer vision, the goal being the processing of
image data for autonomous machine perception [Gonzalez92] . From the perspective of data visual-
ization, image processing is used to manipulate image content to improve the results of subsequent
processing and interpretation. For example, a CT or MRI scan may generate spurious signal noise
or require image segmentation. Using the techniques of image processing, noise can be removed
and automatic and semi-automatic segmentation can be performed on a slice by slice (i.e., image by
image basis). As a result, isosurface generation, volume rendering, and other 3D techniques can be
improved in appearance, accuracy, and effectiveness by applying techniques from image process-
ing.
Since the focus of this text is on 3D graphics and visualization, this chapter treats image pro-
cessing in a limited way. However, we would like to emphasize the interrelationship of image pro-
cessing, computer graphics, and visualization. Often texts and courses treat these as distinctly
388 Image Processing
separate disciplines, when in fact they are closely related (see “Imaging, Computer Graphics, and
Visualization ” on page4 ).
The material presented here was selected to demonstrate a number of important points. First,
the data flow or pipeline approach presented earlier is directly applicable to image processing, with
the added benefit that we can easily implement data streaming and caching due to the regular nature
of image data. Second, image processing algorithms can improve the results of visualization. We
will show this through a number of useful examples. And finally, from a practical point of view, we
wanted to demonstrate a system architecture that includes imaging, graphics, and visualization.
In this section we will briefly describe the data representation behind the imaging pipeline. As we
saw earlier (in “The Dataset ” on page124 ), a dataset consists of both a structure (topology and
geometry) and data attributes. Although in principle an image can be represented as a image data
dataset, the special nature of image processing suggests a more complex representation, as we will
soon see.
An image is typically used to refer to a 2D structured point dataset. More generally, in this
chapter we will define an image as consisting of up to four dimensions: three spatial dimensions x,
y, and z, and time t. The reason we add the time dimension is that images are frequently generated
as a time series, and we often wish to access the data along the time axis. For example, we may plot
the value at a point as a function of time.
As described in “Image Data ” on page136 , an image has both regular topology and geometry.
The regularity of the data lends itself to many special operations. In particular, we can support data
caching and streaming , and operating on regions of interest in the data.
Regions of Interest
When data has a regular spatial organization, it is possible to request the data in pieces or regions of
interest. For example, a mapper may need only a region of the data for its display, so loading or pro-
cessing the whole dataset would be inefficient. An example of this is a two-dimensional viewer that
displays only one slice of a large structured volume. By loading slices only as they are needed, disk
access can be reduced, and memory conserved.
Although regions of interest can have arbitrary shapes, the regular structure of the data sam-
ples determines optimal region configurations. An image stored in a Cartesian coordinate system
easily divides into smaller rectangular regions, while data sampled on a polar coordinate grid is best
divided into pie-shaped regions ( Figure10–1 ). Therefore, operating on regions of data means that
we process “windows” of data specified by ( min,max) ranges of each dimension, or axis. For exam-
ple, a region in a 2D image of dimensions 100 x 100 might be specified as (25,49, 0,49) , meaning
that we would operate on a (25 x 50) window.
10.2 Data Representation 389
Figure 10–1 Axis aligned matrices naturally lend themselves to rectangular regions, and polar
coordinate grids to pie-shaped regions.
The disadvantage of processing regions of interest is that the same data may be read and processed
multiple times. If the viewer described above needs to cine (i.e., loop) through the slices, or interac-
tively pan around a large image, it would be beneficial to have all the data loaded at once.
A compromise between the two extreme approaches of maintaining all data in memory or
operating on small pieces is to update regions larger than requested, but not as large as the whole
image. This is referred to as a data cache. Data caching anticipates future requests and works well
in most cases. However, it breaks down when there is little or no coherence between subsequent
requests.
With the region-processing model, the data objects can be thought of as caches that hold any
number of regions. There are numerous caching strategies for saving and releasing regions that can
be quite complex. The simplest strategy saves only a single region at any one time. If subsequent
requests are completely contained in the cached region, no further processing is required. An alter-
native strategy might divide an image into tiled regions of all the same size. When a region larger
than the tile is requested, multiple tiles are updated to cover the region. When designing a caching
strategy, it is important to consider the overhead of copying data to change its format. Some of the
advantages of complex strategies are lost when all the factors are considered.
Given the ability to operate on regions of data, it is a small step to stream operations on a
whole dataset. Streaming is the process of pulling regions of data in a continual flow through the
pipeline. For instance, a pixel histogram mapper could request single pixels as it accumulates val-
ues in its bins. Large datasets can be processed in this manner without ever having to load more
than a few pixels at a time. If multiple processors are available, region processing can also be used
to split a task into multiple pieces for load balancing and faster execution.
390 Image Processing
Unlike visualization algorithms that may generate normals, vectors, tensors, and texture coordi-
nates, image processing algorithms generally process attribute data consisting of scalar data. Often
the data is a single component (e.g., a gray-scale image), but frequently color images (three compo-
nents of RGB, for example) may also be processed.
In the Visualization Toolkit imaging pipeline, attribute data is represented as n-dimensional
component data. Refer to “Putting It All Together ” on page405 to see the implementation details for
component data, regions of interest, streaming, and caching.
10.3 Algorithms
This section provides an overview and examples for important image processing algorithms. The
importance of the algorithms is measured on their relevance to 3D data visualization. Topics
include: removing noise, smoothing, reducing sampling artifacts, image enhancement, segmenta-
tion, and morphological operators such as erosion and dilation.
Image Restoration
Noise and other artifacts are inherent in all methods of data acquisition. Since artifacts can degrade
the visual appearance and analysis of images, the first step of image processing is often restoration.
Knowledge of the statistical properties of artifacts allows filters to selectively remove them with
minimal impact on the underlying data. For example, most of the power of typical images lie in low
frequencies, while white noise is evenly distributed across the frequency spectrum. In this situation,
low-pass filters eliminate much of the noise, but leave most of the image intact.
A simple implementation of a low-pass smoothing filter is convolution with a kernel with all
positive values. The typical kernels used for smoothing are either constant across a circular neigh-
borhood, or have a Gaussian profile (see Figure10–2 ). Gaussian smoothing results in better-look-
ing images than smoothing with constant kernels, but can be more computationally expensive
because of the large kernel size necessary to capture the Gaussian profile. Smoothing becomes even
more expensive when it is generalized to three-dimensional datasets, and three-dimensional ker-
nels.
One way to speed Gaussian smoothing is to decompose the filter into two 1D convolutions.
Since the 2D Gaussian function is separable,
1 æö i 2 + j2 1 æö i 2 1 æö j 2
gij(), exp ç÷– --------------
= ------------- exp ç÷– ---------
= -------------- exp ç÷– ---------
-------------- (10-1)
2
2ps èø 2s 2 2 ps èø 2 s 2 2 ps èø 2 s 2
smoothing along the x axis and then along the y axis with 1D Gaussian kernels is equivalent to con-
volving with a 2D Gaussian kernel. It is also possible to approximate Gaussian smoothing by con-
volving with a constant binary kernel multiple times.
10.3 Algorithms 391
Gaussian Kernel
Convolution
f*kxy ,
()fij , ()() –
= å ()kxi ,()yj–
Original Image ij,
Figure 10–2 Low-pass filters can be implemented as convolution with a Gaussian ker-
nel. The Gaussian kernel displayed on top has been magnified for this figure
(GaussianSmooth.tcl ).
Nonlinear Smoothing
One problem with simple smoothing to remove noise is that edges are blurred. Although high fre-
quencies make up a small part of images, the human visual system is acutely sensitive to high fre-
quencies in the spatial form of edges. In fact, most of the low frequencies in an image are discarded
by the visual system before it even leaves the retina. One approach to smoothing that preserves
edges is anisotropic diffusion. This filter smooths relatively flat regions of an image, but does not
diffuse across abrupt transitions. The diffusion is iterated until the desired level of noise reduction
is reached. Two possible diffusion criteria are: Diffuse only when the gradient magnitude is below a
specified value, or diffuse two pixels only when the difference between the pixels is lower than a
specified constant.
A median filter also smooths while preserving edges. This filter replaces each pixel with the
median value of the scalar values in a neighborhood centered on the pixel. Median filters are most
effective on high amplitude noise that has a low probability of occurring (see Figure10–3 ). There
are two ways to control the amount and scale of noise removed: The size of the neighborhood can
be varied, or the filter can be applied multiple times. This median filter preserves edges; however, it
does round corners and remove thin lines. The hybrid median filter was developed to address this
behavior. It operates on a 5 x 5 neighborhood around each pixel. The algorithm consists of two
steps: first the median values of an “x”-shaped and “+”-shaped neighborhoods are computed, then
the median of these two values and the center-pixel value is computed to give the final result. The
392 Image Processing
Figure 10–3 Comparison of Gaussian and Median smoothing for reducing low-proba-
bility high-amplitude noise ( MedianComparison.tcl ).
hybrid median has a fixed size neighborhood, but can be applied multiple times to further reduce
noise ( Figure10–4 ).
An artifact called aliasing occurs when subsampling and is often associated with stair-stepping
edges. Sampling theory proves that discrete sampled signals with spacing S, completely describe
continuous functions composed of frequencies less than S/2. When a signal is subsampled, its
capacity to hold high frequency information is reduced. However, the high frequency energy does
not disappear. It wraps around the frequency spectrum appearing as a low frequency alias artifact
(Figure10–5 ). The solution, which eliminates this artifact, is to low-pass filter before subsampling.
Low-pass smoothing reduces the high frequency range of an image that would cause aliasing.
The same aliasing phenomena occurs when acquiring data. If a signal from an analog source
contains high frequencies, saving the analog data in a discrete form requires subsampling that will
introduce alias artifacts. For this reason, it is common practice to acquire data at high resolutions,
then smooth and subsample to reduce the image to a manageable size.
10.3 Algorithms 393
Hybrid-Median Neighborhoods
Figure 10–4 Comparison of median and hybrid-median filters. The hybrid filter pre-
serves corners and thin lines, better than the median filter. The lower patterns represent the
three neighborhoods used to compute the hybrid median (see the example Tcl script
HybridMedianComparison.tcl ).
Low-frequency artifacts, other than aliasing, can also occur when acquiring data. One exam-
ple is base-line drift. As data is acquired over time, the average value (base line) of the signal can
slowly change. This drift can be removed with a high-pass filter after data acquisition. It is also
possible to acquire a second dataset that isolates the baseline. Subtracting the baseline from the pri-
mary signal removes the drift artifact. In general, it is better to measure the artifact than risk making
wrong assumptions that might adversely affect the actual data.
Another gradual change across an image is caused by sensor position. The amplitude of a
measured signal usually attenuates as the source moves away from the sensor. An example of this
394 Image Processing
Figure 10–5 This figure demonstrates aliasing that occurs when a high-frequency signal
is subsampled. High frequencies appear as low frequency artifacts. The lower left image is
an isosurface of a skull after subsampling. The right image used a low-pass filter before
subsampling to reduce aliasing ( IsoSubsample.tcl ).
Image Enhancement
Often datasets contain information or have dynamic range that cannot be completely displayed in a
single image. X-Ray Computed Tomography (CT) datasets, for example, can have 10 times the sca-
lar resolution of the typical computer monitor capable of displaying 256 shades of gray. One
method used for conveying information buried in the large dynamic range of these medical datasets
is to allow a user to interactively set the color map with a window-level transfer function. The user
can then choose to display the range of data they find most important as shown in Figure10–7 . The
slope of the transfer function determines the amount of contrast in the final image. Slopes greater
than one increase contrast, and slopes less than one decrease contrast. All contrast and information
is lost in the scalar ranges where the transfer function is constant and has zero slope.
10.3 Algorithms 395
9000 3000
Number of Pixels
Number of Pixels
Figure 10–6 This MRI image illustrates attenuation that can occur due to sensor posi-
tion. The artifact is removed by dividing by the attenuation profile determined manually.
This histograms shows how the artifact hides information in the form of scalar value
clusters ( Attenuation.tcl ).
The short fall of simple window-level transfer functions are their limited shape. More general
nonlinear transfer functions can be more appropriate for certain datasets. One example is the loga-
rithmic transfer function, , which
fx()K1x
=can be () +to display image power spec-
logused
trums ( Figure10–10 ). Most of the pixels in the power spectrum represent high frequencies, and
have small values. However the smaller population of low-frequency pixels often have large val-
ues. The logarithmic function has the largest slope near zero, and therefore leaves the most contrast
for pixels with small values. However, when the constant K is chosen correctly, none of the large
pixel values become completely saturated.
To take advantage of all the available display contrast, images should have a uniform distri-
bution of intensities. For continuous images, this intensity distribution is called the probability den-
sity function (PDF). For discretely-sampled images with discrete scalar values, the image histogram
has the same information as the PDF ( Figure10–7 ). A histogram breaks the scalar range of an
image into discrete non-overlapping bins. Each bin has a pixel count that represents the number of
pixels whose scalar value falls in that bin’s range.
To achieve the goal of a uniform scalar histogram, transfer functions can be used to spread
out clusters in the histogram and compress scalar ranges that are under-represented in the image. To
maintain the general appearance of the image, the transfer function should be monotonically
increasing so that the brightness relation is maintained. To spread out clusters in the histogram, the
396 Image Processing
13000 1200
Number of Pixels
Number of Pixels
Figure 10–7 The top charts show two window-level transfer functions. The resulting images are dis-
played in the middle row. The bottom row shows image histograms of the images.
slope of the transfer function should be large where the scalar densities are the highest, and the
slope should be small in empty regions of the histogram.
Histogram equalization is an algorithm that automatically generates a tailored transfer func-
tion to increase contrast in an image. For continuous images, the transfer function is simply the
cumulative distribution function (CDF) which is defined as the integral of the PDF. By definition,
the CDF function has a large slope where the PDF has the largest value, and therefore gives the
greatest contrast to scalar ranges that occur most frequently in an image. The result of using the
CDF as a transfer function is an image with an ideal constant scalar distribution. For discrete
images and image histograms, a discrete version of the CDF function can be used. However,
10.3 Algorithms 397
13000
fx()
1500
Number of Pixels
Figure 10–8 Histogram equalization automatically computes a transfer function that produces an
image with a nearly constant scalar histogram.
398 Image Processing
Figure 10–9 High-pass filters can extract and enhance edges in an image. Subtraction
of the Laplacian (middle) from the original image (left) results in edge enhancement or a
sharpening operation (right) ( EnhanceEdges.tcl ).
because of the discrete approximation, the resulting image is not guaranteed to have a constant his-
togram ( Figure10–8 ).
High-pass filters can also be used to compress the range of an image. Since low frequencies
account for much of the dynamic range of an image but carry little information, a high-pass filter
can significantly decrease an image’s scalar range and emphasize hidden details. The Laplacian fil-
ter, which is a second derivative operation, is one implementation of a high-pass filter. It eliminates
constant and low frequencies leaving only high-frequency edges. The output of the Laplacian can
be subtracted from the original image to produce edge enhancement or sharpening of an image
(Figure10–9 ).
Frequency Domain
The Fourier transform belongs to a class of filters that fundamentally change the representation of
an image without changing its information. The output of the Fourier transform is in the frequency
domain. Each pixel is a complex number describing the contribution of a sinusoidal function to the
original image. The magnitude of the pixel encodes the amplitude of the sinusoid, and the orienta-
tion of the complex pixel encodes the sinusoid’s phase. Each pixel represents a sinusoid with differ-
ent orientation and frequency. The reverse Fourier transform converts a frequency domain image
back to the original spatial domain ( Figure10–10 ).
Low-pass and high-pass filtering become trivial in the frequency domain. A portion of the
pixels are simply masked or attenuated. Figure10–11 shows a high pass Butterworth filter that
attenuates the frequency domain image with the function H
Huv,
() 1
= ----------------------------------------------------- (10-2)
1C+ [] 2n ¤ ()u 2 + v 2 n
The gradual attenuation of the filter is important. The ideal high-pass filter, shown in the same fig-
ure, simply masks a set of pixels in the frequency domain. The abrupt transition causes a ringing
effect in the spatial domain (as the figure illustrates).
Although any filter that operates in the frequency domain can also be implemented in the spa-
tial domain, some operations are less computationally expensive and easier to implement in the fre-
10.3 Algorithms 399
M1– N1–
1 xv vy
Fuv,
() å
= ---------- ()j2 exp – p æö------
å fxy, + ------
MN x0= èøM N
y0=
Figure 10–10 The discrete Fourier transform changes an image from the spatial domain into the fre-
quency domain, where each pixel represents a sinusoidal function. This figure show an image and its
power spectrum displayed using a logarithmic transfer function ( VTKSpectrum.tcl ).
quency domain. To perform similar filtering of Figure10–11 in the spatial domain would require
convolution with a large kernel and would be slow. In general, convolution with large kernels is
ab
more efficient when performed in the frequency domain. Multiplication,, in the frequency
domain, is equivalent to convolution,, ina*b
the spatial domain (and vice versa). In these equa-
tions, a
is the Fourier transform of a, and isb the Fourier transform of b.
In order to make frequency-domain processing feasible, it is first necessary to minimize the
cost of transforming from the spatial to frequency domain and back. There exist fast algorithms that
implement the Fourier transform and its inverse. First, the Fourier transform is decomposable, so a
2D transform can be implemented by first taking the 1D Fourier transform of all the rows, and then
taking the Fourier transform of all the columns of an image. Second, the complexity of one-dimen-
sional Fourier transforms can be reduced with an algorithm called the fast Fourier transform (FFT).
It works by recursively factoring the number samples, N, into its prime components. If N is prime
() 2 If
and not factorable, then the transform is completed in one step that is order complexity.
ON
N is divisible by two, the array of numbers is divided into two parts that are transformed separately
and then combined. If N is a power of two, then the algorithm executes in order time. ()
ONNlog
400 Image Processing
ì 2 2 2
Huv,
()
ï
= í 1i f æö
u +Cv <
èø Huv,
() 1
= --------------------------------------------------------
ï 1C+ [] 2n ¤ ()u 2 + v 2 n
î 0otherwise
Figure 10–11 This figure shows two high-pass filters in the frequency domain. The
Butterworth high-pass filter has a gradual attenuation that avoids ringing produced by the
ideal high-pass filter with an abrupt transition ( IdealHighPass.tcl ).
For this reason, it is more efficient to process images with sizes that are powers of two (e.g., 512 x
512) than other sized images. For non-power of two images it may be faster to pad the image to a
size that is a power of two size before processing.
An important point about the discrete Fourier transform is that it treats the image as a peri-
odic function. This means the pixels on the right border are adjacent to pixels on the left border.
Since there is usually no physical relationship between these pixels, the artificial horizontal and
vertical edges can distort the frequency spectrum and subsequent processing. To reduce these arti-
facts, the original image can be multiplied by a window function that becomes zero at the borders.
Another approach removes these artificial edges by smoothing only along the borders.
10.3 Algorithms 401
Figure 10–12 Convolution in frequency space treats the image as a periodic function.
A large kernel can pick up features from both sides of the image. The lower-left image
has been padded with zeros to eliminate wraparound during convolution. On the right,
mirror padding has been used to remove artificial edges introduced by borders
(Pad.tcl ).
In both of these approaches, a portion of the original image is lost, so only the central portion
of an image can be processed. If this is unacceptable, another solution is to double the dimensions
of the original image with a mirror-padding filter. The intermediate image is periodic and continu-
ous ( Figure10–12 ).
Image Segmentation
Segmentation is the process of classifying pixels in an image or volume. It can be one of the most
difficult tasks in the visualization process. One form of segmentation takes an image as input, and
outputs a map that contains a classification for each pixel. The output of such a segmentation filter
usually has binary or discrete values for each pixel; however, it is also possible to output a fuzzy
classification where the pixel’s scalar value represents a measure of confidence in the classification.
A simple example of a one-parameter segmentation is a threshold filter used to mark bone in
a CT dataset. Since bone has the largest scalar value, it is easy to select a threshold that separates
bone from the rest of the image.
For other tissues and other imaging modalities, segmentation is usually more difficult. Noise
in the image and overlapping scalar values of tissues can decrease the effectiveness of simple
threshold segmentation. By using two parameters, the threshold can segment pixels with a range of
402 Image Processing
Correlation Kernel
Figure 10–13 A pipeline containing correlation, thresholding, dilation, and erosion is used here to
segment a region composed of “C”s. The left image shows the original image. The right image shows
the segmented region superimposed on the original image.
scalar values. The extra parameter allows more control over the resulting segmentation, but also
doubles the complexity of selecting the parameters.
Images can be preprocessed to segment images based on more complex features such as tex-
tures. Sometimes textures in tissues add information useful for segmentation. Texture sensitive fil-
ters like Laplacian and gradient magnitude can discriminate between different textures. Additional
filters that can be used for texture segmentation are the range, variance, and correlation filters. The
range filter simply reports the difference between the maximum and minimum values in a neigh-
borhood around each pixel, and the variance filter computes the variance of the neighborhood pix-
els relative to the center pixel.
Figure10–13 shows an example of how a correlation filter can be used for segmentation. A
correlation filter is similar to convolution. The kernel is shifted across the image, and for each loca-
tion the dot product between the image and the kernel gives a measure of correlation between the
two. The output of the correlation filter is large everywhere the pattern occurs in the image, but
small at other locations. Because the resulting map is sparse, additional postprocessing is required
to find a uniform, segmented region. In this example, dilation followed by erosion was used to
close the gaps between the patterns. (Dilations and erosion are discussed in the next section.)
Postprocessing
Although preprocessing can do a lot to improve segmentation results, postprocessing can also be
useful. Morphological filters, which operate on binary or discrete images, can be useful for manip-
ulating the shape of the segmented regions. In this brief discussion we will only consider operations
that use circular footprints, even though these morphological filters can be defined much more gen-
erally. Erosion is implemented by removing pixels within a specified distance of a border. For each
10.3 Algorithms 403
Erosion Dilation
Opening Closing
Figure 10–14 This figure demonstrates various binary filters that can alter the shape of
segmented regions ( MorphComparison.tcl ).
pixel not in the segmented region, all the neighbors in a circular region around the pixels are turned
off. This erosion filter shrinks the segmented region and small isolated regions disappear.
The opposite of erosion is dilation. This filter grows the area of segmented regions. Small
holes in the segmented region are completely closed. Any pixel not in the segmented region but
near the region is turned on. Dilation and erosion are dual filters with nearly identical implementa-
tions. Dilating the “on” pixels is equivalent to eroding “off” pixels in a binary image (see
Figure10–14 ).
404 Image Processing
Closing is the serial application of first dilation and then erosion. When an image is dilated
small holes in the map disappear. However, dilation alone also grows the boundaries of the seg-
mented regions. When dilation is followed by erosion in a closing operation, small holes are
removed; however, the boundary of the segmented regions remain in the same general location.
Opening is the dual of closing. Opening removes small islands of pixels. It is implemented with an
initial erosion, followed by a dilation.
Connectivity filters can also remove small regions without affecting the remaining bound-
aries of segmented regions. This set of filters separate the segmented pixels into equivalence
classes based on a neighbor relation. Two pixels belong to the same class if they are touching.
There are two common neighbor relations in two-dimensional images: four connectivity considers
pixels neighbors if they are edge neighbors, and eight connectivity considers pixels neighbors if
pixels share any vertex.
After the pixels have been assigned an equivalence class, various methods are used to deter-
mine which groups of pixels will pass through the filter, and which classes will be eliminated. The
island-removal filter is a connectivity filter that removes groups that have too few pixels. Seed con-
nectivity allows the user to explicitly specify which groups will pass through the filter. The user or
application specifies a set of seeds. Any group that includes a seed makes it through the filter.
Groups that do not contain seeds are removed. This filter is similar to the seed-connectivity filter;
however, the seeds are supplied in a second image. First the intersection between the segmented
image and the seed image is taken. Each remaining pixel is then added to a set of seeds.
Multispectral Segmentation
From everyday experience we know that it is easier to see structure and information in color images
than in gray-scale images. This is because each pixel contains more information in the red, blue,
and green components than a single component gray-scale pixel. One way to segment multispectral
images is to separate the components and threshold them individually and then combine the result-
ing binary images with logic filters. This allows selection of rectangular patched areas in the color/
component space of the pixels.
By using multiple thresholds combined with multiple levels of logic filters, it is possible to
specify arbitrary areas in the component’s space for segmentation. However, it can be easier and
more efficient to transform the components into a different coordinate system before the threshold
operation. The simplest example of this is to threshold a projection of the components. This is
equivalent to a threshold after performing a dot product between the components of a pixel and a
constant-direction vector. This divides the component space into two areas separated by a hyper-
plane.
Another example of a coordinate transformation is conversion from red, green, blue (RGB)
color component to hue, saturation, value (HSV) representation (see “Color” on page37 ). Segmen-
tation of images based on hue and color saturation is difficult in RGB space, but trivial in HSV
space.
Color is not the only multispectral information that can be used for segmentation. It is possi-
ble to take advantage of multispectral segmentation even if the original dataset has only one com-
ponent. Additional images can be created from spatial information of the images using spatial
filters. These multiple images can then be combined into one multicomponent image, then multi-
component segmentation can proceed.
10.4 Putting It All Together 405
Typically, the number of free parameters in a filter is directly correlated to the dimensionality
of the pixels; and although additional parameters make a filter more powerful, it also makes it more
difficult to find an appropriate set of parameter values. There are supervised and unsupervised algo-
rithms that can be used to automatically select the best set of segmentation parameters, but discus-
sion of these is outside the scope of this book.
Data Representation
In the imaging pipeline, the class for representing and manipulating data is vtkImageData (see
“Types of Datasets ” on page134 for more information). In addition, the data extent (topological
extent specification) plays a vital role in controlling how images are processed.
vtkImageData actually represents the image data. Internally, it refers to an instance of
vtkDataArray . Therefore, its native representation data type may be any one of unsigned char, char,
unsigned short , short , int, float, or any concrete type of vtkDataArray . Please remember that vtkIm-
ageData can represent 1D, 2D (image), and 3D (volume) data.
There are three types of data extents in the imaging pipeline. In general, any rectangular piece
of image data can be described by the extent six-vector ( imin ,imax , j min ,jmax , k min ,kmax ). The
WholeExtent refers to the original data size of an image and is derived from the image dimensions.
The UpdateExtent is the extent that is processed by a particular filter during execution.
Extents are used to manage the streaming of data through the visualization pipeline, as well
as to coordinate the multi-threaded parallel processing that the imaging pipeline uses throughout.
By controlling the extents, it is possible to greatly reduce the amount of memory used by the pipe-
line. For more information, see The VTK User’s Guide sold by Kitware.
In the VTK imaging pipeline, point attribute data is represented differently than in the visual-
ization pipeline. In the imaging pipeline point attribute data is represented as n components per data
point. Typically n is one for gray-scale data, or three for color data but, in general, can be any posi-
tive number.
Create an Image
This example demonstrates how to directly create an image using C++ code. Typically, you will use
an image reader or procedurally create an image from a source object. The example shown here
creates an vtkImageData and then fills it with an image of interfering sinusoidal grids
vtkImageData
vtkImageViewer
int x, y;
vtkImageData *image;
image = vtkImageData::New();
image->SetDimensions(256, 256, 1);
image->SetScalarTypeToFloat();
image->AllocateScalars();
Figure 10–15 Creating an image of two interfering sinusoidal gratings in an image dataset. The
resulting image has dimensions 256 2.
Note that direct pointer access is used to fill the image. The AllocateScalars() method allocates
enough memory for the dimensions provided.
Gradient Magnitude
In this example we demonstrate a lengthy imaging pipeline. The basic purpose of the pipeline is to
visualize information about the image gradient. The gradient direction and magnitude are mapped
into the hue and saturation components of the color HSV space, respectively. The pipeline, result-
ing image, and a portion of the code are shown in Figure10–16 .
The pipeline demonstrates some interesting tricks. The first three filters read CT data of the
human head ( i.e., using vtkImageReader ), magnify the image by a factor of four
(vtkImageMagnify) , and then smooth the data (since magnification uses linear interpolation, intro-
10.4 Putting It All Together 407
ducing some sharp edges). The next filter actually computes the 2D gradient ( vtkImageGradient ),
placing the x-y gradient components into its output.
The next series of filters is where the fun begins. First, the data is converted to polar coordi-
nates ( vtkImageEuclideanToPolar ). We use this filter because we want to operate in color HSV
space (see “Color ” on page37 ). The image magnitude is to be mapped into saturation value, while
the gradient direction is mapped into hue value (remember hue is represented as an angle on the
HSV color wheel). The filter vtkImageConstantPad is used to add a third component to the data,
since the gradient filter only generated two components, and we need three components to repre-
sent color. The vtkImageExtractComponents is used to rearrange the components into HSV order.
Finally, the data is converted back into RGB color space with vtkImageHSVToRGB . (This is nec-
essary because the image viewer expects RGB values.)
Image Warping
In this example we combine the imaging and visualization pipelines. Imaging filters are used to
read in an image ( vtkBMPReader ) and then convert it to grayscale ( vtkImageLuminance ). The
data, which is a image data dataset, is then passed down the visualization pipeline as polygons
using vtkImageDataGeometryFilter . Next we warp the data in the direction perpendicular to the
image plane using the visualization filter vtkWarpScalar . The vtkMergeFilter is used to combine
the warped geometry (now vtkPolyData ) with the original image data from the reader. (Note that in
this example the vtkMergeFilter takes two inputs.) The pipeline, example output, and sample code
are shown in Figure10–17 .
Regression Testing
In our work with VTK, we often need to perform software testing. The testing may be necessary
because we’ve added new classes or features to the system, modified old code, or are simply testing
a graphics library or new piece of hardware. We use a powerful testing procedure based on process-
ing the output of the system, which is typically an image. We refer to the testing process as regres-
sion testing.
Regression testing is based on the following procedure. A test program (typically a Tcl/Tk
script) is written that exercises a portion of the code. In our example, we will assume that we are
testing a feature of implicit modelling. The output of the script is an image with a fixed view, as
shown in Figure10–18 (a). To perform the test, we compare the output of the test program with a
previously stored image, or “valid” image ( Figure10–18 (b)). The valid image was generated when
we initially created the object or objects to be tested, and is assumed to be the correct output. Then,
we use a the filter vtkImageDifference to compare the test image with the valid image. This filter
takes into account dithering and anti-aliasing effects, and creates an output image representing the
difference between the test image and valid image ( Figure10–18 (c)). It also reports the difference
in the images in terms of a pixel count. To determine whether the test is passed, we compare the
pixel count with a threshold value (for example, 10 pixels).
Our regression testing procedure cannot test the original implementation of an object or
objects. The developer must verify that the valid image is indeed correct. However, the process is
invaluable for finding and correcting problems due to incremental code changes (e.g., bug fixes,
408 Image Processing
vtkImageReader
vtkImageMagnify
vtkImageGaussianSmooth
vtkImageGradient
vtkImageEuclideanToPolar
vtkImageConstantPad
vtkImageExtractComponents
vtkImageHSVToRGB
vtkImageGradient gradient
gradient SetInputConnection [smooth GetOutputPort]
gradient SetDimensionality 2
vtkImageEuclideanToPolar polar
polar SetInputConnection [gradient GetOutputPort]
polar SetThetaMaximum 255
vtkImageConstantPad pad
pad SetInputConnection [polar GetOutputPort]
pad SetOutputNumberOfScalarComponents 3
pad SetConstant 200
vtkImageHSVToRGB rgb
rgb SetInputConnection [permute GetOutputPort]
rgb SetMaximum 255
Figure 10–16 An imaging pipeline to visualize gradient information. The gradient direction is
mapped into color hue value while the gradient magnitude is mapped into the color saturation
(ImageGradient.tcl ).
10.4 Putting It All Together 409
vtkBMPReader
vtkImageLuminance
vtkImageDataGeometryFilter
vtkWarpScalar
vtkMergeFilter
vtkDataSetMapper
vtkBMPReader reader
reader SetFileName $VTK_DATA_ROOT/Data/masonry.bmp
vtkImageLuminance luminance
luminance SetInputConnection [reader GetOutputPort]
vtkImageDataGeometryFilter geometry
geometry SetInputConnection [luminance GetOutputPort]
vtkWarpScalar warp
warp SetInputConnection [geometry GetOutputPort]
warp SetScaleFactor -0.1
vtkMergeFilter merge
merge SetGeometryConnection [warp GetOutputPort]
merge SetScalarsConnection [reader GetOutputPort]
vtkDataSetMapper mapper
mapper SetInputConnection [merge GetOutputPort]
mapper SetScalarRange 0 255
mapper ImmediateModeRenderingOff
Figure 10–17 Combining the imaging and visualization pipelines to deform an image in the
z-direction ( imageWarp.tcl ). The vtkMergeFilter is used to combine the warped surface
with the original color data.
enhancements, etc.) Furthermore, the test can be run as a batch process, with a simple pass/fail out-
put, and an image to show the differences.
410 Image Processing
vtkRendererSource renSrc
renSrc WholeWindowOn
renSrc SetInput ren1
vtkPNGReader pnm
pnm SetFileName “valid/$afile.png”
vtkImageDifference imgDiff
imgDiff SetInputConnection 0 [renSrc GetOutputPort]
imgDiff SetInputConnection 1 [pnm GetOutputPort]
imgDiff Update
Figure 10–18 Software regression testing using image processing. A test image is taken from the
renderer and compared with a valid image stored on disk. (a) shows the valid image. (b) shows the
test image (artificially modified by slight camera rotation). (c) shows the image difference. The
code fragment above is extracted from the regression testing procedure.
10.5 Chapter Summary 411
10.7 References
[Ballard82]
D. H. Ballard, C. M. Brown. Compute Vision . Prentice Hall, Inc., Englewood Cliffs, NJ, 1982.
[Davies97]
E. R. Davies. Machine Vision Theory Algorithms Practicalities 2d ed . Academic Press, San Diego,
CA, 1997.
[Gonzalez92]
R. C. Gonzalez, R. E. Woods. Digital Imaging Processing. Addison-Wesley Publishing Co., Read-
ing, MA, 1992.
[Ibanez03]
L. Ibanez, W. Schroeder, L. Ng, J. Cates. The ITK Software Guide. Kitware, Inc. ISBN 1-930934-
10-6.
[Law99]
C. Charles Law, K. M. Martin, W. J. Schroeder, J. E. Temkin. A Multi-Threaded Streaming Pipe-
line Architecture for Large Structured Data Sets. In Proceedings. of Visualization '99 , IEEE, Oc-
tober 1999.
[Martin01]
K. M. Martin, B. Geveci, J. Ahrens, C. Law. Large Scale Data Visualization Using Parallel Data
Streaming. IEEE Computer Graphics & Applications , July 2001.
412 Image Processing
[Niblack86]
W. Niblack. An Introduction to Digital Image Processing . Prentice Hall, Inc., London, 1986.
[Pavlidis82]
T. Pavlidis. Algorithms for Graphics and Image Processing . Computer Science Press, Rockville,
MD, 1982.
[Robb95]
R. Robb. Three-Dimensional Biomedical Imaging Principles and Practice . VCH Publishers, New
York, NY, 1995.
[Russ95]
J. C. Russ. The Image Processing Handbook 2d ed. CRC Press, Inc, Boca Raton, FL, 1995.
[Wolberg90]
G. Wolberg. Digital Image Warping . IEEE Computer Society Press, Los Alamitos, CA, 1990.
10.8 Exercises
10.1 Create an image pipeline that will segment the area with vertical lines in Figure10–19 .
10.3 Create an image pipeline that shows the spectrum of a Gaussian image. What effect does
increasing or decreasing the standard deviation have on the spectrum?
Chapter 11
11.1 Motivation
Before describing in detail how to perform visualization over the Web, it is important to understand
what we expect to gain. Clearly people have been visualizing data prior to the invention of the Web,
but what the Web adds is the ability for people throughout the world to share information quickly
and efficiently. Like all successful communication systems, the Web enables people to interact and
share information more efficiently compared to other methods. In many ways the Web shares the
characteristic of computer visualization in its ability to communicate large amounts of data. For
that reason, computer graphics and visualization are now vital parts of the Web, and are becoming
widespread in their application.
414 Visualization on the Web
To demonstrate these concepts we provide a simple example that illustrates the usefulness of
the Web, and leads us into our first important topic: client-side versus server-side visualization.
One common problem for researchers has been how to share or publish results. Typically, this
involved having one site perform the research, interact with the data, form conclusions, and then
publish the results as a report. The report might include a few pictures and possibly even a short
animation. Obtaining access to the report might be through a journal or conference. Subsequently,
co-workers at other sites would read the report and respond via verbal communication or formal
articles.
While certainly a viable means of sharing information, there are two important shortcomings
in such a scenario. First, the report does not allow another researcher to interact with the visualiza-
tions. They are static pictures or pre-recorded animations. There is no opportunity to look from a
different angle or change the parameters of the visualization. Second, access to the report may be
limited or untimely. For example, some journals require as much as two years to accept, review,
and publish an article. This time delay is too long for many technology-driven fields such as medi-
cine, computers, or business. Such delays in receiving information can result in fruitless research or
a failed business.
Using the Web this scenario changes significantly. It is now possible to create reports so that
other researchers can interact directly with the data, including visualizing the results in an alterna-
tive form. The Web also provides the opportunity to publish results immediately so that anyone
with Web access can view them. Additionally, results can be modified as your work progresses so
that they are always up to date.
Another motivation for visualization over the Web is collaboration. If a researcher is per-
forming a visualization of a dataset at one site, there are a number of hurdles preventing someone at
another site from doing the same. For starters, the data, which could be sizable, must be copied, or
sent from one site to the other. Then the software being used must be available at both sites which
may not even be possible depending on the hardware available. The popularity of cross-platform
systems such as AVS, IBM’s Data Explorer, and VTK have helped this situation, but even then the
software and data reside at both locations. This is frequently referred to as client-side visualization
because all steps of the visualization are performed at the collaboration (or client) sites. In contrast,
server-side visualization occurs when all of the visualization is done at one centralized location
called the server. The results of the server-side visualization are then sent to collaboration sites.
The Web opens up the opportunity to perform mixed client/server visualization that has a
number of benefits. First, let’s consider the drawbacks to client-side only visualization. As men-
tioned in the preceding discussion, client-side visualization requires both the data and the software
at the client. If the datasets are very large it may be impractical to transfer the data over the Web.
Since the server doesn’t know what the client is going to do with the data, all of the data must be
sent. Additionally, the client may not have sufficient memory or performance to perform the visual-
ization. The advantages of client-side visualization are that the user has complete control over the
visualization and can interact with or modify it at will.
With server-side visualization the most significant loss is in interaction. A server-side only
visualization is much like publishing a report. The clients have very little control over the images
and animations it produces. The advantage is that the results are easily viewed from any client with-
out requiring special hardware or software. As we will see in the remaining sections, the advantage
of using recently developed Web technology is that we can mix server-, and client- side visualiza-
tion much more readily than before, providing the benefits of both.
11.2 Early Web Visualization 415
<br>
<A HREF=”tissue.mpg”><IMG SRC=”tissue.jpg”>
<br>Click here for an MPEG Animation</A>
The title and text description are followed by <A HREF=”tissue.mpg”> which associates the
MPEG file, tissue.mpg , with whatever comes between the first <A> and the closing </A>. In this
example there is a JPEG image and a line of text. Clicking on either of these will play the MPEG
animation.
Now let’s use CGI and an HTML form to enable the client to change the isosurface value.
The first step is to obtain the desired isosurface value from the client using an HTML form such as
Figure11–2 . The form was generated by the following HTML code:
416 Visualization on the Web
In this page we show the use of HTML forms to allow the client
(or viewer) to send information to the server. In this example
the user can select to show the bones, make them transparent and
select the isosurface value to use. These parameters then get
passed to the CGI-BIN script makempg.csh</P>
<OPTION>On
<OPTION>Transparent
</SELECT><BR>
Isosurface Value: <SELECT NAME=isoval>
<OPTION>1400 <OPTION>1200
<OPTION SELECTED>1100
<OPTION>1000 <OPTION>900
</SELECT><BR>
<P><INPUT TYPE=”submit”
VALUE=”Generate an MPEG Animation”></FORM></P>
The FORM keyword starts the definition of the HTML form. The ACTION keyword indicates
what should happen when the form is submitted. In this example the server will run a CGI-BIN
script called makempg.csh when a client submits this form. Next the two pull-down menus are
declared with the SELECT keyword. The NAME keyword sets up an association between a string
name and the value for this menu. This will be used by the script makempg.csh to access the val-
ues from the form. The OPTION and SELECTED keywords provide a mechanism to specify the
values for the menu and what value the default should be. Finally, the last two lines create the but-
ton that will submit the form when pressed.
Once the client has submitted the form, the server will execute the CGI-BIN script and pass it
the arguments from the form. The script will then generate a new MPEG animation based on the
client’s request and return it to the client.
While these examples demonstrate a closed loop of interaction between the client and server,
there are two remaining problems. First, this approach places the entire computational load on the
server. While this may be viable for some applications, some servers literally receive millions of
418 Visualization on the Web
World
...
Transformation
client requests a day, severely straining server resources. Second, while the process is interactive,
the lag time between making a change and seeing the result can be considerable, depending on the
length of the animation and the communication bandwidth. Better solutions are now available to
improve interactivity.
many different types of nodes including some support for animation. (See also “Alternative Visual
Programming Models” on page99 for more information.)
The basic idea behind VRML 1.0 is that the 3D content can be downloaded from the server
and then interacted with the client. There are many Web browsers that support VRML and most
take advantage of client-side graphics hardware if available. This helps address both the server-load
problem and the interaction lag time associated with the earlier approach of server-generated
MPEG animations. Like HTML, VRML supports active links so that navigating through a door in
one VRML world can send you to new VRML (or HTML) sites.
To address many of the limitations in VRML 1.0, significant changes were made resulting in
the VRML 2.0 standard. Where VRML 1.0 was primarily a static scene description with some very
limited behaviors, VRML 2.0 adds audio, video, and integration with Web scripting languages and
more. It is still essentially a data file, but with the capabilities of simulating much more realistic and
immersive environments. Many visualization systems, including VTK, support exporting scenes as
VRML files. Consider the following example:
vtkRenderer ren1
vtkRenderWindow renWin
renWin AddRenderer ren1
# create pipeline
#
vtkPLOT3DReader pl3d
pl3d SetXYZFileName “$VTK_DATA_ROOT/Data/combxyz.bin”
pl3d SetQFileName “$VTK_DATA_ROOT/Data/combq.bin”
pl3d SetScalarFunctionNumber 100
pl3d SetVectorFunctionNumber 202
vtkContourFilter iso
iso SetInputConnection [pl3d GetOutputPort]
iso SetValue 0 .38
vtkPolyDataNormals normals
normals SetInputConnection [iso GetOutputPort]
normals SetFeatureAngle 45
vtkPolyDataMapper isoMapper
isoMapper SetInputConnection [normals GetOutputPort]
isoMapper ScalarVisibilityOff
vtkActor isoActor
isoActor SetMapper isoMapper
eval [isoActor GetProperty] SetColor 0.3 0.4 0.5
vtkStructuredGridOutlineFilter outline
outline SetInputConnection [pl3d GetOutputPort]
vtkPolyDataMapper outlineMapper
outlineMapper SetInputConnection [outline GetOutputPort]
vtkActor outlineActor
outlineActor SetMapper outlineMapper
# Add the actors to the renderer, set the background and size
#
420 Visualization on the Web
This is a typical program within VTK that extracts an isosurface and bounding outline from a struc-
tured grid dataset. To export this result to a VRML data file we can use the vtkVRMLExporter as
shown below:
vtkVRMLExporter exp
exp SetRenderWindow renWin
exp SetFileName Combustor.wrl
exp Write
These four lines create an instance of vtkVRMLExporter , set its input to renWin (an instance of
vtkRenderWindow ), set a file name, and finally write out the result. This is different from previous
examples where data was written out using vtkPolyDataWriter or other subclasses of vtkWriter .
vtkVRMLExporter is a subclass of vtkExporter, not vtkWriter . The significant difference is that a
writer takes a vtkDataSet as input and is responsible for writing out a single dataset. An exporter
takes a vtkRenderWindow as input and is responsible for writing out an entire scene, possibly con-
taining multiple actors, lights, textures, and material properties, in addition to any datasets.
If you consider a continuum from a static data file to a fully interactive visualization pro-
gram, vtkWriter would be at one end, vtkExporter in the middle, and a VTK program at the other.
VRML 1.0 would fall at the same place as vtkExporter and VRML 2.0 would fall between
vtkExporter and an actual program due to its added support for behavior and script interaction.
What VRML lacks from a visualization perspective is algorithms. VRML is a 3D multimedia con-
tent format and lacks direct support for applying visualization techniques or algorithms.
able named CONTENT_LENGTH is set to the length of this input. In this example there are two
values passed from the form: iso and isoval . According to convention they are separated by a “ &”
when passed to the CGI-BIN script. The following C++ code extracts these values from the input
string and performs some quick error checking.
if (strncmp(arg1,”isoval=”,7) == 0)
{
isoval = atof(arg1 + 7);
strcpy(isoType,arg1 + 11);
}
else
{
isoval = atof(arg1 + inputLength - 4);
strncpy(isoType,arg1 + 4,inputLength - 16);
isoType[inputLength - 16] = ‘\0’;
}
This code is specific to the parameters in this example, but generic argument extraction routines
such as cgic (see http://www.boutell.com/cgic/ ) can be used. Once the form data has been
obtained, it can be used to set up the visualization pipeline as usual. In the following code, an isos-
urface is added to the renderer based on the isoType input from the form. Likewise if isoType is set
to “Transparent” then that actor’s opacity is set to 0.5.
Once the pipeline is set up, the last step is to generate the proper headers and VRML output. The
header is the keyword Content-type: followed by the keyword x-world/x-vrml that is the specifica-
tion for VRML content. This is often followed by a pragma indicating that the client browser
should not cache the data, typically because of the memory it would consume.
fprintf(stdout,”Pragma: no-cache\n\n”);
The downside to using Java3D or native code is that it sacrifices Java’s portability somewhat.
Where a pure Java program can be byte-compiled and run on any machine that supports Java, a pro-
gram that relies on Java3D or native code requires that the compiled Java3D or native code support
be installed on the client. For each type of machine you want to support, you will need a compiled
version of the native code. For a toolkit like VTK this means that the client would have to down-
load the native VTK support (e.g., an object library) before being able to run VTK-Java applica-
tions. Once that is done, most applications described in this book can be made into a Web-based
visualization. Depending on the needs of the application, the data can be left on the server and the
results sent to the client, or the data could be sent to the client for both processing and viewing.
The following example outlines how to use Java and VTK to display vibrational modes of a
rectangular plate. In the preceding examples an HTML form was used to obtain input from the cli-
ent. With Java we can construct a customized client-side user interface to obtain the required infor-
mation.
The first step in this example creates the HTML code that in turn launches the Java applet.
The key lines are near the end where the applet keyword is used to start the App2 Java applet with a
default window size of 400 by 500. Parameters are passed to the applet using the param keyword
followed by key-value pairs. When the client encounters the applet keyword, it then requests that
Java applet from the server and starts executing it. We will consider the Java code in App2 from a
visualization perspective. A more complete introduction to Java programming can be found in
numerous books (see “Bibliographic Notes” on page434 ).
The applet will have a standard structure starting by importing other classes that this applica-
tion will use.
import vtk.*;
import java.awt.*;
import java.applet.*;
etc...
Next comes the class definition for App2 . As with most Java applets, this class extends the Applet
class. It has a number of instance variables including many VTK objects that will be used to set up
the visualization pipeline.
424 Visualization on the Web
The init() method handles applet initialization. This is where parameters from the HTML page will
be processed and the visualization pipeline and user interface will be set up. To place the rendering
window within the user interface, we use the vtkPanel class that is a subclass of the Java Canvas
class. This way the rendering window can be treated as if it were just another piece of the user
interface.
this.setLayout(grid);
panel = new vtkPanel();
panel.resize(400,400);
constrain(this,panel,0,0,8,8);
Next, this method checks to see if the model parameter is set, and opens a stream connection to the
server that is used to download the data file into a Java string. This is then passed to a
vtkPolyDataReader at which point the data is now available to the native VTK code on the client.
The rest of the pipeline is set up as usual with the exception that a Java syntax is used instead of
C++ or Tcl. (Due to VTK’s object-oriented design the variations from one language to another are
minor.) At this point in the init() method the rest of the pipeline is set up along with some check-
boxes and event handlers for the user interface. The vtkPanel has a method that returns the
RenderWindow that can then be acted on as usual. For example:
panel.GetRenderer().AddActor(a);
examine another geometry, say the vibrational modes of a disc, then it would likely return to the
server for the new data. This is the flexibility that Java provides.
11.6 Java3D
Similar to a native code implementation (such as a VTK implementation) Java3D provides access
to hardware accelerated 3D graphics. Java3D provides both scene graph rendering similar to
VRML, and high-level immediate mode rendering. The immediate mode rendering support is not
as complete as libraries like OpenGL or DirectX, but it does provide a good subset of its function-
ality. Java3D does share some of the limitations of native code implementations in that the client
must have a version of Java3D for their operating system installed for it to work. There are also
some limitations in how both Java3D and native interfaces interact with lightweight GUI compo-
nents such as swing.
To better understand the Java3D API, we’ll walk through an example applet distributed with
the original 1.0 specification. In this example, a colored cube is rendered as it rotates at a fixed rate.
First, let’s consider the definition of the cube. Some of the details have been left out for brev-
ity. The complete description of the cube is stored in a Java class we’ll call ColorCube . It contains
two class variables ( verts and colors ) that store the vertex positions and RGB colors. It has an
instance of the Shape3D class that will be used by Java3D and a method, getShape() , to access it.
426 Visualization on the Web
Finally, ColorCube has a constructor that creates a QuadArray , inserts the verts and colors into it,
and assigns it to the Shape3D instance variable.
Having defined the geometry, the entry point for a Java3D application is the applet. The
HelloUniverse class extends the Applet class and provides the initialization code for this applica-
tion. The constructor for this applet creates a Canvas3D object that is where the 3D information
will be rendered. It then calls the createSceneGraph() method that performs the detailed setup of the
scene graph including creating an instance of ColorCube . Then the constructor creates an instance
of a UniverseBuilder given the Canvas3D and attaches the scene graph to the Universe . The
UniverseBuilder is mostly boiler-plate code that handles setting up the view location (or platform)
and attaching it to the Canvas3D .
{
setLayout(new BorderLayout());
Canvas3D c = new Canvas3D(graphicsConfig);
add("Center", c);
// Create a simple scene and attach it to the virtual universe
BranchGroup scene = createSceneGraph();
UniverseBuilder u = new UniverseBuilder(c);
u.addBranchGraph(scene);
}
}
It is worth noting that in the createSceneGraph() method, the use of the previously defined
ColorCube class and its insertion into the scene graph via the BranchGroup class. The
setCapability() method is used to enable the cube’s transform to be modified and underlies an
important concept. To achieve the highest rendering rate, Java3D performs a number of optimiza-
tions on the scene graph. Many of these optimizations only work if certain properties of the nodes
are guaranteed to not change. So by default most properties of a node are set to be “read only.” To
modify them after creation requires the specific call shown below.
locale.addBranchGraph(bg);
}
import java.awt.*;
import java.applet.*;
import java.lang.*;
import vrml.external.field.*;
import vrml.external.Node;
import vrml.external.Browser;
import vrml.external.exception.*;
Next, the applet defines the init() method that will request a reference to the browser, invoke
initScene() to build the VRML interface, and create the user interface. In this case the user interface
is just two buttons on a white background.
browser = Browser.getBrowser(this);
if (browser == null) {
die("init: NULL browser!");
}
System.out.println("Got the browser: "+browser);
// Build a simple UI
grow_button = new Button("Grow Sphere");
add(grow_button);
shrink_button = new Button("Shrink Sphere");
add(shrink_button);
// Misc other UI setup
Color c = Color.white;
System.out.println("Setting bg color to: " + c);
setBackground(c);
}
The initScene() method sets up the VRML scene and relies heavily on the EAI. For synchronization
reasons, this method starts off by waiting a few seconds to assure that the VRML browser has time
to initialize and read the VRML file specified by the HTML. Then it uses the
browser.getNode(“aName”) method to obtain nodes from the scene graph. These nodes must be
named using the DEF keyword in the VRML file. The first node it gets is the SPHERE node that
happens to be a VRML transform. It uses the getEventIn() method to obtain a handle to the scale
instance variable of this transform which will be used later.
Then the same techniques are used to obtain the ROOT node of the scene graph. If you scan the
VRML file that follows this example, you will see that the ROOT node is just an empty Group .
After obtaining the node we request handles to its addChildren() and removeChildren() methods.
Using the EAI, VRML can be created from a Java string as shown in the following code. This
allows us to create geometry on the fly and add it to the scene graph using the addChildren() handle
obtained above. The handles support matching setValue() and getValue() methods that modify and
interrogate the scene graph respectively.
The events for the two buttons are processed in the action() method. One increases the scale of the
sphere and the other decreases it. This is done using the handle to the SPHERE node’s scale that
was obtained in the initScene() method, and invoking the setValue() method with the appropriate
arguments.
}
else if (b == shrink_button) {
currentScale = currentScale / (float)1.2;
float ascale[] = new float[3];
ascale[0] = currentScale;
ascale[1] = currentScale;
ascale[2] = currentScale;
setScale.setValue(ascale);
}
} // event.target instanceof Button
return true;
}
The last method in the applet draws a border around the two buttons when the applet needs to be
repainted.
/** Override paint() to get more control over how we're drawn */
public void paint(Graphics g)
{
int w = size().width;
int h = size().height;
An excerpt from the VRML file has been included below. Note the use of the DEF keyword to
name nodes that can then be accessed from Java. The resulting Java/VRML example can be seen in
Figure11–5 .
shininess 0.2
transparency 0
}
}
geometry Sphere {}
}
translation -4 0 0
}
]
}
11.11 References
[Ames96]
A. Ames, D. Nadeau, and J. Moreland. The VRML Sourcebook. John Wiley & Sons, Inc., New
York, NY, 1996.
[Flanagan96]
David Flanagan. Java in a Nutshell. O’Reilly & Associates, Inc., Sebastopol, CA, 1996.
[Graham95]
I. S. Graham. The HTML Sourcebook. John Wiley & Sons, Inc., New York, NY, 1995.
11.11 References 435
[Gundavaram96]
S. Gundavaram. CGI Programming on the World Wide Web . O’Reilly & Associates, Inc., Sebas-
topol, CA, 1996.
[Morris95]
M. E. S. Morris. HTML for Fun and Profit. SunSoft Press, Prentice Hall PTR, Englewood Cliffs,
NJ, 1995.
[Pesce95]
M. Pesce. VRML - Browsing and Building Cyberspace . New Riders Publishing, Indianapolis, IN,
1995.
[Wernecke94]
J. Wernecke. The Inventor Mentor . Addison-Wesley, Reading MA,1994.
436 Visualization on the Web
Chapter 12
Applications
modality, has particular diagnostic strengths. The choice of modality is the job of the radiologist
and the referring physician. For the most part, radiologists deal with two-dimensional images, but
there are situations when three-dimensional models can assist the radiologist’s diagnosis. Radiolo-
gists have special training to interpret the two dimensional images and understand the complex ana-
tomical relationships in these two-dimensional representations. However, in dealing with referring
physicians and surgeons, the radiologist sometimes has difficulty communicating these relation-
ships. After all, a surgeon works in three-dimensions during the planning and execution of an oper-
ation; moreover, they are much more comfortable looking at and working with three-dimensional
models.
This case study deals with CT data. Computed tomography measures the attenuation of X-
rays as they pass through the body. A CT image consists of levels of gray that vary from black (for
air), to gray (for soft tissue), to white (for bone). Figure12–1 shows a CT cross section through a
head. This slice is taken perpendicular to the spine approximately through the middle of the ears.
The gray boundary around the head clearly shows the ears and bridge of the nose. The dark regions
on the interior of the slice are the nasal passages and ear canals. The bright areas are bone. This
2
study contains 93 such slices, spaced 1.5 mm apart. Each slice has 256 pixels spaced 0.8 mm apart
with 12 bits of gray level.
Our challenge is to take this gray scale data (over 12 megabytes) and convert it into informa-
tion that will aid the surgeon. Fortunately, our visualization toolkit has just the right techniques. We
will use isocontouring techniques to extract the skin and bone surfaces and display orthogonal
cross-sections to put the isosurface in context. From experience we know that a density value of
500 will define the air/skin boundary, and a value of 1150 will define the soft tissue/bone boundary.
In VTK terminology, medical imaging slice data is image data. Recall from Chapter 5 that for
image data, the topology and geometry of the data is implicitly known, requiring only dimensions,
an origin, and the data spacing.
The steps we follow in this case study are common to many three-dimensional medical stud-
ies.
12.1 3D Medical Imaging 439
Medical images come in many flavors of file formats. This study is stored as flat files without
header information. Each 16-bit pixel is stored with little-endian byte order. Also, as is often the
case, each slice is stored in a separate file with the file suffix being the slice number of the form
prefix.1 , prefix.2 , and so on. Medical imaging files often have a header of a certain size
before the image data starts. The size of the header varies from file format to file format. Finally,
another complication is that sometimes one or more bits in each 16-bit pixel is used to mark con-
nectivity between voxels. It is important to be able to mask out bits as they are read.
VTK provides several image readers including one that can read raw formats of the type
described above— vtkVolume16Reader . To read this data we instantiate the class and set the appro-
priate instance variables as follows.
The FilePrefix and FilePattern instance variable work together to produce the name of files in a
series of slices. The FilePattern—which by default is %s.%d —generates the filename to read by
performing a C-language sprintf() of the FilePrefix and the current file number into the FilePattern
format specifier.
Create an Isosurface
We can choose from three techniques for isosurface visualization: volume rendering, marching
cubes, and dividing cubes. We assume that we want to interact with our data at the highest possible
speed, so we will not use volume rendering. We prefer marching cubes if we have polygonal ren-
dering hardware available, or if we need to move up close to or inside the extracted surfaces. Even
with hardware assisted rendering, we may have to reduce the polygon count to get reasonable ren-
dering speeds. Dividing cubes is appropriate for software rendering. For this application we’ll use
marching cubes.
440 Applications
For medical volumes, marching cubes generates a large number of triangles. To be practical,
2
we’ll do this case study with a reduced resolution dataset. We took the original 256 data and
2
reduced it to 64 slices by averaging neighboring pixels twice in the slice plane. We call the result-
ing dataset quarter since it has 1/4 the resolution of the original data. We adjust the DataSpacing for
the reduced resolution dataset to 3.2 mm per pixel. Our first program will generate an isosurface for
the skin.
The flow in the program is similar to most VTK applications.
aCamera->ComputeViewPlaneNormal();
aRenderer->AddActor(outline);
aRenderer->AddActor(skin);
aRenderer->SetActiveCamera(aCamera);
aRenderer->ResetCamera ();
aCamera->Dolly(1.5);
aRenderer->SetBackground(1,1,1);
renWin->SetSize(640, 480);
aRenderer->ResetCameraClippingRange ();
To provide context for the isosurface an outline is created around the data. An initial view is set up
in a window size of pixels. ´Since the dolly command moves the camera towards the
640480
data, the clipping planes are reset to insure that the isosurface is completely visible. Figure12–2
shows the resulting image of the patient’s skin.
We can improve this visualization in a number of ways. First, we can choose a more appro-
priate color (and other surface properties) for the skin. We use the vtkProperty method
SetDiffuseColor() to set the skin color to a fleshy tone. We also add a specular component to the
skin surface. Next, we can add additional isosurfaces corresponding to various anatomical features.
Here we choose to extract the bone surface by adding an additional pipeline segment. This consists
of the filters vtkMarchingCubes , vtkPolyDataMapper , and vtkActor , just as we did with the skin.
Finally, to improve rendering performance on our system, we create triangle strips from the output
442 Applications
of the contouring process. This requires adding vtkStripper . Figure12–3 shows the resulting
image, and the following is the C++ code for the pipeline.
The Visualization Toolkit provides other useful techniques besides isocontouring for exploring vol-
ume data. One popular technique used in medical imaging is to view orthogonal slices, or planes,
through the data. Because computer graphics hardware supports texture mapping, an approach
using texture mapping gives the best result in terms or interactive performance.
We will extract three orthogonal planes corresponding to the axial, sagittal, and coronal cross
sections that are familiar to radiologists. The axial plane is perpendicular to the patient’s neck, sag-
ittal passes from left to right, and coronal passes from front to back. For illustrative purposes, we
render each of these planes with a different color lookup table. For the sagittal plane, we use a gray
scale. The coronal and axial planes vary the saturation and hue table, respectively. We combine this
with a translucent rendering of the skin (we turn off the bone with the C++ statement bone-
>VisibilityOff() ). The following VTK code creates the three lookup tables that is used in the texture
mapping process.
The image data is mapped to colors using the filter vtkImageMapToColors in combination with the
lookup tables created above. The actual display of the slice is performed with vtkImageActor (see
“Assemblies and Other Types of vtkProp” on page74 for more information) . This class conve-
niently combines a quadrilateral, polygon plane with a texture map. vtkImageActor requires image
data of type unsigned char , which the class vtkImageMapToColors conveniently provides. To
avoid copying the data and to specify the 2D texture to use, the DisplayExtent of each vtkImageA-
ctor is set appropriately. The C++ code is as follows:
// saggital
vtkImageMapToColors *saggitalColors =
vtkImageMapToColors::New();
saggitalColors->SetInputConnection(v16->GetOutputPort());
saggitalColors->SetLookupTable(bwLut);
vtkImageActor *saggital = vtkImageActor::New();
saggital->SetInputConnection(saggitalColors->GetOutputPort());
saggital->SetDisplayExtent(32,32, 0,63, 0,92);
444 Applications
// axial
vtkImageMapToColors *axialColors =
vtkImageMapToColors::New();
axialColors->SetInputConnection(v16->GetOutputPort());
axialColors->SetLookupTable(hueLut);
vtkImageActor *axial = vtkImageActor::New();
axial->SetInputConnection(axialColors->GetOutputPort());
axial->SetDisplayExtent(0,63, 0,63, 46,46);
// coronal
vtkImageMapToColors *coronalColors =
vtkImageMapToColors::New();
coronalColors->SetInputConnection(v16->GetOutputPort());
coronalColors->SetLookupTable(satLut);
vtkImageActor *coronal = vtkImageActor::New();
coronal->SetInputConnection(coronalColors->GetOutputPort());
coronal->SetDisplayExtent(0,63, 32,32, 0,92);
aRenderer->AddActor(outline);
aRenderer->AddActor(saggital);
aRenderer->AddActor(axial);
aRenderer->AddActor(coronal);
aRenderer->AddActor(bone);
aRenderer->AddActor(skin);
composing transparent surfaces for proper results. We render the skin last by adding it to
aRenderer ’s actor list last.
We need to make one last point about processing medical imaging data. Medical images can
be acquired in a variety of orders that refer to the relationship of consecutive slices to the patient.
Radiologists view an image as though they were looking at the patient’s feet. This means that on
the display, the patient’s left appears on the right. For CT there are two standard orders: top to bot-
tom or bottom to top. In a top to bottom acquisition, slice i is farther from the patient’s feet than
slice i - 1. Why do we worry about this order? It is imperative in medical applications that we retain
the left / right relationship. Ignoring the slice acquisition order can result in a flipping of left and
right. To correct this, we need to transform either the original dataset or the geometry we have
extracted. (See “Exercises” on page481 for more information.) Also, you may wish to examine the
implementation of the classes vtkVolume16Reader and vtkVolumeReader (the superclass of
vtkVolume16Reader). These classes have special methods that deal with transforming image data.
The previous example described how to create models from gray-scale medical imaging data. The
techniques for extracting bone and skin models is straightforward compared to the task of generat-
ing models of other soft tissue. The reason is that magnetic resonance and, to some extent, com-
puted tomography, generates similar gray-scale values for different tissue types. For example, the
liver and kidney in a medical computed tomography volume often have overlapping intensities.
Likewise, many different tissues in the brain have overlapping intensities when viewed with mag-
netic resonance imaging. To deal with these problems researchers apply a process called segmenta-
tion to identify different tissues. These processes vary in sophistication from almost completely
automatic methods to manual tracing of images. Segmentation continues to be a hot research area.
Although the segmentation process itself is beyond the scope of this text, in this case study we
show how to process segmented medical data.
For our purposes we assume that someone (or many graduate students) have laboriously
labeled each pixel in each slice of a volume of data with a tissue identifier. This identifier is an inte-
ger number that describes which tissue class each pixel belongs to. For example, we may be given a
series of MRI slices of the knee with tissue numbers defining the meniscus, femur, muscles, and so
forth. Figure12–5 shows two representations of a slice from a volume acquired from a patient’s
knee. The image on the left is the original MRI slice; the image on the right contains tissue labels
for a number of important organs. The bottom image is a composite of the two images.
Notice the difference in the information presented by each representation. The original slice
shows gradual changes at organ borders, while the segmented slice has abrupt changes. The images
we processed in the previous CT example used marching cubes isocontouring algorithm and an
intensity threshold to extract the isosurfaces. The segmented study we present has integer labels
that have a somewhat arbitrary numeric value. Our goal in this example is to somehow take the tis-
sue labels and create grayscale slices that we can process with the same techniques we used previ-
ously. Another goal is to show how image processing and visualization can work together in an
application.
446 Applications
To demonstrate the processing of segmented data we will use a dataset derived from a frog. This
data was prepared at Lawrence Berkeley National Laboratories and is included with their permis-
sion on the CD-ROM accompanying this book. The data was acquired by physically slicing the
frog and photographing the slices. The original segmented data is in the form of tissue masks with
one file per tissue. There are 136 slices per tissue and 15 different tissues. Each slice is 470 by 500
pixels. (To accommodate the volume readers we have in VTK, we processed the mask files and
combined them all in one file for each slice.) We used integer numbers 1–15 to represent the 15 tis-
sues. Figure12–6 shows an original slice, a labeled slice, and a composite of the two representa-
tions.
Before we describe the process to go from binary labeled tissues to gray-scale data suitable
for isosurface extraction, compare the two images of the frog’s brain shown in Figure12–7 . On the
left is a surface extracted using a binary labeling of the brain. The right image was created using the
visualization pipeline that we will develop in this example.
Developing a Strategy
In the last example, we used C++ and created a program that was tailored to extract two surfaces:
one of the skin and one of the bone. All the parameters for the surface extraction were hard-coded
in the source. Since our frog has 15 different tissues; we seek a more general solution to this prob-
lem. We may have to experiment with a number of different parameters for a number of visualiza-
tion and imaging filters. Our goal is to develop a general pipeline that will work not only our 15
tissues but on other medical datasets as well. We’ll design the program to work with a set of user-
specified parameters to control the elements of the pipeline. A reasonable description might look
like:
SLICE_ORDER hfsi
ROWS 470
COLUMNS 500
STUDY ../frogMasks/frogTissue
PIXEL_SIZE 1
SPACING 1.5
plus possibly many more parameters to control decimation, smoothing, and so forth. Working in
C++, we would have to design the format of the file and write code to interpret the statements. We
make the job easier here by using Tcl interpreter. Another decision is to separate the modelling
from the rendering. Our script will generate models in a “batch” mode. We will run one VTK Tcl
script for each tissue. That script will create a .vtk output file containing the polygonal representa-
tion of each tissue. Later, we can render the models with a separate script.
Figure12–8 shows the design of the pipeline. This generic pipeline has been developed over the
years in our laboratory and in the Brigham and Women’s Hospital Surgical Planning Lab. We find
that it produces reasonable models from segmented datasets. Do not be intimidated by the number
of filters (twelve in all). Before we developed VTK, we did similar processing with a hodgepodge
of programs all written with different interfaces. We used intermediate files to pass data from one
filter to the next. The new pipeline, implemented in VTK, is more efficient in time and computing
resources.
We start by developing Tcl scripts to process the volume data. In these scripts, we use the
convention that user-specified variables are in capital letters. First we show the elements of the
pipeline and subsequently show sample files that extract 3D models of the frog’s tissues.
448 Applications
We assume here that all the data to be processed was acquired with a constant center landmark. In
VTK, the origin of the data applies to the lower left of an image volume. In this pipeline, we calcu-
late the origin such that the x,y center of the volume will be (0,0). The DataSpacing describes the
size of each pixel and the distance between slices. DataVOI selects a volume of interest (VOI). A
VOI lets us select areas of interest, sometimes eliminating extraneous structures like the CT table
bed. For the frog, we have written a small C program that reads the tissue label file and finds the
volume of interest for each tissue.
The SetTransform() method defines how to arrange the data in memory. Medical images can
be acquired in a variety of orders. For example, in CT, the data can be gathered from top to bottom
(superior to inferior), or bottom to top (inferior to superior). In addition, MRI data can be acquired
from left to right, right to left, front-to-back (anterior to posterior) or back-to-front. This filter trans-
forms triangle vertices such that the resulting models will all “face” the viewer with a view up of
(0,-1,0), looking down the positive z axis. Also, proper left-right correspondence will be main-
tained. That means the patient’s left will always be left on the generated models. Look in
SliceOrder.tcl to see the permutations and rotations for each order.
All the other parameters are self-explanatory except for the last. In this script, we know that
the pipeline will only be executed once. To conserve memory, we invoke the ReleaseDataFlagOn()
method. This allows the VTK pipeline to release data once it has been processed by a filter. For
large medical datasets, this can mean the difference between being able to process a dataset or not.
vtkPNMReader
ImageData
vtkImageIslandRemoval
vtkImageThreshold
vtkImageShrink3D
vtkImageGaussianSmooth
vtkMarchingCubes
PolyData
vtkDecimatePro
vtkSmoothPolyData
vtkPolyDataNormals
vtkStripper
vtkPolyDataWriter
Figure 12–8 The segmented volume to triangle pipeline. Volume passes through image
pipeline before isosurface extraction ( frogSegmentation.tcl ).
Remove Islands
Some segmentation techniques, especially those that are automatic, may generate islands of mis-
classified voxels. This filter looks for connected pixels with the ISLAND_REPLACE label, and if
the number of connected pixels is less than ISLAND_AREA , it replaces them with the label
TISSUE . Note that this filter is only executed if ISLAND_REPLACE is positive.
Select a Tissue
The rest of the pipeline requires gray-scale data. To convert the volume that now contains integer
tissue labels to a gray-scale volume containing only one tissue, we use the threshold filter to set all
pixels with the value TISSUE (the tissue of choice for this pipeline) to 255 and all other pixels to 0.
The choice of 255 is somewhat arbitrary.
vtkImageThreshold selectTissue
selectTissue ThresholdBetween $TISSUE $TISSUE
selectTissue SetInValue 255
selectTissue SetOutValue 0
selectTissue SetInputConnection [$lastConnection GetOutputPort]
vtkImageShrink3D shrinker
shrinker SetInputConnection [selectTissue GetOutputPort]
eval shrinker SetShrinkFactors $SAMPLE_RATE
shrinker AveragingOn
Generate Triangles
Now we can process the volume with marching cubes just as though we had obtained gray-scale
data from a scanner. We added a few more bells and whistles to the pipeline. The filter runs faster if
we turn off gradient and normal calculations. Marching cubes normally calculates vertex normals
from the gradient of the volume data. In our pipeline, we have concocted a gray-scale representa-
tion and will subsequently decimate the triangle mesh and smooth the resulting vertices. This pro-
cessing invalidates the normals that are calculated by marching cubes.
vtkMarchingCubes mcubes
mcubes SetInputConnection [toStructuredPoints GetOutputPort]
mcubes ComputeScalarsOff
mcubes ComputeGradientsOff
mcubes ComputeNormalsOff
eval mcubes SetValue 0 $VALUE
[mcubes GetOutput] ReleaseDataFlagOn
vtkDecimatePro decimator
decimator SetInputConnection [mcubes GetOutputPort]
eval decimator SetFeatureAngle $DECIMATE_ANGLE
decimator PreserveTopologyOn
decimator SetTargetReduction $DECIMATE_REDUCTION
[decimator GetOutput] ReleaseDataFlagOn
Of course we have already smoothed the image data with a Gaussian kernel so this step may not
give much improvement; however, models that are heavily decimated can sometimes be improved
with additional polygonal smoothing.
vtkSmoothPolyDataFilter smoother
smoother SetInputConnection [decimator GetOutputPort]
eval smoother SetNumberOfIterations $SMOOTH_ITERATIONS
eval smoother SetRelaxationFactor $SMOOTH_FACTOR
eval smoother SetFeatureAngle $SMOOTH_ANGLE
smoother FeatureEdgeSmoothingOff
smoother BoundarySmoothingOff;
smoother SetConvergence 0
[smoother GetOutput] ReleaseDataFlagOn
Generate Normals
To generate smooth shaded models during rendering, we need normals at each vertex. As in deci-
mation, sharp edges can be retained by setting the feature angle.
vtkPolyDataNormals normals
normals SetInputConnection [smoother GetOutputPort]
eval normals SetFeatureAngle $FEATURE_ANGLE
[normals GetOutput] ReleaseDataFlagOn
vtkStripper stripper
stripper SetInputConnection [normals GetOutputPort]
[stripper GetOutput] ReleaseDataFlagOn
vtkPolyDataWriter writer
writer SetInputConnection [stripper GetOutputPort]
eval writer SetFileName $NAME.vtk
writer Update
12.2 Creating Models from Segmented Volume Data 453
causes the pipeline to execute. In practice we do a bit more than just Update the last element of the
pipeline. We explicitly Update each element so that we can time the individual steps. The script
frogSegmentation.tcl contains the more sophisticated approach.
There is a specific file for each tissue type. This tissue-specific file reads in the frog-specific param-
eters, sets tissue-specific parameters, and then reads the pipeline script (we call it
frogSegmentation.tcl ). For example, liver.tcl contains:
source frog.tcl
set NAME liver
set TISSUE 10
set START_SLICE 25
set END_SLICE 126
set VOI “167 297 154 304 $START_SLICE $END_SLICE”
source frogSegmentation.tcl
Parameters in frog.tcl can also be overridden. For example, skeleton.tcl overrides the stan-
dard deviation for the Gaussian filter.
source frog.tcl
set NAME skeleton
set TISSUE 13
set VALUE 368.5
set START_SLICE 1
454 Applications
Note that both of these examples specify a volume of interest. This improves performance of the
imaging and visualization algorithms by eliminating empty space.
Another script, marchingFrog.tcl , uses similar parameters but processes the original
gray-scale volume rather than the segmented volume. This script is used in skin.tcl to extract the
skin. The file marchingFrog.tcl does not have the island removal or threshold pipeline elements
since the data is already has gray-scale information.
Once the models are generated with the process just outlined, they can be rendered using the
following tcl script called ViewFrog.tcl . First we create a Tcl procedure to automate the creation
of actors from the model files. All the pipeline elements are named consistently with the name of
the part followed by the name of the pipeline element. This makes it easy for the user to identify
each object in more sophisticated user interfaces.
After the usual code to create required rendering objects, a single statement for each part creates an
actor we can add to the renderer:
• We mixed image processing and computer graphics algorithms to process data created by an
external segmentation process.
• We developed a generic approach that allows users to control the elements of the pipeline
with a familiar scripting language, tcl.
• We separated the task into a “batch” portion and an “interactive” portion.
versity Medical Media and Information Technologies (SUMMIT) group has on-going work using
the Berkeley frog. They are early VTK users. Enjoy their Virtual Creatures project at: http://
summit.stanford.edu/creatures .
in this example may be unfamiliar to you. This should not be a large concern. We have simply cho-
sen the tools with which we are familiar. Where we have used an Awk script, you might choose to
write a small C program to do the same thing. The value of the example lies in illustrating the high-
level process of solving a visualization problem.
The first step is to obtain the data. We obtained our data from a public site on the World Wide
Web (WWW) that archives stock prices and volumes for many publicly traded stocks. (This Web
site has closed down since publication of the first edition. The data for this example are available
on the CD-ROM.)
Once we have obtained the data, we convert it to a format that can be read into VTK. While
VTK can read in a variety of data formats, frequently your data will not be in one of those. The data
files we obtained are stored in the following format:
Each line stores the data for one day of trading. The first number is the date, stored as the last two
digits of the year, followed by a two-digit month and finally the day of the month. The next three
values represent the high, low, and closing price of the stock for that day. The next value is the vol-
ume of trading in thousands of shares. The final value is the volume of trading in millions of dol-
lars.
We used an Awk script to convert the original data format into a VTK data file. (See the VTK
User’s Guide for information on VTK file formats; or refer to the Web page http://
www.vtk.org/VTK/pdf/file-formats.pdf .) This conversion could be done using many other
approaches, such as writing a C program or a Tcl script.
The above Awk script performs the conversion. Its first line outputs the required header informa-
tion indicating that the file is a VTK data file containing polygonal data. It also includes a comment
indicating that the data represents stock values. There are a few different VTK data formats that we
could have selected. It is up to you to decide which format best suits the data you are visualizing.
We have judged the polygonal format ( vtkPolyData ) as best suited for this particular stock visual-
ization.
The next line of the Awk script creates a variable named count that keeps track of how many
days worth of information is in the file. This is equivalent to the number of lines in the original data
file.
The next fourteen lines convert the six digit date into a more useful format, since the original
format has a number of problems. If we were to blindly use the original format and plot the data
using the date as the independent variable, there would be large gaps in our plot. For example,
931231 is the last day of 1993 and 940101 is the first day of 1994. Chronologically, these two dates
are sequential, but mathematically there are (940101–931231=) 8870 values between them. A sim-
ple solution would be to use the line number as our independent variable. This would work as long
as we knew that every trading day was recorded in the data file. It would not properly handle the
situation where the market was open, but for some reason data was not recorded. A better solution
is to convert the dates into numerically ordered days. The preceding Awk script sets January 1,
1993, as day number one, and then numbers all the following days from there. At the end of these
14 lines the variable, d, will contain the resulting value.
The next line in our Awk script stores the converted date, closing price, and dollar volume
into arrays indexed by the line number stored in the variable count . Once all the lines have been
read and stored into the arrays, we write out the rest of the VTK data file. We have selected the date
as our independent variable and x coordinate. The closing price we store as the y coordinate, and
the z coordinate we set to zero. After indicating the number and type of points to be stored, the Awk
script loops through all the points and writes them out to the VTK data file. It then writes out the
line connectivity list. In this case we just connect one point to the next to form a polyline for each
stock. Finally, we write out the volume information as scalar data associated with the points. Por-
tions of the resulting VTK data file are shown below.
DATASET POLYDATA
POINTS 348 float
242 49.250 0
243 49.125 0
245 48.750 0
246 48.625 0
12.3 Financial Visualization 459
...
POINT_DATA 348
SCALARS volume float
LOOKUP_TABLE default
1139.2
1360.4
1247.2
1745.4
...
Now that we have generated the VTK data file, we can start the process of creating a visualization
for the stock data. To do this, we wrote a Tcl script to be used with the Tcl-based VTK executable.
At a high level the script reads in the stock data, sends it through a tube filter, creates a label for it,
and then creates an outline around the resulting dataset. Ideally, we would like to display multiple
stocks in the same window. To facilitate this, we designed the Tcl script to use a procedure to per-
form operations on a per stock basis. The resulting script is listed below.
# create labels
460 Applications
vtkTextSource $prefix.TextSrc
$prefix.TextSrc SetText “$name”
$prefix.TextSrc SetBacking 0
vtkPolyDataMapper $prefix.LabelMapper
$prefix.LabelMapper SetInput [$prefix.TextSrc GetOutput]
vtkFollower $prefix.LabelActor
$prefix.LabelActor SetMapper $prefix.LabelMapper
$prefix.LabelActor SetPosition $x $y $z
$prefix.LabelActor SetScale 0.25 0.25 0.25
eval $prefix.LabelActor SetOrigin
[$prefix.LabelMapper GetCenter]
# create a sphere source and actor
vtkPolyDataReader $prefix.PolyDataRead
$prefix.PolyDataRead SetFileName
“../../../vtkdata/$prefix.vtk”
vtkTubeFilter $prefix.TubeFilter
$prefix.TubeFilter SetInputConnection \
[$prefix.PolyDataRead GetOutputPort]
$prefix.TubeFilter SetNumberOfSides 8
$prefix.TubeFilter SetRadius 0.5
$prefix.TubeFilter SetRadiusFactor 10000
vtkTransform $prefix.Transform
$prefix.Transform Translate 0 0 $zpos
$prefix.Transform Scale 0.15 1 1
vtkTransformPolyDataFilter $prefix.TransformFilter
$prefix.TransformFilter SetInputConnection
[$prefix.TubeFilter GetOutputPort]
$prefix.TransformFilter SetTransform $prefix.Transform
# increment zpos
set zpos [expr $zpos + 10]
vtkPolyDataMapper $prefix.StockMapper
$prefix.StockMapper SetInputConnection
[$prefix.TransformFilter GetOutputPort]
vtkActor $prefix.StockActor
$prefix.StockActor SetMapper $prefix.StockMapper
$prefix.StockMapper SetScalarRange 0 8000
[$prefix.StockActor GetProperty] SetAmbient 0.5
[$prefix.StockActor GetProperty] SetDiffuse 0.5
# Add the actors to the renderer, set the background and size
#
ren1 AddActor outlineActor
ren1 SetBackground 0.1 0.2 0.4
renWin SetSize 1200 600
# prevent the tk window from showing up then start the event loop wm
withdraw .
The first part of this script consists of the standard procedure for renderer and interactor creation
that can be found in almost all of the VTK Tcl scripts. The next section creates the objects neces-
sary for drawing an outline around all of the stock data. A vtkAppendPolyData filter is used to
append all of the stock data together. This is then sent through a vtkOutlineFilter to create a bound-
ing box around the data. A mapper and actor are created to display the result.
In the next part of this script, we define the procedure to add stock data to this visualization.
The procedure takes five arguments: the name of the stock, the label we want displayed, and the x,
y, z coordinates defining where to position the label. The first line of the procedure indicates that
the variable ren1 should be visible to this procedure. By default the procedure can only access its
own local variables. Next, we create the label using a vtkTextSource , vtkPolyDataMapper , and
vtkFollower . The names of these objects are all prepended with the variable “ $prefix. ” so that the
instance names will be unique. An instance of vtkFollower is used instead of the usual vtkActor ,
because we always want the text to be right-side up and facing the camera. The vtkFollower class
provides this functionality. The remaining lines position and scale the label appropriately. We set
the origin of the label to the center of its data. This insures that the follower will rotate about its
center point.
The next group of lines creates the required objects to read in the data, pass it through a tube
filter and a transform filter, and finally display the result. The tube filter uses the scalar data (stock
volume in this example) to determine the radius of the tube. The mapper also uses the scalar data to
determine the coloring of the tube. The transform filter uses a transform object to set the stock’s
position based on the value of the variable zpos. For each stock, we will increment zpos by 10,
effectively shifting the next stock over 10 units from the current stock. This prevents the stocks
from being stacked on top of each other. We also use the transform to compress the x-axis to make
the data easier to view. Next, we add this stock as an input to the append filter and add the actors
and followers to the renderer. The last line of the procedure sets the follower’s camera to be the
active camera of the renderer.
Back in the main body of the Tcl script, we invoke the AddStock procedure four times with
four different stocks. Finally, we add the outline actor and customize the renderer and camera to
462 Applications
Figure 12–10 Two views from the stock visualization script. The top shows closing price over
time; the bottom shows volume over time ( stocks.tcl ).
produce a nice initial view. Two different views of the result are displayed in Figure12–10 . The top
image shows a history of stock closing prices for our four stocks. The color and width of these lines
correspond to the volume of the stock on that day. The lower image more clearly illustrates the
changes in stock volume by looking at the data from above.
A legitimate complaint with Figure12–10 is that the changing width of the tube makes it
more difficult to see the true shape of the price verses the time curve. We can solve this problem by
using a ribbon filter followed by a linear extrusion filter, instead of the tube filter. The ribbon filter
will create a ribbon whose width will vary in proportion to the scalar value of the data. We then use
the linear extrusion filter to extrude this ribbon along the y-axis so that it has a constant thickness.
The resulting views are shown in Figure12–11 .
12.4 Implicit Modelling 463
Figure 12–11 Two more views of the stock case study. Here the tube filter has been
replaced by a ribbon filter followed with a linear extrusion filter.
vtkTransformPolyDataFilter
vtkTransformPolyDataFilter vtkTransformPolyDataFilter
vtkAppendPolyData
vtkImplicitModeller vtkPolyDataNormals
vtkContourFilter vtkPolyDataMapper
vtkPolyDataMapper
Figure 12–12 The visualization pipeline for the VTK blobby logo.
We create three separate visualization pipelines, one for each letter. Figure12–12 shows the
visualization pipeline. As is common in VTK applications, we design a pipeline and fill in the
details of the instance variables just before we render. We pass the letters through a
vtkTransformPolyDataFilter to position them relative to each other. Then we combine all of the
polygons from the transformed letters into one polygon dataset using the vtkAppendPolyData filter.
The vtkImplicitModeller creates a volume dataset of dimension 64 3 with each voxel containing a
scalar value that is the distance to the nearest polygon. Recall from “Implicit Modelling” on page189
that the implicit modelling algorithm lets us specify the region of influence of each polygon. Here
we specify this using the SetMaximumDistance() method of the vtkImplicitModeller . By restricting
the region of influence, we can significantly improve performance of the implicit modelling algo-
rithm. Then we use vtkContourFilter to extract an isosurface that approximates a distance of 1.0
from each polygon. We create two actors: one for the blobby logo and one for the original polygon
letters. Notice that both actors share the polygon data created by vtkAppendPolyData . Because of
the nature of the VTK visualization pipeline (see “Implicit Execution” on page91 ), the appended
data will only be created once by the portion of the pipeline that is executed first. As a final touch,
we move the polygonal logo in front of the blobby logo. Now we will go through the example in
detail.
First, we read the geometry files that contain polygonal models of each letter in the logo. The
data is in VTK polygonal format, so we use vtkPolyDataReader .
12.4 Implicit Modelling 465
We want to transform each letter into its appropriate location and orientation within the logo. We
create the transform filters here, but defer specifying the location and orientation until later in the
program.
We collect all of the transformed letters into one set of polygons by using an instance of the class
vtkAppendPolyData .
Since the geometry for each letter did not have surface normals, we add them here. We use
vtkPolyDataNormals . Then we complete this portion of the pipeline by creating a mapper and an
actor.
// create normals
vtkPolyDataNormals *logoNormals = vtkPolyDataNormals::New();
logoNormals->SetInputConnection (appendAll->GetOutputPort());
logoNormals->SetFeatureAngle (60);
logoMapper->SetInputConnection (logoNormals->GetOutputPort());
// now an actor
vtkActor *logo = vtkActor::New();
logo->SetMapper (logoMapper);
We create the blobby logo with the implicit modeller, and then extract the logo with
vtkContourFilter . The pipeline is completed by creating a mapper and an actor.
// now an actor
vtkActor *blobbyLogo = vtkActor::New();
blobbyLogo->SetMapper (blobbyLogoMapper);
blobbyLogo->SetProperty (banana);
To improve the look of our resulting visualization, we define a couple of organic colors. Softer col-
ors show up better on some electronic media (e.g., VHS video tape) and are pleasing to the eye.
logo->SetProperty(tomato);
blobbyLogo->SetProperty(banana);
And finally, we position the letters in the logo and move the polygonal logo out in front of the
blobby logo by modifying the actor’s position.
VTransform->Translate (-16,0,12.5);
VTransform->RotateY (40);
KTransform->Translate (14, 0, 0);
KTransform->RotateY (-40);
An image made from the techniques described in this section is shown in Figure12–13 . Note that
the image on the left has been augmented with a texture map.
create a large system of equations that can then be solved on a computer. The grid is topologically
uniform in i-j-k space, but the corresponding physical coordinates need not be uniformly distrib-
uted. This is what we call a structured grid dataset in VTK.
There are a number of techniques we can use when we first look at the complex data pre-
sented by CFD applications. Since we need to apply several algorithms to the data, and since there
will be many parameter changes for these algorithms, we suggest using the Tcl interpreter rather
than C++ code. Our strategy for visualizing this CFD data includes the following:
1. Display the computational grid. The analyst carefully constructed the finite difference grid to
have a higher density in regions where rapid changes occur in the flow variables. We will dis-
play the grid in wireframe so we can see the computational cells.
2. Display the scalar fields on the computational grid. This will give us an overview of where
the scalar data is changing. We will experiment with the extents of the grid extraction to focus
on interesting areas.
3. Explore the vector field by seeding streamlines with a spherical cloud of points. Move the
sphere through areas of rapidly changing velocity.
4. Try using the computational grid itself as seeds for the streamlines. Of course we will have to
restrict the extent of the grid you use for this purpose. Using the grid, we will be able to place
more seeds in regions where the analyst expected more action.
For this case study, we use a dataset from NASA called the LOx Post. It simulates the flow of liquid
oxygen across a flat plate with a cylindrical post perpendicular to the flow [Rogers86] . This analy-
sis models the flow in a rocket engine. The post promotes mixing of the liquid oxygen.
We start by exploring the scalar and vector fields in the data. By calculating the magnitude of
the velocity vectors, we derive a scalar field. This study has a particularly interesting vector field
around the post. We seed the field with multiple starting points (using points arranged along a
curve, referred to as a rake) and experiment with parameters for the streamlines. Streampolygons
are particularly appropriate here and do a nice job of showing the flow downstream from the post.
We animate the streamline creation by moving the seeding line or rake back and forth behind the
post.
Following our own advice, we first display the computational grid. The following Tcl code
produced the right image of Figure12–14 .
# read data
vtkPLOT3DReader pl3d
pl3d SetXYZFileName "$env(VTK_TEXTBOOK_DATA)/postxyz.bin"
pl3d SetQFileName "$env(VTK_TEXTBOOK_DATA)/postq.bin"
pl3d IBlankingOn
pl3d Update
# computational planes: the floor
vtkStructuredGridGeometryFilter floorComp
floorComp SetExtent 0 37 0 75 0 0
floorComp SetInputConnection [pl3d GetOutputPort]
vtkPolyDataMapper floorMapper
floorMapper SetInputConnection [floorComp GetOutputPort]
floorMapper ScalarVisibilityOff
12.5 Computational Fluid Dynamics 469
vtkActor floorActor
floorActor SetMapper floorMapper
[floorActor GetProperty] SetColor 0 0 0
[floorActor GetProperty] SetRepresentationToWireframe
# the post
vtkStructuredGridGeometryFilter postComp
postComp SetExtent 10 10 0 75 0 37
postComp SetInputConnection [pl3d GetOutputPort]
vtkPolyDataMapper postMapper
postMapper SetInputConnection [postComp GetOutputPort]
postMapper ScalarVisibilityOff
vtkActor postActor
postActor SetMapper postMapper
[postActor GetProperty] SetColor 0 0 0
[postActor GetProperty] SetRepresentationToWireframe
# outline
vtkStructuredGridOutlineFilter outline
outline SetInputConnection [pl3d GetOutputPort]
vtkPolyDataMapper outlineMapper
outlineMapper SetInputConnection [outline GetOutputPort]
vtkActor outlineActor
outlineActor SetMapper outlineMapper
[outlineActor GetProperty] SetColor 0 0 0
# Add the actors to the renderer, set the background and size
#
ren1 AddActor outlineActor
ren1 AddActor floorActor
470 Applications
Figure 12–14 Portion of computational grid for the LOx post ( LOxGrid.tcl ).
To display the scalar field using color mapping, we must change the actor’s representation from
wireframe to surface, turn on scalar visibility for each vtkPolyDataMapper , set each mapper’s sca-
lar range, and render again, producing the right image of Figure12–14 .
postActor SetRepresentationToSurface
fanActor SetRepresentationToSurface
floorActor SetRepresentationToSurface
postMapper ScalarVisibilityOn
postMapper SetScalarRange [[pl3d GetOutput] GetScalarRange]
fanMapper ScalarVisibilityOn
fanMapper SetScalarRange [[pl3d GetOutput] GetScalarRange]
floorMapper ScalarVisibilityOn
floorMapper SetScalarRange [[pl3d GetOutput] GetScalarRange]
Now, we explore the vector field using vtkPointSource . Recall that this object generates a random
cloud of points around a spherical center point. We will use this cloud of points to generate stream-
lines. We place the center of the cloud near the post since this is where the velocity seems to be
changing most rapidly. During this exploration, we use streamlines rather than streamtubes for rea-
sons of efficiency. The Tcl code is as follows.
Figure 12–15 Streamlines seeded with spherical cloud of points. Four separate cloud positions are
shown.
Figure12–15 shows streamlines seeded from four locations along the post. Notice how the struc-
ture of the flow begins to emerge as the starting positions for the streamlines are moved up and
down in front of the post. This is particularly true if we do this interactively; the mind assembles
the behavior of the streamlines into a global understanding of the flow field.
For a final example, we use the computational grid to seed streamlines and then generate
streamtubes as is shown in Figure12–16 . A nice feature of this approach is that we generate more
streamlines in regions where the analyst constructed a denser grid. The only change we need to
make is to replace the rake from the sphere source with a portion of the grid geometry.
vtkStructuredGridGeometryFilter seedsComp
seedsComp SetExtent 10 10 37 39 1 35
seedsComp SetInput [pl3d GetOutput]
streamers SetSourceConnection [seedsComp GetOutputPort]
# create tubes
vtkTubeFilter tubes
tubes SetInputConnection [streamers GetOutputPort]
tubes SetNumberOfSides 8
tubes SetRadius .08
tubes SetVaryRadiusOff
# change input to streamtubes
mapTubes SetInputConnection [tubes GetOutputPort]
There are a number of other methods we could use to visualize this data. A 3D widget such as the
vtkLineWidget could be used to seed the streamlines interactively (see “3D Widgets and User Inter-
action” on page252 ). As we saw in “Point Probe” on page312 , probing the data for numerical val-
ues is a valuable technique. In particular, if the probe is a line we can use it in combination with
vtkXYPlotActor to graph the variation of data value along the line. Another useful visualization
would be to identify regions of vorticity. We could use Equation9-12 in conjunction with an isoc-
ontouring algorithm (e.g., vtkContourFilter ) to creates isosurfaces of large helical-density.
12.6 Finite Element Analysis 473
Finite element analysis is a widely used numerical technique for finding solutions of partial differ-
ential equations. Applications of finite element analysis include linear and nonlinear structural,
thermal, dynamic, electromagnetic, and flow analysis. In this application we will visualize the
results of a blow molding process.
In the extrusion blow molding process, a material is extruded through an annular die to form
a hollow cylinder. This cylinder is called a parison . Two mold halves are then closed on the pari-
son, while at the same time the parison is inflated with air. Some of the parison material remains
within the mold while some becomes waste material. The material is typically a polymer plastic
softened with heat, but blow molding has been used to form metal parts. Plastic bottles are often
manufactured using a blow molding process.
Designing the parison die and molds is not easy. Improper design results in large variations in
the wall thickness. In some cases the part may fail in thin-walled regions. As a result, analysis tools
based on finite element techniques have been developed to assist in the design of molds and dies.
The results of one such analysis are shown in Figure12–17 . The polymer was molded using
an isothermal, nonlinear-elastic, incompressible (rubber-like) material. Triangular membrane finite
elements were used to model the parison, while a combination of triangular and quadrilateral finite
elements were used to model the mold. The mold surface is assumed to be rigid, and the parison is
assumed to attach to the mold upon contact. Thus the thinning of the parison is controlled by its
stretching during inflation and the sequence in which it contacts the mold.
Figure12–17 illustrates 10 steps of one analysis. The color of the parison indicates its thick-
ness. Using a rainbow scale, red areas are thinnest while blue regions are thickest. Our visualization
shows clearly one problem with the analysis technique we are using. Note that while the nodes (i.e.,
points) of the finite element mesh are prevented from passing through the mold, the interior of the
triangular elements are not. This is apparent from the occlusion of the mold wireframe by the pari-
son mesh.
To generate these images, we used a Tcl script shown in Figure12–18 and Figure12–19 .
The input data is in VTK format, so a vtkUnstructuredGridReader was used as a source object. The
mesh displacement is accomplished using an instance of vtkWarpVector . At this point the pipeline
splits. We wish to treat the mold and parison differently (different properties such as wireframe ver-
sus surface), but the data for both mold and parison is combined. Fortunately, we can easily sepa-
rate the data using two instances of class vtkConnectivityFilter . One filter extracts the parison,
while the other extracts both parts of the mold. Finally, to achieve a smooth surface appearance on
the parison, we use a vtkPolyDataNormals filter. In order to use this filter, we have to convert the
data type from vtkUnstructuredGrid (output of vtkConnectivityFilter ) to type vtkPolyData . The fil-
ter vtkGeometryFilter does this nicely.
Visualization can be used to display algorithms and data structures. Representing this information
often requires creative work on the part of the application programmer. For example, Robertson et
474 Applications
Figure 12–17 Ten frames from a blow molding finite element analysis. Mold halves (shown in wire-
frame) are closed around a parison as the parison is inflated. Coloring indicates thickness—red areas
are thinner than blue ( blow.tcl ).
12.7 Algorithm Visualization 475
vtkUnstructuredGridReader vtkConnectivityFilter
Extract parison
vtkWarpVector vtkGeometryFilter
Extract mold
vtkConnectivityFilter vtkPolyDataNormals
vtkDataSetMapper vtkPolyDataMapper
Figure 12–18 Tcl script to generate blow molding image. Network topology and ini-
tial portion of script are shown (Part one of two).
al. [Robertson91] have shown 3D techniques for visualizing directory structures and navigating
through them. Their approach involves building three dimensional models (the so-called “cone
trees”) to represent files, directories, and associations between files and directories. Similar
approaches can be used to visualize stacks, queues, linked lists, trees, and other data structures.
In this example we will visualize the operation of the recursive Towers of Hanoi puzzle. In
this puzzle there are three pegs ( Figure12–20 ). In the initial position there are one or more disks
(or pucks) of varying diameter on the pegs. The disks are sorted according to disk diameter, so that
the largest disk is on the bottom, followed by the next largest, and so on. The goal of the puzzle is to
476 Applications
# Add the actors to the renderer, set the background and size
ren1 AddActor moldActor
ren1 AddActor parisonActor
ren1 SetBackground 1 1 1
renWin SetSize 750 400
iren Initialize
iren AddObserver UserEvent {wm deiconify .vtkInteract}
# prevent the tk window from showing up then start the event loop
wm withdraw .
Figure 12–19 Tcl script to generate blow molding image (Part two of two).
12.7 Algorithm Visualization 477
(a) Initial
(b) Intermediate
(c) Final
Figure 12–20 Towers of Hanoi. (a) Initial configuration. (b) Intermediate configuration.
(c) Final configuration ( Hanoi.cxx ).
478 Applications
move the disks from one peg to another, moving the disks one at a time, and never placing a larger
disk on top of a smaller disk.
The classical solution to this puzzle is based on a divide-and-conquer approach
[AhoHopUll83] . The problem of moving n disks from the initial peg to the second peg can be
thought of as solving two subproblems of size n–1. First move n–1 disks from the initial peg to the
third peg. Then move the nth disk to the second peg. Finally, move the n–1 disks on the third peg
back to the second peg.
The solution to this problem can be elegantly implemented using recursion. We have shown
portions of the C++ code in Figure12–21 and Figure12–22 . In the first part of the solution (which
is not shown in Figure12–21 ) the table top, pegs, and disks are created using the two classes
vtkPlaneSource and vtkCylinderSource . The function Hanoi() is then called to begin the recursion.
The routine MovePuck() is responsible for moving a disk from one peg to another. It has been
jazzed up to move the disk in small, user-specified increments, and to flip the disc over as it moves
from one peg to the next. This gives a pleasing visual effect and adds the element of fun to the visu-
alization.
Because of the clear relationship between algorithm and physical reality, the Towers of Hanoi
puzzle is relatively easy to visualize. A major challenge facing visualization researchers is to visu-
alize more abstract information, such as information on the Internet, the structure of documents, or
the effectiveness of advertising/entertainment in large market segments. This type of visualization,
known as information visualization, is likely to emerge in the future as an important research chal-
lenge.
// Routineisresponsibleformovingdisksfromonepegtothenext
//.
voidMovePuck(intpeg1,intpeg2)
{
doubledistance, flipAngle;
vtkActor*movingActor;
inti;
NumberOfMoves++;
//gettheactortomove
movingActor=(vtkActor*)pegStack[peg1].Pop();
//getthedistancetomoveup
distance=(H-(L*(pegStack[peg1].GetNumberOfItems()-1)) + rMax)
/ NumberOfSteps;
for(i=0;i<NumberOfSteps;i++)
{
movingActor->AddPosition(0,distance,0);
Renwin->Render();
}
//getthedistancetomoveacross
distance=(peg2-peg1)*D/NumberOfSteps;
flipAngle=180.0/NumberOfSteps;
for(i=0;i<NumberOfSteps;i++)
{
movingActor->AddPosition(distance,0,0);
movingActor->RotateX(flipAngle);
Renwin->Render();
}
//getthedistancetomovedown
distance=((L*(pegStack[peg2].GetNumberOfItems()-1))-H-
rMax)/NumberOfSteps;
for(i=0;i<NumberOfSteps;i++)
{
movingActor->AddPosition(0,distance,0);
Renwin->Render();
}
pegStack[peg2].Push(movingActor);
}
Figure 12–22 Function to move disks from one peg to another in the Towers of Hanoi
example. The resulting motion is in small steps with an additional flip of the disk.
for referring physicians and surgeons. Medical datasets are typically image data—volumes or lay-
ered stacks of 2D images that form volumes. Common visualization tools for medical imaging
include isosurfaces, cut planes, and image display on volume slices.
Next, we presented an example that applied 3D visualization techniques to financial data. In
this case study, we began by showing how to import data from an external source. We applied tube
filters to the data and varied the width of the tube to show the volume of stock trading. We saw how
480 Applications
different views can be used to present different pieces of information. In this case, we saw that by
viewing the visualization from the front, we saw a conventional price display. Then, by viewing the
visualization from above, we saw trade volume.
In the modelling case study we showed how to use polygonal models and the implicit model-
ling facilities in VTK to create a stylistic logo. The final model was created by extracting an isosur-
face at a user-selected offset.
Computational fluid dynamics analysts frequently employ structured grid data. We examined
some strategies for exploring the scalar and vector fields. The computational grid created by the
analyst serves as a starting point for analyzing the data. We displayed geometry extracted from the
finite difference grid, scalar color mapping, and streamlines and streamtubes to investigate the data.
In the finite element case study, we looked at unstructured grids used in a simulation of a
blow molding process. We displayed the deformation of the geometry using displacement plots,
and represented the material thickness using color mapping. We saw how we can create simple ani-
mations by generating a sequence of images.
We concluded the case studies by visualizing the Towers of Hanoi algorithm. Here we
showed how to combine the procedural power of C++ with the visualization capabilities in VTK.
We saw how visualization often requires our creative resources to cast data structures and informa-
tion into visual form.
12.10 References
[Aho88]
A. V. Aho, B. W. Kernighan, and P. J. Weinberger. The AWK Programming Language . Addison-
Wesley, Reading, MA, 1988.
[AhoHopUll83]
A. V. Aho, J. E. Hopcroft, and J. D. Ullman. Data Structures and Algorithm s. Addison-Wesley,
Reading, MA, 1983.
[Becker95]
R. A. Becker, S. G. Eick, and A. R. Wilks. “Visualizing Network Data.” IEEE Transactions on Vi-
sualization and Graphics . 1(1):16–28,1995.
12.11 Exercises 481
[deLorenzi93]
H. G. deLorenzi and C. A. Taylor. “The Role of Process Parameters in Blow Molding and Corre-
lation of 3-D Finite Element Analysis with Experiment.” International Polymer Processing.
3(4):365–374, 1993.
[Ding90]
C. Ding and P. Mateti. “A Framework for the Automated Drawing of Data Structure Diagrams.”
IEEE Transactions on Software Engineering . 16(5):543–557, May 1990.
[Eick93]
S. G. Eick and G. J. Wills. “Navigating Large Networks with Hierarchies.” In Proceedings of Vi-
sualization ’93 . pp. 204–210, IEEE Computer Society Press, Los Alamitos, CA, October 1993.
[Feiner88]
S. Feiner. “Seeing the Forest for the Trees: Hierarchical Displays of Hypertext Structures.” In
Conference on Office Information Systems . Palo Alto, CA, 1988.
[Gilster94]
P. Gilster. Finding It on the Internet: The Essential Guide to Archie, Veronica, Gopher, WAIS,
WWW (including Mosaic), and Other Search and Browsing Tools . John Wiley & Sons, Inc., 1994.
[Johnson91]
B. Johnson and B. Shneiderman. “Tree-Maps: A Space-Filling Approach to the Visualization of
Hierarchical Information Structure s.” In Proceedings of Visualization ’91 . pp. 284–291, IEEE
Computer Society Press, Los Alamitos, CA, October 1991.
[Perl95]
D. Till. Teach Yourself Perl in 21 Days . Sams Publishing, Indianapolis, Indiana, 1995.
[Robertson91]
G. G. Robertson, J. D. Mackinlay, and S. K. Card. “Cone Trees: Animated 3D Visualizations of
Hierarchical Information.” In Proceedings of ACM CHI ’91 Conference on Human Factors in
Computing Systems . pp. 189–194, 1991.
[Rogers86]
S. E. Rogers, D. Kwak, and U. K. Kaul, “A Numerical Study of Three-Dimensional Incompress-
ible Flow Around Multiple Post.” in Proceedings of AIAA Aerospace Sciences Conference . vol.
AIAA Paper 86-0353. Reno, Nevada, 1986.
12.11 Exercises
12.1 The medical example did nothing to transform the original data into a standard coordinate
system. Many medical systems use RAS coordinates. R is right/left, A is anterior/posterior
and S is Superior/Inferior. This is the patient coordinate system. Discuss and compare the fol-
lowing alternatives for transforming volume data into RAS coordinates.
a) vtkActor transformation methods.
b) vtkTransformFilter .
c) Reader transformations.
12.2 Modify the last example found in the medical application ( Medical3.cxx ) to use
vtkImageDataGeometryFilter instead of vtkImageActor . Compare the performance of using
geometry with using texture. How does the performance change as the resolution of the vol-
ume data changes?
482 Applications
12.3 Modify the last medical example ( Medical3.cxx ) to use v tkTexture and vtkPlaneSource
instead of vtkImageActor .
12.4 Change the medical case study to use dividing cubes for the skin surface.
12.5 Combine the two scripts frogSegmentation.tcl and marchingFrog.tcl into one script
that will handle either segmented or grayscale files. What other parameters and pipeline com-
ponents might be useful in general for this application?
12.6 Create polygonal / line stroked models of your initials and build your own logo. Experiment
with different transformations.
12.7 Enhance the appearance of Towers of Hanoi visualization.
a) Texture map the disks, base plane, and pegs.
b) Create disks with central holes.
12.8 Use the blow molding example as a starting point for the following.
a) Create an animation of the blow molding sequence. Is it possible to interpolate between
time steps? How would you do this?
b) Create the second half of the parison using symmetry. What transformation matrix do you
need to use?
12.9 Start with the stock visualization example presented in this chapter.
a) Modify the example code to use a ribbon filter and linear extrusion filter as described in
the text. Be careful of the width of the generated ribbons.
b) Can you think of a way to present high/low trade values for each day?
Glossary
3D Widget. An interaction paradigm enabling manipulation of scene objects (e.g., lights, camera,
actors, and so on). The 3D widget typically provides a visible representation that can be intuitively
and interactively manipulated.
API. An acronym for application programmer’s interface.
Abstract Class. A class that provides methods and data members for the express purpose of deriv-
ing subclasses. Such objects are used to define a common interface and attributes for their sub-
classes.
Abstraction. A mental process that extracts the essential form or unifying properties of a concept.
Alpha. A specification of opacity (or transparency). An alpha value of one indicates that the object
is opaque. An alpha value of zero indicates that the object is completely transparent.
Ambient Lighting. The background lighting of unlit surfaces.
Animation. A sequence of images displayed in rapid succession. The images may vary due to
changes in geometry, color, lighting, camera position, or other graphics parameters. Animations are
used to display the variation of one or more variables.
Antialiasing. The process of reducing aliasing artifacts. These artifacts typically result from under-
sampling the data. A common use of antialiasing is to draw straight lines that don’t have the jagged
edges found in many systems without antialiasing.
Azimuth. A rotation of a camera about the vertical (or view up) axis.
Attribute. A named member of a class that captures some characteristic of the class. Attributes
have a name, a data type, and a data value. This is the same as a data member or instance variable.
Base Class. A superclass in C++.
484
Binocular Parallax. The effect of viewing the same object with two slightly different viewpoints
to develop depth information.
Boolean Texture. A texture map consisting of distinct regions used to “cut” or accentuate features
of data. For example, a texture map may consist of regions of zero opacity. When such a texture is
mapped onto the surface of an object, portions of its interior becomes visible. Generally used in
conjunction with a quadric (or other implicit function) to generate texture coordinates.
C++. A compiled programming language with roots in the C programming language. C++ is an
extension of C that incorporates object-oriented principles.
CT (Computed Tomography). A data acquisition technique based on X-rays. Data is acquired in a
2
3D volume as a series of slice planes (i.e., a stack of n points).
Cell. The atoms of visualization datasets. Cells define a topology (e.g., polygon, triangle) in terms
of a list of point coordinates.
Cell Attributes. Dataset attributes associated with a cell. See also point attributes .
Class. An object that defines the characteristics of a subset of objects. Typically, it defines methods
and data members. All objects instantiated from a class share that class’s methods and data mem-
bers.
Clipping Plane. A plane that restricts the rendering or processing of data. Front and back clipping
planes are commonly used to restrict the rendering of primitives to those lying between the two
planes.
Color Mapping. A scalar visualization technique that maps scalar values into color. Generally
used to display the variation of data on a surface or through a volume.
Compiled System. A compiled system requires that a program be compiled (or translated into a
lower-level language) before it is executed. Contrast with interpreted systems .
Composite Cell. A cell consisting of one or more primary cells.
Concrete Class. A class that can be instantiated. Typically, abstract classes are not instantiated but
concrete classes are.
Connectivity. A technique to extract connected cells. Cells are connected when they share com-
mon features such as points, edges, or faces.
Contouring. A scalar visualization technique that creates lines (in 2D) or surfaces (in 3D) repre-
senting a constant scalar value across a scalar field. Contour lines are called isovalue lines or iso-
lines. Contour surfaces are called isovalue surfaces or isosurfaces.
Constructor. A class method that is invoked when an instance of that class is created. Typically the
constructor sets any default values and allocates any memory that the instance needs. See also
destructor .
Critical Points. Locations in a vector field where the local vector magnitude goes to zero and the
direction becomes undefined.
Cutting. A visualization technique to slice through or cut data. The cutting surface is typically
described with an implicit function, and data attributes are mapped onto the cut surface. See also
boolean texture .
485
Dataset. The general term used to describe visualization data. Datasets consist of structure (geom-
etry and topology) and dataset attributes (scalars, vectors, tensors, etc.).
Dataset Attributes. The information associated with the structure of a dataset. This can be scalars,
vectors, tensors, normals, and texture coordinates, or arbitrary data arrays that may be contained in
the field.
Data Extraction. The process of selecting a portion of data based on characteristics of the data.
These characteristics may be based on geometric or topological constraints or constraints on data
attribute values.
Data Flow Diagram. A diagram that shows the information flow and operations on that informa-
tion as it moves throughout a program or process.
Data Object. An object that is an abstraction of data. For example, a patient’s file in a hospital
could be a data object. Typical visualization objects include structured grids and volumes. See also
process object .
Data Member. A named member of a class that captures some characteristic of the class. Data
members have a name, a data type, and a data value. This is the same as an attribute or instance
variable.
Data Visualization. The process of transforming data into sensory stimuli, usually visual images.
Data visualization is a general term, encompassing data from engineering and science, as well as
information from business, finance, sociology, geography, information management, and other
fields. Data visualization also includes elements of data analysis, such as statistical analysis. Con-
trast with scientific visualization and information visualization .
Decimation. A type of polygon reduction technique that deletes points in a polygonal mesh that
satisfies a co-planar or co-linear condition and replaces the resulting hole with a new triangulation.
Delaunay Triangulation. A triangulation that satisfies the Delaunay circumsphere criterion. This
criterion states that a circumsphere of each simplex in the triangulation contains only the points
defining the simplex.
Delegation. The process of assigning an object to handle the execution of another object’s meth-
ods. Sometimes it is said that one object forwards certain methods to another object for execution.
Demand-driven. A method of visualization pipeline update where the update occurs only when
data is requested and occurs only in the portion of the network required to generate the data.
Derived Class. A class that is more specific or complete than its superclass. The derived class,
which is also known as the subclass, inherits all the members of its superclass. Usually a derived
class adds new functionality or fills in what was defined by its superclass. See also subclass .
Destructor. A class method that is invoked when an instance of that class is deleted. Typically the
destructor frees memory that the instance was using. See also constructor .
Device Mapper. A mapper that interfaces data to a graphics library or subsystem.
Diffuse Lighting. Reflected light from a matte surface. Diffuse lighting is a function of the relative
angle between the incoming light and surface normal of the object.
486
Displacement Plots. A vector visualization technique that shows the displacement of the surface of
an object. The method generates scalar values by computing the dot product between the surface
normal and vector displacement of the surface. The scalars are visualized using color mapping.
Display Coordinate System. A coordinate system that is the result of mapping the view coordinate
system onto the display hardware.
Divergence. In numerical computation: the tendency of computation to move away from the solu-
tion. In fluid flow: the rapid motion of fluid particles away from one another.
Dividing Cubes. A contour algorithm that represents isosurfaces as a dense cloud of points.
Dolly. A camera operation that moves the camera position towards ( dolly in ) or away ( dolly out )
from the camera focal point.
Double Buffering. A display technique that is used to display animations more smoothly. It con-
sists of using two buffers in the rendering process. While one buffer is being displayed, the next
frame in the animation is being drawn on the other buffer. Once the drawing is complete the two
buffers are swapped and the new image is displayed.
Dynamic Memory Model. A data flow network that does not retain intermediate results as it exe-
cutes. Each time the network executes, it must recompute any data required as input to another pro-
cess object. A dynamic memory model reduces system memory requirements but places greater
demands on computational requirements.
Dynamic Model. A description of a system concerned with synchronizing events and objects.
Effective Stress. A mathematical combination of the normal and shear stress components that pro-
vide a measure of the stress at a point. Effective stress is a scalar value, while stress is represented
with a tensor value. See stress .
Eigenfields. Vector fields defined by the eigenvectors of a tensor.
Eigenvalue. A characteristic value of a matrix. Eigenvalues often correspond to physical phenom-
ena, such as frequency of vibration or magnitude of principal components of stress.
Eigenvector. A vector associated with each eigenvalue. The eigenvector spans the space of the
matrix. Eigenvectors are orthogonal to one another. Eigenvectors often correspond to physical phe-
nomena such as mode shapes of vibration.
Elevation. A rotation of a camera about the horizontal axis.
Entity. Something within a system that has identity. Chairs, airplanes, and cameras are things that
correspond to physical entities in the real world. A database and isosurface algorithm are examples
of nonphysical entities.
Event-driven. A method of visualization pipeline update where updates occur when an event
affects the pipeline, e.g., when an object instance variable is set or modified. See also demand-
driven.
Execution. The process of updating a visualization network.
Explicit Execution. Controlling network updates by performing explicit dependency analysis.
Exporter. An object that saves a VTK scene definition to a file or other program. (A scene consists
of lights, cameras, actors, geometry, properties, texture, and other pertinent data.) See also
importer .
487
field in which particle integration is performed (like streamlines). The other two vectors control the
cross-sectional shape of an ellipse that is swept along the integration path. See also streampolygon .
Image Data. A dataset whose structure is both geometrically and topologically regular. Both
geometry and topology are implicit. A 3D image dataset is known as a volume. A 2D image dataset
is known as a pixmap.
Image-Order Techniques. Rendering techniques that determine for each pixel in the image plane
which data samples contribute to it. Image-order techniques are implemented using ray casting.
Contrast with object-order techniques .
Implicit Execution. Controlling network updates by distributing network dependency throughout
the visualization process objects. Each process object requests that its input be updated before it
executes. This results in a recursive update/execution process throughout the network.
() ,, c is a constant.
Implicit Function. A mathematical function of the form , where
Fxyz = c
Implicit Modelling. A modelling technique that represents geometry as a scalar field. Usually the
scalar is a distance function or implicit function distributed through a volume.
Importer. An object that interfaces to external data or programs to define a complete scene in
VTK. (The scene consists of lights, cameras, actors, geometry, properties, texture, and other perti-
nent data.) See also exporter .
Information Visualization. The process of transforming information into sensory stimuli, usually
visual images. Information visualization is used to describe the process of visualizing data without
structure, such as information on the World Wide Web; or abstract data structures, like computer
file systems or documents. Contrast with scientific visualization and data visualization .
Inheritance. A process where the attributes and methods of a superclass are bestowed upon all sub-
classes derived from that superclass. It is said that the subclasses inherit their superclasses’ methods
and attributes.
Instance. An object that is defined by a class and used by a program or application. There may be
many instances of a specific class.
Instance Variable. A named member of a class that captures a characteristic of the class. Instance
variables have a name, a data type, and a data value. The phrase, instance variable, is often abbrevi-
ated as ivar. This is the same as an attribute or data member.
Intensity. The light energy transferred per unit time across a unit plane perpendicular to the light
rays.
Interpolate. Estimate a value of a function at a point p, given known function values and points
that bracket p.
Interpolation Functions. Functions continuous in value and derivatives used to interpolate data
from known points and function values. Cells use interpolation functions to compute data values
interior to or on the boundary of the cell.
Interpreted System. An interpreted system can execute programs without going through a sepa-
rate compilation stage. Interpreted systems often allow the user to interact and modify the program
as it is running. Contrast with compiled systems .
489
Irregular Data. Data in which the relationship of one data item to the other data items in the
dataset is arbitrary. Irregular data is also known as unstructured data.
Iso-parametric. A form of interpolation in which interpolation for data values is the same as for
the local geometry. Compare with sub-parametric and super-parametric .
Isosurface. A surface representing a constant valued scalar function. See contouring .
Isovalue. The scalar value used to generate an isosurface.
Jacobian. A matrix that relates one coordinate system to another.
Line. A cell defined by two points.
MRI (Magnetic Resonance Imaging). A data acquisition technique based on measuring variation
in magnetic field in response to radio-wave pulses. The data is acquired in a 3D region as a series of
2
slice planes (i.e., a stack of n points).
Mapper. A process object that terminates the visualization network. It maps input data into graph-
ics libraries (or other devices) or writes data to disk (or a communication device).
Manifold Topology. A domain is manifold at a point p in a topological space of dimension n if the
neighborhood around p is homeomorphic to an n-dimensional sphere. Homeomorphic means that
the mapping is one to one without tearing (i.e., like mapping a rubber sheet from a square to a disk).
We generally refer to an object’s topology as manifold if every point in the object is manifold. Con-
trast with nonmanifold topology .
Marching Cubes. A contouring algorithm to create surfaces of constant scalar value in 3D. March-
ing cubes is described for volume datasets, but has been extended to datasets consisting of other
cell types.
Member Function. A member function is a function or transformation that can be applied to an
object. It is the functional equivalent to a data member. Member functions define the behavior of an
object. Methods, operations, and member functions are essentially the same.
Method. A function or transformation that can be applied to an object. Methods define the behav-
ior of an object. Methods, operations, and member functions are essentially the same.
Modal Lines. Lines on the surface of a vibrating object that separate regions of positive and nega-
tive displacement.
Mode Shape. The motion of an object vibrating at a natural frequency. See also eigenvalues and
eigenvectors .
Model Coordinate System. The coordinate system that a model or geometric entity is defined in.
There may be many different model coordinate systems defined for one scene.
Motion Blur. An artifact of the shutter speed of a camera. Since the camera’s shutter stays open for
a finite amount of time, changes in the scene that occur during that time can result in blurring of the
resulting image.
Morph. A progressive transformation of one object into another. Generally used to transform
images (2D morphing) and in some cases geometry (3D morphing).
Multiple Input. Process objects that accept more than one input.
Multiple Output. Process objects that generate more than one output.
490
Pyramid. A type of primary 3D cell. The pyramid has a quadrilateral base connected to a single
apex point. It has five faces, eight edges, and five vertices. The base face of the pyramid is not nec-
essarily planar.
Quadric. A function of the form
2 2 2
() ,,
fxyz = a 0 x + a 1 y ++++++++
a2 z a 3 xya 4 yza 5 xza 6 xa 7 ya 8 za 9 . The quadric
equation can represent many useful 3D objects such as spheres, ellipsoids, cylinders, and cones.
Quadratic Edge. A type of primary 1D cell with a quadratic interpolation function. The quadratic
edge is defined by three points: two end points and a mid-edge node.
Quadratic Triangle. A type of primary 2D cell with quadratic interpolation functions. The qua-
dratic triangle is defined by six points: three corner points and three mid-edge nodes.
Quadratic Quadrilateral. A type of primary 2D cell with quadratic interpolation functions. The
quadratic quadrilateral is defined by eight points: four corner points and four mid-edge nodes.
Quadratic Tetrahedron. A type of primary 3D cell with quadratic interpolation functions. The
quadratic tetrahedron is defined by ten points: four corner points and six mid-edge nodes.
Quadratic Hexahedron. A type of primary 3D cell with quadratic interpolation functions. The
quadratic edge is defined by twenty points: eight corner points and twelve mid-edge nodes.
Quadrilateral (Quad). A type of primary 2D cell. The quadrilateral is four sided with four verti-
ces. The quadrilateral must be convex.
Reader. A source object that reads a file or files and produces a data object.
Reference Counting. A memory management technique used to reduce memory requirements.
Portions of memory (in this case objects) may be referenced by more than one other object. The ref-
erenced object keeps a count of references to it. If the count returns to zero, the object deletes itself,
returning memory back to the system. This technique avoids making copies of memory.
Region of Interest. A portion of a dataset that the user is interested in visualizing. Sometimes
abbreviated ROI.
Regular Data. Data in which one data item is related (either geometrically or topologically) to
other data items. Also referred to as structured data.
Rendering. The process of converting object geometry (i.e., geometric primitives), object proper-
ties, and a specification of lights and camera into an image. The primitives may take many forms
including surface primitives (points, lines, polygons, splines), implicit functions, or volumes.
Resonant Frequency. A frequency at which an object vibrates.
Roll. A rotation of a camera about its direction of projection. See also azimuth , elevation , pitch , and
yaw.
Sampling. Selective acquisition or sampling of data, usually at a regular interval. See also probing .
Scalar. A single value or function value. May also be used to represent a field of such values.
Scalar Range. The minimum and maximum scalar values of a scalar field.
Scalar Generation. Creating scalar values from other data such as vectors or tensors. One example
is computing vector norm.
493
sweeping a regular polygon along the streamline. The radius, number of sides, shape, and rotation
of the polygon are allowed to change in response to data values. See also hyperstreamline .
Streamribbon. A vector visualization technique that represents vectors with ribbons that are every-
where tangent to the vector field
Streamsurface . A surface that is everywhere tangent to a vector field. Can be approximated by
generating a series of streamlines along a curve and connecting the lines with a surface.
Streamwise Vorticity. A measure of the rotation of flow around a streamline.
Structured Data. Data in which one data item is related (either geometrically or topologically) to
other data items. Also referred to as regular data.
Structured Grid. A dataset whose structure is topologically regular but whose geometry is irregu-
lar. Geometry is explicit and topology is implicit. Typically, structured grids consist of hexahedral
cells.
Structured Points. Preferred term is Image Data . A dataset whose structure is both geometrically
and topologically regular. Both geometry and topology are implicit. A 3D structured point dataset
is known as a volume. A 2D structured point dataset is known as a pixmap.
Subclass. A class that is more specific or complete than its superclass. The subclass, which is also
known as the derived class, inherits all the members of its superclass. Usually a subclass will add
some new functionality or fill in what was defined by its superclass. See also derived class .
Sub-parametric. A form of interpolation in which interpolation for data values is of higher order
than that for the local geometry. Compare with iso-parametric and super-parametric .
Subsampling. Sampling data at a resolution at less than final display resolution.
Superclass. A class from which other classes are derived. See also base class .
Super-parametric. A form of interpolation in which interpolation for data values is of lower order
than that for the local geometry. Compare with iso-parametric and sub-parametric .
Surface Rendering. Rendering techniques based on geometric surface primitives such as points,
lines, polygons, and splines. Contrast with volume rendering .
Swept Surface. The surface that an object creates as it is swept through space.
Swept Volume. The volume enclosed by a swept surface.
Tcl. An interpreted language developed by John Ousterhout in the early 1980s.
Tk. A graphical user-interface toolkit based on Tcl.
Tensor. A mathematical generalization of vectors and matrices. A tensor of rank k can be consid-
ered a k-dimensional table. Tensor visualization algorithms treat real33´
symmetric matrix ten-
sors (rank 2 tensors).
Tensor Ellipsoid. A type of glyph used to visualize tensors. The major, medium, and minor eigen-
values of a tensor
33´ define an ellipsoid. The eigenvalues are used to scale along the axes.
Tetrahedron. A 3D primary cell that is a simplex with four triangular faces, six edges, and four
vertices.
Texture Animation. Rapid application of texture maps to visualize data. A useful example maps a
1D texture map of varying intensity along a set of lines to simulate particle flow.
495
Texture Coordinate. Specification of position within texture map. Texture coordinates are used to
map data from Cartesian system into 2D or 3D texture map.
Texture Map. A specification of object properties in a canonical region. These properties are most
often intensity, color, and alpha, or combinations of these. The region is typically a structured array
of data in a pixmap (2D) or in a volume (3D).
Texture Mapping. A rendering technique to add detail to objects without requiring extensive geo-
metric modelling. One common example is to paste a picture on the surface of an object.
Texture Thresholding. Using texture mapping to display selected data. Often makes use of alpha
opacity to conceal regions of minimal interest.
Thresholding. A data selection technique that selects data that lies within a range of data. Typically
scalar thresholding selects data whose scalar values meet a scalar criterion.
Topology. A subset of the information about the structure of a dataset. Topology is a set of proper-
ties invariant under certain geometric transformation such as scaling, rotation, and translation.
Topological Dimension. The dimension or number of parametric coordinates required to address
the domain of an object. For example, a line in 3D space is of topological dimension one because
the line can be parametrized with a single parameter.
44´ of values used to control the position, orientation, and
Transformation Matrix. A matrix
scale of objects.
Triangle Strip. A composite 2D cell consisting of triangles. The triangle strip is an efficient repre-
sentation scheme for triangles where points
n2+ can represent n triangles.
Triangle. A primary 2D cell. The triangle is a simplex with three edges and three vertices.
Triangular Irregular Network (TIN). An unstructured triangulation consisting of triangles. Often
used to represent terrain data.
Triangulation. A set of nonintersecting simplices sharing common vertices, edges, and/or faces.
Type Converter . A type of filter used to convert from one dataset type to another.
Type Checking. The process of enforcing compatibility between objects.
Uniform Grid. A synonym for image data.
Unstructured Data. Data in which one data item is unrelated (either geometrically or topologi-
cally) to other data items. Also referred to as irregular data.
Unstructured Grid. A general dataset form consisting of arbitrary combinations of cells and
points. Both the geometry and topology are explicitly defined.
Unstructured Points. A dataset consisting of vertex cells that are positioned irregularly in space,
with no implicit or explicit topology.
Visualization. The process of converting data to images (or other sensory stimuli). Alternatively,
the end result of the visualization process.
Vector. A specification of direction and magnitude. Vectors can be used to describe fluid velocity,
structural displacement, or object motion.
Vector Field Topology. Vector fields are characterized by regions flow diverges, converges, and/or
rotates. The relationship of these regions one to another is the topology of the flow.
496
View Coordinate System. The projection of the world coordinate system into the camera’s view-
ing frustrum.
View Frustrum. The viewing region of a camera defined by six planes: the front and back clipping
planes, and the four sides of a pyramid defined by the camera position, focal point, and view angle
(or image viewport if viewing in parallel projection).
Visual Programming. A programming model that enables the construction and manipulation of
visualization applications. A typical implementation is the construction of a visualization pipeline
by connecting execution modules into a network.
Visualization Network. A series of process objects and data objects joined together into a dataflow
network.
Volume. A regular array of points in 3D space. Volumes are often defined as a series of 2D images
arranged along the z-axis.
Volume Rendering. The process of directly viewing volume data without converting the data to
intermediate surface primitives. Contrast with surface rendering .
Voxel. Short for volume element. In VTK, a primary three-dimensional cell with six faces. Each
face is perpendicular to one of the coordinate axes.
Warping. A scalar and vector visualization technique that distorts an object to magnify the effects
of data value. Warping may be used on vector data to display displacement or velocity, or on scalar
data to show relative scalar values.
Wedge. A type of primary 3D cell. The wedge has two triangular faces connected with three quad-
rilateral faces. It has five faces, nine edges, and six vertices. The quadrilateral faces of the wedge
are not necessarily planar.
World Coordinate System. A three-dimensional Cartesian coordinate system in which the main
elements of a rendering scene are positioned.
Writer. A type of mapper object that writes data to disk or other I/O device.
Yaw. A rotation of a camera’s position about the vertical axis, centered at its viewpoint. See also
pitch and roll. Contrast with azimuth .
Z-Buffer. Memory that contains the depth (along the view plane normal) of a corresponding ele-
ment in a frame buffer.
Z-Buffering. A technique for performing hidden line (point, surface) removal by keeping track of
the current depth, or z value for each pixel. These values are stored in the z-buffer.
Zoom. A camera operation that changes the field of view of the camera. Contrast with dolly .
Index
clipping with scalars 323–325 source object 82, 86, 184–185 , 493
color mapping 163–165 implementation 193–194
contouring 166–173 reader 492
dividing cubes 319–322 space leaping 242
marching cubes 166–171 spatial extraction 335
scalar attributes 133 specialization 21, 493
scalar generation 171–173, 492 specular light 41, 493
scalar range 492 splatting 493
scan conversion unstructured points 356– 357
to generate discrete rays 225 volume rendering 227–228
scene 493 spreadsheet
scene graph 99, 99 as a model for visualization 99
493 Standard Template Library 29
scientific visualization 493 StartEvent
versus data visualization 1 example 65
versus information visualization 2 state diagram 25, 493
searching 292–293, 493 static memory model 93, 493
image data 297 stereo rendering 244–248
implementation 306–308 polarized 247
segmentation 401– 402, 445, 493 red-blue 246
multi-spectral 404– 405 time multiplexed 245
segmented volume data time parallel 245
application 445– 456 strain 180, 493
sensor position strange attractors 188
image artifact 393 streakline 179, 493
server streaming 96, 389
VRML 420– 422 streamline 179–180, 253, 326, 493
SetInput() 105 application 470
SetInputConnection() 107 implementation 202
shading 56–57 seeding 472
flat 56, 487 streampolygon 327–330, 493
Gouraud 56 application 468
gouraud 487 streamribbon 326–327, 494
Phong 56 streamsurface 326–327, 494
phong 491 streamwise vorticity 326, 494
shear strain 328 stress 180, 493
shear-warp 230–231 structured coordinate system 269
Shepard’s method 358 structured data 122, 122, 494
simple point 344 structured grid 137, 494
simplex 290, 359, 493 example 151
Single Image Random Dot Stereograms 246 representation 144
sink object 82 topology 296
SIRDS 246 structured points 494
Smalltalk 26, 28 see also image data
smoothing 390 subclass 21, 494
mesh 350–352 and abstract class 22
non-linear 391 in object model 23
software sub-parametric 494
where to find 9 interpolation 285
software quality 16 subsampling 336, 494
507