Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

After thinking about this some more, I am adding the Geometry module …

…back into the release, but without Convex.cc and Convex.h, which were introducing GPL 3rd part libraries. We can add Convex.cc and Convex.h to TP, and leave the rest here to (hopefully) one day blossom into a full-fledged geometry module.
  • Loading branch information...
commit 2a29bbf98850a60dc7912cbaaec8c2a3dd44ffec 1 parent 5e4c2c3
Michael Broxton broxtronix authored
2  AUTHORS
View
@@ -22,7 +22,7 @@ Kyle Husmann (NASA Intern) - Camera, Stereo Modules, Stereo Pipeline
Matthew Faulkner (NASA Intern) - Math, Camera Modules
Matthew Deans (CS) - Interest Point Module
Ian Saxton (NASA Intern) - GPU Module
-Todd Templeton (NASA Intern) - FileIO, Math Modules
+Todd Templeton (NASA Intern) - FileIO, Math, Geometry Modules
Aaron Rolett - Mosaic Module
Kerri Cahoy (NASA Intern) - Testing
Joey Gannon (NASA Intern) - Camera Module
7 configure.ac
View
@@ -160,7 +160,7 @@ AM_CONDITIONAL(ENABLE_TEST_COVERAGE, [test x"$ENABLE_TEST_COVERAGE" = x"yes"])
# distribution options
##################################################
-AX_ARG_WITH(dist-remove-modules, [Python gui], [mk am-set], [remove certain modules from the distribution])
+AX_ARG_WITH(dist-remove-modules, [Python Geometry gui], [mk am-set], [remove certain modules from the distribution])
# These need to be here because automake-1.6 is dumb and does not properly
# process AM_CONDITIONALs unless the first argument is a simple string.
@@ -301,12 +301,14 @@ AX_MODULE(INTERESTPOINT, [src/vw/InterestPoint], [libvwInterestPoint.la], yes, [
AX_MODULE(CARTOGRAPHY, [src/vw/Cartography], [libvwCartography.la], yes, [VW], [PROJ4], [GDAL])
AX_MODULE(HDR, [src/vw/HDR], [libvwHDR.la], yes, [VW], [CAMERA LAPACK])
AX_MODULE(STEREO, [src/vw/Stereo], [libvwStereo.la], yes, [VW], [])
+AX_MODULE(GEOMETRY, [src/vw/Geometry], [libvwGeometry.la], yes, [VW], [], [])
if test $host_vendor = apple; then
AX_MODULE(GPU, [src/vw/GPU], [libvwGPU.la], no, [VW], [GL], [CG])
else
AX_MODULE(GPU, [src/vw/GPU], [libvwGPU.la], no, [VW], [GL GLEW], [CG])
fi
+
AX_MODULE(TOOLS, [src/vw/tools], [], yes, [VW], [BOOST_FILESYSTEM BOOST_PROGRAM_OPTIONS THREADS])
AX_MODULE(GUI, [src/vw/gui], [], yes, [VW], [QT BOOST_PROGRAM_OPTIONS GL])
@@ -326,6 +328,7 @@ AM_CONDITIONAL(MAKE_MODULE_CARTOGRAPHY, [test "$MAKE_MODULE_CARTOGRAPHY" = "yes"
AM_CONDITIONAL(MAKE_MODULE_HDR, [test "$MAKE_MODULE_HDR" = "yes"])
AM_CONDITIONAL(MAKE_MODULE_STEREO, [test "$MAKE_MODULE_STEREO" = "yes"])
AM_CONDITIONAL(MAKE_MODULE_GPU, [test "$MAKE_MODULE_GPU" = "yes"])
+AM_CONDITIONAL(MAKE_MODULE_GEOMETRY, [test "$MAKE_MODULE_GEOMETRY" = "yes"])
AM_CONDITIONAL(MAKE_MODULE_TOOLS, [test "$MAKE_MODULE_TOOLS" = "yes"])
AM_CONDITIONAL(MAKE_MODULE_GUI, [test "$MAKE_MODULE_GUI" = "yes"])
AM_CONDITIONAL(MAKE_MODULE_PYTHON, [test "$MAKE_MODULE_PYTHON" = "yes"])
@@ -386,6 +389,8 @@ AC_CONFIG_FILES([ \
src/vw/Stereo/tests/Makefile \
src/vw/GPU/Makefile \
src/vw/GPU/tests/Makefile \
+ src/vw/Geometry/Makefile \
+ src/vw/Geometry/tests/Makefile \
src/vw/InterestPoint/Makefile \
src/vw/InterestPoint/tests/Makefile \
src/vw/Python/vw/Makefile \
37 src/vw/Geometry.h
View
@@ -0,0 +1,37 @@
+// __BEGIN_LICENSE__
+//
+// Copyright (C) 2006 United States Government as represented by the
+// Administrator of the National Aeronautics and Space Administration
+// (NASA). All Rights Reserved.
+//
+// Copyright 2006 Carnegie Mellon University. All rights reserved.
+//
+// This software is distributed under the NASA Open Source Agreement
+// (NOSA), version 1.3. The NOSA has been approved by the Open Source
+// Initiative. See the file COPYING at the top of the distribution
+// directory tree for the complete NOSA document.
+//
+// THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF ANY
+// KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT
+// LIMITED TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO
+// SPECIFICATIONS, ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR
+// A PARTICULAR PURPOSE, OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT
+// THE SUBJECT SOFTWARE WILL BE ERROR FREE, OR ANY WARRANTY THAT
+// DOCUMENTATION, IF PROVIDED, WILL CONFORM TO THE SUBJECT SOFTWARE.
+//
+// __END_LICENSE__
+
+/// \file Geometry.h
+///
+/// A convenience header that includes the header files in vw/Geometry.
+///
+#ifndef __VW_GEOMETRY_H__
+#define __VW_GEOMETRY_H__
+
+#include <vw/Geometry/Shape.h>
+#include <vw/Geometry/Box.h>
+#include <vw/Geometry/Sphere.h>
+#include <vw/Geometry/SpatialTree.h>
+#include <vw/Geometry/PointListIO.h>
+
+#endif // __VW_GEOMETRY_H__
191 src/vw/Geometry/Box.h
View
@@ -0,0 +1,191 @@
+// __BEGIN_LICENSE__
+//
+// Copyright (C) 2006 United States Government as represented by the
+// Administrator of the National Aeronautics and Space Administration
+// (NASA). All Rights Reserved.
+//
+// Copyright 2006 Carnegie Mellon University. All rights reserved.
+//
+// This software is distributed under the NASA Open Source Agreement
+// (NOSA), version 1.3. The NOSA has been approved by the Open Source
+// Initiative. See the file COPYING at the top of the distribution
+// directory tree for the complete NOSA document.
+//
+// THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF ANY
+// KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT
+// LIMITED TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO
+// SPECIFICATIONS, ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR
+// A PARTICULAR PURPOSE, OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT
+// THE SUBJECT SOFTWARE WILL BE ERROR FREE, OR ANY WARRANTY THAT
+// DOCUMENTATION, IF PROVIDED, WILL CONFORM TO THE SUBJECT SOFTWARE.
+//
+// __END_LICENSE__
+
+/// \file Box.h
+///
+/// A box shape class.
+#ifndef __VW_GEOMETRY_BOX_H__
+#define __VW_GEOMETRY_BOX_H__
+
+#include <iostream>
+#include <fstream>
+#include <limits>
+#include <vector>
+#include <math.h>
+
+#include <boost/static_assert.hpp>
+
+#include <vw/Math/Vector.h>
+#include <vw/Math/BBox.h>
+#include <vw/Geometry/Shape.h>
+
+namespace vw {
+namespace geometry {
+
+ // *******************************************************************
+ // class Box
+ // *******************************************************************
+
+ /// A box shape class, which derives almost all of its implementation
+ /// from the math::BBox superclass.
+ template <class RealT, int DimN = 0>
+ class Box : public ShapeBase<Box<RealT, DimN>, RealT, DimN>,
+ public BBox<RealT,DimN> {
+ public:
+
+ /// Default constructor. Constructs the ultimate empty box,
+ /// whose limits are at the opposite corners of the underlying
+ /// numeric space.
+ Box() {}
+
+ /// Constructs a box with the given minimal and maximal points.
+ Box( Vector<RealT, DimN> const& min, Vector<RealT, DimN> const& max )
+ : BBox<RealT, DimN>( min, max ) {}
+
+ /// Constructs a 2D box with the given minimal point coordinates
+ /// and dimensions. (Only valid for 2D boxes.)
+ Box( RealT minx, RealT miny, RealT width, RealT height )
+ : BBox<RealT, DimN>( Vector<RealT,2>(minx,miny),
+ Vector<RealT,2>(minx+width,miny+height) )
+ {
+ BOOST_STATIC_ASSERT( DimN==2 );
+ }
+
+ /// Constructs a 3D box with the given minimal point coordinates
+ /// and dimensions. (Only valid for 3D boxes.)
+ Box( RealT minx, RealT miny, RealT minz, RealT width, RealT height, RealT depth )
+ : BBox<RealT, DimN>( Vector<RealT,3>(minx,miny,minz),
+ Vector<RealT,3>(minx+width,miny+height,minz+depth) )
+ {
+ BOOST_STATIC_ASSERT( DimN==3 );
+ }
+
+ /// Generalized copy constructor.
+ template <class RealT1, int DimN1>
+ Box( BBox<RealT1, DimN1> const& bbox )
+ : BBox<RealT, DimN>( bbox.min(), bbox.max() ) {}
+
+ /// Generalized copy assignment operator.
+ template <class RealT1, int DimN1>
+ Box& operator=( BBox<RealT1, DimN1> const& bbox ) {
+ this->min() = bbox.min();
+ this->max() = bbox.max();
+ return *this;
+ }
+
+ /// We are our own bounding box, so we just return our superclass.
+ BBox<RealT,DimN> const& bbox() const {
+ return *this;
+ }
+
+ /// Writes the box.
+ void write( std::ostream& os = std::cout, bool binary = false ) const {
+ std::vector<Vector<RealT, DimN> > points;
+ points.push_back(this->min());
+ points.push_back(this->max());
+ write_point_list(os, points, binary);
+ }
+
+ /// Writes the box.
+ void write( const char *fn, bool binary = false ) const {
+ if (binary) {
+ std::ofstream of( fn, std::ofstream::out | std::ofstream::binary );
+ write(of, binary);
+ of.close();
+ }
+ else {
+ std::ofstream of( fn );
+ write(of, binary);
+ of.close();
+ }
+ }
+
+ };
+
+ /// Scales a box relative to the origin.
+ template <class RealT, int DimN, class ScalarT>
+ inline Box<RealT, DimN> operator*( Box<RealT, DimN> const& box, ScalarT s ) {
+ return box.bbox() * s;
+ }
+
+ /// Scales a box relative to the origin.
+ template <class RealT, int DimN, class ScalarT>
+ inline Box<RealT, DimN> operator/( Box<RealT, DimN> const& box, ScalarT s ) {
+ return box.bbox() / s;
+ }
+
+ /// Scales a box relative to the origin.
+ template <class RealT, int DimN, class ScalarT>
+ inline Box<RealT, DimN> operator*( ScalarT s, Box<RealT, DimN> const& box ) {
+ return s * box.bbox();
+ }
+
+ /// Translates a box by the given vector.
+ template <class RealT, int DimN, class VectorT>
+ inline Box<RealT, DimN> operator+( Box<RealT, DimN> const& box, VectorBase<VectorT> const& v ) {
+ return box.bbox() + v;
+ }
+
+ /// Translates a box by the given vector.
+ template <class RealT, int DimN, class VectorT>
+ inline Box<RealT, DimN> operator+( VectorBase<VectorT> const& v, Box<RealT, DimN> const& box ) {
+ return v + box.bbox();
+ }
+
+ /// Translates a box by the negation of the given vector.
+ template <class RealT, int DimN, class VectorT>
+ inline Box<RealT, DimN> operator-( Box<RealT, DimN> const& box, VectorBase<VectorT> const& v ) {
+ return box.bbox() - v;
+ }
+
+ /// Writes a box to a file.
+ template <class RealT, int DimN>
+ void write_box( std::string const& filename, Box<RealT,DimN> const& box, bool binary = false ) {
+ box.write(filename.c_str(), binary);
+ }
+
+ /// Reads a box from a file.
+ template <class RealT, int DimN>
+ void read_box( std::string const& filename, Box<RealT,DimN>& box, bool binary = false ) {
+ std::vector<Vector<RealT,DimN> > points;
+ read_point_list(filename, points, binary);
+ VW_ASSERT( points.size() == 2, IOErr() << "Incorrect number of points in box file!" );
+ box = Box<RealT,DimN>(points[0], points[1]);
+ }
+
+} // namespace geometry
+
+ // Convenience typedefs
+ using geometry::Box;
+ typedef Box<float64, 2> Box2;
+ typedef Box<float64, 3> Box3;
+ typedef Box<float64, 4> Box4;
+ typedef Box<float64> BoxN;
+ typedef Box<float32, 2> Box2f;
+ typedef Box<float32, 3> Box3f;
+ typedef Box<float32, 4> Box4f;
+ typedef Box<float32> BoxNf;
+
+} // namespace vw
+
+#endif // __VW_GEOMETRY_BOX_H__
51 src/vw/Geometry/Makefile.am
View
@@ -0,0 +1,51 @@
+# __BEGIN_LICENSE__
+#
+# Copyright (C) 2006 United States Government as represented by the
+# Administrator of the National Aeronautics and Space Administration
+# (NASA). All Rights Reserved.
+#
+# Copyright 2006 Carnegie Mellon University. All rights reserved.
+#
+# This software is distributed under the NASA Open Source Agreement
+# (NOSA), version 1.3. The NOSA has been approved by the Open Source
+# Initiative. See the file COPYING at the top of the distribution
+# directory tree for the complete NOSA document.
+#
+# THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF ANY
+# KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT
+# LIMITED TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO
+# SPECIFICATIONS, ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR
+# A PARTICULAR PURPOSE, OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT
+# THE SUBJECT SOFTWARE WILL BE ERROR FREE, OR ANY WARRANTY THAT
+# DOCUMENTATION, IF PROVIDED, WILL CONFORM TO THE SUBJECT SOFTWARE.
+#
+# __END_LICENSE__
+
+########################################################################
+# sources
+########################################################################
+
+if MAKE_MODULE_GEOMETRY
+
+
+include_HEADERS = Shape.h SpatialTree.h PointListIO.h Sphere.h Box.h
+
+libvwGeometry_la_SOURCES = SpatialTree.cc
+libvwGeometry_la_LIBADD = @MODULE_GEOMETRY_LIBS@
+
+lib_LTLIBRARIES = libvwGeometry.la
+
+endif
+
+########################################################################
+# general
+########################################################################
+
+AM_CPPFLAGS = @VW_CPPFLAGS@
+AM_LDFLAGS = @VW_LDFLAGS@ -version-info @LIBTOOL_VERSION@
+
+SUBDIRS = . tests
+
+includedir = $(prefix)/include/vw/Geometry
+
+include $(top_srcdir)/config/rules.mak
149 src/vw/Geometry/PointListIO.h
View
@@ -0,0 +1,149 @@
+// __BEGIN_LICENSE__
+//
+// Copyright (C) 2006 United States Government as represented by the
+// Administrator of the National Aeronautics and Space Administration
+// (NASA). All Rights Reserved.
+//
+// Copyright 2006 Carnegie Mellon University. All rights reserved.
+//
+// This software is distributed under the NASA Open Source Agreement
+// (NOSA), version 1.3. The NOSA has been approved by the Open Source
+// Initiative. See the file COPYING at the top of the distribution
+// directory tree for the complete NOSA document.
+//
+// THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF ANY
+// KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT
+// LIMITED TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO
+// SPECIFICATIONS, ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR
+// A PARTICULAR PURPOSE, OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT
+// THE SUBJECT SOFTWARE WILL BE ERROR FREE, OR ANY WARRANTY THAT
+// DOCUMENTATION, IF PROVIDED, WILL CONFORM TO THE SUBJECT SOFTWARE.
+//
+// __END_LICENSE__
+
+/// \file PointListIO.h
+///
+/// Provides functions to read/write point lists.
+#ifndef __VW_MATH__POINT_LIST_IO_H__
+#define __VW_MATH__POINT_LIST_IO_H__
+
+
+#include <vector>
+#include <iostream>
+#include <fstream>
+
+#include <vw/Core/Exception.h>
+
+
+namespace vw {
+namespace math {
+
+ /// This function writes a list of points from any container that
+ /// supports the size() and operator[] methods. The container is
+ /// usually a vw::Vector<>, but you could substitute other classes
+ /// here as well.
+ template <class ContainerT>
+ void write_point_list(std::ostream &f, std::vector<ContainerT> const& pts, bool binary = false) {
+ VW_ASSERT( pts.size() > 0, LogicErr() << "No vectors to write!" );
+
+ unsigned num_points = pts.size();
+ unsigned dimensions = pts[0].size();
+
+ if (binary) {
+ f.write((char*)&dimensions, sizeof(dimensions));
+ f.write((char*)&num_points, sizeof(num_points));
+ for (unsigned i = 0; i < num_points; i++) {
+ for (unsigned j = 0; j < dimensions; j++)
+ f.write((char*)&pts[i][j], sizeof(pts[i][j]));
+ }
+ }
+ else {
+ f << dimensions << std::endl;
+ f << num_points << std::endl;
+ for (unsigned i = 0; i < num_points; i++) {
+ for (unsigned j = 0; j < dimensions; j++)
+ f << pts[i][j] << " ";
+ f << std::endl;
+ }
+ }
+ }
+
+ template <class ContainerT>
+ void write_point_list(std::string const& filename, std::vector<ContainerT> const& pts, bool binary = false) {
+ VW_ASSERT( pts.size() > 0, LogicErr() << "No vectors to write!" );
+
+ if (binary) {
+ std::ofstream f(filename.c_str(), std::ofstream::out | std::ofstream::binary);
+ VW_ASSERT( f, IOErr() << "Unable to open file for writing!" );
+ write_point_list(f, pts, binary);
+ f.close();
+ }
+ else {
+ std::ofstream f(filename.c_str());
+ VW_ASSERT( f, IOErr() << "Unable to open file for writing!" );
+ write_point_list(f, pts, binary);
+ f.close();
+ }
+ }
+
+ /// This function reads a list of points into any container that
+ /// supports the set_size() and operator[] methods. The container is
+ /// usually a vw::Vector<>, but you could substitute other classes
+ /// here as well.
+ template <class ContainerT>
+ void read_point_list(std::istream &f, std::vector<ContainerT> &pts, bool binary = false) {
+ ContainerT v;
+ unsigned num_points;
+ unsigned dimensions;
+
+ if (binary) {
+ f.read((char*)&dimensions, sizeof(dimensions));
+ VW_ASSERT( !f.fail(), IOErr() << "Invalid point list file format!" );
+ f.read((char*)&num_points, sizeof(num_points));
+ VW_ASSERT( !f.fail(), IOErr() << "Invalid point list file format!" );
+ v.set_size(dimensions);
+ for (unsigned i = 0; i < num_points; i++) {
+ for (unsigned j = 0; j < dimensions; j++) {
+ f.read((char*)&v[j], sizeof(v[j]));
+ VW_ASSERT( !f.fail(), IOErr() << "Invalid point list file format!" );
+ }
+ pts.push_back(v);
+ }
+ }
+ else {
+ double d;
+ f >> dimensions;
+ VW_ASSERT( !f.fail(), IOErr() << "Invalid point list file format!" );
+ f >> num_points;
+ VW_ASSERT( !f.fail(), IOErr() << "Invalid point list file format!" );
+ v.set_size(dimensions);
+ for (unsigned i = 0; i < num_points; i++) {
+ for (unsigned j = 0; j < dimensions; j++) {
+ f >> d;
+ VW_ASSERT( !f.fail(), IOErr() << "Invalid point list file format!" );
+ v[j] = d;
+ }
+ pts.push_back(v);
+ }
+ }
+ }
+
+ template <class ContainerT>
+ void read_point_list(std::string const& filename, std::vector<ContainerT> &pts, bool binary = false) {
+ if (binary) {
+ std::ifstream f(filename.c_str(), std::ifstream::in | std::ifstream::binary);
+ VW_ASSERT( f, IOErr() << "Unable to open file for reading!" );
+ read_point_list(f, pts, binary);
+ f.close();
+ }
+ else {
+ std::ifstream f(filename.c_str());
+ VW_ASSERT( f, IOErr() << "Unable to open file for reading!" );
+ read_point_list(f, pts, binary);
+ f.close();
+ }
+ }
+
+}} // namespace vw::math
+
+#endif // __VW_MATH__POINT_LIST_IO_H__
170 src/vw/Geometry/Shape.h
View
@@ -0,0 +1,170 @@
+// __BEGIN_LICENSE__
+//
+// Copyright (C) 2006 United States Government as represented by the
+// Administrator of the National Aeronautics and Space Administration
+// (NASA). All Rights Reserved.
+//
+// Copyright 2006 Carnegie Mellon University. All rights reserved.
+//
+// This software is distributed under the NASA Open Source Agreement
+// (NOSA), version 1.3. The NOSA has been approved by the Open Source
+// Initiative. See the file COPYING at the top of the distribution
+// directory tree for the complete NOSA document.
+//
+// THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF ANY
+// KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT
+// LIMITED TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO
+// SPECIFICATIONS, ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR
+// A PARTICULAR PURPOSE, OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT
+// THE SUBJECT SOFTWARE WILL BE ERROR FREE, OR ANY WARRANTY THAT
+// DOCUMENTATION, IF PROVIDED, WILL CONFORM TO THE SUBJECT SOFTWARE.
+//
+// __END_LICENSE__
+
+/// \file Shape.h
+///
+/// Provides a base class for generic shapes.
+#ifndef __VW_GEOMETRY_SHAPE_H__
+#define __VW_GEOMETRY_SHAPE_H__
+
+#include <vw/Math/Vector.h>
+
+namespace vw {
+namespace geometry {
+
+ // *******************************************************************
+ // class ShapeBase
+ // *******************************************************************
+
+ /// A CRTP base class for general n-dimensional bounding shapes.
+ /// Provides a mechanism for restricting function arguments to
+ /// shapes, provides general shape operations, and provides the
+ /// various arithmetic assignment operators.
+ template <class ShapeT, class RealT, int DimN>
+ class ShapeBase {
+ typedef Vector<RealT, DimN> ShapeVectorT;
+ public:
+
+ /// Returns the derived implementation type.
+ ShapeT& shape_impl() { return *static_cast<ShapeT*>(this); }
+
+ /// Returns the derived implementation type.
+ ShapeT const& shape_impl() const { return *static_cast<ShapeT const*>(this); }
+/* These introduce ambiguities in Box, and it's not clear that we really want them....
+ /// Grows a bounding shape to include the given point.
+ template <class VectorT>
+ void grow( VectorBase<VectorT> const& point ) {
+ shape_impl().grow(point);
+ }
+
+ /// Expands this bounding shape by the given offset in every direction.
+ void expand( RealT offset ) {
+ shape_impl().expand(offset);
+ }
+
+ /// Contracts this bounding shape by the given offset in every direction.
+ void contract( RealT offset ) {
+ shape_impl().contract(offset);
+ }
+
+ /// Returns true if the given point is contained in the bounding shape.
+ template <class VectorT>
+ bool contains( VectorBase<VectorT> const& point ) const {
+ return shape_impl().contains(point);
+ }
+
+ /// Returns the center point of the bounding shape.
+ ShapeVectorT center() const {
+ return shape_impl().center();
+ }
+
+ /// Returns true if the bounding shape is empty (i.e. degenerate).
+ bool empty() const {
+ return shape_impl().empty();
+ }
+
+ /// Scales the bounding shape relative to the origin.
+ template <class ScalarT>
+ ShapeT& operator*=( ScalarT s ) {
+ return shape_impl() = shape_impl() * s;
+ }
+
+ /// Scales the bounding shape relative to the origin.
+ template <class ScalarT>
+ ShapeT& operator/=( ScalarT s ) {
+ return shape_impl() = shape_impl() / s;
+ }
+
+ /// Offsets the bounding shape by the given vector.
+ template <class VectorT>
+ ShapeT& operator+=( VectorBase<VectorT> const& v ) {
+ return shape_impl() = shape_impl() + v;
+ }
+
+ /// Offsets the bounding shape by the negation of the given vector.
+ template <class VectorT>
+ ShapeT& operator-=( VectorBase<VectorT> const& v ) {
+ return shape_impl() = shape_impl() - v;
+ }
+*/
+ };
+
+ /// Scales a bounding shape relative to the origin.
+ template <class ShapeT, class RealT, int DimN, class ScalarT>
+ inline ShapeT operator*( ShapeBase<ShapeT, RealT, DimN> const& shape, ScalarT s ) {
+ ShapeT result = shape.shape_impl();
+ result *= s;
+ return result;
+ }
+
+ /// Scales a bounding shape relative to the origin.
+ template <class ShapeT, class RealT, int DimN, class ScalarT>
+ inline ShapeT operator/( ShapeBase<ShapeT, RealT, DimN> const& shape, ScalarT s ) {
+ ShapeT result = shape.shape_impl();
+ result /= s;
+ return result;
+ }
+
+ /// Scales a bounding shape relative to the origin.
+ template <class ShapeT, class RealT, int DimN, class ScalarT>
+ inline ShapeT operator*( ScalarT s, ShapeBase<ShapeT, RealT, DimN> const& shape ) {
+ return shape * s;
+ }
+
+ /// Offsets a bounding shape by the given vector.
+ template <class ShapeT, class RealT, int DimN, class VectorT>
+ inline ShapeT operator+( ShapeBase<ShapeT, RealT, DimN> const& shape, VectorBase<VectorT> const& v ) {
+ ShapeT result = shape.shape_impl();
+ result += v.impl();
+ return result;
+ }
+
+ /// Offsets a bounding shape by the given vector.
+ template <class ShapeT, class RealT, int DimN, class VectorT>
+ inline ShapeT operator+( VectorBase<VectorT> const& v, ShapeBase<ShapeT, RealT, DimN> const& shape ) {
+ return shape + v;
+ }
+
+ /// Offsets a bounding shape by the negation of the given vector.
+ template <class ShapeT, class RealT, int DimN, class VectorT>
+ inline ShapeT operator-( ShapeBase<ShapeT, RealT, DimN> const& shape, VectorBase<VectorT> const& v ) {
+ ShapeT result = shape.shape_impl();
+ result -= v.impl();
+ return result;
+ }
+
+ /// Equality of two bounding shapes.
+ template <class ShapeT, class RealT, int DimN>
+ inline bool operator==( ShapeBase<ShapeT, RealT, DimN> const& shape1, ShapeBase<ShapeT, RealT, DimN> const& shape2 ) {
+ return shape1.shape_impl() == shape2.shape_impl();
+ }
+
+ /// Inequality of two bounding shapes.
+ template <class ShapeT, class RealT, int DimN>
+ inline bool operator!=( ShapeBase<ShapeT, RealT, DimN> const& shape1, ShapeBase<ShapeT, RealT, DimN> const& shape2 ) {
+ return shape1.shape_impl() != shape2.shape_impl();
+ }
+
+}} // namespace vw::geometry
+
+#endif // __VW_GEOMETRY_SHAPE_H__
934 src/vw/Geometry/SpatialTree.cc
View
@@ -0,0 +1,934 @@
+#include <vw/Geometry/SpatialTree.h>
+
+#include <assert.h>
+#include <iostream> // debugging
+#include <fstream>
+#include <stdexcept>
+#include <limits>
+#include <deque>
+#include <queue>
+using namespace std;
+
+#define LOG_2 0.693147181
+
+// A spatial tree is a hierarchical subdivision of n-dimensional space
+
+// A SpatialTree node can be in 3 states:
+//
+// 1) leaf (bbox set, no quads, possibly polygons)
+// 2) split (bbox set, quads (some may be leaves), possibly polygons)
+// 3) unset (no bbox, no quads, no polygons)
+
+namespace vw {
+namespace geometry {
+
+ /*virtual*/ double GeomPrimitive::distance(const Vector<double> &point) const {
+ VW_ASSERT( 0, LogicErr() << "Child class of GeomPrimitive does not implement distance()!" );
+ return 0;
+ }
+
+ /*virtual*/ bool GeomPrimitive::contains(const Vector<double> &point) const {
+ VW_ASSERT( 0, LogicErr() << "Child class of GeomPrimitive does not implement contains()!" );
+ return 0;
+ }
+
+ /*virtual*/ bool GeomPrimitive::intersects(const GeomPrimitive *prim) const {
+ VW_ASSERT( 0, LogicErr() << "Child class of GeomPrimitive does not implement intersects()!" );
+ return 0;
+ }
+
+}} // namespace vw::math
+
+namespace {
+
+ using namespace vw::geometry;
+
+ void split_node(SpatialTree::SpatialTreeNode* node, int num_quadrants, SpatialTree::BBoxT quadrant_bboxes[]) {
+ node->m_is_split = true;
+ for (int i = 0; i < num_quadrants; i++) {
+ node->m_quadrant[i] = new SpatialTree::SpatialTreeNode(num_quadrants);
+ node->m_quadrant[i]->m_bbox = quadrant_bboxes[i];
+ }
+ }
+
+ void split_bbox(SpatialTree::BBoxT &bbox, int num_quadrants, SpatialTree::BBoxT quadrant_bboxes[]) {
+ using namespace ::vw::math::vector_containment_comparison;
+ SpatialTree::VectorT center = bbox.center();
+ SpatialTree::VectorT diagonal_vec = bbox.size() * 0.5;
+ int dim = center.size();
+ int i, j;
+
+ for (i = 0; i < num_quadrants; i++)
+ quadrant_bboxes[i].min() = center;
+ for (int d = 0, width = num_quadrants, half_width = num_quadrants / 2; d < dim; d++, width = half_width, half_width /= 2) {
+ assert(d < dim - 1 || width > 1);
+ for (i = 0; i < num_quadrants;) {
+ for (j = 0; j < half_width; j++, i++)
+ quadrant_bboxes[i].min()[d] -= diagonal_vec[d];
+ for (; j < width; j++, i++)
+ quadrant_bboxes[i].min()[d] += diagonal_vec[d];
+ }
+ }
+ for (i = 0; i < num_quadrants; i++) {
+ quadrant_bboxes[i].max() = ::vw::math::vector_containment_comparison::max(center, quadrant_bboxes[i].min());
+ quadrant_bboxes[i].min() = ::vw::math::vector_containment_comparison::min(center, quadrant_bboxes[i].min());
+ }
+
+ // Debugging:
+ if (num_quadrants == 4) {
+ assert(quadrant_bboxes[0].max() >= quadrant_bboxes[0].min());
+ assert(quadrant_bboxes[1].max() >= quadrant_bboxes[1].min());
+ assert(quadrant_bboxes[2].max() >= quadrant_bboxes[2].min());
+ assert(quadrant_bboxes[3].max() >= quadrant_bboxes[3].min());
+ assert(quadrant_bboxes[3].min() >= quadrant_bboxes[0].min());
+ assert(quadrant_bboxes[3].max() >= quadrant_bboxes[0].max());
+ assert(quadrant_bboxes[0].max() == quadrant_bboxes[3].min());
+ }
+ }
+
+ void grow_bbox(SpatialTree::BBoxT &bbox, int num_primitives, GeomPrimitive *prims[]) {
+ for (int i = 0; i < num_primitives; i++)
+ bbox.grow(prims[i]->bounding_box());
+ }
+
+ void grow_bbox_on_grid(SpatialTree::BBoxT &bbox, const SpatialTree::BBoxT &new_bbox) {
+ using namespace ::vw::math::vector_containment_comparison;
+ double d, f;
+ unsigned p = 1, p_;
+ int i;
+ int dim = bbox.min().size();
+ SpatialTree::VectorT diag, super_diag;
+ SpatialTree::VectorT extra, extra_needed(dim);
+ SpatialTree::BBoxT super_bbox = bbox;
+ super_bbox.grow(new_bbox);
+ super_diag = super_bbox.size();
+ diag = bbox.size();
+
+ // find minimum p such that enlarging bbox by a factor of 2^p in each dimension
+ // will make it at least as large as super_bbox in each dimension
+ for (i = 0; i < dim; i++) {
+ f = super_diag[i] / diag[i];
+ if (f > 1) {
+ p_ = (unsigned)ceil(log(f) / LOG_2);
+ p = max(p, p_);
+ }
+ }
+
+ // shift super_bbox to fit bbox onto the grid, increasing p if necessary
+ for (; 1; p++) {
+ f = (double)((unsigned)1 << p);
+ // extra needed in each dimension to make super_bbox 2^p times larger than bbox
+ // in each dimension
+ extra = f * diag - super_diag;
+ // determine how much we need to decrease super_bbox.min() in each dimension so that
+ // bbox fits on the grid
+ for (i = 0; i < dim; i++) {
+ d = bbox.min()[i] - super_bbox.min()[i];
+ extra_needed[i] = ceil(d / diag[i]) * diag[i] - d;
+ }
+ // do we have this much extra?
+ if (extra_needed <= extra)
+ break;
+ }
+ super_bbox.min() -= extra_needed;
+ super_bbox.max() += (extra - extra_needed);
+
+ // return super_bbox in bbox
+ bbox = super_bbox;
+ }
+
+ struct ApplyState {
+ ApplyState(int num_quadrants_)
+ : num_quadrants(num_quadrants_), tree_node(0), list_elem(0), queued_children(false), level(0), priority(0) {}
+ ApplyState(int num_quadrants_, SpatialTree::SpatialTreeNode *tree_node_)
+ : num_quadrants(num_quadrants_), tree_node(tree_node_), list_elem(0), queued_children(false), level(0), priority(0) {}
+ ApplyState(const ApplyState &state)
+ : num_quadrants(state.num_quadrants), tree_node(state.tree_node), list_elem(state.list_elem), queued_children(state.queued_children), level(state.level), priority(state.priority) {}
+ bool operator<(const ApplyState &state) const {return (priority < state.priority);}
+ int num_quadrants;
+ SpatialTree::SpatialTreeNode *tree_node;
+ SpatialTree::PrimitiveListElem *list_elem;
+ bool queued_children;
+ unsigned int level;
+ double priority; // for SEARCH_BESTFS
+ };
+
+ enum ApplySearchType {
+ SEARCH_DFS,
+ SEARCH_BFS,
+ SEARCH_BESTFS
+ };
+
+ enum ApplyProcessOrder {
+ PROCESS_CHILDREN_BEFORE_CURRENT_NODE,
+ PROCESS_CURRENT_NODE_BEFORE_CHILDREN,
+ PROCESS_CHILDREN_ONLY,
+ PROCESS_CURRENT_NODE_ONLY
+ };
+
+ class ApplyFunctor {
+ public:
+ virtual ~ApplyFunctor() {}
+ virtual ApplySearchType search_type() const {return SEARCH_DFS;}
+ virtual ApplyProcessOrder process_order() const {return PROCESS_CURRENT_NODE_BEFORE_CHILDREN;}
+ virtual bool should_process(const ApplyState &state) {return true;}
+ virtual bool operator()(const ApplyState &state) {return true;}
+ virtual bool should_process_child(const ApplyState &state, double &priority) {return true;}
+ virtual void finished_processing(const ApplyState &state) {}
+ };
+
+ class ApplyQueue {
+ public:
+ ApplyQueue(ApplySearchType type) : m_type(type) {}
+ void push(const ApplyState &state) {
+ switch(m_type) {
+ case SEARCH_DFS:
+ case SEARCH_BFS:
+ m_q.push_back(state);
+ break;
+ case SEARCH_BESTFS:
+ m_pq.push(state);
+ break;
+ }
+ }
+ const ApplyState &top() const {
+ const ApplyState *retval = 0;
+ switch(m_type) {
+ case SEARCH_DFS:
+ retval = &m_q.back();
+ break;
+ case SEARCH_BFS:
+ retval = &m_q.front();
+ break;
+ case SEARCH_BESTFS:
+ retval = &m_pq.top();
+ break;
+ }
+ return *retval;
+ }
+ void pop() {
+ switch(m_type) {
+ case SEARCH_DFS:
+ m_q.pop_back();
+ break;
+ case SEARCH_BFS:
+ m_q.pop_front();
+ break;
+ case SEARCH_BESTFS:
+ m_pq.pop();
+ break;
+ }
+ }
+ bool empty() const {
+ bool retval = false;
+ switch(m_type) {
+ case SEARCH_DFS:
+ case SEARCH_BFS:
+ retval = m_q.empty();
+ break;
+ case SEARCH_BESTFS:
+ retval = m_pq.empty();
+ break;
+ }
+ return retval;
+ }
+ private:
+ deque<ApplyState> m_q;
+ priority_queue<ApplyState,vector<ApplyState>,less<ApplyState> > m_pq;
+ ApplySearchType m_type;
+ };
+
+ void
+ apply_children(ApplyFunctor &func, ApplyState &s, ApplyQueue &q) {
+ ApplyState s2(s.num_quadrants);
+ double priority = 0;
+ int i;
+
+ if (s.tree_node->is_split()) {
+ //s2.tree_node set below
+ s2.list_elem = 0;
+ s2.queued_children = false;
+ s2.level = s.level + 1;
+ for (i = 0; i < s.num_quadrants; i++) {
+ s2.tree_node = s.tree_node->m_quadrant[i];
+ if (func.should_process_child(s2, priority)) {
+ s2.priority = priority;
+ q.push(s2);
+ }
+ }
+ }
+ }
+
+ bool
+ apply_current_node(ApplyFunctor &func, ApplyState &s) {
+ SpatialTree::PrimitiveListElem *next;
+
+ if (!s.list_elem)
+ s.list_elem = s.tree_node->m_primitive_list;
+ while (s.list_elem != 0) {
+ next = s.list_elem->next;
+ if (!func(s))
+ return false; // do not continue processing
+ s.list_elem = next;
+ }
+ return true; // continue processing
+ }
+
+ void
+ apply(ApplyFunctor &func, const ApplyState &state) {
+ ApplyQueue q(func.search_type());
+ ApplyState s(state.num_quadrants);
+
+ q.push(state);
+
+ while (!q.empty()) {
+ s = q.top();
+ q.pop();
+
+ if (func.should_process(s)) {
+ switch (func.process_order()) {
+ case PROCESS_CHILDREN_BEFORE_CURRENT_NODE:
+ if (!s.queued_children) {
+ s.queued_children = true;
+ if (func.search_type() == SEARCH_DFS)
+ q.push(s);
+ apply_children(func, s, q);
+ if (func.search_type() != SEARCH_DFS)
+ q.push(s);
+ }
+ else {
+ if (!apply_current_node(func, s))
+ return; // do not continue processing
+ func.finished_processing(s);
+ }
+ break;
+ case PROCESS_CURRENT_NODE_BEFORE_CHILDREN:
+ if (!apply_current_node(func, s))
+ return; // do not continue processing
+ s.queued_children = true;
+ apply_children(func, s, q);
+ func.finished_processing(s);
+ break;
+ case PROCESS_CHILDREN_ONLY:
+ s.queued_children = true;
+ apply_children(func, s, q);
+ func.finished_processing(s);
+ break;
+ case PROCESS_CURRENT_NODE_ONLY:
+ if (!apply_current_node(func, s))
+ return; // do not continue processing
+ func.finished_processing(s);
+ break;
+ default:
+ break;
+ }
+ }
+ }
+ }
+
+ void
+ apply(ApplyFunctor &func, int num_quadrants, SpatialTree::SpatialTreeNode *root_node) {
+ ApplyState state(num_quadrants, root_node);
+ apply(func, state);
+ }
+
+ class PrintFunctor : public ApplyFunctor {
+ public:
+ PrintFunctor(ostream &os) : m_os(os) {}
+ virtual bool should_process(const ApplyState &state) {
+ process_bbox(state.tree_node->bounding_box(), state.level, "+ ");
+ return true; // process box
+ }
+ virtual bool operator()(const ApplyState &state) {
+ process_bbox(state.list_elem->prim->bounding_box(), state.level + 1, "");
+ return true; // continue processing
+ }
+ private:
+ void process_bbox(const SpatialTree::BBoxT &bbox, int level, std::string prefix) const {
+ for (int i = 0; i < level; i++)
+ m_os << " ";
+ m_os << prefix;
+ m_os << "Min[" << bbox.min() << "] "
+ << "Max[" << bbox.max() << "]"
+ << endl;
+ }
+ ostream &m_os;
+ };
+
+ //NOTE: this can only write a 2D projection (because VRML is 3D)
+ class VRMLFunctor : public ApplyFunctor {
+ public:
+ VRMLFunctor(ostream &os) : m_os(os) {
+ m_selected_level = -1;
+ m_z_spacing = 0.5;
+ m_color[0] = 1; m_color[1] = m_color[2] = 0;
+ }
+ void select_level(int level) { m_selected_level = level; }
+ void z_spacing(float spacing) { m_z_spacing = spacing; }
+ void color(float red, float green, float blue) {
+ m_color[0] = red; m_color[1] = green; m_color[2] = blue;
+ }
+ virtual bool should_process(const ApplyState &state) {
+ process_bbox(state.tree_node->bounding_box(), state.level, 0.5);
+ return true; // process box
+ }
+ virtual bool operator()(const ApplyState &state) {
+ process_bbox(state.list_elem->prim->bounding_box(), state.level, 1.0);
+ return true; // continue processing
+ }
+ private:
+ void process_bbox(const SpatialTree::BBoxT &bbox, int level, float color_scale) const {
+ if (!m_os.fail()) {
+ if ((m_selected_level != -1) && (level != m_selected_level))
+ return;
+
+ float colors[7][3] = {{ 1.0, 0.0, 0.0 }, { 0.0, 1.0, 0.0 },
+ { 0.0, 0.0, 1.0 }, { 1.0, 0.0, 1.0 },
+ { 0.0, 1.0, 1.0 }, { 1.0, 1.0, 0.0 },
+ { 1.0, 1.0, 1.0 }};
+ static const int num_colors = 7; // r,g,b, m,c,y, w
+ int index = (level % num_colors);
+ float z = -level * m_z_spacing;
+ m_os << " Shape {" << endl;
+ m_os << " appearance Appearance {" << endl;
+ m_os << " material Material {" << endl;
+ m_os << " emissiveColor " << (colors[index][0] * color_scale) << " " << (colors[index][1] * color_scale) << " " << (colors[index][2] * color_scale) << endl;
+ m_os << " }" << endl;
+ m_os << " }" << endl;
+ m_os << " geometry IndexedLineSet {" << endl;
+ m_os << " coord Coordinate {" << endl;
+ m_os << " point [" << endl;
+ m_os << " " << bbox.min()[0] << " " << bbox.min()[1] << " " << z << "," << endl;
+ m_os << " " << bbox.min()[0] << " " << bbox.max()[1] << " " << z << "," << endl;
+ m_os << " " << bbox.max()[0] << " " << bbox.max()[1] << " " << z << "," << endl;
+ m_os << " " << bbox.max()[0] << " " << bbox.min()[1] << " " << z << "," << endl;
+ m_os << " ]" << endl;
+ m_os << " }" << endl;
+ m_os << " coordIndex [ 0, 1, 2, 3, 0, -1, ]" << endl;
+ m_os << " }" << endl;
+ m_os << " }" << endl;
+ }
+ else {
+ cout << "ERROR in VRMLFunctor: unable to write to output stream!" << endl;
+ }
+ }
+ private:
+ ostream &m_os;
+ int m_selected_level;
+ float m_z_spacing;
+ float m_color[3];
+ };
+
+ class ClosestFunctor : public ApplyFunctor {
+ public:
+ ClosestFunctor(const SpatialTree::VectorT *point, double distance_threshold = -1) : m_point(point), m_distance_threshold(distance_threshold), m_continue(true), m_prim(0), m_distance(-1) {}
+ virtual ApplySearchType search_type() const {return SEARCH_BESTFS;}
+ virtual bool should_process(const ApplyState &state) {
+ bool test = false;
+ if (m_continue) {
+ double distance = -state.priority;
+ test = test_distance(distance);
+ if (!test)
+ m_continue = false; // stop as soon as possible
+ }
+ return test;
+ }
+ virtual bool should_process_child(const ApplyState &state, double &priority) {
+ double distance = point_to_bbox_distance_heuristic(*m_point, state.tree_node->bounding_box());
+ priority = -distance;
+ return test_distance(distance);
+ }
+ virtual bool operator()(const ApplyState &state) {
+ if (m_continue) {
+ GeomPrimitive *prim = state.list_elem->prim;
+ double distance = point_to_bbox_distance_heuristic(*m_point, prim->bounding_box());
+ if (test_distance(distance)) {
+ distance = prim->distance(*m_point);
+ if (test_distance(distance)) {
+ m_prim = prim;
+ m_distance = distance;
+ }
+ }
+ }
+ return m_continue;
+ }
+ GeomPrimitive *get_primitive() {return m_prim;}
+ double get_distance() {return m_distance;}
+ private:
+ static double point_to_bbox_distance_heuristic(const SpatialTree::VectorT &point, const SpatialTree::BBoxT &bbox) {
+ double distance = 0;
+ if (!bbox.contains(point)) {
+ // the heuristic (which never over-estimates) is to circumscribe a ball around the bbox, and to calculate the distance between the point and the ball
+ distance = norm_2(point - bbox.center()) - norm_2(bbox.size())/2;
+ distance = ::std::max(distance, ::std::numeric_limits<double>::epsilon());
+ }
+ return distance;
+ }
+ inline bool test_distance(double distance) {
+ return (m_distance_threshold < 0 || distance <= m_distance_threshold) && (!m_prim || distance < m_distance);
+ }
+ const SpatialTree::VectorT *m_point;
+ double m_distance_threshold;
+ bool m_continue;
+ GeomPrimitive *m_prim;
+ double m_distance;
+ };
+
+ class ContainsOneFunctor : public ApplyFunctor {
+ public:
+ ContainsOneFunctor(const SpatialTree::VectorT *point) : m_point(point), m_prim(0) {}
+ virtual ApplyProcessOrder process_order() const {return PROCESS_CHILDREN_BEFORE_CURRENT_NODE;}
+ virtual bool should_process(const ApplyState &state) {
+ return state.tree_node->bounding_box().contains(*m_point);
+ }
+ virtual bool operator()(const ApplyState &state) {
+ GeomPrimitive *prim = state.list_elem->prim;
+ if (prim->bounding_box().contains(*m_point) && prim->contains(*m_point)) {
+ m_prim = prim;
+ return false; // stop processing
+ }
+ return true; // continue processing
+ }
+ GeomPrimitive *get_primitive() {return m_prim;}
+ private:
+ const SpatialTree::VectorT *m_point;
+ GeomPrimitive *m_prim;
+ };
+
+ class ContainsAllFunctor : public ApplyFunctor {
+ public:
+ ContainsAllFunctor(const SpatialTree::VectorT *point) : m_point(point), m_alloc(true) {
+ m_prims = new list<GeomPrimitive*>;
+ }
+ ContainsAllFunctor(const SpatialTree::VectorT *point, list<GeomPrimitive*> *prims)
+ : m_point(point), m_alloc(false), m_prims(prims) {}
+ virtual ~ContainsAllFunctor() {
+ if (m_alloc)
+ delete m_prims;
+ }
+ virtual ApplyProcessOrder process_order() const {return PROCESS_CHILDREN_BEFORE_CURRENT_NODE;}
+ virtual bool should_process(const ApplyState &state) {
+ return state.tree_node->bounding_box().contains(*m_point);
+ }
+ virtual bool operator()(const ApplyState &state) {
+ GeomPrimitive *prim = state.list_elem->prim;
+ if (prim->bounding_box().contains(*m_point) && prim->contains(*m_point))
+ m_prims->push_back(prim);
+ return true; // continue processing
+ }
+ list<GeomPrimitive*> *get_primitives() {return m_prims;}
+ private:
+ const SpatialTree::VectorT *m_point;
+ bool m_alloc;
+ list<GeomPrimitive*> *m_prims;
+ };
+
+ class AllOverlapsFunctor : public ApplyFunctor {
+ public:
+ AllOverlapsFunctor(GeomPrimitive *overlap_prim) : m_overlap_prim(overlap_prim), m_alloc(true) {
+ m_overlaps = new list<pair<GeomPrimitive*, GeomPrimitive*> >;
+ }
+ AllOverlapsFunctor(GeomPrimitive *overlap_prim,
+ list<pair<GeomPrimitive*, GeomPrimitive*> > *overlaps)
+ : m_overlap_prim(overlap_prim), m_alloc(false), m_overlaps(overlaps) {}
+ virtual ~AllOverlapsFunctor() {
+ if (m_alloc)
+ delete m_overlaps;
+ }
+ virtual ApplyProcessOrder process_order() const {return PROCESS_CURRENT_NODE_BEFORE_CHILDREN;}
+ virtual bool should_process(const ApplyState &state) {
+ return state.tree_node->bounding_box().intersects(m_overlap_prim->bounding_box());
+ }
+ virtual bool operator()(const ApplyState &state) {
+ GeomPrimitive *prim = state.list_elem->prim;
+ if (prim != m_overlap_prim && prim->bounding_box().intersects(m_overlap_prim->bounding_box()) && prim->intersects(m_overlap_prim))
+ m_overlaps->push_back(make_pair(m_overlap_prim, prim));
+ return true; // continue processing
+ }
+ list<pair<GeomPrimitive*, GeomPrimitive*> > *overlaps() {return m_overlaps;}
+ private:
+ GeomPrimitive *m_overlap_prim;
+ bool m_alloc;
+ list<pair<GeomPrimitive*, GeomPrimitive*> > *m_overlaps;
+ };
+
+ class OverlapPairsFunctor : public ApplyFunctor {
+ public:
+ OverlapPairsFunctor() : m_alloc(true) {
+ m_overlaps = new list<pair<GeomPrimitive*, GeomPrimitive*> >;
+ }
+ OverlapPairsFunctor(list<pair<GeomPrimitive*, GeomPrimitive*> > *overlaps)
+ : m_alloc(false), m_overlaps(overlaps) {}
+ virtual ~OverlapPairsFunctor() {
+ if (m_alloc)
+ delete m_overlaps;
+ }
+ virtual ApplyProcessOrder process_order() const {return PROCESS_CURRENT_NODE_BEFORE_CHILDREN;}
+ virtual bool operator()(const ApplyState &state) {
+ AllOverlapsFunctor func(state.list_elem->prim, m_overlaps);
+ //NOTE: we do not want to create a new state s with s.list_elem = state.list_elem->next
+ // because then, if s.list_elem == 0, apply() will go through the entire primitive list
+ // for the current node; instead, we rely on AllOverlapsFunctor to not add pairs where
+ // the two prims are the same (by pointer value)
+ apply(func, state);
+ return true; // continue processing
+ }
+ list<pair<GeomPrimitive*, GeomPrimitive*> > *overlaps() {return m_overlaps;}
+ private:
+ bool m_alloc;
+ list<pair<GeomPrimitive*, GeomPrimitive*> > *m_overlaps;
+ };
+
+ class NodeContainsBBoxFunctor : public ApplyFunctor {
+ public:
+ NodeContainsBBoxFunctor(const SpatialTree::BBoxT &bbox, int num_quadrants, bool create_children = false, int max_create_level = -1)
+ : m_bbox(bbox), m_create_children(create_children), m_max_create_level(max_create_level), m_tree_node(0), m_first_split_tree_node(0), m_forced_this_level(false) {}
+ virtual ApplyProcessOrder process_order() const {return PROCESS_CHILDREN_ONLY;}
+ virtual bool should_process(const ApplyState &state) {
+ if (!state.tree_node->bounding_box().contains(m_bbox))
+ return false; // do not process
+
+ if (m_create_children && !state.tree_node->is_split()) {
+ if (m_max_create_level < 0 || state.level < (unsigned int)m_max_create_level) {
+ SpatialTree::BBoxT quadrant_bboxes[state.num_quadrants];
+
+ split_bbox(state.tree_node->bounding_box(), state.num_quadrants, quadrant_bboxes);
+ // Check to see if new bbox would fit in a child quad... if so create
+ // the quadrants
+ for (int i = 0; i < state.num_quadrants; i++) {
+ if (quadrant_bboxes[i].contains(m_bbox)) {
+ // we need to make quads...
+ split_node(state.tree_node, state.num_quadrants, quadrant_bboxes);
+ break;
+ }
+ }
+
+ if (!m_first_split_tree_node)
+ m_first_split_tree_node = state.tree_node;
+ }
+ else
+ m_forced_this_level = true;
+ }
+
+ m_tree_node = state.tree_node;
+
+ return true; // process node
+ }
+ virtual bool should_process_child(const ApplyState &state, double &priority) {
+ priority = 0;
+ return state.tree_node->bounding_box().contains(m_bbox);
+ }
+ SpatialTree::SpatialTreeNode *tree_node() {return m_tree_node;}
+ SpatialTree::SpatialTreeNode *first_split_tree_node() {return m_first_split_tree_node;}
+ bool forced_this_level() {return m_forced_this_level;}
+ private:
+ SpatialTree::BBoxT m_bbox;
+ bool m_create_children;
+ int m_max_create_level;
+ SpatialTree::SpatialTreeNode *m_tree_node;
+ SpatialTree::SpatialTreeNode *m_first_split_tree_node;
+ bool m_forced_this_level;
+ };
+
+ class CleanupFunctor : public ApplyFunctor {
+ public:
+ CleanupFunctor() {}
+ virtual ApplyProcessOrder process_order() const {return PROCESS_CHILDREN_BEFORE_CURRENT_NODE;}
+ virtual bool operator()(const ApplyState &state) {
+ delete state.list_elem;
+ return true; // continue processing
+ }
+ virtual void finished_processing(const ApplyState &state) {
+ for (int i = 0; i < state.num_quadrants; i++)
+ state.tree_node->m_quadrant[i] = 0;
+ state.tree_node->m_primitive_list = 0;
+ state.tree_node->m_num_primitives = 0; // mostly for debugging
+ state.tree_node->m_is_split = false;
+ delete state.tree_node;
+ }
+ };
+
+ class CheckFunctor : public ApplyFunctor {
+ public:
+ CheckFunctor(std::ostream &os) : m_os(os), m_success(true) {}
+ virtual ApplyProcessOrder process_order() const {return PROCESS_CURRENT_NODE_BEFORE_CHILDREN;}
+ virtual bool should_process(const ApplyState &state) {
+ double v, v2;
+ SpatialTree::BBoxT b, b2;
+ double f;
+ int i, j;
+ if (!state.tree_node->is_split())
+ return true; // process node
+ v = prod(state.tree_node->bounding_box().size());
+ for (i = 0; i < state.num_quadrants; i++) {
+ b.grow(state.tree_node->m_quadrant[i]->bounding_box());
+ if (!state.tree_node->bounding_box().contains(state.tree_node->m_quadrant[i]->bounding_box())) {
+ m_os << "SpatialTree::check(): Child node with bbox " << state.tree_node->m_quadrant[i]->bounding_box() << " is not contained in its parent node with bbox " << state.tree_node->bounding_box() << "!" << endl;
+ m_success = false;
+ }
+ v2 = prod(state.tree_node->m_quadrant[i]->bounding_box().size());
+ f = state.num_quadrants * v2 / v;
+ if (f < 0.95 || f > 1.05) {
+ m_os << "SpatialTree::check(): Child node with bbox " << state.tree_node->m_quadrant[i]->bounding_box() << " has volume " << v2 << ", but its parent with bbox " << state.tree_node->bounding_box() << " has volume " << v << " (" << state.num_quadrants << " * " << v2 << " / " << v << " = " << f << " != 1)!" << endl;
+ m_success = false;
+ }
+ for (j = i + 1; j < state.num_quadrants; j++) {
+ b2 = state.tree_node->m_quadrant[i]->bounding_box();
+ b2.crop(state.tree_node->m_quadrant[j]->bounding_box());
+ v2 = prod(b2.size());
+ f = state.num_quadrants * v2 / v;
+ if (f > 0.05) {
+ m_os << "SpatialTree::check(): Children nodes with bboxes " << state.tree_node->m_quadrant[i]->bounding_box() << " and " << state.tree_node->m_quadrant[j]->bounding_box() << " of parent node with bbox " << state.tree_node->bounding_box() << " have non-trivial intersection!" << endl;
+ m_success = false;
+ }
+ }
+ }
+ v2 = prod(b.size());
+ f = v2 / v;
+ if (f < 0.95 || f > 1.05) {
+ m_os << "SpatialTree::check(): Union of children nodes of parent node with bbox " << state.tree_node->bounding_box() << " has volume " << v2 << ", but parent node has volume " << v << "!" << endl;
+ m_success = false;
+ }
+ return true; // process node
+ }
+ virtual bool operator()(const ApplyState &state) {
+ int i;
+ if (!state.tree_node->bounding_box().contains(state.list_elem->prim->bounding_box())) {
+ m_os << "SpatialTree::check(): Primitive with bbox " << state.list_elem->prim->bounding_box() << " is not contained in tree node with bbox " << state.tree_node->bounding_box() << "!" << endl;
+ m_success = false;
+ }
+ if (state.tree_node->is_split()) {
+ for (i = 0; i < state.num_quadrants; i++) {
+ if (state.tree_node->m_quadrant[i]->bounding_box().contains(state.list_elem->prim->bounding_box())) {
+ m_os << "SpatialTree::check(): Primitive with bbox " << state.list_elem->prim->bounding_box() << " is in tree node with bbox " << state.tree_node->bounding_box() << ", but it is contained in this node's child with bbox " << state.tree_node->m_quadrant[i]->bounding_box() << "!" << endl;
+ m_success = false;
+ }
+ }
+ }
+ else if (!state.list_elem->forced_this_level) {
+ SpatialTree::BBoxT quadrant_bboxes[state.num_quadrants];
+ split_bbox(state.tree_node->bounding_box(), state.num_quadrants, quadrant_bboxes);
+ for (i = 0; i < state.num_quadrants; i++) {
+ if (quadrant_bboxes[i].contains(state.list_elem->prim->bounding_box())) {
+ m_os << "SpatialTree::check(): Primitive with bbox " << state.list_elem->prim->bounding_box() << " is in tree node with bbox " << state.tree_node->bounding_box() << " at level " << state.level << ", but it could be contained in this node's child with bbox " << quadrant_bboxes[i] << " except that that child does not exist!" << endl;
+ m_success = false;
+ }
+ }
+ }
+ return true; // continue processing
+ }
+ bool success() {return m_success;}
+ private:
+ ostream &m_os;
+ bool m_success;
+ };
+
+} // namespace
+
+namespace vw {
+namespace geometry {
+
+ GeomPrimitive *
+ SpatialTree::closest(const VectorT &point, double distance_threshold /*= -1*/, double *distance /*= 0*/) {
+ ClosestFunctor func(&point, distance_threshold);
+ apply(func, m_num_quadrants, m_root_node);
+ if (distance)
+ *distance = func.get_distance();
+ return func.get_primitive();
+ }
+
+ GeomPrimitive *
+ SpatialTree::contains(const VectorT &point) {
+ ContainsOneFunctor func(&point);
+ apply(func, m_num_quadrants, m_root_node);
+ return func.get_primitive();
+ }
+
+ void
+ SpatialTree::contains(const VectorT &point, list<GeomPrimitive*> &prims) {
+ ContainsAllFunctor func(&point, &prims);
+ apply(func, m_num_quadrants, m_root_node);
+ }
+
+ void
+ SpatialTree::overlap_pairs(list<pair<GeomPrimitive*, GeomPrimitive*> > &overlaps) {
+ OverlapPairsFunctor func(&overlaps);
+ apply(func, m_num_quadrants, m_root_node);
+ }
+
+ void
+ SpatialTree::print(ostream &os /*= cout*/) {
+ PrintFunctor func(os);
+ apply(func, m_num_quadrants, m_root_node);
+ }
+
+ void
+ SpatialTree::write_vrml(char *fn, int level) {
+ ofstream os(fn);
+
+ if (os.fail()) {
+ fprintf(stderr, "write_vrml(): cannot open output file: %s\n", fn);
+ exit(-1);
+ }
+
+ write_vrml(os, level);
+
+ os.close();
+ }
+
+ void
+ SpatialTree::write_vrml(ostream &os, int level) {
+ assert(m_num_quadrants >= 4);
+ VectorT center = bounding_box().center();
+
+ os << "#VRML V2.0 utf8" << endl << "#" << endl;
+ os << "Transform {" << endl;
+ os << " translation " << -center[0] << " " << -center[1] << " 0" << endl;
+ os << " children [" << endl;
+
+ VRMLFunctor func(os);
+ func.select_level(level);
+ apply(func, m_num_quadrants, m_root_node);
+
+ os << " ]" << endl;
+ os << "}" << endl;
+ }
+
+ bool
+ SpatialTree::check(std::ostream &os /*= std::cerr*/) {
+ CheckFunctor func(os);
+ apply(func, m_num_quadrants, m_root_node);
+ return func.success();
+ }
+
+ void
+ SpatialTree::add(GeomPrimitive *prim, int max_create_level /*= -1*/) {
+ SpatialTreeNode *tree_node;
+ SpatialTreeNode *first_split_tree_node;
+ PrimitiveListElem *new_list_elem;
+ PrimitiveListElem *prev_list_elem;
+ PrimitiveListElem *list_elem;
+
+ // expand size of entire spatial tree, if necessary
+ if (!m_root_node->bounding_box().contains(prim->bounding_box())) {
+ int i;
+
+ // create tree structure above the current root
+ BBoxT bbox = m_root_node->bounding_box(), super_bbox = m_root_node->bounding_box();
+ grow_bbox_on_grid(super_bbox, prim->bounding_box());
+ NodeContainsBBoxFunctor func2(bbox, m_num_quadrants, true);
+ SpatialTreeNode *root_node = new SpatialTreeNode(m_num_quadrants);
+ root_node->m_bbox = super_bbox;
+ apply(func2, m_num_quadrants, root_node);
+ tree_node = func2.tree_node();
+
+ // at this point we either have the node that is equivalent to the
+ // old root node, or its parent (due to numerical issues)
+ double f = prod(tree_node->bounding_box().size()) / prod(m_root_node->bounding_box().size());
+ if (f > (double)(m_num_quadrants + 1) / 2) {
+ // we have the parent (volume is m_num_quadrants times greater)
+ BBoxT quadrant_bboxes[m_num_quadrants];
+ split_bbox(tree_node->bounding_box(), m_num_quadrants, quadrant_bboxes);
+ split_node(tree_node, m_num_quadrants, quadrant_bboxes);
+ for (i = 0; i < m_num_quadrants; i++) {
+ if (tree_node->m_quadrant[i]->bounding_box().contains(bbox.center())) {
+ tree_node = tree_node->m_quadrant[i];
+ break;
+ }
+ }
+ }
+
+ // tree_node holds the node that is equivalent to the old root node;
+ // transfer everything from the old root node to tree_node
+ assert(!tree_node->is_split() && tree_node->m_num_primitives == 0);
+ for (i = 0; i < m_num_quadrants; i++) {
+ tree_node->m_quadrant[i] = m_root_node->m_quadrant[i];
+ m_root_node->m_quadrant[i] = 0;
+ }
+ tree_node->m_is_split = m_root_node->m_is_split;
+ m_root_node->m_is_split = false;
+ tree_node->m_primitive_list = m_root_node->m_primitive_list;
+ m_root_node->m_primitive_list = 0;
+ tree_node->m_num_primitives = m_root_node->m_num_primitives;
+ m_root_node->m_num_primitives = 0;
+
+ // replace the root node
+ delete m_root_node;
+ m_root_node = root_node;
+ }
+
+ // find the smallest spatial tree node containing the primitive's bbox
+ NodeContainsBBoxFunctor func(prim->bounding_box(), m_num_quadrants, true, max_create_level);
+ apply(func, m_num_quadrants, m_root_node);
+ tree_node = func.tree_node();
+ assert(tree_node);
+
+ // add primitive to this spatial tree node
+ new_list_elem = new PrimitiveListElem;
+ new_list_elem->prim = prim;
+ new_list_elem->forced_this_level = func.forced_this_level();
+ new_list_elem->next = tree_node->m_primitive_list;
+ tree_node->m_primitive_list = new_list_elem;
+ tree_node->m_num_primitives++;
+
+ // if we split any tree nodes, check for primitives in the
+ // first split node that have forced_this_level set
+ first_split_tree_node = func.first_split_tree_node();
+ if (first_split_tree_node) {
+ for (prev_list_elem = 0, list_elem = first_split_tree_node->m_primitive_list; list_elem; prev_list_elem = list_elem, list_elem = list_elem->next) {
+ if (list_elem->forced_this_level) {
+ NodeContainsBBoxFunctor func3(list_elem->prim->bounding_box(), m_num_quadrants, false);
+ apply(func3, m_num_quadrants, first_split_tree_node);
+ tree_node = func3.tree_node();
+ if (tree_node != first_split_tree_node) {
+ // determine whether the primitive should have forced_this_level set
+ list_elem->forced_this_level = false;
+ if (!tree_node->is_split()) {
+ BBoxT quadrant_bboxes[m_num_quadrants];
+ split_bbox(tree_node->bounding_box(), m_num_quadrants, quadrant_bboxes);
+ for (int i = 0; i < m_num_quadrants; i++) {
+ if (quadrant_bboxes[i].contains(list_elem->prim->bounding_box())) {
+ list_elem->forced_this_level = true;
+ break;
+ }
+ }
+ }
+ // remove the primitive from its current tree node, and add it to the new one
+ if (prev_list_elem)
+ prev_list_elem->next = list_elem->next;
+ else
+ first_split_tree_node->m_primitive_list = list_elem->next;
+ first_split_tree_node->m_num_primitives--;
+ list_elem->next = tree_node->m_primitive_list;
+ tree_node->m_primitive_list = list_elem;
+ tree_node->m_num_primitives++;
+ }
+ }
+ }
+ }
+ }
+
+ SpatialTree::SpatialTree(BBoxT bbox) {
+ m_dim = bbox.min().size();
+ m_num_quadrants = (int)((unsigned)1 << (unsigned)m_dim);
+ m_root_node = new SpatialTreeNode(m_num_quadrants);
+ m_root_node->m_bbox = bbox;
+ }
+
+ SpatialTree::SpatialTree(int num_primitives, GeomPrimitive **prims, int max_create_level /*= -1*/) {
+ VW_ASSERT( prims != 0 && prims[0] != 0, ArgumentErr() << "No GeomPrimitives provided." );
+ m_dim = prims[0]->bounding_box().min().size();
+ m_num_quadrants = (int)((unsigned)1 << (unsigned)m_dim);
+ m_root_node = new SpatialTreeNode(m_num_quadrants);
+ grow_bbox(m_root_node->m_bbox, num_primitives, prims);
+ for (int i = 0; i < num_primitives; i++)
+ add(prims[i], max_create_level);
+ }
+
+ SpatialTree::~SpatialTree() {
+ CleanupFunctor func;
+ apply(func, m_num_quadrants, m_root_node);
+ m_root_node = 0;
+ }
+
+}} // namespace vw::math
89 src/vw/Geometry/SpatialTree.h
View
@@ -0,0 +1,89 @@
+#ifndef __VW_MATH_SPATIAL_TREE_H__
+#define __VW_MATH_SPATIAL_TREE_H__
+
+// Note that this class is not intended to implement a Binary
+// Space Partition (BSP)...
+
+// STL includes:
+#include <iostream>
+#include <list>
+
+#include <vw/Math/Vector.h>
+#include <vw/Math/BBox.h>
+
+namespace vw {
+namespace geometry {
+
+ class GeomPrimitive {
+ public:
+ virtual ~GeomPrimitive() {}
+ // distance() must be implemented to call SpatialTree::closest()
+ virtual double distance(const Vector<double> &point) const;
+ // contains() must be implemented to call SpatialTree::contains()
+ virtual bool contains(const Vector<double> &point) const;
+ // intersects() must be implemented to call SpatialTree::overlap_pairs()
+ virtual bool intersects(const GeomPrimitive *prim) const;
+ virtual const BBox<double> &bounding_box() const = 0;
+ };
+
+ class SpatialTree {
+ public:
+ typedef BBox<double> BBoxT;
+ typedef Vector<double> VectorT;
+
+ struct PrimitiveListElem {
+ PrimitiveListElem() {
+ next = 0;
+ prim = 0;
+ forced_this_level = false;
+ }
+ PrimitiveListElem *next;
+ GeomPrimitive *prim;
+ bool forced_this_level;
+ };
+
+ struct SpatialTreeNode {
+ SpatialTreeNode(int num_quadrants) {
+ m_quadrant = new SpatialTreeNode*[num_quadrants];
+ for (int i = 0; i < num_quadrants; i++)
+ m_quadrant[i] = 0;
+ m_primitive_list = 0;
+ m_num_primitives = 0; // mostly for debugging
+ m_is_split = false;
+ }
+ ~SpatialTreeNode() {
+ delete[] m_quadrant;
+ m_quadrant = 0;
+ }
+ bool is_split() { return m_is_split; }
+ BBoxT &bounding_box() { return m_bbox; }
+ BBoxT m_bbox;
+ PrimitiveListElem *m_primitive_list;
+ int m_num_primitives; // mostly for debugging
+ SpatialTreeNode **m_quadrant;
+ bool m_is_split;
+ };
+
+ SpatialTree(BBoxT bbox);
+ SpatialTree(int num_primitives, GeomPrimitive **prims, int max_create_level = -1);
+ ~SpatialTree();
+ void add(GeomPrimitive *prim, int max_create_level = -1);
+ const BBoxT &bounding_box() const { return m_root_node->m_bbox; }
+ GeomPrimitive *closest(const VectorT &point, double distance_threshold = -1, double *distance = 0);
+ GeomPrimitive *contains(const VectorT &point);
+ void contains(const VectorT &point, std::list<GeomPrimitive*> &prims);
+ void overlap_pairs(std::list<std::pair<GeomPrimitive*, GeomPrimitive*> > &overlaps);
+ void print(std::ostream &os = std::cout);
+ //NOTE: this can only write a 2D projection (because VRML is 3D)
+ void write_vrml(char *fn, int level = -1);
+ void write_vrml(std::ostream &os = std::cout, int level = -1);
+ bool check(std::ostream &os = std::cerr);
+ private:
+ int m_dim;
+ int m_num_quadrants;
+ SpatialTreeNode *m_root_node;
+ };
+
+}} // namespace vw::math
+
+#endif // _SPATIAL_TREE_H_
412 src/vw/Geometry/Sphere.h
View
@@ -0,0 +1,412 @@
+// __BEGIN_LICENSE__
+//
+// Copyright (C) 2006 United States Government as represented by the
+// Administrator of the National Aeronautics and Space Administration
+// (NASA). All Rights Reserved.
+//
+// Copyright 2006 Carnegie Mellon University. All rights reserved.
+//
+// This software is distributed under the NASA Open Source Agreement
+// (NOSA), version 1.3. The NOSA has been approved by the Open Source
+// Initiative. See the file COPYING at the top of the distribution
+// directory tree for the complete NOSA document.
+//
+// THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF ANY
+// KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT
+// LIMITED TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO
+// SPECIFICATIONS, ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR
+// A PARTICULAR PURPOSE, OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT
+// THE SUBJECT SOFTWARE WILL BE ERROR FREE, OR ANY WARRANTY THAT
+// DOCUMENTATION, IF PROVIDED, WILL CONFORM TO THE SUBJECT SOFTWARE.
+//
+// __END_LICENSE__
+
+/// \file Sphere.h
+///
+/// A sphere shape class.
+#ifndef __VW_GEOMETRY_SPHERE_H__
+#define __VW_GEOMETRY_SPHERE_H__
+
+#include <iostream>
+#include <math.h>
+
+#include <boost/static_assert.hpp>
+
+#include <vw/Math/Vector.h>
+#include <vw/Geometry/Shape.h>
+
+namespace vw {
+namespace geometry {
+
+ // *******************************************************************
+ // class SphereBase
+ // *******************************************************************
+
+ /// A general n-dimensional sphere class,
+ /// represented by a vector pointing to the center, and a radius.
+ template <class SphereT, class RealT, int DimN>
+ class SphereBase : public ShapeBase<SphereBase<SphereT, RealT, DimN>, RealT, DimN> {
+ public:
+
+ /// Default constructor. Constructs an empty sphere.
+ SphereBase() : m_empty( true ) {}
+
+ /// Constructs a sphere with the given center and radius.
+ template <class VectorT>
+ SphereBase( VectorBase<VectorT> const& center, RealT radius ) :
+ m_center( center ), m_radius( radius ), m_empty( false ) {}
+
+ /// Constructs a 2D sphere with the given center point
+ /// coordinates and radius. (Only valid for 2D spheres.)
+ SphereBase( RealT centerx, RealT centery, RealT radius )
+ : m_center( Vector<RealT,2>(centerx,centery) ),
+ m_radius( radius ), m_empty( false ) {}
+
+ /// Constructs a 3D sphere with the given center point
+ /// coordinates and radius. (Only valid for 3D spheres.)
+ SphereBase( RealT centerx, RealT centery, RealT centerz, RealT radius )
+ : m_center( Vector<RealT,3>(centerx,centery,centerz) ),
+ m_radius( radius ), m_empty( false ) {}
+
+ /// Returns the derived implementation type.
+ SphereT& impl() { return *static_cast<SphereT*>(this); }
+
+ /// Returns the derived implementation type.
+ SphereT const& impl() const { return *static_cast<SphereT const*>(this); }
+
+ /// Grows a sphere to include the given point.
+ template <class VectorT>
+ void grow( VectorBase<VectorT> const& point ) {
+ VW_ASSERT(m_center.size() == 0 || point.impl().size() == m_center.size(), ArgumentErr() << "Vector must have dimension " << m_center.size() << ".");
+ if (empty()) {
+ m_center = point;
+ m_radius = 0;
+ m_empty = false;
+ }
+ else {
+ Vector<RealT, DimN> v = point - m_center;
+ double dist = norm_2(v);
+ double radius_d;
+ if (dist > (double)m_radius) {
+ radius_d = (dist - (double)m_radius)/2;
+ m_center += v/dist*radius_d;
+ v = point - m_center;
+ dist = norm_2(v);
+ if (dist > 0)
+ m_radius += (RealT)dist;
+ }
+ }
+ }
+
+ /// Grows a sphere to include the given sphere.
+ template <class SphereT1, class RealT1, int DimN1>
+ void grow( SphereBase<SphereT1, RealT1, DimN1> const& sphere ) {
+ if (sphere.empty())
+ return;
+ if (empty()) {
+ m_center = sphere.center_();
+ m_radius = sphere.radius();
+ m_empty = sphere.empty();
+ }
+ else {
+ Vector<RealT, DimN> v = sphere.center_() - m_center;
+ grow(sphere.center_() + normalize(v)*sphere.radius());
+ }
+ }
+
+ /// Crops (intersects) this sphere to the given sphere.
+ template <class SphereT1, class RealT1, int DimN1>
+ void crop( SphereBase<SphereT1, RealT1, DimN1> const& sphere ) {
+ if (empty() || sphere.empty())
+ return;
+ Vector<RealT, DimN> v = sphere.center_() - m_center;
+ RealT dist = (RealT)norm_2(v);
+ if (dist > (m_radius + sphere.radius())) {
+ // intersects(sphere) == false
+ m_radius = 0;
+ m_empty = true;
+ }
+ else if (dist <= (m_radius - sphere.radius())) {
+ // contains(sphere) == true
+ m_center = sphere.center_();
+ m_radius = sphere.radius();
+ }
+ else if (dist <= (sphere.radius() - m_radius)) {
+ // sphere.contains(*this) == true
+ // smallest Sphere is *this
+ return;
+ }
+ else if (m_radius >= dist) {
+ // smallest Sphere is sphere
+ m_center = sphere.center_();
+ m_radius = sphere.radius();
+ }
+ else if (sphere.radius() >= dist) {
+ // smallest Sphere is *this
+ return;
+ }
+ else {
+ // normal intersection
+ RealT x = (dist + (m_radius*m_radius - sphere.radius()*sphere.radius())/dist)/2;
+ m_center += v/dist*x;
+ m_radius = std::sqrt(m_radius*m_radius - x*x);
+ }
+ }
+
+ /// Expands this sphere by the given offset in every direction.
+ void expand( RealT offset ) {
+ if (!empty())
+ m_radius += offset;
+ }
+
+ /// Contracts this sphere by the given offset in every direction.
+ void contract( RealT offset ) {
+ if (!empty())
+ m_radius -= offset;
+ }
+
+ /// Returns true if the given point is contained in the sphere.
+ template <class VectorT>
+ bool contains( const VectorBase<VectorT> &point ) const {
+ VW_ASSERT(m_center.size() == 0 || point.impl().size() == m_center.size(), ArgumentErr() << "Vector must have dimension " << m_center.size() << ".");
+ return (!empty() && (norm_2(m_center - point) <= (double)m_radius));
+ }
+
+ /// Returns true if the given sphere is entirely contained
+ /// in this sphere.
+ template <class SphereT1, class RealT1, int DimN1>
+ bool contains( const SphereBase<SphereT1, RealT1, DimN1> &sphere ) const {
+ return (!empty() && !sphere.empty() && (norm_2(m_center - sphere.center_()) <= (double)(m_radius - sphere.radius())));
+ }
+
+ /// Returns true if the given sphere intersects this
+ /// sphere.
+ template <class SphereT1, class RealT1, int DimN1>
+ bool intersects( const SphereBase<SphereT1, RealT1, DimN1>& sphere ) const {
+ return (!empty() && !sphere.empty() && (norm_2(m_center - sphere.center_()) <= (double)(m_radius + sphere.radius())));
+ }
+
+ /// Returns the size (i.e. the diameter) of the sphere.
+ RealT size() const { return 2*m_radius; }
+
+ /// Returns the center point of the sphere.
+ Vector<RealT, DimN> center() const { return m_center; }
+
+ /// Returns the center point of the sphere.
+ Vector<RealT, DimN> const& center_() const { return m_center; }
+
+ /// Returns the center point of the sphere.
+ Vector<RealT, DimN> &center_() { return m_center; }
+
+ /// Returns the radius of the sphere.
+ RealT const& radius() const { return m_radius; }
+
+ /// Returns the radius of the sphere.
+ RealT &radius() { return m_radius; }
+
+ /// Returns true if the sphere is empty (i.e. degenerate).
+ /// Note that even a zero-radius sphere is not empty,
+ /// because spheres contain their surfaces: a zer-radius
+ /// sphere actually consists of a single point.
+ bool empty() const { return m_empty; }
+
+ /// Scales the sphere relative to the origin.
+ template <class ScalarT>
+ SphereBase& operator*=( ScalarT s ) {
+ m_center *= s;
+ m_radius *= s;
+ return *this;
+ }
+
+ /// Scales the sphere relative to the origin.
+ template <class ScalarT>
+ SphereBase& operator/=( ScalarT s ) {
+ m_center /= s;
+ m_radius /= s;
+ return *this;
+ }
+
+ /// Offsets the sphere by the given vector.
+ template <class VectorT>
+ SphereBase& operator+=( VectorBase<VectorT> const& v ) {
+ m_center += v;
+ return *this;
+ }
+
+ /// Offsets the sphere by the negation of the given vector.
+ template <class VectorT>
+ SphereBase& operator-=( VectorBase<VectorT> const& v ) {
+ m_center -= v;
+ return *this;
+ }
+
+ protected:
+ Vector<RealT, DimN> m_center;
+ RealT m_radius;
+ bool m_empty;
+ };
+
+ /// Scales a sphere relative to the origin.
+ template <class SphereT, class RealT, int DimN, class ScalarT>
+ inline SphereT operator*( SphereBase<SphereT, RealT, DimN> const& sphere, ScalarT s ) {
+ SphereT result = sphere.impl();
+ result *= s;
+ return result;
+ }
+
+ /// Scales a sphere relative to the origin.
+ template <class SphereT, class RealT, int DimN, class ScalarT>
+ inline SphereT operator/( SphereBase<SphereT, RealT, DimN> const& sphere, ScalarT s ) {
+ SphereT result = sphere.impl();
+ result /= s;
+ return result;
+ }
+
+ /// Scales a sphere relative to the origin.
+ template <class SphereT, class RealT, int DimN, class ScalarT>
+ inline SphereT operator*( ScalarT s, SphereBase<SphereT, RealT, DimN> const& sphere ) {
+ return sphere * s;
+ }
+
+ /// Offsets a sphere by the given vector.
+ template <class SphereT, class RealT, int DimN, class VectorT>
+ inline SphereT operator+( SphereBase<SphereT, RealT, DimN> const& sphere, VectorBase<VectorT> const& v ) {
+ SphereT result = sphere.impl();
+ result += v.impl();
+ return result;
+ }
+
+ /// Offsets a sphere by the given vector.
+ template <class SphereT, class RealT, int DimN, class VectorT>
+ inline SphereT operator+( VectorBase<VectorT> const& v, SphereBase<SphereT, RealT, DimN> const& sphere ) {
+ return sphere + v;
+ }
+
+ /// Offsets a sphere by the negation of the given vector.
+ template <class SphereT, class RealT, int DimN, class VectorT>
+ inline SphereT operator-( SphereBase<SphereT, RealT, DimN> const& sphere, VectorBase<VectorT> const& v ) {
+ SphereT result = sphere.impl();
+ result -= v.impl();
+ return result;
+ }
+
+ /// Equality of two spheres.
+ template <class SphereT1, class RealT1, int DimN1, class SphereT2, class RealT2, int DimN2>
+ inline bool operator==( SphereBase<SphereT1,RealT1,DimN1> const& sphere1, SphereBase<SphereT2,RealT2,DimN2> const& sphere2 ) {
+ return sphere1.center_()==sphere2.center_() && sphere1.radius()==sphere2.radius();
+ }
+
+ /// Inequality of two spheres.
+ template <class SphereT1, class RealT1, int DimN1, class SphereT2, class RealT2, int DimN2>
+ inline bool operator!=( SphereBase<SphereT1,RealT1,DimN1> const& sphere1, SphereBase<SphereT2,RealT2,DimN2> const& sphere2 ) {
+ return sphere1.center_()!=sphere2.center_() || sphere1.radius()!=sphere2.radius();
+ }
+
+ /// Writes a sphere to an ostream.
+ template <class SphereT, class RealT, int DimN>
+ std::ostream& operator<<( std::ostream& os, SphereBase<SphereT,RealT,DimN> const& sphere ) {
+ return os << "(" << sphere.center_() << "-" << sphere.radius() << ")";
+ }
+
+ // *******************************************************************
+ // class Sphere
+ // *******************************************************************
+
+ /// A general fixed-dimensional sphere class,
+ /// represented by a vector pointing to the center, and a radius.
+ template <class RealT, int DimN = 0>
+ class Sphere : public SphereBase<Sphere<RealT, DimN>, RealT, DimN> {
+ public:
+
+ /// Default constructor. Constructs an empty sphere.
+ Sphere() : SphereBase<Sphere<RealT, DimN>, RealT, DimN>() {}
+
+ /// Constructs a sphere with the given center and radius.
+ template <class VectorT>
+ Sphere( VectorBase<VectorT> const& center, RealT radius ) :
+ SphereBase<Sphere<RealT, DimN>, RealT, DimN>( center, radius ) {}
+
+ /// Constructs a 2D sphere with the given center point
+ /// coordinates and radius. (Only valid for 2D spheres.)
+ Sphere( RealT centerx, RealT centery, RealT radius )
+ : SphereBase<Sphere<RealT, DimN>, RealT, DimN>( centerx, centery, radius ) {
+ BOOST_STATIC_ASSERT( DimN==2 );
+ }
+
+ /// Constructs a 3D sphere with the given center point
+ /// coordinates and radius. (Only valid for 3D spheres.)
+ Sphere( RealT centerx, RealT centery, RealT centerz, RealT radius )
+ : SphereBase<Sphere<RealT, DimN>, RealT, DimN>( centerx, centery, centerz, radius ) {
+ BOOST_STATIC_ASSERT( DimN==3 );
+ }
+
+ /// Copy constructor.
+ template <class SphereT1, class RealT1, int DimN1>
+ Sphere( SphereBase<SphereT1, RealT1, DimN1> const& sphere )
+ : SphereBase<Sphere<RealT, DimN>, RealT, DimN>( sphere.center_() , sphere.radius() ) {}
+
+ /// Copy assignment operator.
+ template <class SphereT1, class RealT1, int DimN1>
+ Sphere& operator=( SphereBase<SphereT1, RealT1, DimN1> const& sphere ) {
+ this->center_() = sphere.center_();
+ this->radius() = sphere.radius();
+ this->m_empty = sphere.empty();
+ return *this;
+ }
+ };
+
+ /// A general arbitrary-dimensional sphere class,
+ /// represented by a vector pointing to the center, and a radius.
+ template <class RealT>
+ class Sphere<RealT, 0> : public SphereBase<Sphere<RealT, 0>, RealT, 0> {
+ public:
+
+ /// Default constructor. Constructs an empty sphere.
+ Sphere() : SphereBase<Sphere<RealT, 0>, RealT, 0>() {}
+
+ /// Constructs a sphere with the given center and radius.
+ template <class VectorT>
+ Sphere( VectorBase<VectorT> const& center, RealT radius ) :
+ SphereBase<Sphere<RealT, 0>, RealT, 0>( center, radius ) {}
+
+ /// Constructs a 2D sphere with the given center point
+ /// coordinates and radius. (Only valid for 2D spheres.)
+ Sphere( RealT centerx, RealT centery, RealT radius )
+ : SphereBase<Sphere<RealT, 0>, RealT, 0>( centerx, centery, radius ) {}
+
+ /// Constructs a 3D sphere with the given center point
+ /// coordinates and radius. (Only valid for 3D spheres.)
+ Sphere( RealT centerx, RealT centery, RealT centerz, RealT radius )
+ : SphereBase<Sphere<RealT, 0>, RealT, 0>( centerx, centery, centerz, radius ) {}
+
+ /// Copy constructor.
+ template <class SphereT1, class RealT1, int DimN1>
+ Sphere( SphereBase<SphereT1, RealT1, DimN1> const& sphere )
+ : SphereBase<Sphere<RealT, 0>, RealT, 0>( sphere.center_() , sphere.radius() ) {}
+
+ /// Copy assignment operator.
+ template <class SphereT1, class RealT1, int DimN1>
+ Sphere& operator=( SphereBase<SphereT1, RealT1, DimN1> const& sphere ) {
+ this->center_() = sphere.center_();
+ this->radius() = sphere.radius();
+ this->m_empty = sphere.empty();
+ return *this;
+ }
+ };
+
+} // namespace math
+
+ // Convenience typedefs
+ using geometry::Sphere;
+ typedef Sphere<float64, 2> Sphere2;
+ typedef Sphere<float64, 3> Sphere3;
+ typedef Sphere<float64, 4> Sphere4;
+ typedef Sphere<float64> SphereN;
+ typedef Sphere<float32, 2> Sphere2f;
+ typedef Sphere<float32, 3> Sphere3f;
+ typedef Sphere<float32, 4> Sphere4f;
+ typedef Sphere<float32> SphereNf;
+
+} // namespace vw
+
+#endif // __VW_GEOMETRY_SPHERE_H__
50 src/vw/Geometry/tests/Makefile.am
View
@@ -0,0 +1,50 @@
+# __BEGIN_LICENSE__
+#
+# Copyright (C) 2006 United States Government as represented by the
+# Administrator of the National Aeronautics and Space Administration
+# (NASA). All Rights Reserved.
+#
+# Copyright 2006 Carnegie Mellon University. All rights reserved.
+#
+# This software is distributed under the NASA Open Source Agreement
+# (NOSA), version 1.3. The NOSA has been approved by the Open Source
+# Initiative. See the file COPYING at the top of the distribution
+# directory tree for the complete NOSA document.
+#
+# THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF ANY
+# KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT
+# LIMITED TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO
+# SPECIFICATIONS, ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR
+# A PARTICULAR PURPOSE, OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT
+# THE SUBJECT SOFTWARE WILL BE ERROR FREE, OR ANY WARRANTY THAT
+# DOCUMENTATION, IF PROVIDED, WILL CONFORM TO THE SUBJECT SOFTWARE.
+#
+# __END_LICENSE__
+
+########################################################################
+# sources
+########################################################################
+
+if MAKE_MODULE_GEOMETRY
+
+nodist_TestSphere_SOURCES = TestSphere.cxx
+nodist_TestSpatialTree_SOURCES = TestSpatialTree.cxx
+
+TESTS = TestSphere TestSpatialTree
+
+include $(top_srcdir)/config/instantiate.am
+
+endif
+
+########################################################################
+# general
+########################################################################
+
+AM_CPPFLAGS = @VW_CPPFLAGS@ -I$(top_srcdir)/thirdparty/cxxtest
+AM_LDFLAGS = @VW_LDFLAGS@ @PKG_GEOMETRY_LIBS@ @PKG_VW_LIBS@
+
+check_PROGRAMS = $(TESTS)
+EXTRA_DIST = $(TESTS:%=%.h)
+CLEANFILES = $(TESTS:%=%.cxx)
+
+include $(top_srcdir)/config/rules.mak
10 src/vw/Geometry/tests/TestInstantiateFree.h
View
@@ -0,0 +1,10 @@
+#include <vw/Geometry.h>
+
+using namespace vw;
+
+#include "TestInstantiateFreeList.hh"
+
+class TestInstantiateGeometryFree : public CxxTest::TestSuite
+{
+ public: void test_inst() {}
+};
9 src/vw/Geometry/tests/TestInstantiateRecord.h
View
@@ -0,0 +1,9 @@
+#include <vw/Geometry.h>
+using namespace vw;
+
+#include "TestInstantiateRecordList.hh"
+
+class TestInstantiateGeometryRecord : public CxxTest::TestSuite
+{
+ public: void test_inst() {}
+};
237 src/vw/Geometry/tests/TestSpatialTree.h
View
@@ -0,0 +1,237 @@
+// __BEGIN_LICENSE__
+//
+// Copyright (C) 2006 United States Government as represented by the
+// Administrator of the National Aeronautics and Space Administration
+// (NASA). All Rights Reserved.
+//
+// Copyright 2006 Carnegie Mellon University. All rights reserved.
+//
+// This software is distributed under the NASA Open Source Agreement
+// (NOSA), version 1.3. The NOSA has been approved by the Open Source
+// Initiative. See the file COPYING at the top of the distribution
+// directory tree for the complete NOSA document.
+//
+// THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF ANY
+// KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT
+// LIMITED TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO
+// SPECIFICATIONS, ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR
+// A PARTICULAR PURPOSE, OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT
+// THE SUBJECT SOFTWARE WILL BE ERROR FREE, OR ANY WARRANTY THAT
+// DOCUMENTATION, IF PROVIDED, WILL CONFORM TO THE SUBJECT SOFTWARE.
+//
+// __END_LICENSE__
+
+#include <sstream>
+
+#include <cxxtest/TestSuite.h>
+#include <vw/Math/Vector.h>
+#include <vw/Math/BBox.h>
+#include <vw/Geometry/SpatialTree.h>
+
+using namespace std;
+using namespace vw;
+using namespace vw::geometry;
+
+#define TEST_SPATIAL_TREE_PRINT_RESULT_1D "+ Min[Vector1(0)] Max[Vector1(16)]\n + Min[Vector1(8)] Max[Vector1(16)]\n + Min[Vector1(12)] Max[Vector1(16)]\n + Min[Vector1(8)] Max[Vector1(12)]\n + Min[Vector1(10)] Max[Vector1(12)]\n + Min[Vector1(8)] Max[Vector1(10)]\n + Min[Vector1(9)] Max[Vector1(10)]\n + Min[Vector1(9.5)] Max[Vector1(10)]\n + Min[Vector1(9)] Max[Vector1(9.5)]\n + Min[Vector1(9.25)] Max[Vector1(9.5)]\n + Min[Vector1(9)] Max[Vector1(9.25)]\n + Min[Vector1(9.125)] Max[Vector1(9.25)]\n + Min[Vector1(9)] Max[Vector1(9.125)]\n Min[Vector1(9)] Max[Vector1(9.1)]\n + Min[Vector1(8)] Max[Vector1(9)]\n + Min[Vector1(0)] Max[Vector1(8)]\n + Min[Vector1(4)] Max[Vector1(8)]\n + Min[Vector1(0)] Max[Vector1(4)]\n + Min[Vector1(2)] Max[Vector1(4)]\n + Min[Vector1(0)] Max[Vector1(2)]\n + Min[Vector1(1)] Max[Vector1(2)]\n Min[Vector1(1)] Max[Vector1(1.75)]\n + Min[Vector1(1.5)] Max[Vector1(2)]\n Min[Vector1(1.5)] Max[Vector1(2)]\n + Min[Vector1(1)] Max[Vector1(1.5)]\n + Min[Vector1(0)] Max[Vector1(1)]\n + Min[Vector1(0.5)] Max[Vector1(1)]\n + Min[Vector1(0)] Max[Vector1(0.5)]\n + Min[Vector1(0.25)] Max[Vector1(0.5)]\n + Min[Vector1(0)] Max[Vector1(0.25)]\n Min[Vector1(0.1)] Max[Vector1(0.2)]\n"
+
+#define TEST_SPATIAL_TREE_PRINT_RESULT_2D "+ Min[Vector2(0,0)] Max[Vector2(16,16)]\n + Min[Vector2(8,8)] Max[Vector2(16,16)]\n + Min[Vector2(12,12)] Max[Vector2(16,16)]\n + Min[Vector2(12,8)] Max[Vector2(16,12)]\n + Min[Vector2(8,12)] Max[Vector2(12,16)]\n + Min[Vector2(8,8)] Max[Vector2(12,12)]\n + Min[Vector2(10,10)] Max[Vector2(12,12)]\n + Min[Vector2(10,8)] Max[Vector2(12,10)]\n + Min[Vector2(8,10)] Max[Vector2(10,12)]\n + Min[Vector2(8,8)] Max[Vector2(10,10)]\n + Min[Vector2(9,9)] Max[Vector2(10,10)]\n + Min[Vector2(9.5,9.5)] Max[Vector2(10,10)]\n + Min[Vector2(9.5,9)] Max[Vector2(10,9.5)]\n + Min[Vector2(9,9.5)] Max[Vector2(9.5,10)]\n + Min[Vector2(9,9)] Max[Vector2(9.5,9.5)]\n + Min[Vector2(9.25,9.25)] Max[Vector2(9.5,9.5)]\n + Min[Vector2(9.25,9)] Max[Vector2(9.5,9.25)]\n + Min[Vector2(9,9.25)] Max[Vector2(9.25,9.5)]\n + Min[Vector2(9,9)] Max[Vector2(9.25,9.25)]\n + Min[Vector2(9.125,9.125)] Max[Vector2(9.25,9.25)]\n + Min[Vector2(9.125,9)] Max[Vector2(9.25,9.125)]\n + Min[Vector2(9,9.125)] Max[Vector2(9.125,9.25)]\n + Min[Vector2(9,9)] Max[Vector2(9.125,9.125)]\n Min[Vector2(9,9)] Max[Vector2(9.1,9.1)]\n + Min[Vector2(9,8)] Max[Vector2(10,9)]\n + Min[Vector2(8,9)] Max[Vector2(9,10)]\n + Min[Vector2(8,8)] Max[Vector2(9,9)]\n + Min[Vector2(8,0)] Max[Vector2(16,8)]\n + Min[Vector2(0,8)] Max[Vector2(8,16)]\n + Min[Vector2(0,0)] Max[Vector2(8,8)]\n Min[Vector2(1.5,3)] Max[Vector2(2,5)]\n + Min[Vector2(4,4)] Max[Vector2(8,8)]\n + Min[Vector2(4,0)] Max[Vector2(8,4)]\n + Min[Vector2(0,4)] Max[Vector2(4,8)]\n + Min[Vector2(0,0)] Max[Vector2(4,4)]\n + Min[Vector2(2,2)] Max[Vector2(4,4)]\n + Min[Vector2(2,0)] Max[Vector2(4,2)]\n + Min[Vector2(0,2)] Max[Vector2(2,4)]\n Min[Vector2(1,2)] Max[Vector2(1.75,4)]\n + Min[Vector2(0,0)] Max[Vector2(2,2)]\n + Min[Vector2(1,1)] Max[Vector2(2,2)]\n + Min[Vector2(1,0)] Max[Vector2(2,1)]\n + Min[Vector2(0,1)] Max[Vector2(1,2)]\n + Min[Vector2(0,0)] Max[Vector2(1,1)]\n + Min[Vector2(0.5,0.5)] Max[Vector2(1,1)]\n + Min[Vector2(0.5,0)] Max[Vector2(1,0.5)]\n + Min[Vector2(0,0.5)] Max[Vector2(0.5,1)]\n + Min[Vector2(0,0)] Max[Vector2(0.5,0.5)]\n + Min[Vector2(0.25,0.25)] Max[Vector2(0.5,0.5)]\n + Min[Vector2(0.25,0)] Max[Vector2(0.5,0.25)]\n + Min[Vector2(0,0.25)] Max[Vector2(0.25,0.5)]\n + Min[Vector2(0,0)] Max[Vector2(0.25,0.25)]\n Min[Vector2(0.1,0.1)] Max[Vector2(0.2,0.2)]\n"
+
+#define TEST_SPATIAL_TREE_VRML_RESULT "#VRML V2.0 utf8\n#\nTransform {\n translation -8 -8 0\n children [\n Shape {\n appearance Appearance {\n material Material {\n emissiveColor 0.5 0 0\n }\n }\n geometry IndexedLineSet {\n coord Coordinate {\n point [\n 0 0 0,\n 0 16 0,\n 16 16 0,\n 16 0 0,\n ]\n }\n coordIndex [ 0, 1, 2, 3, 0, -1, ]\n }\n }\n Shape {\n appearance Appearance {\n material Material {\n emissiveColor 0 0.5 0\n }\n }\n geometry IndexedLineSet {\n coord Coordinate {\n point [\n 8 8 -0.5,\n 8 16 -0.5,\n 16 16 -0.5,\n 16 8 -0.5,\n ]\n }\n coordIndex [ 0, 1, 2, 3, 0, -1, ]\n }\n }\n Shape {\n appearance Appearance {\n material Material {\n emissiveColor 0 0 0.5\n }\n }\n geometry IndexedLineSet {\n coord Coordinate {\n point [\n 12 12 -1,\n 12 16 -1,\n 16 16 -1,\n 16 12 -1,\n ]\n }\n coordIndex [ 0, 1, 2, 3, 0, -1, ]\n }\n }\n Shape {\n appearance Appearance {\n material Material {\n emissiveColor 0 0 0.5\n }\n }\n geometry IndexedLineSet {\n coord Coordinate {\n point [\n 12 8 -1,\n 12 12 -1,\n 16 12 -1,\n 16 8 -1,\n ]\n }\n coordIndex [ 0, 1, 2, 3, 0, -1, ]\n }\n }\n Shape {\n appearance Appearance {\n material Material {\n emissiveColor 0 0 0.5\n }\n }\n geometry IndexedLineSet {\n coord Coordinate {\n point [\n 8 12 -1,\n 8 16 -1,\n 12 16 -1,\n 12 12 -1,\n ]\n }\n coordIndex [ 0, 1, 2, 3, 0, -1, ]\n }\n }\n Shape {\n appearance Appearance {\n material Material {\n emissiveColor 0 0 0.5\n }\n }\n geometry IndexedLineSet {\n coord Coordinate {\n point [\n 8 8 -1,\n 8 12 -1,\n 12 12 -1,\n 12 8 -1,\n ]\n }\n coordIndex [ 0, 1, 2, 3, 0, -1, ]\n }\n }\n Shape {\n appearance Appearance {\n material Material {\n emissiveColor 0.5 0 0.5\n }\n }\n geometry IndexedLineSet {\n coord Coordinate {\n point [\n 10 10 -1.5,\n 10 12 -1.5,\n 12 12 -1.5,\n 12 10 -1.5,\n ]\n }\n coordIndex [ 0, 1, 2, 3, 0, -1, ]\n }\n }\n Shape {\n appearance Appearance {\n material Material {\n emissiveColor 0.5 0 0.5\n }\n }\n geometry IndexedLineSet {\n coord Coordinate {\n point [\n 10 8 -1.5,\n 10 10 -1.5,\n 12 10 -1.5,\n 12 8 -1.5,\n ]\n }\n coordIndex [ 0, 1, 2, 3, 0, -1, ]\n }\n }\n Shape {\n appearance Appearance {\n material Material {\n emissiveColor 0.5 0 0.5\n }\n }\n geometry IndexedLineSet {\n coord Coordinate {\n point [\n 8 10 -1.5,\n 8 12 -1.5,\n 10 12 -1.5,\n 10 10 -1.5,\n ]\n }\n coordIndex [ 0, 1, 2, 3, 0, -1, ]\n }\n }\n Shape {\n appearance Appearance {\n material Material {\n emissiveColor 0.5 0 0.5\n }\n }\n geometry IndexedLineSet {\n coord Coordinate {\n point [\n 8 8 -1.5,\n 8 10 -1.5,\n 10 10 -1.5,\n 10 8 -1.5,\n ]\n }\n coordIndex [ 0, 1, 2, 3, 0, -1, ]\n }\n }\n Shape {\n appearance Appearance {\n material Material {\n emissiveColor 0 0.5 0.5\n }\n }\n geometry IndexedLineSet {\n coord Coordinate {\n point [\n 9 9 -2,\n 9 10 -2,\n 10 10 -2,\n 10 9 -2,\n ]\n }\n coordIndex [ 0, 1, 2, 3, 0, -1, ]\n }\n }\n Shape {\n appearance Appearance {\n material Material {\n emissiveColor 0.5 0.5 0\n }\n }\n geometry IndexedLineSet {\n coord Coordinate {\n point [\n 9.5 9.5 -2.5,\n 9.5 10 -2.5,\n 10 10 -2.5,\n 10 9.5 -2.5,\n ]\n }\n coordIndex [ 0, 1, 2, 3, 0, -1, ]\n }\n }\n Shape {\n appearance Appearance {\n material Material {\n emissiveColor 0.5 0.5 0\n }\n }\n geometry IndexedLineSet {\n coord Coordinate {\n point [\n 9.5 9 -2.5,\n 9.5 9.5 -2.5,\n 10 9.5 -2.5,\n 10 9 -2.5,\n ]\n }\n coordIndex [ 0, 1, 2, 3, 0, -1, ]\n }\n }\n Shape {\n appearance Appearance {\n material Material {\n emissiveColor 0.5 0.5 0\n }\n }\n geometry IndexedLineSet {\n coord Coordinate {\n point [\n 9 9.5 -2.5,\n 9 10 -2.5,\n 9.5 10 -2.5,\n 9.5 9.5 -2.5,\n ]\n }\n coordIndex [ 0, 1, 2, 3, 0, -1, ]\n }\n }\n Shape {\n appearance Appearance {\n material Material {\n emissiveColor 0.5 0.5 0\n }\n }\n geometry IndexedLineSet {\n coord Coordinate {\n point [\n 9 9 -2.5,\n 9 9.5 -2.5,\n 9.5 9.5 -2.5,\n 9.5 9 -2.5,\n ]\n }\n coordIndex [ 0, 1, 2, 3, 0, -1, ]\n }\n }\n Shape {\n appearance Appearance {\n material Material {\n emissiveColor 0.5 0.5 0.5\n }\n }\n geometry IndexedLineSet {\n coord Coordinate {\n point [\n 9.25 9.25 -3,\n 9.25 9.5 -3,\n 9.5 9.5 -3,\n 9.5 9.25 -3,\n ]\n }\n coordIndex [ 0, 1, 2, 3, 0, -1, ]\n }\n }\n Shape {\n appearance Appearance {\n material Material {\n emissiveColor 0.5 0.5 0.5\n }\n }\n geometry IndexedLineSet {\n coord Coordinate {\n point [\n 9.25 9 -3,\n 9.25 9.25 -3,\n 9.5 9.25 -3,\n 9.5 9 -3,\n ]\n }\n coordIndex [ 0, 1, 2, 3, 0, -1, ]\n }\n }\n Shape {\n appearance Appearance {\n material Material {\n emissiveColor 0.5 0.5 0.5\n }\n }\n geometry IndexedLineSet {\n coord Coordinate {\n point [\n 9 9.25 -3,\n 9 9.5 -3,\n 9.25 9.5 -3,\n 9.25 9.25 -3,\n ]\n }\n coordIndex [ 0, 1, 2, 3, 0, -1, ]\n }\n }\n Shape {\n appearance Appearance {\n material Material {\n emissiveColor 0.5 0.5 0.5\n }\n }\n geometry IndexedLineSet {\n coord Coordinate {\n point [\n 9 9 -3,\n 9 9.25 -3,\n 9.25 9.25 -3,\n 9.25 9 -3,\n ]\n }\n coordIndex [ 0, 1, 2, 3, 0, -1, ]\n }\n }\n Shape {\n appearance Appearance {\n material Material {\n emissiveColor 0.5 0 0\n }\n }\n geometry IndexedLineSet {\n coord Coordinate {\n point [\n 9.125 9.125 -3.5,\n 9.125 9.25 -3.5,\n 9.25 9.25 -3.5,\n 9.25 9.125 -3.5,\n ]\n }\n coordIndex [ 0, 1, 2, 3, 0, -1, ]\n }\n }\n Shape {\n appearance Appearance {\n material Material {\n emissiveColor 0.5 0 0\n }\n }\n geometry IndexedLineSet {\n coord Coordinate {\n point [\n 9.125 9 -3.5,\n 9.125 9.125 -3.5,\n 9.25 9.125 -3.5,\n 9.25 9 -3.5,\n ]\n }\n coordIndex [ 0, 1, 2, 3, 0, -1, ]\n }\n }\n Shape {\n appearance Appearance {\n material Material {\n emissiveColor 0.5 0 0\n }\n }\n geometry IndexedLineSet {\n coord Coordinate {\n point [\n 9 9.125 -3.5,\n 9 9.25 -3.5,\n 9.125 9.25 -3.5,\n 9.125 9.125 -3.5,\n ]\n }\n coordIndex [ 0, 1, 2, 3, 0, -1, ]\n }\n }\n Shape {\n appearance Appearance {\n material Material {\n emissiveColor 0.5 0 0\n }\n }\n geometry IndexedLineSet {\n coord Coordinate {\n point [\n 9 9 -3.5,\n 9 9.125 -3.5,\n 9.125 9.125 -3.5,\n 9.125 9 -3.5,\n ]\n }\n coordIndex [ 0, 1, 2, 3, 0, -1, ]\n }\n }\n Shape {\n appearance Appearance {\n material Material {\n emissiveColor 1 0 0\n }\n }\n geometry IndexedLineSet {\n coord Coordinate {\n point [\n 9 9 -3.5,\n 9 9.1 -3.5,\n 9.1 9.1 -3.5,\n 9.1 9 -3.5,\n ]\n }\n coordIndex [ 0, 1, 2, 3, 0, -1, ]\n }\n }\n Shape {\n appearance Appearance {\n material Material {\n emissiveColor 0 0.5 0.5\n }\n }\n geometry IndexedLineSet {\n coord Coordinate {\n point [\n 9 8 -2,\n 9 9 -2,\n 10 9 -2,\n 10 8 -2,\n ]\n }\n coordIndex [ 0, 1, 2, 3, 0, -1, ]\n }\n }\n Shape {\n appearance Appearance {\n material Material {\n emissiveColor 0 0.5 0.5\n }\n }\n geometry IndexedLineSet {\n coord Coordinate {\n point [\n 8 9 -2,\n 8 10 -2,\n 9 10 -2,\n 9 9 -2,\n ]\n }\n coordIndex [ 0, 1, 2, 3, 0, -1, ]\n }\n }\n Shape {\n appearance Appearance {\n material Material {\n emissiveColor 0 0.5 0.5\n }\n }\n geometry IndexedLineSet {\n coord Coordinate {\n point [\n 8 8 -2,\n 8 9 -2,\n 9 9 -2,\n 9 8 -2,\n ]\n }\n coordIndex [ 0, 1, 2, 3, 0, -1, ]\n }\n }\n Shape {\n appearance Appearance {\n material Material {\n emissiveColor 0 0.5 0\n }\n }\n geometry IndexedLineSet {\n coord Coordinate {\n point [\n 8 0 -0.5,\n 8 8 -0.5,\n 16 8 -0.5,\n 16 0 -0.5,\n ]\n }\n coordIndex [ 0, 1, 2, 3, 0, -1, ]\n }\n }\n Shape {\n appearance Appearance {\n material Material {\n emissiveColor 0 0.5 0\n }\n }\n geometry IndexedLineSet {\n coord Coordinate {\n point [\n 0 8 -0.5,\n 0 16 -0.5,\n 8 16 -0.5,\n 8 8 -0.5,\n ]\n }\n coordIndex [ 0, 1, 2, 3, 0, -1, ]\n }\n }\n Shape {\n appearance Appearance {\n material Material {\n emissiveColor 0 0.5 0\n }\n }\n geometry IndexedLineSet {\n coord Coordinate {\n point [\n 0 0 -0.5,\n 0 8 -0.5,\n 8 8 -0.5,\n 8 0 -0.5,\n ]\n }\n coordIndex [ 0, 1, 2, 3, 0, -1, ]\n }\n }\n Shape {\n appearance Appearance {\n material Material {\n emissiveColor 0 1 0\n }\n }\n geometry IndexedLineSet {\n coord Coordinate {\n point [\n 1.5 3 -0.5,\n 1.5 5 -0.5,\n 2 5 -0.5,\n 2 3 -0.5,\n ]\n }\n coordIndex [ 0, 1, 2, 3, 0, -1, ]\n }\n }\n Shape {\n appearance Appearance {\n material Material {\n emissiveColor 0 0 0.5\n }\n }\n geometry IndexedLineSet {\n coord Coordinate {\n point [\n 4 4 -1,\n 4 8 -1,\n 8 8 -1,\n 8 4 -1,\n ]\n }\n coordIndex [ 0, 1, 2, 3, 0, -1, ]\n }\n }\n Shape {\n appearance Appearance {\n material Material {\n emissiveColor 0 0 0.5\n }\n }\n geometry IndexedLineSet {\n coord Coordinate {\n point [\n 4 0 -1,\n 4 4 -1,\n 8 4 -1,\n 8 0 -1,\n ]\n }\n coordIndex [ 0, 1, 2, 3, 0, -1, ]\n }\n }\n Shape {\n appearance Appearance {\n material Material {\n emissiveColor 0 0 0.5\n }\n }\n geometry IndexedLineSet {\n coord Coordinate {\n point [\n 0 4 -1,\n 0 8 -1,\n 4 8 -1,\n 4 4 -1,\n ]\n }\n coordIndex [ 0, 1, 2, 3, 0, -1, ]\n }\n }\n Shape {\n appearance Appearance {\n material Material {\n emissiveColor 0 0 0.5\n }\n }\n geometry IndexedLineSet {\n coord Coordinate {\n point [\n 0 0 -1,\n 0 4 -1,\n 4 4 -1,\n 4 0 -1,\n ]\n }\n coordIndex [ 0, 1, 2, 3, 0, -1, ]\n }\n }\n Shape {\n appearance Appearance {\n material Material {\n emissiveColor 0.5 0 0.5\n }\n }\n geometry IndexedLineSet {\n coord Coordinate {\n point [\n 2 2 -1.5,\n 2 4 -1.5,\n 4 4 -1.5,\n 4 2 -1.5,\n ]\n }\n coordIndex [ 0, 1, 2, 3, 0, -1, ]\n }\n }\n Shape {\n appearance Appearance {\n material Material {\n emissiveColor 0.5 0 0.5\n }\n }\n geometry IndexedLineSet {\n coord Coordinate {\n point [\n 2 0 -1.5,\n 2 2 -1.5,\n 4 2 -1.5,\n 4 0 -1.5,\n ]\n }\n coordIndex [ 0, 1, 2, 3, 0, -1, ]\n }\n }\n Shape {\n appearance Appearance {\n material Material {\n emissiveColor 0.5 0 0.5\n }\n }\n geometry IndexedLineSet {\n coord Coordinate {\n point [\n 0 2 -1.5,\n 0 4 -1.5,\n 2 4 -1.5,\n 2 2 -1.5,\n ]\n }\n coordIndex [ 0, 1, 2, 3, 0, -1, ]\n }\n }\n Shape {\n appearance Appearance {\n material Material {\n emissiveColor 1 0 1\n }\n }\n geometry IndexedLineSet {\n coord Coordinate {\n point [\n 1 2 -1.5,\n 1 4 -1.5,\n 1.75 4 -1.5,\n 1.75 2 -1.5,\n ]\n }\n coordIndex [ 0, 1, 2, 3, 0, -1, ]\n }\n }\n Shape {\n appearance Appearance {\n material Material {\n emissiveColor 0.5 0 0.5\n }\n }\n geometry IndexedLineSet {\n coord Coordinate {\n point [\n 0 0 -1.5,\n 0 2 -1.5,\n 2 2 -1.5,\n 2 0 -1.5,\n ]\n }\n coordIndex [ 0, 1, 2, 3, 0, -1, ]\n }\n }\n Shape {\n appearance Appearance {\n material Material {\n emissiveColor 0 0.5 0.5\n }\n }\n geometry IndexedLineSet {\n coord Coordinate {\n point [\n 1 1 -2,\n 1 2 -2,\n 2 2 -2,\n 2 1 -2,\n ]\n }\n coordIndex [ 0, 1, 2, 3, 0, -1, ]\n }\n }\n Shape {\n appearance Appearance {\n material Material {\n emissiveColor 0 0.5 0.5\n }\n }\n geometry IndexedLineSet {\n coord Coordinate {\n point [\n 1 0 -2,\n 1 1 -2,\n 2 1 -2,\n 2 0 -2,\n ]\n }\n coordIndex [ 0, 1, 2, 3, 0, -1, ]\n }\n }\n Shape {\n appearance Appearance {\n material Material {\n emissiveColor 0 0.5 0.5\n }\n }\n geometry IndexedLineSet {\n coord Coordinate {\n point [\n 0 1 -2,\n 0 2 -2,\n 1 2 -2,\n 1 1 -2,\n ]\n }\n coordIndex [ 0, 1, 2, 3, 0, -1, ]\n }\n }\n Shape {\n appearance Appearance {\n material Material {\n emissiveColor 0 0.5 0.5\n }\n }\n geometry IndexedLineSet {\n coord Coordinate {\n point [\n 0 0 -2,\n 0 1 -2,\n 1 1 -2,\n 1 0 -2,\n ]\n }\n coordIndex [ 0, 1, 2, 3, 0, -1, ]\n }\n }\n Shape {\n appearance Appearance {\n material Material {\n emissiveColor 0.5 0.5 0\n }\n }\n geometry IndexedLineSet {\n coord Coordinate {\n point [\n 0.5 0.5 -2.5,\n 0.5 1 -2.5,\n 1 1 -2.5,\n 1 0.5 -2.5,\n ]\n }\n coordIndex [ 0, 1, 2, 3, 0, -1, ]\n }\n }\n Shape {\n appearance Appearance {\n material Material {\n emissiveColor 0.5 0.5 0\n }\n }\n geometry IndexedLineSet {\n coord Coordinate {\n point [\n 0.5 0 -2.5,\n 0.5 0.5 -2.5,\n 1 0.5 -2.5,\n 1 0 -2.5,\n ]\n }\n coordIndex [ 0, 1, 2, 3, 0, -1, ]\n }\n }\n Shape {\n appearance Appearance {\n material Material {\n emissiveColor 0.5 0.5 0\n }\n }\n geometry IndexedLineSet {\n coord Coordinate {\n point [\n 0 0.5 -2.5,\n 0 1 -2.5,\n 0.5 1 -2.5,\n 0.5 0.5 -2.5,\n ]\n }\n coordIndex [ 0, 1, 2, 3, 0, -1, ]\n }\n }\n Shape {\n appearance Appearance {\n material Material {\n emissiveColor 0.5 0.5 0\n }\n }\n geometry IndexedLineSet {\n coord Coordinate {\n point [\n 0 0 -2.5,\n 0 0.5 -2.5,\n 0.5 0.5 -2.5,\n 0.5 0 -2.5,\n ]\n }\n coordIndex [ 0, 1, 2, 3, 0, -1, ]\n }\n }\n Shape {\n appearance Appearance {\n material Material {\n emissiveColor 0.5 0.5 0.5\n }\n }\n geometry IndexedLineSet {\n coord Coordinate {\n point [\n 0.25 0.25 -3,\n 0.25 0.5 -3,\n 0.5 0.5 -3,\n 0.5 0.25 -3,\n ]\n }\n coordIndex [ 0, 1, 2, 3, 0, -1, ]\n }\n }\n Shape {\n appearance Appearance {\n material Material {\n emissiveColor 0.5 0.5 0.5\n }\n }\n geometry IndexedLineSet {\n coord Coordinate {\n point [\n 0.25 0 -3,\n 0.25 0.25 -3,\n 0.5 0.25 -3,\n 0.5 0 -3,\n ]\n }\n coordIndex [ 0, 1, 2, 3, 0, -1, ]\n }\n }\n Shape {\n appearance Appearance {\n material Material {\n emissiveColor 0.5 0.5 0.5\n }\n }\n geometry IndexedLineSet {\n coord Coordinate {\n point [\n 0 0.25 -3,\n 0 0.5 -3,\n 0.25 0.5 -3,\n 0.25 0.25 -3,\n ]\n }\n coordIndex [ 0, 1, 2, 3, 0, -1, ]\n }\n }\n Shape {\n appearance Appearance {\n material Material {\n emissiveColor 0.5 0.5 0.5\n }\n }\n geometry IndexedLineSet {\n coord Coordinate {\n point [\n 0 0 -3,\n 0 0.25 -3,\n 0.25 0.25 -3,\n 0.25 0 -3,\n ]\n }\n coordIndex [ 0, 1, 2, 3, 0, -1, ]\n }\n }\n Shape {\n appearance Appearance {\n material Material {\n emissiveColor 1 1 1\n }\n }\n geometry IndexedLineSet {\n coord Coordinate {\n point [\n 0.1 0.1 -3,\n 0.1 0.2 -3,\n 0.2 0.2 -3,\n 0.2 0.1 -3,\n ]\n }\n coordIndex [ 0, 1, 2, 3, 0, -1, ]\n }\n }\n ]\n}\n"
+
+
+class TestGeomPrimitive : public BBoxN, public GeomPrimitive
+{
+ //NOTE: do not yet implement distance() because do not yet test SpatialTree::closest()
+ virtual bool contains(const Vector<double> &point) const {return BBoxN::contains(point);}
+ virtual bool intersects(const GeomPrimitive *prim) const {return BBoxN::intersects(prim->bounding_box());}
+ virtual const BBox<double> &bounding_box() const {return *this;}
+};
+
+int which_one(GeomPrimitive *p, GeomPrimitive *ps[])
+{
+ int i;
+ for (i = 0; ps[i] != 0; i++)
+ {
+ if (ps[i] == p)
+ break;
+ }
+ return i;
+}
+
+class TestSpatialTree : public CxxTest::TestSuite
+{
+public:
+
+ void internal_test_spatial_tree(int dim)
+ {
+ Vector<double,4> b_min(0, 0, 0, 0), b_max(1, 1, 1, 1);
+ BBoxN b(subvector(b_min, 0, dim), subvector(b_max, 0, dim));
+ SpatialTree t(b);
+ std::list<GeomPrimitive*> l;
+ std::list<GeomPrimitive*>::iterator i;
+ std::list<std::pair<GeomPrimitive*, GeomPrimitive*> > overlaps;
+ std::list<std::pair<GeomPrimitive*, GeomPrimitive*> >::iterator i2;
+ int j;
+
+ Vector<double,4> p0(0.1, 0.1, 0.1, 0.1), p0_(0.2, 0.2, 0.2, 0.2);
+ SpatialTree t0(b);
+ TestGeomPrimitive g0_, g0__;
+ g0_.grow(subvector(p0, 0, dim));
+ t0.add(&g0_, 1);
+ TS_ASSERT( t0.check() );
+ g0__.grow(subvector(p0_, 0, dim));
+ t0.add(&g0__, 5);
+ TS_ASSERT( t0.check() );
+
+ TestGeomPrimitive g0;
+ g0.grow(subvector(p0, 0, dim));
+ g0.grow(subvector(p0_, 0, dim));
+ t.add(&g0);
+
+ Vector<double,4> p1(1, 2, 0.1, 0.1), p2(1.75, 4, 0.2, 0.2);
+ TestGeomPrimitive g1;
+ g1.grow(subvector(p1, 0, dim));
+ g1.grow(subvector(p2, 0, dim));
+ t.add(&g1);
+
+ Vector<double,4> p3(1.5, 3, 0.1, 0.1), p4(2, 5, 0.2, 0.2);
+ TS_ASSERT_EQUALS( t.contains(subvector(p3, 0, dim)), &g1 );
+ l.clear();
+ t.contains(subvector(p3, 0, dim), l);
+ TS_ASSERT_EQUALS( l.size(), 1 );
+ TS_ASSERT_EQUALS( *(l.begin()), &g1 );
+ TS_ASSERT_EQUALS( t.contains(subvector(p4, 0, dim)), (GeomPrimitive*)0 );
+ l.clear();
+ t.contains(subvector(p4, 0, dim), l);
+ TS_ASSERT_EQUALS( l.size(), 0 );
+
+ TestGeomPrimitive g2;
+ g2.grow(subvector(p3, 0, dim));
+ g2.grow(subvector(p4, 0, dim));
+ t.add(&g2);
+
+ Vector<double,4> p5(1.25, 3.5, 0.15, 0.15), p6(1.6, 3.5, 0.15, 0.15), p7(1.75, 4.5, 0.15, 0.15), p8(1.25, 4.5, 0.15, 0.15), p9(8, 8, 0.15, 0.15);
+ GeomPrimitive *gt1;
+ GeomPrimitive *gt2;
+ TS_ASSERT_EQUALS( t.contains(subvector(p5, 0, dim)), &g1 );
+ l.clear();
+ t.contains(subvector(p5, 0, dim), l);
+ TS_ASSERT_EQUALS( l.size(), 1 );
+ TS_ASSERT_EQUALS( *(l.begin()), &g1 );
+ gt1 = t.contains(subvector(p6, 0, dim));
+ TS_ASSERT( gt1 == &g1 || gt1 == &g2 );
+ l.clear();
+ t.contains(subvector(p6, 0, dim), l);
+ TS_ASSERT_EQUALS( l.size(), 2 );
+ i = l.begin(); gt1 = *i; i++; gt2 = *i;
+ TS_ASSERT( gt1 == &g1 || gt1 == &g2 );
+ TS_ASSERT( gt2 == &g1 || gt2 == &g2 );
+ TS_ASSERT( gt1 != gt2 );
+ TS_ASSERT_EQUALS( t.contains(subvector(p7, 0, dim)), &g2 );
+ l.clear();
+ t.contains(subvector(p7, 0, dim), l);
+ TS_ASSERT_EQUALS( l.size(), 1 );
+ TS_ASSERT_EQUALS( *(l.begin()), &g2 );
+ if (dim == 1)
+ {
+ TS_ASSERT_EQUALS( t.contains(subvector(p8, 0, dim)), &g1 );
+ l.clear();
+ t.contains(subvector(p8, 0, dim), l);
+ TS_ASSERT_EQUALS( l.size(), 1 );
+ TS_ASSERT_EQUALS( *(l.begin()), &g1 );
+ }
+ else
+ {
+ TS_ASSERT_EQUALS( t.contains(subvector(p8, 0, dim)), (GeomPrimitive*)0 );
+ l.clear();
+ t.contains(subvector(p8, 0, dim), l);
+ TS_ASSERT_EQUALS( l.size(), 0 );
+ }
+ TS_ASSERT_EQUALS( t.contains(subvector(p9, 0, dim)), (GeomPrimitive*)0 );
+ l.clear();
+ t.contains(subvector(p9, 0, dim), l);
+ TS_ASSERT_EQUALS( l.size(), 0 );
+
+ Vector<double,4> p10(9, 9, 9, 9), p10_(9.1, 9.1, 9.1, 9.1);
+ TestGeomPrimitive g3;
+ g3.grow(subvector(p10, 0, dim));
+ g3.grow(subvector(p10_, 0, dim));
+ t.add(&g3);
+
+ overlaps.clear();
+ t.overlap_pairs(overlaps);
+ TS_ASSERT_EQUALS( overlaps.size(), 1 );
+ i2 = overlaps.begin(); gt1 = (*i2).first; gt2 = (*i2).second;
+ TS_ASSERT( gt1 == &g1 || gt1 == &g2 );
+ TS_ASSERT( gt2 == &g1 || gt2 == &g2 );
+ TS_ASSERT( gt1 != gt2 );
+
+ if (dim <= 2)
+ {
+ ostringstream os;
+ const char *print_results[3] = {0, TEST_SPATIAL_TREE_PRINT_RESULT_1D, TEST_SPATIAL_TREE_PRINT_RESULT_2D};
+ std::string printstr(print_results[dim]);
+ t.print(os);
+ TS_ASSERT_EQUALS( os.str(), printstr );
+ }
+
+ if (dim == 2)
+ {
+ ostringstream os2;
+ std::string vrmlstr(TEST_SPATIAL_TREE_VRML_RESULT);
+ t.write_vrml(os2);
+ TS_ASSERT_EQUALS( os2.str(), vrmlstr );
+ }
+
+ Vector<double,4> p11(0.01, 0.01, 0.01, 0.01), p12(6, 6, 6, 6);
+ TestGeomPrimitive g4;
+ g4.grow(subvector(p11, 0, dim));
+ g4.grow(subvector(p12, 0, dim));
+ t.add(&g4);
+
+ overlaps.clear();
+ t.overlap_pairs(overlaps);
+ int num_overlaps = 4;
+ GeomPrimitive *overlaps_truth[4][2] = {{&g4, &g2}, {&g4, &g1}, {&g4, &g0}, {&g2, &g1}};
+ int overlaps_found[4] = {0, 0, 0, 0};
+ //GeomPrimitive *prims[6] = {&g0, &g1, &g2, &g3, &g4, 0};
+ //for (i2 = overlaps.begin(); i2 != overlaps.end(); i2++)
+ // TS_TRACE(stringify(which_one((*i2).first, prims)) + " overlaps " + stringify(which_one((*i2).second, prims)));
+ TS_ASSERT_EQUALS( overlaps.size(), num_overlaps );
+ for (i2 = overlaps.begin(); i2 != overlaps.end(); i2++)
+ {
+ gt1 = (*i2).first; gt2 = (*i2).second;
+ for (j = 0; j < num_overlaps; j++)
+ {
+ if ((gt1 == overlaps_truth[j][0] && gt2 == overlaps_truth[j][1]) || (gt1 == overlaps_truth[j][1] && gt2 == overlaps_truth[j][0]))
+ {
+ overlaps_found[j] = 1;
+ break;
+ }
+ }
+ }
+ for (j = 0; j < num_overlaps; j++)
+ {
+ TS_ASSERT_EQUALS( overlaps_found[j], 1 );
+ }
+
+ TS_ASSERT( t.check() );
+ }
+
+ void test_spatial_tree_1d() {
+ internal_test_spatial_tree(1);
+ }
+
+ void test_spatial_tree_2d() {
+ internal_test_spatial_tree(2);
+ }
+
+ void test_spatial_tree_3d() {
+ internal_test_spatial_tree(3);
+ }
+
+ void test_spatial_tree_4d() {
+ internal_test_spatial_tree(4);
+ }
+
+}; // class TestSpatialTree
65 src/vw/Geometry/tests/TestSphere.h
View
@@ -0,0 +1,65 @@
+// __BEGIN_LICENSE__
+//
+// Copyright (C) 2006 United States Government as represented by the
+// Administrator of the National Aeronautics and Space Administration
+// (NASA). All Rights Reserved.
+//
+// Copyright 2006 Carnegie Mellon University. All rights reserved.
+//
+// This software is distributed under the NASA Open Source Agreement
+// (NOSA), version 1.3. The NOSA has been approved by the Open Source
+// Initiative. See the file COPYING at the top of the distribution
+// directory tree for the complete NOSA document.
+//
+// THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF ANY
+// KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT
+// LIMITED TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO
+// SPECIFICATIONS, ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR
+// A PARTICULAR PURPOSE, OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT
+// THE SUBJECT SOFTWARE WILL BE ERROR FREE, OR ANY WARRANTY THAT
+// DOCUMENTATION, IF PROVIDED, WILL CONFORM TO THE SUBJECT SOFTWARE.
+//
+// __END_LICENSE__
+
+// TestBBall.h
+
+#include <iostream>
+
+#include <cxxtest/TestSuite.h>
+#include <vw/Math/Vector.h>
+#include <vw/Geometry/Sphere.h>
+
+using namespace vw;
+
+class TestSphere : public CxxTest::TestSuite
+{
+public:
+
+ void test_bball()
+ {
+ SphereN b0;
+ TS_ASSERT( b0.empty() );
+ b0.grow(Vector3(0, 0, 0));
+ TS_ASSERT( !b0.empty() );
+ b0.grow(Vector3(1, 0, 0));
+ TS_ASSERT( !b0.empty() );
+
+ // unit ball centered at (0,0,0)
+ Sphere3 b1;
+ b1.grow(Vector3(0, 0, 0));
+ b1.grow(Vector3(0, 0, 1));
+ b1.grow(Vector3(0, 0, -1));
+ b1.grow(Vector3(0, 1, 0));
+ b1.grow(Vector3(0, -1, 0));
+ b1.grow(Vector3(1, 0, 0));
+ b1.grow(Vector3(-1, 0, 0));
+ TS_ASSERT_EQUALS(b1.center(), Vector3(0, 0, 0));
+ TS_ASSERT( b1.contains(Vector3(0.5, 0.5, 0.5)) );
+ TS_ASSERT( !b1.contains(Vector3(0.9, 0.9, 1.5)) );
+ TS_ASSERT( b1.intersects(b1) );
+
+ Sphere3 b2( Vector3( 0, 0, 0 ), 0 );
+ TS_ASSERT( !b2.empty() );
+ }
+
+}; // class TestSphere
5 src/vw/Makefile.am
View
@@ -80,6 +80,11 @@ hdr_subdirs = HDR
hdr_headers = HDR.h
endif
+if MAKE_MODULE_GEOMETRY
+hdr_subdirs = Geometry
+hdr_headers = Geometry.h
+endif
+
if MAKE_MODULE_TOOLS
tools_subdirs = tools
endif
4 src/vw/vw.h
View
@@ -64,6 +64,10 @@
#include <vw/HDR.h>
#endif
+#if defined(VW_HAVE_PKG_GEOMETRY) && VW_HAVE_PKG_GEOMETRY==1
+#include <vw/Geometry.h>
+#endif
+
#if defined(VW_HAVE_PKG_GPU) && VW_HAVE_PKG_GPU==1
#include <vw/GPU.h>
#endif
Please sign in to comment.
Something went wrong with that request. Please try again.