diff --git a/build/msvc100/replay-test.vcxproj b/build/msvc100/replay-test.vcxproj
index 3127ca9..c7161ec 100644
--- a/build/msvc100/replay-test.vcxproj
+++ b/build/msvc100/replay-test.vcxproj
@@ -28,6 +28,7 @@
+
diff --git a/build/msvc100/replay-test.vcxproj.filters b/build/msvc100/replay-test.vcxproj.filters
index ec00476..88b872b 100644
--- a/build/msvc100/replay-test.vcxproj.filters
+++ b/build/msvc100/replay-test.vcxproj.filters
@@ -15,7 +15,10 @@
-
+
+ Source Files
+
+
Source Files
diff --git a/build/msvc100/replay.vcxproj b/build/msvc100/replay.vcxproj
index b410c5c..49d26b0 100644
--- a/build/msvc100/replay.vcxproj
+++ b/build/msvc100/replay.vcxproj
@@ -232,6 +232,7 @@
+
diff --git a/build/msvc100/replay.vcxproj.filters b/build/msvc100/replay.vcxproj.filters
index d01a85d..c8eb345 100644
--- a/build/msvc100/replay.vcxproj.filters
+++ b/build/msvc100/replay.vcxproj.filters
@@ -137,5 +137,8 @@
Header Files
+
+ Header Files
+
\ No newline at end of file
diff --git a/docs/config.doxygen b/docs/config.doxygen
index 99d78a8..e548bf9 100644
--- a/docs/config.doxygen
+++ b/docs/config.doxygen
@@ -1,4 +1,4 @@
-# Doxyfile 1.6.0
+# Doxyfile 1.7.1
# This file describes the settings to be used by the documentation system
# doxygen (www.doxygen.org) for a project
@@ -217,15 +217,15 @@ OPTIMIZE_FOR_FORTRAN = NO
OPTIMIZE_OUTPUT_VHDL = NO
-# Doxygen selects the parser to use depending on the extension of the files it parses.
-# With this tag you can assign which parser to use for a given extension.
-# Doxygen has a built-in mapping, but you can override or extend it using this tag.
-# The format is ext=language, where ext is a file extension, and language is one of
-# the parsers supported by doxygen: IDL, Java, Javascript, C#, C, C++, D, PHP,
-# Objective-C, Python, Fortran, VHDL, C, C++. For instance to make doxygen treat
-# .inc files as Fortran files (default is PHP), and .f files as C (default is Fortran),
-# use: inc=Fortran f=C. Note that for custom extensions you also need to set
-# FILE_PATTERNS otherwise the files are not read by doxygen.
+# Doxygen selects the parser to use depending on the extension of the files it
+# parses. With this tag you can assign which parser to use for a given extension.
+# Doxygen has a built-in mapping, but you can override or extend it using this
+# tag. The format is ext=language, where ext is a file extension, and language
+# is one of the parsers supported by doxygen: IDL, Java, Javascript, CSharp, C,
+# C++, D, PHP, Objective-C, Python, Fortran, VHDL, C, C++. For instance to make
+# doxygen treat .inc files as Fortran files (default is PHP), and .f files as C
+# (default is Fortran), use: inc=Fortran f=C. Note that for custom extensions
+# you also need to set FILE_PATTERNS otherwise the files are not read by doxygen.
EXTENSION_MAPPING =
@@ -397,6 +397,12 @@ HIDE_SCOPE_NAMES = NO
SHOW_INCLUDE_FILES = NO
+# If the FORCE_LOCAL_INCLUDES tag is set to YES then Doxygen
+# will list include files with double quotes in the documentation
+# rather than with sharp brackets.
+
+FORCE_LOCAL_INCLUDES = NO
+
# If the INLINE_INFO tag is set to YES (the default) then a tag [inline]
# is inserted in the documentation for inline members.
@@ -416,12 +422,12 @@ SORT_MEMBER_DOCS = YES
SORT_BRIEF_DOCS = YES
-# If the SORT_MEMBERS_CTORS_1ST tag is set to YES then doxygen
-# will sort the (brief and detailed) documentation of class members so that
-# constructors and destructors are listed first. If set to NO (the default)
-# the constructors will appear in the respective orders defined by
-# SORT_MEMBER_DOCS and SORT_BRIEF_DOCS.
-# This tag will be ignored for brief docs if SORT_BRIEF_DOCS is set to NO
+# If the SORT_MEMBERS_CTORS_1ST tag is set to YES then doxygen
+# will sort the (brief and detailed) documentation of class members so that
+# constructors and destructors are listed first. If set to NO (the default)
+# the constructors will appear in the respective orders defined by
+# SORT_MEMBER_DOCS and SORT_BRIEF_DOCS.
+# This tag will be ignored for brief docs if SORT_BRIEF_DOCS is set to NO
# and ignored for detailed docs if SORT_MEMBER_DOCS is set to NO.
SORT_MEMBERS_CTORS_1ST = YES
@@ -481,6 +487,12 @@ ENABLED_SECTIONS =
MAX_INITIALIZER_LINES = 30
+# Set the SHOW_USED_FILES tag to NO to disable the list of files generated
+# at the bottom of the documentation of classes and structs. If set to YES the
+# list will mention the files that were used to generate the documentation.
+
+SHOW_USED_FILES = YES
+
# If the sources in your project are distributed over multiple directories
# then setting the SHOW_DIRECTORIES tag to YES will show the directory hierarchy
# in the documentation. The default is NO.
@@ -509,12 +521,12 @@ SHOW_NAMESPACES = NO
FILE_VERSION_FILTER =
-# The LAYOUT_FILE tag can be used to specify a layout file which will be parsed by
-# doxygen. The layout file controls the global structure of the generated output files
-# in an output format independent way. The create the layout file that represents
-# doxygen's defaults, run doxygen with the -l option. You can optionally specify a
-# file name after the option, if omitted DoxygenLayout.xml will be used as the name
-# of the layout file.
+# The LAYOUT_FILE tag can be used to specify a layout file which will be parsed
+# by doxygen. The layout file controls the global structure of the generated
+# output files in an output format independent way. The create the layout file
+# that represents doxygen's defaults, run doxygen with the -l option.
+# You can optionally specify a file name after the option, if omitted
+# DoxygenLayout.xml will be used as the name of the layout file.
LAYOUT_FILE =
@@ -798,7 +810,7 @@ IGNORE_PREFIX =
# If the GENERATE_HTML tag is set to YES (the default) Doxygen will
# generate HTML output.
-GENERATE_HTML = NO
+GENERATE_HTML = YES
# The HTML_OUTPUT tag is used to specify where the HTML docs will be put.
# If a relative path is entered the value of OUTPUT_DIRECTORY will be
@@ -833,6 +845,37 @@ HTML_FOOTER =
HTML_STYLESHEET =
+# The HTML_COLORSTYLE_HUE tag controls the color of the HTML output.
+# Doxygen will adjust the colors in the stylesheet and background images
+# according to this color. Hue is specified as an angle on a colorwheel,
+# see http://en.wikipedia.org/wiki/Hue for more information.
+# For instance the value 0 represents red, 60 is yellow, 120 is green,
+# 180 is cyan, 240 is blue, 300 purple, and 360 is red again.
+# The allowed range is 0 to 359.
+
+HTML_COLORSTYLE_HUE = 220
+
+# The HTML_COLORSTYLE_SAT tag controls the purity (or saturation) of
+# the colors in the HTML output. For a value of 0 the output will use
+# grayscales only. A value of 255 will produce the most vivid colors.
+
+HTML_COLORSTYLE_SAT = 100
+
+# The HTML_COLORSTYLE_GAMMA tag controls the gamma correction applied to
+# the luminance component of the colors in the HTML output. Values below
+# 100 gradually make the output lighter, whereas values above 100 make
+# the output darker. The value divided by 100 is the actual gamma applied,
+# so 80 represents a gamma of 0.8, The value 220 represents a gamma of 2.2,
+# and 100 does not change the gamma.
+
+HTML_COLORSTYLE_GAMMA = 80
+
+# If the HTML_TIMESTAMP tag is set to YES then the footer of each generated HTML
+# page will contain the date and time when the page was generated. Setting
+# this to NO can help when comparing the output of multiple runs.
+
+HTML_TIMESTAMP = YES
+
# If the HTML_ALIGN_MEMBERS tag is set to YES, the members of classes,
# files or namespaces will be aligned in HTML using tables. If set to
# NO a bullet list will be used.
@@ -855,7 +898,8 @@ HTML_DYNAMIC_SECTIONS = NO
# directory and running "make install" will install the docset in
# ~/Library/Developer/Shared/Documentation/DocSets so that Xcode will find
# it at startup.
-# See http://developer.apple.com/tools/creatingdocsetswithdoxygen.html for more information.
+# See http://developer.apple.com/tools/creatingdocsetswithdoxygen.html
+# for more information.
GENERATE_DOCSET = NO
@@ -873,6 +917,16 @@ DOCSET_FEEDNAME = "Doxygen generated docs"
DOCSET_BUNDLE_ID = org.doxygen.Project
+# When GENERATE_PUBLISHER_ID tag specifies a string that should uniquely identify
+# the documentation publisher. This should be a reverse domain-name style
+# string, e.g. com.mycompany.MyDocSet.documentation.
+
+DOCSET_PUBLISHER_ID = org.doxygen.Publisher
+
+# The GENERATE_PUBLISHER_NAME tag identifies the documentation publisher.
+
+DOCSET_PUBLISHER_NAME = Publisher
+
# If the GENERATE_HTMLHELP tag is set to YES, additional index files
# will be generated that can be used as input for tools like the
# Microsoft HTML help workshop to generate a compiled HTML help file (.chm)
@@ -917,10 +971,10 @@ BINARY_TOC = NO
TOC_EXPAND = NO
-# If the GENERATE_QHP tag is set to YES and both QHP_NAMESPACE and QHP_VIRTUAL_FOLDER
-# are set, an additional index file will be generated that can be used as input for
-# Qt's qhelpgenerator to generate a Qt Compressed Help (.qch) of the generated
-# HTML documentation.
+# If the GENERATE_QHP tag is set to YES and both QHP_NAMESPACE and
+# QHP_VIRTUAL_FOLDER are set, an additional index file will be generated
+# that can be used as input for Qt's qhelpgenerator to generate a
+# Qt Compressed Help (.qch) of the generated HTML documentation.
GENERATE_QHP = NO
@@ -934,7 +988,7 @@ QCH_FILE =
# Qt Help Project output. For more information please see
# http://doc.trolltech.com/qthelpproject.html#namespace
-QHP_NAMESPACE =
+QHP_NAMESPACE = org.doxygen.Project
# The QHP_VIRTUAL_FOLDER tag specifies the namespace to use when generating
# Qt Help Project output. For more information please see
@@ -942,20 +996,24 @@ QHP_NAMESPACE =
QHP_VIRTUAL_FOLDER = doc
-# If QHP_CUST_FILTER_NAME is set, it specifies the name of a custom filter to add.
-# For more information please see
+# If QHP_CUST_FILTER_NAME is set, it specifies the name of a custom filter to
+# add. For more information please see
# http://doc.trolltech.com/qthelpproject.html#custom-filters
QHP_CUST_FILTER_NAME =
-# The QHP_CUST_FILT_ATTRS tag specifies the list of the attributes of the custom filter to add.For more information please see
-# Qt Help Project / Custom Filters.
+# The QHP_CUST_FILT_ATTRS tag specifies the list of the attributes of the
+# custom filter to add. For more information please see
+#
+# Qt Help Project / Custom Filters.
QHP_CUST_FILTER_ATTRS =
-# The QHP_SECT_FILTER_ATTRS tag specifies the list of the attributes this project's
+# The QHP_SECT_FILTER_ATTRS tag specifies the list of the attributes this
+# project's
# filter section matches.
-# Qt Help Project / Filter Attributes.
+#
+# Qt Help Project / Filter Attributes.
QHP_SECT_FILTER_ATTRS =
@@ -966,6 +1024,23 @@ QHP_SECT_FILTER_ATTRS =
QHG_LOCATION =
+# If the GENERATE_ECLIPSEHELP tag is set to YES, additional index files
+# will be generated, which together with the HTML files, form an Eclipse help
+# plugin. To install this plugin and make it available under the help contents
+# menu in Eclipse, the contents of the directory containing the HTML and XML
+# files needs to be copied into the plugins directory of eclipse. The name of
+# the directory within the plugins directory should be the same as
+# the ECLIPSE_DOC_ID value. After copying Eclipse needs to be restarted before
+# the help appears.
+
+GENERATE_ECLIPSEHELP = NO
+
+# A unique identifier for the eclipse help plugin. When installing the plugin
+# the directory name containing the HTML and XML files should also have
+# this name.
+
+ECLIPSE_DOC_ID = org.doxygen.Project
+
# The DISABLE_INDEX tag can be used to turn on/off the condensed index at
# top of each HTML page. The value NO (the default) enables the index and
# the value YES disables it.
@@ -979,7 +1054,7 @@ ENUM_VALUES_PER_LINE = 4
# The GENERATE_TREEVIEW tag is used to specify whether a tree-like index
# structure should be generated to display hierarchical information.
-# If the tag value is set to FRAME, a side panel will be generated
+# If the tag value is set to YES, a side panel will be generated
# containing a tree-like index structure (just like the one that
# is generated for HTML Help). For this to work a browser that supports
# JavaScript, DHTML, CSS and frames is required (i.e. any modern browser).
@@ -998,6 +1073,11 @@ USE_INLINE_TREES = NO
TREEVIEW_WIDTH = 250
+# When the EXT_LINKS_IN_WINDOW option is set to YES doxygen will open
+# links to external symbols imported via tag files in a separate window.
+
+EXT_LINKS_IN_WINDOW = NO
+
# Use this tag to change the font size of Latex formulas included
# as images in the HTML documentation. The default is 10. Note that
# when you change the font size after a successful doxygen run you need
@@ -1006,15 +1086,34 @@ TREEVIEW_WIDTH = 250
FORMULA_FONTSIZE = 10
-# When the SEARCHENGINE tag is enable doxygen will generate a search box
+# Use the FORMULA_TRANPARENT tag to determine whether or not the images
+# generated for formulas are transparent PNGs. Transparent PNGs are
+# not supported properly for IE 6.0, but are supported on all modern browsers.
+# Note that when changing this option you need to delete any form_*.png files
+# in the HTML output before the changes have effect.
+
+FORMULA_TRANSPARENT = YES
+
+# When the SEARCHENGINE tag is enabled doxygen will generate a search box
# for the HTML output. The underlying search engine uses javascript
-# and DHTML and should work on any modern browser. Note that when using
-# HTML help (GENERATE_HTMLHELP) or Qt help (GENERATE_QHP)
-# there is already a search function so this one should typically
-# be disabled.
+# and DHTML and should work on any modern browser. Note that when using
+# HTML help (GENERATE_HTMLHELP), Qt help (GENERATE_QHP), or docsets
+# (GENERATE_DOCSET) there is already a search function so this one should
+# typically be disabled. For large projects the javascript based search engine
+# can be slow, then enabling SERVER_BASED_SEARCH may provide a better solution.
SEARCHENGINE = NO
+# When the SERVER_BASED_SEARCH tag is enabled the search engine will be
+# implemented using a PHP enabled web server instead of at the web client
+# using Javascript. Doxygen will generate the search PHP script and index
+# file to put on the web server. The advantage of the server
+# based approach is that it scales better to large projects and allows
+# full text search. The disadvances is that it is more difficult to setup
+# and does not have live searching capabilities.
+
+SERVER_BASED_SEARCH = NO
+
#---------------------------------------------------------------------------
# configuration options related to the LaTeX output
#---------------------------------------------------------------------------
@@ -1031,7 +1130,10 @@ GENERATE_LATEX = NO
LATEX_OUTPUT = latex
# The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be
-# invoked. If left blank `latex' will be used as the default command name.
+# invoked. If left blank `latex' will be used as the default command name.
+# Note that when enabling USE_PDFLATEX this option is only used for
+# generating bitmaps for formulas in the HTML output, but not in the
+# Makefile that is written to the output directory.
LATEX_CMD_NAME = latex
@@ -1056,7 +1158,7 @@ PAPER_TYPE = a4wide
# The EXTRA_PACKAGES tag can be to specify one or more names of LaTeX
# packages that should be included in the LaTeX output.
-EXTRA_PACKAGES =
+EXTRA_PACKAGES = amssymb
# The LATEX_HEADER tag can be used to specify a personal LaTeX header for
# the generated latex document. The header should contain everything until
@@ -1091,9 +1193,9 @@ LATEX_BATCHMODE = NO
LATEX_HIDE_INDICES = NO
-# If LATEX_SOURCE_CODE is set to YES then doxygen will include
-# source code with syntax highlighting in the LaTeX output.
-# Note that which sources are shown also depends on other settings
+# If LATEX_SOURCE_CODE is set to YES then doxygen will include
+# source code with syntax highlighting in the LaTeX output.
+# Note that which sources are shown also depends on other settings
# such as SOURCE_BROWSER.
LATEX_SOURCE_CODE = NO
@@ -1176,7 +1278,7 @@ MAN_LINKS = NO
# generate an XML file that captures the structure of
# the code including all documentation.
-GENERATE_XML = YES
+GENERATE_XML = NO
# The XML_OUTPUT tag is used to specify where the XML pages will be put.
# If a relative path is entered the value of OUTPUT_DIRECTORY will be
@@ -1392,6 +1494,14 @@ HIDE_UNDOC_RELATIONS = YES
HAVE_DOT = YES
+# The DOT_NUM_THREADS specifies the number of dot invocations doxygen is
+# allowed to run in parallel. When set to 0 (the default) doxygen will
+# base this on the number of processors available in the system. You can set it
+# explicitly to a value larger than 0 to get control over the balance
+# between CPU load and processing speed.
+
+DOT_NUM_THREADS = 0
+
# By default doxygen will write a font called FreeSans.ttf to the output
# directory and reference it in all dot files that doxygen generates. This
# font does not include all possible unicode characters however, so when you need
diff --git a/include/replay/aabb.hpp b/include/replay/aabb.hpp
index 757e999..292a176 100644
--- a/include/replay/aabb.hpp
+++ b/include/replay/aabb.hpp
@@ -34,7 +34,7 @@ Copyright (c) 2010 Marius Elvert
namespace replay {
-/** An iso-box in \f$R^3\f$.
+/** An iso-box in \f$\mathbb{R}^3\f$.
Represents the intersection of intervals on the 3 principal axes.
\ingroup Math
*/
@@ -45,12 +45,13 @@ class aabb :
public:
/** Classification relative to a plane.
+ \see classify
*/
enum clsfctn
{
- negative, /**< all points have a negative distance. */
- positive, /**< all points have a positive distance. */
- spanning /**< the points have mixed signs in their distances. */
+ negative, /**< All points have a negative distance to the plane. */
+ positive, /**< All points have a positive distance to the plane. */
+ spanning /**< The points have mixed signs in their distances to the plane, so the box intersects the plane. */
};
aabb( );
explicit aabb( const float extends );
diff --git a/include/replay/bounding_rectangle.hpp b/include/replay/bounding_rectangle.hpp
new file mode 100644
index 0000000..9ebd5cb
--- /dev/null
+++ b/include/replay/bounding_rectangle.hpp
@@ -0,0 +1,259 @@
+/*
+replay
+Software Library
+
+Copyright (c) 2010 Marius Elvert
+
+ Permission is hereby granted, free of charge, to any person obtaining a copy
+ of this software and associated documentation files (the "Software"), to deal
+ in the Software without restriction, including without limitation the rights
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ copies of the Software, and to permit persons to whom the Software is
+ furnished to do so, subject to the following conditions:
+
+ The above copyright notice and this permission notice shall be included in
+ all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ THE SOFTWARE.
+
+*/
+
+#ifndef replay_bounding_rectangle_hpp
+#define replay_bounding_rectangle_hpp
+
+#include
+#include
+#include
+#include
+
+namespace replay {
+
+/** Compute a minimal-area bounding rectangle of a 2D convex hull using a rotating calipers algorithm.
+ This algorithm runs in linear time.
+*/
+class bounding_rectangle_algorithm
+{
+public:
+ bounding_rectangle_algorithm( const vector2f* hull, std::size_t n )
+ : hull(hull),n(n)
+ {
+ // Get an initial box and the extrema
+ initial_extrema();
+
+ // Start with no rotation
+ current.u.set(1.f,0.f);
+
+ // Check all possible configurations
+ float min_area=compute_current_size();
+ best=current;
+
+ for ( std::size_t i=1; i= zero_deg )
+ bottom = (bottom+1)%n;
+
+ t = rotated_left( current.u );
+ while ( (ra=dot( t, normalized(get_edge(right)))) >= zero_deg )
+ right = (right+1)%n;
+
+ t = rotated_left( t );
+ while ( (ta=dot( t, normalized(get_edge(top)))) >= zero_deg)
+ top = (top+1)%n;
+
+ t = rotated_left( t );
+ while ( (la=dot( t, normalized(get_edge(left)))) >= zero_deg )
+ left = (left+1)%n;
+
+ // Find the smallest angle, which is the greatest cosine
+ std::size_t s = 0;
+ float m = ba;
+
+ if ( ra > m ) { s=1; m=ra; }
+ if ( ta > m ) { s=2; m=ta; }
+ if ( la > m ) { s=3; m=la; }
+
+ switch( s )
+ {
+ case 0:
+ t = normalized(get_edge(bottom));
+ current.u = t;
+ break;
+ case 1:
+
+ t = normalized(get_edge(right));
+ current.u.set( t[1],-t[0] );
+ break;
+ case 2:
+ t = normalized(get_edge(top));
+ current.u = -t;
+ break;
+ case 3:
+ t = normalized(get_edge(left));
+ current.u.set( -t[1], t[0] );
+ break;
+ }
+ }
+
+ inline float compute_current_size()
+ {
+ const vector2f& u(current.u);
+ // phi is defined by the matrix:
+ // u[0] -u[1]
+ // u[1] u[0]
+
+ const vector2f& l(hull[left]);
+ const vector2f& b(hull[bottom]);
+
+ current.min.set(
+ l[0]*u[0]+l[1]*u[1], // x component of phi(P[Left])
+ -b[0]*u[1]+b[1]*u[0] // y component of phi(P[Bottom])
+ );
+
+ // Likewise for right and top
+ const vector2f& r(hull[right]);
+ const vector2f& t(hull[top]);
+
+ current.max.set(
+ r[0]*u[0]+r[1]*u[1],
+ -t[0]*u[1]+t[1]*u[0]
+ );
+
+ float dx = current.max[0]-current.min[0];
+ float dy = current.max[1]-current.min[1];
+
+ return dx*dy;
+ }
+
+ inline void initial_extrema()
+ {
+ left = right = top = bottom = 0;
+
+ // Find an initial bounding box and the extrema
+ for ( std::size_t i=1; i hull[right][0] )
+ right = i;
+ else
+ {
+ if ( x == hull[left][0] && y < hull[left][1] )
+ left = i;
+
+ else if ( x == hull[right][0] && y > hull[right][1] )
+ right = 1;
+ }
+
+ // Check for new y
+ if ( y < hull[bottom][1] )
+ bottom = i;
+ else if ( y > hull[top][1] )
+ top = i;
+ else
+ {
+ if ( y == hull[bottom][1] && x > hull[bottom][0] )
+ bottom = i;
+
+ else if ( y == hull[top][1] && x < hull[top][0] )
+ top = i;
+ }
+ }
+ }
+
+ // The convex hull
+ const vector2f* hull;
+ std::size_t n;
+
+ struct box_type {
+ // box
+ vector2f min;
+ vector2f max;
+
+ // rotation
+ vector2f u;
+ };
+
+ box_type current;
+ box_type best;
+
+ // Current extrema
+ std::size_t top;
+ std::size_t bottom;
+ std::size_t left;
+ std::size_t right;
+
+ // Selected edge
+ std::size_t selected_edge;
+};
+
+}
+
+#endif // replay_bounding_rectangle_hpp
diff --git a/include/replay/box_packer.hpp b/include/replay/box_packer.hpp
index 0d94b8a..87577fa 100644
--- a/include/replay/box_packer.hpp
+++ b/include/replay/box_packer.hpp
@@ -35,7 +35,10 @@ Copyright (c) 2010 Marius Elvert
namespace replay
{
-/** 2d box packer.
+/** A box packer for 2-dimensions.
+ This algorithm can be used to position a set of axis-aligned rectangles in the plane,
+ so that they do not overlap and that all rectangles together need only a small bounding box.
+ It can be used to generate texture atlases.
This uses a first fit packing algorithm.
*/
class box_packer :
diff --git a/include/replay/byte_color.hpp b/include/replay/byte_color.hpp
index ecd9f83..8b46477 100644
--- a/include/replay/byte_color.hpp
+++ b/include/replay/byte_color.hpp
@@ -36,6 +36,8 @@ namespace replay {
class byte_color4
{
public:
+ /** 8-bit unsigned integer.
+ */
typedef unsigned char byte;
/** 32-bit unsigned integer.
diff --git a/include/replay/math.hpp b/include/replay/math.hpp
index 54b1eb6..f2ef950 100644
--- a/include/replay/math.hpp
+++ b/include/replay/math.hpp
@@ -119,25 +119,26 @@ namespace math {
/** return true if the value is within a treshold of zero.
\ingroup Math
*/
- inline bool near_zero( const float value, const float epsilon )
+ inline bool fuzzy_zero( const float value, const float epsilon )
{
- return abs( value ) < epsilon;
+ return abs(value) < epsilon;
}
/** return true if the value is within a treshold of zero.
\ingroup Math
*/
- inline bool near_zero( const float value )
+ inline bool fuzzy_zero( const float value )
{
- return abs( value ) < default_epsilon;
+ return abs(value) < default_epsilon;
}
- /** return true if a is within a treshold of b.
+ /** Return true if a is within a treshold of b.
+ This is used to compare floating point numbers.
\ingroup Math
*/
- inline bool near( const float a, const float b )
+ inline bool fuzzy_equals( const float a, const float b, const float epsilon=default_epsilon )
{
- return abs( a - b ) < default_epsilon;
+ return abs(a-b) < epsilon;
}
/** check if the value is in the range. borders count as in.
diff --git a/include/replay/minimal_sphere.hpp b/include/replay/minimal_sphere.hpp
index 01f7620..9bc0a2a 100644
--- a/include/replay/minimal_sphere.hpp
+++ b/include/replay/minimal_sphere.hpp
@@ -32,16 +32,19 @@ Copyright (c) 2010 Marius Elvert
namespace replay {
/** Incrementaly construct a d-dimensional point that is equidistant to all
- input points, i.e. all points are on the boundary of a d-dimensional sphere.
+ input points. The input points are on the boundary of a d-dimensional sphere.
This data structure is numerically robust and will reject point pushes that
degenerate the numerical stability (i.e. that are very close to the existing ball).
The code is based on the paper 'Fast and Robust Smallest Enclosing Balls' by
Bernd Gaertner.
+ \ingroup Math
*/
template
class equisphere
{
public:
+ /** Initialize the solver with an error boundary. 1e-15 is a good value to use with floats.
+ */
equisphere( RealType epsilon ) :
m(0), epsilon(epsilon)
{
@@ -49,26 +52,36 @@ class equisphere
std::fill_n(center[0],d,RealType(0));
}
+ /** Get the center of the equisphere.
+ */
const RealType* get_center() const
{
return ( m > 0 ) ? center[m-1] : center[0];
}
+ /** Get the squared radius of the sphere that is currently equidistant to all constraint points.
+ */
RealType get_squared_radius() const
{
return ( m > 0 ) ? sqr_radius[m-1] : sqr_radius[0];
}
+ /** Get the number of points currently used as constraints.
+ */
std::size_t get_support_count() const
{
return m;
}
+ /** Remove the last point constraint.
+ */
void pop()
{
--m;
}
+ /** Add a point constraint.
+ */
template
bool push( const VectorType& p )
{
@@ -190,6 +203,7 @@ class equisphere
Bernd Gaertner.
It employs the move-to-front heuristic. However, this heuristic
is only 'cheap' for std::list containers - otherwise std::rotate is used.
+ \ingroup Math
*/
template
class minimal_ball
diff --git a/include/replay/pixbuf.hpp b/include/replay/pixbuf.hpp
index 2ded5fe..8c0680f 100644
--- a/include/replay/pixbuf.hpp
+++ b/include/replay/pixbuf.hpp
@@ -33,7 +33,8 @@ Copyright (c) 2010 Marius Elvert
namespace replay {
-/** pixel based image.
+/** Pixel based image.
+ \note The image data is stored row-wise without padding, beginning with the bottom-most. This is different from, e.g., the Windows API, where images are stored with the top-most row first.
*/
class pixbuf :
public boost::noncopyable
@@ -47,14 +48,17 @@ class pixbuf :
public:
friend class pixbuf::internal;
+
+ /** A shared (reference-counted) pointer to a pixbuf.
+ */
typedef boost::shared_ptr shared_pixbuf;
/** Color-Format.
*/
enum color_format {
- greyscale, /**< greyscale (8-bit). */
- rgb, /**< Red,Green,Blue (24-bit). */
- rgba /**< Red,Green,Blue and Alpha (32-bit). */
+ greyscale, /**< Greyscale (8-bit). */
+ rgb, /**< Red, Green, Blue (24-bit). */
+ rgba /**< Red, Green, Blue and Alpha (32-bit). */
};
/** 8-bit unsigned int.
diff --git a/include/replay/pixbuf_io.hpp b/include/replay/pixbuf_io.hpp
index ad63fc2..c6cc74e 100644
--- a/include/replay/pixbuf_io.hpp
+++ b/include/replay/pixbuf_io.hpp
@@ -39,6 +39,8 @@ Copyright (c) 2010 Marius Elvert
namespace replay {
+/** Loading and saving functions for raster images.
+*/
namespace pixbuf_io
{
/** Exception that is thrown on read errors.
@@ -47,7 +49,9 @@ namespace pixbuf_io
public std::runtime_error
{
public:
- read_error( const std::string& str ) : std::runtime_error(str) {}
+ /** Initialize with an error string.
+ */
+ explicit read_error( const std::string& str ) : std::runtime_error(str) {}
};
/** Exception that is thrown on write errors.
diff --git a/include/replay/plane3.hpp b/include/replay/plane3.hpp
index 549e831..ec7a903 100644
--- a/include/replay/plane3.hpp
+++ b/include/replay/plane3.hpp
@@ -33,7 +33,8 @@ Copyright (c) 2010 Marius Elvert
namespace replay {
/** 3-dimensional plane.
- All \f$x \in R^3\f$ that satisfy the equation \f$normal*x + d = 0\f$.
+ All \f$\vec{x} \in \mathbb{R}^3\f$ that satisfy the equation \f$\langle\vec{\mathsf{normal}},\vec{x}\rangle + \mathsf{d} = 0\f$.
+ The distance to a plane can be computed by \ref replay::distance().
\ingroup Math
*/
class plane3
@@ -63,7 +64,7 @@ class plane3
*/
void flip();
- /** Clear all components to 0, effectively degenerating the plane into the \f$R^3\f$.
+ /** Clear all components to 0, effectively degenerating the plane into the \f$\mathbb{R}^3\f$.
*/
void clear();
@@ -96,11 +97,11 @@ class plane3
*/
static plane3 construct_from_points( const vector3f& p0, const vector3f& p1, const vector3f& p2 );
- /** exception class.
+ /** Exception class.
*/
class invalid_plane : std::exception {};
- /** convert the equation into hessian normal form.
+ /** Convert the equation into hessian normal form.
*/
void hnf( const float epsilon = math::default_epsilon );
};
diff --git a/include/replay/table.hpp b/include/replay/table.hpp
index 07b984e..9bb0d21 100644
--- a/include/replay/table.hpp
+++ b/include/replay/table.hpp
@@ -49,7 +49,14 @@ template < class T > class table
public:
+ /** An iterator to use with this type.
+ \note This is currently implemented as a raw pointer.
+ */
typedef object_type* iterator;
+
+ /** An immutable iterator to use with this type.
+ \note This is currently implemented as a const raw pointer.
+ */
typedef const object_type* const_iterator;
/** Fill the table with the given value.
diff --git a/include/replay/vector2.hpp b/include/replay/vector2.hpp
index 47d01ba..97a9b0d 100644
--- a/include/replay/vector2.hpp
+++ b/include/replay/vector2.hpp
@@ -39,27 +39,6 @@ template < class type > class vector2
type data[ 2 ];
public:
- /** a component wise less predicate.
- */
- class less
- {
- public:
- /** does the predicate thing.
- */
- bool operator ()( const vector2< type >& a, const vector2< type >& b ) const
- {
- for ( unsigned int i = 0; i < 2; ++i )
- {
- if ( a.data[ i ] < b.data[ i ] )
- return true;
- else if ( a.data[ i ] > b.data[ i ] )
- return false;
- }
-
- return false;
- }
- };
-
/** Get a pointer to the internal array.
*/
inline type* ptr() { return data; }
diff --git a/include/replay/vector3.hpp b/include/replay/vector3.hpp
index 974137b..28e433e 100644
--- a/include/replay/vector3.hpp
+++ b/include/replay/vector3.hpp
@@ -40,27 +40,6 @@ template < class type > class vector3
type data[ 3 ];
public:
- /** a component wise less predicate.
- */
- class less
- {
- public:
- /** does the predicate thing.
- */
- bool operator ()( const vector3< type >& a, const vector3< type >& b ) const
- {
- for ( unsigned int i = 0; i < 3; ++i )
- {
- if ( a.data[ i ] < b.data[ i ] )
- return true;
- else if ( a.data[ i ] > b.data[ i ] )
- return false;
- }
-
- return false;
- }
- };
-
/** Get a pointer to the internal array.
*/
inline type* ptr() { return data; }
diff --git a/include/replay/vector4.hpp b/include/replay/vector4.hpp
index eb7c8b7..7a59a2c 100644
--- a/include/replay/vector4.hpp
+++ b/include/replay/vector4.hpp
@@ -41,28 +41,6 @@ template < class type > class vector4
type data[ 4 ];
public:
- /** a component wise less predicate.
- */
- class less
- {
- public:
- /** does the predicate thing.
- */
- bool operator ()( const vector4< type >& a, const vector4< type >& b ) const
- {
- for ( unsigned int i = 0; i < 4; ++i )
- {
- if ( a.data[ i ] < b.data[ i ] )
- return true;
- else if ( a.data[ i ] > b.data[ i ] )
- return false;
- }
-
- return false;
- }
- };
-
-
/** Get a pointer to the internal array.
*/
inline type* ptr() { return data; }
diff --git a/include/replay/vector_math.hpp b/include/replay/vector_math.hpp
index 98ecd79..19e82f1 100644
--- a/include/replay/vector_math.hpp
+++ b/include/replay/vector_math.hpp
@@ -80,6 +80,31 @@ namespace replay {
+ l.normal[ 2 ] * r[ 14 ] + l.d * r[ 15 ] );
}
+ /** Component wise less predicate.
+ Does a lexical comparision between constant-size arrays, for example n-dimensional vectors.
+ The type to be used only needs have operator[] available.
+ \ingroup Math
+ */
+ template < class ArrayType, std::size_t n >
+ class array_less
+ {
+ public:
+ /** Evalutate the predicate.
+ */
+ bool operator()( const ArrayType& lhs, const ArrayType& rhs ) const
+ {
+ for ( std::size_t i=0; i rhs[i] )
+ return false;
+ }
+
+ return false;
+ }
+ };
+
namespace math {
@@ -109,7 +134,7 @@ namespace math {
*/
void decompose_rotational_matrix( const matrix4& m, quaternion& result );
- /** compute the determinante of a 2x2 matrix given as two vectors.
+ /** Compute the determinante of a 2x2 matrix given as two vectors.
\ingroup Math
*/
inline float det( const vector2f& a, const vector2f& b )
@@ -117,7 +142,7 @@ namespace math {
return a[ 0 ] * b[ 1 ] - a[ 1 ] * b[ 0 ];
}
- /** compute the determinante of a 2x2 matrix given as 4 values.
+ /** Compute the determinante of a 2x2 matrix given as 4 values.
\ingroup Math
*/
inline float det( const float a, const float b, const float c, const float d )
@@ -126,13 +151,13 @@ namespace math {
}
- /** setup a perspective matrix for homogenous coordinates.
+ /** Setup a perspective matrix for homogenous coordinates.
\ingroup Math
*/
void set_perspective_matrix( matrix4& matrix, float fovy,
float aspect, float near, float far );
- /** setup a perspective matrix for homogenous coordinates.
+ /** Setup a perspective matrix for homogenous coordinates.
\ingroup Math
*/
inline matrix4 make_perspective_matrix( float fovy,
@@ -143,13 +168,13 @@ namespace math {
return result;
}
- /** setup an orthographic matrix for homogenous coordinates.
+ /** Setup an orthographic matrix for homogenous coordinates.
\ingroup Math
*/
void set_orthographic_matrix( matrix4& matrix, const fcouple& width,
const fcouple& height, const fcouple& depth );
- /** setup an orthographic matrix for homogenous coordinates.
+ /** Setup an orthographic matrix for homogenous coordinates.
\ingroup Math
*/
inline matrix4 make_orthographic_matrix( const fcouple& width,
@@ -160,10 +185,11 @@ namespace math {
return result;
}
- /** construct a vector that is perpendicular to the given one.
+ /** Construct a vector that is perpendicular to the given one.
+ In general, the resulting vector will be shorter than the given one.
\ingroup Math
*/
- vector3f construct_perpendicular( const vector3f& x );
+ const vector3f construct_perpendicular( const vector3f& x );
/** vector component wise mult by sign.
@@ -242,21 +268,15 @@ namespace math {
/** Find a 2D convex hull of a set of 2d vectors using the gift wrap algorithm.
The points are reordered so that the first points make up a convex hull of the set.
+ The resulting hull is in counter clockwise order.
+ This algorithm is output sensitive in its runtime: it will perform a number of n*k steps,
+ where n is the number of points, and k is the number of points on the convex hull.
\param points The points to find the convex hull of.
\param count The number of points in the set.
\return The number of points that make up the convex hull.
\ingroup Math
*/
- unsigned int gift_wrap2( vector3f* points, unsigned int count );
-
- /** Find a 2D convex hull of a set of 2d vectors using the gift wrap algorithm.
- The points are reordered so that the first points make up a convex hull of the set.
- \param points The points to find the convex hull of.
- \param count The number of points in the set.
- \return The number of points that make up the convex hull.
- \ingroup Math
- */
- unsigned int gift_wrap( vector2f* points, unsigned int count );
+ std::size_t gift_wrap( vector2f* points, std::size_t count );
/** Checks whether the given point is inside the given convex hull.
@@ -269,24 +289,6 @@ namespace math {
*/
bool intersect_line2( const line2& a, const line2& b, vector2f& result );
- /** Compute a sphere from 4 non-coplanar points.
- \returns The square of the radius and center if the points are not coplanar, otherwise the center is undefined and the radius is negative.
- \ingroup Math
- */
- boost::tuple construct_sphere( boost::array P );
-
- /** Construct a circle from three points.
-
- If the points are colinear, a negative radius is returned.
- \ingroup Math
- */
- void construct_circle( const vector2f& a, const vector2f& b, const vector2f& c,
- vector2f& m, float& radius );
-
- /** Construct the circumcircle of a triangle.
- */
- bool construct_circumcircle( const vector3f& a, const vector3f& b, const vector3f& c,
- vector3f& m, float& square_radius );
/** Construct the minimal sphere containing a set of points using Welzl's algorithm.
Expected linear runtime.
@@ -372,34 +374,34 @@ float square_distance( const line3& line, const vector3f& point );
*/
float square_distance( const vector3f& point0, const vector3f& point1 );
-/** finds the square of the euclidean distance of two 3d lines.
+/** Compute the square of the euclidean distance of two 3d lines.
*/
float square_distance( const line3& la, const line3& lb );
-/** finds the euclidean distance of a line and a point.
+/** Compute the euclidean distance of a line and a point.
\ingroup Math
*/
-float distance( const line3& line, const vector3f& point );
+float distance( const replay::line3& line, const replay::vector3f& point );
/** Compute the signed distance of a plane and a point.
If the plane's normal is unit-length, the absolute of this
distance is the euclidean distance.
\ingroup Math
*/
-float distance( const plane3& p, const vector3f& point );
+float distance( const replay::plane3& p, const replay::vector3& point );
/** Compute the euclidean distance of two points.
\ingroup Math
*/
-inline float distance( const vector3f& lhs, const vector3f& rhs ) { return std::sqrt(square_distance(lhs,rhs)); }
+inline float distance( const replay::vector3f& lhs, const replay::vector3f& rhs ) { return std::sqrt(square_distance(lhs,rhs)); }
-/** compute the length of a vector. (2-norm)
+/** Compute the euclidean length of a vector.
\ingroup Math
*/
float magnitude( const vector2f& vector );
-/** compute the length of a vector. (2-norm)
+/** Compute the euclidean length of a vector.
\ingroup Math
*/
float magnitude( const vector3f& vector );
diff --git a/source/box_packer.cpp b/source/box_packer.cpp
index e367c73..fd7651c 100644
--- a/source/box_packer.cpp
+++ b/source/box_packer.cpp
@@ -100,9 +100,9 @@ replay::box_packer::node::insert( const couple< int >& size, int padding )
/** Create a new box packer.
- \param width the width of the area to pack on
- \param height the height of the area to pack on
- \param padding space to be left between packed items
+ \param width The width of the area to pack in
+ \param height The height of the area to pack in
+ \param padding Space to be left between rectangles
*/
replay::box_packer::box_packer( int width, int height, int padding )
: root( new node( box< int >( padding, padding, width-padding, height-padding ) ) ), padding( padding )
@@ -135,7 +135,7 @@ replay::box_packer::pack( int width, int height )
}
/** Pack an item of the given size.
- If there is no more space left to pack the given item, the function
+ This is the exception free variant: if there is no more space left to pack the given item, the function
will return false.
\param width The width of the item to pack.
\param height The height of the item to pack.
diff --git a/source/math.cpp b/source/math.cpp
index 33d1cef..279c2bf 100644
--- a/source/math.cpp
+++ b/source/math.cpp
@@ -29,7 +29,7 @@ Copyright (c) 2010 Marius Elvert
unsigned int replay::math::solve_quadratic_eq( float a, float b, float c, fcouple& result, float epsilon )
{
- if ( !math::near_zero( a, epsilon ) )
+ if ( !math::fuzzy_zero( a, epsilon ) )
{
float r = b*b - 4*a*c;
@@ -56,7 +56,7 @@ unsigned int replay::math::solve_quadratic_eq( float a, float b, float c, fcoupl
}
}
}
- else if ( !math::near_zero( b, epsilon ) )
+ else if ( !math::fuzzy_zero( b, epsilon ) )
{
result[ 0 ] = result[ 1 ] = -c/b;
return 1;
@@ -71,10 +71,15 @@ unsigned int replay::math::solve_quadratic_eq( float a, float b, float c, fcoupl
/** \mainpage Replay
\section section_about About
Replay is a bootstrap library for game development. It mostly provides game development
- oriented mathematical tools, such as \ref replay::vector3, \ref replay::quaternion and, built on those, \ref replay::affinity.
+ oriented mathematical tools, such as \ref replay::vector3, \ref replay::quaternion and,
+ built on those, \ref replay::affinity.
+
+ The library is currently hosted on google code: http://code.google.com/p/replay/
+
+ \section section_dependencies Dependencies
+ Replay depends on libpng (and therefore libpng) and boost.
+
- \section section_dependancies Dependancies
- Replay depends on libpng, expat and boost.
*/
diff --git a/source/matrix4.cpp b/source/matrix4.cpp
index 9ea93b2..eac3a8d 100644
--- a/source/matrix4.cpp
+++ b/source/matrix4.cpp
@@ -372,7 +372,7 @@ replay::matrix4::determinant() const
unsigned int index = 0;
// find the first column that has the 4th element enequal to zero
- while ( index < 4 && math::near_zero( data[ index*4+3 ] ) )
+ while ( index < 4 && math::fuzzy_zero( data[ index*4+3 ] ) )
++index;
if ( index == 4 )
@@ -396,7 +396,7 @@ replay::matrix4::determinant() const
while ( index < 3 )
{
float factor = temp.data[ index*4+3 ];
- if ( !math::near_zero( factor ) )
+ if ( !math::fuzzy_zero( factor ) )
{
factor = -(factor / last[ 3 ]);
temp.set_column( index, temp.get_column( index ) + factor*last );
diff --git a/source/pixbuf.cpp b/source/pixbuf.cpp
index 492fcd6..dcd3e5c 100644
--- a/source/pixbuf.cpp
+++ b/source/pixbuf.cpp
@@ -271,7 +271,7 @@ replay::pixbuf::create( unsigned int x, unsigned int y, color_format format )
return result;
}
-/** return a part of this image.
+/** Return a section of this image.
\param x Source offset x-coordinate.
\param y Source offset y-coordinate.
\param w Width of the part to copy.
@@ -289,7 +289,7 @@ replay::pixbuf::get_sub_image( unsigned int x, unsigned int y, unsigned int w, u
return result;
}
-/** copy a part of one image to another.
+/** Copy a part of one image to another.
\param dx Destination x-coordinate.
\param dy Destination y-coordinate.
\param w Width of the part to copy.
diff --git a/source/pixbuf_io.cpp b/source/pixbuf_io.cpp
index 4fb5738..b75a30d 100644
--- a/source/pixbuf_io.cpp
+++ b/source/pixbuf_io.cpp
@@ -309,38 +309,6 @@ tga_header::load_type2( replay::ibstream& file )
return result;
}
-replay::shared_pixbuf
-tga_header::load( replay::ibstream& file )
-{
- using namespace replay;
-
- file >> id_length >> colormap_type >> image_type;
-
- // colormaps are not supported
- if ( colormap_type != 0 )
- throw pixbuf_io::unrecognized_format();
-
- replay::shared_pixbuf result;
-
- switch ( image_type )
- {
- // uncompressed, unmapped BGR image
- case 2: result=load_type2( file ); break;
-
- // FIXME: add this
- // compressed, unmapped
- //case 10: load_type10( dst, file ); break;
-
- default:
- throw pixbuf_io::unrecognized_format();
- };
-
- if ( image_descriptor & (1 << 5 ) )
- result->flip();
-
- return result;
-}
-
/** Deserialize a TGA encoded file.
*/
replay::shared_pixbuf
@@ -395,6 +363,40 @@ replay::pixbuf_io::save_to_file( const boost::filesystem::path& filename, const
}
}
+#ifndef DOXYGEN_SHOULD_SKIP_THIS
+
+replay::shared_pixbuf
+tga_header::load( replay::ibstream& file )
+{
+ using namespace replay;
+
+ file >> id_length >> colormap_type >> image_type;
+
+ // colormaps are not supported
+ if ( colormap_type != 0 )
+ throw pixbuf_io::unrecognized_format();
+
+ replay::shared_pixbuf result;
+
+ switch ( image_type )
+ {
+ // uncompressed, unmapped BGR image
+ case 2: result=load_type2( file ); break;
+
+ // FIXME: add this
+ // compressed, unmapped
+ //case 10: load_type10( dst, file ); break;
+
+ default:
+ throw pixbuf_io::unrecognized_format();
+ };
+
+ if ( image_descriptor & (1 << 5 ) )
+ result->flip();
+
+ return result;
+}
+
void
tga_header::save( replay::obstream& file, const replay::pixbuf& source )
{
@@ -478,3 +480,5 @@ replay::pixbuf_io::load_from_file( const boost::filesystem::path& filename )
throw pixbuf_io::unrecognized_format();
}
+
+#endif
diff --git a/source/quaternion.cpp b/source/quaternion.cpp
index eb86577..a27d2ca 100644
--- a/source/quaternion.cpp
+++ b/source/quaternion.cpp
@@ -265,7 +265,7 @@ replay::quaternion::shortest_arc( const vector3f& a, const vector3f& b )
{
const float cos = a | b;
- if ( math::near( cos, 1.f ) )
+ if ( math::fuzzy_equals( cos, 1.f ) )
return quaternion();
const vector3f axis = normalized( a * b );
@@ -310,7 +310,7 @@ replay::quaternion::slerp( const replay::quaternion& a, const replay::quaternion
if ( dot < 0.f )
{
- if ( math::near( dot, -1.f ) ) // nlerp
+ if ( math::fuzzy_equals( dot, -1.f ) ) // nlerp
{
quaternion result( a*(1.f-x) - b*x );
return result.normalize();
@@ -326,7 +326,7 @@ replay::quaternion::slerp( const replay::quaternion& a, const replay::quaternion
}
else
{
- if ( math::near( dot, 1.f ) ) // nlerp
+ if ( math::fuzzy_equals( dot, 1.f ) ) // nlerp
{
quaternion result( a*(1.f-x) + b*x );
return result.normalize();
diff --git a/source/scalar.cpp b/source/scalar.cpp
deleted file mode 100644
index 7ed3085..0000000
--- a/source/scalar.cpp
+++ /dev/null
@@ -1,204 +0,0 @@
-/*
-replay
-Software Library
-
-Copyright (c) 2010 Marius Elvert
-
- Permission is hereby granted, free of charge, to any person obtaining a copy
- of this software and associated documentation files (the "Software"), to deal
- in the Software without restriction, including without limitation the rights
- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- copies of the Software, and to permit persons to whom the Software is
- furnished to do so, subject to the following conditions:
-
- The above copyright notice and this permission notice shall be included in
- all copies or substantial portions of the Software.
-
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- THE SOFTWARE.
-
-*/
-
-#include
-#include
-#include
-#include
-#include
-
-/** Gives the value of this scalar as a double.
- If the value cannot be converted to double, this will return 0.
-*/
-double replay::scalar::as_double() const
-{
- std::istringstream str( *this );
- double result = 0.0;
- str >> result;
- return result;
-}
-
-/** Gives the value of this scalar as a float.
- If the value cannot be converted to float, this will return 0.
-*/
-float replay::scalar::as_float() const
-{
- std::istringstream str( *this );
- float result = 0.0;
- str >> result;
- return result;
-}
-
-/** Gives the value of this scalar as a string.
-*/
-const std::string& replay::scalar::as_string() const
-{
- return *this;
-}
-
-
-/** Gives the value of this scalar as an unsigned int.
- If the value cannot be converted to unsigned int, this will return 0.
-*/
-unsigned int replay::scalar::as_uint() const
-{
- std::istringstream str( *this );
- unsigned int result = 0;
- str >> result;
-
- if ( result == 0 && str.peek() == 'x' )
- {
- char x;
- str >> x >> x;
-
- while ( str.good() )
- {
- if ( std::isdigit( x ) )
- result = 16*result + (x - '0');
- else if ( math::in_range( x, 'a', 'f' ) )
- result = 16*result + (x - 'a') + 10;
- else if ( math::in_range( x, 'A', 'F' ) )
- result = 16*result + (x - 'A') + 10;
- else
- break;
-
- str >> x;
- }
- /*str.str( *this );
- str.setf( std::ios::hex );
- str >> result;*/
- }
-
- return result;
-}
-
-/** Gives the value of this scalar as an int.
- If the value cannot be converted to int, this will return 0.
-*/
-int replay::scalar::as_int() const
-{
- std::istringstream str( *this );
- int result = 0;
- str >> result;
- return result;
-}
-
-/** Gives the value of this scalar as bool.
- "true" and "false" strings are also considered valid boolean sequences.
-*/
-bool replay::scalar::as_bool() const
-{
- if ( boost::algorithm::all( static_cast< const std::string& >( *this ),
- boost::algorithm::is_digit() ) )
- {
- return this->as_uint() > 0;
- }
- else
- {
- std::istringstream str( *this );
- bool result = false;
- str.setf( std::ios::boolalpha );
- str >> result;
- return result;
- }
-}
-
-/** Assign a C-style string.
-*/
-replay::scalar& replay::scalar::operator=( const char* x )
-{
- static_cast< std::string& >( *this ) = x;
- return *this;
-}
-
-/** Assign a string.
-*/
-replay::scalar& replay::scalar::operator=( const std::string& x )
-{
- static_cast< std::string& >( *this ) = x;
- return *this;
-}
-
-/** Assign another scalar.
-*/
-replay::scalar& replay::scalar::operator=( const scalar& x )
-{
- static_cast< std::string& >( *this ) = x;
- return *this;
-}
-
-/** Assign a boolean value.
-*/
-replay::scalar& replay::scalar::operator =( const bool x )
-{
- std::ostringstream str;
- str << x;
- return (*this = str.str());
-}
-
-/** Assign a float value.
-*/
-replay::scalar& replay::scalar::operator=( const float x )
-{
- std::ostringstream str;
- str << x;
- return (*this = str.str());
-}
-
-/** Assign an unsigned int.
-*/
-replay::scalar& replay::scalar::operator=( const unsigned int x )
-{
- std::ostringstream str;
- str << x;
- return (*this = str.str());
-}
-
-/** Assign an int.
-*/
-replay::scalar& replay::scalar::operator=( const int x )
-{
- std::ostringstream str;
- str << x;
- return (*this = str.str());
-}
-
-/** Assign a double.
-*/
-replay::scalar& replay::scalar::operator=( const double x )
-{
- std::ostringstream str;
- str << x;
- return (*this = str.str());
-}
-
-/** Clear the value.
-*/
-void replay::scalar::clear()
-{
- std::string::clear();
-}
-
diff --git a/source/vector_math.cpp b/source/vector_math.cpp
index 09cbe1c..d40d15c 100644
--- a/source/vector_math.cpp
+++ b/source/vector_math.cpp
@@ -36,41 +36,6 @@ Copyright (c) 2010 Marius Elvert
namespace {
-/** Compute the circumcenter of a triangle going through [0,0,0], u, and v.
-*/
-inline bool construct_circumcenter( const replay::vector3f& u, const replay::vector3f& v, replay::vector3f& center )
-{
- using namespace replay;
-
- // Solve 0.5u + a*(u x(u x v)) = 0.5v + b*(v x(u x v))
- vector3f n=vector3f::cross_product(u,v);
- vector3f un=vector3f::cross_product(u,n);
- vector3f vn=vector3f::cross_product(v,n);
-
- // This results in an overdetermined system M, so premultiply by M^T
- // Setup a matrix
- float m11 = un.squared();
- float m12 = -(vn|un);
- float m22 = vn.squared();
-
- float det = m11*m22-m12*m12;
-
- // Needs to be invertible
- if ( math::near_zero( det ) )
- return false;
-
- // compute the right side of the equation
- vector3f d=u-v;
- float r1 = 0.5f*-(d|un);
- float r2 = 0.5f*d|vn;
-
- // compute 'a'
- float a = (m22*r1 - m12*r2)/det;
-
- center = 0.5f*u + a*un;
- return true;
-}
-
/** Compute the square distance of a point p to a segment from 0,0 to t.
*/
inline float square_distance_point_segment( const replay::vector2f& t, const replay::vector2f& p )
@@ -150,107 +115,6 @@ void replay::math::minimal_sphere( vector3f* p, std::size_t n, vector3f& m, floa
r = mb.square_radius();
}
-bool replay::math::construct_circumcircle( const vector3f& a, const vector3f& b, const vector3f& c,
- vector3f& m, float& square_radius )
-{
- vector3f db=b-a, dc=c-a;
-
- if ( !construct_circumcenter( db, dc, m ) )
- return false;
-
- square_radius = m.squared();
- m+=a;
-
- return true;
-}
-
-boost::tuple replay::math::construct_sphere( boost::array P )
-{
- boost::array Sqr;
-
-
- // compute the square of all points
- for ( int i=0; i<4; ++i )
- Sqr[i]=P[i].squared();
-
- const float m15 = replay::matrix4(
- Sqr[0], P[0][0], P[0][1], P[0][2],
- Sqr[1], P[1][0], P[1][1], P[1][2],
- Sqr[2], P[2][0], P[2][1], P[2][2],
- Sqr[3], P[3][0], P[3][1], P[3][2] ).determinant();
-
- // we no longer need the values intact..
- // so subtract the last row from the first three, eliminating 3 ones in the last column of the other minors
- for ( int i=0; i<3; ++i )
- {
- Sqr[i]-=Sqr[3];
- P[i]-=P[3];
- }
-
- const float m11 = det3(
- P[0][0], P[0][1], P[0][2],
- P[1][0], P[1][1], P[1][2],
- P[2][0], P[2][1], P[2][2] );
-
- const float m12 = det3(
- Sqr[0], P[0][1], P[0][2],
- Sqr[1], P[1][1], P[1][2],
- Sqr[2], P[2][1], P[2][2] );
-
- const float m13 = det3(
- Sqr[0], P[0][0], P[0][2],
- Sqr[1], P[1][0], P[1][2],
- Sqr[2], P[2][0], P[2][2] );
-
- const float m14 = det3(
- Sqr[0], P[0][0], P[0][1],
- Sqr[1], P[1][0], P[1][1],
- Sqr[2], P[2][0], P[2][1] );
-
- boost::tuple result;
-
- if ( !replay::math::near_zero( m11 ) )
- {
- const float c = 0.5f / m11;
- result.get<0>().set( c*m12, -c*m13, c*m14 );
- result.get<1>() = result.get<0>().squared() - m15/m11;
- }
- else
- {
- // points are coplanar
- result.get<1>() = -1.f;
- }
-
- return result;
-}
-
-replay::vector3f replay::math::construct_perpendicular( const vector3f& x )
-{
- int p = 0;
- float m = math::abs( x[ 0 ] );
- float t;
-
- for ( int i = 1; i < 3; ++i )
- {
- t = abs( x[ i ] );
- if ( m < t )
- {
- m = t;
- p = i;
- }
- }
-
- int q = (p + 1)%3;
- int r = (q + 1)%3;
-
- vector3f result;
- result[ p ] = -x[ q ];
- result[ q ] = x[ p ];
- result[ r ] = 0.f;
-
- return result;
-}
-
void replay::math::decompose_rotational_matrix( const matrix3& m, quaternion& result )
{
result.w = std::sqrt( std::max( 0.f, 1.f + m(0,0) + m(1,1) + m(2,2) ) ) * 0.5f;
@@ -557,40 +421,6 @@ void replay::math::extract_frustum( const matrix4& scene, plane3* frustum )
}
-unsigned int replay::math::gift_wrap2( vector3f* point, unsigned int count )
-{
- unsigned int index = 0;
-
- // find the starting index
- index = std::min_element( point, point + count,
- vector3f::less() ) - point;
-
- std::swap( point[ index ], point[ 0 ] );
-
- for ( unsigned int j = 0; j < (count-1); ++j )
- {
- // invalidate the index
- index = count + 1;
-
- // pick a new index if it's unequal to the last point and if it's the first valid one, or a better one
- // the latter means it's right of the last line
- for ( unsigned int i = 0; i < count; ++i )
- if ( i != j && ( (index > count) || ( math::det( math::splice2( point[ index ]-point[ j ] ),
- math::splice2( point[ i ]-point[ j ] ) ) < 0.f )) )
- index = i;
-
- // we closed the loop
- if ( index == 0 )
- return j + 1;
-
- std::swap( point[ index ], point[ j + 1 ] );
- }
-
- // all points are on the convex hull
- return count;
-}
-
-
unsigned int replay::math::convex_hull_contains( vector2f* hull, unsigned int hullsize,
const vector2f& point, const float threshold )
{
@@ -605,52 +435,59 @@ unsigned int replay::math::convex_hull_contains( vector2f* hull, unsigned int hu
return 1;
}
-unsigned int replay::math::gift_wrap( vector2f* point, unsigned int count )
+const replay::vector3f replay::math::construct_perpendicular( const vector3f& x )
{
- unsigned int index = 0;
+ vector3f result;
+ std::size_t p = 0;
+ float m = math::abs( x[ 0 ] );
- // find the starting index
- index = std::min_element( point, point + count,
- vector2f::less() ) - point;
+ // Find the maximum element
+ for ( std::size_t i=1; i<3; ++i )
+ {
+ register float t = abs( x[ i ] );
+ if ( m < t )
+ {
+ m = t;
+ p = i;
+ }
+ }
- std::swap( point[ index ], point[ 0 ] );
+ int q = (p+1)%3;
+ int r = (q+1)%3;
- for ( unsigned int j = 0; j < (count-1); ++j )
- {
- // invalidate the index
- index = count + 1;
+ result[p] = -x[q];
+ result[q] = x[p];
+ result[r] = 0.f;
- // pick a new index if it's unequal to the last point and if it's the first valid one, or a better one
- // the latter means it's right of the last line
- for ( unsigned int i = 0; i < count; ++i )
- {
- if ( i != j )
- {
- if ( index > count )
- {
- index = i;
- continue;
- }
-
- const vector2f d = point[ i ]-point[ j ];
-
- if ( math::det( point[ index ]-point[ j ], d ) < 0.f )
- {
- index = i;
- }
- }
+ return result;
+}
- }
+std::size_t replay::math::gift_wrap( vector2f* point, std::size_t n )
+{
+ // No need to construct a hull
+ if ( n < 3 )
+ return n;
+
+ // Find the starting point on the convex hull
+ std::size_t candidate = std::min_element( point, point+n, array_less() ) - point;
+ std::swap( point[0], point[candidate] ); // move it to the front
+
+ // Find all other points
+ for ( std::size_t k=1; k 1 && replay::math::det( point[candidate]-point[k-1], point[0]-point[candidate] ) < 0.f )
+ return k;
- std::swap( point[ index ], point[ j + 1 ] );
+ std::swap( point[k], point[candidate] );
}
- // all points are on the convex hull
- return count;
+ return n;
}
replay::vector3f replay::math::intersect_3planes( const plane3& a, const plane3& b, const plane3& c )
@@ -665,18 +502,6 @@ replay::vector3f replay::math::intersect_3planes( const plane3& a, const plane3&
return Temp * -vector3f( a.d, b.d, c.d );
}
-void replay::math::construct_circle( const vector2f& a, const vector2f& b, const vector2f& c,
- vector2f& m, float& radius )
-{
- line2 u((a+b)*0.5f,complement(b-a));
- line2 v((a+c)*0.5f,complement(c-a));
-
- if ( !intersect_line2( u, v, m ) )
- radius = -1.f; // error - points are colinear
- else
- radius = magnitude(a-m);
-}
-
std::ostream& replay::operator<<( std::ostream& cout, const replay::vector2f& v )
{
return cout << '(' << v[ 0 ] << ' ' << v[ 1 ] << ')';
@@ -692,7 +517,7 @@ bool replay::math::intersect_line2( const line2& a, const line2& b, vector2f& re
float denom = det(a.direction,b.direction);
// lines parallel?
- if ( near_zero( denom ) )
+ if ( fuzzy_zero( denom ) )
return false;
float num = det(b.origin-a.origin,b.direction);
@@ -709,7 +534,7 @@ float replay::square_distance( const line3& la, const line3& lb )
float length = magnitude(comp);
// parallel or equal
- if ( math::near_zero(length) )
+ if ( math::fuzzy_zero(length) )
{
// find a reference point
vector3f ref = find_closest_point( la, lb.origin );
diff --git a/test/math_test.cpp b/test/math_test.cpp
index c8d6828..f94706b 100644
--- a/test/math_test.cpp
+++ b/test/math_test.cpp
@@ -62,7 +62,7 @@ BOOST_AUTO_TEST_CASE( quadratic_equation_solver )
float b=die();
float c=die();
- if ( replay::math::near( a,b ) )
+ if ( replay::math::fuzzy_equals( a,b ) )
continue;
fcouple r;
@@ -125,11 +125,6 @@ BOOST_AUTO_TEST_CASE( circumcircle )
// Reconstruct it
vector3f result_center;
- float result_radius_square;
-
- BOOST_REQUIRE( math::construct_circumcircle(a,b,c,result_center,result_radius_square) );
- BOOST_REQUIRE_SMALL((center-result_center).squared(), 0.001f);
- BOOST_REQUIRE_CLOSE(std::sqrt(result_radius_square),radius,0.001f );
equisphere s(1e-16f);
BOOST_REQUIRE(s.push(a.ptr()));
@@ -143,36 +138,6 @@ BOOST_AUTO_TEST_CASE( circumcircle )
}
-BOOST_AUTO_TEST_CASE( sphere_simple )
-{
- using namespace replay;
-
- // A somewhat trivial test case
- boost::array points;
- points[0].set(1.f,0.f,0.f);
- points[1].set(0.f,1.f,0.f);
- points[2].set(0.f,0.f,1.f);
- points[3].set(0.f,-1.f,0.f);
-
- boost::tuple sphere=math::construct_sphere(points);
-
- BOOST_REQUIRE_SMALL( sphere.get<0>().squared(), 0.001f );
- BOOST_REQUIRE_CLOSE( sphere.get<1>(), 1.f, 0.01f );
-
- // And now a more complicated one
- float radius=23.f;
- vector3f center(40.f, 23.f, 71.f);
- points[0] = center+polar_to_model(40.f,20.f)*radius;
- points[1] = center+polar_to_model(110.f,7.f)*radius;
- points[2] = center+polar_to_model(-67.f,-48.f)*radius;
- points[3] = center+polar_to_model(23.f,-70.f)*radius;
-
- sphere=math::construct_sphere(points);
-
- BOOST_REQUIRE_SMALL( (sphere.get<0>()-center).squared(), 0.001f );
- BOOST_REQUIRE_CLOSE( sphere.get<1>(), radius*radius, 0.01f );
-}
-
// Simple test case directly testing the minimal ball solver in 3D
BOOST_AUTO_TEST_CASE( minimal_ball )
{