add kd tree class
add mesh decimation algorithm
This commit is contained in:
3
src/3rdParty/libkdtree/AUTHORS
vendored
Normal file
3
src/3rdParty/libkdtree/AUTHORS
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
Martin F. Krafft <libkdtree@pobox.madduck.net>
|
||||
Paul Harris <paulharris@computer.org>
|
||||
Sylvain Bougerel <sylvain.bougerel.devel@gmail.com>
|
||||
37
src/3rdParty/libkdtree/CMakeLists.txt
vendored
Normal file
37
src/3rdParty/libkdtree/CMakeLists.txt
vendored
Normal file
@@ -0,0 +1,37 @@
|
||||
project (libkdtree CXX)
|
||||
cmake_minimum_required (VERSION 2.6.0)
|
||||
|
||||
option (BUILD_PYTHON_BINDINGS "Build Python bindings (requires SWIG)")
|
||||
|
||||
if (WIN32)
|
||||
|
||||
# Maximum warning level
|
||||
set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /W4")
|
||||
|
||||
# Be strict about warnings... make them errors
|
||||
set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /WX")
|
||||
|
||||
# Detect 64-bit portability issues
|
||||
set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /Wp64")
|
||||
|
||||
else (WIN32)
|
||||
|
||||
# Maximum warning level
|
||||
set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall")
|
||||
|
||||
# turn on debugging
|
||||
set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -g")
|
||||
|
||||
endif (WIN32)
|
||||
|
||||
if (BUILD_PYTHON_BINDINGS)
|
||||
add_subdirectory (python-bindings)
|
||||
endif (BUILD_PYTHON_BINDINGS)
|
||||
|
||||
include_directories (${PROJECT_SOURCE_DIR})
|
||||
|
||||
add_subdirectory(examples)
|
||||
|
||||
file (GLOB KDTREE_HEADERS kdtree++/*.hpp)
|
||||
install (FILES ${KDTREE_HEADERS} DESTINATION ${CMAKE_INSTALL_PREFIX}/include)
|
||||
|
||||
176
src/3rdParty/libkdtree/COPYING
vendored
Normal file
176
src/3rdParty/libkdtree/COPYING
vendored
Normal file
@@ -0,0 +1,176 @@
|
||||
"The Artistic Licence 2.0"
|
||||
Copyright (c) 2000-2006, The Perl Foundation.
|
||||
http://www.perlfoundation.org/legal/licenses/artistic-2_0.html
|
||||
|
||||
Everyone is permitted to copy and distribute verbatim copies of this license
|
||||
document, but changing it is not allowed.
|
||||
|
||||
Preamble
|
||||
~~~~~~~~
|
||||
This license establishes the terms under which a given free software Package
|
||||
may be copied, modified, distributed, and/or redistributed. The intent is that
|
||||
the Copyright Holder maintains some artistic control over the development of
|
||||
that Package while still keeping the Package available as open source and free
|
||||
software.
|
||||
|
||||
You are always permitted to make arrangements wholly outside of this license
|
||||
directly with the Copyright Holder of a given Package. If the terms of this
|
||||
license do not permit the full use that you propose to make of the Package,
|
||||
you should contact the Copyright Holder and seek a different licensing
|
||||
arrangement.
|
||||
|
||||
Definitions
|
||||
~~~~~~~~~~~
|
||||
"Copyright Holder" means the individual(s) or organization(s) named in the
|
||||
copyright notice for the entire Package.
|
||||
|
||||
"Contributor" means any party that has contributed code or other material to
|
||||
the Package, in accordance with the Copyright Holder's procedures.
|
||||
|
||||
"You" and "your" means any person who would like to copy, distribute, or
|
||||
modify the Package.
|
||||
|
||||
"Package" means the collection of files distributed by the Copyright Holder,
|
||||
and derivatives of that collection and/or of those files. A given Package may
|
||||
consist of either the Standard Version, or a Modified Version.
|
||||
|
||||
"Distribute" means providing a copy of the Package or making it accessible to
|
||||
anyone else, or in the case of a company or organization, to others outside of
|
||||
your company or organization.
|
||||
|
||||
"Distributor Fee" means any fee that you charge for Distributing this Package
|
||||
or providing support for this Package to another party. It does not mean
|
||||
licensing fees.
|
||||
|
||||
"Standard Version" refers to the Package if it has not been modified, or has
|
||||
been modified only in ways explicitly requested by the Copyright Holder.
|
||||
|
||||
"Modified Version" means the Package, if it has been changed, and such changes
|
||||
were not explicitly requested by the Copyright Holder.
|
||||
|
||||
"Original License" means this Artistic License as Distributed with the
|
||||
Standard Version of the Package, in its current version or as it may be
|
||||
modified by The Perl Foundation in the future.
|
||||
|
||||
"Source" form means the source code, documentation source, and configuration
|
||||
files for the Package.
|
||||
|
||||
"Compiled" form means the compiled bytecode, object code, binary, or any other
|
||||
form resulting from mechanical transformation or translation of the Source
|
||||
form.
|
||||
|
||||
Permission for Use and Modification Without Distribution
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
(1) You are permitted to use the Standard Version and create and use Modified
|
||||
Versions for any purpose without restriction, provided that you do not
|
||||
Distribute the Modified Version.
|
||||
|
||||
Permissions for Redistribution of the Standard Version
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
(2) You may Distribute verbatim copies of the Source form of the Standard
|
||||
Version of this Package in any medium without restriction, either gratis or
|
||||
for a Distributor Fee, provided that you duplicate all of the original
|
||||
copyright notices and associated disclaimers. At your discretion, such
|
||||
verbatim copies may or may not include a Compiled form of the Package.
|
||||
|
||||
(3) You may apply any bug fixes, portability changes, and other modifications
|
||||
made available from the Copyright Holder. The resulting Package will still be
|
||||
considered the Standard Version, and as such will be subject to the Original
|
||||
License.
|
||||
|
||||
Distribution of Modified Versions of the Package as Source
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
(4) You may Distribute your Modified Version as Source (either gratis or for
|
||||
a Distributor Fee, and with or without a Compiled form of the Modified
|
||||
Version) provided that you clearly document how it differs from the Standard
|
||||
Version, including, but not limited to, documenting any non-standard features,
|
||||
executables, or modules, and provided that you do at least ONE of the
|
||||
following:
|
||||
|
||||
(a) make the Modified Version available to the Copyright Holder of the
|
||||
Standard Version, under the Original License, so that the Copyright
|
||||
Holder may include your modifications in the Standard Version.
|
||||
(b) ensure that installation of your Modified Version does not prevent the
|
||||
user installing or running the Standard Version. In addition, the
|
||||
Modified Version must bear a name that is different from the name of
|
||||
the Standard Version.
|
||||
(c) allow anyone who receives a copy of the Modified Version to make the
|
||||
Source form of the Modified Version available to others under
|
||||
(i) the Original License or
|
||||
(ii) a license that permits the licensee to freely copy, modify and
|
||||
redistribute the Modified Version using the same licensing terms
|
||||
that apply to the copy that the licensee received, and requires
|
||||
that the Source form of the Modified Version, and of any works
|
||||
derived from it, be made freely available in that license fees
|
||||
are prohibited but Distributor Fees are allowed.
|
||||
|
||||
Distribution of Compiled Forms of the Standard Version or Modified Versions
|
||||
without the Source
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
(5) You may Distribute Compiled forms of the Standard Version without the
|
||||
Source, provided that you include complete instructions on how to get the
|
||||
Source of the Standard Version. Such instructions must be valid at the time of
|
||||
your distribution. If these instructions, at any time while you are carrying
|
||||
out such distribution, become invalid, you must provide new instructions on
|
||||
demand or cease further distribution. If you provide valid instructions or
|
||||
cease distribution within thirty days after you become aware that the
|
||||
instructions are invalid, then you do not forfeit any of your rights under
|
||||
this license.
|
||||
|
||||
(6) You may Distribute a Modified Version in Compiled form without the Source,
|
||||
provided that you comply with Section 4 with respect to the Source of the
|
||||
Modified Version.
|
||||
|
||||
Aggregating or Linking the Package
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
(7) You may aggregate the Package (either the Standard Version or Modified
|
||||
Version) with other packages and Distribute the resulting aggregation provided
|
||||
that you do not charge a licensing fee for the Package. Distributor Fees are
|
||||
permitted, and licensing fees for other components in the aggregation are
|
||||
permitted. The terms of this license apply to the use and Distribution of the
|
||||
Standard or Modified Versions as included in the aggregation.
|
||||
|
||||
(8) You are permitted to link Modified and Standard Versions with other works,
|
||||
to embed the Package in a larger work of your own, or to build stand-alone
|
||||
binary or bytecode versions of applications that include the Package, and
|
||||
Distribute the result without restriction, provided the result does not expose
|
||||
a direct interface to the Package.
|
||||
|
||||
Items That are Not Considered Part of a Modified Version
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
(9) Works (including, but not limited to, modules and scripts) that merely
|
||||
extend or make use of the Package, do not, by themselves, cause the Package to
|
||||
be a Modified Version. In addition, such works are not considered parts of the
|
||||
Package itself, and are not subject to the terms of this license.
|
||||
|
||||
General Provisions
|
||||
~~~~~~~~~~~~~~~~~~
|
||||
(10) Any use, modification, and distribution of the Standard or Modified
|
||||
Versions is governed by this Artistic License. By using, modifying or
|
||||
distributing the Package, you accept this license. Do not use, modify, or
|
||||
distribute the Package, if you do not accept this license.
|
||||
|
||||
(11) If your Modified Version has been derived from a Modified Version made by
|
||||
someone other than you, you are nevertheless required to ensure that your
|
||||
Modified Version complies with the requirements of this license.
|
||||
|
||||
(12) This license does not grant you the right to use any trademark, service
|
||||
mark, tradename, or logo of the Copyright Holder.
|
||||
|
||||
(13) This license includes the non-exclusive, worldwide, free-of-charge patent
|
||||
license to make, have made, use, offer to sell, sell, import and otherwise
|
||||
transfer the Package with respect to any patent claims licensable by the
|
||||
Copyright Holder that are necessarily infringed by the Package. If you
|
||||
institute patent litigation (including a cross-claim or counterclaim) against
|
||||
any party alleging that the Package constitutes direct or contributory patent
|
||||
infringement, then this Artistic License to you shall terminate on the date
|
||||
that such litigation is filed.
|
||||
|
||||
(14) Disclaimer of Warranty: THE PACKAGE IS PROVIDED BY THE COPYRIGHT HOLDER
|
||||
AND CONTRIBUTORS "AS IS' AND WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES. THE
|
||||
IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR
|
||||
NON-INFRINGEMENT ARE DISCLAIMED TO THE EXTENT PERMITTED BY YOUR LOCAL LAW.
|
||||
UNLESS REQUIRED BY LAW, NO COPYRIGHT HOLDER OR CONTRIBUTOR WILL BE LIABLE FOR
|
||||
ANY DIRECT, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING IN ANY WAY
|
||||
OUT OF THE USE OF THE PACKAGE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
|
||||
DAMAGE.
|
||||
236
src/3rdParty/libkdtree/ChangeLog
vendored
Normal file
236
src/3rdParty/libkdtree/ChangeLog
vendored
Normal file
@@ -0,0 +1,236 @@
|
||||
libkdtree++ ChangeLog
|
||||
=====================
|
||||
|
||||
2008-11-17 Sylvain Bougerel <sylvain.bougerel@asia.thalesgroup.com>
|
||||
|
||||
- Added #include<cstdio> in order to compile 'printf' statements in the
|
||||
file 'examples/test_find_within_range.cpp'.
|
||||
- Added patch from Max Fellermann in order to compile libkdtree++ with
|
||||
clang++.
|
||||
|
||||
2009-02-10 Paul Harris <paulharris@computer.org>
|
||||
|
||||
- Bug fix: was incorrectly casting a pointer when the search key type
|
||||
was different to the stored type.
|
||||
|
||||
2008-12-30 Paul Harris <paulharris@computer.org>
|
||||
|
||||
- New function: efficient_replace_and_optimise().
|
||||
Yes, its a long name. Sylvain doesn't like it.
|
||||
The reason for the long name is that it is a dangerous function,
|
||||
and it will resort whatever vector<> of data that you pass it.
|
||||
So I wanted the user to really know what they were doing before
|
||||
they called this function.
|
||||
- Now calls sqrt() when required in order to search for items
|
||||
in 'real' distance units... And so it will accept and return distance
|
||||
in 'real' units (as opposed to squared units).
|
||||
This is not an ideal solution, we have all sorts of ideas to improve
|
||||
kdtree which will include less calls to sqrt() for more speed, and
|
||||
the ability to change the standard euclidean distance measurements
|
||||
for distance-on-a-sphere or whatever the user wants.
|
||||
- Changed from using std::sort() to std::nth_element() when optimising
|
||||
the tree. Performance boost.
|
||||
- Added lots of tests to check that the find functions are working
|
||||
correctly when fed edge-cases, including:
|
||||
- Items that are exactly 'max' distance away from the target.
|
||||
- When there are no value items to find.
|
||||
- Templated the find functions so that the target/center point can be
|
||||
anything that can be accessed via the Accessor.
|
||||
- Fixes to make it compile.
|
||||
|
||||
- And, a Python wrapper ! See README.Python
|
||||
|
||||
- CMake support now can build the python wrapper and install the headers
|
||||
and the python wrapper to a destination folder. Its simple, but neat.
|
||||
Does not install python module into the python site packages or anything
|
||||
like that.
|
||||
|
||||
2008-11-17 Sylvain Bougerel <sylvain.bougerel@asia.thalesgroup.com>
|
||||
|
||||
- The version number of the library is now part of the headers.
|
||||
- Fixed a bug with assignment operator.
|
||||
- Fixed uninitialized memory problem with valgrind, when printing the
|
||||
content of the tree. Due to the fact the _M_header was a _Link_type
|
||||
instead of a _Node_base type and _M_root was a _Base_ptr type instead of
|
||||
a _Link_type.
|
||||
- Paul Harris fixed find() by ensuring that the correct node is being
|
||||
matched during a find(). Thus, fixed a similar problem in erase. Paul
|
||||
also added a new test courtesy of Hayne.
|
||||
- Paul Harris augmented test_kdtree with various test on copy
|
||||
construction, assignment, and formatting operator.
|
||||
- Paul Harris added support for CMake, which should suit not only
|
||||
MSVC users but others too.
|
||||
- Paul Harris fixed bug with compiling with MSVC2005 with the 64bit
|
||||
warnings turned on.
|
||||
|
||||
2008-11-12 Sylvain Bougerel <sylvain.bougerel@asia.thalesgroup.com>
|
||||
|
||||
- Fix segfault on the regular iterator when _M_header->_M_right ==
|
||||
_M_root. Fix segfault on the reverse iterator when _M_header->_M_left ==
|
||||
_M_root.
|
||||
|
||||
Besides, it also change the behavior when iterating past the end() or
|
||||
rend(). Previously this would result in segfaults, now it makes the
|
||||
iterator points to an undetermined location in the tree, similarly to
|
||||
the current implementation of GNU libstdc++.
|
||||
|
||||
2008-11-10 Sylvain Bougerel <sylvain.bougerel@asia.thalesgroup.com>
|
||||
|
||||
- kdtree++/iterator.hpp (KDTree): the decrement iterator was
|
||||
ill-written. Its buggy behavior, and the use of non-standard
|
||||
reverse_iterator initialiser needed to be fixed. These error were do to
|
||||
a previous failed attempt by me at fixing the reverse_iterator.
|
||||
|
||||
This time, I believe I got it right, however it needed the kdtree
|
||||
structure to be modified. The reason is that without modification it is
|
||||
not possible to distinguish the "header" from the "root" within the
|
||||
iterator. This is required for the reverse_iterator to work properly.
|
||||
|
||||
Now the kdtree has an additional pointer that points directly to the
|
||||
root. The parent pointer of the header is permanently null. And
|
||||
therefore the header can be distinguished from the root within the
|
||||
iterator by checking the parent of the current node: if it is null, we
|
||||
are at the header.
|
||||
|
||||
|
||||
2008-11-10 Sylvain Bougerel (sylvain.bougerel.devel@gmail.com)
|
||||
|
||||
- patch from Martin Shreiber to make libkdtree to compile with newer
|
||||
version of g++-4.2 and g++4.3.
|
||||
|
||||
- patch from Paul Harris to make libkdtree more exception transparent.
|
||||
|
||||
2007-12-08 Sylvain Bougerel (sylvain.bougerel.devel@gmail.com)
|
||||
|
||||
- fix bug where find_nearest() could return the wrong value if a
|
||||
maximum distance greater than the root distance to the target value
|
||||
was given in argument to the function.
|
||||
|
||||
- find_nearest() still returns SQUARED value of the distance. You still
|
||||
have to use sqrt() on the second member of the iterator.
|
||||
|
||||
- find_nearest() behavior was slightly changed: if many nodes are at
|
||||
the same distance from the target value, the node with the lowest
|
||||
memory address will be returned. This is to catter for the
|
||||
reimplementation of find_exact() coming soon.
|
||||
|
||||
2007-12-02 Sylvain Bougerel (sylvain.bougerel.devel@gmail.com)
|
||||
|
||||
- find_nearest() now returned the SQUARED value of the distance for
|
||||
euclidean space calculation (the default). You have to use sqrt() on
|
||||
the returned distance (i.e. iterator->second) if you want to read the
|
||||
absolute distance returned by find_nearest. My apologies for not
|
||||
making highlighting this beforehand.
|
||||
|
||||
- Increased the performance of find and find_nearest/find_nearest_if by
|
||||
about 50x to 100x depending on your compilation flags.
|
||||
|
||||
- KDTree are not defined as:
|
||||
KDTree<__K, _Val, _Acc, _Cmp, _Alloc>
|
||||
but as:
|
||||
KDTree<__K, _Val, _Acc, _Dist, _Cmp, _Alloc>
|
||||
So pay attention to the _Dist functor. The distance functor calculate
|
||||
the squared difference between 2 elements returned by the accessor. You
|
||||
might have to change your code to reflect the new definition, or it wont
|
||||
compile if you have set custom accessor and comparison functors.
|
||||
|
||||
- The following functors are now accessible in the tree:
|
||||
- the comparison functor, accessible by copy only
|
||||
- the accessor functor, accessible by copy only
|
||||
- the distance functor, accessible read-write, this means that
|
||||
you can modify the behavior of find, find_nearest,
|
||||
find_nearest_if within the same KDTree object.
|
||||
|
||||
- find_exact has not be modified and retained the code of the former,
|
||||
slower algorithm. I have to write some more code to do this. Pls wait a
|
||||
little more.
|
||||
|
||||
- The file accessor.hpp was renamed as function.hpp for it now boast
|
||||
more than just the KDTree accessor
|
||||
|
||||
2007-11-25 Sylvain Bougerel (sylvain.bougerel.devel@gmail.com)
|
||||
|
||||
- fixed the reverse_iterator. Now it can be used.
|
||||
|
||||
2007-10-24 Sylvain Bougerel (sylvain.bougerel.devel@gmail.com)
|
||||
|
||||
- Removal of all the warnings that are yield by the compiler when
|
||||
using the following flags:
|
||||
-Wall -pedantic -ansi
|
||||
Do not hesitate to suggest any flags for additional code checking.
|
||||
|
||||
This release also feature numerous of enhancements by Paul Harris
|
||||
(paulharris@computer.org):
|
||||
- const kdtrees can be searched
|
||||
- find_nearest_if() enforce validation of a predicate
|
||||
- visit_within_range() walk the tree and calls
|
||||
Visitor::operator() on template argument <Visitor> for
|
||||
each node within the range
|
||||
- find_exact() matches an kdtree::value_type by location and by
|
||||
calling kdtree::value_type::operator==() (in case two different
|
||||
items have the same location find_exact() will not return the
|
||||
wrong item)
|
||||
- erase_exact() is to erase() what find_exact() is to find()
|
||||
- check_tree() and num_dist_calcs for debugging purpose plus
|
||||
additional improvements on erase and region intersection
|
||||
|
||||
2004-11-26 Paul Harris (paulharris@computer.org)
|
||||
|
||||
- New feature: find_nearest()
|
||||
- Accessors can now be initialised with the tree, so ptr_fun()
|
||||
or functors can be used to access datapoints.
|
||||
- Accessors now much more generic, so you can use the same
|
||||
accessor to access multiple types.
|
||||
- Range-constructors now optimise() automatically, simplifying
|
||||
the construction of a filled tree.
|
||||
- _Range is now more easy to construct.
|
||||
|
||||
2004-11-15 Martin F. Krafft (libkdtree@pobox.madduck.net)
|
||||
|
||||
- fixed numerous little bugs that led to compilation problems
|
||||
- changed code to compile cleanly with GCC 3.4 and GCC 4.0
|
||||
|
||||
2004-11-06 Martin F. Krafft (libkdtree@pobox.madduck.net)
|
||||
|
||||
- reverted to optimise() to prevent API change, and added an optimize()
|
||||
passthrough method with an appropriate comment.
|
||||
|
||||
2004-11-05 Paul Harris (paulharris@computer.org)
|
||||
|
||||
- Renamed optimise() to optimize().
|
||||
- Added a full set of range constructors and insert(range) methods.
|
||||
it now works with inserter(tree,tree.begin())
|
||||
- Target type no longer needs a default constructor. This also fixes
|
||||
problems with empty trees (would crash if optimized).
|
||||
- Some code cleanup (removed inlines, switched from const_iterator to
|
||||
iterator, added this-> to ensure the methods are called).
|
||||
- Added a new method: count_within_range().
|
||||
- Fixed bug in rend().
|
||||
|
||||
2004-11-04 Martin F. Krafft (libkdtree@pobox.madduck.net)
|
||||
|
||||
- Integrated patch by Paul Harris to fix a logic error pertaining to
|
||||
OutputIterators in find_within_range. find_within_range() now
|
||||
returns the output iterator instead of a count. Thanks, Paul!
|
||||
- Added another fix by Paul Harris to _M_get_j_max, which would cause
|
||||
a dimensional overflow for trees with depths >= K. Thanks (again) Paul!
|
||||
- Made some improvements to the autotools files.
|
||||
|
||||
2004-05-11 Martin F. Krafft (libkdtree@pobox.madduck.net)
|
||||
|
||||
- Fixed CFlags and Libs entries in pkgconfig file.
|
||||
|
||||
2004-05-11 Martin F. Krafft (libkdtree@pobox.madduck.net)
|
||||
|
||||
- Initial release.
|
||||
|
||||
|
||||
COPYRIGHT --
|
||||
libkdtree++ is (c) 2004-2007 Martin F. Krafft <libkdtree@pobox.madduck.net> and
|
||||
Sylvain Bougerel <sylvain.bougerel.devel@gmail.com> and distributed under the
|
||||
terms of the Artistic License 2.0. See the ./COPYING file in the source tree
|
||||
root for more information.
|
||||
|
||||
THIS PACKAGE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES,
|
||||
INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND
|
||||
FITNESS FOR A PARTICULAR PURPOSE.
|
||||
234
src/3rdParty/libkdtree/INSTALL
vendored
Normal file
234
src/3rdParty/libkdtree/INSTALL
vendored
Normal file
@@ -0,0 +1,234 @@
|
||||
Installation Instructions
|
||||
*************************
|
||||
|
||||
Copyright (C) 1994, 1995, 1996, 1999, 2000, 2001, 2002, 2004, 2005,
|
||||
2006 Free Software Foundation, Inc.
|
||||
|
||||
This file is free documentation; the Free Software Foundation gives
|
||||
unlimited permission to copy, distribute and modify it.
|
||||
|
||||
Basic Installation
|
||||
==================
|
||||
|
||||
Briefly, the shell commands `./configure; make; make install' should
|
||||
configure, build, and install this package. The following
|
||||
more-detailed instructions are generic; see the `README' file for
|
||||
instructions specific to this package.
|
||||
|
||||
The `configure' shell script attempts to guess correct values for
|
||||
various system-dependent variables used during compilation. It uses
|
||||
those values to create a `Makefile' in each directory of the package.
|
||||
It may also create one or more `.h' files containing system-dependent
|
||||
definitions. Finally, it creates a shell script `config.status' that
|
||||
you can run in the future to recreate the current configuration, and a
|
||||
file `config.log' containing compiler output (useful mainly for
|
||||
debugging `configure').
|
||||
|
||||
It can also use an optional file (typically called `config.cache'
|
||||
and enabled with `--cache-file=config.cache' or simply `-C') that saves
|
||||
the results of its tests to speed up reconfiguring. Caching is
|
||||
disabled by default to prevent problems with accidental use of stale
|
||||
cache files.
|
||||
|
||||
If you need to do unusual things to compile the package, please try
|
||||
to figure out how `configure' could check whether to do them, and mail
|
||||
diffs or instructions to the address given in the `README' so they can
|
||||
be considered for the next release. If you are using the cache, and at
|
||||
some point `config.cache' contains results you don't want to keep, you
|
||||
may remove or edit it.
|
||||
|
||||
The file `configure.ac' (or `configure.in') is used to create
|
||||
`configure' by a program called `autoconf'. You need `configure.ac' if
|
||||
you want to change it or regenerate `configure' using a newer version
|
||||
of `autoconf'.
|
||||
|
||||
The simplest way to compile this package is:
|
||||
|
||||
1. `cd' to the directory containing the package's source code and type
|
||||
`./configure' to configure the package for your system.
|
||||
|
||||
Running `configure' might take a while. While running, it prints
|
||||
some messages telling which features it is checking for.
|
||||
|
||||
2. Type `make' to compile the package.
|
||||
|
||||
3. Optionally, type `make check' to run any self-tests that come with
|
||||
the package.
|
||||
|
||||
4. Type `make install' to install the programs and any data files and
|
||||
documentation.
|
||||
|
||||
5. You can remove the program binaries and object files from the
|
||||
source code directory by typing `make clean'. To also remove the
|
||||
files that `configure' created (so you can compile the package for
|
||||
a different kind of computer), type `make distclean'. There is
|
||||
also a `make maintainer-clean' target, but that is intended mainly
|
||||
for the package's developers. If you use it, you may have to get
|
||||
all sorts of other programs in order to regenerate files that came
|
||||
with the distribution.
|
||||
|
||||
Compilers and Options
|
||||
=====================
|
||||
|
||||
Some systems require unusual options for compilation or linking that the
|
||||
`configure' script does not know about. Run `./configure --help' for
|
||||
details on some of the pertinent environment variables.
|
||||
|
||||
You can give `configure' initial values for configuration parameters
|
||||
by setting variables in the command line or in the environment. Here
|
||||
is an example:
|
||||
|
||||
./configure CC=c99 CFLAGS=-g LIBS=-lposix
|
||||
|
||||
*Note Defining Variables::, for more details.
|
||||
|
||||
Compiling For Multiple Architectures
|
||||
====================================
|
||||
|
||||
You can compile the package for more than one kind of computer at the
|
||||
same time, by placing the object files for each architecture in their
|
||||
own directory. To do this, you can use GNU `make'. `cd' to the
|
||||
directory where you want the object files and executables to go and run
|
||||
the `configure' script. `configure' automatically checks for the
|
||||
source code in the directory that `configure' is in and in `..'.
|
||||
|
||||
With a non-GNU `make', it is safer to compile the package for one
|
||||
architecture at a time in the source code directory. After you have
|
||||
installed the package for one architecture, use `make distclean' before
|
||||
reconfiguring for another architecture.
|
||||
|
||||
Installation Names
|
||||
==================
|
||||
|
||||
By default, `make install' installs the package's commands under
|
||||
`/usr/local/bin', include files under `/usr/local/include', etc. You
|
||||
can specify an installation prefix other than `/usr/local' by giving
|
||||
`configure' the option `--prefix=PREFIX'.
|
||||
|
||||
You can specify separate installation prefixes for
|
||||
architecture-specific files and architecture-independent files. If you
|
||||
pass the option `--exec-prefix=PREFIX' to `configure', the package uses
|
||||
PREFIX as the prefix for installing programs and libraries.
|
||||
Documentation and other data files still use the regular prefix.
|
||||
|
||||
In addition, if you use an unusual directory layout you can give
|
||||
options like `--bindir=DIR' to specify different values for particular
|
||||
kinds of files. Run `configure --help' for a list of the directories
|
||||
you can set and what kinds of files go in them.
|
||||
|
||||
If the package supports it, you can cause programs to be installed
|
||||
with an extra prefix or suffix on their names by giving `configure' the
|
||||
option `--program-prefix=PREFIX' or `--program-suffix=SUFFIX'.
|
||||
|
||||
Optional Features
|
||||
=================
|
||||
|
||||
Some packages pay attention to `--enable-FEATURE' options to
|
||||
`configure', where FEATURE indicates an optional part of the package.
|
||||
They may also pay attention to `--with-PACKAGE' options, where PACKAGE
|
||||
is something like `gnu-as' or `x' (for the X Window System). The
|
||||
`README' should mention any `--enable-' and `--with-' options that the
|
||||
package recognizes.
|
||||
|
||||
For packages that use the X Window System, `configure' can usually
|
||||
find the X include and library files automatically, but if it doesn't,
|
||||
you can use the `configure' options `--x-includes=DIR' and
|
||||
`--x-libraries=DIR' to specify their locations.
|
||||
|
||||
Specifying the System Type
|
||||
==========================
|
||||
|
||||
There may be some features `configure' cannot figure out automatically,
|
||||
but needs to determine by the type of machine the package will run on.
|
||||
Usually, assuming the package is built to be run on the _same_
|
||||
architectures, `configure' can figure that out, but if it prints a
|
||||
message saying it cannot guess the machine type, give it the
|
||||
`--build=TYPE' option. TYPE can either be a short name for the system
|
||||
type, such as `sun4', or a canonical name which has the form:
|
||||
|
||||
CPU-COMPANY-SYSTEM
|
||||
|
||||
where SYSTEM can have one of these forms:
|
||||
|
||||
OS KERNEL-OS
|
||||
|
||||
See the file `config.sub' for the possible values of each field. If
|
||||
`config.sub' isn't included in this package, then this package doesn't
|
||||
need to know the machine type.
|
||||
|
||||
If you are _building_ compiler tools for cross-compiling, you should
|
||||
use the option `--target=TYPE' to select the type of system they will
|
||||
produce code for.
|
||||
|
||||
If you want to _use_ a cross compiler, that generates code for a
|
||||
platform different from the build platform, you should specify the
|
||||
"host" platform (i.e., that on which the generated programs will
|
||||
eventually be run) with `--host=TYPE'.
|
||||
|
||||
Sharing Defaults
|
||||
================
|
||||
|
||||
If you want to set default values for `configure' scripts to share, you
|
||||
can create a site shell script called `config.site' that gives default
|
||||
values for variables like `CC', `cache_file', and `prefix'.
|
||||
`configure' looks for `PREFIX/share/config.site' if it exists, then
|
||||
`PREFIX/etc/config.site' if it exists. Or, you can set the
|
||||
`CONFIG_SITE' environment variable to the location of the site script.
|
||||
A warning: not all `configure' scripts look for a site script.
|
||||
|
||||
Defining Variables
|
||||
==================
|
||||
|
||||
Variables not defined in a site shell script can be set in the
|
||||
environment passed to `configure'. However, some packages may run
|
||||
configure again during the build, and the customized values of these
|
||||
variables may be lost. In order to avoid this problem, you should set
|
||||
them in the `configure' command line, using `VAR=value'. For example:
|
||||
|
||||
./configure CC=/usr/local2/bin/gcc
|
||||
|
||||
causes the specified `gcc' to be used as the C compiler (unless it is
|
||||
overridden in the site shell script).
|
||||
|
||||
Unfortunately, this technique does not work for `CONFIG_SHELL' due to
|
||||
an Autoconf bug. Until the bug is fixed you can use this workaround:
|
||||
|
||||
CONFIG_SHELL=/bin/bash /bin/bash ./configure CONFIG_SHELL=/bin/bash
|
||||
|
||||
`configure' Invocation
|
||||
======================
|
||||
|
||||
`configure' recognizes the following options to control how it operates.
|
||||
|
||||
`--help'
|
||||
`-h'
|
||||
Print a summary of the options to `configure', and exit.
|
||||
|
||||
`--version'
|
||||
`-V'
|
||||
Print the version of Autoconf used to generate the `configure'
|
||||
script, and exit.
|
||||
|
||||
`--cache-file=FILE'
|
||||
Enable the cache: use and save the results of the tests in FILE,
|
||||
traditionally `config.cache'. FILE defaults to `/dev/null' to
|
||||
disable caching.
|
||||
|
||||
`--config-cache'
|
||||
`-C'
|
||||
Alias for `--cache-file=config.cache'.
|
||||
|
||||
`--quiet'
|
||||
`--silent'
|
||||
`-q'
|
||||
Do not print messages saying which checks are being made. To
|
||||
suppress all normal output, redirect it to `/dev/null' (any error
|
||||
messages will still be shown).
|
||||
|
||||
`--srcdir=DIR'
|
||||
Look for the package's source code in directory DIR. Usually
|
||||
`configure' can determine that directory automatically.
|
||||
|
||||
`configure' also accepts some other, not widely useful, options. Run
|
||||
`configure --help' for more details.
|
||||
|
||||
121
src/3rdParty/libkdtree/README
vendored
Normal file
121
src/3rdParty/libkdtree/README
vendored
Normal file
@@ -0,0 +1,121 @@
|
||||
libkdtree++ README
|
||||
==================
|
||||
|
||||
libkdtree++ is (c) 2004-2007 Martin F. Krafft <libkdtree@pobox.madduck.net>
|
||||
and distributed under the terms of the Artistic License 2.0.
|
||||
See the file LICENSE in the source distribution for more information.
|
||||
|
||||
Please send bugreports to <libkdtree-devel@lists.alioth.debian.org>.
|
||||
|
||||
Introduction
|
||||
------------
|
||||
|
||||
libkdtree++ is a C++ template container implementation of k-dimensional space
|
||||
sorting, using a kd-tree. It:
|
||||
|
||||
- sports an unlimited number of dimensions (in theory)
|
||||
- can store any data structure, access and comparison between the
|
||||
individual dimensional components defaults to the bracket operator, in
|
||||
the range [0, k-1] and the std::less functor by default, but other
|
||||
accessors and comparator can be defined.
|
||||
- has support for custom allocators
|
||||
- implements iterators
|
||||
- provides standard find as well as range queries
|
||||
- has amortised O(lg n) time (O(n lg n) worst case) on most
|
||||
operations (insert/erase/find optimised) and worst-case O(n) space.
|
||||
- provides a means to rebalance and thus optimise the tree.
|
||||
- exists in its own namespace
|
||||
- uses STL coding style, basing a lot of the code on stl_tree.h
|
||||
|
||||
Notes
|
||||
-----
|
||||
|
||||
Note that the library is not (yet) complete and it's not thoroughly tested.
|
||||
However, given the effort and grief I went through in writing it, I would
|
||||
like to make it available to folks, get people to test it, and hopefully have
|
||||
some peeps submit improvements. If you have any suggestions, please write to
|
||||
libkdtree-devel@lists.alioth.debian.org .
|
||||
|
||||
It's not yet documented, although the usage should be fairly straight
|
||||
forward. I am hoping to find someone else to document it as I suck at
|
||||
documentation and as the author, it's exceptionally difficult to stay
|
||||
didactically correct.
|
||||
|
||||
Credits (Martin F. Kraft)
|
||||
-------------------------
|
||||
|
||||
While the library was written all by myself, it would not have been possible
|
||||
without the help of a number of people. Foremost, I would like to thank the
|
||||
folks from the #c++ channel on Freenode, specifically (in no particular order)
|
||||
orbitz, quix, Erwin, pwned, wcstok, dasOp, Chaku, Adrinael, The_Vulture, and
|
||||
LIM2 (if I left anyone out, let me know). Finally, I thank the Artificial
|
||||
Intelligence Laboratory of the University of Zurich, Dr. Peter Eggenberger and
|
||||
Gabriel Gómez for giving me the opportunity to write this stuff.
|
||||
|
||||
Since libkdtree++ makes an effort to stay as close as possible to the feel of
|
||||
a STL container, concepts and inspiration was gained from the SGI C++
|
||||
implementation of red-black trees (stl_tree.h).
|
||||
|
||||
I also have to thank the Debian project for providing an amazingly reliable
|
||||
and flexible developer station with their operating system. I am sorry for
|
||||
everyone who has to use something else.
|
||||
|
||||
Installation
|
||||
------------
|
||||
|
||||
As there is no need to compile any files, you can just:
|
||||
|
||||
$ ./configure
|
||||
$ sudo make install
|
||||
|
||||
|
||||
It now also supports cmake, which can be used to build the examples
|
||||
and tests.
|
||||
To build with cmake, do an out-of-source build like so:
|
||||
|
||||
# ASSUMING you have decompressed it into a directory called libkdtree,
|
||||
# and you are currently in that directory...
|
||||
|
||||
$ cd .. # go up, out of the kdtree source directory
|
||||
$ mkdir build
|
||||
$ cd build
|
||||
$ cmake ../libkdtree
|
||||
$ make
|
||||
|
||||
|
||||
You can use cmake to build the tests and examples on Windows with
|
||||
Visual C++. Use the windows cmake to create a Visual C++ solution and
|
||||
build that.
|
||||
|
||||
Note that cmake and ./configure is not needed at all in order to use
|
||||
kdtree in your application. As kdtree is a header-only library, you
|
||||
just need to #include the kdtree.hpp
|
||||
|
||||
|
||||
Read the following to make use of the library.
|
||||
|
||||
Usage
|
||||
-----
|
||||
|
||||
A simple example program is provided in the ./examples directory
|
||||
(/usr/share/doc/libkdtree++-dev/examples on Debian).
|
||||
|
||||
For those using the ./configure system, the library supports pkg-config.
|
||||
Thus, to compile with the library,
|
||||
|
||||
#include <kdtree++/kdtree.hpp>
|
||||
|
||||
and append the output of `pkg-config libkdtree++ --cflags` to your $CPPFLAGS.
|
||||
|
||||
Each call to erase() and insert() unbalances the tree. It is possible that
|
||||
nodes will not be found while the tree is unbalanced. You rebalance the
|
||||
tree by calling optimize(), and you should call it before you need to search
|
||||
the tree (this includes erase(value) calls, which search the tree).
|
||||
|
||||
It is ok to call insert(value) many times and optimize() at the end, but
|
||||
every erase() call should be followed with optimize().
|
||||
|
||||
These notes are a bit out of date, please check the webpage and mailing list
|
||||
for more info. Documentation is on the TODO list.
|
||||
|
||||
Have fun.
|
||||
12
src/3rdParty/libkdtree/README.Python
vendored
Normal file
12
src/3rdParty/libkdtree/README.Python
vendored
Normal file
@@ -0,0 +1,12 @@
|
||||
Stand-alone Python bindings, contributed by Willi Richert <w.richert@gmx.net>
|
||||
|
||||
To make them:
|
||||
$ cd python-bindings
|
||||
$ make
|
||||
You will find then two files kdtree.py _kdtree.so in the current directory.
|
||||
These are all you need to use libkdtree++.
|
||||
Please examine the test files to get a grip to the usage.
|
||||
|
||||
To run the tests, type:
|
||||
python py-kdtree_test.py
|
||||
|
||||
3
src/3rdParty/libkdtree/examples/CMakeLists.txt
vendored
Normal file
3
src/3rdParty/libkdtree/examples/CMakeLists.txt
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
add_executable (test_hayne test_hayne.cpp)
|
||||
add_executable (test_kdtree test_kdtree.cpp)
|
||||
add_executable (test_find_within_range test_find_within_range.cpp)
|
||||
108
src/3rdParty/libkdtree/examples/test_find_within_range.cpp
vendored
Normal file
108
src/3rdParty/libkdtree/examples/test_find_within_range.cpp
vendored
Normal file
@@ -0,0 +1,108 @@
|
||||
// Thanks to James Remillard
|
||||
//
|
||||
#include <cstdio>
|
||||
#include <kdtree++/kdtree.hpp>
|
||||
#include <vector>
|
||||
#include <map>
|
||||
#include <set>
|
||||
|
||||
using namespace std;
|
||||
|
||||
struct kdtreeNode
|
||||
{
|
||||
typedef double value_type;
|
||||
|
||||
double xyz[3];
|
||||
size_t index;
|
||||
|
||||
value_type operator[](size_t n) const
|
||||
{
|
||||
return xyz[n];
|
||||
}
|
||||
|
||||
double distance( const kdtreeNode &node)
|
||||
{
|
||||
double x = xyz[0] - node.xyz[0];
|
||||
double y = xyz[1] - node.xyz[1];
|
||||
double z = xyz[2] - node.xyz[2];
|
||||
|
||||
// this is not correct return sqrt( x*x+y*y+z*z);
|
||||
|
||||
// this is what kdtree checks with find_within_range()
|
||||
// the "manhattan distance" from the search point.
|
||||
// effectively, distance is the maximum distance in any one dimension.
|
||||
return max(fabs(x),max(fabs(y),fabs(z)));
|
||||
|
||||
}
|
||||
};
|
||||
|
||||
int main(int argc,char *argv[])
|
||||
{
|
||||
vector<kdtreeNode> pts;
|
||||
|
||||
typedef KDTree::KDTree<3,kdtreeNode> treeType;
|
||||
|
||||
treeType tree;
|
||||
|
||||
// make random 3d points
|
||||
for ( size_t n = 0; n < 10000; ++n)
|
||||
{
|
||||
kdtreeNode node;
|
||||
node.xyz[0] = double(rand())/RAND_MAX;
|
||||
node.xyz[1] = double(rand())/RAND_MAX;
|
||||
node.xyz[2] = double(rand())/RAND_MAX;
|
||||
node.index = n;
|
||||
|
||||
tree.insert( node);
|
||||
pts.push_back( node);
|
||||
}
|
||||
|
||||
for (size_t r = 0; r < 1000; ++r)
|
||||
{
|
||||
kdtreeNode refNode;
|
||||
refNode.xyz[0] = double(rand())/RAND_MAX;
|
||||
refNode.xyz[1] = double(rand())/RAND_MAX;
|
||||
refNode.xyz[2] = double(rand())/RAND_MAX;
|
||||
|
||||
double limit = double(rand())/RAND_MAX;
|
||||
|
||||
// find the correct return list by checking every single point
|
||||
set<size_t> correctCloseList;
|
||||
|
||||
for ( size_t i= 0; i < pts.size(); ++i)
|
||||
{
|
||||
double dist = refNode.distance( pts[i]);
|
||||
if ( dist < limit)
|
||||
correctCloseList.insert( i );
|
||||
}
|
||||
|
||||
// now do the same with the kdtree.
|
||||
vector<kdtreeNode> howClose;
|
||||
tree.find_within_range(refNode,limit,back_insert_iterator<vector<kdtreeNode> >(howClose));
|
||||
|
||||
// make sure no extra points are returned, and the return has no missing points.
|
||||
for ( size_t i = 0; i < howClose.size(); ++i)
|
||||
{
|
||||
set<size_t>::iterator hit = correctCloseList.find( howClose[i].index);
|
||||
|
||||
if ( hit != correctCloseList.end())
|
||||
{
|
||||
correctCloseList.erase(hit);
|
||||
}
|
||||
else
|
||||
{
|
||||
// point that is too far away - fail!
|
||||
assert(false);
|
||||
printf("fail, extra points.\n");
|
||||
}
|
||||
}
|
||||
|
||||
// fail, not all of the close enough points returned.
|
||||
assert( correctCloseList.size() == 0);
|
||||
if ( correctCloseList.size() > 0)
|
||||
{
|
||||
printf("fail, missing points.\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
116
src/3rdParty/libkdtree/examples/test_hayne.cpp
vendored
Normal file
116
src/3rdParty/libkdtree/examples/test_hayne.cpp
vendored
Normal file
@@ -0,0 +1,116 @@
|
||||
#define KDTREE_SIZE_T unsigned int
|
||||
#include <kdtree++/kdtree.hpp>
|
||||
|
||||
#include <vector>
|
||||
#include <limits>
|
||||
#include <iostream>
|
||||
#include <functional>
|
||||
|
||||
using namespace std;
|
||||
|
||||
struct duplet
|
||||
{
|
||||
typedef int value_type;
|
||||
|
||||
inline value_type operator[](int const N) const { return d[N]; }
|
||||
|
||||
inline bool operator==(duplet const& other) const
|
||||
{
|
||||
return this->d[0] == other.d[0] && this->d[1] == other.d[1];
|
||||
}
|
||||
|
||||
inline bool operator!=(duplet const& other) const
|
||||
{
|
||||
return this->d[0] != other.d[0] || this->d[1] != other.d[1];
|
||||
}
|
||||
|
||||
friend ostream & operator<<(ostream & o, duplet const& d)
|
||||
{
|
||||
return o << "(" << d[0] << "," << d[1] << ")";
|
||||
}
|
||||
|
||||
value_type d[2];
|
||||
};
|
||||
|
||||
typedef KDTree::KDTree<2, duplet, std::pointer_to_binary_function<duplet,int,double> > duplet_tree_type;
|
||||
|
||||
inline double return_dup( duplet d, int k ) { return d[k]; }
|
||||
|
||||
|
||||
|
||||
int main()
|
||||
{
|
||||
duplet_tree_type dupl_tree_test(std::ptr_fun(return_dup));
|
||||
std::vector<duplet> vDuplets;
|
||||
|
||||
//srand(time(0));
|
||||
int randy1 = 0;
|
||||
int randy2 = 0;
|
||||
for (int i=0; i<700; i++)
|
||||
{
|
||||
//create coordinate for new duplet
|
||||
randy1+=2;
|
||||
randy1=randy1%255;
|
||||
randy2+=3;
|
||||
randy2=randy2%255;
|
||||
//randy1 = rand() % 255;
|
||||
//randy2 = rand() % 255;
|
||||
|
||||
//new duplet
|
||||
duplet super_dupre = { {randy1, randy2} };
|
||||
|
||||
//check if duplet with same coordinate already in vector/tree. If not: insert in vector and tree
|
||||
duplet_tree_type::iterator pItr = dupl_tree_test.find_nearest(super_dupre,std::numeric_limits<double>::max()).first;
|
||||
if (*pItr!=super_dupre)
|
||||
{
|
||||
dupl_tree_test.insert(super_dupre);
|
||||
vDuplets.push_back(super_dupre);
|
||||
}
|
||||
}
|
||||
|
||||
dupl_tree_test.optimise();
|
||||
|
||||
size_t elements;
|
||||
|
||||
while (vDuplets.size() > 0) //delete all duplets from tree which are in the vector
|
||||
{
|
||||
elements = vDuplets.size();
|
||||
|
||||
duplet element_to_erase = vDuplets.back();
|
||||
vDuplets.pop_back();
|
||||
|
||||
if (vDuplets.size() == 147)
|
||||
cout << "THIS IS THE BUG TRIGGER" << endl;
|
||||
|
||||
cout << vDuplets.size() << " : Deleting " << element_to_erase << endl;
|
||||
|
||||
assert( find(dupl_tree_test.begin(),dupl_tree_test.end(), element_to_erase) != dupl_tree_test.end() );
|
||||
assert(dupl_tree_test.find(element_to_erase) != dupl_tree_test.end());
|
||||
|
||||
duplet_tree_type::iterator will = dupl_tree_test.find(element_to_erase);
|
||||
duplet_tree_type::iterator should = dupl_tree_test.find_exact(element_to_erase);
|
||||
|
||||
cout << " tree will delete: " << *will << endl;
|
||||
cout << " tree should delete: " << *should << endl;
|
||||
|
||||
assert(*will == *should);
|
||||
|
||||
dupl_tree_test.erase(element_to_erase); //erase() : will probably erase wrong element sooner or later
|
||||
//dupl_tree_test.erase_exact(element_to_erase); --> this works
|
||||
|
||||
// now check that it cannot find the element UNLESS there is another one with the identical location in the list...
|
||||
if (find(vDuplets.begin(),vDuplets.end(),element_to_erase) == vDuplets.end())
|
||||
{
|
||||
duplet_tree_type::iterator not_there = dupl_tree_test.find(element_to_erase);
|
||||
if (not_there != dupl_tree_test.end())
|
||||
{
|
||||
cout << "SHOULD NOT HAVE FOUND THIS: " << *not_there << endl;
|
||||
assert(0);
|
||||
}
|
||||
else
|
||||
{
|
||||
cout << " find() double-check passed." << endl;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
423
src/3rdParty/libkdtree/examples/test_kdtree.cpp
vendored
Normal file
423
src/3rdParty/libkdtree/examples/test_kdtree.cpp
vendored
Normal file
@@ -0,0 +1,423 @@
|
||||
#define KDTREE_DEFINE_OSTREAM_OPERATORS
|
||||
|
||||
// Make SURE all our asserts() are checked
|
||||
#undef NDEBUG
|
||||
|
||||
#include <kdtree++/kdtree.hpp>
|
||||
|
||||
#include <deque>
|
||||
#include <iostream>
|
||||
#include <vector>
|
||||
#include <limits>
|
||||
#include <functional>
|
||||
#include <set>
|
||||
|
||||
// used to ensure all triplets that are accessed via the operator<< are initialised.
|
||||
std::set<const void*> registered;
|
||||
|
||||
struct triplet
|
||||
{
|
||||
typedef int value_type;
|
||||
|
||||
triplet(value_type a, value_type b, value_type c)
|
||||
{
|
||||
d[0] = a;
|
||||
d[1] = b;
|
||||
d[2] = c;
|
||||
bool reg_ok = (registered.find(this) == registered.end());
|
||||
assert(reg_ok);
|
||||
registered.insert(this).second;
|
||||
}
|
||||
|
||||
triplet(const triplet & x)
|
||||
{
|
||||
d[0] = x.d[0];
|
||||
d[1] = x.d[1];
|
||||
d[2] = x.d[2];
|
||||
bool reg_ok = (registered.find(this) == registered.end());
|
||||
assert(reg_ok);
|
||||
registered.insert(this).second;
|
||||
}
|
||||
|
||||
~triplet()
|
||||
{
|
||||
bool unreg_ok = (registered.find(this) != registered.end());
|
||||
assert(unreg_ok);
|
||||
registered.erase(this);
|
||||
}
|
||||
|
||||
double distance_to(triplet const& x) const
|
||||
{
|
||||
double dist = 0;
|
||||
for (int i = 0; i != 3; ++i)
|
||||
dist += (d[i]-x.d[i])*(d[i]-x.d[i]);
|
||||
return std::sqrt(dist);
|
||||
}
|
||||
|
||||
inline value_type operator[](size_t const N) const { return d[N]; }
|
||||
|
||||
value_type d[3];
|
||||
};
|
||||
|
||||
|
||||
|
||||
// same as triplet, except with the values reversed.
|
||||
struct alternate_triplet
|
||||
{
|
||||
typedef int value_type;
|
||||
|
||||
alternate_triplet(const triplet & x)
|
||||
{
|
||||
d[0] = x.d[2];
|
||||
d[1] = x.d[1];
|
||||
d[2] = x.d[0];
|
||||
}
|
||||
|
||||
inline value_type operator[](size_t const N) const { return d[2-N]; }
|
||||
|
||||
value_type d[3];
|
||||
};
|
||||
|
||||
inline bool operator==(triplet const& A, triplet const& B) {
|
||||
return A.d[0] == B.d[0] && A.d[1] == B.d[1] && A.d[2] == B.d[2];
|
||||
}
|
||||
|
||||
std::ostream& operator<<(std::ostream& out, triplet const& T)
|
||||
{
|
||||
assert(registered.find(&T) != registered.end());
|
||||
return out << '(' << T.d[0] << ',' << T.d[1] << ',' << T.d[2] << ')';
|
||||
}
|
||||
|
||||
inline double tac( triplet t, size_t k ) { return t[k]; }
|
||||
|
||||
// use tac as a class instead of a function,
|
||||
// can access more than one type with just 1 definition.
|
||||
struct alternate_tac
|
||||
{
|
||||
typedef double result_type;
|
||||
double operator()( triplet const& t, size_t k ) const { return t[k]; }
|
||||
double operator()( alternate_triplet const& t, size_t k ) const { return t[k]; }
|
||||
};
|
||||
|
||||
|
||||
typedef KDTree::KDTree<3, triplet, std::pointer_to_binary_function<triplet,size_t,double> > tree_type;
|
||||
|
||||
struct Predicate
|
||||
{
|
||||
bool operator()( triplet const& t ) const
|
||||
{
|
||||
return t[0] > 3; // anything, we are currently testing that it compiles.
|
||||
}
|
||||
};
|
||||
|
||||
// never finds anything
|
||||
struct FalsePredicate
|
||||
{
|
||||
bool operator()( triplet const& t ) const { return false; }
|
||||
};
|
||||
|
||||
int main()
|
||||
{
|
||||
// check that it'll find nodes exactly MAX away
|
||||
{
|
||||
tree_type exact_dist(std::ptr_fun(tac));
|
||||
triplet c0(5, 4, 0);
|
||||
exact_dist.insert(c0);
|
||||
triplet target(7,4,0);
|
||||
|
||||
std::pair<tree_type::const_iterator,double> found = exact_dist.find_nearest(target,2);
|
||||
assert(found.first != exact_dist.end());
|
||||
assert(found.second == 2);
|
||||
std::cout << "Test find_nearest(), found at exact distance away from " << target << ", found " << *found.first << std::endl;
|
||||
}
|
||||
|
||||
// do the same test, except use alternate_triplet as the search key
|
||||
{
|
||||
// NOTE: stores triplet, but we search with alternate_triplet
|
||||
typedef KDTree::KDTree<3, triplet, alternate_tac> alt_tree;
|
||||
|
||||
triplet actual_target(7,0,0);
|
||||
|
||||
alt_tree tree;
|
||||
tree.insert( triplet(0, 0, 7) );
|
||||
tree.insert( triplet(0, 0, 7) );
|
||||
tree.insert( triplet(0, 0, 7) );
|
||||
tree.insert( triplet(3, 0, 0) );
|
||||
tree.insert( actual_target );
|
||||
tree.optimise();
|
||||
|
||||
alternate_triplet target( actual_target );
|
||||
|
||||
std::pair<alt_tree::const_iterator,double> found = tree.find_nearest(target);
|
||||
assert(found.first != tree.end());
|
||||
std::cout << "Test with alternate search type, found: " << *found.first << ", wanted " << actual_target << std::endl;
|
||||
assert(found.second == 0);
|
||||
assert(*found.first == actual_target);
|
||||
}
|
||||
|
||||
|
||||
{
|
||||
tree_type exact_dist(std::ptr_fun(tac));
|
||||
triplet c0(5, 2, 0);
|
||||
exact_dist.insert(c0);
|
||||
triplet target(7,4,0);
|
||||
|
||||
// call find_nearest without a range value - it found a compile error earlier.
|
||||
std::pair<tree_type::const_iterator,double> found = exact_dist.find_nearest(target);
|
||||
assert(found.first != exact_dist.end());
|
||||
std::cout << "Test find_nearest(), found at exact distance away from " << target << ", found " << *found.first << " @ " << found.second << " should be " << std::sqrt(8) << std::endl;
|
||||
assert(found.second == std::sqrt(8));
|
||||
}
|
||||
|
||||
{
|
||||
tree_type exact_dist(std::ptr_fun(tac));
|
||||
triplet c0(5, 2, 0);
|
||||
exact_dist.insert(c0);
|
||||
triplet target(7,4,0);
|
||||
|
||||
std::pair<tree_type::const_iterator,double> found = exact_dist.find_nearest(target,std::sqrt(8));
|
||||
assert(found.first != exact_dist.end());
|
||||
std::cout << "Test find_nearest(), found at exact distance away from " << target << ", found " << *found.first << " @ " << found.second << " should be " << std::sqrt(8) << std::endl;
|
||||
assert(found.second == std::sqrt(8));
|
||||
}
|
||||
|
||||
tree_type src(std::ptr_fun(tac));
|
||||
|
||||
triplet c0(5, 4, 0); src.insert(c0);
|
||||
triplet c1(4, 2, 1); src.insert(c1);
|
||||
triplet c2(7, 6, 9); src.insert(c2);
|
||||
triplet c3(2, 2, 1); src.insert(c3);
|
||||
triplet c4(8, 0, 5); src.insert(c4);
|
||||
triplet c5(5, 7, 0); src.insert(c5);
|
||||
triplet c6(3, 3, 8); src.insert(c6);
|
||||
triplet c7(9, 7, 3); src.insert(c7);
|
||||
triplet c8(2, 2, 6); src.insert(c8);
|
||||
triplet c9(2, 0, 6); src.insert(c9);
|
||||
|
||||
std::cout << src << std::endl;
|
||||
|
||||
src.erase(c0);
|
||||
src.erase(c1);
|
||||
src.erase(c3);
|
||||
src.erase(c5);
|
||||
|
||||
src.optimise();
|
||||
|
||||
|
||||
// test the efficient_replace_and_optimise()
|
||||
tree_type eff_repl = src;
|
||||
{
|
||||
std::vector<triplet> vec;
|
||||
// erased above as part of test vec.push_back(triplet(5, 4, 0));
|
||||
// erased above as part of test vec.push_back(triplet(4, 2, 1));
|
||||
vec.push_back(triplet(7, 6, 9));
|
||||
// erased above as part of test vec.push_back(triplet(2, 2, 1));
|
||||
vec.push_back(triplet(8, 0, 5));
|
||||
// erased above as part of test vec.push_back(triplet(5, 7, 0));
|
||||
vec.push_back(triplet(3, 3, 8));
|
||||
vec.push_back(triplet(9, 7, 3));
|
||||
vec.push_back(triplet(2, 2, 6));
|
||||
vec.push_back(triplet(2, 0, 6));
|
||||
|
||||
eff_repl.clear();
|
||||
eff_repl.efficient_replace_and_optimise(vec);
|
||||
}
|
||||
|
||||
|
||||
std::cout << std::endl << src << std::endl;
|
||||
|
||||
tree_type copied(src);
|
||||
std::cout << copied << std::endl;
|
||||
tree_type assigned;
|
||||
assigned = src;
|
||||
std::cout << assigned << std::endl;
|
||||
|
||||
for (int loop = 0; loop != 4; ++loop)
|
||||
{
|
||||
tree_type * target;
|
||||
switch (loop)
|
||||
{
|
||||
case 0: std::cout << "Testing plain construction" << std::endl;
|
||||
target = &src;
|
||||
break;
|
||||
|
||||
case 1: std::cout << "Testing copy-construction" << std::endl;
|
||||
target = &copied;
|
||||
break;
|
||||
|
||||
case 2: std::cout << "Testing assign-construction" << std::endl;
|
||||
target = &assigned;
|
||||
break;
|
||||
|
||||
default:
|
||||
case 4: std::cout << "Testing efficient-replace-and-optimise" << std::endl;
|
||||
target = &eff_repl;
|
||||
break;
|
||||
}
|
||||
tree_type & t = *target;
|
||||
|
||||
int i=0;
|
||||
for (tree_type::const_iterator iter=t.begin(); iter!=t.end(); ++iter, ++i);
|
||||
std::cout << "iterator walked through " << i << " nodes in total" << std::endl;
|
||||
if (i!=6)
|
||||
{
|
||||
std::cerr << "Error: does not tally with the expected number of nodes (6)" << std::endl;
|
||||
return 1;
|
||||
}
|
||||
i=0;
|
||||
for (tree_type::const_reverse_iterator iter=t.rbegin(); iter!=t.rend(); ++iter, ++i);
|
||||
std::cout << "reverse_iterator walked through " << i << " nodes in total" << std::endl;
|
||||
if (i!=6)
|
||||
{
|
||||
std::cerr << "Error: does not tally with the expected number of nodes (6)" << std::endl;
|
||||
return 1;
|
||||
}
|
||||
|
||||
triplet s(5, 4, 3);
|
||||
std::vector<triplet> v;
|
||||
unsigned int const RANGE = 3;
|
||||
|
||||
size_t count = t.count_within_range(s, RANGE);
|
||||
std::cout << "counted " << count
|
||||
<< " nodes within range " << RANGE << " of " << s << ".\n";
|
||||
t.find_within_range(s, RANGE, std::back_inserter(v));
|
||||
|
||||
std::cout << "found " << v.size() << " nodes within range " << RANGE
|
||||
<< " of " << s << ":\n";
|
||||
std::vector<triplet>::const_iterator ci = v.begin();
|
||||
for (; ci != v.end(); ++ci)
|
||||
std::cout << *ci << " ";
|
||||
std::cout << "\n" << std::endl;
|
||||
|
||||
std::cout << std::endl << t << std::endl;
|
||||
|
||||
// search for all the nodes at exactly 0 dist away
|
||||
for (tree_type::const_iterator target = t.begin(); target != t.end(); ++target)
|
||||
{
|
||||
std::pair<tree_type::const_iterator,double> found = t.find_nearest(*target,0);
|
||||
assert(found.first != t.end());
|
||||
assert(*found.first == *target);
|
||||
std::cout << "Test find_nearest(), found at exact distance away from " << *target << ", found " << *found.first << std::endl;
|
||||
}
|
||||
|
||||
{
|
||||
const double small_dist = 0.0001;
|
||||
std::pair<tree_type::const_iterator,double> notfound = t.find_nearest(s,small_dist);
|
||||
std::cout << "Test find_nearest(), nearest to " << s << " within " << small_dist << " should not be found" << std::endl;
|
||||
|
||||
if (notfound.first != t.end())
|
||||
{
|
||||
std::cout << "ERROR found a node at dist " << notfound.second << " : " << *notfound.first << std::endl;
|
||||
std::cout << "Actual distance = " << s.distance_to(*notfound.first) << std::endl;
|
||||
}
|
||||
|
||||
assert(notfound.first == t.end());
|
||||
}
|
||||
|
||||
{
|
||||
std::pair<tree_type::const_iterator,double> nif = t.find_nearest_if(s,std::numeric_limits<double>::max(),Predicate());
|
||||
std::cout << "Test find_nearest_if(), nearest to " << s << " @ " << nif.second << ": " << *nif.first << std::endl;
|
||||
|
||||
std::pair<tree_type::const_iterator,double> cantfind = t.find_nearest_if(s,std::numeric_limits<double>::max(),FalsePredicate());
|
||||
std::cout << "Test find_nearest_if(), nearest to " << s << " should never be found (predicate too strong)" << std::endl;
|
||||
assert(cantfind.first == t.end());
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
{
|
||||
std::pair<tree_type::const_iterator,double> found = t.find_nearest(s,std::numeric_limits<double>::max());
|
||||
std::cout << "Nearest to " << s << " @ " << found.second << " " << *found.first << std::endl;
|
||||
std::cout << "Should be " << found.first->distance_to(s) << std::endl;
|
||||
// NOTE: the assert does not check for an exact match, as it is not exact when -O2 or -O3 is
|
||||
// switched on. Some sort of optimisation makes the math inexact.
|
||||
assert( fabs(found.second - found.first->distance_to(s)) < std::numeric_limits<double>::epsilon() );
|
||||
}
|
||||
|
||||
{
|
||||
triplet s2(10, 10, 2);
|
||||
std::pair<tree_type::const_iterator,double> found = t.find_nearest(s2,std::numeric_limits<double>::max());
|
||||
std::cout << "Nearest to " << s2 << " @ " << found.second << " " << *found.first << std::endl;
|
||||
std::cout << "Should be " << found.first->distance_to(s2) << std::endl;
|
||||
// NOTE: the assert does not check for an exact match, as it is not exact when -O2 or -O3 is
|
||||
// switched on. Some sort of optimisation makes the math inexact.
|
||||
assert( fabs(found.second - found.first->distance_to(s2)) < std::numeric_limits<double>::epsilon() );
|
||||
}
|
||||
|
||||
std::cout << std::endl;
|
||||
|
||||
std::cout << t << std::endl;
|
||||
|
||||
// Testing iterators
|
||||
{
|
||||
std::cout << "Testing iterators" << std::endl;
|
||||
|
||||
t.erase(c2);
|
||||
t.erase(c4);
|
||||
t.erase(c6);
|
||||
t.erase(c7);
|
||||
t.erase(c8);
|
||||
// t.erase(c9);
|
||||
|
||||
std::cout << std::endl << t << std::endl;
|
||||
|
||||
std::cout << "Forward iterator test..." << std::endl;
|
||||
std::vector<triplet> forwards;
|
||||
for (tree_type::iterator i = t.begin(); i != t.end(); ++i)
|
||||
{ std::cout << *i << " " << std::flush; forwards.push_back(*i); }
|
||||
std::cout << std::endl;
|
||||
std::cout << "Reverse iterator test..." << std::endl;
|
||||
std::vector<triplet> backwards;
|
||||
for (tree_type::reverse_iterator i = t.rbegin(); i != t.rend(); ++i)
|
||||
{ std::cout << *i << " " << std::flush; backwards.push_back(*i); }
|
||||
std::cout << std::endl;
|
||||
std::reverse(backwards.begin(),backwards.end());
|
||||
assert(backwards == forwards);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Walter reported that the find_within_range() wasn't giving results that were within
|
||||
// the specified range... this is the test.
|
||||
{
|
||||
tree_type tree(std::ptr_fun(tac));
|
||||
tree.insert( triplet(28.771200,16.921600,-2.665970) );
|
||||
tree.insert( triplet(28.553101,18.649700,-2.155560) );
|
||||
tree.insert( triplet(28.107500,20.341400,-1.188940) );
|
||||
tree.optimise();
|
||||
|
||||
std::deque< triplet > vectors;
|
||||
triplet sv(18.892500,20.341400,-1.188940);
|
||||
tree.find_within_range(sv, 10.0f, std::back_inserter(vectors));
|
||||
|
||||
std::cout << std::endl << "Test find_with_range( " << sv << ", 10.0f) found " << vectors.size() << " candidates." << std::endl;
|
||||
|
||||
// double-check the ranges
|
||||
for (std::deque<triplet>::iterator v = vectors.begin(); v != vectors.end(); ++v)
|
||||
{
|
||||
double dist = sv.distance_to(*v);
|
||||
std::cout << " " << *v << " dist=" << dist << std::endl;
|
||||
if (dist > 10.0f)
|
||||
std::cout << " This point is too far! But that is by design, its within a 'box' with a 'radius' of 10, not a sphere with a radius of 10" << std::endl;
|
||||
// Not a valid test, it can be greater than 10 if the point is in the corners of the box.
|
||||
// assert(dist <= 10.0f);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* COPYRIGHT --
|
||||
*
|
||||
* This file is part of libkdtree++, a C++ template KD-Tree sorting container.
|
||||
* libkdtree++ is (c) 2004-2007 Martin F. Krafft <libkdtree@pobox.madduck.net>
|
||||
* and Sylvain Bougerel <sylvain.bougerel.devel@gmail.com> distributed under the
|
||||
* terms of the Artistic License 2.0. See the ./COPYING file in the source tree
|
||||
* root for more information.
|
||||
*
|
||||
* THIS PACKAGE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED
|
||||
* WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES
|
||||
* OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
|
||||
*/
|
||||
96
src/3rdParty/libkdtree/kdtree++/allocator.hpp
vendored
Normal file
96
src/3rdParty/libkdtree/kdtree++/allocator.hpp
vendored
Normal file
@@ -0,0 +1,96 @@
|
||||
/** \file
|
||||
* Defines the allocator interface as used by the KDTree class.
|
||||
*
|
||||
* \author Martin F. Krafft <libkdtree@pobox.madduck.net>
|
||||
*/
|
||||
|
||||
#ifndef INCLUDE_KDTREE_ALLOCATOR_HPP
|
||||
#define INCLUDE_KDTREE_ALLOCATOR_HPP
|
||||
|
||||
#include <cstddef>
|
||||
|
||||
#include "node.hpp"
|
||||
|
||||
namespace KDTree
|
||||
{
|
||||
|
||||
template <typename _Tp, typename _Alloc>
|
||||
class _Alloc_base
|
||||
{
|
||||
public:
|
||||
typedef _Node<_Tp> _Node_;
|
||||
typedef typename _Node_::_Base_ptr _Base_ptr;
|
||||
typedef _Alloc allocator_type;
|
||||
|
||||
_Alloc_base(allocator_type const& __A)
|
||||
: _M_node_allocator(__A) {}
|
||||
|
||||
allocator_type
|
||||
get_allocator() const
|
||||
{
|
||||
return _M_node_allocator;
|
||||
}
|
||||
|
||||
|
||||
class NoLeakAlloc
|
||||
{
|
||||
_Alloc_base * base;
|
||||
_Node_ * new_node;
|
||||
|
||||
public:
|
||||
NoLeakAlloc(_Alloc_base * b) : base(b), new_node(base->_M_allocate_node()) {}
|
||||
|
||||
_Node_ * get() { return new_node; }
|
||||
void disconnect() { new_node = NULL; }
|
||||
|
||||
~NoLeakAlloc() { if (new_node) base->_M_deallocate_node(new_node); }
|
||||
};
|
||||
|
||||
|
||||
protected:
|
||||
allocator_type _M_node_allocator;
|
||||
|
||||
_Node_*
|
||||
_M_allocate_node()
|
||||
{
|
||||
return _M_node_allocator.allocate(1);
|
||||
}
|
||||
|
||||
void
|
||||
_M_deallocate_node(_Node_* const __P)
|
||||
{
|
||||
return _M_node_allocator.deallocate(__P, 1);
|
||||
}
|
||||
|
||||
void
|
||||
_M_construct_node(_Node_* __p, _Tp const __V = _Tp(),
|
||||
_Base_ptr const __PARENT = NULL,
|
||||
_Base_ptr const __LEFT = NULL,
|
||||
_Base_ptr const __RIGHT = NULL)
|
||||
{
|
||||
new (__p) _Node_(__V, __PARENT, __LEFT, __RIGHT);
|
||||
}
|
||||
|
||||
void
|
||||
_M_destroy_node(_Node_* __p)
|
||||
{
|
||||
_M_node_allocator.destroy(__p);
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace KDTree
|
||||
|
||||
#endif // include guard
|
||||
|
||||
/* COPYRIGHT --
|
||||
*
|
||||
* This file is part of libkdtree++, a C++ template KD-Tree sorting container.
|
||||
* libkdtree++ is (c) 2004-2007 Martin F. Krafft <libkdtree@pobox.madduck.net>
|
||||
* and Sylvain Bougerel <sylvain.bougerel.devel@gmail.com> distributed under the
|
||||
* terms of the Artistic License 2.0. See the ./COPYING file in the source tree
|
||||
* root for more information.
|
||||
*
|
||||
* THIS PACKAGE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED
|
||||
* WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES
|
||||
* OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
|
||||
*/
|
||||
89
src/3rdParty/libkdtree/kdtree++/function.hpp
vendored
Normal file
89
src/3rdParty/libkdtree/kdtree++/function.hpp
vendored
Normal file
@@ -0,0 +1,89 @@
|
||||
/** \file
|
||||
* Defines the various functors and interfaces used for KDTree.
|
||||
*
|
||||
* \author Martin F. Krafft <libkdtree@pobox.madduck.net>
|
||||
* \author Sylvain Bougerel <sylvain.bougerel.devel@gmail.com>
|
||||
*/
|
||||
|
||||
#ifndef INCLUDE_KDTREE_ACCESSOR_HPP
|
||||
#define INCLUDE_KDTREE_ACCESSOR_HPP
|
||||
|
||||
#include <cstddef>
|
||||
|
||||
namespace KDTree
|
||||
{
|
||||
template <typename _Val>
|
||||
struct _Bracket_accessor
|
||||
{
|
||||
typedef typename _Val::value_type result_type;
|
||||
|
||||
result_type
|
||||
operator()(_Val const& V, size_t const N) const
|
||||
{
|
||||
return V[N];
|
||||
}
|
||||
};
|
||||
|
||||
template <typename _Tp>
|
||||
struct always_true
|
||||
{
|
||||
bool operator() (const _Tp& ) const { return true; }
|
||||
};
|
||||
|
||||
template <typename _Tp, typename _Dist>
|
||||
struct squared_difference
|
||||
{
|
||||
typedef _Dist distance_type;
|
||||
|
||||
distance_type
|
||||
operator() (const _Tp& __a, const _Tp& __b) const
|
||||
{
|
||||
distance_type d=__a - __b;
|
||||
return d*d;
|
||||
}
|
||||
};
|
||||
|
||||
template <typename _Tp, typename _Dist>
|
||||
struct squared_difference_counted
|
||||
{
|
||||
typedef _Dist distance_type;
|
||||
|
||||
squared_difference_counted()
|
||||
: _M_count(0)
|
||||
{ }
|
||||
|
||||
void reset ()
|
||||
{ _M_count = 0; }
|
||||
|
||||
long&
|
||||
count () const
|
||||
{ return _M_count; }
|
||||
|
||||
distance_type
|
||||
operator() (const _Tp& __a, const _Tp& __b) const
|
||||
{
|
||||
distance_type d=__a - __b;
|
||||
++_M_count;
|
||||
return d*d;
|
||||
}
|
||||
|
||||
private:
|
||||
mutable long _M_count;
|
||||
};
|
||||
|
||||
} // namespace KDTree
|
||||
|
||||
#endif // include guard
|
||||
|
||||
/* COPYRIGHT --
|
||||
*
|
||||
* This file is part of libkdtree++, a C++ template KD-Tree sorting container.
|
||||
* libkdtree++ is (c) 2004-2007 Martin F. Krafft <libkdtree@pobox.madduck.net>
|
||||
* and Sylvain Bougerel <sylvain.bougerel.devel@gmail.com> distributed under the
|
||||
* terms of the Artistic License 2.0. See the ./COPYING file in the source tree
|
||||
* root for more information.
|
||||
*
|
||||
* THIS PACKAGE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED
|
||||
* WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES
|
||||
* OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
|
||||
*/
|
||||
258
src/3rdParty/libkdtree/kdtree++/iterator.hpp
vendored
Normal file
258
src/3rdParty/libkdtree/kdtree++/iterator.hpp
vendored
Normal file
@@ -0,0 +1,258 @@
|
||||
/** \file
|
||||
* Defines interfaces for iterators as used by the KDTree class.
|
||||
*
|
||||
* \author Martin F. Krafft <libkdtree@pobox.madduck.net>
|
||||
*/
|
||||
|
||||
#ifndef INCLUDE_KDTREE_ITERATOR_HPP
|
||||
#define INCLUDE_KDTREE_ITERATOR_HPP
|
||||
|
||||
#include <iterator>
|
||||
|
||||
#include <kdtree++/node.hpp>
|
||||
|
||||
namespace KDTree
|
||||
{
|
||||
template <typename _Val, typename _Ref, typename _Ptr>
|
||||
class _Iterator;
|
||||
|
||||
template<typename _Val, typename _Ref, typename _Ptr>
|
||||
inline bool
|
||||
operator==(_Iterator<_Val, _Ref, _Ptr> const&,
|
||||
_Iterator<_Val, _Ref, _Ptr> const&);
|
||||
|
||||
template<typename _Val>
|
||||
inline bool
|
||||
operator==(_Iterator<_Val, const _Val&, const _Val*> const&,
|
||||
_Iterator<_Val, _Val&, _Val*> const&);
|
||||
|
||||
template<typename _Val>
|
||||
inline bool
|
||||
operator==(_Iterator<_Val, _Val&, _Val*> const&,
|
||||
_Iterator<_Val, const _Val&, const _Val*> const&);
|
||||
|
||||
template<typename _Val, typename _Ref, typename _Ptr>
|
||||
inline bool
|
||||
operator!=(_Iterator<_Val, _Ref, _Ptr> const&,
|
||||
_Iterator<_Val, _Ref, _Ptr> const&);
|
||||
|
||||
template<typename _Val>
|
||||
inline bool
|
||||
operator!=(_Iterator<_Val, const _Val&, const _Val*> const&,
|
||||
_Iterator<_Val, _Val&, _Val*> const&);
|
||||
|
||||
template<typename _Val>
|
||||
inline bool
|
||||
operator!=(_Iterator<_Val, _Val&, _Val*> const&,
|
||||
_Iterator<_Val, const _Val&, const _Val*> const&);
|
||||
|
||||
class _Base_iterator
|
||||
{
|
||||
protected:
|
||||
typedef _Node_base::_Base_const_ptr _Base_const_ptr;
|
||||
_Base_const_ptr _M_node;
|
||||
|
||||
inline _Base_iterator(_Base_const_ptr const __N = NULL)
|
||||
: _M_node(__N) {}
|
||||
inline _Base_iterator(_Base_iterator const& __THAT)
|
||||
: _M_node(__THAT._M_node) {}
|
||||
|
||||
inline void
|
||||
_M_increment()
|
||||
{
|
||||
if (_M_node->_M_right)
|
||||
{
|
||||
_M_node = _M_node->_M_right;
|
||||
while (_M_node->_M_left) _M_node = _M_node->_M_left;
|
||||
}
|
||||
else
|
||||
{
|
||||
_Base_const_ptr __p = _M_node->_M_parent;
|
||||
while (__p && _M_node == __p->_M_right)
|
||||
{
|
||||
_M_node = __p;
|
||||
__p = _M_node->_M_parent;
|
||||
}
|
||||
if (__p) // (__p) provide undetermined behavior on end()++ rather
|
||||
// than a seg fault, similar to standard iterator.
|
||||
_M_node = __p;
|
||||
}
|
||||
}
|
||||
|
||||
inline void
|
||||
_M_decrement()
|
||||
{
|
||||
if (!_M_node->_M_parent) // clearly identify the header node
|
||||
{
|
||||
_M_node = _M_node->_M_right;
|
||||
}
|
||||
else if (_M_node->_M_left)
|
||||
{
|
||||
_Base_const_ptr x = _M_node->_M_left;
|
||||
while (x->_M_right) x = x->_M_right;
|
||||
_M_node = x;
|
||||
}
|
||||
else
|
||||
{
|
||||
_Base_const_ptr __p = _M_node->_M_parent;
|
||||
while (__p && _M_node == __p->_M_left) // see below
|
||||
{
|
||||
_M_node = __p;
|
||||
__p = _M_node->_M_parent;
|
||||
}
|
||||
if (__p) // (__p) provide undetermined behavior on rend()++ rather
|
||||
// than a seg fault, similar to standard iterator.
|
||||
_M_node = __p;
|
||||
}
|
||||
}
|
||||
|
||||
template <size_t const __K, typename _Val, typename _Acc,
|
||||
typename _Dist, typename _Cmp, typename _Alloc>
|
||||
friend class KDTree;
|
||||
};
|
||||
|
||||
template <typename _Val, typename _Ref, typename _Ptr>
|
||||
class _Iterator : protected _Base_iterator
|
||||
{
|
||||
public:
|
||||
typedef _Val value_type;
|
||||
typedef _Ref reference;
|
||||
typedef _Ptr pointer;
|
||||
typedef _Iterator<_Val, _Val&, _Val*> iterator;
|
||||
typedef _Iterator<_Val, _Val const&, _Val const*> const_iterator;
|
||||
typedef _Iterator<_Val, _Ref, _Ptr> _Self;
|
||||
typedef _Node<_Val> const* _Link_const_type;
|
||||
typedef std::bidirectional_iterator_tag iterator_category;
|
||||
typedef ptrdiff_t difference_type;
|
||||
|
||||
inline _Iterator()
|
||||
: _Base_iterator() {}
|
||||
inline _Iterator(_Link_const_type const __N)
|
||||
: _Base_iterator(__N) {}
|
||||
inline _Iterator(iterator const& __THAT)
|
||||
: _Base_iterator(__THAT) {}
|
||||
|
||||
_Link_const_type get_raw_node() const
|
||||
{
|
||||
return _Link_const_type(_M_node);
|
||||
}
|
||||
|
||||
reference
|
||||
operator*() const
|
||||
{
|
||||
return _Link_const_type(_M_node)->_M_value;
|
||||
}
|
||||
|
||||
pointer
|
||||
operator->() const
|
||||
{
|
||||
return &(operator*());
|
||||
}
|
||||
|
||||
_Self
|
||||
operator++()
|
||||
{
|
||||
_M_increment();
|
||||
return *this;
|
||||
}
|
||||
|
||||
_Self
|
||||
operator++(int)
|
||||
{
|
||||
_Self ret = *this;
|
||||
_M_increment();
|
||||
return ret;
|
||||
}
|
||||
|
||||
_Self&
|
||||
operator--()
|
||||
{
|
||||
_M_decrement();
|
||||
return *this;
|
||||
}
|
||||
|
||||
_Self
|
||||
operator--(int)
|
||||
{
|
||||
_Self ret = *this;
|
||||
_M_decrement();
|
||||
return ret;
|
||||
}
|
||||
|
||||
friend bool
|
||||
operator== <>(_Iterator<_Val, _Ref, _Ptr> const&,
|
||||
_Iterator<_Val, _Ref, _Ptr> const&);
|
||||
|
||||
friend bool
|
||||
operator== <>(_Iterator<_Val, const _Val&, const _Val*> const&,
|
||||
_Iterator<_Val, _Val&, _Val*> const&);
|
||||
|
||||
friend bool
|
||||
operator== <>(_Iterator<_Val, _Val&, _Val*> const&,
|
||||
_Iterator<_Val, const _Val&, const _Val*> const&);
|
||||
|
||||
friend bool
|
||||
operator!= <>(_Iterator<_Val, _Ref, _Ptr> const&,
|
||||
_Iterator<_Val, _Ref, _Ptr> const&);
|
||||
|
||||
friend bool
|
||||
operator!= <>(_Iterator<_Val, const _Val&, const _Val*> const&,
|
||||
_Iterator<_Val, _Val&, _Val*> const&);
|
||||
|
||||
friend bool
|
||||
operator!= <>(_Iterator<_Val, _Val&, _Val*> const&,
|
||||
_Iterator<_Val, const _Val&, const _Val*> const&);
|
||||
};
|
||||
|
||||
template<typename _Val, typename _Ref, typename _Ptr>
|
||||
inline bool
|
||||
operator==(_Iterator<_Val, _Ref, _Ptr> const& __X,
|
||||
_Iterator<_Val, _Ref, _Ptr> const& __Y)
|
||||
{ return __X._M_node == __Y._M_node; }
|
||||
|
||||
template<typename _Val>
|
||||
inline bool
|
||||
operator==(_Iterator<_Val, const _Val&, const _Val*> const& __X,
|
||||
_Iterator<_Val, _Val&, _Val*> const& __Y)
|
||||
{ return __X._M_node == __Y._M_node; }
|
||||
|
||||
template<typename _Val>
|
||||
inline bool
|
||||
operator==(_Iterator<_Val, _Val&, _Val*> const& __X,
|
||||
_Iterator<_Val, const _Val&, const _Val*> const& __Y)
|
||||
{ return __X._M_node == __Y._M_node; }
|
||||
|
||||
template<typename _Val, typename _Ref, typename _Ptr>
|
||||
inline bool
|
||||
operator!=(_Iterator<_Val, _Ref, _Ptr> const& __X,
|
||||
_Iterator<_Val, _Ref, _Ptr> const& __Y)
|
||||
{ return __X._M_node != __Y._M_node; }
|
||||
|
||||
template<typename _Val>
|
||||
inline bool
|
||||
operator!=(_Iterator<_Val, const _Val&, const _Val*> const& __X,
|
||||
_Iterator<_Val, _Val&, _Val*> const& __Y)
|
||||
{ return __X._M_node != __Y._M_node; }
|
||||
|
||||
template<typename _Val>
|
||||
inline bool
|
||||
operator!=(_Iterator<_Val, _Val&, _Val*> const& __X,
|
||||
_Iterator<_Val, const _Val&, const _Val*> const& __Y)
|
||||
{ return __X._M_node != __Y._M_node; }
|
||||
|
||||
} // namespace KDTree
|
||||
|
||||
#endif // include guard
|
||||
|
||||
/* COPYRIGHT --
|
||||
*
|
||||
* This file is part of libkdtree++, a C++ template KD-Tree sorting container.
|
||||
* libkdtree++ is (c) 2004-2007 Martin F. Krafft <libkdtree@pobox.madduck.net>
|
||||
* and Sylvain Bougerel <sylvain.bougerel.devel@gmail.com> distributed under the
|
||||
* terms of the Artistic License 2.0. See the ./COPYING file in the source tree
|
||||
* root for more information.
|
||||
*
|
||||
* THIS PACKAGE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED
|
||||
* WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES
|
||||
* OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
|
||||
*/
|
||||
1247
src/3rdParty/libkdtree/kdtree++/kdtree.hpp
vendored
Normal file
1247
src/3rdParty/libkdtree/kdtree++/kdtree.hpp
vendored
Normal file
File diff suppressed because it is too large
Load Diff
362
src/3rdParty/libkdtree/kdtree++/node.hpp
vendored
Normal file
362
src/3rdParty/libkdtree/kdtree++/node.hpp
vendored
Normal file
@@ -0,0 +1,362 @@
|
||||
/** \file
|
||||
* Defines interfaces for nodes as used by the KDTree class.
|
||||
*
|
||||
* \author Martin F. Krafft <libkdtree@pobox.madduck.net>
|
||||
*/
|
||||
|
||||
#ifndef INCLUDE_KDTREE_NODE_HPP
|
||||
#define INCLUDE_KDTREE_NODE_HPP
|
||||
|
||||
#ifdef KDTREE_DEFINE_OSTREAM_OPERATORS
|
||||
# include <ostream>
|
||||
#endif
|
||||
|
||||
#include <cstddef>
|
||||
#include <cmath>
|
||||
|
||||
namespace KDTree
|
||||
{
|
||||
struct _Node_base
|
||||
{
|
||||
typedef _Node_base* _Base_ptr;
|
||||
typedef _Node_base const* _Base_const_ptr;
|
||||
|
||||
_Base_ptr _M_parent;
|
||||
_Base_ptr _M_left;
|
||||
_Base_ptr _M_right;
|
||||
|
||||
_Node_base(_Base_ptr const __PARENT = NULL,
|
||||
_Base_ptr const __LEFT = NULL,
|
||||
_Base_ptr const __RIGHT = NULL)
|
||||
: _M_parent(__PARENT), _M_left(__LEFT), _M_right(__RIGHT) {}
|
||||
|
||||
static _Base_ptr
|
||||
_S_minimum(_Base_ptr __x)
|
||||
{
|
||||
while (__x->_M_left) __x = __x->_M_left;
|
||||
return __x;
|
||||
}
|
||||
|
||||
static _Base_ptr
|
||||
_S_maximum(_Base_ptr __x)
|
||||
{
|
||||
while (__x->_M_right) __x = __x->_M_right;
|
||||
return __x;
|
||||
}
|
||||
};
|
||||
|
||||
template <typename _Val>
|
||||
struct _Node : public _Node_base
|
||||
{
|
||||
using _Node_base::_Base_ptr;
|
||||
typedef _Node* _Link_type;
|
||||
|
||||
_Val _M_value;
|
||||
|
||||
_Node(_Val const& __VALUE = _Val(),
|
||||
_Base_ptr const __PARENT = NULL,
|
||||
_Base_ptr const __LEFT = NULL,
|
||||
_Base_ptr const __RIGHT = NULL)
|
||||
: _Node_base(__PARENT, __LEFT, __RIGHT), _M_value(__VALUE) {}
|
||||
|
||||
#ifdef KDTREE_DEFINE_OSTREAM_OPERATORS
|
||||
|
||||
template <typename Char, typename Traits>
|
||||
friend
|
||||
std::basic_ostream<Char, Traits>&
|
||||
operator<<(typename std::basic_ostream<Char, Traits>& out,
|
||||
_Node_base const& node)
|
||||
{
|
||||
out << &node;
|
||||
out << " parent: " << node._M_parent;
|
||||
out << "; left: " << node._M_left;
|
||||
out << "; right: " << node._M_right;
|
||||
return out;
|
||||
}
|
||||
|
||||
template <typename Char, typename Traits>
|
||||
friend
|
||||
std::basic_ostream<Char, Traits>&
|
||||
operator<<(typename std::basic_ostream<Char, Traits>& out,
|
||||
_Node<_Val> const& node)
|
||||
{
|
||||
out << &node;
|
||||
out << ' ' << node._M_value;
|
||||
out << "; parent: " << node._M_parent;
|
||||
out << "; left: " << node._M_left;
|
||||
out << "; right: " << node._M_right;
|
||||
return out;
|
||||
}
|
||||
|
||||
#endif
|
||||
};
|
||||
|
||||
template <typename _Val, typename _Acc, typename _Cmp>
|
||||
class _Node_compare
|
||||
{
|
||||
public:
|
||||
_Node_compare(size_t const __DIM, _Acc const& acc, _Cmp const& cmp)
|
||||
: _M_DIM(__DIM), _M_acc(acc), _M_cmp(cmp) {}
|
||||
|
||||
bool
|
||||
operator()(_Val const& __A, _Val const& __B) const
|
||||
{
|
||||
return _M_cmp(_M_acc(__A, _M_DIM), _M_acc(__B, _M_DIM));
|
||||
}
|
||||
|
||||
private:
|
||||
size_t _M_DIM; // don't make this const so that an assignment operator can be auto-generated
|
||||
_Acc _M_acc;
|
||||
_Cmp _M_cmp;
|
||||
};
|
||||
|
||||
/*! Compare two values on the same dimension using a comparison functor _Cmp
|
||||
and an accessor _Acc.
|
||||
|
||||
The comparison functor and the accessor are references to the template
|
||||
parameters of the KDTree.
|
||||
*/
|
||||
template <typename _ValA, typename _ValB, typename _Cmp,
|
||||
typename _Acc>
|
||||
inline
|
||||
bool
|
||||
_S_node_compare (const size_t __dim,
|
||||
const _Cmp& __cmp, const _Acc& __acc,
|
||||
const _ValA& __a, const _ValB& __b)
|
||||
{
|
||||
return __cmp(__acc(__a, __dim), __acc(__b, __dim));
|
||||
}
|
||||
|
||||
/*! Compute the distance between two values for one dimension only.
|
||||
|
||||
The distance functor and the accessor are references to the template
|
||||
parameters of the KDTree.
|
||||
*/
|
||||
template <typename _ValA, typename _ValB, typename _Dist,
|
||||
typename _Acc>
|
||||
inline
|
||||
typename _Dist::distance_type
|
||||
_S_node_distance (const size_t __dim,
|
||||
const _Dist& __dist, const _Acc& __acc,
|
||||
const _ValA& __a, const _ValB& __b)
|
||||
{
|
||||
return __dist(__acc(__a, __dim), __acc(__b, __dim));
|
||||
}
|
||||
|
||||
/*! Compute the distance between two values and accumulate the result for all
|
||||
dimensions.
|
||||
|
||||
The distance functor and the accessor are references to the template
|
||||
parameters of the KDTree.
|
||||
*/
|
||||
template <typename _ValA, typename _ValB, typename _Dist,
|
||||
typename _Acc>
|
||||
inline
|
||||
typename _Dist::distance_type
|
||||
_S_accumulate_node_distance (const size_t __dim,
|
||||
const _Dist& __dist, const _Acc& __acc,
|
||||
const _ValA& __a, const _ValB& __b)
|
||||
{
|
||||
typename _Dist::distance_type d = 0;
|
||||
for (size_t i=0; i<__dim; ++i)
|
||||
d += __dist(__acc(__a, i), __acc(__b, i));
|
||||
return d;
|
||||
}
|
||||
|
||||
/*! Descend on the left or the right of the node according to the comparison
|
||||
between the node's value and the value.
|
||||
|
||||
\note it's the caller responsibility to check if node is NULL.
|
||||
*/
|
||||
template <typename _Val, typename _Cmp, typename _Acc>
|
||||
inline
|
||||
_Node_base*
|
||||
_S_node_descend (const size_t __dim,
|
||||
const _Cmp& __cmp, const _Acc& __acc,
|
||||
const _Val& __val, const _Node_base* __node)
|
||||
{
|
||||
if (_S_node_compare(__dim, __cmp, __acc, __val, static_cast<const _Node<_Val>* >(__node)->_M_value))
|
||||
return __node->_M_left;
|
||||
else
|
||||
return __node->_M_right;
|
||||
}
|
||||
|
||||
/*! Find the nearest node to __val from __node
|
||||
|
||||
If many nodes are equidistant to __val, the node with the lowest memory
|
||||
address is returned.
|
||||
|
||||
\return the nearest node of __end node if no nearest node was found for the
|
||||
given arguments.
|
||||
*/
|
||||
template <class SearchVal,
|
||||
typename _Val, typename _Cmp,
|
||||
typename _Acc, typename _Dist,
|
||||
typename _Predicate>
|
||||
inline
|
||||
std::pair<const _Node<_Val>*,
|
||||
std::pair<size_t, typename _Dist::distance_type> >
|
||||
_S_node_nearest (const size_t __k, size_t __dim, SearchVal const& __val,
|
||||
const _Node<_Val>* __node, const _Node_base* __end,
|
||||
const _Node<_Val>* __best, typename _Dist::distance_type __max,
|
||||
const _Cmp& __cmp, const _Acc& __acc, const _Dist& __dist,
|
||||
_Predicate __p)
|
||||
{
|
||||
const _Node_base* pcur = __node;
|
||||
const _Node_base* cur = _S_node_descend(__dim % __k, __cmp, __acc, __val, __node);
|
||||
size_t cur_dim = __dim+1;
|
||||
// find the smallest __max distance in direct descent
|
||||
while (cur)
|
||||
{
|
||||
if (__p(static_cast<const _Node<_Val>* >(cur)->_M_value))
|
||||
{
|
||||
typename _Dist::distance_type d = 0;
|
||||
for (size_t i=0; i != __k; ++i)
|
||||
d += _S_node_distance(i, __dist, __acc, __val, static_cast<const _Node<_Val>* >(cur)->_M_value);
|
||||
d = sqrt(d);
|
||||
if (d <= __max)
|
||||
// ("bad candidate notes")
|
||||
// Changed: removed this test: || ( d == __max && cur < __best ))
|
||||
// Can't do this optimisation without checking that the current 'best' is not the root AND is not a valid candidate...
|
||||
// This is because find_nearest() etc will call this function with the best set to _M_root EVEN IF _M_root is not a valid answer (eg too far away or doesn't pass the predicate test)
|
||||
{
|
||||
__best = static_cast<const _Node<_Val>* >(cur);
|
||||
__max = d;
|
||||
__dim = cur_dim;
|
||||
}
|
||||
}
|
||||
pcur = cur;
|
||||
cur = _S_node_descend(cur_dim % __k, __cmp, __acc, __val, cur);
|
||||
++cur_dim;
|
||||
}
|
||||
// Swap cur to prev, only prev is a valid node.
|
||||
cur = pcur;
|
||||
--cur_dim;
|
||||
pcur = NULL;
|
||||
// Probe all node's children not visited yet (siblings of the visited nodes).
|
||||
const _Node_base* probe = cur;
|
||||
const _Node_base* pprobe = probe;
|
||||
const _Node_base* near_node;
|
||||
const _Node_base* far_node;
|
||||
size_t probe_dim = cur_dim;
|
||||
if (_S_node_compare(probe_dim % __k, __cmp, __acc, __val, static_cast<const _Node<_Val>* >(probe)->_M_value))
|
||||
near_node = probe->_M_right;
|
||||
else
|
||||
near_node = probe->_M_left;
|
||||
if (near_node
|
||||
// only visit node's children if node's plane intersect hypersphere
|
||||
&& (sqrt(_S_node_distance(probe_dim % __k, __dist, __acc, __val, static_cast<const _Node<_Val>* >(probe)->_M_value)) <= __max))
|
||||
{
|
||||
probe = near_node;
|
||||
++probe_dim;
|
||||
}
|
||||
while (cur != __end)
|
||||
{
|
||||
while (probe != cur)
|
||||
{
|
||||
if (_S_node_compare(probe_dim % __k, __cmp, __acc, __val, static_cast<const _Node<_Val>* >(probe)->_M_value))
|
||||
{
|
||||
near_node = probe->_M_left;
|
||||
far_node = probe->_M_right;
|
||||
}
|
||||
else
|
||||
{
|
||||
near_node = probe->_M_right;
|
||||
far_node = probe->_M_left;
|
||||
}
|
||||
if (pprobe == probe->_M_parent) // going downward ...
|
||||
{
|
||||
if (__p(static_cast<const _Node<_Val>* >(probe)->_M_value))
|
||||
{
|
||||
typename _Dist::distance_type d = 0;
|
||||
for (size_t i=0; i < __k; ++i)
|
||||
d += _S_node_distance(i, __dist, __acc, __val, static_cast<const _Node<_Val>* >(probe)->_M_value);
|
||||
d = sqrt(d);
|
||||
if (d <= __max) // CHANGED, see the above notes ("bad candidate notes")
|
||||
{
|
||||
__best = static_cast<const _Node<_Val>* >(probe);
|
||||
__max = d;
|
||||
__dim = probe_dim;
|
||||
}
|
||||
}
|
||||
pprobe = probe;
|
||||
if (near_node)
|
||||
{
|
||||
probe = near_node;
|
||||
++probe_dim;
|
||||
}
|
||||
else if (far_node &&
|
||||
// only visit node's children if node's plane intersect hypersphere
|
||||
sqrt(_S_node_distance(probe_dim % __k, __dist, __acc, __val, static_cast<const _Node<_Val>* >(probe)->_M_value)) <= __max)
|
||||
{
|
||||
probe = far_node;
|
||||
++probe_dim;
|
||||
}
|
||||
else
|
||||
{
|
||||
probe = probe->_M_parent;
|
||||
--probe_dim;
|
||||
}
|
||||
}
|
||||
else // ... and going upward.
|
||||
{
|
||||
if (pprobe == near_node && far_node
|
||||
// only visit node's children if node's plane intersect hypersphere
|
||||
&& sqrt(_S_node_distance(probe_dim % __k, __dist, __acc, __val, static_cast<const _Node<_Val>* >(probe)->_M_value)) <= __max)
|
||||
{
|
||||
pprobe = probe;
|
||||
probe = far_node;
|
||||
++probe_dim;
|
||||
}
|
||||
else
|
||||
{
|
||||
pprobe = probe;
|
||||
probe = probe->_M_parent;
|
||||
--probe_dim;
|
||||
}
|
||||
}
|
||||
}
|
||||
pcur = cur;
|
||||
cur = cur->_M_parent;
|
||||
--cur_dim;
|
||||
pprobe = cur;
|
||||
probe = cur;
|
||||
probe_dim = cur_dim;
|
||||
if (cur != __end)
|
||||
{
|
||||
if (pcur == cur->_M_left)
|
||||
near_node = cur->_M_right;
|
||||
else
|
||||
near_node = cur->_M_left;
|
||||
if (near_node
|
||||
// only visit node's children if node's plane intersect hypersphere
|
||||
&& (sqrt(_S_node_distance(cur_dim % __k, __dist, __acc, __val, static_cast<const _Node<_Val>* >(cur)->_M_value)) <= __max))
|
||||
{
|
||||
probe = near_node;
|
||||
++probe_dim;
|
||||
}
|
||||
}
|
||||
}
|
||||
return std::pair<const _Node<_Val>*,
|
||||
std::pair<size_t, typename _Dist::distance_type> >
|
||||
(__best, std::pair<size_t, typename _Dist::distance_type>
|
||||
(__dim, __max));
|
||||
}
|
||||
|
||||
|
||||
} // namespace KDTree
|
||||
|
||||
#endif // include guard
|
||||
|
||||
/* COPYRIGHT --
|
||||
*
|
||||
* This file is part of libkdtree++, a C++ template KD-Tree sorting container.
|
||||
* libkdtree++ is (c) 2004-2007 Martin F. Krafft <libkdtree@pobox.madduck.net>
|
||||
* and Sylvain Bougerel <sylvain.bougerel.devel@gmail.com> distributed under the
|
||||
* terms of the Artistic License 2.0. See the ./COPYING file in the source tree
|
||||
* root for more information.
|
||||
*
|
||||
* THIS PACKAGE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED
|
||||
* WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES
|
||||
* OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
|
||||
*/
|
||||
131
src/3rdParty/libkdtree/kdtree++/region.hpp
vendored
Normal file
131
src/3rdParty/libkdtree/kdtree++/region.hpp
vendored
Normal file
@@ -0,0 +1,131 @@
|
||||
/** \file
|
||||
* Defines the interface of the _Region class.
|
||||
*
|
||||
* \author Martin F. Krafft <libkdtree@pobox.madduck.net>
|
||||
*/
|
||||
|
||||
#ifndef INCLUDE_KDTREE_REGION_HPP
|
||||
#define INCLUDE_KDTREE_REGION_HPP
|
||||
|
||||
#include <cstddef>
|
||||
|
||||
#include <kdtree++/node.hpp>
|
||||
|
||||
namespace KDTree
|
||||
{
|
||||
|
||||
template <size_t const __K, typename _Val, typename _SubVal,
|
||||
typename _Acc, typename _Cmp>
|
||||
struct _Region
|
||||
{
|
||||
typedef _Val value_type;
|
||||
typedef _SubVal subvalue_type;
|
||||
|
||||
// special typedef for checking against a fuzzy point (for find_nearest)
|
||||
// Note the region (first) component is not supposed to have an area, its
|
||||
// bounds should all be set to a specific point.
|
||||
typedef std::pair<_Region,_SubVal> _CenterPt;
|
||||
|
||||
_Region(_Acc const& __acc=_Acc(), const _Cmp& __cmp=_Cmp())
|
||||
: _M_cmp(__acc), _M_acc(__cmp) {}
|
||||
|
||||
template <typename Val>
|
||||
_Region(Val const& __V,
|
||||
_Acc const& __acc=_Acc(), const _Cmp& __cmp=_Cmp())
|
||||
: _M_acc(__acc), _M_cmp(__cmp)
|
||||
{
|
||||
for (size_t __i = 0; __i != __K; ++__i)
|
||||
{
|
||||
_M_low_bounds[__i] = _M_high_bounds[__i] = _M_acc(__V,__i);
|
||||
}
|
||||
}
|
||||
|
||||
template <typename Val>
|
||||
_Region(Val const& __V, subvalue_type const& __R,
|
||||
_Acc const& __acc=_Acc(), const _Cmp& __cmp=_Cmp())
|
||||
: _M_acc(__acc), _M_cmp(__cmp)
|
||||
{
|
||||
for (size_t __i = 0; __i != __K; ++__i)
|
||||
{
|
||||
_M_low_bounds[__i] = _M_acc(__V,__i) - __R;
|
||||
_M_high_bounds[__i] = _M_acc(__V,__i) + __R;
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
intersects_with(_CenterPt const& __THAT) const
|
||||
{
|
||||
for (size_t __i = 0; __i != __K; ++__i)
|
||||
{
|
||||
// does it fall outside the bounds?
|
||||
// ! low-tolerance <= x <= high+tolerance
|
||||
// ! (low-tol <= x and x <= high+tol)
|
||||
// !low-tol<=x or !x<=high+tol
|
||||
// low-tol>x or x>high+tol
|
||||
// x<low-tol or high+tol<x
|
||||
if (_M_cmp(__THAT.first._M_low_bounds[__i], _M_low_bounds[__i] - __THAT.second)
|
||||
|| _M_cmp(_M_high_bounds[__i] + __THAT.second, __THAT.first._M_low_bounds[__i]))
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
intersects_with(_Region const& __THAT) const
|
||||
{
|
||||
for (size_t __i = 0; __i != __K; ++__i)
|
||||
{
|
||||
if (_M_cmp(__THAT._M_high_bounds[__i], _M_low_bounds[__i])
|
||||
|| _M_cmp(_M_high_bounds[__i], __THAT._M_low_bounds[__i]))
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
encloses(value_type const& __V) const
|
||||
{
|
||||
for (size_t __i = 0; __i != __K; ++__i)
|
||||
{
|
||||
if (_M_cmp(_M_acc(__V, __i), _M_low_bounds[__i])
|
||||
|| _M_cmp(_M_high_bounds[__i], _M_acc(__V, __i)))
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
_Region&
|
||||
set_high_bound(value_type const& __V, size_t const __L)
|
||||
{
|
||||
_M_high_bounds[__L % __K] = _M_acc(__V, __L % __K);
|
||||
return *this;
|
||||
}
|
||||
|
||||
_Region&
|
||||
set_low_bound(value_type const& __V, size_t const __L)
|
||||
{
|
||||
_M_low_bounds[__L % __K] = _M_acc(__V, __L % __K);
|
||||
return *this;
|
||||
}
|
||||
|
||||
subvalue_type _M_low_bounds[__K], _M_high_bounds[__K];
|
||||
_Acc _M_acc;
|
||||
_Cmp _M_cmp;
|
||||
};
|
||||
|
||||
} // namespace KDTree
|
||||
|
||||
#endif // include guard
|
||||
|
||||
/* COPYRIGHT --
|
||||
*
|
||||
* This file is part of libkdtree++, a C++ template KD-Tree sorting container.
|
||||
* libkdtree++ is (c) 2004-2007 Martin F. Krafft <libkdtree@pobox.madduck.net>
|
||||
* and Sylvain Bougerel <sylvain.bougerel.devel@gmail.com> distributed under the
|
||||
* terms of the Artistic License 2.0. See the ./COPYING file in the source tree
|
||||
* root for more information.
|
||||
*
|
||||
* THIS PACKAGE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED
|
||||
* WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES
|
||||
* OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
|
||||
*/
|
||||
19
src/3rdParty/libkdtree/python-bindings/CMakeLists.txt
vendored
Normal file
19
src/3rdParty/libkdtree/python-bindings/CMakeLists.txt
vendored
Normal file
@@ -0,0 +1,19 @@
|
||||
find_package (SWIG REQUIRED)
|
||||
include (${SWIG_USE_FILE})
|
||||
|
||||
find_package (PythonLibs)
|
||||
include_directories (${PYTHON_INCLUDE_PATH})
|
||||
|
||||
include_directories (${CMAKE_CURRENT_SOURCE_DIR})
|
||||
include_directories (${CMAKE_CURRENT_SOURCE_DIR}/..)
|
||||
|
||||
# Build the _kdtree python module
|
||||
set_source_files_properties (py-kdtree.i PROPERTIES CPLUSPLUS ON)
|
||||
swig_add_module (kdtree python py-kdtree.i)
|
||||
swig_link_libraries (kdtree ${PYTHON_LIBRARIES})
|
||||
|
||||
# Copy the test file into the build dir
|
||||
install (FILES py-kdtree_test.py DESTINATION ${CMAKE_INSTALL_PREFIX}/python)
|
||||
install (FILES ${CMAKE_BINARY_DIR}/python-bindings/kdtree.py DESTINATION ${CMAKE_INSTALL_PREFIX}/python)
|
||||
install (FILES ${CMAKE_BINARY_DIR}/python-bindings/_kdtree.so DESTINATION ${CMAKE_INSTALL_PREFIX}/python)
|
||||
|
||||
264
src/3rdParty/libkdtree/python-bindings/gen-swig-hpp.py
vendored
Normal file
264
src/3rdParty/libkdtree/python-bindings/gen-swig-hpp.py
vendored
Normal file
@@ -0,0 +1,264 @@
|
||||
#!/usr/bin/python
|
||||
|
||||
|
||||
TREE_TYPES = [(dim, "int", "unsigned long long", "i", "L") for dim in range(2,7)] + \
|
||||
[(dim, "float", "unsigned long long", "f", "L") for dim in range(2,7)]
|
||||
|
||||
|
||||
def write_swig_file(tmpl_fn_name, swig_fn_name):
|
||||
TMPL_SEPARATOR_DEF="""\
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// TYPE (%s) -> %s
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
"""
|
||||
TMPL_SEPARATOR=[]
|
||||
|
||||
TMPL_RECORD_DEF="""\
|
||||
#define RECORD_%i%s%s record_t<%i, %s, %s> // cf. py-kdtree.hpp
|
||||
"""
|
||||
TMPL_RECORD=[]
|
||||
|
||||
TMPL_IN_CONV_RECORD_DEF="""\
|
||||
%%typemap(in) RECORD_%i%s%s (RECORD_%i%s%s temp) {
|
||||
if (PyTuple_Check($input)) {
|
||||
if (PyArg_ParseTuple($input,"(%s)%s", %s, &temp.data)!=0)
|
||||
{
|
||||
$1 = temp;
|
||||
} else {
|
||||
PyErr_SetString(PyExc_TypeError,"tuple must have %i elements: (%i dim %s vector, %s value)");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
} else {
|
||||
PyErr_SetString(PyExc_TypeError,"expected a tuple.");
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
"""
|
||||
TMPL_IN_CONV_RECORD=[]
|
||||
|
||||
TMPL_IN_CONV_POINT_DEF="""\
|
||||
%%typemap(in) RECORD_%i%s%s::point_t (RECORD_%i%s%s::point_t point) {
|
||||
if (PyTuple_Check($input)) {
|
||||
if (PyArg_ParseTuple($input,"%s", %s)!=0)
|
||||
{
|
||||
$1 = point;
|
||||
} else {
|
||||
PyErr_SetString(PyExc_TypeError,"tuple must contain %i ints");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
} else {
|
||||
PyErr_SetString(PyExc_TypeError,"expected a tuple.");
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
"""
|
||||
TMPL_IN_CONV_POINT=[]
|
||||
|
||||
|
||||
TMPL_OUT_CONV_POINT_DEF="""\
|
||||
%%typemap(out) RECORD_%i%s%s * {
|
||||
RECORD_%i%s%s * r = $1;
|
||||
PyObject* py_result;
|
||||
|
||||
if (r != NULL) {
|
||||
|
||||
py_result = PyTuple_New(2);
|
||||
if (py_result==NULL) {
|
||||
PyErr_SetString(PyErr_Occurred(),"unable to create a tuple.");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (PyTuple_SetItem(py_result, 0, Py_BuildValue("(%s)", %s))==-1) {
|
||||
PyErr_SetString(PyErr_Occurred(),"(a) when setting element");
|
||||
|
||||
Py_DECREF(py_result);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (PyTuple_SetItem(py_result, 1, Py_BuildValue("%s", r->data))==-1) {
|
||||
PyErr_SetString(PyErr_Occurred(),"(b) when setting element");
|
||||
|
||||
Py_DECREF(py_result);
|
||||
return NULL;
|
||||
}
|
||||
} else {
|
||||
py_result = Py_BuildValue("");
|
||||
}
|
||||
|
||||
$result = py_result;
|
||||
}
|
||||
"""
|
||||
TMPL_OUT_CONV_POINT=[]
|
||||
|
||||
TMPL_OUT_CONV_RECORD_DEF="""\
|
||||
%%typemap(out) std::vector<RECORD_%i%s%s >* {
|
||||
std::vector<RECORD_%i%s%s >* v = $1;
|
||||
|
||||
PyObject* py_result = PyList_New(v->size());
|
||||
if (py_result==NULL) {
|
||||
PyErr_SetString(PyErr_Occurred(),"unable to create a list.");
|
||||
return NULL;
|
||||
}
|
||||
std::vector<RECORD_%i%s%s >::const_iterator iter = v->begin();
|
||||
|
||||
for (size_t i=0; i<v->size(); i++, iter++) {
|
||||
if (PyList_SetItem(py_result, i, Py_BuildValue("(%s)%s", %s, (*iter).data))==-1) {
|
||||
PyErr_SetString(PyErr_Occurred(),"(c) when setting element");
|
||||
|
||||
Py_DECREF(py_result);
|
||||
return NULL;
|
||||
} else {
|
||||
//std::cout << "successfully set element " << *iter << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
$result = py_result;
|
||||
}
|
||||
"""
|
||||
TMPL_OUT_CONV_RECORD=[]
|
||||
|
||||
TMPL_PY_CLASS_DEF="""\
|
||||
%%template () RECORD_%i%s%s;
|
||||
%%template (KDTree_%i%s) PyKDTree<%i, %s, %s>;
|
||||
"""
|
||||
TMPL_PY_CLASS=[]
|
||||
|
||||
|
||||
TYPE_DEFS = []
|
||||
|
||||
for t in TREE_TYPES:
|
||||
dim, coord_t, data_t, py_coord_t, py_data_t = t
|
||||
coord_t_short = "".join([_[0] for _ in coord_t.split(" ")])
|
||||
data_t_short = "".join([_[0] for _ in data_t.split(" ")])
|
||||
|
||||
TMPL_SEPARATOR.append(TMPL_SEPARATOR_DEF%(",".join([coord_t for _ in range(dim)]), data_t))
|
||||
|
||||
TMPL_RECORD.append(TMPL_RECORD_DEF%(dim, coord_t_short, data_t_short, dim, coord_t, data_t))
|
||||
|
||||
TMPL_IN_CONV_RECORD.append(TMPL_IN_CONV_RECORD_DEF%\
|
||||
(dim, coord_t_short, data_t_short,
|
||||
dim, coord_t_short, data_t_short,
|
||||
py_coord_t*dim, py_data_t, ",".join(["&temp.point[%i]"%i for i in range(dim)]),
|
||||
dim, dim, coord_t, data_t)
|
||||
)
|
||||
|
||||
TMPL_IN_CONV_POINT.append(TMPL_IN_CONV_POINT_DEF%\
|
||||
(dim, coord_t_short, data_t_short,
|
||||
dim, coord_t_short, data_t_short,
|
||||
py_coord_t*dim, ",".join(["&point[%i]"%i for i in range(dim)]),
|
||||
dim)
|
||||
)
|
||||
|
||||
TMPL_OUT_CONV_RECORD.append(TMPL_OUT_CONV_RECORD_DEF%\
|
||||
(dim, coord_t_short, data_t_short,
|
||||
dim, coord_t_short, data_t_short,
|
||||
dim, coord_t_short, data_t_short,
|
||||
py_coord_t*dim, py_data_t, ",".join(["(*iter).point[%i]"%i for i in range(dim)]),
|
||||
)
|
||||
)
|
||||
TMPL_OUT_CONV_POINT.append(TMPL_OUT_CONV_POINT_DEF%\
|
||||
(dim, coord_t_short, data_t_short,
|
||||
dim, coord_t_short, data_t_short,
|
||||
py_coord_t*dim, ",".join(["r->point[%i]"%i for i in range(dim)]),
|
||||
py_data_t)
|
||||
)
|
||||
|
||||
TMPL_PY_CLASS.append(TMPL_PY_CLASS_DEF%\
|
||||
(dim, coord_t_short, data_t_short,
|
||||
dim, coord_t.capitalize(), dim, coord_t, data_t)
|
||||
)
|
||||
|
||||
|
||||
TMPL_BODY_LIST = []
|
||||
for i in range(len(TREE_TYPES)):
|
||||
TMPL_BODY_LIST.append(TMPL_SEPARATOR[i] + "\n" + \
|
||||
TMPL_RECORD[i] + "\n" + \
|
||||
TMPL_IN_CONV_POINT[i] + "\n" + \
|
||||
TMPL_IN_CONV_RECORD[i] + "\n" + \
|
||||
TMPL_OUT_CONV_POINT[i] + "\n" + \
|
||||
TMPL_OUT_CONV_RECORD[i])
|
||||
|
||||
TMPL_BODY = "\n\n".join(TMPL_BODY_LIST)
|
||||
|
||||
# write swig file
|
||||
i_content = open(tmpl_fn_name, "r").read()
|
||||
i_content = i_content.replace("%%TMPL_BODY%%", TMPL_BODY).replace("%%TMPL_PY_CLASS_DEF%%", "\n".join(TMPL_PY_CLASS))
|
||||
f=open(swig_fn_name, "w")
|
||||
f.write(i_content)
|
||||
f.close()
|
||||
|
||||
|
||||
def write_hpp_file(tmpl_fn_name, hpp_fn_name):
|
||||
TMPL_SEPARATOR_DEF="""\
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// Definition of (%s) with data type %s
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
"""
|
||||
TMPL_SEPARATOR=[]
|
||||
|
||||
TMPL_RECORD_DEF = """\
|
||||
#define RECORD_%i%s%s record_t<%i, %s, %s>
|
||||
#define KDTREE_TYPE_%i%s%s KDTree::KDTree<%i, RECORD_%i%s%s, std::pointer_to_binary_function<RECORD_%i%s%s,int,double> >
|
||||
"""
|
||||
TMPL_RECORD=[]
|
||||
|
||||
TMPL_OP_EQ_DEF = """\
|
||||
inline bool operator==(RECORD_%i%s%s const& A, RECORD_%i%s%s const& B) {
|
||||
return %s && A.data == B.data;
|
||||
}
|
||||
"""
|
||||
TMPL_OP_EQ = []
|
||||
|
||||
TMPL_OP_OUT_DEF="""\
|
||||
std::ostream& operator<<(std::ostream& out, RECORD_%i%s%s const& T)
|
||||
{
|
||||
return out << '(' << %s << '|' << T.data << ')';
|
||||
}
|
||||
"""
|
||||
TMPL_OP_OUT = []
|
||||
|
||||
TYPE_DEFS = []
|
||||
|
||||
for t in TREE_TYPES:
|
||||
dim, coord_t, data_t, py_coord_t, py_data_t = t
|
||||
coord_t_short = "".join([_[0] for _ in coord_t.split(" ")])
|
||||
data_t_short = "".join([_[0] for _ in data_t.split(" ")])
|
||||
|
||||
TMPL_SEPARATOR.append(TMPL_SEPARATOR_DEF%(",".join([coord_t for _ in range(dim)]), data_t))
|
||||
|
||||
TMPL_RECORD.append(TMPL_RECORD_DEF%(dim, coord_t_short, data_t_short,
|
||||
dim, coord_t, data_t,
|
||||
dim, coord_t_short, data_t_short,
|
||||
dim,
|
||||
dim, coord_t_short, data_t_short,
|
||||
dim, coord_t_short, data_t_short)
|
||||
)
|
||||
|
||||
TMPL_OP_EQ.append(TMPL_OP_EQ_DEF%(dim, coord_t_short, data_t_short,
|
||||
dim, coord_t_short, data_t_short,
|
||||
" && ".join(["A.point[%i] == B.point[%i]"%(i,i) for i in range(dim)])))
|
||||
|
||||
TMPL_OP_OUT.append(TMPL_OP_OUT_DEF%(dim, coord_t_short, data_t_short,
|
||||
" << ',' << ".join(["T.point[%i]"%i for i in range(dim)])))
|
||||
|
||||
|
||||
TMPL_BODY_LIST = []
|
||||
for i in range(len(TREE_TYPES)):
|
||||
TMPL_BODY_LIST.append(TMPL_SEPARATOR[i] + "\n" + TMPL_RECORD[i] + "\n" + TMPL_OP_EQ[i] + "\n" + TMPL_OP_OUT[i])
|
||||
|
||||
TMPL_BODY = "\n\n".join(TMPL_BODY_LIST)
|
||||
|
||||
# write hpp file
|
||||
hpp_content = open(tmpl_fn_name, "r").read()
|
||||
hpp_content = hpp_content.replace("%%TMPL_HPP_DEFS%%", TMPL_BODY)
|
||||
f=open(hpp_fn_name, "w")
|
||||
f.write(hpp_content)
|
||||
f.close()
|
||||
|
||||
|
||||
if __name__=="__main__":
|
||||
write_swig_file("py-kdtree.i.tmpl", "py-kdtree.i")
|
||||
write_hpp_file("py-kdtree.hpp.tmpl", "py-kdtree.hpp")
|
||||
|
||||
145
src/3rdParty/libkdtree/python-bindings/py-kdtree.hpp.tmpl
vendored
Normal file
145
src/3rdParty/libkdtree/python-bindings/py-kdtree.hpp.tmpl
vendored
Normal file
@@ -0,0 +1,145 @@
|
||||
/** \file
|
||||
* Provides a Python interface for the libkdtree++.
|
||||
*
|
||||
* \author Willi Richert <w.richert@gmx.net>
|
||||
*
|
||||
*
|
||||
* This defines a proxy to a (int, int) -> long long KD-Tree. The long
|
||||
* long is needed to save a reference to Python's object id(). Thereby,
|
||||
* you can associate Python objects with 2D integer points.
|
||||
*
|
||||
* If you want to customize it you can adapt the following:
|
||||
*
|
||||
* * Dimension of the KD-Tree point vector.
|
||||
* * DIM: number of dimensions.
|
||||
* * operator==() and operator<<(): adapt to the number of comparisons
|
||||
* * py-kdtree.i: Add or adapt all usages of PyArg_ParseTuple() to reflect the
|
||||
* number of dimensions.
|
||||
* * adapt query_records in find_nearest() and count_within_range()
|
||||
* * Type of points.
|
||||
* * coord_t: If you want to have e.g. floats you have
|
||||
* to adapt all usages of PyArg_ParseTuple(): Change "i" to "f" e.g.
|
||||
* * Type of associated data.
|
||||
* * data_t: currently unsigned long long, which is "L" in py-kdtree.i
|
||||
* * PyArg_ParseTuple() has to be changed to reflect changes in data_t
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
#ifndef _PY_KDTREE_H_
|
||||
#define _PY_KDTREE_H_
|
||||
|
||||
#include <kdtree++/kdtree.hpp>
|
||||
|
||||
#include <iostream>
|
||||
#include <vector>
|
||||
#include <limits>
|
||||
|
||||
template <size_t DIM, typename COORD_T, typename DATA_T >
|
||||
struct record_t {
|
||||
static const size_t dim = DIM;
|
||||
typedef COORD_T coord_t;
|
||||
typedef DATA_T data_t;
|
||||
|
||||
typedef coord_t point_t[dim];
|
||||
|
||||
inline coord_t operator[](size_t const N) const { return point[N]; }
|
||||
|
||||
point_t point;
|
||||
data_t data;
|
||||
};
|
||||
|
||||
typedef double RANGE_T;
|
||||
|
||||
%%TMPL_HPP_DEFS%%
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// END OF TYPE SPECIFIC DEFINITIONS
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
template <class RECORD_T>
|
||||
inline double tac(RECORD_T r, int k) { return r[k]; }
|
||||
|
||||
template <size_t DIM, typename COORD_T, typename DATA_T >
|
||||
class PyKDTree {
|
||||
public:
|
||||
|
||||
typedef record_t<DIM, COORD_T, DATA_T> RECORD_T;
|
||||
typedef KDTree::KDTree<DIM, RECORD_T, std::pointer_to_binary_function<RECORD_T,int,double> > TREE_T;
|
||||
TREE_T tree;
|
||||
|
||||
PyKDTree() : tree(std::ptr_fun(tac<RECORD_T>)) { };
|
||||
|
||||
void add(RECORD_T T) { tree.insert(T); };
|
||||
|
||||
/**
|
||||
Exact erase.
|
||||
*/
|
||||
bool remove(RECORD_T T) {
|
||||
bool removed = false;
|
||||
|
||||
typename TREE_T::const_iterator it = tree.find_exact(T);
|
||||
if (it!=tree.end()) {
|
||||
tree.erase_exact(T);
|
||||
removed = true;
|
||||
}
|
||||
return removed;
|
||||
};
|
||||
|
||||
int size(void) { return tree.size(); }
|
||||
|
||||
void optimize(void) { tree.optimise(); }
|
||||
|
||||
RECORD_T* find_exact(RECORD_T T) {
|
||||
RECORD_T* found = NULL;
|
||||
typename TREE_T::const_iterator it = tree.find_exact(T);
|
||||
if (it!=tree.end())
|
||||
found = new RECORD_T(*it);
|
||||
|
||||
return found;
|
||||
}
|
||||
|
||||
size_t count_within_range(typename RECORD_T::point_t T, RANGE_T range) {
|
||||
RECORD_T query_record;
|
||||
memcpy(query_record.point, T, sizeof(COORD_T)*DIM);
|
||||
|
||||
return tree.count_within_range(query_record, range);
|
||||
}
|
||||
|
||||
std::vector<RECORD_T >* find_within_range(typename RECORD_T::point_t T, RANGE_T range) {
|
||||
RECORD_T query_record;
|
||||
memcpy(query_record.point, T, sizeof(COORD_T)*DIM);
|
||||
|
||||
std::vector<RECORD_T> *v = new std::vector<RECORD_T>;
|
||||
tree.find_within_range(query_record, range, std::back_inserter(*v));
|
||||
return v;
|
||||
}
|
||||
|
||||
RECORD_T* find_nearest (typename RECORD_T::point_t T) {
|
||||
RECORD_T* found = NULL;
|
||||
RECORD_T query_record;
|
||||
memcpy(query_record.point, T, sizeof(COORD_T)*DIM);
|
||||
|
||||
std::pair<typename TREE_T::const_iterator, typename TREE_T::distance_type> best =
|
||||
tree.find_nearest(query_record, std::numeric_limits<typename TREE_T::distance_type>::max());
|
||||
|
||||
if (best.first!=tree.end()) {
|
||||
found = new RECORD_T(*best.first);
|
||||
}
|
||||
return found;
|
||||
}
|
||||
|
||||
std::vector<RECORD_T >* get_all() {
|
||||
std::vector<RECORD_T>* v = new std::vector<RECORD_T>;
|
||||
|
||||
for (typename TREE_T::const_iterator iter=tree.begin(); iter!=tree.end(); ++iter) {
|
||||
v->push_back(*iter);
|
||||
}
|
||||
|
||||
return v;
|
||||
}
|
||||
|
||||
size_t __len__() { return tree.size(); }
|
||||
};
|
||||
#endif //_PY_KDTREE_H_
|
||||
27
src/3rdParty/libkdtree/python-bindings/py-kdtree.i.tmpl
vendored
Normal file
27
src/3rdParty/libkdtree/python-bindings/py-kdtree.i.tmpl
vendored
Normal file
@@ -0,0 +1,27 @@
|
||||
/** \file
|
||||
*
|
||||
* Provides a Python interface for the libkdtree++.
|
||||
*
|
||||
* \author Willi Richert <w.richert@gmx.net>
|
||||
*
|
||||
*/
|
||||
|
||||
%module kdtree
|
||||
|
||||
%{
|
||||
#define SWIG_FILE_WITH_INIT
|
||||
#include "py-kdtree.hpp"
|
||||
%}
|
||||
|
||||
|
||||
%ignore record_t::operator[];
|
||||
%ignore operator==;
|
||||
%ignore operator<<;
|
||||
%ignore KDTree::KDTree::operator=;
|
||||
%ignore tac;
|
||||
|
||||
%%TMPL_BODY%%
|
||||
|
||||
%include "py-kdtree.hpp"
|
||||
|
||||
%%TMPL_PY_CLASS_DEF%%
|
||||
96
src/3rdParty/libkdtree/python-bindings/py-kdtree_test.cpp
vendored
Normal file
96
src/3rdParty/libkdtree/python-bindings/py-kdtree_test.cpp
vendored
Normal file
@@ -0,0 +1,96 @@
|
||||
#define KDTREE_DEFINE_OSTREAM_OPERATORS
|
||||
|
||||
#include <kdtree++/kdtree.hpp>
|
||||
|
||||
#include <iostream>
|
||||
#include <vector>
|
||||
|
||||
#include "py-kdtree.hpp"
|
||||
|
||||
int main()
|
||||
{
|
||||
|
||||
|
||||
KDTree_2Int t;
|
||||
|
||||
RECORD_2il c0 = { {5, 4} }; t.add(c0);
|
||||
RECORD_2il c1 = { {4, 2} }; t.add(c1);
|
||||
RECORD_2il c2 = { {7, 6} }; t.add(c2);
|
||||
RECORD_2il c3 = { {2, 2} }; t.add(c3);
|
||||
RECORD_2il c4 = { {8, 0} }; t.add(c4);
|
||||
RECORD_2il c5 = { {5, 7} }; t.add(c5);
|
||||
RECORD_2il c6 = { {3, 3} }; t.add(c6);
|
||||
RECORD_2il c7 = { {9, 7} }; t.add(c7);
|
||||
RECORD_2il c8 = { {2, 2} }; t.add(c8);
|
||||
RECORD_2il c9 = { {2, 0} }; t.add(c9);
|
||||
|
||||
std::cout << t.tree << std::endl;
|
||||
|
||||
t.remove(c0);
|
||||
t.remove(c1);
|
||||
t.remove(c3);
|
||||
t.remove(c5);
|
||||
|
||||
t.optimize();
|
||||
|
||||
std::cout << std::endl << t.tree << std::endl;
|
||||
|
||||
int i=0;
|
||||
for (KDTREE_TYPE_2il::const_iterator iter=t.tree.begin(); iter!=t.tree.end(); ++iter, ++i);
|
||||
std::cout << "iterator walked through " << i << " nodes in total" << std::endl;
|
||||
if (i!=6)
|
||||
{
|
||||
std::cerr << "Error: does not tally with the expected number of nodes (6)" << std::endl;
|
||||
return 1;
|
||||
}
|
||||
i=0;
|
||||
for (KDTREE_TYPE_2il::const_reverse_iterator iter=t.tree.rbegin(); iter!=t.tree.rend(); ++iter, ++i);
|
||||
std::cout << "reverse_iterator walked through " << i << " nodes in total" << std::endl;
|
||||
if (i!=6)
|
||||
{
|
||||
std::cerr << "Error: does not tally with the expected number of nodes (6)" << std::endl;
|
||||
return 1;
|
||||
}
|
||||
|
||||
RECORD_2il::point_t s = {5, 4};
|
||||
std::vector<RECORD_2il> v;
|
||||
unsigned int const RANGE = 3;
|
||||
|
||||
size_t count = t.count_within_range(s, RANGE);
|
||||
std::cout << "counted " << count
|
||||
<< " nodes within range " << RANGE << " of " << s << ".\n";
|
||||
v = t.find_within_range(s, RANGE);
|
||||
|
||||
std::cout << "found " << v.size() << " nodes within range " << RANGE
|
||||
<< " of " << s << ":\n";
|
||||
std::vector<RECORD_2il>::const_iterator ci = v.begin();
|
||||
for (; ci != v.end(); ++ci)
|
||||
std::cout << *ci << " ";
|
||||
std::cout << "\n" << std::endl;
|
||||
|
||||
std::cout << "Nearest to " << s << ": " <<
|
||||
t.find_nearest(s) << std::endl;
|
||||
|
||||
RECORD_2il::point_t s2 = { 10, 10};
|
||||
std::cout << "Nearest to " << s2 << ": " <<
|
||||
t.find_nearest(s2) << std::endl;
|
||||
|
||||
std::cout << std::endl;
|
||||
|
||||
std::cout << t.tree << std::endl;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* COPYRIGHT --
|
||||
*
|
||||
* This file is part of libkdtree++, a C++ template KD-Tree sorting container.
|
||||
* libkdtree++ is (c) 2004-2007 Martin F. Krafft <libkdtree@pobox.madduck.net>
|
||||
* and Sylvain Bougerel <sylvain.bougerel.devel@gmail.com> distributed under the
|
||||
* terms of the Artistic License 2.0. See the ./COPYING file in the source tree
|
||||
* root for more information.
|
||||
*
|
||||
* THIS PACKAGE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED
|
||||
* WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES
|
||||
* OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
|
||||
*/
|
||||
400
src/3rdParty/libkdtree/python-bindings/py-kdtree_test.py
vendored
Normal file
400
src/3rdParty/libkdtree/python-bindings/py-kdtree_test.py
vendored
Normal file
@@ -0,0 +1,400 @@
|
||||
#
|
||||
# $Id: py-kdtree_test.py 2268 2008-08-20 10:08:58Z richert $
|
||||
#
|
||||
|
||||
import unittest
|
||||
|
||||
from kdtree import KDTree_2Int, KDTree_4Int, KDTree_3Float, KDTree_4Float, KDTree_6Float
|
||||
|
||||
|
||||
class KDTree_2IntTestCase(unittest.TestCase):
|
||||
def test_empty(self):
|
||||
nn = KDTree_2Int()
|
||||
self.assertEqual(0, nn.size())
|
||||
|
||||
actual = nn.find_nearest((2,3))
|
||||
self.assertTrue(None==actual, "%s != %s"%(str(None), str(actual)))
|
||||
|
||||
def test_get_all(self):
|
||||
nn = KDTree_2Int()
|
||||
o1 = object()
|
||||
nn.add(((1,1), id(o1)))
|
||||
o2 = object()
|
||||
nn.add(((10,10), id(o2)))
|
||||
o3 = object()
|
||||
nn.add(((11,11), id(o3)))
|
||||
|
||||
self.assertEqual([((1,1), id(o1)), ((10,10), id(o2)), ((11,11), id(o3))], nn.get_all())
|
||||
self.assertEqual(3, len(nn))
|
||||
|
||||
nn.remove(((10,10), id(o2)))
|
||||
self.assertEqual(2, len(nn))
|
||||
self.assertEqual([((1,1), id(o1)), ((11,11), id(o3))], nn.get_all())
|
||||
|
||||
def test_nearest(self):
|
||||
nn = KDTree_2Int()
|
||||
|
||||
nn_id = {}
|
||||
|
||||
o1 = object()
|
||||
nn.add(((1,1), id(o1)))
|
||||
nn_id[id(o1)] = o1
|
||||
o2 = object()
|
||||
nn.add(((10,10), id(o2)))
|
||||
nn_id[id(o2)] = o2
|
||||
|
||||
expected = o1
|
||||
actual = nn.find_nearest((2,2))[1]
|
||||
self.assertTrue(expected==nn_id[actual], "%s != %s"%(str(expected), str(nn_id[actual])))
|
||||
|
||||
expected = o2
|
||||
actual = nn.find_nearest((6, 6))[1]
|
||||
self.assertTrue(expected==nn_id[actual], "%s != %s"%(str(expected), str(nn_id[actual])))
|
||||
|
||||
def test_find_within_range(self):
|
||||
nn = KDTree_6Float()
|
||||
|
||||
nn_id = {}
|
||||
|
||||
o1 = object()
|
||||
nn.add(((1,1,0,0,0,0), id(o1)))
|
||||
nn_id[id(o1)] = o1
|
||||
o2 = object()
|
||||
nn.add(((10,10,0,0,0,0), id(o2)))
|
||||
nn_id[id(o2)] = o2
|
||||
o3 = object()
|
||||
nn.add(((4.1, 4.1,0,0,0,0), id(o3)))
|
||||
nn_id[id(o3)] = o3
|
||||
|
||||
expected = set([long(id(o1)), long(id(o3))])
|
||||
actual = set([ident
|
||||
for _coord, ident
|
||||
in nn.find_within_range((2.1,2.1,0,0,0,0), 3.9)])
|
||||
self.assertTrue(expected==actual, "%s != %s"%(str(expected), str(actual)))
|
||||
|
||||
|
||||
def test_remove(self):
|
||||
class C:
|
||||
def __init__(self, i):
|
||||
self.i = i
|
||||
self.next = None
|
||||
|
||||
nn = KDTree_2Int()
|
||||
|
||||
k1, o1 = (1,1), C(7)
|
||||
self.assertFalse(nn.remove((k1, id(o1))), "This cannot be removed!")
|
||||
nn.add((k1, id(o1)))
|
||||
|
||||
k2, o2 = (1,1), C(7)
|
||||
nn.add((k2, id(o2)))
|
||||
|
||||
self.assertEqual(2, nn.size())
|
||||
self.assertTrue(nn.remove((k2, id(o2))))
|
||||
self.assertEqual(1, nn.size())
|
||||
self.assertFalse(nn.remove((k2, id(o2))))
|
||||
self.assertEqual(1, nn.size())
|
||||
|
||||
nearest = nn.find_nearest(k1)
|
||||
self.assertTrue(nearest[1] == id(o1), "%s != %s"%(nearest[1], o1))
|
||||
#self.assertTrue(nearest[1] is o1, "%s,%s is not %s"%(str(nearest[0]), str(nearest[1]), str((k1,id(o1)))))
|
||||
|
||||
def test_count_within_range(self):
|
||||
nn = KDTree_2Int()
|
||||
|
||||
for p in [(0,0), (1,0), (0,1), (1,1)]:
|
||||
nn.add((p, id(p)))
|
||||
|
||||
res = nn.count_within_range((0,0), 1.0)
|
||||
self.assertEqual(3, res, "Counted %i points instead of %i"%(res, 3))
|
||||
|
||||
res = nn.count_within_range((0,0), 1.9)
|
||||
self.assertEqual(4, res, "Counted %i points instead of %i"%(res, 4))
|
||||
|
||||
class KDTree_4IntTestCase(unittest.TestCase):
|
||||
def test_empty(self):
|
||||
nn = KDTree_4Int()
|
||||
self.assertEqual(0, nn.size())
|
||||
|
||||
actual = nn.find_nearest((0,0,2,3))
|
||||
self.assertTrue(None==actual, "%s != %s"%(str(None), str(actual)))
|
||||
|
||||
def test_get_all(self):
|
||||
nn = KDTree_4Int()
|
||||
o1 = object()
|
||||
nn.add(((0,0,1,1), id(o1)))
|
||||
o2 = object()
|
||||
nn.add(((0,0,10,10), id(o2)))
|
||||
o3 = object()
|
||||
nn.add(((0,0,11,11), id(o3)))
|
||||
|
||||
self.assertEqual([((0,0,1,1), id(o1)), ((0,0,10,10), id(o2)), ((0,0,11,11), id(o3))], nn.get_all())
|
||||
self.assertEqual(3, len(nn))
|
||||
|
||||
nn.remove(((0,0,10,10), id(o2)))
|
||||
self.assertEqual(2, len(nn))
|
||||
self.assertEqual([((0,0,1,1), id(o1)), ((0,0,11,11), id(o3))], nn.get_all())
|
||||
|
||||
def test_nearest(self):
|
||||
nn = KDTree_4Int()
|
||||
|
||||
nn_id = {}
|
||||
|
||||
o1 = object()
|
||||
nn.add(((0,0,1,1), id(o1)))
|
||||
nn_id[id(o1)] = o1
|
||||
o2 = object()
|
||||
nn.add(((0,0,10,10), id(o2)))
|
||||
nn_id[id(o2)] = o2
|
||||
|
||||
expected = o1
|
||||
actual = nn.find_nearest((0,0,2,2))[1]
|
||||
self.assertTrue(expected==nn_id[actual], "%s != %s"%(str(expected), str(nn_id[actual])))
|
||||
|
||||
expected = o2
|
||||
actual = nn.find_nearest((0,0,6,6))[1]
|
||||
self.assertTrue(expected==nn_id[actual], "%s != %s"%(str(expected), str(nn_id[actual])))
|
||||
|
||||
def test_remove(self):
|
||||
class C:
|
||||
def __init__(self, i):
|
||||
self.i = i
|
||||
self.next = None
|
||||
|
||||
nn = KDTree_4Int()
|
||||
|
||||
k1, o1 = (0,0,1,1), C(7)
|
||||
self.assertFalse(nn.remove((k1, id(o1))), "This cannot be removed!")
|
||||
nn.add((k1, id(o1)))
|
||||
|
||||
k2, o2 = (0,0,1,1), C(7)
|
||||
nn.add((k2, id(o2)))
|
||||
|
||||
self.assertEqual(2, nn.size())
|
||||
self.assertTrue(nn.remove((k2, id(o2))))
|
||||
self.assertEqual(1, nn.size())
|
||||
self.assertFalse(nn.remove((k2, id(o2))))
|
||||
self.assertEqual(1, nn.size())
|
||||
|
||||
nearest = nn.find_nearest(k1)
|
||||
self.assertTrue(nearest[1] == id(o1), "%s != %s"%(nearest[1], o1))
|
||||
#self.assertTrue(nearest[1] is o1, "%s,%s is not %s"%(str(nearest[0]), str(nearest[1]), str((k1,id(o1)))))
|
||||
|
||||
class KDTree_4FloatTestCase(unittest.TestCase):
|
||||
def test_empty(self):
|
||||
nn = KDTree_4Float()
|
||||
self.assertEqual(0, nn.size())
|
||||
|
||||
actual = nn.find_nearest((0,0,2,3))
|
||||
self.assertTrue(None==actual, "%s != %s"%(str(None), str(actual)))
|
||||
|
||||
def test_get_all(self):
|
||||
nn = KDTree_4Int()
|
||||
o1 = object()
|
||||
nn.add(((0,0,1,1), id(o1)))
|
||||
o2 = object()
|
||||
nn.add(((0,0,10,10), id(o2)))
|
||||
o3 = object()
|
||||
nn.add(((0,0,11,11), id(o3)))
|
||||
|
||||
self.assertEqual([((0,0,1,1), id(o1)), ((0,0,10,10), id(o2)), ((0,0,11,11), id(o3))], nn.get_all())
|
||||
self.assertEqual(3, len(nn))
|
||||
|
||||
nn.remove(((0,0,10,10), id(o2)))
|
||||
self.assertEqual(2, len(nn))
|
||||
self.assertEqual([((0,0,1,1), id(o1)), ((0,0,11,11), id(o3))], nn.get_all())
|
||||
|
||||
def test_nearest(self):
|
||||
nn = KDTree_4Int()
|
||||
|
||||
nn_id = {}
|
||||
|
||||
o1 = object()
|
||||
nn.add(((0,0,1,1), id(o1)))
|
||||
nn_id[id(o1)] = o1
|
||||
o2 = object()
|
||||
nn.add(((0,0,10,10), id(o2)))
|
||||
nn_id[id(o2)] = o2
|
||||
|
||||
expected = o1
|
||||
actual = nn.find_nearest((0,0,2,2))[1]
|
||||
self.assertTrue(expected==nn_id[actual], "%s != %s"%(str(expected), str(nn_id[actual])))
|
||||
|
||||
expected = o2
|
||||
actual = nn.find_nearest((0,0,6,6))[1]
|
||||
self.assertTrue(expected==nn_id[actual], "%s != %s"%(str(expected), str(nn_id[actual])))
|
||||
|
||||
def test_remove(self):
|
||||
class C:
|
||||
def __init__(self, i):
|
||||
self.i = i
|
||||
self.next = None
|
||||
|
||||
nn = KDTree_4Int()
|
||||
|
||||
k1, o1 = (0,0,1,1), C(7)
|
||||
self.assertFalse(nn.remove((k1, id(o1))), "This cannot be removed!")
|
||||
nn.add((k1, id(o1)))
|
||||
|
||||
k2, o2 = (0,0,1,1), C(7)
|
||||
nn.add((k2, id(o2)))
|
||||
|
||||
self.assertEqual(2, nn.size())
|
||||
self.assertTrue(nn.remove((k2, id(o2))))
|
||||
self.assertEqual(1, nn.size())
|
||||
self.assertFalse(nn.remove((k2, id(o2))))
|
||||
self.assertEqual(1, nn.size())
|
||||
|
||||
nearest = nn.find_nearest(k1)
|
||||
self.assertTrue(nearest[1] == id(o1), "%s != %s"%(nearest[1], o1))
|
||||
#self.assertTrue(nearest[1] is o1, "%s,%s is not %s"%(str(nearest[0]), str(nearest[1]), str((k1,id(o1)))))
|
||||
|
||||
class KDTree_3FloatTestCase(unittest.TestCase):
|
||||
def test_empty(self):
|
||||
nn = KDTree_3Float()
|
||||
self.assertEqual(0, nn.size())
|
||||
|
||||
actual = nn.find_nearest((2,3,0))
|
||||
self.assertTrue(None==actual, "%s != %s"%(str(None), str(actual)))
|
||||
|
||||
def test_get_all(self):
|
||||
nn = KDTree_3Float()
|
||||
o1 = object()
|
||||
nn.add(((1,1,0), id(o1)))
|
||||
o2 = object()
|
||||
nn.add(((10,10,0), id(o2)))
|
||||
o3 = object()
|
||||
nn.add(((11,11,0), id(o3)))
|
||||
|
||||
self.assertEqual([((1,1,0), id(o1)), ((10,10,0), id(o2)), ((11,11,0), id(o3))], nn.get_all())
|
||||
self.assertEqual(3, len(nn))
|
||||
|
||||
nn.remove(((10,10,0), id(o2)))
|
||||
self.assertEqual(2, len(nn))
|
||||
self.assertEqual([((1,1,0), id(o1)), ((11,11,0), id(o3))], nn.get_all())
|
||||
|
||||
def test_nearest(self):
|
||||
nn = KDTree_3Float()
|
||||
|
||||
nn_id = {}
|
||||
|
||||
o1 = object()
|
||||
nn.add(((1,1,0), id(o1)))
|
||||
nn_id[id(o1)] = o1
|
||||
o2 = object()
|
||||
nn.add(((10,10,0), id(o2)))
|
||||
nn_id[id(o2)] = o2
|
||||
o3 = object()
|
||||
nn.add(((4.1, 4.1,0), id(o3)))
|
||||
nn_id[id(o3)] = o3
|
||||
|
||||
expected = o3
|
||||
actual = nn.find_nearest((2.9,2.9,0))[1]
|
||||
self.assertTrue(expected==nn_id[actual], "%s != %s"%(str(expected), str(nn_id[actual])))
|
||||
|
||||
expected = o3
|
||||
actual = nn.find_nearest((6, 6,0))[1]
|
||||
self.assertTrue(expected==nn_id[actual], "%s != %s"%(str(expected), str(nn_id[actual])))
|
||||
|
||||
def test_remove(self):
|
||||
class C:
|
||||
def __init__(self, i):
|
||||
self.i = i
|
||||
self.next = None
|
||||
|
||||
nn = KDTree_3Float()
|
||||
|
||||
k1, o1 = (1.1,1.1,0), C(7)
|
||||
self.assertFalse(nn.remove((k1, id(o1))), "This cannot be removed!")
|
||||
nn.add((k1, id(o1)))
|
||||
|
||||
k2, o2 = (1.1,1.1,0), C(7)
|
||||
nn.add((k2, id(o2)))
|
||||
|
||||
self.assertEqual(2, nn.size())
|
||||
self.assertTrue(nn.remove((k2, id(o2))))
|
||||
self.assertEqual(1, nn.size())
|
||||
self.assertFalse(nn.remove((k2, id(o2))))
|
||||
self.assertEqual(1, nn.size())
|
||||
|
||||
nearest = nn.find_nearest(k1)
|
||||
self.assertTrue(nearest[1] == id(o1), "%s != %s"%(nearest[1], o1))
|
||||
#self.assertTrue(nearest[1] is o1, "%s,%s is not %s"%(str(nearest[0]), str(nearest[1]), str((k1,id(o1)))))
|
||||
|
||||
class KDTree_6FloatTestCase(unittest.TestCase):
|
||||
def test_empty(self):
|
||||
nn = KDTree_6Float()
|
||||
self.assertEqual(0, nn.size())
|
||||
|
||||
actual = nn.find_nearest((2,3,0,0,0,0))
|
||||
self.assertTrue(None==actual, "%s != %s"%(str(None), str(actual)))
|
||||
|
||||
def test_get_all(self):
|
||||
nn = KDTree_6Float()
|
||||
o1 = object()
|
||||
nn.add(((1,1,0,0,0,0), id(o1)))
|
||||
o2 = object()
|
||||
nn.add(((10,10,0,0,0,0), id(o2)))
|
||||
o3 = object()
|
||||
nn.add(((11,11,0,0,0,0), id(o3)))
|
||||
|
||||
self.assertEqual([((1,1,0,0,0,0), id(o1)), ((10,10,0,0,0,0), id(o2)), ((11,11,0,0,0,0 ), id(o3))], nn.get_all())
|
||||
self.assertEqual(3, len(nn))
|
||||
|
||||
nn.remove(((10,10,0,0,0,0), id(o2)))
|
||||
self.assertEqual(2, len(nn))
|
||||
self.assertEqual([((1,1,0,0,0,0), id(o1)), ((11,11,0,0,0,0), id(o3))], nn.get_all())
|
||||
|
||||
def test_nearest(self):
|
||||
nn = KDTree_6Float()
|
||||
|
||||
nn_id = {}
|
||||
|
||||
o1 = object()
|
||||
nn.add(((1,1,0,0,0,0), id(o1)))
|
||||
nn_id[id(o1)] = o1
|
||||
o2 = object()
|
||||
nn.add(((10,10,0,0,0,0), id(o2)))
|
||||
nn_id[id(o2)] = o2
|
||||
o3 = object()
|
||||
nn.add(((4.1, 4.1,0,0,0,0), id(o3)))
|
||||
nn_id[id(o3)] = o3
|
||||
|
||||
expected = o3
|
||||
actual = nn.find_nearest((2.9,2.9,0,0,0,0))[1]
|
||||
self.assertTrue(expected==nn_id[actual], "%s != %s"%(str(expected), str(nn_id[actual])))
|
||||
|
||||
expected = o3
|
||||
actual = nn.find_nearest((6, 6,0,0,0,0))[1]
|
||||
self.assertTrue(expected==nn_id[actual], "%s != %s"%(str(expected), str(nn_id[actual])))
|
||||
|
||||
def test_remove(self):
|
||||
class C:
|
||||
def __init__(self, i):
|
||||
self.i = i
|
||||
self.next = None
|
||||
|
||||
nn = KDTree_6Float()
|
||||
|
||||
k1, o1 = (1.1,1.1,0,0,0,0), C(7)
|
||||
self.assertFalse(nn.remove((k1, id(o1))), "This cannot be removed!")
|
||||
nn.add((k1, id(o1)))
|
||||
|
||||
k2, o2 = (1.1,1.1,0,0,0,0), C(7)
|
||||
nn.add((k2, id(o2)))
|
||||
|
||||
self.assertEqual(2, nn.size())
|
||||
self.assertTrue(nn.remove((k2, id(o2))))
|
||||
self.assertEqual(1, nn.size())
|
||||
self.assertFalse(nn.remove((k2, id(o2))))
|
||||
self.assertEqual(1, nn.size())
|
||||
|
||||
nearest = nn.find_nearest(k1)
|
||||
self.assertTrue(nearest[1] == id(o1), "%s != %s"%(nearest[1], o1))
|
||||
#self.assertTrue(nearest[1] is o1, "%s,%s is not %s"%(str(nearest[0]), str(nearest[1]), str((k1,id(o1)))))
|
||||
|
||||
|
||||
def suite():
|
||||
return unittest.defaultTestLoader.loadTestsFromModule(sys.modules.get(__name__))
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main()
|
||||
@@ -5,7 +5,7 @@ endif(WIN32)
|
||||
include_directories(
|
||||
${CMAKE_CURRENT_BINARY_DIR}
|
||||
${CMAKE_CURRENT_SOURCE_DIR}
|
||||
${CMAKE_SOURCE_DIR}/src/3rdParty
|
||||
${CMAKE_SOURCE_DIR}/src/3rdParty/libkdtree
|
||||
${Boost_INCLUDE_DIRS}
|
||||
${PYTHON_INCLUDE_DIRS}
|
||||
${XercesC_INCLUDE_DIRS}
|
||||
@@ -50,6 +50,8 @@ SET(Core_SRCS
|
||||
Core/Builder.h
|
||||
Core/Curvature.cpp
|
||||
Core/Curvature.h
|
||||
Core/Decimation.cpp
|
||||
Core/Decimation.h
|
||||
Core/Definitions.cpp
|
||||
Core/Definitions.h
|
||||
Core/Degeneration.cpp
|
||||
@@ -64,6 +66,8 @@ SET(Core_SRCS
|
||||
Core/Info.cpp
|
||||
Core/Info.h
|
||||
Core/Iterator.h
|
||||
Core/KDTree.cpp
|
||||
Core/KDTree.h
|
||||
Core/MeshIO.cpp
|
||||
Core/MeshIO.h
|
||||
Core/MeshKernel.cpp
|
||||
|
||||
97
src/Mod/Mesh/App/Core/Decimation.cpp
Normal file
97
src/Mod/Mesh/App/Core/Decimation.cpp
Normal file
@@ -0,0 +1,97 @@
|
||||
/***************************************************************************
|
||||
* Copyright (c) 2013 Werner Mayer <wmayer[at]users.sourceforge.net> *
|
||||
* *
|
||||
* This file is part of the FreeCAD CAx development system. *
|
||||
* *
|
||||
* This library is free software; you can redistribute it and/or *
|
||||
* modify it under the terms of the GNU Library General Public *
|
||||
* License as published by the Free Software Foundation; either *
|
||||
* version 2 of the License, or (at your option) any later version. *
|
||||
* *
|
||||
* This library is distributed in the hope that it will be useful, *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
* GNU Library General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU Library General Public *
|
||||
* License along with this library; see the file COPYING.LIB. If not, *
|
||||
* write to the Free Software Foundation, Inc., 59 Temple Place, *
|
||||
* Suite 330, Boston, MA 02111-1307, USA *
|
||||
* *
|
||||
***************************************************************************/
|
||||
|
||||
|
||||
#include "PreCompiled.h"
|
||||
#ifndef _PreComp_
|
||||
#endif
|
||||
|
||||
#include "Decimation.h"
|
||||
#include "MeshKernel.h"
|
||||
#include "Algorithm.h"
|
||||
#include "Iterator.h"
|
||||
#include "TopoAlgorithm.h"
|
||||
#include <Base/Tools.h>
|
||||
#include "Simplify.h"
|
||||
|
||||
|
||||
using namespace MeshCore;
|
||||
|
||||
MeshSimplify::MeshSimplify(MeshKernel& mesh)
|
||||
: myKernel(mesh)
|
||||
{
|
||||
}
|
||||
|
||||
MeshSimplify::~MeshSimplify()
|
||||
{
|
||||
}
|
||||
|
||||
void MeshSimplify::simplify(float tolerance, float reduction)
|
||||
{
|
||||
Simplify alg;
|
||||
|
||||
const MeshPointArray& points = myKernel.GetPoints();
|
||||
for (std::size_t i = 0; i < points.size(); i++) {
|
||||
Simplify::Vertex v;
|
||||
v.p = points[i];
|
||||
alg.vertices.push_back(v);
|
||||
}
|
||||
|
||||
const MeshFacetArray& facets = myKernel.GetFacets();
|
||||
for (std::size_t i = 0; i < facets.size(); i++) {
|
||||
Simplify::Triangle t;
|
||||
for (int j = 0; j < 3; j++)
|
||||
t.v[j] = facets[i]._aulPoints[j];
|
||||
alg.triangles.push_back(t);
|
||||
}
|
||||
|
||||
int target_count = static_cast<int>(static_cast<float>(facets.size()) * (1.0f-reduction));
|
||||
|
||||
// Simplification starts
|
||||
alg.simplify_mesh(target_count, tolerance);
|
||||
|
||||
// Simplification done
|
||||
MeshPointArray new_points;
|
||||
new_points.reserve(alg.vertices.size());
|
||||
for (std::size_t i = 0; i < alg.vertices.size(); i++) {
|
||||
new_points.push_back(alg.vertices[i].p);
|
||||
}
|
||||
|
||||
std::size_t numFacets = 0;
|
||||
for (std::size_t i = 0; i < alg.triangles.size(); i++) {
|
||||
if (!alg.triangles[i].deleted)
|
||||
numFacets++;
|
||||
}
|
||||
MeshFacetArray new_facets;
|
||||
new_facets.reserve(numFacets);
|
||||
for (std::size_t i = 0; i < alg.triangles.size(); i++) {
|
||||
if (!alg.triangles[i].deleted) {
|
||||
MeshFacet face;
|
||||
face._aulPoints[0] = alg.triangles[i].v[0];
|
||||
face._aulPoints[1] = alg.triangles[i].v[1];
|
||||
face._aulPoints[2] = alg.triangles[i].v[2];
|
||||
new_facets.push_back(face);
|
||||
}
|
||||
}
|
||||
|
||||
myKernel.Adopt(new_points, new_facets, true);
|
||||
}
|
||||
46
src/Mod/Mesh/App/Core/Decimation.h
Normal file
46
src/Mod/Mesh/App/Core/Decimation.h
Normal file
@@ -0,0 +1,46 @@
|
||||
/***************************************************************************
|
||||
* Copyright (c) 2013 Werner Mayer <wmayer[at]users.sourceforge.net> *
|
||||
* *
|
||||
* This file is part of the FreeCAD CAx development system. *
|
||||
* *
|
||||
* This library is free software; you can redistribute it and/or *
|
||||
* modify it under the terms of the GNU Library General Public *
|
||||
* License as published by the Free Software Foundation; either *
|
||||
* version 2 of the License, or (at your option) any later version. *
|
||||
* *
|
||||
* This library is distributed in the hope that it will be useful, *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
* GNU Library General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU Library General Public *
|
||||
* License along with this library; see the file COPYING.LIB. If not, *
|
||||
* write to the Free Software Foundation, Inc., 59 Temple Place, *
|
||||
* Suite 330, Boston, MA 02111-1307, USA *
|
||||
* *
|
||||
***************************************************************************/
|
||||
|
||||
|
||||
#ifndef MESH_DECIMATION_H
|
||||
#define MESH_DECIMATION_H
|
||||
|
||||
|
||||
namespace MeshCore
|
||||
{
|
||||
class MeshKernel;
|
||||
|
||||
class MeshExport MeshSimplify
|
||||
{
|
||||
public:
|
||||
MeshSimplify(MeshKernel&);
|
||||
~MeshSimplify();
|
||||
void simplify(float tolerance, float reduction);
|
||||
|
||||
private:
|
||||
MeshKernel& myKernel;
|
||||
};
|
||||
|
||||
} // namespace MeshCore
|
||||
|
||||
|
||||
#endif // MESH_DECIMATION_H
|
||||
155
src/Mod/Mesh/App/Core/KDTree.cpp
Normal file
155
src/Mod/Mesh/App/Core/KDTree.cpp
Normal file
@@ -0,0 +1,155 @@
|
||||
/***************************************************************************
|
||||
* Copyright (c) 2011 Werner Mayer <wmayer[at]users.sourceforge.net> *
|
||||
* *
|
||||
* This file is part of the FreeCAD CAx development system. *
|
||||
* *
|
||||
* This library is free software; you can redistribute it and/or *
|
||||
* modify it under the terms of the GNU Library General Public *
|
||||
* License as published by the Free Software Foundation; either *
|
||||
* version 2 of the License, or (at your option) any later version. *
|
||||
* *
|
||||
* This library is distributed in the hope that it will be useful, *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
* GNU Library General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU Library General Public *
|
||||
* License along with this library; see the file COPYING.LIB. If not, *
|
||||
* write to the Free Software Foundation, Inc., 59 Temple Place, *
|
||||
* Suite 330, Boston, MA 02111-1307, USA *
|
||||
* *
|
||||
***************************************************************************/
|
||||
|
||||
|
||||
#include "PreCompiled.h"
|
||||
#ifdef _MSC_VER
|
||||
# pragma warning(disable : 4396)
|
||||
#endif
|
||||
#ifndef _PreComp_
|
||||
#endif
|
||||
|
||||
#include "KDTree.h"
|
||||
#include <kdtree++/kdtree.hpp>
|
||||
|
||||
using namespace MeshCore;
|
||||
|
||||
struct Point3d
|
||||
{
|
||||
typedef float value_type;
|
||||
|
||||
Point3d(const Base::Vector3f& f, unsigned long i) : p(f), i(i)
|
||||
{
|
||||
}
|
||||
|
||||
inline value_type operator[](const int N) const
|
||||
{
|
||||
return p[N];
|
||||
}
|
||||
|
||||
inline bool operator==(const Point3d& other) const
|
||||
{
|
||||
return (this->p) == (other.p);
|
||||
}
|
||||
|
||||
inline bool operator!=(const Point3d& other) const
|
||||
{
|
||||
return (this->p) != (other.p);
|
||||
}
|
||||
|
||||
inline void operator=(const Point3d& other)
|
||||
{
|
||||
this->p = other.p;
|
||||
this->i = other.i;
|
||||
}
|
||||
|
||||
Base::Vector3f p;
|
||||
unsigned long i;
|
||||
};
|
||||
|
||||
typedef KDTree::KDTree<3, Point3d> MyKDTree;
|
||||
|
||||
class MeshKDTree::Private
|
||||
{
|
||||
public:
|
||||
MyKDTree kd_tree;
|
||||
};
|
||||
|
||||
MeshKDTree::MeshKDTree(const std::vector<Base::Vector3f>& points) : d(new Private)
|
||||
{
|
||||
unsigned long index=0;
|
||||
for (std::vector<Base::Vector3f>::const_iterator it = points.begin(); it != points.end(); ++it) {
|
||||
d->kd_tree.insert(Point3d(*it, index++));
|
||||
}
|
||||
}
|
||||
|
||||
MeshKDTree::MeshKDTree(const MeshPointArray& points) : d(new Private)
|
||||
{
|
||||
unsigned long index=0;
|
||||
for (MeshPointArray::_TConstIterator it = points.begin(); it != points.end(); ++it) {
|
||||
d->kd_tree.insert(Point3d(*it, index++));
|
||||
}
|
||||
}
|
||||
|
||||
MeshKDTree::~MeshKDTree()
|
||||
{
|
||||
delete d;
|
||||
}
|
||||
|
||||
bool MeshKDTree::IsEmpty() const
|
||||
{
|
||||
return d->kd_tree.empty();
|
||||
}
|
||||
|
||||
void MeshKDTree::Clear()
|
||||
{
|
||||
d->kd_tree.clear();
|
||||
}
|
||||
|
||||
void MeshKDTree::Optimize()
|
||||
{
|
||||
d->kd_tree.optimize();
|
||||
}
|
||||
|
||||
unsigned long MeshKDTree::FindNearest(const Base::Vector3f& p, Base::Vector3f& n, float& dist) const
|
||||
{
|
||||
std::pair<MyKDTree::const_iterator, MyKDTree::distance_type> it =
|
||||
d->kd_tree.find_nearest(Point3d(p,0));
|
||||
if (it.first == d->kd_tree.end())
|
||||
return ULONG_MAX;
|
||||
unsigned long index = it.first->i;
|
||||
n = it.first->p;
|
||||
dist = it.second;
|
||||
return index;
|
||||
}
|
||||
|
||||
unsigned long MeshKDTree::FindNearest(const Base::Vector3f& p, float max_dist,
|
||||
Base::Vector3f& n, float& dist) const
|
||||
{
|
||||
std::pair<MyKDTree::const_iterator, MyKDTree::distance_type> it =
|
||||
d->kd_tree.find_nearest(Point3d(p,0), max_dist);
|
||||
if (it.first == d->kd_tree.end())
|
||||
return ULONG_MAX;
|
||||
unsigned long index = it.first->i;
|
||||
n = it.first->p;
|
||||
dist = it.second;
|
||||
return index;
|
||||
}
|
||||
|
||||
unsigned long MeshKDTree::FindExact(const Base::Vector3f& p) const
|
||||
{
|
||||
MyKDTree::const_iterator it =
|
||||
d->kd_tree.find_exact(Point3d(p,0));
|
||||
if (it == d->kd_tree.end())
|
||||
return ULONG_MAX;
|
||||
unsigned long index = it->i;
|
||||
return index;
|
||||
}
|
||||
|
||||
void MeshKDTree::FindInRange(const Base::Vector3f& p, float range, std::vector<unsigned long>& indices) const
|
||||
{
|
||||
std::vector<Point3d> v;
|
||||
d->kd_tree.find_within_range(Point3d(p,0), range, std::back_inserter(v));
|
||||
indices.reserve(v.size());
|
||||
for (std::vector<Point3d>::iterator it = v.begin(); it != v.end(); ++it)
|
||||
indices.push_back(it->i);
|
||||
}
|
||||
60
src/Mod/Mesh/App/Core/KDTree.h
Normal file
60
src/Mod/Mesh/App/Core/KDTree.h
Normal file
@@ -0,0 +1,60 @@
|
||||
/***************************************************************************
|
||||
* Copyright (c) 2011 Werner Mayer <wmayer[at]users.sourceforge.net> *
|
||||
* *
|
||||
* This file is part of the FreeCAD CAx development system. *
|
||||
* *
|
||||
* This library is free software; you can redistribute it and/or *
|
||||
* modify it under the terms of the GNU Library General Public *
|
||||
* License as published by the Free Software Foundation; either *
|
||||
* version 2 of the License, or (at your option) any later version. *
|
||||
* *
|
||||
* This library is distributed in the hope that it will be useful, *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
* GNU Library General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU Library General Public *
|
||||
* License along with this library; see the file COPYING.LIB. If not, *
|
||||
* write to the Free Software Foundation, Inc., 59 Temple Place, *
|
||||
* Suite 330, Boston, MA 02111-1307, USA *
|
||||
* *
|
||||
***************************************************************************/
|
||||
|
||||
|
||||
#ifndef MESH_KDTREE_H
|
||||
#define MESH_KDTREE_H
|
||||
|
||||
#include "Elements.h"
|
||||
|
||||
namespace MeshCore
|
||||
{
|
||||
|
||||
class MeshExport MeshKDTree
|
||||
{
|
||||
public:
|
||||
MeshKDTree(const std::vector<Base::Vector3f>& points);
|
||||
MeshKDTree(const MeshPointArray& points);
|
||||
~MeshKDTree();
|
||||
|
||||
bool IsEmpty() const;
|
||||
void Clear();
|
||||
void Optimize();
|
||||
|
||||
unsigned long FindNearest(const Base::Vector3f& p, Base::Vector3f& n, float&) const;
|
||||
unsigned long FindNearest(const Base::Vector3f& p, float max_dist,
|
||||
Base::Vector3f& n, float&) const;
|
||||
unsigned long FindExact(const Base::Vector3f& p) const;
|
||||
void FindInRange(const Base::Vector3f&, float, std::vector<unsigned long>&) const;
|
||||
|
||||
private:
|
||||
class Private;
|
||||
Private* d;
|
||||
|
||||
MeshKDTree(const MeshKDTree&);
|
||||
void operator= (const MeshKDTree&);
|
||||
};
|
||||
|
||||
} // namespace MeshCore
|
||||
|
||||
|
||||
#endif // MESH_KDTREE_H
|
||||
518
src/Mod/Mesh/App/Core/Simplify.h
Normal file
518
src/Mod/Mesh/App/Core/Simplify.h
Normal file
@@ -0,0 +1,518 @@
|
||||
// http://voxels.blogspot.de/2014/05/quadric-mesh-simplification-with-source.html
|
||||
// https://github.com/sp4cerat/Fast-Quadric-Mesh-Simplification
|
||||
//
|
||||
// MIT License
|
||||
|
||||
// Changes:
|
||||
// * Use Base::Vector3f as vec3f class
|
||||
// * Move global variables to a class to make the algorithm usable for multi-threading
|
||||
// * Comment out printf statements
|
||||
// * Fix compiler warnings
|
||||
// * Remove macros loop,i,j,k
|
||||
|
||||
#include <vector>
|
||||
#include <Base/Vector3D.h>
|
||||
|
||||
#define _USE_MATH_DEFINES
|
||||
|
||||
typedef Base::Vector3f vec3f;
|
||||
|
||||
class SymetricMatrix {
|
||||
|
||||
public:
|
||||
|
||||
// Constructor
|
||||
|
||||
SymetricMatrix(double c=0) { for (std::size_t i=0;i<10;++i ) m[i] = c; }
|
||||
|
||||
SymetricMatrix(double m11, double m12, double m13, double m14,
|
||||
double m22, double m23, double m24,
|
||||
double m33, double m34,
|
||||
double m44) {
|
||||
m[0] = m11; m[1] = m12; m[2] = m13; m[3] = m14;
|
||||
m[4] = m22; m[5] = m23; m[6] = m24;
|
||||
m[7] = m33; m[8] = m34;
|
||||
m[9] = m44;
|
||||
}
|
||||
|
||||
// Make plane
|
||||
|
||||
SymetricMatrix(double a,double b,double c,double d)
|
||||
{
|
||||
m[0] = a*a; m[1] = a*b; m[2] = a*c; m[3] = a*d;
|
||||
m[4] = b*b; m[5] = b*c; m[6] = b*d;
|
||||
m[7 ] =c*c; m[8 ] = c*d;
|
||||
m[9 ] = d*d;
|
||||
}
|
||||
|
||||
double operator[](int c) const { return m[c]; }
|
||||
|
||||
// Determinant
|
||||
|
||||
double det(int a11, int a12, int a13,
|
||||
int a21, int a22, int a23,
|
||||
int a31, int a32, int a33)
|
||||
{
|
||||
double det = m[a11]*m[a22]*m[a33] + m[a13]*m[a21]*m[a32] + m[a12]*m[a23]*m[a31]
|
||||
- m[a13]*m[a22]*m[a31] - m[a11]*m[a23]*m[a32]- m[a12]*m[a21]*m[a33];
|
||||
return det;
|
||||
}
|
||||
|
||||
const SymetricMatrix operator+(const SymetricMatrix& n) const
|
||||
{
|
||||
return SymetricMatrix( m[0]+n[0], m[1]+n[1], m[2]+n[2], m[3]+n[3],
|
||||
m[4]+n[4], m[5]+n[5], m[6]+n[6],
|
||||
m[ 7]+n[ 7], m[ 8]+n[8 ],
|
||||
m[ 9]+n[9 ]);
|
||||
}
|
||||
|
||||
SymetricMatrix& operator+=(const SymetricMatrix& n)
|
||||
{
|
||||
m[0]+=n[0]; m[1]+=n[1]; m[2]+=n[2]; m[3]+=n[3];
|
||||
m[4]+=n[4]; m[5]+=n[5]; m[6]+=n[6]; m[7]+=n[7];
|
||||
m[8]+=n[8]; m[9]+=n[9];
|
||||
return *this;
|
||||
}
|
||||
|
||||
double m[10];
|
||||
};
|
||||
///////////////////////////////////////////
|
||||
|
||||
class Simplify
|
||||
{
|
||||
public:
|
||||
struct Triangle { int v[3];double err[4];int deleted,dirty;vec3f n; };
|
||||
struct Vertex { vec3f p;int tstart,tcount;SymetricMatrix q;int border;};
|
||||
struct Ref { int tid,tvertex; };
|
||||
std::vector<Triangle> triangles;
|
||||
std::vector<Vertex> vertices;
|
||||
std::vector<Ref> refs;
|
||||
|
||||
void simplify_mesh(int target_count, double tolerance_factor, double agressiveness=7);
|
||||
|
||||
private:
|
||||
// Helper functions
|
||||
|
||||
double vertex_error(SymetricMatrix q, double x, double y, double z);
|
||||
double calculate_error(int id_v1, int id_v2, vec3f &p_result);
|
||||
bool flipped(vec3f p,int i0,int i1,Vertex &v0,Vertex &v1,std::vector<int> &deleted);
|
||||
void update_triangles(int i0,Vertex &v,std::vector<int> &deleted,int &deleted_triangles);
|
||||
void update_mesh(int iteration);
|
||||
void compact_mesh();
|
||||
};
|
||||
|
||||
//
|
||||
// Main simplification function
|
||||
//
|
||||
// target_count : target nr. of triangles
|
||||
// agressiveness : sharpness to increase the threashold.
|
||||
// 5..8 are good numbers
|
||||
// more iterations yield higher quality
|
||||
//
|
||||
void Simplify::simplify_mesh(int target_count, double tolerance_factor, double agressiveness)
|
||||
{
|
||||
(void)tolerance_factor;
|
||||
// init
|
||||
//printf("%s - start\n",__FUNCTION__);
|
||||
//int timeStart=timeGetTime();
|
||||
|
||||
for (std::size_t i=0;i<triangles.size();++i)
|
||||
triangles[i].deleted=0;
|
||||
|
||||
// main iteration loop
|
||||
|
||||
int deleted_triangles=0;
|
||||
std::vector<int> deleted0,deleted1;
|
||||
int triangle_count=triangles.size();
|
||||
|
||||
for (int iteration=0;iteration<100;++iteration)
|
||||
{
|
||||
// target number of triangles reached ? Then break
|
||||
//printf("iteration %d - triangles %d\n",iteration,triangle_count-deleted_triangles);
|
||||
if (triangle_count-deleted_triangles<=target_count)
|
||||
break;
|
||||
|
||||
// update mesh once in a while
|
||||
if (iteration%5==0)
|
||||
{
|
||||
update_mesh(iteration);
|
||||
}
|
||||
|
||||
// clear dirty flag
|
||||
for (std::size_t i=0;i<triangles.size();++i)
|
||||
triangles[i].dirty=0;
|
||||
|
||||
//
|
||||
// All triangles with edges below the threshold will be removed
|
||||
//
|
||||
// The following numbers works well for most models.
|
||||
// If it does not, try to adjust the 3 parameters
|
||||
//
|
||||
double threshold = 0.000000001*pow(double(iteration+3),agressiveness);
|
||||
//if (tolerance_factor < 1.0)
|
||||
// threshold *= tolerance_factor;
|
||||
|
||||
// remove vertices & mark deleted triangles
|
||||
for (std::size_t i=0;i<triangles.size();++i)
|
||||
{
|
||||
Triangle &t=triangles[i];
|
||||
if (t.err[3]>threshold)
|
||||
continue;
|
||||
if (t.deleted)
|
||||
continue;
|
||||
if (t.dirty)
|
||||
continue;
|
||||
|
||||
for (std::size_t j=0;j<3;++j)
|
||||
{
|
||||
if (t.err[j]<threshold)
|
||||
{
|
||||
int i0=t.v[ j ]; Vertex &v0 = vertices[i0];
|
||||
int i1=t.v[(j+1)%3]; Vertex &v1 = vertices[i1];
|
||||
|
||||
// Border check
|
||||
if (v0.border != v1.border)
|
||||
continue;
|
||||
|
||||
// Compute vertex to collapse to
|
||||
vec3f p;
|
||||
calculate_error(i0,i1,p);
|
||||
|
||||
deleted0.resize(v0.tcount); // normals temporarily
|
||||
deleted1.resize(v1.tcount); // normals temporarily
|
||||
|
||||
// dont remove if flipped
|
||||
if (flipped(p,i0,i1,v0,v1,deleted0))
|
||||
continue;
|
||||
if (flipped(p,i1,i0,v1,v0,deleted1))
|
||||
continue;
|
||||
|
||||
// not flipped, so remove edge
|
||||
v0.p=p;
|
||||
v0.q=v1.q+v0.q;
|
||||
int tstart=refs.size();
|
||||
|
||||
update_triangles(i0,v0,deleted0,deleted_triangles);
|
||||
update_triangles(i0,v1,deleted1,deleted_triangles);
|
||||
|
||||
int tcount=refs.size()-tstart;
|
||||
|
||||
if (tcount<=v0.tcount)
|
||||
{
|
||||
// save ram
|
||||
if (tcount)
|
||||
memcpy(&refs[v0.tstart],&refs[tstart],tcount*sizeof(Ref));
|
||||
}
|
||||
else
|
||||
{
|
||||
// append
|
||||
v0.tstart=tstart;
|
||||
}
|
||||
|
||||
v0.tcount=tcount;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// done?
|
||||
if (triangle_count-deleted_triangles<=target_count)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// clean up mesh
|
||||
compact_mesh();
|
||||
|
||||
// ready
|
||||
//int timeEnd=timeGetTime();
|
||||
//printf("%s - %d/%d %d%% removed in %d ms\n",__FUNCTION__,
|
||||
// triangle_count-deleted_triangles,
|
||||
// triangle_count,deleted_triangles*100/triangle_count,
|
||||
// timeEnd-timeStart);
|
||||
|
||||
}
|
||||
|
||||
// Check if a triangle flips when this edge is removed
|
||||
|
||||
bool Simplify::flipped(vec3f p, int i0, int i1,
|
||||
Vertex &v0,
|
||||
Vertex &v1,
|
||||
std::vector<int> &deleted)
|
||||
{
|
||||
(void)i0; (void)v1;
|
||||
int bordercount=0;
|
||||
for (int k=0;k<v0.tcount;++k)
|
||||
{
|
||||
Triangle &t=triangles[refs[v0.tstart+k].tid];
|
||||
if (t.deleted)
|
||||
continue;
|
||||
|
||||
int s=refs[v0.tstart+k].tvertex;
|
||||
int id1=t.v[(s+1)%3];
|
||||
int id2=t.v[(s+2)%3];
|
||||
|
||||
if (id1==i1 || id2==i1) // delete ?
|
||||
{
|
||||
bordercount++;
|
||||
deleted[k]=1;
|
||||
continue;
|
||||
}
|
||||
vec3f d1 = vertices[id1].p-p; d1.Normalize();
|
||||
vec3f d2 = vertices[id2].p-p; d2.Normalize();
|
||||
if (fabs(d1.Dot(d2))>0.999)
|
||||
return true;
|
||||
vec3f n;
|
||||
n = d1.Cross(d2);
|
||||
n.Normalize();
|
||||
deleted[k]=0;
|
||||
if (n.Dot(t.n)<0.2)
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// Update triangle connections and edge error after a edge is collapsed
|
||||
|
||||
void Simplify::update_triangles(int i0,Vertex &v,std::vector<int> &deleted,int &deleted_triangles)
|
||||
{
|
||||
vec3f p;
|
||||
for (int k=0;k<v.tcount;++k)
|
||||
{
|
||||
Ref &r=refs[v.tstart+k];
|
||||
Triangle &t=triangles[r.tid];
|
||||
if (t.deleted)
|
||||
continue;
|
||||
if (deleted[k])
|
||||
{
|
||||
t.deleted=1;
|
||||
deleted_triangles++;
|
||||
continue;
|
||||
}
|
||||
t.v[r.tvertex]=i0;
|
||||
t.dirty=1;
|
||||
t.err[0]=calculate_error(t.v[0],t.v[1],p);
|
||||
t.err[1]=calculate_error(t.v[1],t.v[2],p);
|
||||
t.err[2]=calculate_error(t.v[2],t.v[0],p);
|
||||
t.err[3]=std::min(t.err[0],std::min(t.err[1],t.err[2]));
|
||||
refs.push_back(r);
|
||||
}
|
||||
}
|
||||
|
||||
// compact triangles, compute edge error and build reference list
|
||||
|
||||
void Simplify::update_mesh(int iteration)
|
||||
{
|
||||
if(iteration>0) // compact triangles
|
||||
{
|
||||
int dst=0;
|
||||
for (std::size_t i=0;i<triangles.size();++i)
|
||||
{
|
||||
if (!triangles[i].deleted)
|
||||
{
|
||||
triangles[dst++]=triangles[i];
|
||||
}
|
||||
}
|
||||
triangles.resize(dst);
|
||||
}
|
||||
//
|
||||
// Init Quadrics by Plane & Edge Errors
|
||||
//
|
||||
// required at the beginning ( iteration == 0 )
|
||||
// recomputing during the simplification is not required,
|
||||
// but mostly improves the result for closed meshes
|
||||
//
|
||||
if (iteration == 0)
|
||||
{
|
||||
for (std::size_t i=0;i<vertices.size();++i)
|
||||
vertices[i].q=SymetricMatrix(0.0);
|
||||
|
||||
for (std::size_t i=0;i<triangles.size();++i)
|
||||
{
|
||||
Triangle &t=triangles[i];
|
||||
vec3f n,p[3];
|
||||
for (std::size_t j=0;j<3;++j)
|
||||
p[j]=vertices[t.v[j]].p;
|
||||
n = (p[1]-p[0]).Cross(p[2]-p[0]);
|
||||
n.Normalize();
|
||||
t.n=n;
|
||||
for (std::size_t j=0;j<3;++j)
|
||||
vertices[t.v[j]].q = vertices[t.v[j]].q+SymetricMatrix(n.x,n.y,n.z,-n.Dot(p[0]));
|
||||
}
|
||||
for (std::size_t i=0;i<triangles.size();++i)
|
||||
{
|
||||
// Calc Edge Error
|
||||
Triangle &t=triangles[i];vec3f p;
|
||||
for (std::size_t j=0;j<3;++j)
|
||||
t.err[j] = calculate_error(t.v[j],t.v[(j+1)%3],p);
|
||||
t.err[3]=std::min(t.err[0],std::min(t.err[1],t.err[2]));
|
||||
}
|
||||
}
|
||||
|
||||
// Init Reference ID list
|
||||
for (std::size_t i=0;i<vertices.size();++i)
|
||||
{
|
||||
vertices[i].tstart=0;
|
||||
vertices[i].tcount=0;
|
||||
}
|
||||
for (std::size_t i=0;i<triangles.size();++i)
|
||||
{
|
||||
Triangle &t=triangles[i];
|
||||
for (std::size_t j=0;j<3;++j)
|
||||
vertices[t.v[j]].tcount++;
|
||||
}
|
||||
int tstart=0;
|
||||
for (std::size_t i=0;i<vertices.size();++i)
|
||||
{
|
||||
Vertex &v=vertices[i];
|
||||
v.tstart=tstart;
|
||||
tstart+=v.tcount;
|
||||
v.tcount=0;
|
||||
}
|
||||
|
||||
// Write References
|
||||
refs.resize(triangles.size()*3);
|
||||
for (std::size_t i=0;i<triangles.size();++i)
|
||||
{
|
||||
Triangle &t=triangles[i];
|
||||
for (std::size_t j=0;j<3;++j)
|
||||
{
|
||||
Vertex &v=vertices[t.v[j]];
|
||||
refs[v.tstart+v.tcount].tid=i;
|
||||
refs[v.tstart+v.tcount].tvertex=j;
|
||||
v.tcount++;
|
||||
}
|
||||
}
|
||||
|
||||
// Identify boundary : vertices[].border=0,1
|
||||
if (iteration == 0)
|
||||
{
|
||||
std::vector<int> vcount,vids;
|
||||
|
||||
for (std::size_t i=0;i<vertices.size();++i)
|
||||
vertices[i].border=0;
|
||||
|
||||
for (std::size_t i=0;i<vertices.size();++i)
|
||||
{
|
||||
Vertex &v=vertices[i];
|
||||
vcount.clear();
|
||||
vids.clear();
|
||||
for (int j=0; j<v.tcount; ++j)
|
||||
{
|
||||
int k=refs[v.tstart+j].tid;
|
||||
Triangle &t=triangles[k];
|
||||
for (int k=0;k<3;++k)
|
||||
{
|
||||
std::size_t ofs=0; int id=t.v[k];
|
||||
while(ofs<vcount.size())
|
||||
{
|
||||
if (vids[ofs]==id)
|
||||
break;
|
||||
ofs++;
|
||||
}
|
||||
if(ofs==vcount.size())
|
||||
{
|
||||
vcount.push_back(1);
|
||||
vids.push_back(id);
|
||||
}
|
||||
else
|
||||
{
|
||||
vcount[ofs]++;
|
||||
}
|
||||
}
|
||||
}
|
||||
for (std::size_t j=0;j<vcount.size();++j) {
|
||||
if (vcount[j]==1)
|
||||
vertices[vids[j]].border=1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Finally compact mesh before exiting
|
||||
|
||||
void Simplify::compact_mesh()
|
||||
{
|
||||
int dst=0;
|
||||
for (std::size_t i=0;i<vertices.size();++i)
|
||||
{
|
||||
vertices[i].tcount=0;
|
||||
}
|
||||
for (std::size_t i=0;i<triangles.size();++i)
|
||||
{
|
||||
if (!triangles[i].deleted)
|
||||
{
|
||||
Triangle &t=triangles[i];
|
||||
triangles[dst++]=t;
|
||||
for (std::size_t j=0;j<3;++j)
|
||||
vertices[t.v[j]].tcount=1;
|
||||
}
|
||||
}
|
||||
|
||||
triangles.resize(dst);
|
||||
dst=0;
|
||||
for (std::size_t i=0;i<vertices.size();++i)
|
||||
{
|
||||
if (vertices[i].tcount)
|
||||
{
|
||||
vertices[i].tstart=dst;
|
||||
vertices[dst].p=vertices[i].p;
|
||||
dst++;
|
||||
}
|
||||
}
|
||||
for (std::size_t i=0;i<triangles.size();++i)
|
||||
{
|
||||
Triangle &t=triangles[i];
|
||||
for (std::size_t j=0;j<3;++j)
|
||||
t.v[j]=vertices[t.v[j]].tstart;
|
||||
}
|
||||
vertices.resize(dst);
|
||||
}
|
||||
|
||||
// Error between vertex and Quadric
|
||||
|
||||
double Simplify::vertex_error(SymetricMatrix q, double x, double y, double z)
|
||||
{
|
||||
return q[0]*x*x + 2*q[1]*x*y + 2*q[2]*x*z + 2*q[3]*x + q[4]*y*y
|
||||
+ 2*q[5]*y*z + 2*q[6]*y + q[7]*z*z + 2*q[8]*z + q[9];
|
||||
}
|
||||
|
||||
// Error for one edge
|
||||
|
||||
double Simplify::calculate_error(int id_v1, int id_v2, vec3f &p_result)
|
||||
{
|
||||
// compute interpolated vertex
|
||||
|
||||
SymetricMatrix q = vertices[id_v1].q + vertices[id_v2].q;
|
||||
bool border = vertices[id_v1].border & vertices[id_v2].border;
|
||||
double error=0;
|
||||
double det = q.det(0, 1, 2, 1, 4, 5, 2, 5, 7);
|
||||
|
||||
if (det != 0 && !border)
|
||||
{
|
||||
// q_delta is invertible
|
||||
p_result.x = -1/det*(q.det(1, 2, 3, 4, 5, 6, 5, 7 , 8)); // vx = A41/det(q_delta)
|
||||
p_result.y = 1/det*(q.det(0, 2, 3, 1, 5, 6, 2, 7 , 8)); // vy = A42/det(q_delta)
|
||||
p_result.z = -1/det*(q.det(0, 1, 3, 1, 4, 6, 2, 5, 8)); // vz = A43/det(q_delta)
|
||||
error = vertex_error(q, p_result.x, p_result.y, p_result.z);
|
||||
}
|
||||
else
|
||||
{
|
||||
// det = 0 -> try to find best result
|
||||
vec3f p1=vertices[id_v1].p;
|
||||
vec3f p2=vertices[id_v2].p;
|
||||
vec3f p3=(p1+p2)/2;
|
||||
double error1 = vertex_error(q, p1.x,p1.y,p1.z);
|
||||
double error2 = vertex_error(q, p2.x,p2.y,p2.z);
|
||||
double error3 = vertex_error(q, p3.x,p3.y,p3.z);
|
||||
error = std::min(error1, std::min(error2, error3));
|
||||
if (error1 == error)
|
||||
p_result=p1;
|
||||
if (error2 == error)
|
||||
p_result=p2;
|
||||
if (error3 == error)
|
||||
p_result=p3;
|
||||
}
|
||||
return error;
|
||||
}
|
||||
|
||||
///////////////////////////////////////////
|
||||
@@ -51,6 +51,7 @@
|
||||
#include "Core/Triangulation.h"
|
||||
#include "Core/Trim.h"
|
||||
#include "Core/Visitor.h"
|
||||
#include "Core/Decimation.h"
|
||||
|
||||
#include "Mesh.h"
|
||||
#include "MeshPy.h"
|
||||
@@ -940,6 +941,12 @@ void MeshObject::smooth(int iterations, float d_max)
|
||||
_kernel.Smooth(iterations, d_max);
|
||||
}
|
||||
|
||||
void MeshObject::decimate(float fTolerance, float fReduction)
|
||||
{
|
||||
MeshCore::MeshSimplify dm(this->_kernel);
|
||||
dm.simplify(fTolerance, fReduction);
|
||||
}
|
||||
|
||||
Base::Vector3d MeshObject::getPointNormal(unsigned long index) const
|
||||
{
|
||||
std::vector<Base::Vector3f> temp = _kernel.CalcVertexNormals();
|
||||
|
||||
@@ -216,6 +216,7 @@ public:
|
||||
void movePoint(unsigned long, const Base::Vector3d& v);
|
||||
void setPoint(unsigned long, const Base::Vector3d& v);
|
||||
void smooth(int iterations, float d_max);
|
||||
void decimate(float fTolerance, float fReduction);
|
||||
Base::Vector3d getPointNormal(unsigned long) const;
|
||||
std::vector<Base::Vector3d> getPointNormals() const;
|
||||
void crossSections(const std::vector<TPlane>&, std::vector<TPolylines> §ions,
|
||||
|
||||
@@ -409,6 +409,19 @@ The argument int is the mode: 0=inner, 1=outer
|
||||
smooth([iteration=1,maxError=FLT_MAX])</UserDocu>
|
||||
</Documentation>
|
||||
</Methode>
|
||||
<Methode Name="decimate">
|
||||
<Documentation>
|
||||
<UserDocu>
|
||||
Decimate the mesh
|
||||
decimate(tolerance(Float), reduction(Float))
|
||||
tolerance: maximum error
|
||||
reduction: reduction factor must be in the range [0.0,1.0]
|
||||
Example:
|
||||
mesh.decimate(0.5, 0.1) # reduction by up to 10 percent
|
||||
mesh.decimate(0.5, 0.9) # reduction by up to 90 percent
|
||||
</UserDocu>
|
||||
</Documentation>
|
||||
</Methode>
|
||||
<Methode Name="optimizeTopology" Const="true">
|
||||
<Documentation>
|
||||
<UserDocu>Optimize the edges to get nicer facets</UserDocu>
|
||||
|
||||
@@ -353,7 +353,7 @@ PyObject* MeshPy::offset(PyObject *args)
|
||||
getMeshObjectPtr()->offsetSpecial2(Float);
|
||||
} PY_CATCH;
|
||||
|
||||
Py_Return;
|
||||
Py_Return;
|
||||
}
|
||||
|
||||
PyObject* MeshPy::offsetSpecial(PyObject *args)
|
||||
@@ -366,7 +366,7 @@ PyObject* MeshPy::offsetSpecial(PyObject *args)
|
||||
getMeshObjectPtr()->offsetSpecial(Float,zmax,zmin);
|
||||
} PY_CATCH;
|
||||
|
||||
Py_Return;
|
||||
Py_Return;
|
||||
}
|
||||
|
||||
PyObject* MeshPy::crossSections(PyObject *args)
|
||||
@@ -1074,7 +1074,7 @@ PyObject* MeshPy::flipNormals(PyObject *args)
|
||||
getMeshObjectPtr()->flipNormals();
|
||||
} PY_CATCH;
|
||||
|
||||
Py_Return;
|
||||
Py_Return;
|
||||
}
|
||||
|
||||
PyObject* MeshPy::hasNonUniformOrientedFacets(PyObject *args)
|
||||
@@ -1119,7 +1119,7 @@ PyObject* MeshPy::harmonizeNormals(PyObject *args)
|
||||
getMeshObjectPtr()->harmonizeNormals();
|
||||
} PY_CATCH;
|
||||
|
||||
Py_Return;
|
||||
Py_Return;
|
||||
}
|
||||
|
||||
PyObject* MeshPy::countComponents(PyObject *args)
|
||||
@@ -1143,7 +1143,7 @@ PyObject* MeshPy::removeComponents(PyObject *args)
|
||||
}
|
||||
} PY_CATCH;
|
||||
|
||||
Py_Return;
|
||||
Py_Return;
|
||||
}
|
||||
|
||||
PyObject* MeshPy::fillupHoles(PyObject *args)
|
||||
@@ -1184,7 +1184,7 @@ PyObject* MeshPy::fixIndices(PyObject *args)
|
||||
getMeshObjectPtr()->validateIndices();
|
||||
} PY_CATCH;
|
||||
|
||||
Py_Return;
|
||||
Py_Return;
|
||||
}
|
||||
|
||||
PyObject* MeshPy::fixDeformations(PyObject *args)
|
||||
@@ -1198,7 +1198,7 @@ PyObject* MeshPy::fixDeformations(PyObject *args)
|
||||
getMeshObjectPtr()->validateDeformations(fMaxAngle, fEpsilon);
|
||||
} PY_CATCH;
|
||||
|
||||
Py_Return;
|
||||
Py_Return;
|
||||
}
|
||||
|
||||
PyObject* MeshPy::fixDegenerations(PyObject *args)
|
||||
@@ -1211,7 +1211,7 @@ PyObject* MeshPy::fixDegenerations(PyObject *args)
|
||||
getMeshObjectPtr()->validateDegenerations(fEpsilon);
|
||||
} PY_CATCH;
|
||||
|
||||
Py_Return;
|
||||
Py_Return;
|
||||
}
|
||||
|
||||
PyObject* MeshPy::removeDuplicatedPoints(PyObject *args)
|
||||
@@ -1223,7 +1223,7 @@ PyObject* MeshPy::removeDuplicatedPoints(PyObject *args)
|
||||
getMeshObjectPtr()->removeDuplicatedPoints();
|
||||
} PY_CATCH;
|
||||
|
||||
Py_Return;
|
||||
Py_Return;
|
||||
}
|
||||
|
||||
PyObject* MeshPy::removeDuplicatedFacets(PyObject *args)
|
||||
@@ -1235,7 +1235,7 @@ PyObject* MeshPy::removeDuplicatedFacets(PyObject *args)
|
||||
getMeshObjectPtr()->removeDuplicatedFacets();
|
||||
} PY_CATCH;
|
||||
|
||||
Py_Return;
|
||||
Py_Return;
|
||||
}
|
||||
|
||||
PyObject* MeshPy::refine(PyObject *args)
|
||||
@@ -1247,7 +1247,7 @@ PyObject* MeshPy::refine(PyObject *args)
|
||||
getMeshObjectPtr()->refine();
|
||||
} PY_CATCH;
|
||||
|
||||
Py_Return;
|
||||
Py_Return;
|
||||
}
|
||||
|
||||
PyObject* MeshPy::optimizeTopology(PyObject *args)
|
||||
@@ -1261,7 +1261,7 @@ PyObject* MeshPy::optimizeTopology(PyObject *args)
|
||||
getMeshObjectPtr()->optimizeTopology(fMaxAngle);
|
||||
} PY_CATCH;
|
||||
|
||||
Py_Return;
|
||||
Py_Return;
|
||||
}
|
||||
|
||||
PyObject* MeshPy::optimizeEdges(PyObject *args)
|
||||
@@ -1274,7 +1274,7 @@ PyObject* MeshPy::optimizeEdges(PyObject *args)
|
||||
getMeshObjectPtr()->optimizeEdges();
|
||||
} PY_CATCH;
|
||||
|
||||
Py_Return;
|
||||
Py_Return;
|
||||
}
|
||||
|
||||
PyObject* MeshPy::splitEdges(PyObject *args)
|
||||
@@ -1286,7 +1286,7 @@ PyObject* MeshPy::splitEdges(PyObject *args)
|
||||
getMeshObjectPtr()->splitEdges();
|
||||
} PY_CATCH;
|
||||
|
||||
Py_Return;
|
||||
Py_Return;
|
||||
}
|
||||
|
||||
PyObject* MeshPy::splitEdge(PyObject *args)
|
||||
@@ -1321,7 +1321,7 @@ PyObject* MeshPy::splitEdge(PyObject *args)
|
||||
getMeshObjectPtr()->splitEdge(facet, neighbour, v);
|
||||
} PY_CATCH;
|
||||
|
||||
Py_Return;
|
||||
Py_Return;
|
||||
}
|
||||
|
||||
PyObject* MeshPy::splitFacet(PyObject *args)
|
||||
@@ -1351,7 +1351,7 @@ PyObject* MeshPy::splitFacet(PyObject *args)
|
||||
getMeshObjectPtr()->splitFacet(facet, v1, v2);
|
||||
} PY_CATCH;
|
||||
|
||||
Py_Return;
|
||||
Py_Return;
|
||||
}
|
||||
|
||||
PyObject* MeshPy::swapEdge(PyObject *args)
|
||||
@@ -1381,7 +1381,7 @@ PyObject* MeshPy::swapEdge(PyObject *args)
|
||||
getMeshObjectPtr()->swapEdge(facet, neighbour);
|
||||
} PY_CATCH;
|
||||
|
||||
Py_Return;
|
||||
Py_Return;
|
||||
}
|
||||
|
||||
PyObject* MeshPy::collapseEdge(PyObject *args)
|
||||
@@ -1411,7 +1411,7 @@ PyObject* MeshPy::collapseEdge(PyObject *args)
|
||||
getMeshObjectPtr()->collapseEdge(facet, neighbour);
|
||||
} PY_CATCH;
|
||||
|
||||
Py_Return;
|
||||
Py_Return;
|
||||
}
|
||||
|
||||
PyObject* MeshPy::collapseFacet(PyObject *args)
|
||||
@@ -1429,7 +1429,7 @@ PyObject* MeshPy::collapseFacet(PyObject *args)
|
||||
getMeshObjectPtr()->collapseFacet(facet);
|
||||
} PY_CATCH;
|
||||
|
||||
Py_Return;
|
||||
Py_Return;
|
||||
}
|
||||
|
||||
PyObject* MeshPy::insertVertex(PyObject *args)
|
||||
@@ -1452,7 +1452,7 @@ PyObject* MeshPy::insertVertex(PyObject *args)
|
||||
getMeshObjectPtr()->insertVertex(facet, v);
|
||||
} PY_CATCH;
|
||||
|
||||
Py_Return;
|
||||
Py_Return;
|
||||
}
|
||||
|
||||
PyObject* MeshPy::snapVertex(PyObject *args)
|
||||
@@ -1475,7 +1475,7 @@ PyObject* MeshPy::snapVertex(PyObject *args)
|
||||
getMeshObjectPtr()->snapVertex(facet, v);
|
||||
} PY_CATCH;
|
||||
|
||||
Py_Return;
|
||||
Py_Return;
|
||||
}
|
||||
|
||||
PyObject* MeshPy::printInfo(PyObject *args)
|
||||
@@ -1513,7 +1513,7 @@ PyObject* MeshPy::collapseFacets(PyObject *args)
|
||||
return 0;
|
||||
}
|
||||
|
||||
Py_Return;
|
||||
Py_Return;
|
||||
}
|
||||
|
||||
PyObject* MeshPy::foraminate(PyObject *args)
|
||||
@@ -1590,7 +1590,7 @@ PyObject* MeshPy::cut(PyObject *args)
|
||||
polygon2d.Add(Base::Vector2d(it->x, it->y));
|
||||
getMeshObjectPtr()->cut(polygon2d, proj, MeshObject::CutType(mode));
|
||||
|
||||
Py_Return;
|
||||
Py_Return;
|
||||
}
|
||||
|
||||
PyObject* MeshPy::trim(PyObject *args)
|
||||
@@ -1624,7 +1624,7 @@ PyObject* MeshPy::trim(PyObject *args)
|
||||
polygon2d.Add(Base::Vector2d(it->x, it->y));
|
||||
getMeshObjectPtr()->trim(polygon2d, proj, MeshObject::CutType(mode));
|
||||
|
||||
Py_Return;
|
||||
Py_Return;
|
||||
}
|
||||
|
||||
PyObject* MeshPy::smooth(PyObject *args)
|
||||
@@ -1639,7 +1639,20 @@ PyObject* MeshPy::smooth(PyObject *args)
|
||||
getMeshObjectPtr()->smooth(iter, d_max);
|
||||
} PY_CATCH;
|
||||
|
||||
Py_Return;
|
||||
Py_Return;
|
||||
}
|
||||
|
||||
PyObject* MeshPy::decimate(PyObject *args)
|
||||
{
|
||||
float fTol, fRed;
|
||||
if (!PyArg_ParseTuple(args, "ff", &fTol,&fRed))
|
||||
return NULL;
|
||||
|
||||
PY_TRY {
|
||||
getMeshObjectPtr()->decimate(fTol, fRed);
|
||||
} PY_CATCH;
|
||||
|
||||
Py_Return;
|
||||
}
|
||||
|
||||
PyObject* MeshPy::nearestFacetOnRay(PyObject *args)
|
||||
|
||||
@@ -200,7 +200,7 @@ void MeshSelection::prepareFreehandSelection(bool add,SoEventCallbackCB *cb)
|
||||
freehand->setColor(1.0f, 0.0f, 0.0f);
|
||||
freehand->setLineWidth(3.0f);
|
||||
viewer->navigationStyle()->startSelection(freehand);
|
||||
|
||||
|
||||
QBitmap cursor = QBitmap::fromData(QSize(CROSS_WIDTH, CROSS_HEIGHT), cross_bitmap);
|
||||
QBitmap mask = QBitmap::fromData(QSize(CROSS_WIDTH, CROSS_HEIGHT), cross_mask_bitmap);
|
||||
QCursor custom(cursor, mask, CROSS_HOT_X, CROSS_HOT_Y);
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
include_directories(
|
||||
${CMAKE_CURRENT_BINARY_DIR}
|
||||
${CMAKE_SOURCE_DIR}/src
|
||||
${Boost_INCLUDE_DIRS}
|
||||
${PYTHON_INCLUDE_DIRS}
|
||||
${XercesC_INCLUDE_DIRS}
|
||||
)
|
||||
@@ -40,6 +41,7 @@ if(BUILD_QT5)
|
||||
else()
|
||||
qt4_add_resources(Resource_SRCS Resources/Test.qrc)
|
||||
endif()
|
||||
|
||||
SET(Resource_SRCS
|
||||
${Resource_SRCS}
|
||||
Resources/Test.qrc
|
||||
|
||||
Reference in New Issue
Block a user