./NearTree-3.1.1/0000755002342100234170000000000011640401672013425 5ustar bernstehfaculty./NearTree-3.1.1/v.h0000644002342100234170000000523211640401607014043 0ustar bernstehfaculty//* //* v.h //* NearTree //* //* Copyright 2001, 2008 Larry Andrews. All rights reserved //* Revised 12 Dec 2008 for sourceforge release -- H. J. Bernstein //********************************************************************** //* * //* YOU MAY REDISTRIBUTE NearTree UNDER THE TERMS OF THE LGPL * //* * //**********************************************************************/ //************************* LGPL NOTICES ******************************* //* * //* This library is free software; you can redistribute it and/or * //* modify it under the terms of the GNU Lesser General Public * //* License as published by the Free Software Foundation; either * //* version 2.1 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 * //* Lesser General Public License for more details. * //* * //* You should have received a copy of the GNU Lesser General Public * //* License along with this library; if not, write to the Free * //* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, * //* MA 02110-1301 USA * //* * //**********************************************************************/ // v.h: interface for the v class. // // This is just a trivial vector class in 3-space for the purpose // of demonstrating the nearest neighbor template class. It is not // designed to do anything important, and, as a consequence, it is // very incomplete. // // larry andrews, 2001 // ////////////////////////////////////////////////////////////////////// #if !defined(V_H_INCLUDED) #define V_H_INCLUDED // #include class v { public: v operator- ( const v& v ) const; bool operator< ( const v& v ) const; operator double( ) const; v ( const double& da, const double& db, const double& dc ); v ( const double& da ); v ( ); ~v ( ); double Norm( void ) const; friend std::ostream& operator <<( std::ostream& os, const v& v ); private: bool m_bIsDefined; double m_dvec[ 3 ]; }; #endif // !defined(V_H_INCLUDED) ./NearTree-3.1.1/Makefile0000644002342100234170000003202711640401607015067 0ustar bernstehfaculty# # Makefile # NearTree # # Part if the NearTree API # Copyright 2008, 2009 Larry Andrews. All rights reserved # # Makefile created by Herbert J. Bernstein on 1/08/09 # with permission from Larry Andrews. # Copyright 2008 Larry Andrews and Herbert J. Bernstein. # All rights reserved. # # Revised 30 May 2009, release with full containerization of C++ # version and KNear/Far in C++ and C, LCA + HJB # # Revised 31 October 2009, adding triple.h # #********************************************************************** #* * #* YOU MAY REDISTRIBUTE THE NearTree API UNDER THE TERMS OF THE LGPL * #* * #**********************************************************************/ #************************* LGPL NOTICES ******************************* #* * #* This library is free software; you can redistribute it and/or * #* modify it under the terms of the GNU Lesser General Public * #* License as published by the Free Software Foundation; either * #* version 2.1 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 * #* Lesser General Public License for more details. * #* * #* You should have received a copy of the GNU Lesser General Public * #* License along with this library; if not, write to the Free * #* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, * #* MA 02110-1301 USA * #* * #**********************************************************************/ # Version string VERSION = 6:0:1 RELEASE = 3.1 # # Compiler and compilation flags # CC = gcc ifneq ($(MSYSTEM),MINGW32) CFLAGS = -g -O2 -Wall -ansi -pedantic -DCNEARTREE_SAFE_TRIANG=1 TIME = time else CFLAGS = -g -O2 -Wall -DCNEARTREE_SAFE_TRIANG=1 TIME = endif # # libtool path if system default is not suitable # #LIBTOOL = $(HOME)/bin/libtool ifndef LIBTOOL LIBTOOL = libtool endif # # If local headers must be quoted uncomment the next line # #USE_LOCAL_HEADERS = 1 # # Uncomment the next two lines if CVector is installed locally in $(HOME)/include # and $(HOME)/lib # #CVECTOR_INCLUDE = -I$(HOME)/include #CVECTOR_LIBLOC = -L$(HOME)/lib # # Directories # ROOT = . LIB = $(ROOT)/lib BIN = $(ROOT)/bin SRC = $(ROOT) INC = $(ROOT) EXAMPLES = $(ROOT) TESTDATA = $(ROOT) ifndef INSTALL_PREFIX INSTALL_PREFIX = /usr/local #INSTALL_PREFIX = $(HOME) endif # # Include directories # ifdef USE_LOCAL_HEADERS INCLUDES = -DUSE_LOCAL_HEADERS else INCLUDES = -I$(INC) $(CVECTOR_INCLUDE) endif # # C++ Libraries # CPPLIBRARIES = -lm # # C Libraries # CLIBRARIES = $(CVECTOR_LIBLOC) -lCVector -lm COMPILE_COMMAND = $(LIBTOOL) --mode=compile $(CC) $(CFLAGS) $(INCLUDES) $(WARNINGS) -c CPPCOMPILE_COMMAND = $(LIBTOOL) --mode=compile $(CXX) $(CFLAGS) $(INCLUDES) $(WARNINGS) -c LIBRARY_LINK_COMMAND = $(LIBTOOL) --mode=link $(CC) -version-info $(VERSION) -no-undefined -rpath $(INSTALL_PREFIX)/lib BUILD_COMMAND_LOCAL = $(LIBTOOL) --mode=link $(CC) $(CFLAGS) $(INCLUDES) CPPBUILD_COMMAND_LOCAL = $(LIBTOOL) --mode=link $(CXX) -no-undefined $(CFLAGS) $(INCLUDES) BUILD_COMMAND_DYNAMIC = $(LIBTOOL) --mode=link $(CC) -no-undefined $(CFLAGS) -shared -I$(INSTALL_PREFIX)/include BUILD_COMMAND_STATIC = $(LIBTOOL) --mode=link $(CC) $(CFLAGS) -static-libtool-libs -I$(INSTALL_PREFIX)/include INSTALL_COMMAND = $(LIBTOOL) --mode=install cp INSTALL_FINISH_COMMAND = $(LIBTOOL) --mode=finish OBJ_EXT = lo LIB_EXT = la ###################################################################### # You should not need to make modifications below this line # ###################################################################### # # Suffixes of files to be used or built # .SUFFIXES: .c .$(OBJ_EXT) .$(LIB_EXT) # # Common dependencies # COMMONDEP = Makefile # # Source files # CPPSOURCE = $(SRC)/main.cpp $(SRC)/CNearTreeTest.cpp $(SRC)/v.cpp CSOURCE = $(SRC)/CNearTree.c $(SRC)/main.c $(SRC)/CNearTreeTest.c SOURCE = $(CPPSOURCE) $(CSOURCE) # # Header files # HEADERS = $(INC)/TNear.h $(INC)/CNearTree.h $(INC)/v.h $(INC)/rhrand.h $(INC)/triple.h # Default: instructions # default: @echo ' ' @echo '***************************************************************' @echo ' ' @echo ' PLEASE READ README_NearTree.txt and lgpl.txt' @echo ' ' @echo ' Before making the NearTree libraries and example programs, check' @echo ' that the chosen settings are correct' @echo ' ' @echo ' The current C++ and C compile commands are:' @echo ' ' @echo ' $(CPPCOMPILE_COMMAND)' @echo ' $(COMPILE_COMMAND)' @echo ' ' @echo ' The C API, CNearTree.c, depends on the sourceforge project CVector ' ifdef CVECTOR_INCLUDE @echo ' The variable CVECTOR_INCLUDE is defined as ' @echo ' $(CVECTOR_INCLUDE)' else @echo ' You are currently setup to use the system defaults for CVector' @echo ' If that is not correct, define the variable CVECTOR_INCLUDE ' endif @echo ' ' @echo ' The current library link command is:' @echo ' ' @echo ' $(LIBRARY_LINK_COMMAND)' @echo ' ' @echo ' The current C++ and C library local, and C dynamic and static build commands are:' @echo ' ' @echo ' $(CPPBUILD_COMMAND_LOCAL)' @echo ' $(BUILD_COMMAND_LOCAL)' @echo ' $(BUILD_COMMAND_DYNAMIC)' @echo ' $(BUILD_COMMAND_STATIC)' @echo ' ' @echo ' Before installing the NearTree library and example programs, check' @echo ' that the install directory and install commands are correct:' @echo ' ' @echo ' The current values are :' @echo ' ' @echo ' $(INSTALL_PREFIX) ' @echo ' $(INSTALL_COMMAND) ' @echo ' $(INSTALL_FINISH) ' @echo ' ' @echo ' To compile the NearTree library and example programs type:' @echo ' ' @echo ' make clean' @echo ' make all' @echo ' ' @echo ' To run a set of tests type:' @echo ' ' @echo ' make tests' @echo ' ' @echo ' To clean up the directories type:' @echo ' ' @echo ' make clean' @echo ' ' @echo ' To install the library and headers type:' @echo ' ' @echo ' make install' @echo ' ' @echo '***************************************************************' @echo ' ' # # Compile the library and examples # all: $(LIB) $(BIN) $(SOURCE) $(HEADERS) \ $(LIB)/libCNearTree.$(LIB_EXT) \ $(BIN)/CPPMain $(BIN)/CMain $(BIN)/CPPNearTreeTest $(BIN)/CNearTreeTest $(BIN)/CNearTreeTestInst install: all $(INSTALL_PREFIX) $(INSTALL_PREFIX)/lib $(INSTALL_PREFIX)/include \ $(INC) $(LIB)/libCNearTree.$(LIB_EXT) $(INC)/TNear.h $(INC)/CNearTree.h \ $(INC)/rhrand.h $(INC)/triple.h $(INSTALL_COMMAND) $(LIB)/libCNearTree.$(LIB_EXT) $(INSTALL_PREFIX)/lib/libCNearTree.$(LIB_EXT) $(INSTALL_FINISH_COMMAND) $(INSTALL_PREFIX)/lib/libCNearTree.$(LIB_EXT) -cp $(INSTALL_PREFIX)/include/TNear.h $(INSTALL_PREFIX)/include/TNear_old.h -cp $(INSTALL_PREFIX)/include/CNearTree.h $(INSTALL_PREFIX)/include/CNearTree_old.h cp $(INC)/TNear.h $(INSTALL_PREFIX)/include/TNear.h cp $(INC)/rhrand.h $(INSTALL_PREFIX)/include/rhrand.h cp $(INC)/triple.h $(INSTALL_PREFIX)/include/triple.h cp $(INC)/CNearTree.h $(INSTALL_PREFIX)/include/CNearTree.h chmod 644 $(INSTALL_PREFIX)/include/TNear.h chmod 644 $(INSTALL_PREFIX)/include/CNearTree.h chmod 644 $(INSTALL_PREFIX)/include/rhrand.h chmod 644 $(INSTALL_PREFIX)/include/triple.h echo "Testing final install dynamic" $(BUILD_COMMAND_DYNAMIC) $(INCLUDES) $(EXAMPLES)/CNearTreeTest.c \ -L$(INSTALL_PREFIX)/lib -lCNearTree $(CLIBRARIES) -o $(BIN)/CNearTreeTest_dynamic $(BIN)/CNearTreeTest_dynamic echo "Testing final install static" $(BUILD_COMMAND_STATIC) $(INCLUDES) $(EXAMPLES)/CNearTreeTest.c \ -L$(INSTALL_PREFIX)/lib -lCNearTree $(CLIBRARIES) -o $(BIN)/CNearTreeTest_static $(BIN)/CNearTreeTest_static # # Directories # $(INSTALL_PREFIX): mkdir -p $(INSTALL_PREFIX) $(INSTALL_PREFIX)/lib: $(INSTALL_PREFIX) mkdir -p $(INSTALL_PREFIX)/lib $(INSTALL_PREFIX)/bin: $(INSTALL_PREFIX) mkdir -p $(INSTALL_PREFIX)/bin $(INSTALL_PREFIX)/include: $(INSTALL_PREFIX) mkdir -p $(INSTALL_PREFIX)/include $(LIB): mkdir $(LIB) $(BIN): mkdir $(BIN) # # CNearTree library # $(LIB)/libCNearTree.$(LIB_EXT): $(SRC)/CNearTree.c $(INC)/CNearTree.h $(LIB) $(COMMONDEP) $(COMPILE_COMMAND) -c $(SRC)/CNearTree.c $(LIBRARY_LINK_COMMAND) -o $(LIB)/libCNearTree.$(LIB_EXT) CNearTree.$(OBJ_EXT) $(INCLUDES) \ $(CLIBRARIES) # # example programs # $(BIN)/CPPMain: $(INC)/TNear.h $(EXAMPLES)/main.cpp $(EXAMPLES)/v.cpp $(BIN) $(CPPBUILD_COMMAND_LOCAL) $(EXAMPLES)/main.cpp $(EXAMPLES)/v.cpp $(CPPLIBRARIES) \ -o $@ $(BIN)/CPPMain_Flip: $(INC)/TNear.h $(EXAMPLES)/main_flip.cpp $(EXAMPLES)/v.cpp $(BIN) $(CPPBUILD_COMMAND_LOCAL) $(EXAMPLES)/main_flip.cpp $(EXAMPLES)/v.cpp $(CPPLIBRARIES) \ -o $@ $(BIN)/CPPNearTreeTest: $(INC)/TNear.h $(EXAMPLES)/CNearTreeTest.cpp $(EXAMPLES)/v.cpp $(BIN) $(CPPBUILD_COMMAND_LOCAL) $(EXAMPLES)/CNearTreeTest.cpp $(EXAMPLES)/v.cpp $(CPPLIBRARIES) \ -o $@ $(BIN)/CPPNearTreeTestInst: $(INC)/TNear.h $(EXAMPLES)/CNearTreeTest.cpp $(EXAMPLES)/v.cpp $(BIN) $(CPPBUILD_COMMAND_LOCAL) -DCNEARTREE_INSTRUMENTED $(EXAMPLES)/CNearTreeTest.cpp $(EXAMPLES)/v.cpp $(CPPLIBRARIES) \ -o $@ $(BIN)/CPPNearTreeTestInstFlip: $(INC)/TNear.h $(EXAMPLES)/CNearTreeTest.cpp $(EXAMPLES)/v.cpp $(BIN) $(CPPBUILD_COMMAND_LOCAL) -DCNEARTREE_INSTRUMENTED -DCNEARTREE_FORCEFLIP $(EXAMPLES)/CNearTreeTest.cpp $(EXAMPLES)/v.cpp $(CPPLIBRARIES) \ -o $@ $(BIN)/CPPNearTreeTestInstNoDefer: $(INC)/TNear.h $(EXAMPLES)/CNearTreeTest.cpp $(EXAMPLES)/v.cpp $(BIN) $(CPPBUILD_COMMAND_LOCAL) -DCNEARTREE_INSTRUMENTED -DCNEARTREE_NODEFER $(EXAMPLES)/CNearTreeTest.cpp $(EXAMPLES)/v.cpp $(CPPLIBRARIES) \ -o $@ $(BIN)/CPPNearTreeTestInstNoFlip: $(INC)/TNear.h $(EXAMPLES)/CNearTreeTest.cpp $(EXAMPLES)/v.cpp $(BIN) $(CPPBUILD_COMMAND_LOCAL) -DCNEARTREE_INSTRUMENTED -DCNEARTREE_NOFLIP $(EXAMPLES)/CNearTreeTest.cpp $(EXAMPLES)/v.cpp $(CPPLIBRARIES) \ -o $@ $(BIN)/CPPNearTreeTestInstNoFlipNoDefer: $(INC)/TNear.h $(EXAMPLES)/CNearTreeTest.cpp $(EXAMPLES)/v.cpp $(BIN) $(CPPBUILD_COMMAND_LOCAL) -DCNEARTREE_INSTRUMENTED -DCNEARTREE_NOFLIP -DCNEARTREE_NODEFER $(EXAMPLES)/CNearTreeTest.cpp $(EXAMPLES)/v.cpp $(CPPLIBRARIES) \ -o $@ $(BIN)/CMain: $(INC)/CNearTree.h $(EXAMPLES)/main.c $(SRC)/CNearTree.c $(BIN) $(LIB)/libCNearTree.$(LIB_EXT) $(BUILD_COMMAND_LOCAL) $(EXAMPLES)/main.c $(SRC)/CNearTree.c $(LIB)/libCNearTree.$(LIB_EXT) $(CLIBRARIES) \ -o $@ $(BIN)/CNearTreeTest: $(INC)/CNearTree.h $(EXAMPLES)/CNearTreeTest.c $(SRC)/CNearTree.c $(BIN) $(LIB)/libCNearTree.$(LIB_EXT) $(BUILD_COMMAND_LOCAL) $(EXAMPLES)/CNearTreeTest.c $(SRC)/CNearTree.c $(LIB)/libCNearTree.$(LIB_EXT) $(CLIBRARIES) \ -o $@ $(BIN)/CNearTreeTestInst: $(INC)/CNearTree.h $(EXAMPLES)/CNearTreeTest.c $(SRC)/CNearTree.c $(BIN) $(LIB)/libCNearTree.$(LIB_EXT) $(BUILD_COMMAND_LOCAL) -DCNEARTREE_INSTRUMENTED $(EXAMPLES)/CNearTreeTest.c $(SRC)/CNearTree.c $(LIB)/libCNearTree.$(LIB_EXT) $(CLIBRARIES) \ -o $@ # # Tests # tests: $(LIB) $(BIN) $(BIN)/CPPMain $(BIN)/CPPMain_Flip $(BIN)/CPPNearTreeTest \ $(BIN)/CPPNearTreeTestInst $(BIN)/CMain $(BIN)/CNearTreeTest \ $(BIN)/CPPNearTreeTestInstFlip $(BIN)/CPPNearTreeTestInstNoDefer \ $(BIN)/CPPNearTreeTestInstNoFlip $(BIN)/CPPNearTreeTestInstNoFlipNoDefer \ $(BIN)/CNearTreeTestInst $(TIME) $(BIN)/CPPMain 3458923 > $(TESTDATA)/CPPMain.lst $(TIME) $(BIN)/CPPMain_Flip 3458923 > $(TESTDATA)/CPPMain_Flip.lst $(TIME) $(BIN)/CMain 3458923 > $(TESTDATA)/CMain.lst $(TIME) $(BIN)/CPPNearTreeTest $(TIME) $(BIN)/CPPNearTreeTestInst $(TIME) $(BIN)/CPPNearTreeTestInstFlip $(TIME) $(BIN)/CPPNearTreeTestInstNoDefer $(TIME) $(BIN)/CPPNearTreeTestInstNoFlip $(TIME) $(BIN)/CNearTreeTest --debug $(TIME) $(BIN)/CNearTreeTestInst --debug ifneq ($(MSYSTEM),MINGW32) diff -b -c $(TESTDATA)/CPPMain_orig.lst $(TESTDATA)/CPPMain.lst diff -b -c $(TESTDATA)/CPPMain_orig.lst $(TESTDATA)/CPPMain_Flip.lst diff -b -c $(TESTDATA)/CMain_orig.lst $(TESTDATA)/CMain.lst else diff -b -c $(TESTDATA)/CPPMain_MINGW_orig.lst $(TESTDATA)/CPPMain.lst diff -b -c $(TESTDATA)/CPPMain_MINGW_orig.lst $(TESTDATA)/CPPMain_Flip.lst diff -b -c $(TESTDATA)/CMain_MINGW_orig.lst $(TESTDATA)/CMain.lst endif # # Remove all non-source files # empty: @-rm -rf $(LIB) @-rm -rf $(BIN) # # Remove temporary files # clean: @-rm -f core @-rm -f *.o @-rm -f *.$(OBJ_EXT) @-rm -f *.c.* @-rm -rf .libs @-rm CMain.lst @-rm CPPMain.lst # # Restore to distribution state # distclean: clean empty ./NearTree-3.1.1/triple.h0000644002342100234170000001011111640401607015065 0ustar bernstehfaculty/* * triple.h * * * Created by Herbert J. Bernstein on 10/26/10. * Copyright 2010 Herbert J. Bernstein * */ /********************************************************************** * * * YOU MAY REDISTRIBUTE THE CVector API UNDER THE TERMS OF THE LGPL * * * **********************************************************************/ /************************* LGPL NOTICES ******************************* * * * This library is free software; you can redistribute it and/or * * modify it under the terms of the GNU Lesser General Public * * License as published by the Free Software Foundation; either * * version 2.1 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 * * Lesser General Public License for more details. * * * * You should have received a copy of the GNU Lesser General Public * * License along with this library; if not, write to the Free * * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, * * MA 02110-1301 USA * * * **********************************************************************/ /************************* PAIR.H NOTICE ****************************** * triple.h was derived from pair.h * * which was subject to the following notice: * * * * Copyright (c) 1994 * * Hewlett-Packard Company * * * * Permission to use, copy, modify, distribute and sell this software * * and its documentation for any purpose is hereby granted without * * fee, provided that the above copyright notice appear in all copies * * and that both that copyright notice and this permission notice * * appear in supporting documentation. Hewlett-Packard Company makes * * no representations about the suitability of this software for any * * purpose. It is provided "as is" without express or implied * * warranty. * * * **********************************************************************/ #ifndef TRIPLE_H #define TRIPLE_H template class triple { private: TR1 m_first; TR2 m_second; TR3 m_third; public: triple() : m_first(TR1()), m_second(TR2()), m_third(TR3()) {} triple(const TR1& first, const TR2& second, const TR3& third ) : m_first(first), m_second(second), m_third(third) {} inline TR1 GetFirst( void ) const { return m_first; } inline TR2 GetSecond( void ) const { return m_second; } inline TR3 GetThird( void ) const { return m_third; } inline bool operator==(const triple& rhs) { return m_first == rhs.GetFirst() && m_second == rhs.m_second && m_third == rhs.m_third; } inline bool operator<(const triple& rhs) { return m_first < rhs.GetFirst() || (m_first == rhs.GetFirst() && m_second < rhs.GetSecond) || (m_first == rhs.GetFirst() && m_second < rhs.GetSecond && m_third < rhs.GetThird); } }; template inline triple make_triple(const TR1& first, const TR2& second, const TR3& third) { return triple(first, second, third); } #endif ./NearTree-3.1.1/v.cpp0000644002342100234170000001026711640401607014402 0ustar bernstehfaculty//* //* v.cpp //* NearTree //* //* Copyright 2001, 2008 Larry Andrews. All rights reserved //* Revised 12 Dec 2008 for sourceforge release -- H. J. Bernstein //********************************************************************** //* * //* YOU MAY REDISTRIBUTE NearTree UNDER THE TERMS OF THE LGPL * //* * //**********************************************************************/ //************************* LGPL NOTICES ******************************* //* * //* This library is free software; you can redistribute it and/or * //* modify it under the terms of the GNU Lesser General Public * //* License as published by the Free Software Foundation; either * //* version 2.1 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 * //* Lesser General Public License for more details. * //* * //* You should have received a copy of the GNU Lesser General Public * //* License along with this library; if not, write to the Free * //* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, * //* MA 02110-1301 USA * //* * //**********************************************************************/ // v.cpp: implementation of the v class. // ////////////////////////////////////////////////////////////////////// #include #include #include #include "v.h" ////////////////////////////////////////////////////////////////////// // Construction/Destruction ////////////////////////////////////////////////////////////////////// v::v( ) { m_bIsDefined = false; m_dvec[0] = DBL_MAX; m_dvec[1] = DBL_MAX; m_dvec[2] = DBL_MAX; } v::~v( ) { m_bIsDefined = false; m_dvec[0] = DBL_MAX; m_dvec[1] = DBL_MAX; m_dvec[2] = DBL_MAX; } v::v( const double& da ) { m_bIsDefined = true; m_dvec[0] = da; m_dvec[1] = da; m_dvec[2] = da; } v::v( const double& da, const double& db, const double& dc ) { m_bIsDefined = true; m_dvec[0] = da; m_dvec[1] = db; m_dvec[2] = dc; } ////////////////////////////////////////////////////////////////////// // Other Stuff ////////////////////////////////////////////////////////////////////// std::ostream& operator<< ( std::ostream& os, const v& v ) { // output a vector os << '{' <=fabs(m_dvec[1]) && fabs(m_dvec[0])>=fabs(m_dvec[2]) ? fabs(m_dvec[0]) : fabs(m_dvec[1])>=fabs(m_dvec[2]) ? fabs(m_dvec[1]) : fabs(m_dvec[2]) ); // Hamming measure (if this is a difference vector) return ( (m_dvec[0]==0 ? 0 : 1) + (m_dvec[1]==0 ? 0 : 1) + (m_dvec[2]==0 ? 0 : 1) ) } double v::Norm( void ) const { return( sqrt( m_dvec[0]*m_dvec[0] + m_dvec[1]*m_dvec[1] + m_dvec[2]*m_dvec[2] ) ); } ./NearTree-3.1.1/CMain_orig.lst0000644002342100234170000000545411640401607016166 0ustar bernstehfaculty Trial 0 from probe point [1.82104, 1.82104, 9.76844] Closest distance 0.343036 to [2, 2, 10] Farthest distance 15.8035 to [10, 10, -1] Returned 1 items within 0.65 of [1.82104,1.82104,9.76844] [2,2,10] ------------------------------------------------------------- Trial 1 from probe point [9.11527, 9.11527, -1.1729] Closest distance 0.237632 to [9, 9, -1] Farthest distance 18.1513 to [-1, -1, 10] Returned 1 items within 0.7 of [9.11527,9.11527,-1.1729] [9,9,-1] ------------------------------------------------------------- Trial 2 from probe point [8.72188, 8.72188, -0.582827] Closest distance 0.573349 to [9, 9, -1] Farthest distance 17.3501 to [-1, -1, 10] Returned 2 items within 0.75 of [8.72188,8.72188,-0.582827] [9,9,-1] [9,9,0] ------------------------------------------------------------- Trial 3 from probe point [0.126652, 0.126652, 12.31] ***** nothing within 0.8 of [0.126652, 0.126652, 12.31] Farthest distance 19.2905 to [10, 10, -1] ------------------------------------------------------------- Trial 4 from probe point [5.38713, 5.38713, 4.41931] Closest distance 0.689605 to [5, 5, 4] Farthest distance 10.6177 to [-1, -1, 10] Returned 4 items within 0.85 of [5.38713,5.38713,4.41931] [5,5,4] [5,5,5] [5,6,4] [6,5,4] ------------------------------------------------------------- Trial 5 from probe point [7.70684, 7.70684, 0.939741] Closest distance 0.418948 to [8, 8, 1] Farthest distance 15.2875 to [-1, -1, 10] Returned 3 items within 0.9 of [7.70684,7.70684,0.939741] [8,8,1] [8,7,1] [7,8,1] ------------------------------------------------------------- Trial 6 from probe point [2.17292, 2.17292, 9.24062] Closest distance 0.343075 to [2, 2, 9] Farthest distance 15.0797 to [10, 10, -1] Returned 4 items within 0.95 of [2.17292,2.17292,9.24062] [2,2,9] [2,2,10] [2,3,9] [3,2,9] ------------------------------------------------------------- Trial 7 from probe point [8.45454, 8.45454, -0.181814] Closest distance 0.668038 to [8, 8, 0] Farthest distance 16.8061 to [-1, -1, 10] Returned 4 items within 1 of [8.45454,8.45454,-0.181814] [8,8,0] [8,9,0] [9,8,0] [9,9,0] ------------------------------------------------------------- Trial 8 from probe point [9.45402, 9.45402, -1.68104] Closest distance 0.935994 to [9, 9, -1] Farthest distance 18.842 to [-1, -1, 10] Returned 4 items within 1.05 of [9.45402,9.45402,-1.68104] [9,9,-1] [9,10,-1] [10,9,-1] [10,10,-1] ------------------------------------------------------------- Trial 9 from probe point [2.69814, 2.69814, 8.45279] Closest distance 0.622297 to [3, 3, 8] Farthest distance 13.9996 to [10, 10, -1] Returned 7 items within 1.1 of [2.69814,2.69814,8.45279] [3,3,8] [3,3,9] [2,3,8] [3,2,8] [2,3,9] [3,2,9] [2,2,8] ------------------------------------------------------------- ./NearTree-3.1.1/CPPMain_orig.lst0000644002342100234170000000532211640401607016420 0ustar bernstehfaculty Trial 0 from probe point {1.82104,1.82104,9.76844} Closest distance 0.343036 to {2,2,10} Farthest distance 15.8035 to {10,10,-1} Returned 1 items within 0.65 of {1.82104,1.82104,9.76844} {2,2,10} ------------------------------------------------------------- Trial 1 from probe point {9.11527,9.11527,-1.1729} Closest distance 0.237632 to {9,9,-1} Farthest distance 18.1513 to {-1,-1,10} Returned 1 items within 0.7 of {9.11527,9.11527,-1.1729} {9,9,-1} ------------------------------------------------------------- Trial 2 from probe point {8.72188,8.72188,-0.582827} Closest distance 0.573349 to {9,9,-1} Farthest distance 17.3501 to {-1,-1,10} Returned 2 items within 0.75 of {8.72188,8.72188,-0.582827} {9,9,-1} {9,9,0} ------------------------------------------------------------- Trial 3 from probe point {0.126652,0.126652,12.31} ***** nothing within 0.8 of {0.126652,0.126652,12.31} Farthest distance 19.2905 to {10,10,-1} ------------------------------------------------------------- Trial 4 from probe point {5.38713,5.38713,4.41931} Closest distance 0.689605 to {5,5,4} Farthest distance 10.6177 to {-1,-1,10} Returned 4 items within 0.85 of {5.38713,5.38713,4.41931} {5,5,4} {5,5,5} {5,6,4} {6,5,4} ------------------------------------------------------------- Trial 5 from probe point {7.70684,7.70684,0.939741} Closest distance 0.418948 to {8,8,1} Farthest distance 15.2875 to {-1,-1,10} Returned 3 items within 0.9 of {7.70684,7.70684,0.939741} {7,8,1} {8,7,1} {8,8,1} ------------------------------------------------------------- Trial 6 from probe point {2.17292,2.17292,9.24062} Closest distance 0.343075 to {2,2,9} Farthest distance 15.0797 to {10,10,-1} Returned 4 items within 0.95 of {2.17292,2.17292,9.24062} {2,2,9} {2,2,10} {2,3,9} {3,2,9} ------------------------------------------------------------- Trial 7 from probe point {8.45454,8.45454,-0.181814} Closest distance 0.668038 to {8,8,0} Farthest distance 16.8061 to {-1,-1,10} Returned 4 items within 1 of {8.45454,8.45454,-0.181814} {8,8,0} {8,9,0} {9,8,0} {9,9,0} ------------------------------------------------------------- Trial 8 from probe point {9.45402,9.45402,-1.68104} Closest distance 0.935994 to {9,9,-1} Farthest distance 18.842 to {-1,-1,10} Returned 4 items within 1.05 of {9.45402,9.45402,-1.68104} {9,9,-1} {9,10,-1} {10,9,-1} {10,10,-1} ------------------------------------------------------------- Trial 9 from probe point {2.69814,2.69814,8.45279} Closest distance 0.622297 to {3,3,8} Farthest distance 13.9996 to {10,10,-1} Returned 7 items within 1.1 of {2.69814,2.69814,8.45279} {2,2,8} {2,3,8} {2,3,9} {3,2,8} {3,2,9} {3,3,8} {3,3,9} ------------------------------------------------------------- ./NearTree-3.1.1/main.cpp0000644002342100234170000001164511640401607015062 0ustar bernstehfaculty//* //* main.cpp //* NearTree //* //* Copyright 2001, 2008 Larry Andrews. All rights reserved //* Revised 12 Dec 2008 for sourceforge release -- H. J. Bernstein //********************************************************************** //* * //* YOU MAY REDISTRIBUTE NearTree UNDER THE TERMS OF THE LGPL * //* * //**********************************************************************/ //************************* LGPL NOTICES ******************************* //* * //* This library is free software; you can redistribute it and/or * //* modify it under the terms of the GNU Lesser General Public * //* License as published by the Free Software Foundation; either * //* version 2.1 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 * //* Lesser General Public License for more details. * //* * //* You should have received a copy of the GNU Lesser General Public * //* License along with this library; if not, write to the Free * //* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, * //* MA 02110-1301 USA * //* * //**********************************************************************/ #include #include #include #include #include #include #include #include "TNear.h" #include "v.h" #ifndef USE_LOCAL_HEADERS #include #else #include "rhrand.h" #endif RHrand rhr; int main ( int argc, char* argv[] ) { CNearTree vTree; v vBest = DBL_MAX; long i,j,k; const long lMaxRow = 10; std::vector vReturn; if (argc <= 1) { rhr.srandom( (unsigned int)time( NULL ) ); /* use the current time to seed the random number generator */ } else { rhr.srandom((unsigned int)atoi(argv[1])); } //--------------------------------------- // build up a library of points to search among //--------------------------------------- for ( k=-1; k<=lMaxRow; k++ ) { for ( j=-1; j<=lMaxRow; j++) { for ( i= lMaxRow ; i>=-1; i-- ) { vTree.insert( v((double)i, (double)j, (double)k) ); } // for i } // for j } // for k std::cout << std::endl; //--------------------------------------- // Done building the tree; now try a retrieval //--------------------------------------- double dRad = 0.6; long lReturn; for ( i=0; i<10; i++ ) { dRad += 0.05; double x = rhr.urand() * double( lMaxRow ) ; double y = x; double z = ( 1.25 * double(lMaxRow) - 1.5 * x ); v vSearch( x, 0.5*(x+y), z ); std::cout << "Trial " << i << " from probe point " << vSearch << std::endl; // find the nearest point to vSearch if ( vTree.NearestNeighbor( dRad, vBest, vSearch ) ) { std::cout << " Closest distance " << (double) ( vSearch - vBest ) << " to " << vBest << std::endl; } else { std::cout << " ***** nothing within " << dRad << " of " << vSearch << std::endl; } // find the farthest point from vSearch if ( vTree.FarthestNeighbor ( vBest, vSearch ) ) { std::cout << " Farthest distance " << (double) ( vSearch - vBest ) << " to " << vBest << std::endl; } else { std::cout << " No Farthest object found" << std::endl; } // search for all points within a "sphere" out to radius dRad if ( ( lReturn = vTree.FindInSphere( dRad, vReturn, vSearch )) > 0 ) { std::cout << " Returned " << lReturn << " items within " << dRad << " of "<< vSearch << std::endl; std::sort(vReturn.begin( ),vReturn.end( )); std::vector ::iterator iv; for ( iv=vReturn.begin( ); iv class CNearTree; // // Nearest Neighbor algorithm after Kalantari and McDonald, // (IEEE Transactions on Software Engineering, v. SE-9, pp. // 631-634,1983) // modified to use recursion instead of a double-linked tree // and simplified so that it does a bit less checking for // things like is the distance to the right less than the // distance to the left; it was found that these checks made little // to no difference in timing. // Later revisions have replaced the use of recursion with a stack, // except for the case of inserting data into the tree. // This template is used to contain a collection of objects. After the // collection has been loaded into this structure, it can be quickly // queried for which object is "closest" to some probe object of the // same type. The major restriction on applicability of the near-tree // is that the algorithm only works if the objects obey the triangle // inequality. The triangle rule states that the length of any side of // a triangle cannot exceed the sum of the lengths of the other two sides. // The user of this class needs to provide at least the following // functionality for the template to work. For the built-in // numerics of C++, they are provided here (or else you should create them). // DistanceType Norm( ); // conversion constructor from the templated class to DistanceType // (usually will return a "length" of type double) // operator- ( ); // geometrical (vector) difference of two objects // a copy constructor would be nice // a constructor would be nice // a destructor would be nice // The provided interface is: // // #include "TNear.h" // // CNearTree( void ) // constructor // instantiated by something like: CNearTree vTree; // for some type T // the following additional convenience constructors are available // // CNearTree( const ContainerType ) // constructor from containers, std::vector, ..., or CNearTree // // void insert( const T& t ) // where t is an object of the type T // the following additional convenience insert template available // all inserts are delayed until a search is performed or until an explicit call to CompleteDelayedInsertions // is called or a search is called. The purpose is to distribute the objects a bit more // randomly. Excessively ordered objects leads to less than optimal trees. // Places objects in a queue for insertion later when CompleteDelayInsert // // void insert( ContainerType ) // for containers, std::vector, ..., or CNearTree // all inserts are delayed until a search is performed or until an explicit call to CompleteDelayedInsertions // // bool NearestNeighbor ( const DistanceType dRadius, T& tClosest, const T& t ) const // dRadius is the largest radius within which to search; make it // very large if you want to include every point that was loaded; dRadius // is returned as the closest distance to the probe (or the search radius // if nothing is found) // tClosest is returned as the object that was found closest to the probe // point (if any were within radius dRadius of the probe) // t is the probe point, used to search in the group of points insert'ed // return value is true if some object was found within the search radius, false otherwise // // iterator NearestNeighbor( const DistanceType radius, const T& probe ); returns an iterator // to the nearest point to the probe point or end() if there is none // // bool FarthestNeighbor ( T& tFarthest, const T& t ) const // tFarthest is returned as the object that was found farthest to the probe // point // t is the probe point, used to search in the group of points insert'ed // return value is true if some object was found, false otherwise // // iterator FarthestNeighbor( const T& probe ); returns an iterator // to the farthest point to the probe point or end() if there is none // // // the following functions (FindInSphere, FindOutSphere, and FindInAnnulus) all return a container // (ContainerType) that can be any standard library container (such as std::vector< T >) or CNearTree. // each has an alternate version in which, in addition the indices of the objects in the // object store are returned in a second parallel vector. // // long FindInSphere ( const DistanceType dRadius, ContainerType& tClosest, const T& t ) const // long FindInSphere ( const DistanceType dRadius, ContainerType& tClosest, std::vector& tIndices, const T& t ) const // dRadius is the radius within which to search; make it very large if you want to // include every point that was loaded; // tClosest is returned as the ContainerType of objects that were found within a radius dRadius // of the probe point // if tIndices is used, it is a vector to which to add the indices of the points found // t is the probe point, used to search in the group of points insert'ed // return value is the number of objects found within the search radius // // long FindOutSphere ( const DistanceType dRadius, ContainerType& tClosest, const T& t ) const // long FindOutSphere ( const DistanceType dRadius, ContainerType& tClosest, std::vector& tIndices, const T& t ) const // dRadius is the radius outside which to search; make it very small if you want to // include every point that was loaded; // tClosest is returned as the ContainerType of objects that were found within a radius dRadius // of the probe point // if tIndices is used, it is a vector to which to add the indices of the points found // t is the probe point, used to search in the group of points insert'ed // return value is the number of objects found within the search radius // // long FindInAnnulus (const DistanceType dRadius1, const DistanceType dRadius2, ContainerType& tClosest, const T& t ) const // long FindInAnnulus (const DistanceType dRadius1, const DistanceType dRadius2, ContainerType& tClosest, std::vector& tIndices, const T& t ) const // dRadius1 and dRadius2 are the two radii between which to find data points // tClosest is returned ContainerType of the objects found in the annulus // if tIndices is used, it is a vector to which to add the indices of the points found // t is the probe point, used to search in the group of points insert'ed // return value is the number of objects found within the search radius // // long FindK_NearestNeighbors ( const size_t k, const DistanceType& radius, OutputContainerType& tClosest, const T& t ) // long FindK_NearestNeighbors ( const size_t k, const DistanceType& radius, OutputContainerType& tClosest, std::vector& tIndices, const T& t ) // k is the maximum number of nearest neighbors to return. Finds this many if possible // radius Within a sphere defined by radius, search for the k-nearest-neighbors // tClosest is returned ContainerType of the objects found within the sphere // if tIndices is used, it is a vector to which to add the indices of the points found // t is the probe point, used to search in the group of points insert'ed // // long FindK_FarthestNeighbors ( const size_t k, OutputContainerType& tClosest, const T& t ) // long FindK_FarthestNeighbors ( const size_t k, OutputContainerType& tClosest, std::vector& tIndices, const T& t ) // k is the maximum number of farthest neighbors to return. Finds this many if possible // tClosest is returned ContainerType of the objects found // if tIndices is used, it is a vector to which to add the indices of the points found // t is the probe point, used to search in the group of points insert'ed // // The variants LeftNearestNeighbor, LeftFarthestNeighbor, LeftFindInSphere, LeftFindOutSphere, // LeftFindInAnnulus, LeftFindK_NearestNeighbors, and LeftFindK_FarthestNeighbors are the // older, search-left-first versions, retained for exiting applications that may require support // for those versions and for testing and validation. Those older versions are deprecated // and may be removed in an upcoming release. // // ~CNearTree( void ) // destructor // // ===================================================================================================== // access functions // // T at( const size_t n ) const // returns the n'th item of the internal data store // // T operator[] ( const size_t n) // returns the n'th item of the internal data store // // operator ContainerType( void ) const // returns all of the inserted objects in the tree in a container of type ContainerType. // ContainerType can be std::vector, etc, or other containers. // The returned vector contents are not guaranteed to be returned in the order loaded. // // iterator begin ( void ) const // returns an iterator to the beginning of the internal data store // // iterator end ( void ) const // returns an iterator to the end of the data store (one beyond the last item) // // iterator back ( void ) const // returns an iterator to the last data item of the internal data store // // ===================================================================================================== // information and special operation functions // ===================================================================================================== // // void ImmediateInsert( void ) Places objects immediately into the tree. The usual insert function // delays insertions, allowing them to be inserted into the tree in a more random order. The delay // can improve the structure of the tree and speed searches. // // void CompleteDelayedInsert( void ) Calls insert for all delayed objects. sqrt(n) of them are inserted // by random choice. The rest are inserted in linear order as originally queued. CompleteDelayedInsert // is invoked at the beginning of all searches, so the average user will never need // to call it. // // size_t GetDeferredSize( void ) Returns the number of delayed objects that have not // yet been insert'ed. This is mainly for information about details of the tree. // // size_t GetTotalSize( void ) Returns the number of objects that have been insert'ed plus // those DelayInsert'ed // // size_t size( void ) identical to GetTotalSize // // size_t GetDepth( void ) Returns the maximum tree layers from the root. This is // mainly for information about details of the tree. // // bool empty( void ) returns true if the tree is empty, otherwise false // // ===================================================================================================== // iterators // Random access iterators are provided for accessing the data in a CNearTree. The most important // expected use is to retrieve the objects returned from one of the sphere search functions that // return a CNearTree. However, they can be used with any CNearTree. // They should function in a fashion essentially the same as STL iterators. There is no assurance // that data will be returned in the order it was loaded, just that it is accessible. The same set is // provided for const_iterator. // ===================================================================================================== // iterator( void ) { }; // constructor // // iterator& operator= ( const iterator& s ) // iterator operator++ ( const int n ) // iterator operator-- ( const int n ) // iterator& operator++ ( void ) // iterator& operator-- ( void ) // iterator operator+ ( const long n ) const // iterator operator- ( const long n ) const // iterator& operator+= ( const long n ) // iterator& operator-= ( const long n ) // T operator* ( void ) const // // bool operator== ( const iterator& t ) const // bool operator!= ( const iterator& t ) const // // const T * const operator-> ( void ) const // // ===================================================================================================== // // So a complete program is: // // #include "TNear.h" // #include // void main() // { // CNearTree< double > dT; // double dNear; // dT.insert( 1.5 ); // if ( dT.FindNearestNeighbor( 10000.0, dNear, 2.0 )) printf( "%f\n",DistanceType(dNear-2.0) ); // } // // and it should print 0.5 (that's how for 2.0 is from 1.5) // // //------------------------------------------------------------------------- #if !defined(TNEAR_H_INCLUDED) #define TNEAR_H_INCLUDED #include #include #include #include #include #ifdef _MSC_VER #define USE_LOCAL_HEADERS #endif #ifndef USE_LOCAL_HEADERS #include #include #else #include "rhrand.h" #include "triple.h" #endif #include #include #include #ifdef CNEARTREE_SAFE_TRIANG #define TRIANG(a,b,c) ( (((b)+(c))-(a) >= 0) \ || ((b)-((a)-(c)) >= 0) \ || ((c)-((a)-(b)) >= 0)) #else #define TRIANG(a,b,c) ( (((b)+(c))-(a) >= 0)) #endif //======================================================================= // CNearTree is the root class for the neartree. The actual data of the // tree is stored in NearTreeNode objects descending from a CNearTree. //======================================================================= template class CNearTree { //======================================================================= // NOTES: // // The types of objects that can be stored in the tree is quite broad. The // biggest limitation is that the objects must reside in some sort of metric // space and must obey the triangle rule. They must also be all of the same // size because they are stored in an std::vector. If your application // requires object of varying storage, then your best way to use this // code is to store pointers or handles and to write your own distance functions. // // The type of the objects to be stored is the only _required_ template argument. // The type of the distance measure (DistanceType) defaults to double. If your // applications is for an integer type then the type for DistanceType can be your // integer type. This has the potential for speeding the calculations by // avoiding FP computation. Other general types can be used if desired, but you // may need to also input a value of distMinValue. // // The template argument distMinValue must be something that your class will // understand as a negative number. The default input is negative one. Internally, // that is cast to DistanceType. Since most uses will be for DistanceType // to be double, that is a simple conversion. Obviously, for integer types, // there is no problem either. The need for this value is to have something // internally that is recognizable as smaller than the smallest "distance" // that can exist between any two objects in your type. For most users, // there is no need to input anything other than the default, -1. -1 must // be castable to DistanceType. It seems unlikely that anyone would actually // need this optional parameter, but it is here for completeness. // // It is a design decision that this class cannot work for unsigned types. // It is hard to see how to verify the triangle rule for unsigned types, // and distance computations become more complex. Sorry, unsigned types // are left as an exercise for the reader. // //======================================================================= // insert copies the input objects into a binary NEAR tree. When a node has // two entries, a descending node is used or created. The current datum is // put into the branch descending from the nearer of the two // objects in the current node. // NearestNeighbor retrieves the object nearest to some probe by descending // the tree to search out the appropriate object. Speed is gained // by pruning the tree if there can be no data below that are // nearer than the best so far found. // The tree is built in time O(n log n), and retrievals take place in // average time O(log n). However, worst case is O(n). public: // DistanceBetween // template function for calculating the "distance" between two objects. // The specific functions for the built-in types must be here also. For // the common types (int, float, ...) they are provided. template static inline DistanceType DistanceBetween( const TT& t1, const TT& t2 ) { DistanceType d = ( t1-t2 ).Norm( ); return( d>0?d:-d ); // apparent compiler error makes this necessary } static inline DistanceType DistanceBetween( const double t1, const double t2 ) { return( (DistanceType)fabs( t1-t2 ) ); // encourage the compiler to get the correct abs } //static inline DistanceType DistanceBetween( const long double t1, const long double t2 ) //{ // return( (DistanceType)fabsl(t1-t2) ); // encourage the compiler to get the correct abs //} static inline DistanceType DistanceBetween( const float t1, const float t2 ) { return( (DistanceType)fabsf( t1-t2 )); // encourage the compiler to get the correct abs } static inline DistanceType DistanceBetween( const int t1, const int t2 ) { return( (DistanceType)abs(t1-t2) ); // encourage the compiler to get the correct abs } static inline DistanceType DistanceBetween( const long t1, const long t2 ) { return( (DistanceType)labs(t1-t2) ); // encourage the compiler to get the correct abs } //static inline DistanceType DistanceBetween( const long long t1, const long long t2 ) //{ // return( (DistanceType)llabs(t1-t2) ); // encourage the compiler to get the correct abs //} static inline DistanceType DistanceBetween( const short t1, const short t2 ) { return( (DistanceType)abs(t1-t2) ); // encourage the compiler to get the correct abs } private: RHrand rhr; // forward declaration of nested class NearTreeNode template class NearTreeNode; public: // Forward declaration for the nested classes, iterator and const_iterator. Friend is necessary // for the access to the appropriate data elements class iterator; friend class iterator; class const_iterator; friend class const_iterator; static const long NTF_NoPrePrune = 1; //flag to supress all search prepruning static const long NTF_ForcePrePrune = 2; //flag to force search prepruning static const long NTF_NoFlip = 4; //flag to suppress flips on insert static const long NTF_ForceFlip = 8; //flag to force flips on insert static const long NTF_NoDefer =16; //flag to prevent deferred insert #ifdef CNEARTREE_FORCEPREPRUNE static const long NFT_FlagDefaultPrune = NTF_ForcePrePrune; #ifdef CNEARTREE_NOPREPRUNE #error "CNEARTREE_NOPREPRUNE conflicts with CNEARTREE_FORCEPREPRUNE" #endif #else #ifdef CNEARTREE_NOPREPRUNE static const long NFT_FlagDefaultPrune = NTF_NoPrePrune; #else static const long NFT_FlagDefaultPrune = 0; #endif #endif #ifdef CNEARTREE_FORCEFLIP static const long NFT_FlagDefaultFlip = NTF_ForceFlip; #ifdef CNEARTREE_NOFLIP #error "CNEARTREE_NOFLIP conflicts with CNEARTREE_FORCEFLIP" #endif #else #ifdef CNEARTREE_NOFLIP static const long NFT_FlagDefaultFlip = NTF_NoFlip; #else static const long NFT_FlagDefaultFlip = 0; #endif #endif #ifdef CNEARTREE_NODEFER static const long NFT_FlagDefaultDefer = NTF_NoDefer; #else static const long NFT_FlagDefaultDefer = 0; #endif static const long NTF_FlagsDefault = NFT_FlagDefaultPrune|NFT_FlagDefaultFlip|NFT_FlagDefaultDefer; private: // start of real definition of CNearTree std::vector m_DelayedIndices; // objects queued for insertion, possibly in random order std::vector m_ObjectStore; // all inserted objects go here size_t m_DeepestDepth; // maximum depth of the tree NearTreeNode m_BaseNode; // the tree's data is stored down from here long m_Flags; // flags for operational control (mainly for testing) DistanceType m_DiamEstimate; // estimated diameter DistanceType m_SumSpacings; // sum of spacings at time of insertion DistanceType m_SumSpacingsSq; // sum of squares of spacings at time of insertion double m_DimEstimate; // estimated dimension double m_DimEstimateEsd; // estimated dimension estimated standard deviation #ifdef CNEARTREE_INSTRUMENTED mutable size_t m_NodeVisits; // number of node visits #endif public: //======================================================================= // CNearTree ( ) // // Default constructor for class CNearTree // creates an empty tree with no right or left node and with the dMax-below // set to negative values so that any match found will be stored since it will // greater than the negative value // //======================================================================= CNearTree ( void ) // constructor : m_DelayedIndices ( ) , m_ObjectStore ( ) , m_DeepestDepth ( 0 ) , m_BaseNode ( ) , m_Flags ( NTF_FlagsDefault ) , m_DiamEstimate ( DistanceType( 0 ) ) , m_SumSpacings ( DistanceType( 0 ) ) , m_SumSpacingsSq ( DistanceType( 0 ) ) , m_DimEstimate ( 0 ) , m_DimEstimateEsd( 0 ) #ifdef CNEARTREE_INSTRUMENTED , m_NodeVisits( 0 ) #endif { } // CNearTree constructor //======================================================================= // CNearTree ( const InputContainer& o ) // // templated constructor for class CNearTree for input of containers. // The containers can be standard library containers or a CNearTree. // //======================================================================= template CNearTree ( const InputContainer& o ) // constructor : m_DelayedIndices ( ) , m_ObjectStore ( ) , m_DeepestDepth ( 0 ) , m_BaseNode ( ) , m_Flags ( NTF_FlagsDefault ) , m_DiamEstimate ( DistanceType( 0 ) ) , m_SumSpacings ( DistanceType( 0 ) ) , m_SumSpacingsSq ( DistanceType( 0 ) ) , m_DimEstimate ( 0 ) , m_DimEstimateEsd( 0 ) #ifdef CNEARTREE_INSTRUMENTED , m_NodeVisits( 0 ) #endif { typename InputContainer::const_iterator it; for( it=o.begin(); it!=o.end(); ++it ) { insert( *it ); } } // CNearTree constructor //======================================================================= // CNearTree ( InputContainer& o ) // // templated constructor for class CNearTree for input of containers. // The containers can be standard library containers or a CNearTree. // //======================================================================= template explicit CNearTree ( InputContainer& o ) // constructor : m_DelayedIndices ( ) , m_ObjectStore ( ) , m_DeepestDepth ( 0 ) , m_BaseNode ( ) , m_Flags ( NTF_FlagsDefault ) , m_DiamEstimate ( DistanceType( 0 ) ) , m_SumSpacings ( DistanceType( 0 ) ) , m_SumSpacingsSq ( DistanceType( 0 ) ) , m_DimEstimate ( 0 ) , m_DimEstimateEsd( 0 ) #ifdef CNEARTREE_INSTRUMENTED , m_NodeVisits( 0 ) #endif { typename InputContainer::iterator it; for( it=o.begin(); it!=o.end(); ++it ) { insert( *it ); } } // CNearTree constructor //======================================================================= // CNearTree ( const InputContainer& o1, const InputContainer& o1 ) // // templated constructor for class CNearTree for merging multiple // containers. // The containers can be standard library containers or CNearTrees. // //======================================================================= template CNearTree ( const InputContainer1& o1, const InputContainer2& o2 ) // constructor : m_DelayedIndices ( ) , m_ObjectStore ( ) , m_DeepestDepth ( 0 ) , m_BaseNode ( ) , m_Flags ( NTF_FlagsDefault ) , m_DiamEstimate ( DistanceType( 0 ) ) , m_SumSpacings ( DistanceType( 0 ) ) , m_SumSpacingsSq ( DistanceType( 0 ) ) , m_DimEstimate ( 0 ) , m_DimEstimateEsd( 0 ) #ifdef CNEARTREE_INSTRUMENTED , m_NodeVisits( 0 ) #endif { typename InputContainer1::const_iterator it1; for( it1=o1.begin(); it1!=o1.end(); ++it1 ) { insert( *it1 ); } typename InputContainer2::const_iterator it2; for( it2=o2.begin(); it2!=o2.end(); ++it2 ) { insert( *it2 ); } } // CNearTree constructor //======================================================================= // ~CNearTree ( ) // // Destructor for class CNearTree // //======================================================================= ~CNearTree ( void ) // destructor { clear ( ); } // ~CNearTree //======================================================================= // Name: Get and Set Flags // Description: get and set tree flags // //======================================================================= long GetFlags( void ) const { return m_Flags; } void SetFlags( const long flags ) { m_Flags = flags; } long GetFlags( const long mask ) const { return m_Flags&mask; } void SetFlags( const long flags, const long mask ) { m_Flags = (flags&mask)|(m_Flags&(~mask)); } //======================================================================= // Name: operator=() // Description: put container's contents into a NearTree, // wiping out the current contents // //======================================================================= template CNearTree& operator= ( const InputContainer& o ) { if (this != &o) { this->clear(); this->insert( o ); this->CompleteDelayedInsert( ); } return( *this ); } template CNearTree& operator= ( InputContainer& o ) { if (this != &o) { this->clear(); this->insert( o ); this->CompleteDelayedInsert( ); } return( *this ); } /* template CNearTree& operator= ( const InputContainer& o ) const { if (this != &o) { this->clear(); this->insert( o ); this->CompleteDelayedInsert( ); } return( *this ); } template CNearTree& operator= ( InputContainer& o ) const { if (this != &o) { this->clear(); this->insert( o ); this->CompleteDelayedInsert( ); } return( *this ); } */ //======================================================================= // Name: operator+=() // Description: add a container's contents to a NearTree // //======================================================================= template CNearTree& operator+= ( const InputContainer& o ) { if ( this->empty( ) ) { // if "this" is empty, all that will remain is "o" this->insert( o ); } else if ( o.empty( ) ) { // do nothing if there is nothing to be added to "this" } else { std::set s1, s2, s3; s1.insert( this->begin( ), this->end( ) ); s2.insert( o.begin(), o.end( ) ); this->clear( ); std::set_union( s1.begin( ), s1.end( ), s2.begin( ), s2.end( ), std::inserter( s3, s3.end( ) ) ); this->insert( s3 ); } this->CompleteDelayedInsert( ); return( *this ); } template CNearTree& operator+= ( InputContainer& o ) { if ( this->empty( ) ) { // if "this" is empty, all that will remain is "o" this->insert( o ); } else if ( o.empty( ) ) { // do nothing if there is nothing to be added to "this" } else { std::set s1, s2, s3; s1.insert( this->begin( ), this->end( ) ); s2.insert( o.begin(), o.end( ) ); this->clear( ); std::set_union( s1.begin( ), s1.end( ), s2.begin( ), s2.end( ), std::inserter( s3, s3.end( ) ) ); this->insert( s3 ); } this->CompleteDelayedInsert( ); return( *this ); } //======================================================================= // Name: operator-=() // Description: removes a container's contents from a NearTree // //======================================================================= template CNearTree& operator-= ( const InputContainer& o ) { if ( this->empty( ) ) {// nothing to do if there's nothing to remove from } else if ( o.empty( ) ) { // do nothing if there is nothing to be removed } else { std::set s1, s2, s3; s1.insert( this->begin( ), this->end( ) ); s2.insert( o.begin(), o.end( ) ); this->clear( ); std::set_difference( s1.begin( ), s1.end( ), s2.begin( ), s2.end( ), std::inserter( s3, s3.end( ) ) ); this->insert( s3 ); } this->CompleteDelayedInsert( ); return( *this ); } template CNearTree& operator-= ( InputContainer& o ) { if ( this->empty( ) ) {// nothing to do if there's nothing to remove from } else if ( o.empty( ) ) { // do nothing if there is nothing to be removed } else { std::set s1, s2, s3; s1.insert( this->begin( ), this->end( ) ); s2.insert( o.begin(), o.end( ) ); this->clear( ); std::set_difference( s1.begin( ), s1.end( ), s2.begin( ), s2.end( ), std::inserter( s3, s3.end( ) ) ); this->insert( s3 ); } this->CompleteDelayedInsert( ); return( *this ); } //======================================================================= // Name: set_symmetric_difference() // Description: removes the portion container's contents from a NearTree // that is already in the NearTree and add in the portion // of the container's contents that is not already in the // NearTree // (= Sheffer stroke operation and NAND = exclusive or) // //======================================================================= template CNearTree& set_symmetric_difference ( const InputContainer& o ) { if ( o.empty( ) ) { // do nothing if "this" is already complete } else if ( this->empty( ) ) { // all that will remain is the content of "o" this->insert( o ); } else { std::set s1, s2, s3; s1.insert( this->begin( ), this->end( ) ); s2.insert( o.begin(), o.end( ) ); this->clear( ); std::set_symmetric_difference( s1.begin( ), s1.end( ), s2.begin( ), s2.end( ), std::inserter( s3, s3.end( ) ) ); this->insert( s3 ); } this->CompleteDelayedInsert( ); return( *this ); } template CNearTree& set_symmetric_difference ( InputContainer& o ) { if ( o.empty( ) ) { // do nothing if "this" is already complete } else if ( this->empty( ) ) { // all that will remain is the content of "o" this->insert( o ); } else { std::set s1, s2, s3; s1.insert( this->begin( ), this->end( ) ); s2.insert( o.begin(), o.end( ) ); this->clear( ); std::set_symmetric_difference( s1.begin( ), s1.end( ), s2.begin( ), s2.end( ), std::inserter( s3, s3.end( ) ) ); this->insert( s3 ); } this->CompleteDelayedInsert( ); return( *this ); } //======================================================================= // clear( void ) // // removes all content from a tree // //======================================================================= void clear ( void ) { this->m_BaseNode .clear( ); // clear the nodes of the tree if ( ! this->m_DelayedIndices.empty( ) ) { std::vector vtempLong; m_DelayedIndices.swap( vtempLong ); // release any delayed indices list } if ( ! this->m_ObjectStore.empty( ) ) { std::vector vtempT; this->m_ObjectStore.swap( vtempT ); // release the object store } this->m_DeepestDepth = 0; this->m_DiamEstimate = DistanceType( 0 ); this->m_SumSpacings = DistanceType( 0 ); this->m_SumSpacingsSq = DistanceType( 0 ); this->m_DimEstimate = 0; this->m_DimEstimateEsd = 0; #ifdef CNEARTREE_INSTRUMENTED this->m_NodeVisits = 0; #endif } //======================================================================= // empty ( ) // // Test for an empty CNearTree // //======================================================================= bool empty ( void ) const { return ( m_ObjectStore.empty( ) ); } //======================================================================= // void insert ( const T& t ) // // Function to insert some "point" as an object into a CNearTree for // later searching // // t is an object of the templated type which is to be inserted into a // NearTree // // The function ImmediateInsert immediately inserts the object into the tree. // insert keeps the object in an internal store, but does not // immediately insert it. The object in the internal store are only inserted // when CompleteDelayedInsert is called or when one of the search functions // is invoked (they call CompleteDelayedInsert). When that is called, all // of the stored objects are then inserted into the list in a way designed // to give a relatively more balanced tree even if the data are strongly sorted. // //======================================================================= void insert ( const T& t ) { m_ObjectStore .push_back( t ); m_DelayedIndices .push_back( (long)m_ObjectStore.size( ) - 1 ); if ((m_Flags & NTF_NoDefer) && (m_DeepestDepth < 100)) { this->CompleteDelayedInsert(); } m_DimEstimate = 0; m_DimEstimateEsd= 0; }; //======================================================================= // insert( const iterator& i, const T& t ) // // dummy here just for compatibility with std::vector and std::list, etc. //======================================================================= void insert( const iterator& /*i*/, const T& t ) { insert( t ); } //======================================================================= // insert ( const InputContainer& o ) // // Function to insert a containerful for data into a CNearTree. Standard // Library containers and CNearTree's can be used. // // insert keeps the object in an internal store, but does not // immediately insert it. The object in the internal store are only inserted // when CompleteDelayedInsert is called or when one of the search functions // is invoked (they call CompleteDelayedInsert). When that is called, all // of the stored objects are then inserted into the list in a way designed // to give a relatively more balanced tree even if the data are strongly sorted. // //======================================================================= template< typename InputContainer > void insert ( const InputContainer& o ) { typename InputContainer::const_iterator it; for( it=o.begin(); it!=o.end(); ++it ) { m_ObjectStore .push_back( *it ); m_DelayedIndices .push_back( (long)m_ObjectStore.size( ) - 1 ); } if ((m_Flags & NTF_NoDefer) && (m_DeepestDepth < 100)) { this->CompleteDelayedInsert(); } m_DimEstimate = 0; m_DimEstimateEsd= 0; } //======================================================================= // void ImmediateInsert ( const T& t ) // // Function to insert some "point" as an object into a CNearTree for // later searching. Data is immediately put into the tree, instead of // being delayed (as function insert does). Use insert unless there is // some known need to insert immediately. // // t is an object of the templated type which is to be inserted into a // NearTree // // Three possibilities exist: put the datum into the left // position (first test),into the right position, or else // into a node descending from the nearer of those positions // when they are both already used. // //======================================================================= void ImmediateInsert ( const T& t ) { size_t localDepth = 0; const long n = m_ObjectStore.size(); m_ObjectStore.push_back(t); if ( (m_Flags & NTF_ForceFlip) ) { m_BaseNode.InserterDelayed_Flip( n, localDepth, m_ObjectStore, m_SumSpacings, m_SumSpacingsSq ); } else if ( !(m_Flags & NTF_NoFlip) ) { m_BaseNode.InserterDelayed_Flip( n, localDepth, m_ObjectStore, m_SumSpacings, m_SumSpacingsSq ); } else { m_BaseNode.InserterDelayed( n, localDepth, m_ObjectStore, m_SumSpacings, m_SumSpacingsSq ); } m_DeepestDepth = std::max( localDepth, m_DeepestDepth ); m_DiamEstimate = m_BaseNode.GetDiamEstimate(m_ObjectStore); m_DimEstimate = 0; m_DimEstimateEsd= 0; } //======================================================================= // ImmediateInsert ( const InputContainer& o ) // // see the description of ImmediateInsert above // //======================================================================= template< typename InputContainer > void ImmediateInsert ( const InputContainer& o ) { size_t localDepth = 0; typename InputContainer::const_iterator it; long n; if ( (m_Flags & NTF_ForceFlip) || !(m_Flags & NTF_NoFlip) ) { for( it=o.begin(); it!=o.end(); ++it ) { n = m_ObjectStore.size(); m_ObjectStore.push_back(*it); localDepth = 0; m_BaseNode.InserterDelayed_Flip( n, localDepth, m_ObjectStore, m_SumSpacings, m_SumSpacingsSq ); m_DeepestDepth = std::max( localDepth, m_DeepestDepth ); } } else { for( it=o.begin(); it!=o.end(); ++it ) { n = m_ObjectStore.size(); m_ObjectStore.push_back(*it); localDepth = 0; m_BaseNode.InserterDelayed( n, localDepth, m_ObjectStore, m_SumSpacings, m_SumSpacingsSq ); m_DeepestDepth = std::max( localDepth, m_DeepestDepth ); } } m_DiamEstimate = m_BaseNode.GetDiamEstimate(m_ObjectStore); m_DimEstimate = 0; m_DimEstimateEsd= 0; } //======================================================================= // iterator NearestNeighbor ( const DistanceType &radius, const T& t ) const // // Function to search a NearTree for the object closest to some probe point, t. This function // is only here so that the function Nearest can be called without having the radius const. // This was necessary because Nearest is recursive, but needs to keep the current smallest radius. // // dRadius is the maximum search radius - any point farther than dRadius from the probe // point will be ignored // t is the probe point // // the return is an iterator to the templated type and is the returned nearest point // to the probe point (t) that can be found in the NearTree // or iterator::end if no point was found // // This version used the balanced search //======================================================================= inline iterator NearestNeighbor ( const DistanceType& radius, const T& t ) const { T closest; size_t index = ULONG_MAX; DistanceType tempRadius = radius; const_cast(this)->CompleteDelayedInsert( ); if( this->empty( ) || radius < DistanceType( 0 ) ) { return ( iterator(end( )) ); } else if ( m_BaseNode.Nearest( tempRadius, closest, t, index, m_ObjectStore #ifdef CNEARTREE_INSTRUMENTED , m_NodeVisits #endif ) ) { return ( iterator( (long)index, this ) ); } else { return ( iterator(end( )) ); } }// NearestNeighbor //======================================================================= // iterator LeftNearestNeighbor ( const DistanceType &radius, const T& t ) const // // Function to search a NearTree for the object closest to some probe point, t. This function // is only here so that the function Nearest can be called without having the radius const. // This was necessary because Nearest is recursive, but needs to keep the current smallest radius. // // dRadius is the maximum search radius - any point farther than dRadius from the probe // point will be ignored // t is the probe point // // the return is an iterator to the templated type and is the returned nearest point // to the probe point (t) that can be found in the NearTree // or iterator::end if no point was found // // This version used the left-first search //======================================================================= inline iterator LeftNearestNeighbor ( const DistanceType& radius, const T& t ) const { T closest; size_t index = ULONG_MAX; DistanceType tempRadius = radius; const_cast(this)->CompleteDelayedInsert( ); if( this->empty( ) || radius < DistanceType( 0 ) ) { return ( iterator(end( )) ); } else if ( m_BaseNode.LeftNearest( tempRadius, closest, t, index, m_ObjectStore #ifdef CNEARTREE_INSTRUMENTED , m_NodeVisits #endif ) ) { return ( iterator( (long)index, this ) ); } else { return ( iterator(end( )) ); } }// LeftNearestNeighbor //======================================================================= // bool NearestNeighbor ( const DistanceType& dRadius, T& tClosest, const T& t ) const // // Function to search a NearTree for the object closest to some probe point, t. This function // is only here so that the function Nearest can be called without having the radius const. // This was necessary because Nearest is recursive, but needs to keep the current smallest radius. // // dRadius is the maximum search radius - any point farther than dRadius from the probe // point will be ignored // tClosest is an object of the templated type and is the returned nearest point // to the probe point that can be found in the NearTree // t is the probe point // // the return value is true only if a point was found // // // This version used the balanced search //======================================================================= inline bool NearestNeighbor ( const DistanceType& dRadius, T& tClosest, const T& t ) const { const_cast(this)->CompleteDelayedInsert( ); if ( dRadius < DistanceType(0) ) { return ( false ); } else if ( this->empty( ) ) { return ( false ); } else { DistanceType dSearchRadius = dRadius; size_t index = ULONG_MAX; return ( this->m_BaseNode.Nearest ( dSearchRadius, tClosest, t, index, m_ObjectStore #ifdef CNEARTREE_INSTRUMENTED , m_NodeVisits #endif ) ); } } // NearestNeighbor //======================================================================= // bool LeftNearestNeighbor ( const DistanceType& dRadius, T& tClosest, const T& t ) const // // Function to search a NearTree for the object closest to some probe point, t. This function // is only here so that the function Nearest can be called without having the radius const. // This was necessary because Nearest is recursive, but needs to keep the current smallest radius. // // dRadius is the maximum search radius - any point farther than dRadius from the probe // point will be ignored // tClosest is an object of the templated type and is the returned nearest point // to the probe point that can be found in the NearTree // t is the probe point // // the return value is true only if a point was found // // // This version used the left-first search //======================================================================= inline bool LeftNearestNeighbor ( const DistanceType& dRadius, T& tClosest, const T& t ) const { const_cast(this)->CompleteDelayedInsert( ); if ( dRadius < DistanceType(0) ) { return ( false ); } else if ( this->empty( ) ) { return ( false ); } else { DistanceType dSearchRadius = dRadius; size_t index = ULONG_MAX; return ( this->m_BaseNode.LeftNearest ( dSearchRadius, tClosest, t, index, m_ObjectStore #ifdef CNEARTREE_INSTRUMENTED , m_NodeVisits #endif ) ); } } // LeftNearestNeighbor //======================================================================= // iterator ShortNearestNeighbor ( const DistanceType &radius, const T& t ) // // Function to search a NearTree for the object closest to some probe point, t. This function // is only here so that the function Nearest can be called without having the radius const. // This was necessary because Nearest is recursive, but needs to keep the current smallest radius. // // dRadius is the maximum search radius - any point farther than dRadius from the probe // point will be ignored // t is the probe point // // the return is an iterator to the templated type and is the returned nearest point // to the probe point (t) that can be found in the NearTree // or iterator::end if no point was found // // This version uses the short-radius balanced search //======================================================================= inline iterator ShortNearestNeighbor ( const DistanceType& radius, const T& t ) { T closest; size_t dimest; size_t index = ULONG_MAX; DistanceType tempRadius = radius; const_cast(this)->CompleteDelayedInsert( ); if( this->empty( ) || radius < DistanceType( 0 ) ) { return ( iterator(end( )) ); } else if (!(m_Flags & NTF_NoPrePrune) && (dimest=(this)->GetDimEstimate())>0) { DistanceType shortRadius = m_DiamEstimate/DistanceType((1+m_ObjectStore.size())); DistanceType limitRadius = 10*m_DiamEstimate/DistanceType((1+m_ObjectStore.size())); DistanceType meanSpacing = m_SumSpacings/DistanceType((1+m_ObjectStore.size())); DistanceType varSpacing = m_SumSpacingsSq/DistanceType((1+m_ObjectStore.size()))-meanSpacing*meanSpacing; if (limitRadius > radius/2.) limitRadius = radius/2.; if (limitRadius > meanSpacing/2.) limitRadius = meanSpacing/2.; double lineardensity=pow((double)m_ObjectStore.size(),1./(dimest)); if (shortRadius > DistanceType( 0 ) && ( (varSpacing < 0.25*meanSpacing*meanSpacing/(dimest) || (lineardensity*((double)meanSpacing) > 1.) || (m_Flags & NTF_ForcePrePrune)))) { DistanceType testRadius; while (shortRadius <= limitRadius) { testRadius = shortRadius; if (m_BaseNode.Nearest ( testRadius, closest, t, index, m_ObjectStore #ifdef CNEARTREE_INSTRUMENTED , m_NodeVisits #endif )) return iterator( (long)index, this ); shortRadius *= DistanceType(10); } } if ( m_BaseNode.Nearest( tempRadius, closest, t, index, m_ObjectStore #ifdef CNEARTREE_INSTRUMENTED , m_NodeVisits #endif ) ) { return ( iterator( (long)index, this ) ); } else { return ( iterator(end( )) ); } } else if ( m_BaseNode.Nearest( tempRadius, closest, t, index, m_ObjectStore #ifdef CNEARTREE_INSTRUMENTED , m_NodeVisits #endif ) ) { return ( iterator( (long)index, this ) ); } else { return ( iterator(end( )) ); } } // end ShortNeartestNeighbor //======================================================================= // bool ShortNearestNeighbor ( const DistanceType& dRadius, T& tClosest, const T& t ) const // // Function to search a NearTree for the object closest to some probe point, t. This function // is only here so that the function Nearest can be called without having the radius const. // This was necessary because Nearest is recursive, but needs to keep the current smallest radius. // // dRadius is the maximum search radius - any point farther than dRadius from the probe // point will be ignored // tClosest is an object of the templated type and is the returned nearest point // to the probe point that can be found in the NearTree // t is the probe point // // the return value is true only if a point was found // // This version will handle the short radius pruning // // // This version uses the short-radius balanced search //======================================================================= inline bool ShortNearestNeighbor ( const DistanceType& dRadius, T& tClosest, const T& t ) { size_t index = ULONG_MAX; double dimest; const_cast(this)->CompleteDelayedInsert( ); DistanceType dSearchRadius = dRadius; if ( dRadius < DistanceType(0) ) { return ( false ); } else if ( this->empty( ) ) { return ( false ); } else { if (!(m_Flags & NTF_NoPrePrune) && (dimest=(this)->GetDimEstimate())>0.) { DistanceType shortRadius = m_DiamEstimate/DistanceType((1+m_ObjectStore.size())); DistanceType limitRadius = 10.0*m_DiamEstimate/DistanceType((1+m_ObjectStore.size())); DistanceType meanSpacing = m_SumSpacings/DistanceType((1+m_ObjectStore.size())); DistanceType varSpacing = m_SumSpacingsSq/DistanceType((1+m_ObjectStore.size()))-meanSpacing*meanSpacing; if (limitRadius > dRadius/2.) limitRadius = dRadius/2.; if (limitRadius > meanSpacing/2.) limitRadius = meanSpacing/2.; bool bReturn; double lineardensity=pow((double)m_ObjectStore.size(),1./(dimest)); if (shortRadius > DistanceType( 0 ) && ( (varSpacing < 0.25*meanSpacing*meanSpacing/(dimest) || (lineardensity*((double)meanSpacing) > 1.) || (m_Flags & NTF_ForcePrePrune)))) { DistanceType testRadius; while (shortRadius <= limitRadius) { testRadius = shortRadius; if (bReturn = this->m_BaseNode.Nearest ( testRadius, tClosest, t, index, m_ObjectStore #ifdef CNEARTREE_INSTRUMENTED , m_NodeVisits #endif ), bReturn) return bReturn; shortRadius *= DistanceType(10); } } } return ( this->m_BaseNode.Nearest ( dSearchRadius, tClosest, t, index, m_ObjectStore #ifdef CNEARTREE_INSTRUMENTED , m_NodeVisits #endif ) ); } } // end ShortNearestNeighbor //======================================================================= // iterator LeftShortNearestNeighbor ( const DistanceType &radius, const T& t ) // // Function to search a NearTree for the object closest to some probe point, t. This function // is only here so that the function Nearest can be called without having the radius const. // This was necessary because Nearest is recursive, but needs to keep the current smallest radius. // // dRadius is the maximum search radius - any point farther than dRadius from the probe // point will be ignored // t is the probe point // // the return is an iterator to the templated type and is the returned nearest point // to the probe point (t) that can be found in the NearTree // or iterator::end if no point was found // // This version used the short-radius left-first search //======================================================================= inline iterator LeftShortNearestNeighbor ( const DistanceType& radius, const T& t ) { T closest; size_t dimest; size_t index = ULONG_MAX; DistanceType tempRadius = radius; const_cast(this)->CompleteDelayedInsert( ); if( this->empty( ) || radius < DistanceType( 0 ) ) { return ( iterator(end( )) ); } else if (!(m_Flags & NTF_NoPrePrune) && (dimest=(this)->GetDimEstimate())>0) { DistanceType shortRadius = m_DiamEstimate/DistanceType((1+m_ObjectStore.size())); DistanceType limitRadius = 10*m_DiamEstimate/DistanceType((1+m_ObjectStore.size())); DistanceType meanSpacing = m_SumSpacings/DistanceType((1+m_ObjectStore.size())); DistanceType varSpacing = m_SumSpacingsSq/DistanceType((1+m_ObjectStore.size()))-meanSpacing*meanSpacing; if (limitRadius > radius/2.) limitRadius = radius/2.; if (limitRadius > meanSpacing/2.) limitRadius = meanSpacing/2.; double lineardensity=pow((double)m_ObjectStore.size(),1./(dimest)); if (shortRadius > DistanceType( 0 ) && ( (varSpacing < 0.25*meanSpacing*meanSpacing/(dimest) || (lineardensity*((double)meanSpacing) > 1.) || (m_Flags & NTF_ForcePrePrune)))) { DistanceType testRadius; while (shortRadius <= limitRadius) { testRadius = shortRadius; if (m_BaseNode.Nearest ( testRadius, closest, t, index, m_ObjectStore #ifdef CNEARTREE_INSTRUMENTED , m_NodeVisits #endif )) return iterator( (long)index, this ); shortRadius *= DistanceType(10); } } if ( m_BaseNode.LeftNearest( tempRadius, closest, t, index, m_ObjectStore #ifdef CNEARTREE_INSTRUMENTED , m_NodeVisits #endif ) ) { return ( iterator( (long)index, this ) ); } else { return ( iterator(end( )) ); } } else if ( m_BaseNode.LeftNearest( tempRadius, closest, t, index, m_ObjectStore #ifdef CNEARTREE_INSTRUMENTED , m_NodeVisits #endif ) ) { return ( iterator( (long)index, this ) ); } else { return ( iterator(end( )) ); } } // sedn LeftShortNearestNeightbor //======================================================================= // bool LeftShortNearestNeighbor ( const DistanceType& dRadius, T& tClosest, const T& t ) const // // Function to search a NearTree for the object closest to some probe point, t. This function // is only here so that the function Nearest can be called without having the radius const. // This was necessary because Nearest is recursive, but needs to keep the current smallest radius. // // dRadius is the maximum search radius - any point farther than dRadius from the probe // point will be ignored // tClosest is an object of the templated type and is the returned nearest point // to the probe point that can be found in the NearTree // t is the probe point // // the return value is true only if a point was found // // This version uses the short-radius left-first search //======================================================================= inline bool LeftShortNearestNeighbor ( const DistanceType& dRadius, T& tClosest, const T& t ) { size_t index = ULONG_MAX; double dimest; const_cast(this)->CompleteDelayedInsert( ); DistanceType dSearchRadius = dRadius; if ( dRadius < DistanceType(0) ) { return ( false ); } else if ( this->empty( ) ) { return ( false ); } else { if (!(m_Flags & NTF_NoPrePrune) && (dimest=(this)->GetDimEstimate())>0.) { DistanceType shortRadius = m_DiamEstimate/DistanceType((1+m_ObjectStore.size())); DistanceType limitRadius = 10.0*m_DiamEstimate/DistanceType((1+m_ObjectStore.size())); DistanceType meanSpacing = m_SumSpacings/DistanceType((1+m_ObjectStore.size())); DistanceType varSpacing = m_SumSpacingsSq/DistanceType((1+m_ObjectStore.size()))-meanSpacing*meanSpacing; if (limitRadius > dRadius/2.) limitRadius = dRadius/2.; if (limitRadius > meanSpacing/2.) limitRadius = meanSpacing/2.; bool bReturn; double lineardensity=pow((double)m_ObjectStore.size(),1./(dimest)); if (shortRadius > DistanceType( 0 ) && ( (varSpacing < 0.25*meanSpacing*meanSpacing/(dimest) || (lineardensity*((double)meanSpacing) > 1.) || (m_Flags & NTF_ForcePrePrune)))) { DistanceType testRadius; while (shortRadius <= limitRadius) { testRadius = shortRadius; if (bReturn = this->m_BaseNode.LeftNearest ( testRadius, tClosest, t, index, m_ObjectStore #ifdef CNEARTREE_INSTRUMENTED , m_NodeVisits #endif )) return bReturn; shortRadius *= DistanceType(10); } } } return ( this->m_BaseNode.LeftNearest ( dSearchRadius, tClosest, t, index, m_ObjectStore #ifdef CNEARTREE_INSTRUMENTED , m_NodeVisits #endif ) ); } } // LeftNearestNearestNeighbor //======================================================================= // iterator FarthestNeighbor ( const T& t ) const // // Function to search a NearTree for the object farthest from some probe point, t. This function // is only here so that the function Farthest can be called without having the radius const. // This was necessary because Farthest is recursive, but needs to keep the current largest radius. // // t is the probe point // // the return is an iterator to the templated type and is the returned farthest point // from the probe point (t) that can be found in the NearTree // or iterator::end if no point was found // // This version uses the balanced search //======================================================================= iterator FarthestNeighbor ( const T& t ) const { T farthest; size_t index = ULONG_MAX; DistanceType radius = DistanceType( distMinValue ); const_cast(this)->CompleteDelayedInsert( ); if( this->empty( ) ) { return ( iterator(this->end( )) ); } else if ( m_BaseNode.Farthest( radius, farthest, t, index, m_ObjectStore #ifdef CNEARTREE_INSTRUMENTED , m_NodeVisits #endif ) ) { return ( iterator( (long)index, this ) ); } else { return ( iterator(this->end( )) ); } } //======================================================================= // iterator LeftFarthestNeighbor ( const T& t ) const // // Function to search a NearTree for the object farthest from some probe point, t. This function // is only here so that the function Farthest can be called without having the radius const. // This was necessary because Farthest is recursive, but needs to keep the current largest radius. // // t is the probe point // // the return is an iterator to the templated type and is the returned farthest point // from the probe point (t) that can be found in the NearTree // or iterator::end if no point was found // // This version uses the left-first search //======================================================================= iterator LeftFarthestNeighbor ( const T& t ) const { T farthest; size_t index = ULONG_MAX; DistanceType radius = DistanceType( distMinValue ); const_cast(this)->CompleteDelayedInsert( ); if( this->empty( ) ) { return ( end( ) ); } else if ( m_BaseNode.LeftFarthest( radius, farthest, t, index, m_ObjectStore #ifdef CNEARTREE_INSTRUMENTED , m_NodeVisits #endif ) ) { return ( iterator( (long)index, this ) ); } else { return ( end( ) ); } } //======================================================================= // bool FarthestNeighbor ( T& tFarthest, const T& t ) const // // Function to search a NearTree for the object farthest from some probe point, t. This function // is only here so that the function FarthestNeighbor can be called without the user // having to input a search radius and so the search radius can be guaranteed to be // negative at the start. // // tFarthest is an object of the templated type and is the returned farthest point // from the probe point that can be found in the NearTree // t is the probe point // // the return value is true only if a point was found (should only be false for // an empty tree) // //======================================================================= bool FarthestNeighbor ( T& tFarthest, const T& t ) const { const_cast(this)->CompleteDelayedInsert( ); if ( this->empty( ) ) { return ( false ); } else { DistanceType dSearchRadius = DistanceType( distMinValue ); size_t index = ULONG_MAX; return ( this->m_BaseNode.Farthest ( dSearchRadius, tFarthest, t, index, m_ObjectStore #ifdef CNEARTREE_INSTRUMENTED , m_NodeVisits #endif ) ); } } // FarthestNeighbor //======================================================================= // bool LeftFarthestNeighbor ( T& tFarthest, const T& t ) const // // Function to search a NearTree for the object farthest from some probe point, t. This function // is only here so that the function FarthestNeighbor can be called without the user // having to input a search radius and so the search radius can be guaranteed to be // negative at the start. // // tFarthest is an object of the templated type and is the returned farthest point // from the probe point that can be found in the NearTree // t is the probe point // // the return value is true only if a point was found (should only be false for // an empty tree) // // This version uses the left-first search //======================================================================= bool LeftFarthestNeighbor ( T& tFarthest, const T& t ) const { const_cast(this)->CompleteDelayedInsert( ); if ( this->empty( ) ) { return ( false ); } else { DistanceType dSearchRadius = DistanceType( distMinValue ); size_t index = ULONG_MAX; return ( this->m_BaseNode.LeftFarthest ( dSearchRadius, tFarthest, t, index, m_ObjectStore #ifdef CNEARTREE_INSTRUMENTED , m_NodeVisits #endif ) ); } } // LeftFarthestNeighbor //======================================================================= template void BelongsToPoints( const T& t1, const T& t2, ContainerType& group1, ContainerType& group2 ) { group1.clear(); group2.clear(); typename CNearTree::iterator it; for ( it=this->begin( ); it!=this->end( ); ++it ) { if( DistanceBetween( (*it), t1 ) < DistanceBetween( (*it), t2) ) { group1.insert( group1.end( ), (*it) ); } else { group2.insert( group2.end(), (*it) ); } } } // end BelongsToPoints template void BelongsToPoints( const T& t1, const T& t2, ContainerType& group1, ContainerType& group2, std::vector& group1_ordinals, std::vector& group2_ordinals) { group1.clear(); group2.clear(); typename CNearTree::iterator it; for ( it=this->begin( ); it!=this->end( ); ++it ) { if( DistanceBetween( (*it), t1 ) < DistanceBetween( (*it), t2) ) { group1.insert( group1.end( ), (*it) ); group1_ordinals.insert( group1_ordinals.end( ), it.get_position( ) ); } else { group2.insert( group2.end(), (*it) ); group2_ordinals.insert( group2_ordinals.end( ), it.get_position( ) ); } } } // end BelongsToPoints //======================================================================= template void SeparateByRadius( const DistanceType radius, const T& probe, ContainerTypeInside& inside, ContainerTypeOutside& outside ) { inside.clear(); outside.clear(); typename CNearTree::iterator it; for ( it=this->begin( ); it!=this->end( ); ++it ) { if( DistanceBetween( (*it), probe ) < radius ) { inside.insert( inside.end( ), (*it) ); } else { outside.insert( outside.end(), (*it) ); } } // The following was the first cut, but it's slower. //const long nInside = FindInSphere ( radius, inside, tProbe ); //const long nOutside = FindOutSphere( radius, outside, tProbe ); } // end SeparateByRadius //======================================================================= template void SeparateByRadius( const DistanceType radius, const T& probe, ContainerTypeInside& inside, ContainerTypeOutside& outside, std::vector& inside_ordinals, std::vector& outside_ordinals) { inside.clear(); outside.clear(); typename CNearTree::iterator it; for ( it=this->begin( ); it!=this->end( ); ++it ) { if( DistanceBetween( (*it), probe ) < radius ) { inside.insert( inside.end( ), (*it) ); inside_ordinals.insert( inside_ordinals.end( ), it.get_position()); } else { outside.insert( outside.end(), (*it) ); inside_ordinals.insert( outside_ordinals.end( ), it.get_position()); } } // The following was the first cut, but it's slower. //const long nInside = FindInSphere ( radius, inside, tProbe ); //const long nOutside = FindOutSphere( radius, outside, tProbe ); } // end SeparateByRadius //======================================================================= // long FindInSphere ( const DistanceType& dRadius, OutputContainerType& tClosest, const T& t ) const // // Function to search a NearTree for the set of objects closer to some probe point, t, // than dRadius. This is only here so that tClosest can be cleared before starting the work. // // dRadius is the maximum search radius - any point farther than dRadius from the probe // point will be ignored // tClosest is returned as a container of objects of the templated type and is the // returned set of nearest points to the probe point that can be found // in the NearTree. The container can be a Standard Library container or // a CNearTree // t is the probe point // // returns the number of objects returned in the container (for sets, that may not equal the number found) // //======================================================================= template inline long FindInSphere ( const DistanceType& dRadius, OutputContainerType& tClosest, const T& t ) const { // clear the contents of the return vector so that things don't accidentally accumulate tClosest.clear( ); const_cast(this)->CompleteDelayedInsert( ); if( this->empty( ) ) { return( 0L ); } else { return ( m_BaseNode.InSphere( dRadius, tClosest, t, m_ObjectStore #ifdef CNEARTREE_INSTRUMENTED , m_NodeVisits #endif ) ); } } // FindInSphere template inline long FindInSphere ( const DistanceType& dRadius, OutputContainerType& tClosest, std::vector& tIndices, const T& t ) const { // clear the contents of the return vector so that things don't accidentally accumulate tClosest.clear( ); tIndices.clear( ); const_cast(this)->CompleteDelayedInsert( ); if( this->empty( ) ) { return( 0L ); } else { return ( m_BaseNode.InSphere( dRadius, tClosest, tIndices, t, m_ObjectStore #ifdef CNEARTREE_INSTRUMENTED , m_NodeVisits #endif ) ); } } // FindInSphere //======================================================================= // long LeftFindInSphere ( const DistanceType& dRadius, OutputContainerType& tClosest, const T& t ) const // // Function to search a NearTree for the set of objects closer to some probe point, t, // than dRadius. This is only here so that tClosest can be cleared before starting the work. // // dRadius is the maximum search radius - any point farther than dRadius from the probe // point will be ignored // tClosest is returned as a container of objects of the templated type and is the // returned set of nearest points to the probe point that can be found // in the NearTree. The container can be a Standard Library container or // a CNearTree // t is the probe point // // returns the number of objects returned in the container (for sets, that may not equal the number found) // // This version used the left-first search //======================================================================= template inline long LeftFindInSphere ( const DistanceType& dRadius, OutputContainerType& tClosest, const T& t ) const { // clear the contents of the return vector so that things don't accidentally accumulate tClosest.clear( ); const_cast(this)->CompleteDelayedInsert( ); if( this->empty( ) ) { return( 0L ); } else { return ( m_BaseNode.LeftInSphere( dRadius, tClosest, t, m_ObjectStore #ifdef CNEARTREE_INSTRUMENTED , m_NodeVisits #endif ) ); } } // LeftFindInSphere template inline long LeftFindInSphere ( const DistanceType& dRadius, OutputContainerType& tClosest, std::vector& tIndices, const T& t ) const { // clear the contents of the return vector so that things don't accidentally accumulate tClosest.clear( ); tIndices.clear( ); const_cast(this)->CompleteDelayedInsert( ); if( this->empty( ) ) { return( 0L ); } else { return ( m_BaseNode.LeftInSphere( dRadius, tClosest, tIndices, t, m_ObjectStore #ifdef CNEARTREE_INSTRUMENTED , m_NodeVisits #endif ) ); } } // LeftFindInSphere //======================================================================= // long FindOutSphere ( const DistanceType& dRadius, OutputContainerType& tFarthest, const T& t ) const // // Function to search a NearTree for the set of objects farther from some probe point, t, // than dRadius. This is only here so that tFarthest can be cleared before starting the work. // // dRadius is the maximum search radius - any point nearer than dRadius from the probe // point will be ignored // tFarthest is returned as a container of objects of the templated type and is the // returned set of nearest points to the probe point that can be found // in the NearTree. The container can be a Standard Library container or // a CNearTree // t is the probe point // // returns the number of objects returned in the container (for sets, that may not equal the number found) // // This version uses the balanced search //======================================================================= template long FindOutSphere ( const DistanceType& dRadius, OutputContainerType& tFarthest, const T& t ) const { // clear the contents of the return vector so that things don't accidentally accumulate tFarthest.clear( ); const_cast(this)->CompleteDelayedInsert( ); if( this->empty( ) ) { return( 0L ); } else { return ( m_BaseNode.OutSphere( dRadius, tFarthest, t, m_ObjectStore #ifdef CNEARTREE_INSTRUMENTED , m_NodeVisits #endif ) ); } } // FindOutSphere template long FindOutSphere ( const DistanceType& dRadius, OutputContainerType& tFarthest, std::vector& tIndices, const T& t ) const { // clear the contents of the return vector so that things don't accidentally accumulate tFarthest.clear( ); tIndices.clear( ); const_cast(this)->CompleteDelayedInsert( ); if( this->empty( ) ) { return( 0L ); } else { return ( m_BaseNode.OutSphere( dRadius, tFarthest, tIndices, t, m_ObjectStore #ifdef CNEARTREE_INSTRUMENTED , m_NodeVisits #endif ) ); } } // FindOutSphere //======================================================================= // long leftFindOutSphere ( const DistanceType& dRadius, OutputContainerType& tFarthest, const T& t ) const // // Function to search a NearTree for the set of objects farther from some probe point, t, // than dRadius. This is only here so that tFarthest can be cleared before starting the work. // // dRadius is the maximum search radius - any point nearer than dRadius from the probe // point will be ignored // tFarthest is returned as a container of objects of the templated type and is the // returned set of nearest points to the probe point that can be found // in the NearTree. The container can be a Standard Library container or // a CNearTree // t is the probe point // // returns the number of objects returned in the container (for sets, that may not equal the number found) // // This version uses the left-first search //======================================================================= template long LeftFindOutSphere ( const DistanceType& dRadius, OutputContainerType& tFarthest, const T& t ) const { // clear the contents of the return vector so that things don't accidentally accumulate tFarthest.clear( ); const_cast(this)->CompleteDelayedInsert( ); if( this->empty( ) ) { return( 0L ); } else { return ( m_BaseNode.LeftOutSphere( dRadius, tFarthest, t, m_ObjectStore #ifdef CNEARTREE_INSTRUMENTED , m_NodeVisits #endif ) ); } } // LeftFindOutSphere template long LeftFindOutSphere ( const DistanceType& dRadius, OutputContainerType& tFarthest, std::vector& tIndices, const T& t ) const { // clear the contents of the return vector so that things don't accidentally accumulate tFarthest.clear( ); tIndices.clear( ); const_cast(this)->CompleteDelayedInsert( ); if( this->empty( ) ) { return( 0L ); } else { return ( m_BaseNode.LeftOutSphere( dRadius, tFarthest, tIndices, t, m_ObjectStore #ifdef CNEARTREE_INSTRUMENTED , m_NodeVisits #endif ) ); } } // LeftFindOutSphere //======================================================================= // long FindInAnnulus ( const DistanceType& dRadius1, const DistanceType dRadius2, OutputContainerType& tAnnular, const T& t ) const // // Function to search a NearTree for the set of objects within a "spherical" annulus // // dRadius1 is the minimum search radius - any point nearer than dRadius1 from the probe // point will be ignored // dRadius2 is the maximum search radius - any point farther than dRadius2 from the probe // point will be ignored // tAnnular is returned as a container of objects of the templated type and is the // returned set of nearest points to the probe point that can be found // in the NearTree. The container can be a Standard Library container or // a CNearTree // t is the probe point // // returns the number of objects returned in the container (for sets, that may not equal the number found) // // This version uses the balanced search //======================================================================= template long FindInAnnulus ( const DistanceType& dRadius1, const DistanceType& dRadius2, OutputContainerType& tAnnular, const T& t ) const { long lReturn = 0; // clear the contents of the return vector so that things don't accidentally accumulate tAnnular.clear( ); const_cast(this)->CompleteDelayedInsert( ); if( this->empty( ) ) { } else if ( dRadius1 > dRadius2 ) { // Make sure that r1 < r2 return ( FindInAnnulus( dRadius2, dRadius1, tAnnular, t ) ); } else { lReturn = this->m_BaseNode.InAnnulus( dRadius1, dRadius2, tAnnular, t, m_ObjectStore #ifdef CNEARTREE_INSTRUMENTED , m_NodeVisits #endif ); } return ( lReturn ); } // FindInAnnulus template long FindInAnnulus ( const DistanceType& dRadius1, const DistanceType& dRadius2, OutputContainerType& tAnnular, std::vector& tIndices, const T& t ) const { long lReturn = 0; // clear the contents of the return vector so that things don't accidentally accumulate tAnnular.clear( ); tIndices.clear( ); const_cast(this)->CompleteDelayedInsert( ); if( this->empty( ) ) { } else if ( dRadius1 > dRadius2 ) { // Make sure that r1 < r2 return ( FindInAnnulus( dRadius2, dRadius1, tAnnular, tIndices, t ) ); } else { lReturn = this->m_BaseNode.InAnnulus( dRadius1, dRadius2, tAnnular, tIndices, t, m_ObjectStore #ifdef CNEARTREE_INSTRUMENTED , m_NodeVisits #endif ); } return ( lReturn ); } // FindInAnnulus //======================================================================= // long LeftFindInAnnulus ( const DistanceType& dRadius1, const DistanceType dRadius2, OutputContainerType& tAnnular, const T& t ) const // // Function to search a NearTree for the set of objects within a "spherical" annulus // // dRadius1 is the minimum search radius - any point nearer than dRadius1 from the probe // point will be ignored // dRadius2 is the maximum search radius - any point farther than dRadius2 from the probe // point will be ignored // tAnnular is returned as a container of objects of the templated type and is the // returned set of nearest points to the probe point that can be found // in the NearTree. The container can be a Standard Library container or // a CNearTree // t is the probe point // // returns the number of objects returned in the container (for sets, that may not equal the number found) // // This version uses the left-first search //======================================================================= template long LeftFindInAnnulus ( const DistanceType& dRadius1, const DistanceType& dRadius2, OutputContainerType& tAnnular, const T& t ) const { long lReturn = 0; // clear the contents of the return vector so that things don't accidentally accumulate tAnnular.clear( ); const_cast(this)->CompleteDelayedInsert( ); if( this->empty( ) ) { } else if ( dRadius1 > dRadius2 ) { // Make sure that r1 < r2 return ( LeftFindInAnnulus( dRadius2, dRadius1, tAnnular, t ) ); } else { lReturn = this->m_BaseNode.LeftInAnnulus( dRadius1, dRadius2, tAnnular, t, m_ObjectStore #ifdef CNEARTREE_INSTRUMENTED , m_NodeVisits #endif ); } return ( lReturn ); } // LeftFindInAnnulus template long LeftFindInAnnulus ( const DistanceType& dRadius1, const DistanceType& dRadius2, OutputContainerType& tAnnular, std::vector& tIndices, const T& t ) const { long lReturn = 0; // clear the contents of the return vector so that things don't accidentally accumulate tAnnular.clear( ); tIndices.clear( ); const_cast(this)->CompleteDelayedInsert( ); if( this->empty( ) ) { } else if ( dRadius1 > dRadius2 ) { // Make sure that r1 < r2 return ( LeftFindInAnnulus( dRadius2, dRadius1, tAnnular, tIndices, t ) ); } else { lReturn = this->m_BaseNode.LeftInAnnulus( dRadius1, dRadius2, tAnnular, tIndices, t, m_ObjectStore #ifdef CNEARTREE_INSTRUMENTED , m_NodeVisits #endif ); } return ( lReturn ); } // LeftFindInAnnulus //======================================================================= // long FindK_NearestNeighbors( const size_t k, const DistanceType& dRadius, OutputContainerType& tClosest, const T& t ) const // // Function to search a NearTree for the set of objects closer to some probe point, t, // than dRadius. This is only here so that tClosest can be cleared before starting the work // and radius can be updated while processing. // // k is the maximum number of points to return // dRadius is the maximum search radius - any point farther than dRadius from the probe // point will be ignored // tClosest is returned as a container of objects of the templated type and is the // returned set of nearest points to the probe point that can be found // in the NearTree. The container can be a Standard Library container or // a CNearTree // t is the probe point // // returns the number of objects returned in the container (for sets, that may not equal the number found) // //======================================================================= template long FindK_NearestNeighbors ( const size_t k, const DistanceType& radius, OutputContainerType& tClosest, const T& t ) { // clear the contents of the return vector so that things don't accidentally accumulate tClosest.clear( ); const_cast(this)->CompleteDelayedInsert( ); if( this->empty( ) ) { return( 0L ); } else { std::vector > K_Storage; DistanceType dRadius = radius; const long lFound = m_BaseNode.K_Near( k, dRadius, K_Storage, t, this->m_ObjectStore #ifdef CNEARTREE_INSTRUMENTED , m_NodeVisits #endif ); for( unsigned int i=0; i long FindK_NearestNeighbors ( const size_t k, const DistanceType& radius, OutputContainerType& tClosest, std::vector& tIndices, const T& t ) { // clear the contents of the return vector so that things don't accidentally accumulate tClosest.clear( ); tIndices.clear( ); const_cast(this)->CompleteDelayedInsert( ); if( this->empty( ) ) { return( 0L ); } else { std::vector > K_Storage; DistanceType dRadius = radius; const long lFound = m_BaseNode.K_Near( k, dRadius, K_Storage, t, this->m_ObjectStore #ifdef CNEARTREE_INSTRUMENTED , m_NodeVisits #endif ); for( unsigned int i=0; i long LeftFindK_NearestNeighbors ( const size_t k, const DistanceType& radius, OutputContainerType& tClosest, const T& t ) { // clear the contents of the return vector so that things don't accidentally accumulate tClosest.clear( ); const_cast(this)->CompleteDelayedInsert( ); if( this->empty( ) ) { return( 0L ); } else { std::vector > K_Storage; DistanceType dRadius = radius; const long lFound = m_BaseNode.LeftK_Near( k, dRadius, K_Storage, t, this->m_ObjectStore #ifdef CNEARTREE_INSTRUMENTED , m_NodeVisits #endif ); for( unsigned int i=0; i long LeftFindK_NearestNeighbors ( const size_t k, const DistanceType& radius, OutputContainerType& tClosest, std::vector& tIndices, const T& t ) { // clear the contents of the return vector so that things don't accidentally accumulate tClosest.clear( ); tIndices.clear( ); const_cast(this)->CompleteDelayedInsert( ); if( this->empty( ) ) { return( 0L ); } else { std::vector > K_Storage; DistanceType dRadius = radius; const long lFound = m_BaseNode.LeftK_Near( k, dRadius, K_Storage, t, this->m_ObjectStore #ifdef CNEARTREE_INSTRUMENTED , m_NodeVisits #endif ); for( unsigned int i=0; i long FindK_FarthestNeighbors ( const size_t k, OutputContainerType& tFarthest, const T& t ) { // clear the contents of the return vector so that things don't accidentally accumulate tFarthest.clear( ); const_cast(this)->CompleteDelayedInsert( ); if( this->empty( ) ) { return( 0L ); } else { std::vector > K_Storage; DistanceType dRadius = 0; const long lFound = m_BaseNode.K_Far( k, dRadius, K_Storage, t, this->m_ObjectStore #ifdef CNEARTREE_INSTRUMENTED , m_NodeVisits #endif ); for( unsigned int i=0; i long FindK_FarthestNeighbors ( const size_t k, OutputContainerType& tFarthest, std::vector& tIndices, const T& t ) { // clear the contents of the return vector so that things don't accidentally accumulate tFarthest.clear( ); tIndices.clear( ); const_cast(this)->CompleteDelayedInsert( ); if( this->empty( ) ) { return( 0L ); } else { std::vector > K_Storage; DistanceType dRadius = 0; const long lFound = m_BaseNode.K_Far( k, dRadius, K_Storage, t, this->m_ObjectStore #ifdef CNEARTREE_INSTRUMENTED , m_NodeVisits #endif ); for( unsigned int i=0; i long LeftFindK_FarthestNeighbors ( const size_t k, OutputContainerType& tFarthest, const T& t ) { // clear the contents of the return vector so that things don't accidentally accumulate tFarthest.clear( ); const_cast(this)->CompleteDelayedInsert( ); if( this->empty( ) ) { return( 0L ); } else { std::vector > K_Storage; DistanceType dRadius = 0; const long lFound = m_BaseNode.LeftK_Far( k, dRadius, K_Storage, t, this->m_ObjectStore #ifdef CNEARTREE_INSTRUMENTED , m_NodeVisits #endif ); for( unsigned int i=0; i long LeftFindK_FarthestNeighbors ( const size_t k, OutputContainerType& tFarthest, std::vector& tIndices, const T& t ) { // clear the contents of the return vector so that things don't accidentally accumulate tFarthest.clear( ); tIndices.clear( ); const_cast(this)->CompleteDelayedInsert( ); if( this->empty( ) ) { return( 0L ); } else { std::vector > K_Storage; DistanceType dRadius = 0; const long lFound = m_BaseNode.LeftK_Far( k, dRadius, K_Storage, t, this->m_ObjectStore #ifdef CNEARTREE_INSTRUMENTED , m_NodeVisits #endif ); for( unsigned int i=0; i 0) { npass++; errsize = (m_BaseNode.GetTreeSize())>>(-1+m_DeepestDepth); if ( errsize < 1 ) { size_t n = (size_t)((double)(vectorSize-1u) * (DistanceType)(rhr.urand())); rhr.urand( ); rhr.urand( ); // Find the next pointer that hasn't already had its object "insert"ed // We can do this blindly since sqrt(n)<=n for all cases. n=1 would be the only // bad case here, and that will not trigger the later loop. while ( m_DelayedIndices[n] == -1 ) { ++n; n = n% vectorSize; } insertDelayed( (long)m_DelayedIndices[n] ); m_DelayedIndices[n] = -1; ntarget--; } // finish by inserting all the remaining objects added=0; for ( size_t i=0; i 100 || added > npass*8) { errsize = (m_BaseNode.GetTreeSize())>>(-1+m_DeepestDepth); if (errsize < 1) break; } } } } // now get rid of the temporary storage that was used for delayed // insertions (fast way, faster than clear() ) std::vector DelayedPointersTemp; DelayedPointersTemp .swap( m_DelayedIndices ); m_DiamEstimate = m_BaseNode.GetDiamEstimate(m_ObjectStore); }; //======================================================================= // void CompleteDelayedInsertRandom ( void ) // // When CompleteDelayedInsertRandom is invoked, if there are any objects in the // delayed store they are then inserted into the neartree. CompleteDelayedInsertRandom // randomly selects all objects and inserts them. m_DelayedIndices is empty after // a call to CompleteDelayedInsertRandom. // //======================================================================= inline void CompleteDelayedInsertRandom ( void ) { if ( m_DelayedIndices.empty( ) ) { return; } // insert a random selection of the objects const size_t vectorSize = m_DelayedIndices.size( ); for ( size_t i=0; i DelayedPointersTemp; DelayedPointersTemp.swap( m_DelayedIndices ); m_DiamEstimate = m_BaseNode.GetDiamEstimate(m_ObjectStore); }; //======================================================================= // size_t GetDeferredSize ( void ) // // The number of objects currently queued for insertion. // //======================================================================= size_t GetDeferredSize ( void ) const { return ( m_DelayedIndices.size( ) ); }; //======================================================================= // DistanceType GetMeanSpacing ( void ) // // Get an estimate of the spacing of points // // //======================================================================= DistanceType GetMeanSpacing ( void ) { return m_SumSpacings/DistanceType((1+m_ObjectStore.size())); } //======================================================================= // DistanceType GetVarSpacing ( void ) // // Get an estimate of variance of the spacing of points // // //======================================================================= DistanceType GetVarSpacing ( void ) { DistanceType meanSpacing = m_SumSpacings/DistanceType((1+m_ObjectStore.size())); return m_SumSpacingsSq/DistanceType((1+m_ObjectStore.size()))-meanSpacing*meanSpacing; } //======================================================================= // size_t GetNodeVisits ( void ) // // Get the number of visits to nodes // Uninstrumented returns 0 // // //======================================================================= inline size_t GetNodeVisits ( void ) { #ifdef CNEARTREE_INSTRUMENTED return m_NodeVisits; #else return 0; #endif } #ifdef CNEARTREE_INSTRUMENTED //======================================================================= // void SetNodeVisits ( const size_t visits ) // // Set the number of visits to nodes // // //======================================================================= void SetNodeVisits ( const size_t visits ) { m_NodeVisits = visits; } #endif //======================================================================= // DistanceType GetDiamEstimate ( void ) // // Get an estimate of the diameter // // //======================================================================= DistanceType GetDiamEstimate ( void ) { return m_DiamEstimate; } //======================================================================= // double GetDimEstimate ( void ) // // Get an estimate of the dimension of the collection of points // in the tree. If no argument, estimate to within esd of 0.1 // // //======================================================================= double GetDimEstimate ( void ) { return GetDimEstimate(0.1); }; //======================================================================= // double GetDimEstimateEsd ( void ) // // Get the current best estimate of the dimension esd // //======================================================================= double GetDimEstimateEsd ( void ) { if (m_DimEstimate <= 0.) { if (GetDimEstimate(0.1) <= 0.) return DBL_MAX; } return m_DimEstimateEsd; } //======================================================================= // double GetDimEstimate ( const double DimEstimateEsd ) // // Get an estimate of the dimension of the collection of points // in the tree, to within the specified esd // // //======================================================================= double GetDimEstimate ( const double DimEstimateEsd ) { const_cast(this)->CompleteDelayedInsert( ); if ( m_DimEstimate == DBL_MAX ) return ( 0. ); if ( m_DimEstimate > 0. && (m_DimEstimateEsd <= DimEstimateEsd || DimEstimateEsd <= 0.) ) return (m_DimEstimate); size_t estsize = m_ObjectStore.size(); std::vector sampledisklarge; std::vector sampledisksmall; size_t trials; double estd; double estdim = 0.; double estdimsq = 0.; double testlim = (DimEstimateEsd<=0.)?0.01:(DimEstimateEsd*DimEstimateEsd); DistanceType meanSpacing = m_SumSpacings/DistanceType((1+m_ObjectStore.size())); size_t n; long poplarge, popsmall, poptrial; T probe = m_ObjectStore[0]; /* Do not try to get a dimension extimate with fewer than 32 points or a diameter less than DBL_EPSILON*/ if (estsize < 32 || (double)m_DiamEstimate < DBL_EPSILON) { m_DimEstimate = m_DimEstimateEsd = DBL_MAX; return( 0 ); } /* Estimate the number of points per unit distance and a target radius that would produce 4096 points in dimension 1. If this would bring us beyond the diameter/1.1, reduce to that size. */ double pointdensity = ((double)estsize)/((double)m_DiamEstimate); double targetradius = 4096./pointdensity; double rat; double shrinkfactor; if (targetradius < meanSpacing*10.) targetradius = meanSpacing*10.; if (targetradius > (double)m_DiamEstimate/1.1) targetradius = (double)m_DiamEstimate/1.1; /* Now try to find a smaller adjusted target radius that will contain a reasonable number of points*/ shrinkfactor = 4.; n = (size_t)(((double)estsize-1u) * ((DistanceType)rhr.urand())); rhr.urand( ); rhr.urand( ); probe = m_ObjectStore[n]; poptrial=FindInSphere((DistanceType)(targetradius/shrinkfactor),sampledisklarge,probe); do { shrinkfactor = shrinkfactor/1.1; popsmall=poptrial; poptrial=FindInSphere((DistanceType)(targetradius/shrinkfactor),sampledisklarge,probe); n = (size_t)(((double)estsize-1u) * ((DistanceType)rhr.urand())); rhr.urand( ); rhr.urand( ); probe = m_ObjectStore[n]; } while (poptrial < 256 && shrinkfactor > 1. && poptrial <= popsmall+10); targetradius /= shrinkfactor; targetradius *= 1.1; long goodtrials = 0; trials = (size_t)sqrt(0.5+(double)estsize); if (trials < 10) trials = 10; n = (size_t)(((double)estsize-1u) * ((DistanceType)rhr.urand())); rhr.urand( ); rhr.urand( ); probe = m_ObjectStore[n]; for(size_t ii = 0; ii < trials; ii++) { n = (size_t)(((double)estsize-1u) * ((DistanceType)rhr.urand())); rhr.urand( ); rhr.urand( ); probe = m_ObjectStore[n]; if ((poplarge=FindInSphere((DistanceType)targetradius,sampledisklarge,probe))>0 &&(popsmall=FindInSphere((DistanceType)(targetradius/1.1),sampledisksmall,probe))>0 && popsmall < poplarge) { rat = (double)poplarge/(double)popsmall; estd = log(rat)/log(1.1); estdim += estd; estdimsq += estd*estd; goodtrials++; if (goodtrials > (1L+(long)(trials))/2 && fabs(estdimsq/((double)goodtrials) - estdim*estdim/((double)(goodtrials*goodtrials))) <= testlim) break; } } if (goodtrials < 1) { m_DimEstimate = m_DimEstimateEsd = DBL_MAX; return(0); } m_DimEstimate = estdim/((double)goodtrials); m_DimEstimateEsd = sqrt(fabs(estdimsq/((double)goodtrials) - m_DimEstimate*m_DimEstimate)); if (m_DimEstimate + 3.*m_DimEstimateEsd< 0.) { m_DimEstimate = m_DimEstimateEsd = DBL_MAX; } return(m_DimEstimate); }; //======================================================================= // size_t GetTotalSize ( void ) // // The total number of objects that have been inserted plus those // queued for insertion. // //======================================================================= size_t GetTotalSize ( void ) const { return ( m_ObjectStore.size( ) ); }; //======================================================================= // size_t size ( void ) // // The total number of objects that have been inserted plus those // queued for insertion. // //======================================================================= size_t size ( void ) const { return ( GetTotalSize( ) ); }; //======================================================================= // size_t GetDepth ( void ) const // // The greatest depth of the tree (1-based) from the root. // //======================================================================= size_t GetDepth ( void ) const { return ( m_DeepestDepth ); }; //======================================================================= // size_t GetHeight( void ) const // // The greatest the height of the root. // //======================================================================= size_t GetHeight ( void ) const { #ifdef CNEARTREE_INSTRUMENTED return ( m_BaseNode.GetTreeHeight() ); #else return ( m_DeepestDepth ); #endif }; //======================================================================= // T Centroid ( void ) const // // compute the centroid of a neartree // //======================================================================= T Centroid( void ) const { T t( T(0.0) ); const unsigned int count = m_ObjectStore.size( ); if ( count == 0 ) { } else { for ( unsigned int i=0; i static T Centroid( CentroidContainerType& vt ) { T t( T(0.0) ); const unsigned int count = vt.size( ); if ( count == 0 ) { } else { typename CentroidContainerType::iterator it; for ( it=vt.begin( ); it!=vt.end( ); ++it ) { t += (*it); } t = T( DistanceType(t) / DistanceType(count) ); } return( t ); } //======================================================================= // std::vector GetObjectStore ( void ) const // // Utility function to copy the data object to a user's container object. // //======================================================================= std::vector GetObjectStore ( void ) const { return ( m_ObjectStore ); } //======================================================================= // operator ContainerType ( void ) const // // Utility function to copy the data object to a user's container object. // //======================================================================= template operator ContainerType ( void ) const { return ( m_ObjectStore ); } public: iterator begin ( void ) { return ( iterator( 0, this ) ); }; iterator end ( void ) { return ( iterator( m_ObjectStore.empty( )? 1 :(long)m_ObjectStore.size( ) , this ) ); }; iterator back ( void ) { return ( iterator( m_ObjectStore.empty( )? 1 :(long)m_ObjectStore.size( )-1, this ) ); }; const_iterator begin ( void ) const { return ( const_iterator( 0, this ) ); }; const_iterator end ( void ) const { return ( const_iterator( m_ObjectStore.empty( )? 1 :(long)m_ObjectStore.size( ) , this ) ); }; const_iterator back ( void ) const { return ( const_iterator( m_ObjectStore.empty( )? 1 :(long)m_ObjectStore.size( )-1, this ) ); }; T at( const size_t n ) const { return ( m_ObjectStore[n] ); }; T operator[] ( const size_t position ) const { return ( m_ObjectStore[position] ); }; private: //======================================================================= void insertDelayed ( const long n ) { size_t localDepth = 0; if ((m_Flags & NTF_ForceFlip) || !(m_Flags & NTF_NoFlip)) { m_BaseNode.InserterDelayed_Flip( n, localDepth, m_ObjectStore, m_SumSpacings, m_SumSpacingsSq ); } else { m_BaseNode.InserterDelayed( n, localDepth, m_ObjectStore, m_SumSpacings, m_SumSpacingsSq ); } if ( localDepth > m_DeepestDepth ) m_DeepestDepth = localDepth; } //======================================================================= //======================================================================= //======================================================================= //======================================================================= //======================================================================= //======================================================================= //======================================================================= //======================================================================= //======================================================================= //======================================================================= //======================================================================= //======================================================================= // end of CNearTree //======================================================================= template class KT : private U { private: DistanceType d; KT( void ) : U() { }; }; // start of nested class NearTreeNode //======================================================================= //======================================================================= //======================================================================= //======================================================================= //======================================================================= //======================================================================= //======================================================================= //======================================================================= //======================================================================= //======================================================================= //======================================================================= //======================================================================= //======================================================================= // // NEARTREENODE - nested class to hold the actual neartree and the indices to its data objects // // For the description of the template parameters, see the text above in the description // of CNearTree. //======================================================================= template class NearTreeNode { size_t m_ptLeft; // index of left object (of type TNode) stored in this node size_t m_ptRight; // index of right object (of type TNode) stored in this node DistanceTypeNode m_dMaxLeft; // longest distance from the left object to // anything below it in the tree DistanceTypeNode m_dMaxRight; // longest distance from the right object to // anything below it in the tree NearTreeNode * m_pLeftBranch; // tree descending from the left object NearTreeNode * m_pRightBranch; // tree descending from the right object size_t m_iTreeSize; // size of this node tree #ifdef CNEARTREE_INSTRUMENTED mutable size_t m_iHeight; // height of the tree #endif public: NearTreeNode( void ) // NearTreeNode constructor : m_ptLeft ( ULONG_MAX ) , m_ptRight ( ULONG_MAX ) , m_dMaxLeft ( DistanceTypeNode( distMinValueNode ) ) , m_dMaxRight ( DistanceTypeNode( distMinValueNode ) ) , m_pLeftBranch ( 0 ) , m_pRightBranch ( 0 ) , m_iTreeSize ( 0 ) #ifdef CNEARTREE_INSTRUMENTED , m_iHeight ( 0 ) #endif { }; // NearTreeNode constructor //======================================================================= ~NearTreeNode( void ) // NearTreeNode destructor { NearTreeNode * left; NearTreeNode * right; std::vector desStack; NearTreeNode * pc; pc = this; while ((void *)pc) { if (pc->m_ptRight != ULONG_MAX || pc->m_ptLeft !=ULONG_MAX ) { left = pc->m_pLeftBranch; right = pc->m_pRightBranch; pc->m_pLeftBranch =0; pc->m_pRightBranch =0; if (pc != this) delete pc; if ( left ) desStack.push_back(left); if ( right ) desStack.push_back(right); } pc = 0; if (!desStack.empty()){ pc = desStack.back(); desStack.pop_back(); } } }; // end NearTreeNode destructor //======================================================================= void clear( void ) { NearTreeNode * left; NearTreeNode * right; std::vector clearStack; NearTreeNode * pc; pc = this; while ((void *)pc) { if (pc->m_ptRight != ULONG_MAX || pc->m_ptLeft !=ULONG_MAX) { left = pc->m_pLeftBranch; right = pc->m_pRightBranch; pc->m_pLeftBranch =0; pc->m_pRightBranch =0; pc->m_ptLeft = ULONG_MAX; pc->m_ptRight = ULONG_MAX; pc->m_dMaxLeft = DistanceTypeNode( distMinValueNode ); pc->m_dMaxRight = DistanceTypeNode( distMinValueNode ); pc->m_iTreeSize = 0; #ifdef CNEARTREE_INSTRUMENTED pc->m_iHeight = 0; #endif if (pc != this) delete pc; if ( left ) clearStack.push_back(left); if ( right ) clearStack.push_back(right); } pc = 0; if (!clearStack.empty()){ pc = clearStack.back(); clearStack.pop_back(); } } }; // end clear //======================================================================= inline size_t GetTreeSize( void ) const { return m_iTreeSize; } inline size_t GetLeftTreeSize( void ) const { return (!m_pLeftBranch)?0:(m_pLeftBranch->m_iTreeSize); } inline size_t GetRightTreeSize( void ) const { return (!m_pRightBranch)?0:(m_pRightBranch->m_iTreeSize); } inline size_t GetTreeHeight( void ) const { #ifdef CNEARTREE_INSTRUMENTED return m_iHeight; #else return 0; #endif } //======================================================================= DistanceTypeNode GetDiamEstimate( std::vector& objectStore ) const { DistanceTypeNode temp = DistanceTypeNode(0); if (m_dMaxRight > temp) temp=m_dMaxRight; if (m_dMaxLeft >temp) temp=m_dMaxLeft; if (m_ptLeft != ULONG_MAX && m_ptRight != ULONG_MAX && DistanceBetween(objectStore[m_ptLeft],objectStore[m_ptRight])> temp) temp= DistanceBetween(objectStore[m_ptLeft],objectStore[m_ptRight]); return temp; } //======================================================================= // void InserterDelayed_Flip ( const TNode& t, size_t& localDepth, std::vector& objectStore, // DistanceTypeNode& SumSpacings, DistanceTypeNode& SumSpacingsSq ) // // Function to insert some "point" as an object into a CNearTree for // later searching // // t is an object of the templated type which is to be inserted into a // NearTree // // localDepth is the returned deepest tree level reached for the current insert // // Three possibilities exist: put the datum into the left // position (first test),into the right position, or else // into a node descending from the nearer of those positions // when they are both already used. // // This version will do a flip on insertions to try to drive the top pairs // apart, starting just before a terminal node // //======================================================================= //======================================================================= // void InserterDelayed ( const TNode& t, size_t& localDepth, std::vector& objectStore, // DistanceTypeNode& SumSpacings, DistanceTypeNode& SumSpacingsSq ) // // Function to insert some "point" as an object into a CNearTree for // later searching // // t is an object of the templated type which is to be inserted into a // NearTree // // localDepth is the returned deepest tree level reached for the current insert // // Three possibilities exist: put the datum into the left // position (first test),into the right position, or else // into a node descending from the nearer of those positions // when they are both already used. // //======================================================================= //======================================================================= void InserterDelayed_Flip ( const long n, size_t& localDepth, std::vector& objectStore, DistanceTypeNode& SumSpacings, DistanceTypeNode& SumSpacingsSq ) { DistanceTypeNode dTempRight = DistanceTypeNode(0); DistanceTypeNode dTempLeft = DistanceTypeNode(0); DistanceTypeNode dTempLeftRight = DistanceTypeNode(0); ++localDepth; ++m_iTreeSize; if ( m_ptLeft == ULONG_MAX ) { m_ptLeft = n; #ifdef CNEARTREE_INSTRUMENTED m_iHeight = 1; #endif return; } dTempLeft = DistanceBetween( objectStore[n], objectStore[m_ptLeft] ); if ( m_ptRight == ULONG_MAX ) { m_ptRight = n; SumSpacings += dTempLeft; SumSpacingsSq += dTempLeft*dTempLeft; return; } dTempRight = DistanceBetween( objectStore[n], objectStore[m_ptRight] ); dTempLeftRight = DistanceBetween(objectStore[m_ptLeft], objectStore[m_ptRight]); if ( dTempLeft > dTempRight ) { if ( m_pRightBranch == 0 ) { m_pRightBranch = new NearTreeNode; } // note that the next line assumes that m_dMaxRight is negative for a new node if ( m_dMaxRight < dTempRight ) m_dMaxRight = dTempRight; // If the left branch is empty, we are going to put something here if ( m_pRightBranch->m_ptLeft == ULONG_MAX ) { m_pRightBranch->m_ptLeft = n; SumSpacings += dTempRight; SumSpacingsSq += dTempRight*dTempRight; ++localDepth; ++(m_pRightBranch->m_iTreeSize); #ifdef CNEARTREE_INSTRUMENTED m_pRightBranch->m_iHeight = 1; if (m_iHeight < 2) m_iHeight = 2; #endif // See if it would be better to put the new node at this level and drop the current // Right node down one level if (dTempRight > dTempLeftRight) { m_pRightBranch->m_ptLeft = m_ptRight; m_ptRight = n; } return; } m_pRightBranch->InserterDelayed_Flip( n, localDepth, objectStore, SumSpacings, SumSpacingsSq ); #ifdef CNEARTREE_INSTRUMENTED m_iHeight = 1+m_pRightBranch->m_iHeight; if (m_pLeftBranch && m_pLeftBranch->m_iHeight >= m_iHeight) m_iHeight = 1+m_pLeftBranch->m_iHeight; #endif } else // ((DistanceTypeNode)(t - *m_tLeft) <= (DistanceTypeNode)(t - *m_tRight) ) { if ( m_pLeftBranch == 0 ) { m_pLeftBranch = new NearTreeNode; } // note that the next line assumes that m_dMaxLeft is negative for a new node if ( m_dMaxLeft < dTempLeft ) m_dMaxLeft = dTempLeft; // If the left branch is empty, we are going to put something here if ( m_pLeftBranch->m_ptLeft == ULONG_MAX ) { m_pLeftBranch->m_ptLeft = n; SumSpacings += dTempLeft; SumSpacingsSq += dTempLeft*dTempLeft; ++localDepth; ++(m_pLeftBranch->m_iTreeSize); #ifdef CNEARTREE_INSTRUMENTED m_pLeftBranch->m_iHeight = 1; if (m_iHeight < 2) m_iHeight = 2; #endif // See if it would be better to put the new node at this level and drop the current // Left node down one level if (dTempLeft > dTempLeftRight) { m_pLeftBranch->m_ptLeft = m_ptLeft; m_ptLeft = n; } return; } m_pLeftBranch->InserterDelayed_Flip( n, localDepth, objectStore, SumSpacings, SumSpacingsSq ); #ifdef CNEARTREE_INSTRUMENTED m_iHeight = 1+m_pLeftBranch->m_iHeight; if (m_pRightBranch && m_pRightBranch->m_iHeight >= m_iHeight) m_iHeight = 1+m_pRightBranch->m_iHeight; #endif } } // end InserterDelayed_Flip //======================================================================= void InserterDelayed ( const long n, size_t& localDepth, std::vector& objectStore, DistanceTypeNode& SumSpacings, DistanceTypeNode& SumSpacingsSq ) { DistanceTypeNode dTempRight = DistanceTypeNode(0); DistanceTypeNode dTempLeft = DistanceTypeNode(0); ++localDepth; ++m_iTreeSize; if ( m_ptLeft == ULONG_MAX ) { m_ptLeft = n; #ifdef CNEARTREE_INSTRUMENTED m_iHeight = 1; #endif return; } dTempLeft = DistanceBetween( objectStore[n], objectStore[m_ptLeft] ); if ( m_ptRight == ULONG_MAX ) { m_ptRight = n; SumSpacings += dTempLeft; SumSpacingsSq += dTempLeft*dTempLeft; return; } dTempRight = DistanceBetween( objectStore[n], objectStore[m_ptRight] ); if ( dTempLeft > dTempRight ) { if ( m_pRightBranch == 0 ) { m_pRightBranch = new NearTreeNode; } // note that the next line assumes that m_dMaxRight is negative for a new node if ( m_dMaxRight < dTempRight ) m_dMaxRight = dTempRight; if ( m_pRightBranch->m_ptLeft == ULONG_MAX) { m_pRightBranch->m_ptLeft = n; SumSpacings += dTempRight; SumSpacingsSq += dTempRight*dTempRight; ++localDepth; ++(m_pRightBranch->m_iTreeSize); #ifdef CNEARTREE_INSTRUMENTED m_pRightBranch->m_iHeight = 1; if (m_iHeight < 2) m_iHeight = 2; #endif return; } m_pRightBranch->InserterDelayed( n, localDepth, objectStore, SumSpacings, SumSpacingsSq ); #ifdef CNEARTREE_INSTRUMENTED m_iHeight = 1+m_pRightBranch->m_iHeight; if (m_pLeftBranch && m_pLeftBranch->m_iHeight >= m_iHeight) m_iHeight = 1+m_pLeftBranch->m_iHeight; #endif } else // ((DistanceTypeNode)(t - *m_tLeft) <= (DistanceTypeNode)(t - *m_tRight) ) { if ( m_pLeftBranch == 0 ) { m_pLeftBranch = new NearTreeNode; } // note that the next line assumes that m_dMaxLeft is negative for a new node if ( m_dMaxLeft < dTempLeft ) m_dMaxLeft = dTempLeft; if ( m_pLeftBranch->m_ptLeft == ULONG_MAX ) { m_pLeftBranch->m_ptLeft = n; SumSpacings += dTempLeft; SumSpacingsSq += dTempLeft*dTempLeft; ++localDepth; ++(m_pLeftBranch->m_iTreeSize); #ifdef CNEARTREE_INSTRUMENTED m_pLeftBranch->m_iHeight = 1; if (m_iHeight < 2) m_iHeight = 2; #endif return; } m_pLeftBranch->InserterDelayed( n, localDepth, objectStore, SumSpacings, SumSpacingsSq ); #ifdef CNEARTREE_INSTRUMENTED m_iHeight = 1+m_pLeftBranch->m_iHeight; if (m_pRightBranch && m_pRightBranch->m_iHeight >= m_iHeight) m_iHeight = 1+m_pRightBranch->m_iHeight; #endif } } // end InserterDelayed //======================================================================= // void ReInserter_Flip ( const NearTreeNode * pntn, size_t& localDepth, std::vector& objectStore ), // // Function to reinsert the elements from the object store // contained in a NearTreeNode into a CNearTree for later searching // // pntn is a point to a neartree node, the objects from which are to be re-inserted into a // NearTree // // localDepth is the returned deepest tree level reached for the current insert // // This version will do a flip on insertions to try to drive the top pairs // apart // //======================================================================= void ReInserter_Flip ( const NearTreeNode * pntn, size_t& localDepth, std::vector& objectStore) { size_t tempdepth1, tempdepth2, tempdepth3, tempdepth4; DistanceTypeNode SumSpacings, SumSpacingsSq; tempdepth1 = tempdepth2 = tempdepth3 = tempdepth4 = localDepth; if ( pntn->m_ptRight != ULONG_MAX) InserterDelayed_Flip( pntn->m_ptRight, tempdepth1, objectStore, SumSpacings, SumSpacingsSq ); if ( pntn->m_ptLeft != ULONG_MAX) InserterDelayed_Flip( pntn->m_ptLeft, tempdepth2, objectStore, SumSpacings, SumSpacingsSq ); if ( pntn->m_pLeftBranch ) ReInserter_Flip(pntn->m_pLeftBranch, tempdepth3, objectStore ); if ( pntn->m_pRightBranch ) ReInserter_Flip(pntn->m_pRightBranch, tempdepth4, objectStore ); localDepth = tempdepth1>localDepth?tempdepth1:localDepth; localDepth = tempdepth2>localDepth?tempdepth2:localDepth; localDepth = tempdepth3>localDepth?tempdepth3:localDepth; localDepth = tempdepth4>localDepth?tempdepth4:localDepth; } // end ReInserter_Flip //======================================================================= // bool Nearest ( DistanceTypeNode& dRadius, TNode& tClosest, const TNode& t, // const std::vector& objectStore) const // // Private function to search a NearTree for the object closest to some probe point, t. // This function is only called by NearestNeighbor. // // dRadius is the smallest currently known distance of an object from the probe point. // tClosest is an object of the templated type and is the returned closest point // to the probe point that can be found in the NearTree // t is the probe point // objectStore is the complete object store of the NearTree // // the return value is true only if a point was found within dRadius // //======================================================================= bool Nearest ( DistanceTypeNode& dRadius, TNode& tClosest, const TNode& t, size_t& pClosest, const std::vector& objectStore #ifdef CNEARTREE_INSTRUMENTED , size_t& VisitCount #endif ) const { std::vector sStack; DistanceTypeNode dDL=DistanceTypeNode(0), dDR=DistanceTypeNode(0); NearTreeNode* pt = const_cast(this); pClosest = ULONG_MAX; #ifdef CNEARTREE_INSTRUMENTED ++VisitCount; #endif if ( pt->m_ptLeft == ULONG_MAX && pt->m_ptRight == ULONG_MAX) return false; // test for empty while ( pt->m_ptLeft != ULONG_MAX || pt->m_ptRight != ULONG_MAX || !sStack.empty( ) ) { if (pt->m_ptLeft == ULONG_MAX && pt->m_ptRight == ULONG_MAX) { if (!sStack.empty( )) { pt = sStack.back(); sStack.pop_back(); #ifdef CNEARTREE_INSTRUMENTED ++VisitCount; #endif continue; } break; } if (pt->m_ptLeft != ULONG_MAX) { dDL = DistanceBetween( t, objectStore[pt->m_ptLeft] ); if ( dDL <= dRadius ) { dRadius = dDL; pClosest = pt->m_ptLeft; } } if (pt->m_ptRight != ULONG_MAX) { #ifdef CNEARTREE_INSTRUMENTED ++VisitCount; #endif dDR = DistanceBetween( t, objectStore[pt->m_ptRight]); if ( dDR <= dRadius ) { dRadius = dDR; pClosest = pt->m_ptRight; } } /* See if both branches are populated. In that case, save one branch on the stack, and process the other one based on which one seems smaller, but useful first] */ if (pt->m_pLeftBranch != 0 && pt->m_pRightBranch != 0 ) { if (dDL+pt->m_dMaxLeft < dDR+pt->m_dMaxRight || pt->m_pRightBranch == 0) { if ( TRIANG(dDL,pt->m_dMaxLeft,dRadius)) { if ( TRIANG(dDR,pt->m_dMaxRight,dRadius)) { sStack.push_back(pt->m_pRightBranch); } pt = pt->m_pLeftBranch; #ifdef CNEARTREE_INSTRUMENTED ++VisitCount; #endif continue; } /* If we are here, the left branch was not useful Fall through to use the right */ } /* We come here either because pursuing the left branch was not useful of the right branch look shorter */ if ( TRIANG(dDR,pt->m_dMaxRight,dRadius)) { if ( TRIANG(dDL,pt->m_dMaxLeft,dRadius)) { sStack.push_back(pt->m_pLeftBranch); } pt = pt->m_pRightBranch; #ifdef CNEARTREE_INSTRUMENTED ++VisitCount; #endif continue; } } /* Only one branch is viable, try them one at a time */ if ( pt->m_pLeftBranch != 0 && TRIANG(dDL,pt->m_dMaxLeft,dRadius)) { pt = pt->m_pLeftBranch; #ifdef CNEARTREE_INSTRUMENTED ++VisitCount; #endif continue; } if ( pt->m_pRightBranch != 0 && TRIANG(dDR,pt->m_dMaxRight,dRadius)) { pt = pt->m_pRightBranch; #ifdef CNEARTREE_INSTRUMENTED ++VisitCount; #endif continue; } /* We have procesed both sides, we need to go to the stack */ if (!sStack.empty( )) { pt = sStack.back(); sStack.pop_back(); #ifdef CNEARTREE_INSTRUMENTED ++VisitCount; #endif continue; } break; } if ( !sStack.empty( ) ) // for safety !!! { std::vector sTemp; sTemp.swap( sStack ); } if ( pClosest != ULONG_MAX ) tClosest = objectStore[pClosest]; return ( pClosest != ULONG_MAX ); }; // end Nearest //======================================================================= // bool LeftNearest ( DistanceTypeNode& dRadius, TNode& tClosest, const TNode& t, // const std::vector& objectStore) const // // Private function to search a NearTree for the object closest to some probe point, t. // This function is only called by NearestNeighbor. // // dRadius is the smallest currently known distance of an object from the probe point. // tClosest is an object of the templated type and is the returned closest point // to the probe point that can be found in the NearTree // t is the probe point // objectStore is the complete object store of the NearTree // // the return value is true only if a point was found within dRadius // // This version differs from Nearest by searching to the left first // //======================================================================= bool LeftNearest ( DistanceTypeNode& dRadius, TNode& tClosest, const TNode& t, size_t& pClosest, const std::vector& objectStore #ifdef CNEARTREE_INSTRUMENTED , size_t& VisitCount #endif ) const { std::vector sStack; enum { left, right, end } eDir; eDir = left; // examine the left nodes first NearTreeNode* pt = const_cast(this); pClosest = ULONG_MAX; if ( pt->m_ptLeft == ULONG_MAX) return false; // test for empty #ifdef CNEARTREE_INSTRUMENTED ++VisitCount; #endif while ( ! ( eDir == end && sStack.empty( ) ) ) { if ( eDir == right ) { const DistanceTypeNode dDR = DistanceBetween( t, objectStore[pt->m_ptRight] ); if ( dDR <= dRadius ) { dRadius = dDR; pClosest = pt->m_ptRight; } if ( pt->m_pRightBranch != 0 && TRIANG(dDR,pt->m_dMaxRight,dRadius)) { // we did the left and now we finished the right, go down pt = pt->m_pRightBranch; eDir = left; #ifdef CNEARTREE_INSTRUMENTED ++VisitCount; #endif } else { eDir = end; } } if ( eDir == left ) { const DistanceTypeNode dDL = DistanceBetween( t, objectStore[pt->m_ptLeft] ); if ( dDL <= dRadius ) { dRadius = dDL; pClosest = pt->m_ptLeft; } if ( pt->m_ptRight != ULONG_MAX ) // only stack if there's a right object { sStack.push_back( pt ); } if ( pt->m_pLeftBranch != 0 && TRIANG(dDL,pt->m_dMaxLeft,dRadius)) { // we did the left, go down #ifdef CNEARTREE_INSTRUMENTED ++VisitCount; #endif pt = pt->m_pLeftBranch; } else { eDir = end; } } if ( eDir == end && !sStack.empty( ) ) { pt = sStack.back( ); #ifdef CNEARTREE_INSTRUMENTED ++VisitCount; #endif sStack.pop_back( ); eDir = right; } } if ( !sStack.empty( ) ) // for safety !!! { std::vector sTemp; sTemp.swap( sStack ); } if ( pClosest != ULONG_MAX ) tClosest = objectStore[pClosest]; return ( pClosest != ULONG_MAX ); }; // end LeftNearest //======================================================================= // bool Farthest ( DistanceTypeNode& dRadius, TNode& tFarthest, const TNode& t ) const // // Private function to search a NearTree for the object farthest from some probe point, t. // This function is only called by FarthestNeighbor. // // dRadius is the largest currently known distance of an object from the probe point. // tFarthest is an object of the templated type and is the returned farthest point // from the probe point that can be found in the NearTree // t is the probe point // // the return value is true only if a point was found (should only be false for // an empty tree) // //======================================================================= bool Farthest ( DistanceTypeNode& dRadius, TNode& tFarthest, const TNode& t, size_t& pFarthest, const std::vector& objectStore #ifdef CNEARTREE_INSTRUMENTED , size_t& VisitCount #endif ) const { std::vector sStack; DistanceTypeNode dDL=DistanceTypeNode(0), dDR=DistanceTypeNode(0); NearTreeNode* pt = const_cast(this); pFarthest = ULONG_MAX; #ifdef CNEARTREE_INSTRUMENTED ++VisitCount; #endif if ( pt->m_ptLeft == ULONG_MAX && pt->m_ptRight == ULONG_MAX) return false; // test for empty while ( pt->m_ptLeft != ULONG_MAX || pt->m_ptRight != ULONG_MAX || !sStack.empty( ) ) { if (pt->m_ptLeft == ULONG_MAX && pt->m_ptRight == ULONG_MAX) { if (!sStack.empty( )) { pt = sStack.back(); sStack.pop_back(); #ifdef CNEARTREE_INSTRUMENTED ++VisitCount; #endif continue; } break; } if (pt->m_ptLeft != ULONG_MAX) { dDL = DistanceBetween( t, objectStore[pt->m_ptLeft] ); if ( dDL >= dRadius ) { dRadius = dDL; pFarthest = pt->m_ptLeft; } } if (pt->m_ptRight != ULONG_MAX) { #ifdef CNEARTREE_INSTRUMENTED ++VisitCount; #endif dDR = DistanceBetween( t, objectStore[pt->m_ptRight]); if ( dDR >= dRadius ) { dRadius = dDR; pFarthest = pt->m_ptRight; } } /* See if both branches are populated. In that case, save one branch on the stack, and process the other one based on which one seems larger, but useful first] */ if (pt->m_pLeftBranch != 0 && pt->m_pRightBranch != 0 ) { if (dDL+pt->m_dMaxLeft > dDR+pt->m_dMaxRight || pt->m_pRightBranch == 0) { if ( TRIANG(dRadius,dDL,pt->m_dMaxLeft)) { if ( TRIANG(dRadius,dDR,pt->m_dMaxRight)) { sStack.push_back(pt->m_pRightBranch); } pt = pt->m_pLeftBranch; #ifdef CNEARTREE_INSTRUMENTED ++VisitCount; #endif continue; } /* If we are here, the left branch was not useful Fall through to use the right */ } /* We come here either because pursuing the left branch was not useful of the right branch look shorter */ if ( TRIANG(dRadius,dDR,pt->m_dMaxRight)) { if ( TRIANG(dRadius,dDL,pt->m_dMaxLeft)) { sStack.push_back(pt->m_pLeftBranch); } pt = pt->m_pRightBranch; #ifdef CNEARTREE_INSTRUMENTED ++VisitCount; #endif continue; } } /* Only one branch is viable, try them one at a time */ if ( pt->m_pLeftBranch != 0 && TRIANG(dRadius,dDL,pt->m_dMaxLeft)) { pt = pt->m_pLeftBranch; #ifdef CNEARTREE_INSTRUMENTED ++VisitCount; #endif continue; } if ( pt->m_pRightBranch != 0 && TRIANG(dRadius,dDR,pt->m_dMaxRight)) { pt = pt->m_pRightBranch; #ifdef CNEARTREE_INSTRUMENTED ++VisitCount; #endif continue; } /* We have procesed both sides, we need to go to the stack */ if (!sStack.empty( )) { pt = sStack.back(); sStack.pop_back(); #ifdef CNEARTREE_INSTRUMENTED ++VisitCount; #endif continue; } break; } if ( !sStack.empty( ) ) // for safety !!! { std::vector sTemp; sTemp.swap( sStack ); } if ( pFarthest != ULONG_MAX ) tFarthest = objectStore[pFarthest]; return ( pFarthest != ULONG_MAX ); }; // end Farthest //======================================================================= // bool LeftFarthest ( DistanceTypeNode& dRadius, TNode& tFarthest, const TNode& t ) const // // Private function to search a NearTree for the object farthest from some probe point, t. // This function is only called by FarthestNeighbor. // // dRadius is the largest currently known distance of an object from the probe point. // tFarthest is an object of the templated type and is the returned farthest point // from the probe point that can be found in the NearTree // t is the probe point // // the return value is true only if a point was found (should only be false for // an empty tree) // // This version differs from Farthest by searching to the left first // //======================================================================= bool LeftFarthest ( DistanceTypeNode& dRadius, TNode& tFarthest, const TNode& t, size_t& pFarthest, const std::vector& objectStore #ifdef CNEARTREE_INSTRUMENTED , size_t& VisitCount #endif ) const { std::vector sStack; enum { left, right, end } eDir; eDir = left; // examine the left nodes first NearTreeNode* pt = const_cast(this); pFarthest = ULONG_MAX; #ifdef CNEARTREE_INSTRUMENTED ++VisitCount; #endif if (pt->m_ptLeft == ULONG_MAX) return false; // test for empty while ( ! ( eDir == end && sStack.empty( ) ) ) { if ( eDir == right ) { const DistanceTypeNode dDR = DistanceBetween( t , objectStore[pt->m_ptRight] ); if ( dDR >= dRadius ) { dRadius = dDR; pFarthest = pt->m_ptRight; } if ( pt->m_pRightBranch != 0 && TRIANG(dRadius,dDR,pt->m_dMaxRight)) { // we did the left and now we finished the right, go down pt = pt->m_pRightBranch; #ifdef CNEARTREE_INSTRUMENTED ++VisitCount; #endif eDir = left; } else { eDir = end; } } if ( eDir == left ) { const DistanceTypeNode dDL = DistanceBetween( t , objectStore[pt->m_ptLeft] ); if ( dDL >= dRadius ) { dRadius = dDL; pFarthest = pt->m_ptLeft; } if ( pt->m_ptRight != ULONG_MAX ) // only stack if there's a right object { sStack.push_back( pt ); } if ( pt->m_pLeftBranch != 0 && TRIANG(dRadius,dDL,pt->m_dMaxLeft) ) { // we did the left, go down pt = pt->m_pLeftBranch; #ifdef CNEARTREE_INSTRUMENTED ++VisitCount; #endif } else { eDir = end; } } if ( eDir == end && !sStack.empty( ) ) { pt = sStack.back( ); #ifdef CNEARTREE_INSTRUMENTED ++VisitCount; #endif sStack.pop_back( ); eDir = right; } } if ( !sStack.empty( ) ) // for safety !!! { std::vector sTemp; sTemp.swap( sStack ); } if ( pFarthest != ULONG_MAX ) tFarthest = objectStore[pFarthest]; return ( pFarthest != ULONG_MAX ); }; // end LeftFarthest //======================================================================= // long InSphere ( // const DistanceTypeNode& dRadius, // ContainerType& tClosest, // const TNode& t, // const std::vector& objectStore // ) const // // Private function to search a NearTree for the objects inside of the specified radius // from the probe point // This function is only called by FindInSphere. // // dRadius is the search radius // tClosest is a CNearTree of objects of the templated type found within dRadius of the // probe point // t is the probe point // // returns the number of objects returned in the container (for sets, that may not equal the number found) // //======================================================================= template long InSphere ( const DistanceTypeNode& dRadius, ContainerType& tClosest, const TNode& t, const std::vector& objectStore #ifdef CNEARTREE_INSTRUMENTED , size_t& VisitCount #endif ) const { std::vector sStack; DistanceTypeNode dDL=DistanceTypeNode(0), dDR=DistanceTypeNode(0); NearTreeNode* pt = const_cast(this); #ifdef CNEARTREE_INSTRUMENTED ++VisitCount; #endif if ( pt->m_ptLeft == ULONG_MAX && pt->m_ptRight == ULONG_MAX) return false; // test for empty while ( pt->m_ptLeft != ULONG_MAX || pt->m_ptRight != ULONG_MAX || !sStack.empty( ) ) { if (pt->m_ptLeft == ULONG_MAX && pt->m_ptRight == ULONG_MAX) { if (!sStack.empty( )) { pt = sStack.back(); sStack.pop_back(); #ifdef CNEARTREE_INSTRUMENTED ++VisitCount; #endif continue; } break; } if (pt->m_ptLeft != ULONG_MAX) { dDL = DistanceBetween( t, objectStore[pt->m_ptLeft] ); if ( dDL <= dRadius ) { tClosest.insert( tClosest.end(), objectStore[pt->m_ptLeft] ); } } if (pt->m_ptRight != ULONG_MAX) { #ifdef CNEARTREE_INSTRUMENTED ++VisitCount; #endif dDR = DistanceBetween( t, objectStore[pt->m_ptRight]); if ( dDR <= dRadius ) { tClosest.insert( tClosest.end(), objectStore[pt->m_ptRight] ); } } /* See if both branches are populated. In that case, save one branch on the stack, and process the other one based on which one seems smaller, but useful first] */ if (pt->m_pLeftBranch != 0 && pt->m_pRightBranch != 0 ) { if (dDL+pt->m_dMaxLeft < dDR+pt->m_dMaxRight || pt->m_pRightBranch == 0) { if ( TRIANG(dDL,pt->m_dMaxLeft,dRadius)) { if ( TRIANG(dDR,pt->m_dMaxRight,dRadius)) { sStack.push_back(pt->m_pRightBranch); } pt = pt->m_pLeftBranch; #ifdef CNEARTREE_INSTRUMENTED ++VisitCount; #endif continue; } /* If we are here, the left branch was not useful Fall through to use the right */ } /* We come here either because pursuing the left branch was not useful of the right branch look shorter */ if ( TRIANG(dDR,pt->m_dMaxRight,dRadius)) { if ( TRIANG(dDL,pt->m_dMaxLeft,dRadius)) { sStack.push_back(pt->m_pLeftBranch); } pt = pt->m_pRightBranch; #ifdef CNEARTREE_INSTRUMENTED ++VisitCount; #endif continue; } } /* Only one branch is viable, try them one at a time */ if ( pt->m_pLeftBranch != 0 && TRIANG(dDL,pt->m_dMaxLeft,dRadius)) { pt = pt->m_pLeftBranch; #ifdef CNEARTREE_INSTRUMENTED ++VisitCount; #endif continue; } if ( pt->m_pRightBranch != 0 && TRIANG(dDR,pt->m_dMaxRight,dRadius)) { pt = pt->m_pRightBranch; #ifdef CNEARTREE_INSTRUMENTED ++VisitCount; #endif continue; } /* We have procesed both sides, we need to go to the stack */ if (!sStack.empty( )) { pt = sStack.back(); sStack.pop_back(); #ifdef CNEARTREE_INSTRUMENTED ++VisitCount; #endif continue; } break; } if ( !sStack.empty( ) ) // for safety !!! { std::vector sTemp; sTemp.swap( sStack ); } return ( (long)tClosest.size() ); } // end InSphere template long InSphere ( const DistanceTypeNode& dRadius, ContainerType& tClosest, std::vector& tIndices, const TNode& t, const std::vector& objectStore #ifdef CNEARTREE_INSTRUMENTED , size_t& VisitCount #endif ) const { std::vector sStack; DistanceTypeNode dDL=0., dDR=0.; NearTreeNode* pt = const_cast(this); #ifdef CNEARTREE_INSTRUMENTED ++VisitCount; #endif if ( pt->m_ptLeft == ULONG_MAX && pt->m_ptRight == ULONG_MAX) return false; // test for empty while ( pt->m_ptLeft != ULONG_MAX || pt->m_ptRight != ULONG_MAX || !sStack.empty( ) ) { if (pt->m_ptLeft == ULONG_MAX && pt->m_ptRight == ULONG_MAX) { if (!sStack.empty( )) { pt = sStack.back(); sStack.pop_back(); #ifdef CNEARTREE_INSTRUMENTED ++VisitCount; #endif continue; } break; } if (pt->m_ptLeft != ULONG_MAX) { dDL = DistanceBetween( t, objectStore[pt->m_ptLeft] ); if ( dDL <= dRadius ) { tClosest.insert( tClosest.end(), objectStore[pt->m_ptLeft] ); tIndices.insert( tIndices.end(), pt->m_ptLeft); } } if (pt->m_ptRight != ULONG_MAX) { #ifdef CNEARTREE_INSTRUMENTED ++VisitCount; #endif dDR = DistanceBetween( t, objectStore[pt->m_ptRight]); if ( dDR <= dRadius ) { tClosest.insert( tClosest.end(), objectStore[pt->m_ptRight] ); tIndices.insert( tIndices.end(), pt->m_ptRight); } } /* See if both branches are populated. In that case, save one branch on the stack, and process the other one based on which one seems smaller, but useful first] */ if (pt->m_pLeftBranch != 0 && pt->m_pRightBranch != 0 ) { if (dDL+pt->m_dMaxLeft < dDR+pt->m_dMaxRight || pt->m_pRightBranch == 0) { if ( TRIANG(dDL,pt->m_dMaxLeft,dRadius)) { if ( TRIANG(dDR,pt->m_dMaxRight,dRadius)) { sStack.push_back(pt->m_pRightBranch); } pt = pt->m_pLeftBranch; #ifdef CNEARTREE_INSTRUMENTED ++VisitCount; #endif continue; } /* If we are here, the left branch was not useful Fall through to use the right */ } /* We come here either because pursuing the left branch was not useful of the right branch look shorter */ if ( TRIANG(dDR,pt->m_dMaxRight,dRadius)) { if ( TRIANG(dDL,pt->m_dMaxLeft,dRadius)) { sStack.push_back(pt->m_pLeftBranch); } pt = pt->m_pRightBranch; #ifdef CNEARTREE_INSTRUMENTED ++VisitCount; #endif continue; } } /* Only one branch is viable, try them one at a time */ if ( pt->m_pLeftBranch != 0 && TRIANG(dDL,pt->m_dMaxLeft,dRadius)) { pt = pt->m_pLeftBranch; #ifdef CNEARTREE_INSTRUMENTED ++VisitCount; #endif continue; } if ( pt->m_pRightBranch != 0 && TRIANG(dDR,pt->m_dMaxRight,dRadius)) { pt = pt->m_pRightBranch; #ifdef CNEARTREE_INSTRUMENTED ++VisitCount; #endif continue; } /* We have procesed both sides, we need to go to the stack */ if (!sStack.empty( )) { pt = sStack.back(); sStack.pop_back(); #ifdef CNEARTREE_INSTRUMENTED ++VisitCount; #endif continue; } break; } if ( !sStack.empty( ) ) // for safety !!! { std::vector sTemp; sTemp.swap( sStack ); } return ( (long)tClosest.size() ); } // end InSphere //======================================================================= // long LeftInSphere ( // const DistanceTypeNode& dRadius, // ContainerType& tClosest, // const TNode& t, // const std::vector& objectStore // ) const // // Private function to search a NearTree for the objects inside of the specified radius // from the probe point // This function is only called by FindInSphere. // // dRadius is the search radius // tClosest is a CNearTree of objects of the templated type found within dRadius of the // probe point // t is the probe point // // returns the number of objects returned in the container (for sets, that may not equal the number found) // // This version searches to the left first // //======================================================================= template long LeftInSphere ( const DistanceTypeNode& dRadius, ContainerType& tClosest, const TNode& t, const std::vector& objectStore #ifdef CNEARTREE_INSTRUMENTED , size_t& VisitCount #endif ) const { std::vector sStack; enum { left, right, end } eDir; eDir = left; // examine the left nodes first NearTreeNode* pt = const_cast(this); if (pt->m_ptLeft == ULONG_MAX) return false; // test for empty #ifdef CNEARTREE_INSTRUMENTED ++VisitCount; #endif while ( ! ( eDir == end && sStack.empty( ) ) ) { if ( eDir == right ) { const DistanceTypeNode dDR = DistanceBetween( t, objectStore[pt->m_ptRight] ); if ( dDR <= dRadius ) { tClosest.insert( tClosest.end(), objectStore[pt->m_ptRight] ); } if ( pt->m_pRightBranch != 0 && TRIANG(dDR,pt->m_dMaxRight,dRadius) ) { // we did the left and now we finished the right, go down pt = pt->m_pRightBranch; #ifdef CNEARTREE_INSTRUMENTED ++VisitCount; #endif eDir = left; } else { eDir = end; } } if ( eDir == left ) { const DistanceTypeNode dDL = DistanceBetween( t, objectStore[pt->m_ptLeft] ); if ( dDL <= dRadius ) { tClosest.insert( tClosest.end(), objectStore[pt->m_ptLeft] ); } if ( pt->m_ptRight != ULONG_MAX ) // only stack if there's a right object { sStack.push_back( pt ); } if ( pt->m_pLeftBranch != 0 && TRIANG(dDL,pt->m_dMaxLeft,dRadius) ) { // we did the left, go down pt = pt->m_pLeftBranch; #ifdef CNEARTREE_INSTRUMENTED ++VisitCount; #endif } else { eDir = end; } } if ( eDir == end && !sStack.empty( ) ) { pt = sStack.back( ); #ifdef CNEARTREE_INSTRUMENTED ++VisitCount; #endif sStack.pop_back( ); eDir = right; } } return ( (long)tClosest.size() ); } // end LeftInSphere template long LeftInSphere ( const DistanceTypeNode& dRadius, ContainerType& tClosest, std::vector& tIndices, const TNode& t, const std::vector& objectStore #ifdef CNEARTREE_INSTRUMENTED , size_t& VisitCount #endif ) const { std::vector sStack; enum { left, right, end } eDir; eDir = left; // examine the left nodes first NearTreeNode* pt = const_cast(this); #ifdef CNEARTREE_INSTRUMENTED ++VisitCount; #endif if (pt->m_ptLeft == ULONG_MAX) return false; // test for empty while ( ! ( eDir == end && sStack.empty( ) ) ) { if ( eDir == right ) { const DistanceTypeNode dDR = DistanceBetween( t, objectStore[pt->m_ptRight] ); if ( dDR <= dRadius ) { tClosest.insert( tClosest.end(), objectStore[pt->m_ptRight] ); tIndices.insert( tIndices.end(), pt->m_ptRight); } if ( pt->m_pRightBranch != 0 && TRIANG(dDR,pt->m_dMaxRight,dRadius) ) { // we did the left and now we finished the right, go down pt = pt->m_pRightBranch; #ifdef CNEARTREE_INSTRUMENTED ++VisitCount; #endif eDir = left; } else { eDir = end; } } if ( eDir == left ) { const DistanceTypeNode dDL = DistanceBetween( t, objectStore[pt->m_ptLeft] ); if ( dDL <= dRadius ) { tClosest.insert( tClosest.end(), objectStore[pt->m_ptLeft] ); tIndices.insert( tIndices.end(), pt->m_ptLeft); } if ( pt->m_ptRight != ULONG_MAX ) // only stack if there's a right object { sStack.push_back( pt ); } if ( pt->m_pLeftBranch != 0 && TRIANG(dDL,pt->m_dMaxLeft,dRadius) ) { // we did the left, go down pt = pt->m_pLeftBranch; #ifdef CNEARTREE_INSTRUMENTED ++VisitCount; #endif } else { eDir = end; } } if ( eDir == end && !sStack.empty( ) ) { pt = sStack.back( ); #ifdef CNEARTREE_INSTRUMENTED ++VisitCount; #endif sStack.pop_back( ); eDir = right; } } return ( (long)tClosest.size() ); } // end LeftInSphere //======================================================================= // long OutSphere ( // const DistanceTypeNode& dRadius, // ContainerType& tFarthest, // const TNode& t, // const std::vector& objectStore // ) const // // Private function to search a NearTree for the objects outside of the specified radius // from the probe point // This function is only called by FindOutSphere. // // dRadius is the search radius // tFarthest is a CNearTree of objects of the templated type found within dRadius of the // probe point // t is the probe point // // returns the number of objects returned in the container (for sets, that may not equal the number found) // //======================================================================= template long OutSphere ( const DistanceTypeNode& dRadius, ContainerType& tFarthest, const TNode& t, const std::vector objectStore #ifdef CNEARTREE_INSTRUMENTED , size_t& VisitCount #endif ) const { std::vector sStack; DistanceTypeNode dDL=0., dDR=0.; NearTreeNode* pt = const_cast(this); #ifdef CNEARTREE_INSTRUMENTED ++VisitCount; #endif if ( pt->m_ptLeft == ULONG_MAX && pt->m_ptRight == ULONG_MAX) return false; // test for empty while ( pt->m_ptLeft != ULONG_MAX || pt->m_ptRight != ULONG_MAX || !sStack.empty( ) ) { if (pt->m_ptLeft == ULONG_MAX && pt->m_ptRight == ULONG_MAX) { if (!sStack.empty( )) { pt = sStack.back(); sStack.pop_back(); #ifdef CNEARTREE_INSTRUMENTED ++VisitCount; #endif continue; } break; } if (pt->m_ptLeft != ULONG_MAX) { dDL = DistanceBetween( t, objectStore[pt->m_ptLeft] ); if ( dDL >= dRadius ) { tFarthest.insert( tFarthest.end(), objectStore[pt->m_ptLeft] ); } } if (pt->m_ptRight != ULONG_MAX) { #ifdef CNEARTREE_INSTRUMENTED ++VisitCount; #endif dDR = DistanceBetween( t, objectStore[pt->m_ptRight]); if ( dDR >= dRadius ) { tFarthest.insert( tFarthest.end(), objectStore[pt->m_ptRight] ); } } /* See if both branches are populated. In that case, save one branch on the stack, and process the other one based on which one seems larger, but useful first] */ if (pt->m_pLeftBranch != 0 && pt->m_pRightBranch != 0 ) { if (dDL+pt->m_dMaxLeft > dDR+pt->m_dMaxRight || pt->m_pRightBranch == 0) { if ( TRIANG(dRadius,dDL,pt->m_dMaxLeft)) { if ( TRIANG(dRadius,dDR,pt->m_dMaxRight)) { sStack.push_back(pt->m_pRightBranch); } pt = pt->m_pLeftBranch; #ifdef CNEARTREE_INSTRUMENTED ++VisitCount; #endif continue; } /* If we are here, the left branch was not useful Fall through to use the right */ } /* We come here either because pursuing the left branch was not useful of the right branch look shorter */ if ( TRIANG(dRadius,dDR,pt->m_dMaxRight)) { if ( TRIANG(dRadius,dDL,pt->m_dMaxLeft)) { sStack.push_back(pt->m_pLeftBranch); } pt = pt->m_pRightBranch; #ifdef CNEARTREE_INSTRUMENTED ++VisitCount; #endif continue; } } /* Only one branch is viable, try them one at a time */ if ( pt->m_pLeftBranch != 0 && TRIANG(dRadius,dDL,pt->m_dMaxLeft)) { pt = pt->m_pLeftBranch; #ifdef CNEARTREE_INSTRUMENTED ++VisitCount; #endif continue; } if ( pt->m_pRightBranch != 0 && TRIANG(dRadius,dDR,pt->m_dMaxRight)) { pt = pt->m_pRightBranch; #ifdef CNEARTREE_INSTRUMENTED ++VisitCount; #endif continue; } /* We have procesed both sides, we need to go to the stack */ if (!sStack.empty( )) { pt = sStack.back(); sStack.pop_back(); #ifdef CNEARTREE_INSTRUMENTED ++VisitCount; #endif continue; } break; } if ( !sStack.empty( ) ) // for safety !!! { std::vector sTemp; sTemp.swap( sStack ); } return ( (long)tFarthest.size() ); } // end OutSphere template long OutSphere ( const DistanceTypeNode& dRadius, ContainerType& tFarthest, std::vector& tIndices, const TNode& t, const std::vector objectStore #ifdef CNEARTREE_INSTRUMENTED , size_t& VisitCount #endif ) const { std::vector sStack; DistanceTypeNode dDL=0., dDR=0.; NearTreeNode* pt = const_cast(this); #ifdef CNEARTREE_INSTRUMENTED ++VisitCount; #endif if ( pt->m_ptLeft == ULONG_MAX && pt->m_ptRight == ULONG_MAX) return false; // test for empty while ( pt->m_ptLeft != ULONG_MAX || pt->m_ptRight != ULONG_MAX || !sStack.empty( ) ) { if (pt->m_ptLeft == ULONG_MAX && pt->m_ptRight == ULONG_MAX) { if (!sStack.empty( )) { pt = sStack.back(); sStack.pop_back(); #ifdef CNEARTREE_INSTRUMENTED ++VisitCount; #endif continue; } break; } if (pt->m_ptLeft != ULONG_MAX) { dDL = DistanceBetween( t, objectStore[pt->m_ptLeft] ); if ( dDL >= dRadius ) { tFarthest.insert( tFarthest.end(), objectStore[pt->m_ptLeft] ); tIndices.insert( tIndices.end(), pt->m_ptLeft); } } if (pt->m_ptRight != ULONG_MAX) { #ifdef CNEARTREE_INSTRUMENTED ++VisitCount; #endif dDR = DistanceBetween( t, objectStore[pt->m_ptRight]); if ( dDR >= dRadius ) { tFarthest.insert( tFarthest.end(), objectStore[pt->m_ptRight] ); tIndices.insert( tIndices.end(), pt->m_ptRight); } } /* See if both branches are populated. In that case, save one branch on the stack, and process the other one based on which one seems larger, but useful first] */ if (pt->m_pLeftBranch != 0 && pt->m_pRightBranch != 0 ) { if (dDL+pt->m_dMaxLeft > dDR+pt->m_dMaxRight || pt->m_pRightBranch == 0) { if ( TRIANG(dRadius,dDL,pt->m_dMaxLeft)) { if ( TRIANG(dRadius,dDR,pt->m_dMaxRight)) { sStack.push_back(pt->m_pRightBranch); } pt = pt->m_pLeftBranch; #ifdef CNEARTREE_INSTRUMENTED ++VisitCount; #endif continue; } /* If we are here, the left branch was not useful Fall through to use the right */ } /* We come here either because pursuing the left branch was not useful of the right branch look shorter */ if ( TRIANG(dRadius,dDR,pt->m_dMaxRight)) { if ( TRIANG(dRadius,dDL,pt->m_dMaxLeft)) { sStack.push_back(pt->m_pLeftBranch); } pt = pt->m_pRightBranch; #ifdef CNEARTREE_INSTRUMENTED ++VisitCount; #endif continue; } } /* Only one branch is viable, try them one at a time */ if ( pt->m_pLeftBranch != 0 && TRIANG(dRadius,dDL,pt->m_dMaxLeft)) { pt = pt->m_pLeftBranch; #ifdef CNEARTREE_INSTRUMENTED ++VisitCount; #endif continue; } if ( pt->m_pRightBranch != 0 && TRIANG(dRadius,dDR,pt->m_dMaxRight)) { pt = pt->m_pRightBranch; #ifdef CNEARTREE_INSTRUMENTED ++VisitCount; #endif continue; } /* We have procesed both sides, we need to go to the stack */ if (!sStack.empty( )) { pt = sStack.back(); sStack.pop_back(); #ifdef CNEARTREE_INSTRUMENTED ++VisitCount; #endif continue; } break; } if ( !sStack.empty( ) ) // for safety !!! { std::vector sTemp; sTemp.swap( sStack ); } return ( (long)tFarthest.size() ); } // end OutSphere //======================================================================= // long LeftOutSphere ( // const DistanceTypeNode& dRadius, // ContainerType& tFarthest, // const TNode& t, // const std::vector& objectStore // ) const // // Private function to search a NearTree for the objects outside of the specified radius // from the probe point // This function is only called by FindOutSphere. // // dRadius is the search radius // tFarthest is a CNearTree of objects of the templated type found within dRadius of the // probe point // t is the probe point // // returns the number of objects returned in the container (for sets, that may not equal the number found) // //======================================================================= template long LeftOutSphere ( const DistanceTypeNode& dRadius, ContainerType& tFarthest, const TNode& t, const std::vector objectStore #ifdef CNEARTREE_INSTRUMENTED , size_t& VisitCount #endif ) const { std::vector sStack; enum { left, right, end } eDir; eDir = left; // examine the left nodes first NearTreeNode* pt = const_cast(this); #ifdef CNEARTREE_INSTRUMENTED ++VisitCount; #endif if (pt->m_ptLeft == ULONG_MAX) return false; // test for empty while ( ! ( eDir == end && sStack.empty( ) ) ) { if ( eDir == right ) { const DistanceTypeNode dDR = DistanceBetween( t, objectStore[pt->m_ptRight] ); if ( dDR >= dRadius ) { tFarthest.insert( tFarthest.end(), objectStore[pt->m_ptRight] ); } if ( pt->m_pRightBranch != 0 && TRIANG(dRadius,dDR,pt->m_dMaxRight) ) { // we did the left and now we finished the right, go down pt = pt->m_pRightBranch; #ifdef CNEARTREE_INSTRUMENTED ++VisitCount; #endif eDir = left; } else { eDir = end; } } if ( eDir == left ) { const DistanceTypeNode dDL = DistanceBetween( t, objectStore[pt->m_ptLeft] ); if ( dDL >= dRadius ) { tFarthest.insert( tFarthest.end(), objectStore[pt->m_ptLeft] ); } if ( pt->m_ptRight != ULONG_MAX ) // only stack if there's a right object { sStack.push_back( pt ); } if ( pt->m_pLeftBranch != 0 && TRIANG(dRadius,dDL,pt->m_dMaxLeft) ) { // we did the left, go down pt = pt->m_pLeftBranch; #ifdef CNEARTREE_INSTRUMENTED ++VisitCount; #endif } else { eDir = end; } } if ( eDir == end && !sStack.empty( ) ) { pt = sStack.back( ); #ifdef CNEARTREE_INSTRUMENTED ++VisitCount; #endif sStack.pop_back( ); eDir = right; } } return ( (long)tFarthest.size() ); } // end LeftOutSphere template long LeftOutSphere ( const DistanceTypeNode& dRadius, ContainerType& tFarthest, std::vector& tIndices, const TNode& t, const std::vector objectStore #ifdef CNEARTREE_INSTRUMENTED , size_t& VisitCount #endif ) const { std::vector sStack; enum { left, right, end } eDir; eDir = left; // examine the left nodes first NearTreeNode* pt = const_cast(this); #ifdef CNEARTREE_INSTRUMENTED ++VisitCount; #endif if (pt->m_ptLeft == ULONG_MAX) return false; // test for empty while ( ! ( eDir == end && sStack.empty( ) ) ) { if ( eDir == right ) { const DistanceTypeNode dDR = DistanceBetween( t, objectStore[pt->m_ptRight] ); if ( dDR >= dRadius ) { tFarthest.insert( tFarthest.end(), objectStore[pt->m_ptRight] ); tIndices.insert( tIndices.end(), pt->m_ptRight ); } if ( pt->m_pRightBranch != 0 && TRIANG(dRadius,dDR,pt->m_dMaxRight) ) { // we did the left and now we finished the right, go down pt = pt->m_pRightBranch; #ifdef CNEARTREE_INSTRUMENTED ++VisitCount; #endif eDir = left; } else { eDir = end; } } if ( eDir == left ) { const DistanceTypeNode dDL = DistanceBetween( t, objectStore[pt->m_ptLeft] ); if ( dDL >= dRadius ) { tFarthest.insert( tFarthest.end(), objectStore[pt->m_ptLeft] ); tIndices.insert( tIndices.end(), pt->m_ptLeft ); } if ( pt->m_ptRight != ULONG_MAX ) // only stack if there's a right object { sStack.push_back( pt ); } if ( pt->m_pLeftBranch != 0 && TRIANG(dRadius,dDL,pt->m_dMaxLeft) ) { // we did the left, go down pt = pt->m_pLeftBranch; #ifdef CNEARTREE_INSTRUMENTED ++VisitCount; #endif } else { eDir = end; } } if ( eDir == end && !sStack.empty( ) ) { pt = sStack.back( ); #ifdef CNEARTREE_INSTRUMENTED ++VisitCount; #endif sStack.pop_back( ); eDir = right; } } return ( (long)tFarthest.size() ); } // end LeftOutSphere //======================================================================= // long InAnnulus ( const DistanceTypeNode& dRadius1, const DistanceTypeNode& dRadius2, CNearTree< TNode >& tAnnular, const TNode& t ) const // // Private function to search a NearTree for the objects within a specified annulus from probe point // This function is only called by FindInAnnulus. // // dRadius1, dRadius2 specifies the range of the annulus // tAnnular is a NearTree of objects of the templated type found between the two radii // t is the probe point // // returns the number of objects returned in the container (for sets, that may not equal the number found) // //======================================================================= template long InAnnulus ( const DistanceTypeNode& dRadius1, const DistanceTypeNode& dRadius2, ContainerType& tAnnular, const TNode& t, const std::vector objectStore #ifdef CNEARTREE_INSTRUMENTED , size_t& VisitCount #endif ) const { std::vector sStack; DistanceTypeNode dDL=0., dDR=0.; NearTreeNode* pt = const_cast(this); #ifdef CNEARTREE_INSTRUMENTED ++VisitCount; #endif if ( pt->m_ptLeft == ULONG_MAX && pt->m_ptRight == ULONG_MAX) return false; // test for empty while ( pt->m_ptLeft != ULONG_MAX || pt->m_ptRight != ULONG_MAX || !sStack.empty( ) ) { if (pt->m_ptLeft == ULONG_MAX && pt->m_ptRight == ULONG_MAX) { if (!sStack.empty( )) { pt = sStack.back(); sStack.pop_back(); #ifdef CNEARTREE_INSTRUMENTED ++VisitCount; #endif continue; } break; } if (pt->m_ptLeft != ULONG_MAX) { dDL = DistanceBetween( t, objectStore[pt->m_ptLeft] ); if ( dDL <= dRadius2 && dDL >= dRadius1 ) { tAnnular.insert( tAnnular.end(), objectStore[pt->m_ptLeft] ); } } if (pt->m_ptRight != ULONG_MAX) { #ifdef CNEARTREE_INSTRUMENTED ++VisitCount; #endif dDR = DistanceBetween( t, objectStore[pt->m_ptRight]); if ( dDR <= dRadius2 && dDR >= dRadius1 ) { tAnnular.insert( tAnnular.end(), objectStore[pt->m_ptRight] ); } } /* See if both branches are populated. In that case, save one branch on the stack, and process the other one based on which one seems closer, but useful first */ if (pt->m_pLeftBranch != 0 && pt->m_pRightBranch != 0 ) { if (dDL+pt->m_dMaxLeft < dDR+pt->m_dMaxRight || pt->m_pRightBranch == 0) { if ( (TRIANG(dRadius1,dDL,pt->m_dMaxLeft)) && (TRIANG(dDL,pt->m_dMaxLeft,dRadius2) )) { if ( (TRIANG(dRadius1,dDR,pt->m_dMaxRight)) && (TRIANG(dDR,pt->m_dMaxRight,dRadius2) )) { sStack.push_back(pt->m_pRightBranch); } pt = pt->m_pLeftBranch; #ifdef CNEARTREE_INSTRUMENTED ++VisitCount; #endif continue; } /* If we are here, the left branch was not useful Fall through to use the right */ } /* We come here either because pursuing the left branch was not useful of the right branch look shorter */ if ( (TRIANG(dRadius1,dDR,pt->m_dMaxRight)) && (TRIANG(dDR,pt->m_dMaxRight,dRadius2) ) ) { if ( (TRIANG(dRadius1,dDL,pt->m_dMaxLeft)) && (TRIANG(dDL,pt->m_dMaxLeft,dRadius2) )) { sStack.push_back(pt->m_pLeftBranch); } pt = pt->m_pRightBranch; #ifdef CNEARTREE_INSTRUMENTED ++VisitCount; #endif continue; } } /* Only one branch is viable, try them one at a time */ if ( pt->m_pLeftBranch != 0 && (TRIANG(dRadius1,dDL,pt->m_dMaxLeft)) && (TRIANG(dDL,pt->m_dMaxLeft,dRadius2) )) { pt = pt->m_pLeftBranch; #ifdef CNEARTREE_INSTRUMENTED ++VisitCount; #endif continue; } if ( pt->m_pRightBranch != 0 && (TRIANG(dRadius1,dDR,pt->m_dMaxRight)) && (TRIANG(dDR,pt->m_dMaxRight,dRadius2) )) { pt = pt->m_pRightBranch; #ifdef CNEARTREE_INSTRUMENTED ++VisitCount; #endif continue; } /* We have procesed both sides, we need to go to the stack */ if (!sStack.empty( )) { pt = sStack.back(); sStack.pop_back(); #ifdef CNEARTREE_INSTRUMENTED ++VisitCount; #endif continue; } break; } if ( !sStack.empty( ) ) // for safety !!! { std::vector sTemp; sTemp.swap( sStack ); } return ( (long)tAnnular.size() ); } // end InAnnulus template long InAnnulus ( const DistanceTypeNode& dRadius1, const DistanceTypeNode& dRadius2, ContainerType& tAnnular, std::vector& tIndices, const TNode& t, const std::vector objectStore #ifdef CNEARTREE_INSTRUMENTED , size_t& VisitCount #endif ) const { std::vector sStack; DistanceTypeNode dDL=0., dDR=0.; NearTreeNode* pt = const_cast(this); #ifdef CNEARTREE_INSTRUMENTED ++VisitCount; #endif if ( pt->m_ptLeft == ULONG_MAX && pt->m_ptRight == ULONG_MAX) return false; // test for empty while ( pt->m_ptLeft != ULONG_MAX || pt->m_ptRight != ULONG_MAX || !sStack.empty( ) ) { if (pt->m_ptLeft == ULONG_MAX && pt->m_ptRight == ULONG_MAX) { if (!sStack.empty( )) { pt = sStack.back(); sStack.pop_back(); #ifdef CNEARTREE_INSTRUMENTED ++VisitCount; #endif continue; } break; } if (pt->m_ptLeft != ULONG_MAX) { dDL = DistanceBetween( t, objectStore[pt->m_ptLeft] ); if ( dDL <= dRadius2 && dDL >= dRadius1 ) { tAnnular.insert( tAnnular.end(), objectStore[pt->m_ptLeft] ); tIndices.insert( tIndices.end(), pt->m_ptLeft); } } if (pt->m_ptRight != ULONG_MAX) { #ifdef CNEARTREE_INSTRUMENTED ++VisitCount; #endif dDR = DistanceBetween( t, objectStore[pt->m_ptRight]); if ( dDR <= dRadius2 && dDR >= dRadius1 ) { tAnnular.insert( tAnnular.end(), objectStore[pt->m_ptRight] ); tIndices.insert( tIndices.end(), pt->m_ptRight); } } /* See if both branches are populated. In that case, save one branch on the stack, and process the other one based on which one seems larger, but useful first] */ if (pt->m_pLeftBranch != 0 && pt->m_pRightBranch != 0 ) { if (dDL+pt->m_dMaxLeft < dDR+pt->m_dMaxRight || pt->m_pRightBranch == 0) { if ( (TRIANG(dRadius1,dDL,pt->m_dMaxLeft)) && (TRIANG(dDL,pt->m_dMaxLeft,dRadius2) )) { if ( (TRIANG(dRadius1,dDR,pt->m_dMaxRight)) && (TRIANG(dDR,pt->m_dMaxRight,dRadius2) )) { sStack.push_back(pt->m_pRightBranch); } pt = pt->m_pLeftBranch; #ifdef CNEARTREE_INSTRUMENTED ++VisitCount; #endif continue; } /* If we are here, the left branch was not useful Fall through to use the right */ } /* We come here either because pursuing the left branch was not useful of the right branch look shorter */ if ( (TRIANG(dRadius1,dDR,pt->m_dMaxRight)) && (TRIANG(dDR,pt->m_dMaxRight,dRadius2) ) ) { if ( (TRIANG(dRadius1,dDL,pt->m_dMaxLeft)) && (TRIANG(dDL,pt->m_dMaxLeft,dRadius2) )) { sStack.push_back(pt->m_pLeftBranch); } pt = pt->m_pRightBranch; #ifdef CNEARTREE_INSTRUMENTED ++VisitCount; #endif continue; } } /* Only one branch is viable, try them one at a time */ if ( pt->m_pLeftBranch != 0 && (TRIANG(dRadius1,dDL,pt->m_dMaxLeft)) && (TRIANG(dDL,pt->m_dMaxLeft,dRadius2) )) { pt = pt->m_pLeftBranch; #ifdef CNEARTREE_INSTRUMENTED ++VisitCount; #endif continue; } if ( pt->m_pRightBranch != 0 && (TRIANG(dRadius1,dDR,pt->m_dMaxRight)) && (TRIANG(dDR,pt->m_dMaxRight,dRadius2) )) { pt = pt->m_pRightBranch; #ifdef CNEARTREE_INSTRUMENTED ++VisitCount; #endif continue; } /* We have procesed both sides, we need to go to the stack */ if (!sStack.empty( )) { pt = sStack.back(); sStack.pop_back(); #ifdef CNEARTREE_INSTRUMENTED ++VisitCount; #endif continue; } break; } if ( !sStack.empty( ) ) // for safety !!! { std::vector sTemp; sTemp.swap( sStack ); } return ( (long)tAnnular.size() ); } // end InAnnulus //======================================================================= // long LeftInAnnulus ( const DistanceTypeNode& dRadius1, const DistanceTypeNode& dRadius2, CNearTree< TNode >& tAnnular, const TNode& t ) const // // Private function to search a NearTree for the objects within a specified annulus from probe point // This function is only called by FindInAnnulus. // // dRadius1, dRadius2 specifies the range of the annulus // tAnnular is a NearTree of objects of the templated type found between the two radii // t is the probe point // // returns the number of objects returned in the container (for sets, that may not equal the number found) // //======================================================================= template long LeftInAnnulus ( const DistanceTypeNode& dRadius1, const DistanceTypeNode& dRadius2, ContainerType& tAnnular, const TNode& t, const std::vector objectStore #ifdef CNEARTREE_INSTRUMENTED , size_t& VisitCount #endif ) const { std::vector sStack; enum { left, right, end } eDir; eDir = left; // examine the left nodes first NearTreeNode* pt = const_cast(this); #ifdef CNEARTREE_INSTRUMENTED ++VisitCount; #endif if (pt->m_ptLeft == ULONG_MAX) return false; // test for empty while ( ! ( eDir == end && sStack.empty( ) ) ) { if ( eDir == right ) { const DistanceTypeNode dDR = DistanceBetween( t, objectStore[pt->m_ptRight] ); if ( dDR <= dRadius2 && dDR >= dRadius1 ) { tAnnular.insert( tAnnular.end( ), objectStore[pt->m_ptRight] ); } if ( pt->m_pRightBranch != 0 && (TRIANG(dRadius1,dDR,pt->m_dMaxRight)) && (TRIANG(dDR,pt->m_dMaxRight,dRadius2) ) ) { // we did the left and now we finished the right, go down pt = pt->m_pRightBranch; #ifdef CNEARTREE_INSTRUMENTED ++VisitCount; #endif eDir = left; } else { eDir = end; } } if ( eDir == left ) { const DistanceTypeNode dDL = DistanceBetween( t, objectStore[pt->m_ptLeft] ); if ( dDL <= dRadius2 && dDL >= dRadius1 ) { tAnnular.insert( tAnnular.end(), objectStore[pt->m_ptLeft] ); } if ( pt->m_ptRight != ULONG_MAX ) // only stack if there's a right object { sStack.push_back( pt ); } if ( pt->m_pLeftBranch != 0 && (TRIANG(dRadius1,dDL,pt->m_dMaxLeft)) && (TRIANG(dDL,pt->m_dMaxLeft,dRadius2) ) ) { // we did the left, go down pt = pt->m_pLeftBranch; #ifdef CNEARTREE_INSTRUMENTED ++VisitCount; #endif } else { eDir = end; } } if ( eDir == end && !sStack.empty( ) ) { pt = sStack.back( ); #ifdef CNEARTREE_INSTRUMENTED ++VisitCount; #endif sStack.pop_back( ); eDir = right; } } return ( (long)tAnnular.size() ); } // end LeftInAnnulus template long LeftInAnnulus ( const DistanceTypeNode& dRadius1, const DistanceTypeNode& dRadius2, ContainerType& tAnnular, std::vector& tIndices, const TNode& t, const std::vector objectStore #ifdef CNEARTREE_INSTRUMENTED , size_t& VisitCount #endif ) const { std::vector sStack; enum { left, right, end } eDir; eDir = left; // examine the left nodes first NearTreeNode* pt = const_cast(this); #ifdef CNEARTREE_INSTRUMENTED ++VisitCount; #endif if (pt->m_ptLeft == ULONG_MAX) return false; // test for empty while ( ! ( eDir == end && sStack.empty( ) ) ) { if ( eDir == right ) { const DistanceTypeNode dDR = DistanceBetween( t, objectStore[pt->m_ptRight] ); if ( dDR <= dRadius2 && dDR >= dRadius1 ) { tAnnular.insert( tAnnular.end( ), objectStore[pt->m_ptRight] ); tIndices.insert( tIndices.end( ), pt->m_ptRight ); } if ( pt->m_pRightBranch != 0 && (TRIANG(dRadius1,dDR,pt->m_dMaxRight)) && (TRIANG(dDR,pt->m_dMaxRight,dRadius2) ) ) { // we did the left and now we finished the right, go down pt = pt->m_pRightBranch; #ifdef CNEARTREE_INSTRUMENTED ++VisitCount; #endif eDir = left; } else { eDir = end; } } if ( eDir == left ) { const DistanceTypeNode dDL = DistanceBetween( t, objectStore[pt->m_ptLeft] ); if ( dDL <= dRadius2 && dDL >= dRadius1 ) { tAnnular.insert( tAnnular.end(), objectStore[pt->m_ptLeft] ); tIndices.insert( tIndices.end( ), pt->m_ptLeft ); } if ( pt->m_ptRight != ULONG_MAX ) // only stack if there's a right object { sStack.push_back( pt ); } if ( pt->m_pLeftBranch != 0 && (TRIANG(dRadius1,dDL,pt->m_dMaxLeft)) && (TRIANG(dDL,pt->m_dMaxLeft,dRadius2) ) ) { // we did the left, go down pt = pt->m_pLeftBranch; #ifdef CNEARTREE_INSTRUMENTED ++VisitCount; #endif } else { eDir = end; } } if ( eDir == end && !sStack.empty( ) ) { pt = sStack.back( ); #ifdef CNEARTREE_INSTRUMENTED ++VisitCount; #endif sStack.pop_back( ); eDir = right; } } return ( (long)tAnnular.size() ); } // end LeftInAnnulus //======================================================================= // long K_Near ( const DistanceTypeNode dRadius, // std::vector >& tClosest, // const TNode& t, const std::vector& objectStore ) const // long K_Near ( const DistanceTypeNode dRadius, // std::vector >& tClosest, // const TNode& t, const std::vector& objectStore ) const // // Private function to search a NearTree for the objects inside of the specified radius // from the probe point // This function is only called by FindK_Nearest. // // k: the maximum number of object to return, giving preference to the nearest // dRadius: the search radius, which will be updated when the internal store is resized // tClosest: is a vector of pairs of Nodes and objects or of triples // of Nodes, objects and ordinals of objects where the objects // are of the templated type found within dRadius of the // probe point, limited by the k-near search // t: is the probe point // objectStore: the internal vector storing the object in CNearTree // // returns the number of objects returned in the container (for sets, that may not equal the number found) // /*=======================================================================*/ long K_Near ( const size_t k, DistanceTypeNode& dRadius, std::vector >& tClosest, const TNode& t, const std::vector& objectStore #ifdef CNEARTREE_INSTRUMENTED , size_t& VisitCount #endif ) { std::vector sStack; DistanceTypeNode dDL=0., dDR=0.; NearTreeNode* pt = const_cast(this); #ifdef CNEARTREE_INSTRUMENTED ++VisitCount; #endif if ( pt->m_ptLeft == ULONG_MAX && pt->m_ptRight == ULONG_MAX) return false; // test for empty while ( pt->m_ptLeft != ULONG_MAX || pt->m_ptRight != ULONG_MAX || !sStack.empty( ) ) { if (pt->m_ptLeft == ULONG_MAX && pt->m_ptRight == ULONG_MAX) { if (!sStack.empty( )) { pt = sStack.back(); sStack.pop_back(); #ifdef CNEARTREE_INSTRUMENTED ++VisitCount; #endif continue; } break; } if (pt->m_ptLeft != ULONG_MAX) { dDL = DistanceBetween( t, objectStore[pt->m_ptLeft] ); if ( dDL <= dRadius ) { tClosest.insert( tClosest.end(), std::make_pair( dDL, objectStore[pt->m_ptLeft] ) ); if( tClosest.size( ) > 2*k ) K_Resize( k, t, tClosest, dRadius ); } } if (pt->m_ptRight != ULONG_MAX) { #ifdef CNEARTREE_INSTRUMENTED ++VisitCount; #endif dDR = DistanceBetween( t, objectStore[pt->m_ptRight]); if ( dDR <= dRadius ) { tClosest.insert( tClosest.end(), std::make_pair( dDR, objectStore[pt->m_ptRight] ) ); if( tClosest.size( ) > 2*k ) K_Resize( k, t, tClosest, dRadius ); } } /* See if both branches are populated. In that case, save one branch on the stack, and process the other one based on which one seems smaller, but useful first] */ if (pt->m_pLeftBranch != 0 && pt->m_pRightBranch != 0 ) { if (dDL+pt->m_dMaxLeft < dDR+pt->m_dMaxRight || pt->m_pRightBranch == 0) { if ( TRIANG(dDL,pt->m_dMaxLeft,dRadius)) { if ( TRIANG(dDR,pt->m_dMaxRight,dRadius)) { sStack.push_back(pt->m_pRightBranch); } pt = pt->m_pLeftBranch; #ifdef CNEARTREE_INSTRUMENTED ++VisitCount; #endif continue; } /* If we are here, the left branch was not useful Fall through to use the right */ } /* We come here either because pursuing the left branch was not useful of the right branch look shorter */ if ( TRIANG(dDR,pt->m_dMaxRight,dRadius)) { if ( TRIANG(dDL,pt->m_dMaxLeft,dRadius)) { sStack.push_back(pt->m_pLeftBranch); } pt = pt->m_pRightBranch; #ifdef CNEARTREE_INSTRUMENTED ++VisitCount; #endif continue; } } /* Only one branch is viable, try them one at a time */ if ( pt->m_pLeftBranch != 0 && TRIANG(dDL,pt->m_dMaxLeft,dRadius)) { pt = pt->m_pLeftBranch; #ifdef CNEARTREE_INSTRUMENTED ++VisitCount; #endif continue; } if ( pt->m_pRightBranch != 0 && TRIANG(dDR,pt->m_dMaxRight,dRadius)) { pt = pt->m_pRightBranch; #ifdef CNEARTREE_INSTRUMENTED ++VisitCount; #endif continue; } /* We have procesed both sides, we need to go to the stack */ if (!sStack.empty( )) { pt = sStack.back(); sStack.pop_back(); #ifdef CNEARTREE_INSTRUMENTED ++VisitCount; #endif continue; } break; } if ( !sStack.empty( ) ) // for safety !!! { std::vector sTemp; sTemp.swap( sStack ); } if( tClosest.size( ) > 1 ) K_Resize( k, t, tClosest, dRadius ); return ( (long)tClosest.size( ) ); } // end KNear long K_Near ( const size_t k, DistanceTypeNode& dRadius, std::vector >& tClosest, const TNode& t, const std::vector& objectStore #ifdef CNEARTREE_INSTRUMENTED , size_t& VisitCount #endif ) { std::vector sStack; DistanceTypeNode dDL=0., dDR=0.; NearTreeNode* pt = const_cast(this); #ifdef CNEARTREE_INSTRUMENTED ++VisitCount; #endif if ( pt->m_ptLeft == ULONG_MAX && pt->m_ptRight == ULONG_MAX) return false; // test for empty while ( pt->m_ptLeft != ULONG_MAX || pt->m_ptRight != ULONG_MAX || !sStack.empty( ) ) { if (pt->m_ptLeft == ULONG_MAX && pt->m_ptRight == ULONG_MAX) { if (!sStack.empty( )) { pt = sStack.back(); sStack.pop_back(); #ifdef CNEARTREE_INSTRUMENTED ++VisitCount; #endif continue; } break; } if (pt->m_ptLeft != ULONG_MAX) { dDL = DistanceBetween( t, objectStore[pt->m_ptLeft] ); if ( dDL <= dRadius ) { tClosest.insert( tClosest.end(), make_triple( dDL, objectStore[pt->m_ptLeft], pt->m_ptLeft ) ); if( tClosest.size( ) > 2*k ) K_Resize( k, t, tClosest, dRadius ); } } if (pt->m_ptRight != ULONG_MAX) { #ifdef CNEARTREE_INSTRUMENTED ++VisitCount; #endif dDR = DistanceBetween( t, objectStore[pt->m_ptRight]); if ( dDR <= dRadius ) { tClosest.insert( tClosest.end(), make_triple( dDR, objectStore[pt->m_ptRight], pt->m_ptRight ) ); if( tClosest.size( ) > 2*k ) K_Resize( k, t, tClosest, dRadius ); } } /* See if both branches are populated. In that case, save one branch on the stack, and process the other one based on which one seems smaller, but useful first] */ if (pt->m_pLeftBranch != 0 && pt->m_pRightBranch != 0 ) { if (dDL+pt->m_dMaxLeft < dDR+pt->m_dMaxRight || pt->m_pRightBranch == 0) { if ( TRIANG(dDL,pt->m_dMaxLeft,dRadius)) { if ( TRIANG(dDR,pt->m_dMaxRight,dRadius)) { sStack.push_back(pt->m_pRightBranch); } pt = pt->m_pLeftBranch; #ifdef CNEARTREE_INSTRUMENTED ++VisitCount; #endif continue; } /* If we are here, the left branch was not useful Fall through to use the right */ } /* We come here either because pursuing the left branch was not useful of the right branch look shorter */ if ( TRIANG(dDR,pt->m_dMaxRight,dRadius)) { if ( TRIANG(dDL,pt->m_dMaxLeft,dRadius)) { sStack.push_back(pt->m_pLeftBranch); } pt = pt->m_pRightBranch; #ifdef CNEARTREE_INSTRUMENTED ++VisitCount; #endif continue; } } /* Only one branch is viable, try them one at a time */ if ( pt->m_pLeftBranch != 0 && TRIANG(dDL,pt->m_dMaxLeft,dRadius)) { pt = pt->m_pLeftBranch; #ifdef CNEARTREE_INSTRUMENTED ++VisitCount; #endif continue; } if ( pt->m_pRightBranch != 0 && TRIANG(dDR,pt->m_dMaxRight,dRadius)) { pt = pt->m_pRightBranch; #ifdef CNEARTREE_INSTRUMENTED ++VisitCount; #endif continue; } /* We have procesed both sides, we need to go to the stack */ if (!sStack.empty( )) { pt = sStack.back(); sStack.pop_back(); #ifdef CNEARTREE_INSTRUMENTED ++VisitCount; #endif continue; } break; } if ( !sStack.empty( ) ) // for safety !!! { std::vector sTemp; sTemp.swap( sStack ); } if( tClosest.size( ) > 1 ) K_Resize( k, t, tClosest, dRadius ); return ( (long)tClosest.size( ) ); } // end KNear //======================================================================= // long K_Far ( const DistanceTypeNode dRadius, std::vector >& tFarthest, const TNode& t ) const // long K_Far ( const DistanceTypeNode dRadius, std::vector >& tFarthest, tFarthest, const TNode& t ) const // // Private function to search a NearTree for the objects inside of the specified radius // from the probe point. Distances are stored in an intermediate array as negative values // so that the same logic as K_Near can be used. // This function is only called by FindK_Farthest. // // k: the maximum number of object to return, giving preference to the nearest // dRadius: the search radius, which will be updated when the internal store is resized // tFarthest: is a vector of pairs of Nodes and objects or of triples // of Nodes, objects and ordinals of objects where the objects // are of the templated type found outside of dRadius of the // probe point, limited by the k-farthest search // t: is the probe point // objectStore: the internal vector storing the object in CNearTree // // returns the number of objects returned in the container (for sets, that may not equal the number found) // /*=======================================================================*/ long K_Far ( const size_t k, DistanceTypeNode& dRadius, std::vector >& tFarthest, const TNode& t, const std::vector& objectStore #ifdef CNEARTREE_INSTRUMENTED , size_t& VisitCount #endif ) { std::vector sStack; DistanceTypeNode dDL=0., dDR=0.; NearTreeNode* pt = const_cast(this); #ifdef CNEARTREE_INSTRUMENTED ++VisitCount; #endif if ( pt->m_ptLeft == ULONG_MAX && pt->m_ptRight == ULONG_MAX) return false; // test for empty while ( pt->m_ptLeft != ULONG_MAX || pt->m_ptRight != ULONG_MAX || !sStack.empty( ) ) { if (pt->m_ptLeft == ULONG_MAX && pt->m_ptRight == ULONG_MAX) { if (!sStack.empty( )) { pt = sStack.back(); sStack.pop_back(); #ifdef CNEARTREE_INSTRUMENTED ++VisitCount; #endif continue; } break; } if (pt->m_ptLeft != ULONG_MAX) { dDL = DistanceBetween( t, objectStore[pt->m_ptLeft] ); if ( dDL >= dRadius ) { tFarthest.insert( tFarthest.end(), std::make_pair( -dDL, objectStore[pt->m_ptLeft] ) ); if( tFarthest.size( ) > 2*k ) K_Resize( k, t, tFarthest, dRadius ); } } if (pt->m_ptRight != ULONG_MAX) { #ifdef CNEARTREE_INSTRUMENTED ++VisitCount; #endif dDR = DistanceBetween( t, objectStore[pt->m_ptRight]); if ( dDR >= dRadius ) { tFarthest.insert( tFarthest.end(), std::make_pair( -dDR, objectStore[pt->m_ptRight] ) ); if( tFarthest.size( ) > 2*k ) K_Resize( k, t, tFarthest, dRadius ); } } /* See if both branches are populated. In that case, save one branch on the stack, and process the other one based on which one seems larger, but useful first] */ if (pt->m_pLeftBranch != 0 && pt->m_pRightBranch != 0 ) { if (dDL+pt->m_dMaxLeft > dDR+pt->m_dMaxRight || pt->m_pRightBranch == 0) { if ( TRIANG(dRadius,dDL,pt->m_dMaxLeft)) { if ( TRIANG(dRadius,dDR,pt->m_dMaxRight)) { sStack.push_back(pt->m_pRightBranch); } pt = pt->m_pLeftBranch; #ifdef CNEARTREE_INSTRUMENTED ++VisitCount; #endif continue; } /* If we are here, the left branch was not useful Fall through to use the right */ } /* We come here either because pursuing the left branch was not useful of the right branch look shorter */ if ( TRIANG(dRadius,dDR,pt->m_dMaxRight)) { if ( TRIANG(dRadius,dDL,pt->m_dMaxLeft)) { sStack.push_back(pt->m_pLeftBranch); } pt = pt->m_pRightBranch; #ifdef CNEARTREE_INSTRUMENTED ++VisitCount; #endif continue; } } /* Only one branch is viable, try them one at a time */ if ( pt->m_pLeftBranch != 0 && TRIANG(dRadius,dDL,pt->m_dMaxLeft)) { pt = pt->m_pLeftBranch; #ifdef CNEARTREE_INSTRUMENTED ++VisitCount; #endif continue; } if ( pt->m_pRightBranch != 0 && TRIANG(dRadius,dDR,pt->m_dMaxRight)) { pt = pt->m_pRightBranch; #ifdef CNEARTREE_INSTRUMENTED ++VisitCount; #endif continue; } /* We have procesed both sides, we need to go to the stack */ if (!sStack.empty( )) { pt = sStack.back(); sStack.pop_back(); #ifdef CNEARTREE_INSTRUMENTED ++VisitCount; #endif continue; } break; } if ( !sStack.empty( ) ) // for safety !!! { std::vector sTemp; sTemp.swap( sStack ); } if( tFarthest.size( ) > k ) K_Resize( k, t, tFarthest, dRadius ); return ( (long)tFarthest.size( ) ); } // end KFar long K_Far ( const size_t k, DistanceTypeNode& dRadius, std::vector >& tFarthest, const TNode& t, const std::vector& objectStore #ifdef CNEARTREE_INSTRUMENTED , size_t& VisitCount #endif ) { std::vector sStack; DistanceTypeNode dDL=0., dDR=0.; NearTreeNode* pt = const_cast(this); #ifdef CNEARTREE_INSTRUMENTED ++VisitCount; #endif if ( pt->m_ptLeft == ULONG_MAX && pt->m_ptRight == ULONG_MAX) return false; // test for empty while ( pt->m_ptLeft != ULONG_MAX || pt->m_ptRight != ULONG_MAX || !sStack.empty( ) ) { if (pt->m_ptLeft == ULONG_MAX && pt->m_ptRight == ULONG_MAX) { if (!sStack.empty( )) { pt = sStack.back(); sStack.pop_back(); #ifdef CNEARTREE_INSTRUMENTED ++VisitCount; #endif continue; } break; } if (pt->m_ptLeft != ULONG_MAX) { dDL = DistanceBetween( t, objectStore[pt->m_ptLeft] ); if ( dDL >= dRadius ) { tFarthest.insert( tFarthest.end(), make_triple( -dDL, objectStore[pt->m_ptLeft], pt->m_ptLeft) ); if( tFarthest.size( ) > 2*k ) K_Resize( k, t, tFarthest, dRadius ); } } if (pt->m_ptRight != ULONG_MAX) { #ifdef CNEARTREE_INSTRUMENTED ++VisitCount; #endif dDR = DistanceBetween( t, objectStore[pt->m_ptRight]); if ( dDR >= dRadius ) { tFarthest.insert( tFarthest.end(), make_triple( -dDR, objectStore[pt->m_ptRight], pt->m_pt_Right ) ); if( tFarthest.size( ) > 2*k ) K_Resize( k, t, tFarthest, dRadius ); } } /* See if both branches are populated. In that case, save one branch on the stack, and process the other one based on which one seems larger, but useful first] */ if (pt->m_pLeftBranch != 0 && pt->m_pRightBranch != 0 ) { if (dDL+pt->m_dMaxLeft > dDR+pt->m_dMaxRight || pt->m_pRightBranch == 0) { if ( TRIANG(dRadius,dDL,pt->m_dMaxLeft)) { if ( TRIANG(dRadius,dDR,pt->m_dMaxRight)) { sStack.push_back(pt->m_pRightBranch); } pt = pt->m_pLeftBranch; #ifdef CNEARTREE_INSTRUMENTED ++VisitCount; #endif continue; } /* If we are here, the left branch was not useful Fall through to use the right */ } /* We come here either because pursuing the left branch was not useful of the right branch look shorter */ if ( TRIANG(dRadius,dDR,pt->m_dMaxRight)) { if ( TRIANG(dRadius,dDL,pt->m_dMaxLeft)) { sStack.push_back(pt->m_pLeftBranch); } pt = pt->m_pRightBranch; #ifdef CNEARTREE_INSTRUMENTED ++VisitCount; #endif continue; } } /* Only one branch is viable, try them one at a time */ if ( pt->m_pLeftBranch != 0 && TRIANG(dRadius,dDL,pt->m_dMaxLeft)) { pt = pt->m_pLeftBranch; #ifdef CNEARTREE_INSTRUMENTED ++VisitCount; #endif continue; } if ( pt->m_pRightBranch != 0 && TRIANG(dRadius,dDR,pt->m_dMaxRight)) { pt = pt->m_pRightBranch; #ifdef CNEARTREE_INSTRUMENTED ++VisitCount; #endif continue; } /* We have procesed both sides, we need to go to the stack */ if (!sStack.empty( )) { pt = sStack.back(); sStack.pop_back(); #ifdef CNEARTREE_INSTRUMENTED ++VisitCount; #endif continue; } break; } if ( !sStack.empty( ) ) // for safety !!! { std::vector sTemp; sTemp.swap( sStack ); } if( tFarthest.size( ) > 1 ) K_Resize( k, t, tFarthest, dRadius ); return ( (long)tFarthest.size( ) ); } // end KFar //======================================================================= // long LeftK_Near ( const DistanceTypeNode dRadius, // std::vector >& tClosest, // const TNode& t, const std::vector& objectStore ) const // long LeftK_Near ( const DistanceTypeNode dRadius, // std::vector >& tClosest, // const TNode& t, const std::vector& objectStore ) const // // Private function to search a NearTree for the objects inside of the specified radius // from the probe point // This function is only called by LeftFindK_Nearest. // // k: the maximum number of object to return, giving preference to the nearest // dRadius: the search radius, which will be updated when the internal store is resized // tClosest: is a vector of pairs of Nodes and objects or of triples // of Nodes, objects and ordinals of objects where the objects // are of the templated type found within dRadius of the // probe point, limited by the k-near search // t: is the probe point // objectStore: the internal vector storing the object in CNearTree // // returns the number of objects returned in the container (for sets, that may not equal the number found) // /*=======================================================================*/ long LeftK_Near ( const size_t k, DistanceTypeNode& dRadius, std::vector >& tClosest, const TNode& t, const std::vector& objectStore #ifdef CNEARTREE_INSTRUMENTED , size_t& VisitCount #endif ) { std::vector sStack; enum { left, right, end } eDir; eDir = left; // examine the left nodes first NearTreeNode* pt = const_cast(this); #ifdef CNEARTREE_INSTRUMENTED ++VisitCount; #endif if (pt->m_ptLeft == ULONG_MAX) return false; // test for empty while ( ! ( eDir == end && sStack.empty( ) ) ) { if ( eDir == right ) { const DistanceTypeNode dDR = DistanceBetween( t, objectStore[pt->m_ptRight] ); if ( dDR <= dRadius ) { tClosest.insert( tClosest.end(), std::make_pair( dDR, objectStore[pt->m_ptRight] ) ); if( tClosest.size( ) > 2*k ) K_Resize( k, t, tClosest, dRadius ); } if ( pt->m_pRightBranch != 0 && TRIANG(dDR,pt->m_dMaxRight,dRadius) ) { // we did the left and now we finished the right, go down pt = pt->m_pRightBranch; #ifdef CNEARTREE_INSTRUMENTED ++VisitCount; #endif eDir = left; } else { eDir = end; } } if ( eDir == left ) { const DistanceTypeNode dDL = DistanceBetween( t, objectStore[pt->m_ptLeft] ); if ( dDL <= dRadius ) { tClosest.insert( tClosest.end(), std::make_pair( dDL, objectStore[pt->m_ptLeft] ) ); if( tClosest.size( ) > 2*k ) K_Resize( k, t, tClosest, dRadius ); } if ( pt->m_ptRight != ULONG_MAX ) // only stack if there's a right object { sStack.push_back( pt ); } if ( pt->m_pLeftBranch != 0 && TRIANG(dDL,pt->m_dMaxLeft,dRadius) ) { // we did the left, go down pt = pt->m_pLeftBranch; #ifdef CNEARTREE_INSTRUMENTED ++VisitCount; #endif } else { eDir = end; } } if ( eDir == end && !sStack.empty( ) ) { pt = sStack.back( ); #ifdef CNEARTREE_INSTRUMENTED ++VisitCount; #endif sStack.pop_back( ); eDir = right; } } if( tClosest.size( ) > k ) K_Resize( k, t, tClosest, dRadius ); return ( (long)tClosest.size( ) ); } // end LeftK_Near long LeftK_Near ( const size_t k, DistanceTypeNode& dRadius, std::vector >& tClosest, const TNode& t, const std::vector& objectStore #ifdef CNEARTREE_INSTRUMENTED , size_t& VisitCount #endif ) { std::vector sStack; enum { left, right, end } eDir; eDir = left; // examine the left nodes first NearTreeNode* pt = const_cast(this); #ifdef CNEARTREE_INSTRUMENTED ++VisitCount; #endif if (pt->m_ptLeft == ULONG_MAX) return false; // test for empty while ( ! ( eDir == end && sStack.empty( ) ) ) { if ( eDir == right ) { const DistanceTypeNode dDR = DistanceBetween( t, objectStore[pt->m_ptRight] ); if ( dDR <= dRadius ) { tClosest.insert( tClosest.end(), make_triple( dDR, objectStore[pt->m_ptRight], pt->m_ptRight ) ); if( tClosest.size( ) > 2*k ) K_Resize( k, t, tClosest, dRadius ); } if ( pt->m_pRightBranch != 0 && TRIANG(dDR,pt->m_dMaxRight,dRadius) ) { // we did the left and now we finished the right, go down pt = pt->m_pRightBranch; #ifdef CNEARTREE_INSTRUMENTED ++VisitCount; #endif eDir = left; } else { eDir = end; } } if ( eDir == left ) { const DistanceTypeNode dDL = DistanceBetween( t, objectStore[pt->m_ptLeft] ); if ( dDL <= dRadius ) { tClosest.insert( tClosest.end(), make_triple( dDL, objectStore[pt->m_ptLeft], pt->m_ptLeft ) ); if( tClosest.size( ) > 2*k ) K_Resize( k, t, tClosest, dRadius ); } if ( pt->m_ptRight != ULONG_MAX ) // only stack if there's a right object { sStack.push_back( pt ); } if ( pt->m_pLeftBranch != 0 && TRIANG(dDL,pt->m_dMaxLeft,dRadius) ) { // we did the left, go down pt = pt->m_pLeftBranch; #ifdef CNEARTREE_INSTRUMENTED ++VisitCount; #endif } else { eDir = end; } } if ( eDir == end && !sStack.empty( ) ) { pt = sStack.back( ); #ifdef CNEARTREE_INSTRUMENTED ++VisitCount; #endif sStack.pop_back( ); eDir = right; } } if( tClosest.size( ) > 1 ) K_Resize( k, t, tClosest, dRadius ); return ( (long)tClosest.size( ) ); } // end LeftK_Near //======================================================================= // long LeftK_Far ( const DistanceTypeNode dRadius, std::vector >& tFarthest, const TNode& t ) const // long LeftK_Far ( const DistanceTypeNode dRadius, std::vector >& tFarthest, tFarthest, const TNode& t ) const // // Private function to search a NearTree for the objects inside of the specified radius // from the probe point. Distances are stored in an intermediate array as negative values // so that the same logic as K_Near can be used. // This function is only called by LeftFindK_Farthest. // // k: the maximum number of object to return, giving preference to the nearest // dRadius: the search radius, which will be updated when the internal store is resized // tFarthest: is a vector of pairs of Nodes and objects or of triples // of Nodes, objects and ordinals of objects where the objects // are of the templated type found outside of dRadius of the // probe point, limited by the k-farthest search // t: is the probe point // objectStore: the internal vector storing the object in CNearTree // // returns the number of objects returned in the container (for sets, that may not equal the number found) // /*=======================================================================*/ long LeftK_Far ( const size_t k, DistanceTypeNode& dRadius, std::vector >& tFarthest, const TNode& t, const std::vector& objectStore #ifdef CNEARTREE_INSTRUMENTED , size_t& VisitCount #endif ) { std::vector sStack; enum { left, right, end } eDir; eDir = left; // examine the left nodes first NearTreeNode* pt = const_cast(this); #ifdef CNEARTREE_INSTRUMENTED ++VisitCount; #endif if (pt->m_ptLeft == ULONG_MAX) return false; // test for empty while ( ! ( eDir == end && sStack.empty( ) ) ) { if ( eDir == right ) { const DistanceTypeNode dDR = DistanceBetween( t, objectStore[pt->m_ptRight] ); if ( dDR >= dRadius ) { tFarthest.insert( tFarthest.end(), std::make_pair( -dDR, objectStore[pt->m_ptRight] ) ); if( tFarthest.size( ) > 2*k ) K_Resize( k, t, tFarthest, dRadius ); } if ( pt->m_pRightBranch != 0 && TRIANG(dRadius,dDR,pt->m_dMaxRight) ) { // we did the left and now we finished the right, go down pt = pt->m_pRightBranch; #ifdef CNEARTREE_INSTRUMENTED ++VisitCount; #endif eDir = left; } else { eDir = end; } } if ( eDir == left ) { const DistanceTypeNode dDL = DistanceBetween( t, objectStore[pt->m_ptLeft] ); if ( dDL >= dRadius ) { tFarthest.insert( tFarthest.end(), std::make_pair( -dDL, objectStore[pt->m_ptLeft] ) ); if( tFarthest.size( ) > 2*k ) K_Resize( k, t, tFarthest, dRadius ); } if ( pt->m_ptRight != ULONG_MAX ) // only stack if there's a right object { sStack.push_back( pt ); } if ( pt->m_pLeftBranch != 0 && TRIANG(dRadius,dDL,pt->m_dMaxLeft) ) { // we did the left, go down pt = pt->m_pLeftBranch; #ifdef CNEARTREE_INSTRUMENTED ++VisitCount; #endif } else { eDir = end; } } if ( eDir == end && !sStack.empty( ) ) { pt = sStack.back( ); #ifdef CNEARTREE_INSTRUMENTED ++VisitCount; #endif sStack.pop_back( ); eDir = right; } } if( tFarthest.size( ) > 1 ) K_Resize( k, t, tFarthest, dRadius ); return ( (long)tFarthest.size( ) ); } // end K_Far long LeftK_Far ( const size_t k, DistanceTypeNode& dRadius, std::vector >& tFarthest, const TNode& t, const std::vector& objectStore #ifdef CNEARTREE_INSTRUMENTED , size_t& VisitCount #endif ) { std::vector sStack; enum { left, right, end } eDir; eDir = left; // examine the left nodes first NearTreeNode* pt = const_cast(this); #ifdef CNEARTREE_INSTRUMENTED ++VisitCount; #endif if (pt->m_ptLeft == ULONG_MAX) return false; // test for empty while ( ! ( eDir == end && sStack.empty( ) ) ) { if ( eDir == right ) { const DistanceTypeNode dDR = DistanceBetween( t, objectStore[pt->m_ptRight] ); if ( dDR >= dRadius ) { tFarthest.insert( tFarthest.end(), make_triple( -dDR, objectStore[pt->m_ptRight], pt->m_pt_Right ) ); if( tFarthest.size( ) > 2*k ) K_Resize( k, t, tFarthest, dRadius ); } if ( pt->m_pRightBranch != 0 && TRIANG(dRadius,dDR,pt->m_dMaxRight) ) { // we did the left and now we finished the right, go down pt = pt->m_pRightBranch; #ifdef CNEARTREE_INSTRUMENTED ++VisitCount; #endif eDir = left; } else { eDir = end; } } if ( eDir == left ) { const DistanceTypeNode dDL = DistanceBetween( t, objectStore[pt->m_ptLeft] ); if ( dDL >= dRadius ) { tFarthest.insert( tFarthest.end(), make_triple( -dDL, objectStore[pt->m_ptLeft], pt->m_ptLeft) ); if( tFarthest.size( ) > 2*k ) K_Resize( k, t, tFarthest, dRadius ); } if ( pt->m_ptRight != ULONG_MAX ) // only stack if there's a right object { sStack.push_back( pt ); } if ( pt->m_pLeftBranch != 0 && TRIANG(dRadius,dDL,pt->m_dMaxLeft) ) { // we did the left, go down pt = pt->m_pLeftBranch; #ifdef CNEARTREE_INSTRUMENTED ++VisitCount; #endif } else { eDir = end; } } if ( eDir == end && !sStack.empty( ) ) { pt = sStack.back( ); #ifdef CNEARTREE_INSTRUMENTED ++VisitCount; #endif sStack.pop_back( ); eDir = right; } } if( tFarthest.size( ) > 1 ) K_Resize( k, t, tFarthest, dRadius ); return ( (long)tFarthest.size( ) ); } // end LeftK_Far //======================================================================= // static bool K_Sorter2( const std::pair& t1, const std::pair& t2 ) // static bool K_Sorter3( const triple& t1, const std::pair& t2 ) // // Private static function used to sort the K-near/far internal data stores. This // replaces the default less<>, which doesn't necessarily exist for all objects. // All this does is compare the distances, so only the .first element needs // to be examined. // //======================================================================= static bool K_Sorter2( const std::pair& t1, const std::pair& t2 ) { return ( t1.first < t2.first ); } static bool K_Sorter3( const triple& t1, const triple& t2 ) { return ( t1.GetFirst() < t2.GetFirst() ); } //======================================================================= // void K_Resize ( const size_t k, const TNode& t, std::vector >& tClosest, DistanceTypeNode& dRadius ) const // void K_Resize ( const size_t k, const TNode& t, std::vector >& tClosest, DistanceTypeNode& dRadius ) const // // Private function to limit the size of internally stored data for K-nearest/farthest-neighbor searches // This function is only called by K_Near and K_Far. // // dRadius is the search radius, updated to the best-known value // tClosest is a vector of pairs of Nodes and objects or of triples // of Nodes, objects and ordinals of objects where the objects // are of the templated type found within dRadius of the // probe point // t is the probe point // //======================================================================= void K_Resize( const size_t k, const TNode& t, std::vector >& tClosest, DistanceTypeNode& dRadius ) { size_t target = tClosest.size(); if (target > k ) target = k; std::sort( tClosest.begin(), tClosest.end(), &K_Sorter2 ); tClosest.resize( target ); dRadius = DistanceBetween( t, tClosest[tClosest.size()-1].second ); } // end K_Resize void K_Resize( const size_t k, const TNode& t, std::vector >& tClosest, DistanceTypeNode& dRadius ) { size_t target = tClosest.size(); if (target > k ) target = k; std::sort( tClosest.begin(), tClosest.end(), &K_Sorter3 ); tClosest.resize( target ); dRadius = DistanceBetween( t, tClosest[tClosest.size()-1].GetSecond() ); } // end K_Resize }; // end NearTreeNode //======================================================================= //======================================================================= //======================================================================= //======================================================================= //======================================================================= //======================================================================= //======================================================================= //======================================================================= //======================================================================= //======================================================================= //======================================================================= //======================================================================= //======================================================================= // end NearTreeNode nested class in CNearTree //======================================================================= // start of iterator, a nested class in CNearTree //======================================================================= //======================================================================= //======================================================================= //======================================================================= //======================================================================= //======================================================================= //======================================================================= //======================================================================= //======================================================================= //======================================================================= //======================================================================= //======================================================================= //======================================================================= //======================================================================= //======================================================================= //==================================================================================== // class iterator // // nested class within CNearTree //==================================================================================== public: class iterator : public std::iterator< std::random_access_iterator_tag, T, int, T*, T& > { public: friend class CNearTree< T, DistanceType, distMinValue >; private: long position; const CNearTree< T, DistanceType, distMinValue >* parent; public: iterator( void ) { }; // constructor explicit iterator( const const_iterator& s ) { position = ((const_iterator)s).get_position(); parent = ((const_iterator)s).get_parent(); };// constructor iterator& operator= ( const iterator& s ) { position = s.position; parent = s.parent; return ( *this ); }; iterator& operator= ( const const_iterator& s ) { position = ((const_iterator&)s).get_position(); parent = ((const_iterator&)s).get_parent(); return ( *this ); }; iterator operator++ ( const int n ) { iterator it(*this); position+=1+n; return ( it ); }; iterator operator-- ( const int n ) { iterator it(*this); position-=1+n; return ( it ); }; iterator& operator++ ( void ) { ++position; return ( *this ); }; iterator& operator-- ( void ) { --position; return ( *this ); }; iterator operator+ ( const long n ) const { iterator it( position+n, parent); return ( it ); }; iterator operator- ( const long n ) const { iterator it( position-n, parent); return ( it ); }; iterator& operator+= ( const long n ) { position += n; return ( *this ); }; iterator& operator-= ( const long n ) { position -= n; return ( *this ); }; T operator* ( void ) const { return ( parent->m_ObjectStore[position] ); }; bool operator== ( const iterator& t ) const { return ( t.position==(parent->m_ObjectStore.empty( )?1:position) && t.parent==parent ); }; bool operator!= ( const iterator& t ) const { return ( ! (*this==t )); }; bool operator== ( const const_iterator& t ) const { return ( ((const_iterator&)t).get_position()==(parent->m_ObjectStore.empty( )?1:position) && ((const_iterator&)t).get_parent()==parent ); }; bool operator!= ( const const_iterator& t ) const { return ( ! (*this==t )); }; bool operator> ( const iterator& t ) const { return ( (*this).get_position()>t.get_position() ); }; bool operator> ( const const_iterator& t ) const { return ( (*this).get_position()>t.get_position() ); }; bool operator< ( const iterator& t ) const { return ( (*this).get_position() ( void ) const { return ( &(const_cast(parent)->m_ObjectStore[position]) ); }; long get_position( void ) const {return position;}; const CNearTree< T, DistanceType, distMinValue >* get_parent( void ) {return parent;}; private: iterator ( const long s, const CNearTree* const nt ) { position = s; parent = nt; }; // constructor }; // class iterator //==================================================================================== // end of nested class "iterator" //==================================================================================== class const_iterator : public std::iterator< std::random_access_iterator_tag, T, int, T*, T& > { public: friend class CNearTree< T, DistanceType, distMinValue >; private: long position; const CNearTree< T, DistanceType, distMinValue >* parent; public: const_iterator( void ) { }; // constructor explicit const_iterator( const iterator& s ) { position = ((iterator)s).get_position(); parent = ((iterator)s).get_parent(); }; // constructor const_iterator& operator= ( const const_iterator& s ) { position = s.position; parent = s.parent; return ( *this ); }; const_iterator& operator= ( const iterator& s ) { position = ((iterator &)s).get_position(); parent = ((iterator &)s).get_parent(); return ( *this ); }; const_iterator operator++ ( const int n ) { const_iterator it(*this); position+=1+n; return ( it ); }; const_iterator operator-- ( const int n ) { const_iterator it(*this); position-=1+n; return ( it ); }; const_iterator& operator++ ( void ) { ++position; return ( *this ); }; const_iterator& operator-- ( void ) { --position; return ( *this ); }; const_iterator operator+ ( const long n ) const { const_iterator it( position+n, parent); return ( it ); }; const_iterator operator- ( const long n ) const { const_iterator it( position-n, parent); return ( it ); }; const_iterator& operator+= ( const long n ) { position += n; return ( *this ); }; const_iterator& operator-= ( const long n ) { position -= n; return ( *this ); }; T operator* ( void ) const { return ( parent->m_ObjectStore[position] ); }; bool operator== ( const const_iterator& t ) const { return ( t.position==(parent->m_ObjectStore.empty( )?1:position) && t.parent==parent ); }; bool operator!= ( const const_iterator& t ) const { return ( ! (*this==t )); }; bool operator== ( const iterator& t ) const { return ( ((iterator &)t).get_position()==(parent->m_ObjectStore.empty( )?1:position) && ((iterator &)t).get_parent()==parent ); }; bool operator!= ( const iterator& t ) const { return ( ! (*this==t )); }; bool operator> ( const iterator& t ) const { return ( (*this).get_position()>t.get_position() ); }; bool operator> ( const const_iterator& t ) const { return ( (*this).get_position()>t.get_position() ); }; bool operator< ( const iterator& t ) const { return ( (*this).get_position() ( void ) const { return ( &(const_cast(parent)->m_ObjectStore[position]) ); }; long get_position ( void ) const {return position;}; const CNearTree< T, DistanceType, distMinValue >* get_parent( void ) {return parent;}; private: const_iterator ( const long s, const CNearTree* nt ) { position = s; parent = nt; }; // constructor }; // end class const_iterator //==================================================================================== // end of nested class "const_iterator" //==================================================================================== }; // template class CNearTree #endif // !defined(TNEAR_H_INCLUDED) ./NearTree-3.1.1/CMain_MINGW_orig.lst0000644002342100234170000000557411640401607017132 0ustar bernstehfaculty Trial 0 from probe point [1.82104, 1.82104, 9.76844] Closest distance 0.343036 to [2, 2, 10] Farthest distance 15.8035 to [10, 10, -1] Returned 1 items within 0.65 of [1.82104,1.82104,9.76844] [2,2,10] ------------------------------------------------------------- Trial 1 from probe point [9.11527, 9.11527, -1.1729] Closest distance 0.237632 to [9, 9, -1] Farthest distance 18.1513 to [-1, -1, 10] Returned 1 items within 0.7 of [9.11527,9.11527,-1.1729] [9,9,-1] ------------------------------------------------------------- Trial 2 from probe point [8.72188, 8.72188, -0.582827] Closest distance 0.573349 to [9, 9, -1] Farthest distance 17.3501 to [-1, -1, 10] Returned 2 items within 0.75 of [8.72188,8.72188,-0.582827] [9,9,-1] [9,9,0] ------------------------------------------------------------- Trial 3 from probe point [0.126652, 0.126652, 12.31] ***** nothing within 0.8 of [0.126652, 0.126652, 12.31] Farthest distance 19.2905 to [10, 10, -1] ------------------------------------------------------------- Trial 4 from probe point [5.38713, 5.38713, 4.41931] Closest distance 0.689605 to [5, 5, 4] Farthest distance 10.6177 to [-1, -1, 10] Returned 4 items within 0.85 of [5.38713,5.38713,4.41931] [5,5,4] [5,5,5] [5,6,4] [6,5,4] ------------------------------------------------------------- Trial 5 from probe point [7.70684, 7.70684, 0.939741] Closest distance 0.418948 to [8, 8, 1] Farthest distance 15.2875 to [-1, -1, 10] Returned 3 items within 0.9 of [7.70684,7.70684,0.939741] [8,8,1] [8,7,1] [7,8,1] ------------------------------------------------------------- Trial 6 from probe point [2.17292, 2.17292, 9.24062] Closest distance 0.343075 to [2, 2, 9] Farthest distance 15.0797 to [10, 10, -1] Returned 4 items within 0.95 of [2.17292,2.17292,9.24062] [2,2,9] [2,2,10] [2,3,9] [3,2,9] ------------------------------------------------------------- Trial 7 from probe point [8.45454, 8.45454, -0.181814] Closest distance 0.668038 to [8, 8, 0] Farthest distance 16.8061 to [-1, -1, 10] Returned 4 items within 1 of [8.45454,8.45454,-0.181814] [8,8,0] [8,9,0] [9,8,0] [9,9,0] ------------------------------------------------------------- Trial 8 from probe point [9.45402, 9.45402, -1.68104] Closest distance 0.935994 to [9, 9, -1] Farthest distance 18.842 to [-1, -1, 10] Returned 4 items within 1.05 of [9.45402,9.45402,-1.68104] [9,9,-1] [9,10,-1] [10,9,-1] [10,10,-1] ------------------------------------------------------------- Trial 9 from probe point [2.69814, 2.69814, 8.45279] Closest distance 0.622297 to [3, 3, 8] Farthest distance 13.9996 to [10, 10, -1] Returned 7 items within 1.1 of [2.69814,2.69814,8.45279] [3,3,8] [3,3,9] [2,3,8] [3,2,8] [2,3,9] [3,2,9] [2,2,8] ------------------------------------------------------------- ./NearTree-3.1.1/CPPMain_MINGW_orig.lst0000644002342100234170000000544211640401607017364 0ustar bernstehfaculty Trial 0 from probe point {1.82104,1.82104,9.76844} Closest distance 0.343036 to {2,2,10} Farthest distance 15.8035 to {10,10,-1} Returned 1 items within 0.65 of {1.82104,1.82104,9.76844} {2,2,10} ------------------------------------------------------------- Trial 1 from probe point {9.11527,9.11527,-1.1729} Closest distance 0.237632 to {9,9,-1} Farthest distance 18.1513 to {-1,-1,10} Returned 1 items within 0.7 of {9.11527,9.11527,-1.1729} {9,9,-1} ------------------------------------------------------------- Trial 2 from probe point {8.72188,8.72188,-0.582827} Closest distance 0.573349 to {9,9,-1} Farthest distance 17.3501 to {-1,-1,10} Returned 2 items within 0.75 of {8.72188,8.72188,-0.582827} {9,9,-1} {9,9,0} ------------------------------------------------------------- Trial 3 from probe point {0.126652,0.126652,12.31} ***** nothing within 0.8 of {0.126652,0.126652,12.31} Farthest distance 19.2905 to {10,10,-1} ------------------------------------------------------------- Trial 4 from probe point {5.38713,5.38713,4.41931} Closest distance 0.689605 to {5,5,4} Farthest distance 10.6177 to {-1,-1,10} Returned 4 items within 0.85 of {5.38713,5.38713,4.41931} {5,5,4} {5,5,5} {5,6,4} {6,5,4} ------------------------------------------------------------- Trial 5 from probe point {7.70684,7.70684,0.939741} Closest distance 0.418948 to {8,8,1} Farthest distance 15.2875 to {-1,-1,10} Returned 3 items within 0.9 of {7.70684,7.70684,0.939741} {7,8,1} {8,7,1} {8,8,1} ------------------------------------------------------------- Trial 6 from probe point {2.17292,2.17292,9.24062} Closest distance 0.343075 to {2,2,9} Farthest distance 15.0797 to {10,10,-1} Returned 4 items within 0.95 of {2.17292,2.17292,9.24062} {2,2,9} {2,2,10} {2,3,9} {3,2,9} ------------------------------------------------------------- Trial 7 from probe point {8.45454,8.45454,-0.181814} Closest distance 0.668038 to {8,8,0} Farthest distance 16.8061 to {-1,-1,10} Returned 4 items within 1 of {8.45454,8.45454,-0.181814} {8,8,0} {8,9,0} {9,8,0} {9,9,0} ------------------------------------------------------------- Trial 8 from probe point {9.45402,9.45402,-1.68104} Closest distance 0.935994 to {9,9,-1} Farthest distance 18.842 to {-1,-1,10} Returned 4 items within 1.05 of {9.45402,9.45402,-1.68104} {9,9,-1} {9,10,-1} {10,9,-1} {10,10,-1} ------------------------------------------------------------- Trial 9 from probe point {2.69814,2.69814,8.45279} Closest distance 0.622297 to {3,3,8} Farthest distance 13.9996 to {10,10,-1} Returned 7 items within 1.1 of {2.69814,2.69814,8.45279} {2,2,8} {2,3,8} {2,3,9} {3,2,8} {3,2,9} {3,3,8} {3,3,9} ------------------------------------------------------------- ./NearTree-3.1.1/CNearTreeTest.cpp0000644002342100234170000040520311640401607016603 0ustar bernstehfaculty//* //* CNearTreeTest.cpp //* NearTree //* //* test harness for the templated neartree implementation, TNear.h //* Copyright 2008 Larry Andrews. All rights reserved //* //* Revised 29 November 2009, added SeparateByRadius and BelongsToPoint //* to be used for cluster analysis. //* BelongsToPoint simply runs thru all the //* because that is the fastest way //* Revised 30 May 2009, release with full containerization of C++ //* version and KNear/Far in C++ and C, LCA + HJB //* Revised 13 Nov 2010, revisions to C++ version for balanced //* searches, LCA+HJB //********************************************************************** //* * //* YOU MAY REDISTRIBUTE NearTree UNDER THE TERMS OF THE LGPL * //* * //**********************************************************************/ //************************* LGPL NOTICES ******************************* //* * //* This library is free software; you can redistribute it and/or * //* modify it under the terms of the GNU Lesser General Public * //* License as published by the Free Software Foundation; either * //* version 2.1 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 * //* Lesser General Public License for more details. * //* * //* You should have received a copy of the GNU Lesser General Public * //* License along with this library; if not, write to the Free * //* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, * //* MA 02110-1301 USA * //* * //**********************************************************************/ /* This is a test harness for the templated neartree implementation, CNearTree. */ #include #include #include #include #include #include #include #include #ifndef USE_LOCAL_HEADERS #include #include #else #include "TNear.h" #include "rhrand.h" #endif #include #include #include #include #define ABS(x) (((x)<0)?-(x):(x)) RHrand rhr; void testSeparation( void ); void testEmptyTree( void ); void testLinearTree( const int n ); void testFindFirstObject( void ); void testFindLastObject( void ); void testFindInSphereFromBottom( void ); void testBackwardForward( void ); void testFindInSphereFromTop( void ); void testOutSphere( void ); void testDelayedInsertion( void ); void testDelayedInsertionRandom( void ); void testIterators( void ); void testFindInAnnulus( void ); void testMisc( void ); void testRandomTree1( const int n ); void testRandomTree2( const int n ); void testBigVector( void ); void testIntegerReturn( void ); void testBigIntVec( void ); void testSTLContainerInput( void ); void testKNearFar( void ); void testMergeConstructor( void ); void testOperatorPlusEquals( void ); void testOperatorMinusEquals( void ); void testSetSymmetricDifference( void ); void testCentroid( void ); void testLloyd( void ); //std::vector LloydCycleStep( const CNearTree& coord, const std::vector& vIn ); long g_errorCount; int debug; #define timecommand(idstring,command) \ { \ clock_t tc1 = std::clock();\ {command} \ clock_t tc2 = std::clock();\ fprintf( stdout, "%s time %f \n", idstring, ((double)(tc2-tc1))/CLOCKS_PER_SEC); \ } #ifndef CNEARTREE_INSTRUMENTED #define timetreecommand(tree,idstring,command) \ timecommand(idstring,command) #else #define timetreecommand(tree,idstring,command) \ { \ size_t nv1 = tree.GetNodeVisits(); \ clock_t tc1 = std::clock();\ {command} \ clock_t tc2 = std::clock();\ size_t nv2 = tree.GetNodeVisits(); \ fprintf( stdout, "%s time %f, visits %ld \n", idstring, ((double)(tc2-tc1))/CLOCKS_PER_SEC, (long)(nv2-nv1)); \ } #endif /*=======================================================================*/ int main(int argc, char* argv[]) { g_errorCount = 0; debug = 0; if (argc > 1 && !strcmp(argv[1],"--debug")) debug = 1; /* test the interface with an empty tree */ testEmptyTree( ); fprintf( stdout, "testEmptyTree\n" ); /* test the interface with trees with varying content, one entry and several */ for( int i=1; i<10; ++i ) { char tagstring[40]; sprintf(tagstring,"testLinearTree %d",i); testLinearTree( i ); } timecommand("testSeparation",{testSeparation( );}); timecommand("testFindFirstObject",{testFindFirstObject( );}); timecommand("testFindLastObject",{testFindLastObject( );}); testFindInSphereFromBottom( ); fprintf( stdout, "testFindInSphereFromBottom\n" ); testFindInSphereFromTop( ); fprintf( stdout, "testFindInSphereFromTop\n" ); testOutSphere( ); fprintf( stdout, "testOutSphere\n" ); testFindInAnnulus( ); fprintf( stdout, "testFindInAnnulus\n" ); testRandomTree1( 10000 ); fprintf( stdout, "testRandomTree1\n" ); testRandomTree2( 1000 ); fprintf( stdout, "testRandomTree2\n" ); testBigVector( ); fprintf( stdout, "testBigVector\n" ); testBigIntVec( ); fprintf( stdout, "testBigIntVec\n" ); testBackwardForward( ); fprintf( stdout, "testBackwardForward\n" ); testDelayedInsertion( ); fprintf( stdout, "testDelayedInsertion\n" ); #ifndef CNEARTREE_NODEFER testDelayedInsertionRandom( ); fprintf( stdout, "CompleteDelayedInsertRandom\n" ); #endif testIterators( ); fprintf( stdout, "testIterators\n" ); testIntegerReturn( ); fprintf( stdout, "testIntegerReturn\n" ); testMisc( ); fprintf( stdout, "testMisc\n" ); testSTLContainerInput( ); fprintf( stdout, "testSTLContainerInput\n" ); testKNearFar( ); fprintf( stdout, "testKNearFar\n" ); timecommand("testMergeConstructor",{testMergeConstructor( );}); timecommand("testOperatorPlusEquals",{testOperatorPlusEquals( );}); timecommand("testOperatorMinusEquals",{testOperatorMinusEquals( );}); timecommand("testSetSymmetricDifference",{testSetSymmetricDifference( );}); timecommand("testCentroid",{testCentroid( );}); timecommand("testLloyd",{testLloyd( );}); if( g_errorCount == 0 ) { fprintf(stdout, "No errors were detected while testing CNearTree\n" ); } else { fprintf(stdout, "%ld Errors were detected while testing CNearTree\n", g_errorCount ); } return g_errorCount; } // end main /* For an empty tree of int's, test the public interface for CNearTree. */ /*=======================================================================*/ void testEmptyTree( void ) { CNearTree tree; int close; int nFar; std::vector v; bool bTreeEmpty; bool bTreeHasNearest; bool bTreeHasFarthest; long lFoundPointsInSphere; long myflags = tree.GetFlags(); if ((myflags&CNearTree::NTF_NoPrePrune)) fprintf(stdout, "Flag NTF_NoPrePrune set \n"); if ((myflags&CNearTree::NTF_ForcePrePrune)) fprintf(stdout, "Flag NTF_ForcePrePrune set \n"); if ((myflags&CNearTree::NTF_NoFlip)) fprintf(stdout, "Flag NTF_NoFlip set \n"); if ((myflags&CNearTree::NTF_ForceFlip)) fprintf(stdout, "Flag NTF_ForceFlip set \n"); if ((myflags&CNearTree::NTF_NoDefer)) fprintf(stdout, "Flag NTF_NoDefer set \n"); bTreeEmpty = tree.empty( ); if( ! bTreeEmpty ) { ++g_errorCount; fprintf(stdout, "testEmptyTree: ..empty incorrect for empty tree\n" ); } if( tree.size( ) != 0 ) { ++g_errorCount; fprintf(stdout, "testEmptyTree: .size incorrect for empty tree\n" ); } bTreeHasNearest = tree.NearestNeighbor( 0.0, close, 1 ); if( bTreeHasNearest ) { ++g_errorCount; fprintf(stdout, "testEmptyTree: .NearestNeighbor incorrect for empty tree\n" ); } bTreeHasFarthest = tree.FarthestNeighbor( nFar, 0 ); if( bTreeHasFarthest ) { ++g_errorCount; fprintf(stdout, "testEmptyTree: .FarthestNeighbor incorrect for empty tree\n" ); } CNearTree ntReturn; lFoundPointsInSphere = tree.FindInSphere( 1000.0, ntReturn, 1 ); if( lFoundPointsInSphere != 0 ) { ++g_errorCount; fprintf(stdout, "testEmptyTree: .FindInSphere incorrect for empty tree\n" ); } tree.clear( ); } // end testEmptyTree /* Test CNearTree using a tree built only using int's. This is not a robust test in some ways because the tree is only composed of right branches and left leaves. Perform some general tests. */ /*=======================================================================*/ void testLinearTree( const int n ) { CNearTree tree; /* generate an unbalanced tree*/ for( int i1=1; i1<=n; ++i1 ) { tree.insert( i1 ); } if( tree.GetDepth( ) > (size_t)(n+1)/2 ) { ++g_errorCount; fprintf(stdout, "testLinearTree: tree depth is too large, %lu is greater than %d\n", (unsigned long)tree.GetDepth( ), (n+1)/2 ); } #ifdef CNEARTREE_INSTRUMENTED if( tree.GetHeight( ) != tree.GetDepth( ) ) { ++g_errorCount; fprintf(stdout, "testLinearTree: tree depth != tree height, %lu != %lu\n", (unsigned long)tree.GetDepth( ), (unsigned long)tree.GetHeight( ) ); } #endif size_t estdim = (size_t)(0.5+tree.GetDimEstimate()); if (n < 129 && estdim != 0) { ++g_errorCount; fprintf(stdout, "testLinearTree: dimension estimate %ld\n",(long)estdim); } /* Search for the nearest value using a probe point that is larger than the largest value that was input. The returned values should be the last value entered into the tree. */ int closest=-1; const bool bClose = tree.NearestNeighbor( 22.0, closest, 2*n ); if( ! bClose ) { ++g_errorCount; fprintf(stdout, "testLinearTree: NearestNeighbor failed to find anything\n" ); } else if( closest != n ) { ++g_errorCount; fprintf(stdout, "NearestNeighbor failed in testLinearTree, got %d, should be %d\n", closest, n ); } /* Search for the farthest value using a probe point that is larger than the largest value that was input. The returned values should be the first value entered into the tree. */ int farthest; const bool bFar = tree.FarthestNeighbor( farthest, 2*n ); if( ! bFar ) { ++g_errorCount; fprintf(stdout, "testLinearTree: FarthestNeighbor failed to find anything\n" ); } else if( farthest != 1 ) { ++g_errorCount; fprintf(stdout, "FarthestNeighbor failed in testLinearTree, got %d, should be %d\n", farthest, n ); } /* Find all of the points in the tree using a negative radius, using the first input point as the probe point. Nothing should be found. */ CNearTree ntReturn; const long lFoundPointsInSphere = tree.FindInSphere( -100.0, ntReturn, 1 ); if( lFoundPointsInSphere != 0 ) { ++g_errorCount; fprintf(stdout, "FindInSphere found points for negative radius\n" ); } /* Find all of the points in the tree using a small radius. Do separate searches for every point entered. In every case, only a single point should be found. */ long localErrorCount = 0; long localErrorMax = 0; for( int i=1; i<=n; ++i ) { ntReturn.clear( ); const long found = tree.FindInSphere( 0.1, ntReturn, 1 ); if( found != 1 ) { ++localErrorCount; if( found > localErrorMax ) { localErrorMax = found; } } } if( localErrorCount != 0 ) { ++g_errorCount; fprintf(stdout, "FindInSphere found too many points (as many as %ld) %ld times\n", localErrorMax, localErrorCount ); } /* Find all of the points in the tree that are within a large radius, using the first input point as the probe point. All of the input points should be found within the radius. */ if( tree.FindInSphere( (double)(10*n), ntReturn, 0 ) != n ) { ++g_errorCount; fprintf(stdout, "FindInSphere did not find all the points, found %ld\n", tree.FindInSphere( (double)(10*n), ntReturn, 0 ) ); } /* test operator[ ] */ for( size_t i=1; i<=(size_t)n; ++i ) { if( i != (size_t)tree[i-1] ) { ++g_errorCount; fprintf(stdout, "testLinearTree: found tree[i]!=i for tree[i-1]=%d, i=%ld\n", tree[i-1], (long)i ); } } tree.clear( ); } // end testLinearTree /* Perform general tests using floating point numbers. Two test sets are included, one for float and one for double. The values are computed starting from some initial value, and each succeeding value is one half of the previous until "zero" is computed (the zero is NOT inserted into the tree). The tree will consist of only right branches and left leaves. Experience showed that differing implementations of behaviors for denormalized floating point numbers causes problems both with the tests and with the building of the tree. So FLT_MIN and DBL_MIN have replaced zero as the lower bounds. */ /*=======================================================================*/ void testFindFirstObject( void ) { { double fFinal = FLT_MAX; /* just initialization */ CNearTree tree; long count = 0; /* build the float tree starting with 1.0 */ const float fInitial = 1.0; float f = fInitial; while( f > fInitial*FLT_EPSILON ) { tree.insert( f ); fFinal = f; f /= 2.0; ++count; } if( tree.empty( ) ) { ++g_errorCount; fprintf(stdout, "testFindFirstObject incorrectly found empty tree for float\n" ); } // /* // Search for the value closest to zero. It should be a very small, probably // denormalized number. // */ float closest = 0.0; const bool bReturnNear = tree.NearestNeighbor( 1.5*fFinal, closest, 0.0 ); if( ! bReturnNear ) { ++g_errorCount; fprintf(stdout, "testFindFirstObject: Near failed to find anything\n" ); } else if( ABS(closest - fFinal) > FLT_EPSILON ) { ++g_errorCount; fprintf(stdout, "testFindFirstObject: Near failed for float, got %f\n", closest ); } // /* // Search for the value farthest from a large number. It should be a // very small, probably denormalized number. // */ float farthest = -1000.0; const bool bReturnFar = tree.FarthestNeighbor( farthest, 100.0 ); if( ! bReturnFar ) { ++g_errorCount; fprintf(stdout, "testFindFirstObject Far failed to any anything for floatn" ); } else if( ABS(farthest - fFinal) > 100.*FLT_EPSILON ) { ++g_errorCount; fprintf(stdout, "testFindFirstObject Far failed for float, got %g\n", farthest ); } // /* // Determine if FindInSphere can find all of the input data. // */ CNearTree sphereReturn; const long lFound = tree.FindInSphere( 100.0, sphereReturn, 1.0 ); if( lFound != count ) { ++g_errorCount; fprintf(stdout, "testFindFirstObject: found wrong count for FindInSphere for float, should be%ld, got %ld\n", count, lFound ); } } { double dFinal = DBL_MAX; /* just initialization */ CNearTree tree; long count = 0; /* build the double tree starting with 1.0 */ const double dInitial = 1.0; double f = dInitial; /* generate an unbalanced tree*/ while( f > 0.0 && f >= dInitial*DBL_EPSILON ) { tree.insert( f ); dFinal = f; f /= 2.0; ++count; } if( tree.empty( ) ) { ++g_errorCount; fprintf(stdout, "testFindFirstObject incorrectly found empty tree for double\n" ); } /* Search for the value closest to zero. It should be a very small, probably denormalized number. */ double closest = 0.0; const bool bReturnNear = tree.NearestNeighbor( 1.0e-10, closest, 0.0 ); if( ! bReturnNear ) { ++g_errorCount; fprintf(stdout, "testFindFirstObject: Near failed to find anything\n" ); } else if( closest-dFinal != 0.0 ) { ++g_errorCount; fprintf(stdout, "testFindFirstObject: Near failed for double, got %f\n", closest ); } /* Search for the value farthest from a large number. It should be a very small, probably denormalized number. */ double farthest = 10000.0; const bool bReturn = tree.FarthestNeighbor( farthest, 100.0 ); if( ! bReturn ) { ++g_errorCount; fprintf(stdout, "testFindFirstObject: Far failed to find anything for double\n" ); } else if( ABS(farthest-dFinal) > 100.*DBL_EPSILON ) { ++g_errorCount; fprintf(stdout, "testFindFirstObject Far failed for double, got %g\n", farthest ); } /* Determine if FindInSphere can find all of the input data. */ CNearTree sphereReturn; const long lFound = tree.FindInSphere( 100.0, sphereReturn, 1.0 ); if( lFound != count ) { ++g_errorCount; fprintf(stdout, "testFindFirstObject: found wrong count for FindInSphere for double, should be%ld, got %ld\n", count, lFound ); } } } // end testFindFirstObject /* Perform general tests using floating point numbers. Build a tree of floats. The values are computed starting from some initial value, and each succeeding value is one half of the previous until "zero" is computed (the zero is NOT inserted into the tree). The tree will consist of only right branches and left leaves. Experience showed that differing implementations of behaviors for denormalized floating point numbers causes problems both with the tests and with the building of the tree. So FLT_MIN and DBL_MIN have replaced zero as the lower bounds. */ /*=======================================================================*/ void testFindLastObject( void ) { { CNearTree tree; float f = 1.0; /* generate an unbalanced tree*/ while( f > 0.0 && f >= FLT_MIN ) { tree.insert( f ); f /= 2.0; } float closest = 0.0; const bool bReturn = tree.NearestNeighbor( 100.0, closest, 11.0 ); if( ! bReturn ) { ++g_errorCount; fprintf(stdout, "testFindLastObject: Near failed to find anything\n" ); } else if( closest != 1.0 ) { ++g_errorCount; fprintf(stdout, "testFindLastObject: Near failed for float, got %g\n", closest ); } } { CNearTree tree; double f = 1.0; /* generate an unbalanced tree*/ while( f > 0.0 && f >= DBL_MIN) { tree.insert( f ); f /= 2.0; } double closest = 0.0; const bool bReturn = tree.NearestNeighbor( 100.0, closest, 11.0 ); if( ! bReturn ) { ++g_errorCount; fprintf(stdout, "testFindLastObject: Near failed to find anything\n" ); } else if( closest != 1.0 ) { ++g_errorCount; fprintf(stdout, "testFindLastObject: Near failed for float, got %g\n", closest ); } } { CNearTree tree; float f = 1.0; /* generate an unbalanced tree*/ while( f > 0.0 && f >= FLT_MIN) { tree.insert( f ); f /= 2.0; } float closest = 0.0; const float search = -11.0; const bool bReturn = tree.FarthestNeighbor( closest, search ); if( ! bReturn ) { ++g_errorCount; fprintf(stdout, "testFindLastObject: Far failed to find anything\n" ); } else if( closest != 1.0 ) { ++g_errorCount; fprintf(stdout, "testFindLastObject: Far failed for float, got %f\n", closest ); } } { CNearTree tree; double f = 1.0; /* generate an unbalanced tree*/ while( f > 0.0 && f >= DBL_MIN) { tree.insert( f ); f /= 2.0; } double closest = 0.0; const bool bReturn = tree.FarthestNeighbor( closest, -11.0 ); if( ! bReturn ) { ++g_errorCount; fprintf(stdout, "testFindLastObject: Far failed to find anything\n" ); } else if( closest != 1.0 ) { ++g_errorCount; fprintf(stdout, "testFindLastObject: Far failed for float, got %f\n", closest ); } } { CNearTree tree; double f = 1.0; /* generate an unbalanced tree*/ while( f > 0.0 && f >= DBL_MIN) { f /= 2.0; } f = DBL_MIN; while( f < 1.01 ) { tree.insert( f ); f *= 2.0; } double farthest = 0.0; const bool bReturnNear = tree.NearestNeighbor( 1000.0, farthest, 1000.0 ); if( ! bReturnNear ) { ++g_errorCount; fprintf(stdout, "testFindLastObject Near failed to find anything for double\n" ); } else if( farthest != 1.0 ) { ++g_errorCount; fprintf(stdout, "testFindLastObject Near failed for double, reverse tree, got %f\n", farthest ); } double closest = 0.0; const bool bReturnFar = tree.FarthestNeighbor( closest, -11.0 ); if( ! bReturnFar ) { ++g_errorCount; fprintf(stdout, "testFindLastObject Far failed to find anything for double\n" ); } else if( closest != 1.0 ) { ++g_errorCount; fprintf(stdout, "testFindLastObject Far failed for double, reverse tree, got %f\n", closest ); } } } // end testFindLastObject /*=======================================================================*/ void testFindInSphereFromBottom( void ) { const int nmax = 100; CNearTree tree; for( int i=1; i<=nmax; ++i ) { tree.insert( (double)i ); } /* generate an unbalanced tree*/ for( int i=1; i<=nmax; ++i ) { const double radius = 0.05 + (double)i; CNearTree sphereReturn; const long lReturned = tree.FindInSphere( radius, sphereReturn, 0.9 ); if( lReturned != (long)i ) { ++g_errorCount; fprintf(stdout, "FindInSphere failed in testFindInSphereFromBottom for i=%d\n", i ); } } for( int i=1; i<=nmax; ++i ) { const double radius = 0.05 + (double)i; CNearTree sphereReturn; const long lReturned = tree.LeftFindInSphere( radius, sphereReturn, 0.9 ); if( lReturned != (long)i ) { ++g_errorCount; fprintf(stdout, "LeftFindInSphere failed in testFindInSphereFromBottom for i=%d\n", i ); } } } // end testFindInSphereFromBottom /*=======================================================================*/ void testFindInSphereFromTop( void ) { const int nmax = 100; CNearTree tree; for( int i=1; i<=nmax; ++i ) { tree.insert( (double)i ); } /* generate an unbalanced tree*/ for( int i=1; i<=nmax; ++i ) { const double radius = 0.05 + (double)i; CNearTree sphereReturn; const long lReturned = tree.FindInSphere( radius, sphereReturn, 0.1 + (double)nmax ); if( lReturned != (long)i ) { ++g_errorCount; fprintf(stdout, "FindInSphere failed in testFindInSphereFromTop for i=%d\n", i ); } } std::vector v; /* generate an unbalanced tree*/ for( int i=1; i<=nmax; ++i ) { v.clear( ); const double radius = 0.05 + (double)i; CNearTree sphereReturn; const long lReturned = tree.FindInSphere( radius, v, 0.1 + (double)nmax ); if( lReturned != (long)i ) { ++g_errorCount; fprintf(stdout, "FindInSphere failed for vector in testFindInSphereFromTop for i=%d\n", i ); } } } // end testFindInSphereFromTop /*=======================================================================*/ void testOutSphere( void ) { const int nmax = 100; CNearTree tree; /* generate an unbalanced tree*/ for( int i=1; i<=nmax; ++i ) { tree.insert( (double)i ); } // now test the NearTree return for( int i=1; i<=nmax; ++i ) { CNearTree sphereReturn; const double radius = 0.05 + (double)i; const long lReturned = tree.FindOutSphere( radius, sphereReturn, 0.1 + (double)nmax ); if( lReturned != 100-(long)i ) { ++g_errorCount; fprintf(stdout, "testOutSphere: FindOutSphere failed for i=%d\n", i ); } } // now test the vector return for( int i=1; i<=nmax; ++i ) { std::vector v; v.clear( ); const double radius = 0.05 + (double)i; const long lReturned = tree.FindOutSphere( radius, v, 0.1 + (double)nmax ); if( lReturned != 100-(long)i ) { ++g_errorCount; fprintf(stdout, "testOutSphere: FindOutSphere failed for for vector for i=%d\n", i ); } } } // end testOutSphere /* Test CNearTree with a bunch of random numbers (integers). */ /*=======================================================================*/ void testRandomTree1( const int nRequestedRandoms ) { const int n = nRequestedRandoms; CNearTree tree; int nmax = INT_MIN; int nmin = INT_MAX; /* Build the tree with n random numbers. Remember the largest and smallest values. */ for( int i=0; i nmax ) nmax = next; if( next < nmin ) nmin = next; } { /*verify that the correct extremal point is detected (from below)*/ int closest=INT_MAX; const bool bNear = tree.NearestNeighbor( (double)LONG_MAX, closest, INT_MIN/2 ); if( ! bNear ) { ++g_errorCount; fprintf(stdout, "testRandomTree1: NearestNeighbor failed to find anything\n" ); } else if( closest != nmin ) { ++g_errorCount; fprintf(stdout, "testRandomTree1: NearestNeighbor failed for min\n" ); } int farthest=INT_MIN; const bool bFar = tree.FarthestNeighbor( farthest, INT_MIN/2 ); if( !bFar ) { ++g_errorCount; fprintf(stdout, "testRandomTree1: FarthestNeighbor failed to find anything\n" ); } else if( farthest != nmax ) { ++g_errorCount; fprintf(stdout, "testRandomTree1: FarthestNeighbor failed in testRandomTree1 for min\n" ); } } { /*verify that the correct extremal point is detected (from above)*/ int closest=INT_MIN; const bool bNear = tree.NearestNeighbor( (double)LONG_MAX, closest, INT_MAX/2 ); if( ! bNear ) { ++g_errorCount; fprintf(stdout, "testRandomTree1: NearestNeighbor failed to find anything for max\n" ); } else if( closest != nmax ) { ++g_errorCount; fprintf(stdout, "testRandomTree1: NearestNeighbor failed for max\n" ); } int farthest; const bool bFar = tree.FarthestNeighbor( farthest, INT_MAX/2 ); if( !bFar ) { ++g_errorCount; fprintf(stdout, "testRandomTree1: FarthestNeighbor failed to find anything for min\n" ); } else if( farthest != nmin ) { ++g_errorCount; fprintf(stdout, "testRandomTree1: FarthestNeighbor failed for min\n" ); } } { /*verify that for very large radius, every point is detected (from below)*/ std::vector v; const double radius = DBL_MAX; CNearTree sphereReturn; const long lReturn = tree.FindInSphere( radius, sphereReturn, INT_MIN/2 ); if( lReturn != n ) { ++g_errorCount; fprintf(stdout, "FindInSphere failed in testRandomTree1, n=%d, lReturn=%ld\n", n, lReturn ); } } { /*verify that for very large radius, every point is detected (from below)*/ std::vector v; const double radius = DBL_MAX; CNearTree sphereReturn; std::vector sphereIndices; const long lReturn = tree.FindInSphere( radius, sphereReturn, sphereIndices, INT_MIN/2 ); if( lReturn != n || sphereIndices.size() != (size_t)n ) { ++g_errorCount; fprintf(stdout, "FindInSphere failed in testRandomTree1, n=%d, lReturn=%ld, indices=%ld\n", n, (long)lReturn, (long)sphereIndices.size() ); } else { for (size_t ii = 0; ii < (size_t) n; ii++) { if (tree[sphereIndices[ii]]!=sphereReturn[ii]) { ++g_errorCount; fprintf(stdout, "FindInSphere: testRandomTree1: tree[%ld] != sphereReturn[%ld]\n", (long)sphereIndices[ii], (long)ii ); } } } } { /*verify that we find NO points if we are below the lowest and with too small radius*/ const double radius = .5; CNearTree sphereReturn; const long lReturn = tree.FindInSphere( radius, sphereReturn, nmin-1 ); if( lReturn != 0 ) { ++g_errorCount; fprintf(stdout, "FindInSphere failed in testRandomTree1 found points incorrectly, n=%d, lReturn=%ld\n", n, lReturn ); } } { /*verify that we find NO points if we are below the lowest and with too small radius*/ const double radius = .5; CNearTree sphereReturn; CNearTree sphereIndices; const long lReturn = tree.FindInSphere( radius, sphereReturn, nmin-1 ); if( lReturn != 0 || sphereIndices.size() !=0) { ++g_errorCount; fprintf(stdout, "FindInSphere failed in testRandomTree1 found points or indices incorrectly, n=%d, lReturn=%ld, indices=%ld\n", n, lReturn, (long)sphereIndices.size()); } } { /*test that the number of found points in a sphere is non-deceasing with increasing radius*/ long lReturn = 0; int lastFoundCount = 0; double radius = 0.00001; /* start with a very small radius (remember these are int's) */ while( radius < (double)(5*(nmax-nmin)) ) { CNearTree sphereReturn; lReturn = tree.FindInSphere( radius, sphereReturn, nmin-1 ); if( lReturn < lastFoundCount ) { ++g_errorCount; fprintf(stdout, "FindInSphere in testRandomTree1 found DECREASING count on increasing radius for radius=%f\n", radius ); break; } else { lastFoundCount = lReturn; radius *= 1.414; } } /* verify that all points were included in the final check (beyond all reasonable distances) */ if( lReturn != n ) { ++g_errorCount; fprintf(stdout, "FindInSphere in testRandomTree1 did not find all the points\n" ); } } } // end testRandomTree1 /* Test CNearTree with a bunch of random numbers (integers). */ /*=======================================================================*/ void testRandomTree2( const int nRequestedRandoms ) { const int n = nRequestedRandoms; CNearTree tree; int nmax = INT_MIN; int nmin = INT_MAX; /* Build the tree with n random numbers. Remember the largest and smallest values. */ for( int i=0; i nmax ) nmax = next; if( next < nmin ) nmin = next; } { /*verify that the correct extremal point is detected (from below)*/ int closest=INT_MAX; const bool bNear = tree.NearestNeighbor( (double)LONG_MAX, closest, INT_MIN/2 ); if( ! bNear ) { ++g_errorCount; fprintf(stdout, "testRandomTree2: NearestNeighbor failed to find anything\n" ); } else if( closest != nmin ) { ++g_errorCount; fprintf(stdout, "testRandomTree2: NearestNeighbor failed for min\n" ); } int farthest=INT_MIN; const bool bFar = tree.FarthestNeighbor( farthest, INT_MIN/2 ); if( !bFar ) { ++g_errorCount; fprintf(stdout, "testRandomTree2: FarthestNeighbor failed to find anything\n" ); } else if( farthest != nmax ) { ++g_errorCount; fprintf(stdout, "testRandomTree2: FarthestNeighbor failed in testRandomTree2 for min\n" ); } } { /*verify that the correct extremal point is detected (from above)*/ int closest=INT_MIN; const bool bNear = tree.NearestNeighbor( (double)LONG_MAX, closest, INT_MAX/2 ); if( ! bNear ) { ++g_errorCount; fprintf(stdout, "testRandomTree2: NearestNeighbor failed to find anything for max\n" ); } else if( closest != nmax ) { ++g_errorCount; fprintf(stdout, "testRandomTree2: NearestNeighbor failed for max\n" ); } int farthest; const bool bFar = tree.FarthestNeighbor( farthest, INT_MAX/2 ); if( !bFar ) { ++g_errorCount; fprintf(stdout, "testRandomTree2: FarthestNeighbor failed to find anything for min\n" ); } else if( farthest != nmin ) { ++g_errorCount; fprintf(stdout, "testRandomTree2: FarthestNeighbor failed for min\n" ); } } { /*verify that for very large radius, every point is detected (from below)*/ std::vector v; const double radius = DBL_MAX; CNearTree sphereReturn; const long lReturn = tree.FindInSphere( radius, sphereReturn, INT_MIN/2 ); if( lReturn != n ) { ++g_errorCount; fprintf(stdout, "FindInSphere failed in testRandomTree2, n=%d, lReturn=%ld\n", n, lReturn ); } } { /*verify that for very large radius, every point is detected (from below)*/ std::vector v; const double radius = DBL_MAX; CNearTree sphereReturn; std::vector sphereIndices; const long lReturn = tree.FindInSphere( radius, sphereReturn, sphereIndices, INT_MIN/2 ); if( lReturn != n || sphereIndices.size() != (size_t)n ) { ++g_errorCount; fprintf(stdout, "FindInSphere failed in testRandomTree2, n=%d, lReturn=%ld, indices=%ld\n", n, (long)lReturn, (long)sphereIndices.size() ); } else { for (size_t ii = 0; ii < (size_t)n; ii++) { if (tree[sphereIndices[ii]]!=sphereReturn[ii]) { ++g_errorCount; fprintf(stdout, "FindInSphere: testRandomTree2: tree[%ld] != sphereReturn[%ld]\n", (long)sphereIndices[ii], (long)ii ); } } } } { /*verify that we find NO points if we are below the lowest and with too small radius*/ const double radius = .5; CNearTree sphereReturn; const long lReturn = tree.FindInSphere( radius, sphereReturn, nmin-1 ); if( lReturn != 0 ) { ++g_errorCount; fprintf(stdout, "FindInSphere failed in testRandomTree2 found points incorrectly, n=%d, lReturn=%ld\n", n, lReturn ); } } { /*verify that we find NO points if we are below the lowest and with too small radius*/ const double radius = .5; CNearTree sphereReturn; std::vector sphereIndices; const long lReturn = tree.FindInSphere( radius, sphereReturn, sphereIndices, nmin-1 ); if( lReturn != 0 || sphereIndices.size() !=0 ) { ++g_errorCount; fprintf(stdout, "FindInSphere failed in testRandomTree2 found points or indices incorrectly, n=%d, lReturn=%ld, indices=%ld\n", n, lReturn, (long)sphereIndices.size()); } } { /*test that the number of found points in a sphere is non-deceasing with increasing radius*/ long lReturn = 0; int lastFoundCount = 0; double radius = 0.00001; /* start with a very small radius (remember these are int's) */ while( radius < (double)(5*(nmax-nmin)) ) { CNearTree sphereReturn; lReturn = tree.FindInSphere( radius, sphereReturn, nmin-1 ); if( lReturn < lastFoundCount ) { ++g_errorCount; fprintf(stdout, "FindInSphere in testRandomTree2 found DECREASING count on increasing radius for radius=%f\n", radius ); break; } else { lastFoundCount = lReturn; radius *= 1.414; } } lastFoundCount = 0; radius = 0.00001; /* start with a very small radius (remember these are int's) */ while( radius < (double)(5*(nmax-nmin)) ) { CNearTree sphereReturn; std::vector sphereIndices; lReturn = tree.FindInSphere( radius, sphereReturn, sphereIndices, nmin-1 ); if( lReturn < lastFoundCount || sphereIndices.size() != (size_t)lReturn ) { ++g_errorCount; fprintf(stdout, "FindInSphere in testRandomTree2 found DECREASING count on increasing radius for radius=%f" " or mismatched index count %ld != %ld\n", radius, (long)sphereIndices.size(), (long)lastFoundCount ); break; } else { for (size_t ii = 0; ii < sphereIndices.size(); ii++) { if (tree[sphereIndices[ii]]!=sphereReturn[ii]) { ++g_errorCount; fprintf(stdout, "FindInSphere in testRandomTree2 mismatch between tree[%ld] and sphereReturn[%ld]\n", (long)sphereIndices[ii], (long)ii); } } lastFoundCount = lReturn; radius *= 1.414; } } /* verify that all points were included in the final check (beyond all reasonable distances) */ if( lReturn != n ) { ++g_errorCount; fprintf(stdout, "FindInSphere in testRandomTree2 did not find all the points\n" ); } } } // end testRandomTree2 /*=======================================================================*/ /* make a 17-dimension vector class for testing */ class vec17 { public: double pd[17]; int dim; double length; // just for a signature for debugging vec17( ) : dim(17), length(0) { for( int i=0; ipd[i] - v.pd[i]; } vtemp.length = Norm( ); return( vtemp ); } double Norm( void ) const { double dtemp = 0.0; for( int i=0; i tree; vec17 vAll[vectorsize]; /* keep a list of all of the input so we can find particular entries */ double rmax = -DBL_MAX; double rmin = DBL_MAX; vec17 v17min; /* to be the point nearest to the origin */ vec17 v17max; /* to be the point farthest from the origin */ /* All of the coordinate values will be in the range 0-RHrand::RHRAND_MAX. In other words, all of the data points will be within a 17-D cube that has a corner at the origin of the space. */ for( int i=0; i rmax ) { rmax = v.Norm( ); v17max = v; } tree.insert( v ); vAll[i] = v; } timetreecommand(tree,"FarthestNeighbor",{ { size_t estdim = (size_t)(0.5+tree.GetDimEstimate()); if ( estdim < 6) { ++g_errorCount; fprintf(stdout, "testBigVector: dimension estimate %ld < 6 \n",(long)estdim); } else { fprintf(stdout, "testBigVector: dimension estimate %ld\n",(long)estdim); } { /* Find the point farthest from the point that was nearest the origin. */ vec17 vFarthest; tree.FarthestNeighbor( vFarthest, v17min ); /* Brute force search for the farthest */ vec17 vSearch; double dmax = -DBL_MAX; for( int i=0; i dmax ) { dmax = ( vAll[i] - v17min ).Norm( ); vSearch = vAll[i]; } } double distdiff = ( (vSearch-v17min) - (vFarthest-v17min) ).Norm( ); distdiff = (distdiff<0)?-distdiff:distdiff; if( distdiff > DBL_MIN ) { ++g_errorCount; fprintf(stdout, "in testBigVector, apparently FarthestNeighbor has failed\n" ); } } { /* somewhere in the middle, find a point and its nearest neighbor */ /* make sure that each includes the other in sphere search */ const vec17 vBox17Center( (double)(RHrand::RHRAND_MAX/2) ); vec17 vNearCenter; vec17 vCloseToNearCenter; tree.NearestNeighbor( double(RHrand::RHRAND_MAX/2)*sqrt(17.), vNearCenter, vBox17Center ); CNearTree sphereReturn; std::vector sphereIndices; unsigned long iFoundNearCenter = (unsigned long)tree.FindInSphere( double(RHrand::RHRAND_MAX/2)*sqrt(17.)/2., sphereReturn, vNearCenter ); /* Brute force search for the point closest to the point closest to the center */ double dmin = DBL_MAX; for( unsigned long i=0; i DBL_MIN && ( vNearCenter-sphereReturn[i] ).Norm( ) < dmin ) { dmin = ( vNearCenter-sphereReturn[i] ).Norm( ); vCloseToNearCenter = sphereReturn[i]; } } { //const double radius = ( vCloseToNearCenter - vNearCenter ).Norm( ); const double radius = RHrand::RHRAND_MAX*sqrt(17.0); unsigned long iSphereFoundNearCenter = (unsigned long)tree.FindInSphere( radius, sphereReturn, vNearCenter ); double searchRadius = radius/2; double delta = searchRadius; int count = 0; while( iSphereFoundNearCenter != 2 && count < 100 ) { iSphereFoundNearCenter = (unsigned long)tree.FindInSphere( searchRadius, sphereReturn, vNearCenter ); if( iSphereFoundNearCenter > 2 ) { searchRadius = searchRadius - delta/2; } else if( iSphereFoundNearCenter < 2 ) { searchRadius = searchRadius + delta/2; } delta /= 2; ++count; } // end while if( iSphereFoundNearCenter != 2 ) { ++g_errorCount; fprintf(stdout, "testBigVector: FindInSphere failed to find only 2 points\n" ); } } { //const double radius = ( vCloseToNearCenter - vNearCenter ).Norm( ); const double radius = RHrand::RHRAND_MAX*sqrt(17.0); unsigned long iSphereFoundNearCenter = (unsigned long)tree.FindInSphere( radius, sphereReturn, vNearCenter ); double searchRadius = radius/2; double delta = searchRadius; int count = 0; while( iSphereFoundNearCenter != 2 && count < 100 ) { iSphereFoundNearCenter = (unsigned long)tree.FindInSphere( searchRadius, sphereReturn, sphereIndices, vNearCenter ); if ((size_t)iSphereFoundNearCenter != sphereIndices.size()) { ++g_errorCount; fprintf(stdout, "testBigVector: FindInSphere mismatch size %ld with indices %ld\n", (long)iSphereFoundNearCenter, (long)sphereIndices.size()); } else { for (size_t ii = 0; ii < sphereIndices.size(); ii++) { if ((tree[sphereIndices[ii]]-sphereReturn[ii]).Norm() != 0.) { fprintf(stdout, "testBigVector: FindInSphere mismatch tree[%ld] != sphereReturn[%ld]\n", (long)sphereIndices[ii], (long)ii); } } } if( iSphereFoundNearCenter > 2 ) { searchRadius = searchRadius - delta/2; } else if( iSphereFoundNearCenter < 2 ) { searchRadius = searchRadius + delta/2; } delta /= 2; ++count; } // end while if( iSphereFoundNearCenter != 2 || sphereIndices.size() != 2 ) { ++g_errorCount; fprintf(stdout, "testBigVector: FindInSphere failed to find only 2 points or indices !=2\n" ); } } if( dmin == DBL_MAX ) { ++g_errorCount; fprintf(stdout, "testBigVector: apparently FindInSphere failed\n" ); } { /* Using zero radius, check that only one point is found when a point is searched with FindInSphere */ sphereReturn.clear( ); const long iFound = tree.FindInSphere( 0.0, sphereReturn, vNearCenter ); if( iFound < 1 ) { ++g_errorCount; fprintf(stdout, "testBigVector: FindInSphere found no points using zero radius\n" ); } else if( iFound != 1 ) { ++g_errorCount; fprintf(stdout, "testBigVector: FindInSphere found more than %ld points using zero radius\n", iFound ); } } { /* Using minimal radius, check that at least 2 points are found when a point is searched with FindInSphere */ sphereReturn.clear( ); const long iFound = tree.FindInSphere( (vCloseToNearCenter-vNearCenter).Norm( ), sphereReturn, vNearCenter ); if( iFound < 2 ) { ++g_errorCount; fprintf(stdout, "testBigVector: FindInSphere found only 1 point\n" ); } } { /* Using small radius, check that only one point is found when a point is searched with FindInSphere */ sphereReturn.clear( ); const long iFound = tree.FindInSphere( (vCloseToNearCenter-vNearCenter).Norm( )*0.9, sphereReturn, vNearCenter ); if( iFound < 1 ) { ++g_errorCount; fprintf(stdout, "testBigVector: FindInSphere found no points using %f radius\n", (vCloseToNearCenter-vNearCenter).Norm( )*0.9 ); } else if( iFound != 1 ) { ++g_errorCount; fprintf(stdout, "testBigVector: FindInSphere found %ld points using %f radius\n", iFound, (vCloseToNearCenter-vNearCenter).Norm( )*0.9 ); } } }} }); timetreecommand(tree,"FarthestNeighbor Left",{ {size_t estdim = (size_t)(0.5+tree.GetDimEstimate());; if ( estdim < 6) { ++g_errorCount; fprintf(stdout, "testBigVector: dimension estimate %ld <6 \n",(long)estdim); } else { fprintf(stdout, "testBigVector: dimension estimate %ld\n",(long)estdim); } { /* Find the point farthest from the point that was nearest the origin. */ vec17 vFarthest; tree.LeftFarthestNeighbor( vFarthest, v17min ); /* Brute force search for the farthest */ vec17 vSearch; double dmax = -DBL_MAX; for( int i=0; i dmax ) { dmax = ( vAll[i] - v17min ).Norm( ); vSearch = vAll[i]; } } double distdiff = ( (vSearch-v17min) - (vFarthest-v17min) ).Norm( ); distdiff = (distdiff<0)?-distdiff:distdiff; if( distdiff > DBL_MIN ) { ++g_errorCount; fprintf(stdout, "in testBigVector, apparently LeftFarthestNeighbor has failed\n" ); } } { /* somewhere in the middle, find a point and its nearest neighbor */ /* make sure that each includes the other in sphere search */ const vec17 vBox17Center( (double)(RHrand::RHRAND_MAX/2) ); vec17 vNearCenter; vec17 vCloseToNearCenter; tree.LeftNearestNeighbor( double(RHrand::RHRAND_MAX/2)*sqrt(17.), vNearCenter, vBox17Center ); CNearTree sphereReturn; std::vector sphereIndices; unsigned long iFoundNearCenter = (unsigned long)tree.LeftFindInSphere( double(RHrand::RHRAND_MAX/2)*sqrt(17.)/2., sphereReturn, vNearCenter ); /* Brute force search for the point closest to the point closest to the center */ double dmin = DBL_MAX; for( unsigned long i=0; i DBL_MIN && ( vNearCenter-sphereReturn[i] ).Norm( ) < dmin ) { dmin = ( vNearCenter-sphereReturn[i] ).Norm( ); vCloseToNearCenter = sphereReturn[i]; } } { //const double radius = ( vCloseToNearCenter - vNearCenter ).Norm( ); const double radius = RHrand::RHRAND_MAX*sqrt(17.0); unsigned long iSphereFoundNearCenter = (unsigned long)tree.LeftFindInSphere( radius, sphereReturn, vNearCenter ); double searchRadius = radius/2; double delta = searchRadius; int count = 0; while( iSphereFoundNearCenter != 2 && count < 100 ) { iSphereFoundNearCenter = (unsigned long)tree.LeftFindInSphere( searchRadius, sphereReturn, vNearCenter ); if( iSphereFoundNearCenter > 2 ) { searchRadius = searchRadius - delta/2; } else if( iSphereFoundNearCenter < 2 ) { searchRadius = searchRadius + delta/2; } delta /= 2; ++count; } // end while if( iSphereFoundNearCenter != 2 ) { ++g_errorCount; fprintf(stdout, "testBigVector: LeftFindInSphere failed to find only 2 points\n" ); } } { //const double radius = ( vCloseToNearCenter - vNearCenter ).Norm( ); const double radius = RHrand::RHRAND_MAX*sqrt(17.0); unsigned long iSphereFoundNearCenter = (unsigned long)tree.LeftFindInSphere( radius, sphereReturn, vNearCenter ); double searchRadius = radius/2; double delta = searchRadius; int count = 0; while( iSphereFoundNearCenter != 2 && count < 100 ) { iSphereFoundNearCenter = (unsigned long)tree.LeftFindInSphere( searchRadius, sphereReturn, sphereIndices, vNearCenter ); if ((size_t)iSphereFoundNearCenter != sphereIndices.size()) { ++g_errorCount; fprintf(stdout, "testBigVector: LeftFindInSphere mismatch size %ld with indices %ld\n", (long)iSphereFoundNearCenter, (long)sphereIndices.size()); } else { for (size_t ii = 0; ii < sphereIndices.size(); ii++) { if ((tree[sphereIndices[ii]]-sphereReturn[ii]).Norm() != 0.) { fprintf(stdout, "testBigVector: LeftFindInSphere mismatch tree[%ld] != sphereReturn[%ld]\n", (long)sphereIndices[ii], (long)ii); } } } if( iSphereFoundNearCenter > 2 ) { searchRadius = searchRadius - delta/2; } else if( iSphereFoundNearCenter < 2 ) { searchRadius = searchRadius + delta/2; } delta /= 2; ++count; } // end while if( iSphereFoundNearCenter != 2 || sphereIndices.size() != 2 ) { ++g_errorCount; fprintf(stdout, "testBigVector: Left FindInSphere failed to find only 2 points or indices !=2\n" ); } } if( dmin == DBL_MAX ) { ++g_errorCount; fprintf(stdout, "testBigVector: apparently LeftFindInSphere failed\n" ); } { /* Using zero radius, check that only one point is found when a point is searched with FindInSphere */ sphereReturn.clear( ); const long iFound = tree.LeftFindInSphere( 0.0, sphereReturn, vNearCenter ); if( iFound < 1 ) { ++g_errorCount; fprintf(stdout, "testBigVector: LeftFindInSphere found no points using zero radius\n" ); } else if( iFound != 1 ) { ++g_errorCount; fprintf(stdout, "testBigVector: LeftFindInSphere found more than %ld points using zero radius\n", iFound ); } } { /* Using minimal radius, check that at least 2 points are found when a point is searched with FindInSphere */ sphereReturn.clear( ); const long iFound = tree.LeftFindInSphere( (1.+DBL_EPSILON)*(vCloseToNearCenter-vNearCenter).Norm( ), sphereReturn, vNearCenter ); if( iFound < 2 ) { ++g_errorCount; fprintf(stdout, "testBigVector: LeftFindInSphere found only 1 point\n" ); } } { /* Using small radius, check that only one point is found when a point is searched with FindInSphere */ sphereReturn.clear( ); const long iFound = tree.LeftFindInSphere( (vCloseToNearCenter-vNearCenter).Norm( )*0.9, sphereReturn, vNearCenter ); if( iFound < 1 ) { ++g_errorCount; fprintf(stdout, "testBigVector: LeftFindInSphere found no points using %f radius\n", (vCloseToNearCenter-vNearCenter).Norm( )*0.9 ); } else if( iFound != 1 ) { ++g_errorCount; fprintf(stdout, "testBigVector: LeftFindInSphere found %ld points using %f radius\n", iFound, (vCloseToNearCenter-vNearCenter).Norm( )*0.9 ); } } }} }); } // testBigVector /*=======================================================================*/ void testBackwardForward( void ) { CNearTree tree; const int nMax = 1000; for( int i=0; i DBL_MIN ) { fprintf(stdout, "testBackwardForward::NearestNeighbor failed, closest=%f\n", closest ); } } } // end testBackwardForward /*=======================================================================*/ const long nmax = 10001; void testDelayedInsertion( void ) { { // make sure that CompleteDelayedInsert flushes the delayed data CNearTree tree; for( int i=1; i<=nmax; ++i ) { const double insertValue = (double)(i); tree.insert( insertValue ); } tree.CompleteDelayedInsert( ); const size_t depth = tree.GetDepth( ); const size_t insertedSize = tree.GetTotalSize( ); const size_t delayed = tree.GetDeferredSize( ); if( delayed != 0 || (long)insertedSize != nmax ) { ++g_errorCount; fprintf(stdout, "testDelayedInsertion: CompleteDelayedInsert completion is incorrect\n" ); } else if( depth >=nmax/2 ) { ++g_errorCount; fprintf(stdout, "testDelayedInsertion: tree depth is too large, %lu is greater than %ld\n", (unsigned long)depth, nmax/2 ); } fprintf(stdout, "testDelayedInsertionRandom: tree depth is %ld\n", (unsigned long)depth ); #ifdef CNEARTREE_INSTRUMENTED if( tree.GetHeight( ) != tree.GetDepth( ) ) { ++g_errorCount; fprintf(stdout, "testDelayedInsertionRandom: tree depth != tree height, %lu != %lu\n", (unsigned long)tree.GetDepth( ), (unsigned long)tree.GetHeight( ) ); } #endif } { // make sure that FindInSphere flushes the delayed data const long nmax2 = 100; CNearTree tree; for( int i=1; i<=nmax2; ++i ) { if( (i%2) == 0 ) { tree.ImmediateInsert( (double)i ); } else { tree.insert( (double)i ); } } CNearTree sphereReturn; const double radius = 1000.0; const long lReturned = tree.FindInSphere( radius, sphereReturn, 0.9 ); if( lReturned != nmax2 ) { ++g_errorCount; fprintf(stdout, "testDelayedInsertion: FindInSphere failed for nmax2=%ld, found %ld points\n", nmax2, lReturned ); } } { // make sure that NearestNeighbor flushes the delayed data const long nmax2 = 100; CNearTree tree; double fFinal = DBL_MAX; for( int i=1; i<=nmax2; ++i ) { if( (i%2) == 0 && i!=nmax2) // ensure that the last one is delayed { tree.ImmediateInsert( (double)i ); } else { tree.insert( (double)i ); fFinal = (double)i; } } double closest; const double radius = 0.1; const bool bReturned = tree.NearestNeighbor( radius, closest, fFinal ); if( ! bReturned ) { ++g_errorCount; fprintf(stdout, "testDelayedInsertion: NearestNeighbor failed\n" ); } else if( closest != fFinal ) { ++g_errorCount; fprintf(stdout, "testDelayedInsertion: NearestNeighbor failed to find the data\n" ); } } { // make sure that FarthestNeighbor flushes the delayed data const long nmax2 = 100; CNearTree tree; double fFinal = DBL_MAX; for( int i=1; i<=nmax2; ++i ) { if( (i%2) == 0 && i!=nmax2) // ensure that the last one is delayed { tree.ImmediateInsert( (double)i ); } else { tree.insert( (double)i ); fFinal = (double)i; } } double farthest; const bool bReturned = tree.FarthestNeighbor( farthest, -100.0 ); if( ! bReturned ) { ++g_errorCount; fprintf(stdout, "testDelayedInsertion: FarthestNeighbor failed\n" ); } else if( farthest != fFinal ) { ++g_errorCount; fprintf(stdout, "testDelayedInsertion: FarthestNeighbor failed to find the data\n" ); } } } // end testDelayedInsertion /*=======================================================================*/ void testDelayedInsertionRandom( void ) { { // make sure that CompleteDelayedInsert flushes the delayed data CNearTree tree; for( int i=1; i<=nmax; ++i ) { const double insertValue = (double)(i); tree.insert( insertValue ); } tree.CompleteDelayedInsertRandom( ); const size_t depth = tree.GetDepth( ); const size_t insertedSize = tree.GetTotalSize( ); const size_t delayed = tree.GetDeferredSize( ); if( delayed != 0 || (long)insertedSize != nmax ) { ++g_errorCount; fprintf(stdout, "testDelayedInsertionRandom: CompleteDelayedInsertRandom completion is incorrect\n" ); } else if( depth >= sqrt( (double)(nmax/2) ) ) { ++g_errorCount; fprintf(stdout, "testDelayedInsertionRandom: tree depth is too large, %lu is greater than %ld\n", (unsigned long)depth, (long)sqrt( (double)(nmax/2) ) ); } fprintf(stdout, "testDelayedInsertionRandom: tree depth is %ld\n", (unsigned long)depth ); #ifdef CNEARTREE_INSTRUMENTED if( tree.GetHeight( ) != tree.GetDepth( ) ) { ++g_errorCount; fprintf(stdout, "testDelayedInsertionRandom: tree depth != tree height, %lu != %lu\n", (unsigned long)tree.GetDepth( ), (unsigned long)tree.GetHeight( ) ); } #endif } } // end testDelayedInsertionRandom /*=======================================================================*/ void testIterators( void ) { CNearTree tree; CNearTree::iterator itEmpty = tree.back( ); CNearTree::iterator itTest = tree.end( ); if( itEmpty != tree.end( ) ) { ++g_errorCount; fprintf(stdout, "testIterators: back failed for empty tree\n" ); } if( itEmpty != tree.end( ) ) { ++g_errorCount; fprintf(stdout, "testIterators: back failed for empty tree\n" ); } const int nMax = 1000; for( int i=0; i::iterator itSingle = tree.back( ); if( (*itSingle) != 1 ) { ++g_errorCount; fprintf(stdout, "testIterators: size failed for size=2 tree\n" ); } } } { CNearTree::iterator it; it = --tree.end( ); if( *it != nMax-1 ) { ++g_errorCount; fprintf(stdout, "testIterators: test01 failed\n" ); } CNearTree::iterator itTest( it ); if( itTest != it ) { ++g_errorCount; fprintf(stdout, "testIterators: copy construction failed\n" ); } it = tree.begin( ); if( *it != 0 ) { ++g_errorCount; fprintf(stdout, "testIterators: test02 failed\n" ); } it = it+1; if( *it != 1 ) { ++g_errorCount; fprintf(stdout, "testIterators: test03 failed\n" ); } it = it-1; if( *it != 0 ) { ++g_errorCount; fprintf(stdout, "testIterators: test04 failed\n" ); } const int i0 = *it; if( i0 != 0 ) { ++g_errorCount; fprintf(stdout, "testIterators: test05 failed\n" ); } ++it; if( *it != 1 ) { ++g_errorCount; fprintf(stdout, "testIterators: test06 failed\n" ); } --it; if( *it != 0 ) { ++g_errorCount; fprintf(stdout, "testIterators: test07 failed\n" ); } const CNearTree::iterator itPlus = it++; if( *it != 1 ) { *itPlus; // just to keep LINT happy ++g_errorCount; fprintf(stdout, "testIterators: test08 failed\n" ); } it--; if( i0 != 0 ) { ++g_errorCount; fprintf(stdout, "testIterators: test09 failed\n" ); } ++it; if( *it != 1 ) { ++g_errorCount; fprintf(stdout, "testIterators: test10 failed\n" ); } } { CNearTree::iterator it; const int searchValue = 14; const CNearTree::iterator itEnd = tree.end( ); it = tree.NearestNeighbor( 0.1, searchValue ); if( it == itEnd ) { ++g_errorCount; fprintf(stdout, "testIterators: NearestNeighbor failed with iterator\n" ); } else if( *it != searchValue ) { ++g_errorCount; fprintf(stdout, "testIterators: NearestNeighbor found wrong value with iterator, %d\n", *it ); } it = tree.FarthestNeighbor( searchValue ); if( it == tree.end( ) ) { ++g_errorCount; fprintf(stdout, "testIterators:FarthestNeighbor failed with iterator\n" ); } else if( *it != nMax-1 ) { ++g_errorCount; fprintf(stdout, "testIterators: FarthestNeighbor found wrong value with iterator, %d\n", *it ); } } { // test InSphere CNearTree sphereTree; const double radius = 5.0; const long sizeReturned = tree.FindInSphere( radius, sphereTree, 50 ); CNearTree::iterator itSphere = sphereTree.begin( ); const size_t sphereSizeIn = sphereTree.size( ); if( (long)sphereSizeIn != sizeReturned ) { ++g_errorCount; fprintf(stdout, "testIterators: FindInSphere and size found different values, %ld and %ld\n", sizeReturned, (long)sphereSizeIn ); } const long sizeReturned2In = tree.FindInSphere( radius, sphereTree, 50 ); if( sizeReturned != sizeReturned2In ) { ++g_errorCount; fprintf(stdout, "testIterators: 2nd FindInSphere found different value, %ld and %ld\n", sizeReturned, sizeReturned2In ); } std::vector sphereVector; const long sizeReturnedV = tree.FindInSphere( radius, sphereVector, 50 ); if( (long)sphereSizeIn != sizeReturnedV ) { ++g_errorCount; fprintf(stdout, "testIterators: FindInSphere for vector and size found different values, %ld and %ld\n", sizeReturned, (long)sphereSizeIn ); } // test OutSphere const long sizeReturnedOut = tree.FindOutSphere( radius, sphereTree, 50 ); itSphere = sphereTree.begin( ); const size_t sphereSizeOut = sphereTree.size( ); if( (long)sphereSizeOut != sizeReturnedOut ) { ++g_errorCount; fprintf(stdout, "testIterators: FindOutSphere and size found different values, %ld and %ld\n", sizeReturned, (long)sphereSizeOut ); } const long sizeReturned2Out = tree.FindOutSphere( radius, sphereTree, 50 ); if( sizeReturned2Out != sizeReturnedOut ) { ++g_errorCount; fprintf(stdout, "testIterators: 2nd FindOutSphere found different value, %ld and %ld\n", sizeReturned, sizeReturned2Out ); } if( sizeReturned2In+sizeReturned2Out != nMax+2 ) { // because there are 2 ints on the boundary, the count should be nMax+2 ++g_errorCount; fprintf(stdout, "testIterators: total count from InSphere and OutSphere is wrong, %ld, should be%d\n", sizeReturned2Out+sizeReturned2Out, nMax+2 ); } sphereTree.insert( 999999 ); CNearTree::iterator it = sphereTree.end( ); --it; if( *(it) != 999999 ) { ++g_errorCount; fprintf(stdout, "testIterators: Error after incrementing iterator at end(1)\n" ); } it = --sphereTree.end( ); if( *(it) != 999999 ) { ++g_errorCount; fprintf(stdout, "testIterators: Error after incrementing iterator at end(2)\n" ); } } { vec17 v; CNearTree sphereReturn; sphereReturn.insert( v ); CNearTree::iterator itv = sphereReturn.begin( ); const int n = itv->dim; if( n != 17 ) { ++g_errorCount; fprintf(stdout, "testIterators: operator-> got wrong value for dim, %d\n", n ); } const double d = itv->pd[0]; if( d != v.pd[0] ) { ++g_errorCount; fprintf(stdout, "testIterators: operator-> got wrong value for pd[0], %g\n", d ); } } } // end testIterators /*=======================================================================*/ class v2 { int m,n; public: v2( const int mm, const int nn ) : m(mm), n(nn) { } v2 operator- ( const v2& v ) const { return( v2( m-v.m, n-v.n ) ); } double Norm( void ) const { return( sqrt( (double)( n*n + m*m ) ) ); // L2 measure } }; // end of v2 /*=======================================================================*/ void testFindInAnnulus( void ) { { CNearTree tree; CNearTree::iterator itEmpty = tree.back( ); // make sure back works itEmpty = tree.back( ); const int nMax = 1000; for( int i=0; i annulusTree; const long lInAnnulus = tree.FindInAnnulus( r1, r2, annulusTree, 0 ); if( lInAnnulus != (299-101+1) ) { ++g_errorCount; fprintf(stdout, "testFindInAnnulus: wrong number of objects found\n" ); } CNearTree::iterator itNear = annulusTree.NearestNeighbor( 1000.0, 0 ); if( *itNear != 101 ) { ++g_errorCount; fprintf(stdout, "testFindInAnnulus: lowest value (%d) is incorrect\n", *itNear ); } CNearTree::iterator itFar = annulusTree.FarthestNeighbor( 0 ); if( *itFar != 299 ) { ++g_errorCount; fprintf(stdout, "testFindInAnnulus: highest value (%d) is incorrect\n", *itFar ); } } { CNearTree annulusTree; std::vector annulusIndices; const long lInAnnulus = tree.FindInAnnulus( r1, r2, annulusTree, annulusIndices, 0 ); if( lInAnnulus != (299-101+1) || annulusIndices.size() != (299-101+1) ) { ++g_errorCount; fprintf(stdout, "testFindInAnnulus: wrong number of objects found\n" ); } else { for (size_t ii=0; ii < annulusIndices.size(); ii++) { if (tree[annulusIndices[ii]] != annulusTree[ii]) { ++g_errorCount; fprintf(stdout, "testFindInAnnulus: mismatch tree[%ld] != annulusTree[%ld]\n", (long)annulusIndices[ii], (long)ii); } } } CNearTree::iterator itNear = annulusTree.NearestNeighbor( 1000.0, 0 ); if( *itNear != 101 ) { ++g_errorCount; fprintf(stdout, "testFindInAnnulus: lowest value (%d) is incorrect\n", *itNear ); } CNearTree::iterator itFar = annulusTree.FarthestNeighbor( 0 ); if( *itFar != 299 ) { ++g_errorCount; fprintf(stdout, "testFindInAnnulus: highest value (%d) is incorrect\n", *itFar ); } } { std::vector annulusvector; const long lInAnnulus = tree.FindInAnnulus( r1, r2, annulusvector, 0 ); if( lInAnnulus != (299-101+1) ) { ++g_errorCount; fprintf(stdout, "testFindInAnnulus: for vector, wrong number of objects found\n" ); } } } { // test annulus in the case of more than 1-D using CNearTree return CNearTree< v2 > tree; for( int i=0; i<30; ++i ) { for( int j=0; j<30; ++j ) { tree.insert( v2(i,j) ); } } double estdim = tree.GetDimEstimate()+tree.GetDimEstimateEsd(); if ( estdim <= 1.5) { ++g_errorCount; fprintf(stdout, "testFindInAnnulus: dimension estimate %g <= 1.5\n",estdim); } else { fprintf(stdout, "testFindInAnnulus: dimension estimate %g\n",estdim); } const double r1 = 4.0; const double r2 = 8.0; const v2 probe( -1, -1 ); // use FindInAnnulus to find the points in the annulus CNearTree< v2 > annulusResult; const long searchFoundInAnnulus = tree.FindInAnnulus( r2, r1, annulusResult, probe ); // now count all the points in the annulus by brute force int count = 0; const double radius = 0.001; // specify a very small radius so integer grid will only detect single points for( int i=0; i<30; ++i ) { for( int j=0; j<30; ++j ) { const v2 probe2( i, j ); v2 vReturn( 0, 0 ); // dummy coords for constructor if( annulusResult.NearestNeighbor( radius, vReturn, probe2 ) ) { ++count; } } } if( searchFoundInAnnulus != count ) { ++g_errorCount; fprintf(stdout, "testFindInAnnulus: wrong number of points found in annulus by NearTree, %ld, direct count=%d\n", searchFoundInAnnulus, count ); } } } // end testFindInAnnulus /*=======================================================================*/ void testMisc( void ) { CNearTree nt; for( int i=0; i<20; ++i ) { nt.insert( i ); } const std::vector v = nt; if( v.size( ) != nt.size( ) ) { ++g_errorCount; fprintf(stdout, "testMisc: wrong number of points %ld in vector\n", (long)v.size( ) ); } CNearTree nt1; nt1 = nt; if( nt1.size( ) != nt.size( ) ) { ++g_errorCount; fprintf(stdout, "testMisc: wrong number of points %ld in CNearTree\n", (long)nt1.size( ) ); } const size_t indexToRetrieve = 3; if( nt.at( indexToRetrieve ) != (int)indexToRetrieve ) { ++g_errorCount; fprintf(stdout, "testMisc: 'at' returned wrong value, %d\n",nt.at( 3 ) ); } } // end testMisc /*=======================================================================*/ void testIntegerReturn( void ) { { CNearTree nt; const int nmax2 = 20; for( int i=0; i nt; const int nmax2 = 20; for( int i=-nmax2; iNorm( ); }; explicit intVec17( const int d ) : dim( 17 ), length( 0.0 ) { for( int i=0; iNorm( ); }; ~intVec17( void ) { }; int Norm( void ) const { long dtemp = 0; for( int i=0; i tree; intVec17 vAll[vectorsize]; /* keep a list of all of the input so we can find particular entries */ double rmax = -DBL_MAX; double rmin = DBL_MAX; intVec17 v17min; /* to be the point nearest to the origin */ intVec17 v17max; /* to be the point farthest from the origin */ /* All of the coordinate values will be in the range 0-RHrand::RHRAND_MAX. In other words, all of the data points will be within a 17-D cube that has a corner at the origin of the space. */ for( int i=0; i rmax ) { rmax = v.Norm( ); v17max = v; } tree.insert( v ); vAll[i] = v; } double estdim = tree.GetDimEstimate(0.01)+tree.GetDimEstimateEsd(); if ( estdim < 3.5) { ++g_errorCount; fprintf(stdout, "testBigIntVec: dimension estimate %g < 3.5\n",estdim); } else { fprintf(stdout, "testBigIntVec: dimension estimate %g\n",estdim); } timetreecommand(tree, "testBigIntVector",{ { /* Find the point farthest from the point that was nearest the origin. */ intVec17 vFarthest; tree.FarthestNeighbor( vFarthest, v17min ); /* Brute force search for the farthest */ intVec17 vSearch; double dmax = -DBL_MAX; for( int i=0; i dmax ) { dmax = ( vAll[i] - v17min ).Norm( ); vSearch = vAll[i]; } } int distdiff = (int)((vSearch-v17min).Norm( )-(vFarthest-v17min).Norm( )); distdiff = (distdiff<0)?-distdiff:distdiff; if( distdiff > DBL_MIN ) { ++g_errorCount; fprintf(stdout, "in testBigIntVector, apparently FarthestNeighbor has failed\n" ); } } }); timetreecommand(tree, "testBigIntVector Left",{ { /* Find the point farthest from the point that was nearest the origin. */ intVec17 vFarthest; tree.LeftFarthestNeighbor( vFarthest, v17min ); /* Brute force search for the farthest */ intVec17 vSearch; double dmax = -DBL_MAX; for( int i=0; i dmax ) { dmax = ( vAll[i] - v17min ).Norm( ); vSearch = vAll[i]; } } int distdiff = (int)((vSearch-v17min).Norm( )-(vFarthest-v17min).Norm( )); distdiff = (distdiff<0)?-distdiff:distdiff; if( distdiff > DBL_MIN ) { ++g_errorCount; fprintf(stdout, "in testBigIntVector Left, apparently FarthestNeighbor has failed\n" ); } } }); { /* somewhere in the middle, find a point and its nearest neighbor */ /* make sure that each includes the other in sphere search */ const intVec17 vBox17Center( RHrand::RHRAND_MAX/2 ); intVec17 vNearCenter; intVec17 vCloseToNearCenter; const bool bFoundNear = tree.NearestNeighbor( (int)RHrand::RHRAND_MAX*17, vNearCenter, vBox17Center ); if( ! bFoundNear ) { ++g_errorCount; fprintf(stdout, "testBigIntVector: NearestNeighbor found no points\n" ); } CNearTree sphereReturn; // really, the only way to get the next section perfectly right is to do a // binary search until exactly 2 points are found. (or do a linear search thru the points) const int radius = 2*(int)(RHrand::RHRAND_MAX/2*sqrt(17.)); // hand-tuned value unsigned long iFoundNearCenter = (unsigned long)tree.FindInSphere( radius, sphereReturn, vNearCenter ); int searchRadius = radius/2; int delta = searchRadius; int count = 0; while( iFoundNearCenter != 2 && count < 100 ) { iFoundNearCenter = (unsigned long)tree.FindInSphere( searchRadius, sphereReturn, vNearCenter ); if( iFoundNearCenter > 2 ) { searchRadius = searchRadius - delta/2; } else if( iFoundNearCenter < 2 ) { searchRadius = searchRadius + delta/2; } delta /= 2; ++count; } // end while if( iFoundNearCenter < 2 ) { ++g_errorCount; fprintf(stdout, "testBigIntVector: FindInSphere found %lu points, instead of 2\n", (unsigned long)iFoundNearCenter ); } /* Brute force search for the point closest to the point closest to the center */ double dmin = DBL_MAX; for( unsigned long i=0; i void test2Containers_InSphere( T1 & t1, T2 & t2 ) /*=======================================================================*/ { t1.clear( ); t2.clear( ); for( int i=0; i<10; ++i ) { t1.insert( t1.end( ), i ); } CNearTree nt(t1); nt.insert( t1 ); { const unsigned long nFound = nt.FindInSphere( 1.1, t2, 5 ); if( nFound != 6 && nFound != 3 ) // sets do not allow duplicates { ++g_errorCount; fprintf(stdout, "test2Containers_InSphere: Found wrong # points %lu, expected 3 or 6\n", (unsigned long)nFound ); } if( nFound != t2.size( ) && nFound/2 != t2.size( ) ) // sets do not allow duplicates { ++g_errorCount; fprintf(stdout, "test2Containers_InSphere: size(t2) %lu !=nFound\n", (unsigned long)t2.size( ) ); } } { const unsigned long nFound = nt.LeftFindInSphere( 1.1, t2, 5 ); if( nFound != 6 && nFound != 3 ) // sets do not allow duplicates { ++g_errorCount; fprintf(stdout, "test2Containers_LeftInSphere: Found wrong # points %lu, expected 3 or 6\n", (unsigned long)nFound ); } if( nFound != t2.size( ) && nFound/2 != t2.size( ) ) // sets do not allow duplicates { ++g_errorCount; fprintf(stdout, "test2Containers_LeftInSphere: size(t2) %lu !=nFound\n", (unsigned long)t2.size( ) ); } } } // end test2Containers_InSphere /*=======================================================================*/ // test2Containers_OutSphere // // for FindOutSphere : // for testing both insertion of a container using a constructor and insertion // from a container and return of data using a container /*=======================================================================*/ template< typename T1, typename T2 > void test2Containers_OutSphere( T1 & t1, T2 & t2 ) /*=======================================================================*/ { t1.clear( ); t2.clear( ); for( int i=0; i<10; ++i ) { t1.insert( t1.end( ), i ); } CNearTree nt(t1); nt.insert( t1 ); { const unsigned long nFound = nt.FindOutSphere( 1.1, t2, 5 ); if( nFound != 14 && nFound != 7 ) // sets do not allow duplicates { ++g_errorCount; fprintf(stdout, "test2Containers_OutSphere: Found wrong # points %lu, expected 7 or 14\n", (unsigned long)nFound ); } if( nFound != t2.size( ) && nFound/2 != t2.size( ) ) // sets do not allow duplicates { ++g_errorCount; fprintf(stdout, "test2Containers_OutSphere: size(t2) %lu !=nFound\n", (unsigned long)t2.size( ) ); } }; { const unsigned long nFound = nt.LeftFindOutSphere( 1.1, t2, 5 ); if( nFound != 14 && nFound != 7 ) // sets do not allow duplicates { ++g_errorCount; fprintf(stdout, "test2Containers_LeftOutSphere: Found wrong # points %lu, expected 7 or 14\n", (unsigned long)nFound ); } if( nFound != t2.size( ) && nFound/2 != t2.size( ) ) // sets do not allow duplicates { ++g_errorCount; fprintf(stdout, "test2Containers_LeftOutSphere: size(t2) %lu !=nFound\n", (unsigned long)t2.size( ) ); } }; } // end test2Containers_OutSphere /*=======================================================================*/ // test2Containers_InAnnulus // // for FindInAnnulus : // for testing both insertion of a container using a constructor and insertion // from a container and return of data using a container /*=======================================================================*/ template< typename T1, typename T2 > void test2Containers_InAnnulus( T1 & t1, T2 & t2 ) /*=======================================================================*/ { t1.clear( ); t2.clear( ); for( int i=0; i<10; ++i ) { t1.insert( t1.end( ), i ); } CNearTree nt(t1); nt.insert( t1 ); { const unsigned long nFound = nt.FindInAnnulus( 1.1, 3.9, t2, 5 ); if( nFound != 8 && nFound != 4 ) { ++g_errorCount; fprintf(stdout, "test2Containers_InAnnulus: Found wrong # points %lu, expected 8 or 4\n", (unsigned long)nFound ); } if( nFound != t2.size( ) && nFound/2 != t2.size( ) ) // sets do not allow duplicates { ++g_errorCount; fprintf(stdout, "test2Containers_InAnnulus: size(t2) %lu !=nFound\n", (unsigned long)t2.size( ) ); } }; { const unsigned long nFound = nt.LeftFindInAnnulus( 1.1, 3.9, t2, 5 ); if( nFound != 8 && nFound != 4 ) { ++g_errorCount; fprintf(stdout, "test2Containers_LeftInAnnulus: Found wrong # points %lu, expected 8 or 4\n", (unsigned long)nFound ); } if( nFound != t2.size( ) && nFound/2 != t2.size( ) ) // sets do not allow duplicates { ++g_errorCount; fprintf(stdout, "test2Containers_LeftInAnnulus: size(t2) %lu !=nFound\n", (unsigned long)t2.size( ) ); } }; } // end test2Containers_InAnnulus /*=======================================================================*/ void testSTLContainerInput( void ) { { std::vector v; std::vector vb; for( int i=0; i<10; ++i ) { v.push_back( i ); } { // test the constructors CNearTree tv(v); if( tv.size() != 10 ) { ++g_errorCount; fprintf(stdout, "testSTLContainerInput: vector constructor has wrong count\n" ); } } { // test the inserters CNearTree tv; tv.insert( v ); if( tv.size() != 10 ) { ++g_errorCount; fprintf(stdout, "testSTLContainerInput: vector insertion has wrong count\n" ); } } { // test the inserters CNearTree tv; tv.insert( v ); CNearTree t; CNearTree tb; test2Containers_InSphere( t, tb ); test2Containers_InSphere( t, v ); test2Containers_InSphere( v, tb ); test2Containers_InSphere( v, vb ); test2Containers_OutSphere( t, tb ); test2Containers_OutSphere( t, v ); test2Containers_OutSphere( v, tb ); test2Containers_OutSphere( v, vb ); test2Containers_InAnnulus( t, tb ); test2Containers_InAnnulus( t, v ); test2Containers_InAnnulus( v, tb ); test2Containers_InAnnulus( v, vb ); } } { std::list l; std::list lb; for( int i=0; i<10; ++i ) { l.push_back( i ); } { // test the constructors CNearTree tl(l); if( tl.size() != 10 ) { ++g_errorCount; fprintf(stdout, "testSTLContainerInput: list constructor has wrong count\n" ); } } { // test the inserters CNearTree tl; tl.insert( l ); if( tl.size() != 10 ) { ++g_errorCount; fprintf(stdout, "testSTLContainerInput: list insertion has wrong count\n" ); } } { // test the inserters CNearTree tl; tl.insert( l ); CNearTree t; CNearTree tb; test2Containers_InSphere( t, tb ); test2Containers_InSphere( t, l ); test2Containers_InSphere( l, tb ); test2Containers_InSphere( l, lb ); test2Containers_OutSphere( t, tb ); test2Containers_OutSphere( t, l ); test2Containers_OutSphere( l, tb ); test2Containers_OutSphere( l, lb ); test2Containers_InAnnulus( t, tb ); test2Containers_InAnnulus( t, l ); test2Containers_InAnnulus( l, tb ); test2Containers_InAnnulus( l, lb ); } } { std::set s; std::set sb; for( int i=0; i<10; ++i ) { s.insert( i ); } { // test the constructors CNearTree ts(s); if( ts.size() != 10 ) { ++g_errorCount; fprintf(stdout, "testSTLContainerInput: set constructor has wrong count\n" ); } } { // test the inserters CNearTree ts; ts.insert( s ); if( ts.size() != 10 ) { ++g_errorCount; fprintf(stdout, "testSTLContainerInput: set insertion has wrong count\n" ); } } { // test the inserters CNearTree ts; ts.insert( s ); CNearTree t; CNearTree tb; test2Containers_InSphere( t, tb ); test2Containers_InSphere( t, s ); test2Containers_InSphere( s, tb ); test2Containers_InSphere( s, sb ); test2Containers_OutSphere( t, tb ); test2Containers_OutSphere( t, s ); test2Containers_OutSphere( s, tb ); test2Containers_OutSphere( s, sb ); test2Containers_InAnnulus( t, tb ); test2Containers_InAnnulus( t, s ); test2Containers_InAnnulus( s, tb ); test2Containers_InAnnulus( s, sb ); } } } // testSTLContainerInput /*=======================================================================*/ void testNearTreeInsertion ( void ) /*=======================================================================*/ { CNearTree nt1; CNearTree nt2; int count = 0; const int nInTree = 10; for ( int i=0; i ntI; //for( int i=0; i ntD; //for( int i=0; i tree; CNearTree outTree; std::vector outIndices; { const int searchPoint = 50; const long nToFind0 = 0; const double radius0 = 1000.0; const size_t lFound0 = tree.FindK_NearestNeighbors( nToFind0, radius0, outTree, searchPoint ); outTree.CompleteDelayedInsert( ); if( lFound0 != 0 ) { ++g_errorCount; fprintf(stdout, "testKNearFar, Near: #0: found wrong count %ld\n", (long)lFound0); } } { const int searchPoint = 50; const long nToFind0 = 0; const double radius0 = 1000.0; const size_t lFound0 = tree.LeftFindK_NearestNeighbors( nToFind0, radius0, outTree, searchPoint ); outTree.CompleteDelayedInsert( ); if( lFound0 != 0 ) { ++g_errorCount; fprintf(stdout, "testKNearFar, Left Near: #0: found wrong count %ld\n", (long)lFound0); } } { const int searchPoint = 50; const long nToFind0 = 0; const double radius0 = 1000.0; const size_t lFound0 = tree.FindK_NearestNeighbors( nToFind0, radius0, outTree, outIndices, searchPoint ); outTree.CompleteDelayedInsert( ); if( lFound0 != 0 || outIndices.size() != 0 ) { ++g_errorCount; fprintf(stdout, "testKNearFar, Near: #0: found wrong count %ld and unexpected indices %ld \n", (long)lFound0, (long)outIndices.size()); } } { const int searchPoint = 50; const long nToFind0 = 0; const double radius0 = 1000.0; const size_t lFound0 = tree.LeftFindK_NearestNeighbors( nToFind0, radius0, outTree, outIndices, searchPoint ); outTree.CompleteDelayedInsert( ); if( lFound0 != 0 || outIndices.size() != 0 ) { ++g_errorCount; fprintf(stdout, "testKNearFar, Left Near: #0: found wrong count %ld and unexpected indices %ld \n", (long)lFound0, (long)outIndices.size()); } } for( int i=0; i<100; ++i ) { tree.insert( i ); } { const int searchPoint = 50; const long nToFind1 = 13; const double radius1 = 1000.0; const size_t lFound1 = tree.FindK_NearestNeighbors( nToFind1, radius1, outTree, searchPoint ); outTree.CompleteDelayedInsert( ); if( lFound1 != 13 ) { ++g_errorCount; fprintf(stdout, "testKNearFar, Near: #1: found wrong count %ld\n", (long)lFound1 ); } } { const int searchPoint = 50; const long nToFind1 = 13; const double radius1 = 1000.0; const size_t lFound1 = tree.LeftFindK_NearestNeighbors( nToFind1, radius1, outTree, searchPoint ); outTree.CompleteDelayedInsert( ); if( lFound1 != 13 ) { ++g_errorCount; fprintf(stdout, "testKNearFar, Left Near: #1: found wrong count %ld\n", (long)lFound1 ); } } { const int searchPoint = 50; const long nToFind1 = 13; const double radius1 = 1000.0; const size_t lFound1 = tree.FindK_NearestNeighbors( nToFind1, radius1, outTree, outIndices, searchPoint ); outTree.CompleteDelayedInsert( ); if( lFound1 != 13 || outIndices.size() !=13) { ++g_errorCount; fprintf(stdout, "testKNearFar, Near: #1: found wrong count %ld or wrong indices %ld\n", (long)lFound1, (long)outIndices.size()); } else { for (size_t ii = 0; ii < outIndices.size(); ii++) { if (tree[outIndices[ii]] != outTree[ii]) { ++g_errorCount; fprintf(stdout, "testKNearFar, Near: #1: mismatch between tree[%ld] and outTree[%ld]\n", (long)outIndices[ii], (long)ii); } } } } { const int searchPoint = 50; const long nToFind1 = 13; const double radius1 = 1000.0; const size_t lFound1 = tree.LeftFindK_NearestNeighbors( nToFind1, radius1, outTree, outIndices, searchPoint ); outTree.CompleteDelayedInsert( ); if( lFound1 != 13 || outIndices.size() !=13) { ++g_errorCount; fprintf(stdout, "testKNearFar, Left Near: #1: found wrong count %ld or wrong indices %ld\n", (long)lFound1, (long)outIndices.size()); } else { for (size_t ii = 0; ii < outIndices.size(); ii++) { if (tree[outIndices[ii]] != outTree[ii]) { ++g_errorCount; fprintf(stdout, "testKNearFar, Left Near: #1: mismatch between tree[%ld] and outTree[%ld]\n", (long)outIndices[ii], (long)ii); } } } } { const int searchPoint = 98; const long nToFind2 = 13; const double radius2 = 3.5; const size_t lFound2 = tree.FindK_NearestNeighbors( nToFind2, radius2, outTree, searchPoint ); outTree.CompleteDelayedInsert( ); if( lFound2 != 5 ) { ++g_errorCount; fprintf(stdout, "testKNearFar, Near: found wrong count #2\n" ); } } { const int searchPoint = 50; const long nToFind3 = 7; const double radius3 = 12; const size_t lFound3 = tree.FindK_NearestNeighbors( nToFind3, radius3, outTree, searchPoint ); outTree.CompleteDelayedInsert( ); if( lFound3 != 7u ) { ++g_errorCount; fprintf(stdout, "testKNearFar, Near: found wrong count #3\n" ); } } { const int searchPoint = 2; const long nToFind4 = 7; const double radius4 = 12; const size_t lFound4 = tree.FindK_NearestNeighbors( nToFind4, radius4, outTree, searchPoint ); outTree.CompleteDelayedInsert( ); if( lFound4 != 7u ) { ++g_errorCount; fprintf(stdout, "testKNearFar, Near: found wrong count #4\n" ); } } { const int searchPoint = 2; const long nToFind5 = 7; const double radius5 = 3.5; std::vector outVector; const size_t lFound5 = tree.FindK_NearestNeighbors( nToFind5, radius5, outVector, searchPoint ); if( lFound5 != 6u ) { ++g_errorCount; fprintf(stdout, "testKNearFar, Near: found wrong count #5\n" ); } } { const int searchPoint = 2; const long nToFind5 = 7; const double radius5 = 3.5; std::list outList; const size_t lFound6 = tree.FindK_NearestNeighbors( nToFind5, radius5, outList, searchPoint ); if( lFound6 != 6u ) { ++g_errorCount; fprintf(stdout, "testKNearFar, Near: found wrong count #6\n" ); } } { CNearTree tree; CNearTree outTree; const unsigned int n2Store = 20; for ( unsigned int i=0; i outVector; const size_t lFound5 = tree.FindK_FarthestNeighbors( nToFind5, outVector, searchPoint ); if( lFound5 != 7u ) { ++g_errorCount; fprintf(stdout, "testKNearFar, Far: found wrong count #5\n" ); } } { const int searchPoint = 200; const long nToFind6 = 7; std::list outList; const size_t lFound6 = tree.FindK_FarthestNeighbors( nToFind6, outList, searchPoint ); if( lFound6 != 7u ) { ++g_errorCount; fprintf(stdout, "testKNearFar, Far: found wrong count #6\n" ); } } { const int searchPoint = 2; const long nToFind7 = 7; std::set outSet; const size_t lFound7 = tree.FindK_FarthestNeighbors( nToFind7, outSet, searchPoint ); if( lFound7 != 7u ) { ++g_errorCount; fprintf(stdout, "testKNearFar, Far: found wrong count #7\n" ); } } } // end testKNearFar void testSeparation( void ) { CNearTree t; const int imin = 0; const int imax = 2000000; for ( int i=imin; i container; container group1, group2; std::vector group1_indices; std::vector group2_indices; t.BelongsToPoints( imin, imax, group1, group2 ); if ((long int)group1.size() != (long int)group2.size()) { ++g_errorCount; fprintf( stdout, "testSeparation: in %ld out %ld\n", (long int)group1.size(), (long int)group2.size() ); } group1.clear(); group2.clear(); t.BelongsToPoints( imin, imax, group1, group2, group1_indices, group2_indices); if ((long int)group1.size() != (long int)group2.size()) { ++g_errorCount; fprintf( stdout, "testSeparation: in %ld out %ld\n", (long int)group1.size(), (long int)group2.size() ); } if ((long int)group1_indices.size() != (long int)group1.size()) { ++g_errorCount; fprintf( stdout, "testSeparation: in indices %ld in %ld\n", (long int)group1_indices.size(), (long int)group2.size() ); } if ((long int)group2_indices.size() != (long int)group2.size()) { ++g_errorCount; fprintf( stdout, "testSeparation: out indices %ld out %ld\n", (long int)group1_indices.size(), (long int)group2.size() ); } for (size_t ii=0; ii < group1.size(); ii++) { if (t[group1_indices[ii]] != group1[ii]) { ++g_errorCount; fprintf( stdout, "testSeparation: group1 index error index t[%ld] != group1[%ld] \n", (long)group1_indices[ii], (long)ii); } } for (size_t ii=0; ii < group2.size(); ii++) { if (t[group2_indices[ii]] != group2[ii]) { ++g_errorCount; fprintf( stdout, "testSeparation: group2 index error index t[%ld] != group2[%ld] \n", (long)group2_indices[ii], (long)ii); } } } void testMergeConstructor( void ) { CNearTree nt1; std::vector nt2; int count = 0; const int nInTree = 10; for ( int i=0; i test0( nt2 ); // one vector const CNearTree test1( nt1, nt1 );// two neartrees const CNearTree test2( nt1, nt2 );// neartree and a vector const CNearTree test3( nt2, nt2 );// two vectors const long lFound = test2.size( ); if( lFound != 2*nInTree ) { ++g_errorCount; fprintf(stdout, "testMergeConstructor: found wrong count\n" ); } } void testOperatorPlusEquals( void ) { CNearTree nt1; std::vector nt2; std::set s2; int count = 0; const int nInTree = 10; for ( int i=0; i nt1a(nt1) ; for ( int i=0; i nt1; CNearTree nt2; int count = 0; const int nInTree = 2*5; // tests below depend on this being an even number for ( int i=0; i nt1; CNearTree nt2; std::vector v2; const int nInTree = 2*5; // tests below depend on this being an even number for ( int i=0; i nt1a = CNearTree(nt1); for ( int i=0; i nt1b = CNearTree(nt1a); nt1b.set_symmetric_difference( v2 ); const long lFounda = nt1a.size( ); if( lFounda != nInTree ) { ++g_errorCount; fprintf(stdout, "testSetSymmetricDifference-a, found wrong count \n" ); } } void testCentroid( ) { { std::vector v; for ( int i=0; i<20; ++i ) { v.push_back( i ); } CNearTree nt( v ); const double cm1 = nt.Centroid( ); const double cm2 = CNearTree::Centroid( v ); if ( cm1 != cm2 ) { ++g_errorCount; fprintf(stdout, "testCentroid-a, cm1 %f cm2 %f\n", cm1, cm2 ); } } { std::vector v; for ( int i=0; i<20; ++i ) { v.push_back( i ); } CNearTree nt( v ); const double cm1 = nt.Centroid( ); const double cm2 = CNearTree::Centroid( v ); if ( cm1 != cm2 ) { ++g_errorCount; fprintf(stdout, "testCentroid-b, cm1 %f cm2 %f\n", cm1, cm2 ); } } } template< typename T > std::vector LloydCycleStep( const CNearTree& coord, const std::vector& vIn ) { std::vector v(vIn); std::vector vSum(v.size( ), 0); std::vector vCount( v.size( ) ); typename CNearTree::iterator it; for ( it=coord.begin( ); it!=coord.end( ); ++it ) { double dmin = DBL_MAX; int indexVSumMin=0; int indexVMin = 0; for ( unsigned int i=0; i 0.0 ) { vSum[i] /= double(vCount[i]); } } return( vSum ); } void testLloyd( ) { CNearTree vdata; std::vector vk; for ( int i=0; i<20000; ++i ) { vdata.insert( double(i) ); } size_t estdim = (size_t)(0.5+vdata.GetDimEstimate()); if ( estdim != 1) { ++g_errorCount; fprintf(stdout, "testLloyd: dimension estimate %ld != 1\n",(long)estdim); } vk.push_back( double(-12) ); vk.push_back( double(0) ); vk.push_back( double(17) ); for ( int i=0; i<60; ++i ) { std::vector vOut = LloydCycleStep( vdata, vk ); if (i > 35 && (vk[0] != 3333. || vk[1] != 10000. || vk[2] != 16666.5)) { ++g_errorCount; fprintf( stdout, "testLoyd cycle %d ", i); for ( unsigned int j=0; j 35) break; } vk = vOut; } } //> Lloyd cycle step //> //> put starting points (SPs) in a neartree //> //> CNearTree LloydCycle( const CNearTree& data, const CNearTree& SP ) //> make a vector v of Vector_3 of size SP.size( ) and one of long same size //> for each data point //> get iterator to nearest SP //> v[it->GetPosition()] += *it; //> ++count[it->GetPosition()]; //> end for //> //> foreach in v //> v[i] /= count[i] //> //> return (CNearTree(v)); ./NearTree-3.1.1/rhrand.h0000644002342100234170000001177211640401607015062 0ustar bernstehfaculty/* * rhrand.h * RHrand * * Based on: * Random Number generator by Rob Harrison, derived from * "one in J.M.Hammersley and D.C. Handscomb, "Monte Carlo * Methods," Methuen & Co., London and Wiley & Sons, New * York, 1964, p47". See also, D. E. Knuth "The Art of * Computer Programming", Volume 2, "Seminumerical * Alogorithms, Third Edition, Addison-Wesley, Reading MA, * 1997. * * This adaptation by H. J. Bernstein * Copyright 2009 Rob Harrison, Larry Andrews and Herbert J. Bernstein * */ /********************************************************************** * * * YOU MAY REDISTRIBUTE THE rhrand API UNDER THE TERMS OF THE LGPL * * * **********************************************************************/ /************************* LGPL NOTICES ******************************* * * * This library is free software; you can redistribute it and/or * * modify it under the terms of the GNU Lesser General Public * * License as published by the Free Software Foundation; either * * version 2.1 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 * * Lesser General Public License for more details. * * * * You should have received a copy of the GNU Lesser General Public * * License along with this library; if not, write to the Free * * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, * * MA 02110-1301 USA * * * **********************************************************************/ #ifndef RHRAND_H_INCLUDED #define RHRAND_H_INCLUDED #ifdef __cplusplus #include class RHrand { private: double randomNumberBuffer[56]; int indx; int jndx; int kndx; double dTemp; public: static const int RHRAND_MAX = 32767; RHrand( void ) { /* default constructor */ srandom(0); }; RHrand( const int iseed ) { /* constructor with seed */ srandom(iseed); }; ~RHrand(void ) { /* nothing to do for destructor */ }; void srandom ( const int iseed ) { jndx = iseed; if (jndx < 0) jndx = -jndx; for( indx=0; indx<(int)(sizeof(randomNumberBuffer)/sizeof(randomNumberBuffer[0])); ++indx ) { jndx = (jndx*2349 + 14867)%32767; randomNumberBuffer[indx] = fabs((double)(jndx/32767.0)); } indx = 55; kndx = 54; jndx = 31; return; }; double urand( void ) { indx = indx%55 + 1; jndx = jndx%55 + 1; kndx = kndx%55 + 1; randomNumberBuffer[indx-1] = modf( randomNumberBuffer[jndx-1]+randomNumberBuffer[kndx-1], &dTemp ); return randomNumberBuffer[indx-1]; }; int random( void ) { return (int)(urand()*((double)RHRAND_MAX)); }; }; #ifndef RHRAND_NOCCODE extern "C" { #endif #endif #ifndef RHRAND_NOCCODE #include typedef struct CRHrand_ { double buffer[56]; int indx; int jndx; int kndx; double dTemp; } CRHrand; typedef CRHrand * CRHrandHandle; #define CRHRAND_MAX 32767 #define CRHrandSrandom(randhandle,iseed) { \ (randhandle)->jndx = iseed; \ if ((randhandle)->jndx < 0) (randhandle)->jndx = -(randhandle)->jndx; \ for((randhandle)->indx=0; (randhandle)->indx<(sizeof((randhandle)->buffer)/sizeof((randhandle)->buffer[0])); ++(randhandle)->indx ) \ { \ (randhandle)->jndx = ((randhandle)->jndx*2349 + 14867)%32767; \ ((randhandle)->buffer)[(randhandle)->indx] = fabs((double)(((randhandle)->jndx)/32767.0)); \ } \ (randhandle)->indx = 55; \ (randhandle)->kndx = 54; \ (randhandle)->jndx = 31; \ } #define CRHrandUrand(randhandle) ( \ (randhandle)->indx = (randhandle)->indx%55 + 1, \ (randhandle)->jndx = (randhandle)->jndx%55 + 1, \ (randhandle)->kndx = (randhandle)->kndx%55 + 1, \ ((randhandle)->buffer)[(randhandle)->indx-1] \ = modf( ((randhandle)->buffer)[(randhandle)->jndx-1]+ \ ((randhandle)->buffer)[(randhandle)->kndx-1], &(randhandle)->dTemp ) , \ ((randhandle)->buffer)[(randhandle)->indx-1] ) #define CRHrandRandom(randhandle) ((int)(CRHrandUrand(randhandle)*(double)CRHRAND_MAX)) #ifdef __cplusplus } #endif #endif #endif ./NearTree-3.1.1/main.c0000644002342100234170000002033711640401607014520 0ustar bernstehfaculty/* * main.c * NearTree * * Copyright 2001, 2008 Larry Andrews. All rights reserved * Revised 12 Dec 2008 for sourceforge release -- H. J. Bernstein */ /********************************************************************** * * * YOU MAY REDISTRIBUTE NearTree UNDER THE TERMS OF THE LGPL * * * **********************************************************************/ /************************* LGPL NOTICES ******************************* * * * This library is free software; you can redistribute it and/or * * modify it under the terms of the GNU Lesser General Public * * License as published by the Free Software Foundation; either * * version 2.1 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 * * Lesser General Public License for more details. * * * * You should have received a copy of the GNU Lesser General Public * * License along with this library; if not, write to the Free * * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, * * MA 02110-1301 USA * * * **********************************************************************/ #include #include #include #include #include #ifndef USE_LOCAL_HEADERS #include #else #include "rhrand.h" #endif CRHrand rhr; #ifndef USE_LOCAL_HEADERS #include #else #include "CNearTree.h" #endif int main ( int argc, char** argv ) { CNearTreeHandle treehandle; double v[3],vSearch[3]; double * vBest; void * vvBest; CVectorHandle vReturn; CVectorHandle dDs; CVectorHandle stIndices; CVectorHandle oReturn; double xdist; long i,j,k; const long lMaxRow = 10; double dRad = 0.6; CNearTreeCreate(&treehandle,3,CNEARTREE_TYPE_DOUBLE); CVectorCreate(&vReturn,sizeof(void *),10); CVectorCreate(&oReturn,sizeof(void *),10); CVectorCreate(&dDs,sizeof(double),10); CVectorCreate(&stIndices,sizeof(size_t),10); if (argc <= 1) { CRHrandSrandom(&rhr, (int)time( NULL ) ); /* use the current time to seed the random number generator */ } else { CRHrandSrandom(&rhr, (int)atoi(argv[1])); } /*--------------------------------------- build up a library of points to search among ---------------------------------------*/ for ( k=-1; k<=lMaxRow; k++ ) { for ( j=-1; j<=lMaxRow; j++) { for ( i= lMaxRow ; i>=-1; i-- ) { v[0] = (double)i; v[1] = (double)j; v[2] = (double)k; CNearTreeInsert(treehandle,&v[0],NULL); } /* for i */ } /* for j */ } /* for k */ fprintf(stdout,"\n"); /*--------------------------------------- Done building the tree; now try a retrieval ---------------------------------------*/ for ( i=0; i<10; i++ ) { double x, y, z; dRad += 0.05; x = CRHrandUrand(&rhr) * ((double) lMaxRow ); y = x; z = ( 1.25 * ((double) lMaxRow) - 1.5 * x ); vSearch[0] = x; vSearch[1] = 0.5*(x+y); vSearch[2] = z; fprintf(stdout,"Trial %ld from probe point [%g, %g, %g]\n", i, vSearch[0], vSearch[1], vSearch[2]); /* find the nearest point to vSearch */ if ( !CNearTreeNearestNeighbor(treehandle,dRad,&vvBest,NULL,vSearch)) { vBest = (double *)vvBest; fprintf(stdout," Closest distance %g to [%g, %g, %g]\n", sqrt(CNearTreeDistsq((void *)vSearch,vvBest,3,CNEARTREE_TYPE_DOUBLE)), vBest[0],vBest[1],vBest[2]); } else { fprintf(stdout," ***** nothing within %g of [%g, %g, %g]\n", dRad, vSearch[0], vSearch[1], vSearch[2]); } /* find the farthest point from vSearch */ if ( !CNearTreeFarthestNeighbor(treehandle,&vvBest,NULL,vSearch)) { vBest = (double *)vvBest; fprintf(stdout," Farthest distance %g to [%g, %g, %g]\n", sqrt(CNearTreeDistsq(vSearch,vBest,3,CNEARTREE_TYPE_DOUBLE)), vBest[0],vBest[1],vBest[2]); } else { fprintf(stdout," No Farthest object found\n"); } /* search for all points within a "sphere" out to radius dRad */ CVectorClear( dDs ); CVectorClear( stIndices ); CVectorClear( vReturn ); CVectorClear( oReturn ); if ( !CNearTreeFindInSphere( treehandle, dRad, vReturn, oReturn, vSearch,1 ) ) { size_t index, jndex, kndex, tndex; void * prevpoint; void * foundpoint; void * localmetrics; void * localindices; int redo; fprintf(stdout," Returned %lu items within %g of [%g,%g,%g]\n", (long unsigned int)vReturn->size, dRad, vSearch[0], vSearch[1], vSearch[2]); for (index=0; index < CVectorSize(vReturn); index++) { CVectorGetElement(vReturn,&foundpoint,index); xdist = CNearTreeDist(treehandle,(void CNEARTREE_FAR *)foundpoint, (void CNEARTREE_FAR *)vSearch); CNearTreeSortIn(dDs,stIndices,xdist,index,CVectorSize(vReturn)); } CVectorGetElementptr(dDs, &localmetrics,0); CVectorGetElementptr(stIndices, &localindices,0); redo = 1; while (redo == 1) { redo = 0; for (index=1; index < CVectorSize(stIndices); index++) { CVectorGetElement(stIndices,&jndex,index-1); CVectorGetElement(stIndices,&kndex,index); CVectorGetElement(vReturn,&prevpoint,jndex); CVectorGetElement(vReturn,&foundpoint,kndex); if (fabs(((double *)localmetrics)[jndex]-((double *)localmetrics)[kndex]) <=DBL_EPSILON*fabs(((double*)localmetrics)[jndex]+((double*)localmetrics)[kndex])) { if ( ( ((double *)foundpoint)[0] < ((double *)prevpoint)[0] ) ||( ((double *)foundpoint)[0] == ((double *)prevpoint)[0] && ((double *)foundpoint)[1] < ((double *)prevpoint)[1]) || ( ((double *)foundpoint)[0] == ((double *)prevpoint)[0] && ((double *)foundpoint)[1] == ((double *)prevpoint)[1] && ((double *)foundpoint)[1] < ((double *)prevpoint)[1]) ) { tndex = ((size_t *)localindices)[index-1]; ((size_t *)localindices)[index-1] = ((size_t *)localindices)[index]; ((size_t *)localindices)[index] = tndex; CVectorSetFlags(stIndices,0); redo = 1; } } } } for (index=0; index < CVectorSize(stIndices); index++) { CVectorGetElement(stIndices,&jndex,index); CVectorGetElement(vReturn,&foundpoint,jndex); fprintf (stdout,"\t [%g,%g,%g]\n",((double *)foundpoint)[0], ((double *)foundpoint)[1], ((double *)foundpoint)[2]); } } fprintf(stdout," -------------------------------------------------------------\n"); } /* for i */ CNearTreeFree(&treehandle); return ( EXIT_SUCCESS ); } ./NearTree-3.1.1/README_NearTree.html0000644002342100234170000021660211640404077017046 0ustar bernstehfaculty NearTree -- function library efficiently solving the Nearest Neighbor Problem
CVector Get NearTree at SourceForge.net. Fast, secure and Free Open Source software downloads

NearTree

Release 3.1.1
23 April 2011 (revised 27 September 2011)
© Copyright 2001, 2008, 2009, 2010, 2011 Larry Andrews. All rights reserved
based on
Larry Andrews, "A template for the nearest neighbor problem",
C/C++ Users Journal, Volume 19 , Issue 11 (November 2001), 40 - 49 (2001), ISSN:1075-2838,
www.ddj.com/architect/184401449

Revised 12 Dec 2008, for sourceforge release, Larry Andrews and Herbert J. Bernstein
8 Jan 2009 Release 1.0 LCA and HJB
11 Jan 2009 Release 1.0.1 LCA and HJB
21 March 2009 Release 2.0 LCA and HJB
30 May 2009 Release 2.1 LCA and HJB
4 June 2009 Release 2.1.1 LCA and HJB
7 June 2009 Release 2.1.2 LCA and HJB
7 July 2009 Release 2.1.3 LCA and HJB
29 November 2009 Release 2.1.4 LCA
23 April 2010 Release 2.1.5 LCA and HJB
18 July 2010 Release 2.2 HJB
25 July 2010 Release 2.2.1 HJB
31 August 2010 Release 2.3 LCA
7 September 2010 Release 2.3.1 LCA
30 October 2010 Release 2.3.2 LCA
22 March 2011 Release 3.0 LCA and HJB
5 April 2011 Release 3.0.1 LCA and HJB
19 April 2011 Release 3.0.2 HJB
23 April 2011 Release 3.1 HJB
27 September 2011 Release 3.1.1 HJB

YOU MAY REDISTRIBUTE NearTree UNDER THE TERMS OF THE LGPL

LGPL NOTICES

This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 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* Lesser General Public License for more details.

You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA

This is a release of an API for finding nearest neighbors among points in spaces of arbitrary dimensions. This release provides a C++ template, TNear.h, and a C library, CNearTree.c, with example/test programs.

Release 3.1.1 adjusted the libtool version from 5:0:1 to 6:0:1 to avoid confusion on the SONAME of the library as requested by Teemu Ikonen for use as a Debian package.

Release 3.1 adjusted the randomization to be based on the depth rather than the population and added an optional detailed height calculation.

Release 3.0.2 added to randomization on insertion when the tree is not well balanced.

Release 3.0.1 updated the diameter calculation and fixed some documentation errors.

Release 3.0 (formerly named Release 2.4) is a major change to NearTree, restructuring the default search from left-first to balanced and adding hooks to collect information about the tree.

Release 2.3.2 adds optional returns of vectors of ordinals of found objects

Release 2.3.1 adds Centroid method for Lloyd clustering.

Release 2.3 added methods for clustering.

Release 2.2.1 was a minor revision to Release 2.2 to add an include of limits.h to TNear.h, primarily for MINGW use.

Release 2.2 added support for C code for fixed length string searches using a hamming distance norm, and for spherical and hemispherical geodesic norm based searches. Because of the addition of new type and norm flags, the version 2.2 shared libraries cannot be used to support binaries compiled against earlier headers and vice-versa.

Release 2.1.5 was a cleanup update to the 2.1 release of 30 May 2009 to increase portability, in five stages (2.1.1 on 4 June 2009, 2.1.2 on 7 June 2009, 2.1.3 on 7 July 2009, 2.1.4 on 29 November 2009 and 2.1.5 on 23 April 2010) dealing with the following issues:

  • Convert to use of a self-contained portable random-number generator from Rob Harrison (2.1.1)
  • Ensure wider use of const where appropriate (2.1.1)
  • Correct typos and unclear wording in the README (2.1.2)
  • Reorganize use of USE_LOCAL_HEADERS in CNearTreeTest.cpp (2.1.2)
  • Change FAR macro to CNEARTREE_FAR (2.1.3)
  • Add BelongsToPoints and SeparateByRadius (2.1.4)
  • Fix dimensions for rhrand (2.1.5)

The 2.1 release was a minor update to the 2.0 release of 21 March 2009 to deal with the following issues:

  • Make delayed insertion the default
  • Complete the containerization of TNear.h
  • Add code for K-nearest/farthest in TNear.h and in CNearTree.c
  • Correct the InAnnulus search filter

Release 2.0 was a major update to the 1.0 release of 8 January 2009 to deal with the following issues:

  • Replace use recursion with a stack, except in insertion logic
  • Replace use of double with templated DistanceType (usually double)
  • Provide constuctors to build NearTree from vectors, lists or sets
  • Change "Insert" to "insert" for consistency with other containers
  • Add access function "at" or array type references [], and provide contents of a neartree as a vector
  • Add iterator support
  • Provide delayed insertion logic
  • Functions added for searches outside of a sphere or in an annular region

Our thanks to Nicolas Brodu for suggesting the more general handling of the distance type.

Note: As Nicolas Brodu has noted, CNearTree is particularly well-suited to multi-threaded applications. However, if the same CNearTree is to be searched in multiple threads, it is important to complete all insertions and/or delayed insertions before parallel execution of parallel searches.


Contents



Installation

The NearTree package is available at www.sourceforge.net/projects/neartree. A source tarball is available at downloads.sourceforge.net/neartree/NearTree-3.1.1.tar.gz. Later tarballs may be available.

If you decide to simply use the TNear.h header to add nearest neighbor support to C++ code under Visual Studio, be sure to also use the rhrand.h and triple.h headers. It is no longer necessary to define USE_LOCAL_HEADERS, which is automatically defined if _MSC_VER is defined. For unix or MINGW, you will need to use the Makefile and to have libtool on your system. Be warned that the default libtool under Mac OS X will not work for this installation.

When the source tarball is downloaded and unpacked, you should have a directory NearTree-3.1.1. To see the current settings for a build execute

make

which should give the following information:


 PLEASE READ README_NearTree.txt and lgpl.txt
 
 Before making the NearTree libraries and example programs, check
 that the chosen settings are correct
 
 The current C++ and C compile commands are:
 
   libtool --mode=compile g++ -g -O2  -Wall -ansi -pedantic  \
      -DCNEARTREE_SAFE_TRIANG=1 -I.   -c
   libtool --mode=compile gcc -g -O2  -Wall -ansi -pedantic  \
      -DCNEARTREE_SAFE_TRIANG=1 -I.   -c
 
 The C API, CNearTree.c, depends on the sourceforge project CVector 
 You are currently setup to use the system defaults for CVector
 If that is not correct, define the variable CVECTOR_INCLUDE 

 The current library link command is:
 
   libtool --mode=link  gcc -version-info 6:0:1  \
     -no-undefined -rpath /usr/local/lib
 
 The current C++ and C library local, and C dynamic and static build commands are:
 
   libtool --mode=link g++ -no-undefined -g -O2  -Wall -ansi -pedantic \
      -DCNEARTREE_SAFE_TRIANG=1 -I. 
   libtool --mode=link gcc -g -O2  -Wall -ansi -pedantic \
      -DCNEARTREE_SAFE_TRIANG=1 -I. 
   libtool --mode=link gcc -no-undefined -g -O2  -Wall -ansi -pedantic \
      -DCNEARTREE_SAFE_TRIANG=1 -shared -I/usr/local/include
   libtool --mode=link gcc -g -O2  -Wall -ansi -pedantic  \
      -DCNEARTREE_SAFE_TRIANG=1 -static-libtool-libs -I/usr/local/include
 
 Before installing the NearTree library and example programs, check
 that the install directory and install commands are correct:
 
 The current values are :
 
   /usr/local 
   libtool --mode=install cp 
    
 
 To compile the NearTree library and example programs type:
 
   make clean
   make all
 
 To run a set of tests type:
 
   make tests
 
 To clean up the directories type:
 
   make clean
 
 To install the library and headers type:
 
   make install


If these settings need to be changed, edit Makefile. On some systems, e.g. Mac OS X, the default libtool is not appropriate. In that case you should install a recent version of libtool. The CVector kit has been tested with libtool versions 1.3.5 and 1.5.4. For MINGW, libtool version 2.2.6 and gcc version 4 are needed to work with shared libraries (DLLs). If the system libtool is not to be used, define the variable LIBTOOL to be the path to the libtool executable, e.g. in bash

export LIBTOOL=$HOME/bin/libtool

or in the Makefile

LIBTOOL = $(HOME)/bin/libtool

If you need to include local header files using #include "..." instead of #include <...>, define the variable USE_LOCAL_HEADERS. USE_LOCAL_HEADERS is the default for Visual Studio under Microsoft Windows.

Optionally, you may also define CNEARTREE_FORCEFLIP to maximize tree reorganization on insertion, CNEARTREE_NOFLIP to suppress tree reorganization on insertion, CNEARTREE_NODEFER to make all insertions immediate, CNEARTREE_FORCEPREPUNE to do searches first with a tighter estimate on the search radius, and CNEARTREE_NOPREPRUNE to suppress that behavior. The defaults are to do tree reorganization on insertion, to defer insertions, but not to preprune the search radius.

If you define CNEARTREE_INSTRUMENTED, code will be enabled to track node visits in searching the tree.

The triangle inequality that must be evaluated in building trees and retrieving data may not be evaluated correctly if the range of the three values is extremely large (>10**15 or so for doubles) or may be evaluated differently by some compilers in different parts of a program (due to differing usage of registers). The default in this API is to do the triangle inequality three different ways under the control of CNEARTREE_SAFE_TRIANG


#ifdef CNEARTREE_SAFE_TRIANG
#define TRIANG(a,b,c) (  (((b)+(c))-(a) >= 0) \
                      || ((b)-((a)-(c)) >= 0) \
                      || ((c)-((a)-(b)) >= 0))    
#else
#define TRIANG(a,b,c) (  (((b)+(c))-(a) >= 0))
#endif

Problems with the unsafe definition of TRIANG have been seen in Linux under gcc version 4 and in MS Window under VS 2003. There is a slight performance hit from the triple test. If maximal speed is critical and misidentification of nearest points by relative distance errors of about 1 part in 10**15 is not a serious problem, the definition of -DCNEARTREE_SAFE_TRIANG=1 can be removed from the definition of CFLAGS in the Makefile.

NOTE: A range of 10**15 is comparable to the diameter of the earth vs. the separation of two bonded atoms.



The C++ template: TNear.h

This is a revised release of

template <typename T, typename DistanceType=double, int distMinValue=-1 > class CNearTree;

implementing the Nearest Neighbor algorithm after Kalantari and McDonald, (IEEE Transactions on Software Engineering, v. SE-9, pp. 631-634,1983) modified to use recursion for insertions and recursion (original version) or a stack (current version) for searches instead of a double-linked tree and simplified. The default search algorithm no longer favors the left branch first, but follows the more balanced Kalantari and McDonald approach. The prior search algorithm is available in "Left" versions of the search routines doing a bit less checking for things like is the distance to the right less than the distance to the left.

This template is used to contain a collection of objects. After the collection has been loaded into this structure, it can be quickly queried for which object is "closest" to some probe object of the same type. The major restriction on applicability of the near-tree is that the algorithm only works if the objects obey the triangle inequality. The triangle rule states that the length of any side of a triangle cannot exceed the sum of the lengths of the other two sides.

CNearTree is the root class for the neartree. The actual data of the tree is stored in NearTreeNode objects descending from a CNearTree.

The types of objects that can be stored in the tree is quite broad. The biggest limitation is that the objects must reside in some sort of metric space and must obey the triangle rule. They must also be all of the same size because they are stored in an std::vector. If your application requires objects of varying storage, then your best way to use this code is to store pointers or handles and to write your own distance functions. Note that std::string is a pointer type variable and so can be stored directly.

The type of the objects to be stored is the only required template argument. The type of the distance measure (DistanceType) defaults to double. If your application is for an integer type, then the type for DistanceType can be your integer type. This has the potential for speeding the calculations by avoiding FP computation. Other general types can be used if desired, but you may need to also input a value of distMinValue.

The template argument distMinValue must be something that your class will understand as a negative number. The default input is negative one. Internally, that is cast to DistanceType. Since most uses will be for DistanceType to be double, that is a simple conversion. Obviously, for integer types, there is no problem either. The need for this value is to have something internally that is recognizable as smaller than the smallest "distance" that can exist between any two objects in your type. For most users, there is no need to input anything other than the default, -1. -1 must be castable to DistanceType. It seems unlikely that anyone would actually need this optional parameter, but it is here for completeness.

It is a design decision that this class cannot work for unsigned types. Verifying the triangle rule for unsigned types is more complex. Sorry, unsigned types are left as an exercise for the reader.

The user of this class needs to provide at least the following functionality for the template to work. For the built-in numerics of C++, they are provided by the system.

DistanceType Norm( void );
  // a function "Norm( void )" of the templated class
// to return DistanceType (usually will return a
// "length" of type double)
operator- ( ); // geometrical (vector) difference of two objects
// a copy constructor would be nice
// a constructor would be nice
// a destructor would be nice

The provided interface is:


    #include <TNear.h>

    CNearTree( void )   // constructor
       instantiated by something like:      CNearTree <T> vTree;
       for some type T
       
    CNearTree( const ContainerType<T> & o)    // constructor from containers, e.g. ...

    CNearTree( const std::vector<T> & o )     // constructor
    CNearTree( const std::list<T> & o )       // constructor
    CNearTree( const std::set<T> & o )        // constructor
    CNearTree( const CNearTree<T> & o )       // constructor

    CNearTree( const ContainerType<T> & o1,
                      const ContainerType<T> & o2) 
                                                              // constructor merging 2 containers, e.g. ...
    
    ~CNearTree( void )  // destructor
    
    void clear( void )  // clear the NearTree
    
    long GetFlags( void ) const                       // Get all execution flags
    void SetFlags( const long flags )                 // Set all execution flags
    long GetFlags( const long mask ) const     // Get execution flags within mask
    void SetFlags( const long flags, const long mask )
                                                                           // Set execution flags within mask
                                                                           
    // The available execution flags are
    
    static const long        NTF_NoPrePrune        = 1; //flag to suppress all search prepruning
    static const long        NTF_ForcePrePrune     = 2; //flag to force search prepruning
    static const long        NTF_NoFlip            = 4; //flag to suppress flips on insert
    static const long        NTF_ForceFlip         = 8; //flag to force flips on insert
    static const long        NTF_NoDefer           =16; //flag to prevent deferred insert

    
    template<typename InputContainer>
    CNearTree& operator=( const InputContainer& o )
                                                              // put container's contents into a NearTree,
                                                              // wiping out the current contents
    
    template<typename InputContainer>
    CNearTree& operator=( InputContainer& o )
                                                              // put container's contents into a NearTree,
                                                              // wiping out the current contents

    template<typename InputContainer>
    CNearTree& operator+=( const InputContainer& o )
                                                              // add a container's contents to a NearTree

    template<typename InputContainer>
    CNearTree& operator-=( const InputContainer& o )
                                                              // remove a container's contents from a NearTree

    template<typename InputContainer>
    CNearTree& set_symmetric_difference( const InputContainer&, o )
                                                              // remove the part of a container's 
                                                              // contents from a NearTree that is
                                                              // already in the Neartree and add
                                                              // in the contents of the container
                                                              // that is not already in the Neartree
                                                              // i.e. the exclusive or
                                                              
    

    void insert( const T& t )
       where t is an object of the type T

            all inserts are delayed until a search is performed or
            until an explicit call to CompleteDelayedInsertions
            is called or a search is called. The purpose is to distribute 
            the objects a bit more  randomly. Excessively ordered objects 
            leads to less than optimal trees.
      
            Starting with the 2.1 release, places objects in a queue for 
            insertion later when  CompleteDelayInsert is called.  In
            earlier releases the default was immediate insertion.
            
            The following additional convenience insert template
            allow insertion of containers of objects


    template< typename InputContainer >
    void insert( ContainerType & o )      // e. g. ...

    void insert( const std::vector<T> & o )
    void insert( const std::list<T> & o )
    void insert( const std::set<T> & o ) 
    void insert( const CNearTree<T> & o ) 

    iterator NearestNeighbor ( const DistanceType & dRadius, const T& t ) const
       returns an iterator to the nearest point to the probe point t or end() if there is none
    bool NearestNeighbor ( const DistanceType& dRadius,  T& tClosest,   const T& t ) const
       dRadius is the largest radius within which to search; make it
          very large if you want to include every point that was loaded.
       tClosest is returned as the object that was found closest to the probe
          point (if any were within radius dRadius of the probe)
       t is the probe point, used to search in the group of points insert'ed

       return value is true if some object was found within the search radius, false otherwise.
           If false is returned, tClosest is invalid (at best).


    iterator FarthestNeighbor ( T& const T& t ) const
       returns an iterator to the nearest point to the probe point t or end() if there is none
    bool FarthestNeighbor ( T& tFarthest,   const T& t ) const
       tFarthest is returned as the object that was found farthest from the probe
          point
       t is the probe point, used to search in the group of points Insert'ed
       return value is true if some object was found, false otherwise
          If false is returned, tFarthest is invalid (at best).

    iterator LeftNearestNeighbor ( const DistanceType & dRadius, const T& t ) const
       returns an iterator to the nearest point to the probe point t or end() if there is none
    bool LeftNearestNeighbor ( const DistanceType& dRadius,  T& tClosest,   const T& t ) const
       dRadius is the largest radius within which to search; make it
          very large if you want to include every point that was loaded.
       tClosest is returned as the object that was found closest to the probe
          point (if any were within radius dRadius of the probe)
       t is the probe point, used to search in the group of points insert'ed

       return value is true if some object was found within the search radius, false otherwise.
           If false is returned, tClosest is invalid (at best).


    iterator LeftFarthestNeighbor ( T& const T& t ) const
       returns an iterator to the nearest point to the probe point t or end() if there is none
    bool LeftFarthestNeighbor ( T& tFarthest,   const T& t ) const
       tFarthest is returned as the object that was found farthest from the probe
          point
       t is the probe point, used to search in the group of points Insert'ed
       return value is true if some object was found, false otherwise
          If false is returned, tFarthest is invalid (at best).

    The "Left..." versions of NearestNeighbor and FarthestNeighbor are deprecated versions
    provided for compatibility with earlier releases of NearTree.  There are also "Short..."
    and "LeftShort..." versions of NearestNeighbor to support experimental prepruning logic.


    The following functions (BelongsToPoints, SeparateByRadius, FindInSphere, FindOutSphere, 
    and FindInAnnulus) all return a container (ContainerType) that can be any standard library 
    container (such as std::vector< T >) or CNearTree.  In each case option arguments
    allow a parallel vector of indices to be returned for each container, giving the
    indices of the returned objects within the original NearTree.
     
    template<typename ContainerType>
    void BelongsToPoints ( const T& t1, const T& t2, 
        ContainerType& group1, ContainerType& group2 )
    template<typename ContainerType>
    void BelongsToPoints ( const T& t1, const T& t2, 
        ContainerType& group1, ContainerType& group2,
        std::vector<size_t>& group1_ordinals, std::vector<size_t>& group2_ordinals)
       returns the points closer to t1 than to t2 in group1 and the rest in group 2
       if group1_ordinals and group2_ordinals are provided the ordinals of the
       found objects in the object store are put into those vectors. The ordinals
       can be used as indices into the CNearTree itself.
       
    template<typename ContainerTypeInside, typename ContainerTypeOutside>
    void SeparateByRadius ( const DistanceType radius, const T& probe, 
        ContainerTypeInside& inside, ContainerTypeOutside& outside )
    template<typename ContainerTypeInside, typename ContainerTypeOutside>
    void SeparateByRadius ( const DistanceType radius, const T& probe, 
        ContainerTypeInside& inside, ContainerTypeOutside& outside,
        std::vector<size_t>& inside_ordinals, std::vector<size_t>& outside_ordinals)
       return the points within radius of the probe in inside and the rest in outside
       if inside_ordinals and outside_ordinals are provided the ordinals of the
       found objects in the object store are put into those vectors.  The ordinals
       can be used as indices into the CNearTree itself.


    long FindInSphere ( const DistanceType& dRadius,  
         ContainerType& tInside,   const T& t ) const
    long FindInSphere ( const DistanceType& dRadius,  
         ContainerType& tInside,   
         std::vector<size_t>& tIndices, const T& t ) const
    long FindInSphere ( const DistanceType& dRadius,
         CNearTree<  T >& tInside,  const T& t ) const
    long LeftFindInSphere ( const DistanceType& dRadius,  
         ContainerType& tInside,   const T& t ) const
    long LeftFindInSphere ( const DistanceType& dRadius,  
         ContainerType& tInside,   
         std::vector<size_t>& tIndices, const T& t ) const
    long LeftFindInSphere ( const DistanceType& dRadius,
         CNearTree<  T >& tInside,  const T& t ) const
       dRadius is the radius within which to search; make it very large if you want to
           include every point that was loaded;
       tInside is returned as the NearTree or container of objects that were found within a radius dRadius
          of the probe point
       if the tIndices argument is given it will be returned as a vector
          of indices in the near tree of the objects returned.
       t is the probe point, used to search in the group of points Insert'ed

       return value is the count of the number of points found within the search radius
       the "Left..." versions are deprecated versions provided for compatibility with
       earlier NearTree releases.

    long FindOutSphere ( const DistanceType& dRadius,
         ContainerType& tOutside,   const T& t ) const
    long FindOutSphere ( const DistanceType& dRadius,
         ContainerType& tOutside,
         std::vector<size_t>& tIndices, const T& t ) const
    long FindOutSphere ( const DistanceType& dRadius,
         CNearTree<  T >& tOutside,   const T& t ) const
    long LeftFindOutSphere ( const DistanceType& dRadius,
         ContainerType& tOutside,   const T& t ) const
    long LeftFindOutSphere ( const DistanceType& dRadius,
         ContainerType& tOutside,
         std::vector<size_t>& tIndices, const T& t ) const
    long LeftFindOutSphere ( const DistanceType& dRadius,
         CNearTree<  T >& tOutside,   const T& t ) const
       dRadius is the radius outside of which to search
       tOutside is returned as the NearTree or container of objects that were found at
          or outside of radius dRadius of the probe point
       if the tIndices argument is given it will be returned as a vector
          of indices in the near tree of the objects returned.
       t is the probe point, used to search in the group of points Insert'ed

       return value is the count of the number of points found outside the search radius
       the "Left..." versions are deprecated versions provided for compatibility with
       earlier NearTree releases.
    
    long FindInAnnulus ( const DistanceType& dRadius1,
         const DistanceType& dRadius2, 
         ContainerType& tInRing,   const T& t ) const
    long FindInAnnulus ( const DistanceType& dRadius1,
         const DistanceType& dRadius2, 
         ContainerType& tInRing,
         std::vector<size_t>& tIndices,  const T& t ) const
    long FindInAnnulus ( const DistanceType& dRadius1, 
         const DistanceType& dRadius2,
         CNearTree<  T >& tInRing,   const T& t ) const
    long LeftFindInAnnulus ( const DistanceType& dRadius1,
         const DistanceType& dRadius2, 
         ContainerType& tInRing,   const T& t ) const
    long LeftFindInAnnulus ( const DistanceType& dRadius1,
         const DistanceType& dRadius2, 
         ContainerType& tInRing,
         std::vector<size_t>& tIndices,  const T& t ) const
    long LeftFindInAnnulus ( const DistanceType& dRadius1, 
         const DistanceType& dRadius2,
         CNearTree<  T >& tInRing,   const T& t ) const
       dRadius1 and  dRadius2 are the two radii between which to find data points
       tInRing is returned as the NearTree or container of objects that were found at 
          or outside of a radius dRadius1 and at or inside of radius dRadius2 of the probe point
       if the tIndices argument is given it will be returned as a vector
          of indices in the near tree of the objects returned.
       t is the probe point, used to search in the group of points Insert'ed

       return value is the count of the number of points found within the annulus
       the "Left..." versions are deprecated versions provided for compatibility with
       earlier NearTree releases.
    
    long FindK_NearestNeighbors ( const size_t k, const DistanceType& dRadius,
         ContainerType& tClosest, const T& t )
    long FindK_NearestNeighbors ( const size_t k, const DistanceType& dRadius,
         ContainerType& tClosest,
         std::vector<size_t>& tIndices, const T& t )
    long FindK_NearestNeighbors ( const size_t k, const DistanceType& dRadius,
         CNearTree<  T >& tClosest, const T& t )
    long LeftFindK_NearestNeighbors ( const size_t k, const DistanceType& dRadius,
         ContainerType& tClosest, const T& t )
    long LeftFindK_NearestNeighbors ( const size_t k, const DistanceType& dRadius,
         ContainerType& tClosest,
         std::vector<size_t>& tIndices, const T& t )
    long LeftFindK_NearestNeighbors ( const size_t k, const DistanceType& dRadius,
         CNearTree<  T >& tClosest, const T& t )
       k is the maximum number of nearest neighbors to return. Finds this many if possible
       dRadius within a sphere defined by dRadius, to search for the k-nearest-neighbors
       tClosest is returned as the ContainerType or NearTree of the objects found
       if the tIndices argument is given it will be returned as a vector
          of indices in the near tree of the objects returned.
       t is the probe point, used to search in the group of points insert'ed

       return value is the count of the number of points found within the sphere
       the "Left..." versions are deprecated versions provided for compatibility with
       earlier NearTree releases.


    long FindK_FarthestNeighbors ( const size_t k,
         ContainerType& tFarthest, const T& t )
    long FindK_FarthestNeighbors ( const size_t k,
         ContainerType& tFarthest,
         std::vector<size_t>& tIndices, const T& t )
    long FindK_FarthestNeighbors ( const size_t k, 
          CNearTree<  T >& tFarthest, const T& t )
    long LeftFindK_FarthestNeighbors ( const size_t k,
         ContainerType& tFarthest, const T& t )
    long LeftFindK_FarthestNeighbors ( const size_t k,
         ContainerType& tFarthest,
         std::vector<size_t>& tIndices, const T& t )
    long LeftFindK_FarthestNeighbors ( const size_t k, 
          CNearTree<  T >& tFarthest, const T& t )
       k is the maximum number of farthest neighbors to return. Finds this many if possible
       tFarthest is returned as the ContainerType or NearTree of the objects found
       if the tIndices argument is given it will be returned as a vector
          of indices in the near tree of the objects returned.
       t is the probe point, used to search in the group of points insert'ed

       return value is the count of the number of points found within the sphere
       the "Left..." versions are deprecated versions provided for compatibility with
       earlier NearTree releases.

   

Access Functions: T at ( const size_t n ) const returns the n'th item of the internal data store. This is not guaranteed to be in the order of insertion. T operator[] ( const size_t n ) returns the n'th item of the internal data store. This is not guaranteed to be in the order of insertion. template<typename ContainerType> operator ContainerType ( void ) const returns all of the inserted objects in the tree in a container of type ContainerType. ContainerType can be std::vector<T>, etc, or other containers, including CNearTree<T>. The returned vector contents are not guaranteed to be returned in the order loaded. iterator begin ( void ) const returns an iterator to the beginning of the internal data store iterator end ( void ) const returns an iterator to the end of the data store (one beyond the last item) iterator back ( void ) const returns an iterator to the last data item of the internal data store
Information and special operation functions: void ImmediateInsert( const T&aamp; t ) insert places objects in a queue for insertion later when CompleteDelayInsert is called or a search is called. ImmediateInsert inserts the data immediately into the tree (with the potential of a less balanced tree). ImmediateInsert is not intended for the ordinary user. void CompleteDelayedInsert ( void ) completes insertion for all delayed objects. sqrt(n) of them are inserted by random choice. The rest are inserted in linear order as originally queued. CompleteDelayedInsert is invoked at the beginning of all searches, so the average user will never need to call it. size_t GetDeferredSize ( void ) returns the number of delayed objects that have not yet completed insertion. This is mainly for information about details of the tree. size_t GetTotalSize ( void ) returns the number of objects that have been insert'ed plus those DelayInsert'ed size_t size ( void ) identical to GetTotalSize size_t GetDepth ( void ) returns the maximum tree layers from the root. This is mainly for information about details of the tree. double GetDimEstimate ( void ) // returns an estimate of the Hausdorff dimension double GetDimEstimate ( const double DimEstimateEsd ) // returns an estimate of the Hausdorff dimension // to within the given esd double GetDimEstimateEsd ( void ) // returns an estimate of the esd double GetDiamEstimate ( void ) // returns an estimate of the diameter DistanceType GetMeanSpacing ( void ) // returns an estimate object spacing DistanceType GetVarSpacing ( void ) // returns an estimate object spacing variance size_t GetNodeVisits ( void ) // returns the number of node visits if // CNEARTREE_INSTRUMENTED as defined, 0 otherwise void SetNodeVisits,/b> ( const size_t visits) // set the number of node visits T Centroid ( void ) returns the centroid of a neartree. bool empty ( void ) returns true if the tree is empty, otherwise false
Iterators: Random access iterators are provided for accessing the data in a CNearTree. The most important expected use is to retrieve the objects returned from one of the sphere search functions that can return a CNearTree. However, they can be used with any CNearTree. They should function in a fashion essentially the same as STL iterators. There is no assurance that data will be returned in the order it was loaded, just that it is accessible. This is the list of iterators. The same set is available for const_iterator. iterator ( void ) { }; // constructor iterator ( const const_iterator& s ) iterator& operator= ( const iterator& s ) iterator& operator= ( const const_iterator& s ) iterator operator++ ( const int n ) iterator operator-- ( const int n ) iterator& operator++ ( void ) iterator& operator-- ( void ) iterator operator+ ( const long n ) const iterator operator- ( const long n ) const iterator& operator+= ( const long n ) iterator& operator-= ( const long n ) T operator* ( void ) const bool operator== ( const iterator& t ) const bool operator!= ( const iterator& t ) const bool operator== ( const const_iterator&
t ) const bool operator!= ( const const_iterator& t ) const bool operator> ( const iterator& t ) const bool operator> ( const const_iterator& t ) const bool operator< ( const iterator& t ) const bool operator< ( const const_iterator& t ) const const T * const operator-> ( void ) const

So a complete program is:


 #include "TNear.h"
 #include <cstdio>
 void main()
 {
   CNearTree< double > dT;
   double dNear;
   dT.Insert( 1.5 );
   if ( dT.NearestNeighbor( 10000.0,   dNear,  2.0 )) printf( "%f\n",double(dNear-2.0) );
 }

and it should print 0.5 (that's how for 2.0 is from 1.5). For more examples of the use of TNear.h, see main.cpp and CNearTreeTest.cpp.

The C NearTree API: CNearTree.c

Synopsis

#include <CNearTree.h>

double CNearTreeDistsq ( CNearTreeHandle treehandle, void * coord1, void * coord2 );

double CNearTreeDist ( CNearTreeHandle treehandle, void * coord1, void * coord2 );

int CNearTreeSetNorm ( const CNearTreeHandle treehandle, int treenorm );

int CNearTreeNodeCreate ( const CNearTreeHandle treehandle, CNearTreeNodeHandle * treenodehandle )

int CNearTreeCreate ( CNearTreeHandle * treehandle, size_t treedim, int treetype );

int CNearTreeFree ( const CNearTreeHandle treehandle );

int CNearTreeClear ( CNearTreeHandle * treehandle );

int CNearTreeNodeFree ( CNearTreeNodeHandle * treenodehandle );

int CNearTreeInsert( const CNearTreeHandle treehandle, const void * coord, const void * obj );

int CNearTreeImmediateInsert ( const CNearTreeHandle treehandle, const void * coord, const void * obj );

int CNearTreeDelayedInsert ( const CNearTreeHandle treehandle, const void * coord, const void * obj ); /* ***DEPRECATED*** */

int CNearTreeNodeInsert ( const CNearTreeHandle treehandle, CNearTreeNodeHandle treenodehandle, size_t index; size_t * depth );

int CNearTreeNodeInsert_Flip ( const CNearTreeHandle treehandle, CNearTreeNodeHandle treenodehandle, size_t index; size_t * depth );

int CNearTreeNodeReInsert_Flip ( const CNearTreeHandle treehandle, const CNearTreeNodeHandle treenodehandle, const CNearTreeNodeHandle pntn, size_t * depth );

int CNearTreeCompleteDelayedInsert ( const CNearTreeHandle treehandle ) int CNearTreeZeroIfEmpty ( const CNearTreeHandle treehandle );

int CNearTreeGetSize ( const CNearTreeHandle treehandle, size_t * size );

int CNearTreeGetTotalSize ( const CNearTreeHandle treehandle, size_t * size ); /* ***DEPRECATED*** */

size_t CNearTreeSize ( const CNearTreeHandle treehandle);

int CNearTreeGetDeferredSize ( const CNearTreeHandle treehandle, size_t * size );

int CNearTreeGetDelayedSize ( const CNearTreeHandle treehandle, size_t * size ); /* ***DEPRECATED*** */

int CNearTreeGetDepth ( const CNearTreeHandle treehandle, size_t * depth )

int CNearTreeGetFlags ( const CNearTreeHandle treehandle, long * flags, const long mask )

int CNearTreeSetFlags ( const CNearTreeHandle treehandle, const long flags, const long mask )

int CNearTreeGetMeanSpacing ( const CNearTreeHandle treehandle, double * spacing );

int CNearTreeGetVarSpacing ( const CNearTreeHandle treehandle, double * varspacing );

int CNearTreeCount ( const CNearTreeHandle treehandle, size_t * count );

int CNearTreeNodeCount ( const CNearTreeNodeHandle treenodehandle, size_t * count );

#ifdef CNEARTREE_INSTRUMENTED

int CNearTreeGetNodeVisits ( const CNearTreeHandle treehandle, size_t * visits);

int CNearTreeSetNodeVisits ( const CNearTreeHandle treehandle, const size_t visits );

#endif

int CNearTreeGetDiamEstimate ( const CNearTreeHandle treehandle, double * diamest );

int CNearTreeGetDimEstimateEsd ( const CNearTreeHandle treehandle, double * dimestesd );

int CNearTreeGetDimEstimate ( const CNearTreeHandle treehandle, double * dimest, const double DimEstimateEsd );

int CNearTreeNearestNeighbor ( const CNearTreeHandle treehandle, const double dRadius, void * * coordClosest, void * * objClosest, const void * coord );

int CNearLeftTreeNearestNeighbor ( const CNearTreeHandle treehandle, const double dRadius, void * * coordClosest, void * * objClosest, const void * coord ); /* ***DEPRECATED*** */

int CNearTreeFarthestNeighbor ( const CNearTreeHandle treehandle, void * * coordFarthest, void * * objFarthest, const void * coord );

int CNearTreeFindInSphere ( const CNearTreeHandle treehandle, const double dRadius, CVectorHandle coordInside, CVectorHandle objInside, const void * coord, int resetcount );

int CNearTreeFindTreeInSphere ( const CNearTreeHandle treehandle, const double dRadius, CNearTreeHandle foundInside, const void * coord, int resetcount )

int CNearTreeFindOutSphere ( const CNearTreeHandle treehandle, const double dRadius, CVectorHandle coordOutside, CVectorHandle objOutside, const void * coord, int resetcount );

int CNearTreeFindTreeOutSphere ( const CNearTreeHandle treehandle, const double dRadius, CNearTreeHandle foundOutside, const void * coord, int resetcount )

int CNearTreeFindInAnnulus ( const CNearTreeHandle treehandle, const double dRadiusInner, const double dRadiusOuter, CVectorHandle coordInRing, CVectorHandle objInRing, const void * coord, int resetcount );

int CNearTreeFindTreeInAnnulus ( const CNearTreeHandle treehandle, const double dRadiusInner, const double dRadiusOuter, CNearTreeHandle foundInRing, const void * coord, int resetcount )

int CNearTreeFindKNearest ( const CNearTreeHandle treehandle, const size_t k, const double dRadius, CVectorHandle coordClosest, CVectorHandle objClosest, const void * coord, int resetcount );

int CNearTreeFindKTreeNearest ( const CNearTreeHandle treehandle, const size_t k, const double dRadius, CNearTreeHandle foundClosest, const void * coord, int resetcount )

int CNearTreeFindKFarthest ( const CNearTreeHandle treehandle, const size_t k, const double dRadius, CVectorHandle coordFarthest, CVectorHandle objFarthest, const void * coord, int resetcount );

int CNearTreeFindKTreeFarthest ( const CNearTreeHandle treehandle, const size_t k, const double dRadius, CNearTreeHandle foundFarthest, const void * coord, int resetcount )

int CNearTreeNearest ( const CNearTreeHandle treehandle, double * dRadius, void * * coordClosest, void * * objClosest, const void * coord );

int CNearTreeLeftNearest ( const CNearTreeHandle treehandle, double * dRadius, void * * coordClosest, void * * objClosest, const void * coord ); /* ***DEPRECATED*** */

int CNearTreeFindFarthest ( const CNearTreeHandle treehandle, double * dRadius, void * * coordFarthest, void * * objFarthest, const void * coord );

int CNearTreeObjects ( const CNearTreeHandle treehandle, CVectorHandle * vectorhandle );

void * CNearTreeObjectAt ( const CNearTreeHandle treehandle, size_t index );

int CNearTreeCoords ( const CNearTreeHandle treehandle, CVectorHandle * vectorhandle );

void * CNearTreeCoordAt ( const CNearTreeHandle treehandle, size_t index );

The NearTree API works with coordinate vectors in an arbitrary number of dimensions. Each neartree is accessed by a pointer of type CNearTreeHandle which points to a struct of type CNearTree, which points to a tree of nodes of type CNearTreeNode:


    typedef struct _CNearTreeNode {
        size_t           m_indexLeft;    /* index of left coords in m_CoordStore  
                                            and of left object in m_ObjectStore     */
        size_t           m_indexRight;   /* index of right coords in m_CoordStore 
                                            and of right object in m_ObjectStore     */
        double           m_dMaxLeft;     /* longest distance from the left object
                                            to anything below it in the tree            */
        double           m_dMaxRight;    /* longest distance from the right object 
                                            to anything below it in the tree            */
        struct _CNearTreeNode * m_pLeftBranch;  
                                         /* tree descending from the left object        */
        struct _CNearTreeNode * m_pRightBranch; 
                                         /* tree descending from the right object       */
        int              m_iflags;       /* flags                                       */
    } CNearTreeNode;
    
    
    typedef CNearTreeNode * CNearTreeNodeHandle;   
    
    typedef struct {
        CNearTreeNodeHandle m_ptTree;     /* pointer to the actual tree                  */
        size_t           m_szdimension;   /* dimension of the coordinates                */
        size_t           m_szsize;        /* size of this tree                           */
        size_t           m_szdepth;       /* depth of this tree                          */
        int              m_iflags;        /* flags                                       */
        CVectorHandle    m_ObjectStore;   /* all inserted objects                        */
        CVectorHandle    m_CoordStore;    /* all inserted coordinates                    */
        CVectorHandle    m_DelayedIndices;/* objects queued for insertion                */
    } CNearTree;
    
    typedef CNearTree     FAR * CNearTreeHandle;
    
    /*  Execution Control Flags */
    
#define CNTF_NOPREPRUNE    0x10000L     /*flag to suppress all search prepruning */
#define CNTF_FORCEPREPRUNE 0x20000L     /*flag to force search prepruning       */
#define CNTF_NOFLIP        0x40000L     /*flag to suppress flips on insert      */
#define CNTF_FORCEFLIP     0x80000L     /*flag to force flips on insert         */
#define CNTF_NODEFER      0x100000L     /*flag to prevent deferred insert       */


The internal operation of the API depends on the function CNearTreeDist that returns the distance (L1, L2 or L-infinity) between two coordinate vectors as a double according to the parameters of the given tree. Note that the tree may store the coordinates as integers or as doubles, but the distance is always computed as a double. If this function is replaced by a user function, it is important that the replacement obey the triangle inequality.

A neartree is created by CNearTreeCreate and freed by CNearTreeFree. treedim is the dimension of the coordinate vectors and treetype is one of the three predefined constants CNEARTREE_TYPE_DOUBLE for double or CNEARTREE_TYPE_INTEGER for integer or CNEARTREE_TYPE_STRING, optionally ORed with CNEARTREE_NORM_L1, CNEARTREE_NORM_L2 or CNEARTREE_NORM_LINF for L1, L2 or L-infinity norms, CNEARTREE_NORM_SPHERE or CNEARTREE_NORM_HSPHERE for a spherical or hemispherical norm (L1-norm combination of radial and spherical/hemispherical triangle distances), or CNEARTREE_NORM_HAMMING for the string-Hamming distance norm (add one for each differing character position).

Starting with release 2.1, all insertions are delayed by default, unless the insertions is done by a call to CNearTreeImmediateInsert. The insertions that have been queued are completed by a call to CNearTreeCompleteDelayedInsert or by any search. The insertions are actually done in a randomized order, either for an initial block of sqrt(#queue) by default. or for the entire queue if the flag CNEARTREE_DEFER_ALL is ored with treetype.

Starting with release 3 (formerly called release 2.4) optionally, you may also define CNEARTREE_FORCEFLIP to maximize tree reorganization on insertion, CNEARTREE_NOFLIP to suppress tree reorganization on insertion, CNEARTREE_NODEFER to make all insertions immediate, CNEARTREE_FORCEPREPUNE to do searches first with a tighter estimate on the search radius, and CNEARTREE_NOPREPRUNE to suppress that behavior. The defaults are to do tree reorganization on insertion, to defer insertions, but not to preprune the search radius. If you define CNEARTREE_INSTRUMENTED, code will be enabled to track node visits in searching the tree.

The flags CNEARTREE_DEFER_ALL and CNEARTREE_FLIP used in prior releases are deprecated, but are still defined. They have no effect.

When first created, a neartree has no right or left node and with the dMax-below set to negative values so that any match found will be stored since it will greater than the negative value. The tree is then populated by calls to CNearTreeInsert, with each call providing a coordinate vector coord and an optional object pointer obj. The API copies the coordinate vector, but does not copy the object. Later, when a search is requested or an explicit call to CNearTreeCompleteDelayedInsert is made, the tree is populated in the order left, right and then the nearer child, working from a randomized selection from the items queued for insertion.

Optionally, the actual insertions may done immediately by calling CNearTreeImmediateInsert instead of CNearTreeInsert. For upwards compatibility of the library for existing code, the deprecated CNearTreeDelayedInsert is provided as an deprecated alternate call to CNearTreeInsert.

The neartree is searched for the nearest or farthest coordinate vector in the neartree to a given probe coordinate vector coord by CNearTreeNearestNeighbor and CNearTreeFarthestNeighbor, respectively. Starting with release 3, the search is balanced, following the left or right branch first depending on which child node is closest. The former left-first behavior is deprecated, but still available in CNearLeftTreeNearestNeighbor. The given radius confines the search to a sphere around the probe. If more than a single extremal coordinate point is needed, CNearTreeFindInSphere can be used to obtain a CVector result vector of all the coordinate vectors that satisfy the constraint of being within a specified radius, or CNearTreeFindOutSphere can be used to obtain a CVector result vector of all the coordinates that satisfy the constraint of being outside a specified radius. CNearTreeFindIn Annulus can be used to obtain a CVector result vector of all the coordinates that satisfy the constraint of being between two specified radii from the probe. CNearTreeFindKNearest can be used to obtain a CVector result vector of the k coordinates closest to the probe point such that all results are within the specified radius of the probe point, or CNearTreeFindKFarthest to obtain a CVector result vector of the k coordinates farthest from the probe point such that all results are at or outside the specified radius of the probe point. The vectors themselves are not copied into the result vector. If the parameter resetcount is true (non zero) the result vector is cleared before the search. A CVector result vector of the matching object pointers is returned if objs is not NULL. Aternatively the forms CNearTreeFindTreeInSphere, CNearTreeFindTreeOutSphere, CNearTreeFindTreeInAnnulus, CNearTreeFindKTreeNearest, CNearTreeFindKTreeFarthest can be used to obtain CNearTrees rather than CVectors of results. The functions CNearTreeNearest and CNearTreeFindFarthest implement CNearTreeNearestNeighbor and CNearTreeFarthestNeighbor, respectively, adjusting the radius of the search while the search is in progress and are not normally used by users.

The size of the tree as a count of objects can be obtained using the function NearTreeGetSize or the macro NearTreeSize. The size of the tree as a count of nodes and the depth of the tree can be obtained using the functions CNearTreeCount and CNearTreeGetDepth. Estimates of the Hausdorff dimension, the esd of that estimate, the diameter, the spacing and the variance of the spacing can be obtained with CNearTreeGetDimEstimate, CNearTreeGetDimEstimateEsd, CNearTreeGetDiamEstimate, CNearTreeGetMeanSpacing and CNearTreeGetVarSpacing.

Returns

If CNearTreeDist fails, it returns -1. Except for CNearTreeDist, all the functions in the API return 0 ( CNEARTREE_SUCCESS ) for success. If dynamic memory allocation fails, CNEARTREE_MALLOC_FAILED is returned. If a call is made with an improper argument, CNEARTREE_BAD_ARGUMENT is returned. If a search fails to find anything, CNEARTREE_NOT_FOUND is returned. If there is a failure in an attempt to free a CNearTree, CNEARTREE_FREE_FAILED is returned. If any of the internal call to CVector fail, CNEARTREE_CVECTOR_FAILED is returned. For convenience in debugging, the formerly negative values of these returns are now positive.

Examples

To create a neartree for 3-dimensional vectors of doubles:

 
#include <CNearTree.h>
CNearTreeHandle treehandle;
int bReturn;
 
 ...
 
 bReturn = !CNearTreeCreate(&treehandle,3,CNEARTREE_TYPE_DOUBLE);

To insert a copy of a 3-dimensional vector of doubles into this tree, with no associated object:

 
    double v[3];
 
 ...
     
    v[0] = 1.; v[1] = 2.; v[2] = 3.;
    bReturn = !CNearTreeInsert(treehandle,&v[0],NULL);

To search for the nearest neighbor to a probe vector vSearch in a radius of 3., returning a pointer to the resulting vector in vBest:

 
    double * vBest;
    void * vvBest;
    double vSearch[3];
    double   dRad = =3.;
    
  ...
  
    if ( !CNearTreeNearestNeighbor(treehandle,dRad,&vvBest,NULL,vSearch))
        {   vBest = (double *)vvBest; }

Note the use of a separate void * vvBest instead of a cast of &vBest to avoid compiler type punning warnings.

For more examples of the use of CNearTree.c, see main.c and CNearTreeTest.c in the release kit.



A Portable pseudo-random number generator: rhrand.h

rhrand.h is a portable pseudo-random number generator based one by Rob Harrison, derived from "one in J.M.Hammersley and D.C. Handscomb, 'Monte Carlo Methods,' Methuen & Co., London and Wiley & Sons, New York, 1964, p47". See also, D. E. Knuth "The Art of Computer Programming", Volume 2, "Seminumerical Alogorithms, Third Edition, Addison-Wesley, Reading MA, 1997.

rhrand.h is a header file in which a C++ class, RHrand, is defined, and a C struct typedef CRHrand is defined.

The C++ interface is


    static const int RHRAND_MAX = 32767;  /* the integer range accessible as RHrand::RHRAND_MAX */
    
    RHrand(void)                          /* the default constructor */
    
    RHrand( const int iseed )             /* a constructor to start with the given seed */
    
    ~RHrand( void)                        /* a destructor */
    
    void srandom( const int iseed)        /* reset the generator based on the given seed */
    
    double urand( void )                  /* return a random double uniformly distributed in [0,1) */
    
    int random ( void )                   /* return a random integer uniformly distributed in [0, RHRAND_MAX-1] */

In C++ code, typical use is


#include <rhhand.h>
    RHrand rhr;

...

    x = rhr.urand();

The C interface is suppressed in RHRAND_NOCCODE is defined. Otherwise the C interface is based on defining a struct of type CRHRrand and calling macros that refer to a handle of type RCRHrandHandle.


    typedef struct CRHrand_ {           /* the struct used in random number generattion */
        double buffer[55];
        int indx;
        int jndx;
        int kndx;
        double dTemp;
    } CRHrand;

    typedef CRHrand * CRHrandHandle;     /* the type to be used in maro calls */

    #define CRHRAND_MAX 32767            /* the integer range */
    
    #define CRHrandSrandom(randhandle,iseed) ...  
                                         /* a macro to call to initialize CHRrandHandle randhandle
                                            using see int iseed */
                                            
    #define CRHrandUrand(randhandle) ... /* a macro to return a random double uniformly distributed in [0,1) */
    
    #define CRHrandRandom(randhandle) ((int)(CRHrandUrand(randhandle)*(double)CRHRAND_MAX))
                                         /* a macro to return a random integer uniformly distributed in 
                                            [0, CRHRAND_MAX-1] */

Typical use is


#include <rhhand.h>
    CRHrand rhr;

...

    CRHrandSrandom(&rhr, 0 ); 

...

    x = CRHrandUrand(&rhr);


Updated 27 September 2011
./NearTree-3.1.1/CNearTreeTest.c0000644002342100234170000025126511640401607016252 0ustar bernstehfaculty/* * CNearTreeTest.c * NearTree * * Based on CNearTreeTest.cpp * Copyright 2008 Larry Andrews. All rights reserved * * C Version created by Herbert J. Bernstein on 1/1/09 * with permission from Larry Andrews. * * Rev 18 Jan 2009, Tests of DelayedInsert * * Copyright 2008, 2009 Larry Andrews and Herbert J. Bernstein. * All rights reserved. * * Revised 30 May 2009, release with full containerization of C++ * version and KNear/Far in C++ and C, LCA + HJB * */ /********************************************************************** * * * YOU MAY REDISTRIBUTE NearTree UNDER THE TERMS OF THE LGPL * * * **********************************************************************/ /************************* LGPL NOTICES ******************************* * * * This library is free software; you can redistribute it and/or * * modify it under the terms of the GNU Lesser General Public * * License as published by the Free Software Foundation; either * * version 2.1 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 * * Lesser General Public License for more details. * * * * You should have received a copy of the GNU Lesser General Public * * License along with this library; if not, write to the Free * * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, * * MA 02110-1301 USA * * * **********************************************************************/ /* This is a test harness for the C version neartree API CNearTree.c. */ #include #include #include #include #include #ifndef USE_LOCAL_HEADERS #include #else #include "CNearTree.h" #endif #ifndef USE_LOCAL_HEADERS #include #else #include "rhrand.h" #endif CRHrand rhr; void testEmptyTree( void ); void testLinearTree( const int n ); void testFindFirstObject( void ); void testFindLastObject( void ); void testFindInSphereFromBottom( void ); void testBackwardForward( void ); void testFindInSphereFromTop( void ); void testFindOutSphere( void ); void testDelayedInsertion( void ); void testIterators( void ); void testFindInAnnulus( void ); void testMisc( void ); void testRandomTree1( const int n ); void testBigVector( void ); void testDelayedInsertion( void ); void testKNearFar( void ); void test4Sphere(void); void testStrings(void); long g_errorCount; int dbgflg; #define bool int /* for older C compilers */ /*=======================================================================*/ int main(int argc, char** argv) { int i; dbgflg = 0; if (argc > 1 && !strncmp(argv[1],"--debug",7)) { dbgflg = 1; } if (dbgflg) fprintf(stderr,"Debug enabled\n"); CRHrandSrandom(&rhr,0); /* test the interface with an empty tree */ testEmptyTree( ); /* test the C API with trees with varying content, one entry and several */ for( i=1; i<10; ++i ) { testLinearTree( i ); } testFindFirstObject( ); fprintf( stdout, "testFindFirstObject\n" ); testFindLastObject( ); fprintf( stdout, "testFindLastObject\n" ); testFindInSphereFromBottom( ); fprintf( stdout, "testFindInSphereFromBottom\n" ); testFindInSphereFromTop( ); fprintf( stdout, "testFindInSphereFromTop\n" ); testFindOutSphere(); fprintf( stdout, "testFindOutSphere\n" ); testFindInAnnulus( ); fprintf( stdout, "testFindInAnnulus\n" ); testRandomTree1( 10000 ); fprintf( stdout, "testRandomTree1\n" ); testBackwardForward( ); fprintf( stdout, "testBackwardForward\n" ); testBigVector( ); fprintf( stdout, "testBigVector\n" ); testDelayedInsertion( ); fprintf( stdout, "testDelayedInsertion\n" ); testKNearFar(); fprintf( stdout, "testKNearFar\n" ); test4Sphere(); fprintf( stdout, "test4Sphere\n" ); testStrings(); fprintf( stdout, "testStrings\n" ); if( g_errorCount == 0 ) { fprintf(stdout, "No errors were detected while testing CNearTree\n" ); } return g_errorCount; } /* For an empty tree of int's, test the public interface for CNearTree. */ /*=======================================================================*/ void testEmptyTree( void ) { CNearTreeHandle tree; CVectorHandle v; int CNEARTREE_FAR * close; void CNEARTREE_FAR * vclose; int CNEARTREE_FAR * nFar; void CNEARTREE_FAR * vnFar; int probe[1]; bool bTreeEmpty; bool bTreeHasNearest; bool bTreeHasFarthest; bool bInSphere; size_t lFoundPointsInSphere; if (CNearTreeCreate(&tree,1,CNEARTREE_TYPE_INTEGER)) { ++g_errorCount; fprintf(stdout,"CNearTreeTest: testEmptyTree: CNearTreeCreate failed.\n"); } bTreeEmpty = !CNearTreeZeroIfEmpty(tree); if( ! bTreeEmpty ) { ++g_errorCount; fprintf(stdout, "CNearTreeTest: testEmptyTree: CNearTreeZeroIfEmpty not zero for empty tree\n" ); } probe[0] = 1; bTreeHasNearest = !CNearTreeNearestNeighbor(tree, 0.0, &vclose, NULL, probe); close = (int CNEARTREE_FAR *)vclose; if( bTreeHasNearest ) { ++g_errorCount; fprintf(stdout, "CNearTreeTest: testEmptyTree: NearestNeighbor incorrect for empty tree\n" ); } probe[0] = 0; bTreeHasFarthest = !CNearTreeFarthestNeighbor(tree, &vnFar, NULL, probe); nFar = (int CNEARTREE_FAR *)vnFar; if( bTreeHasFarthest ) { ++g_errorCount; fprintf(stdout, "CNearTreeTest: testEmptyTree: FarthestNeighbor incorrect for empty tree\n" ); } probe[0] = 1; if (CVectorCreate(&v,sizeof(int CNEARTREE_FAR *),10)) { ++g_errorCount; fprintf(stdout,"CNearTreeTest: testEmptyTree: CVectorCreate failed\n" ); } bInSphere = !CNearTreeFindInSphere( tree, 1000.0, v, NULL, probe, 1); lFoundPointsInSphere = CVectorSize(v); if( bInSphere || lFoundPointsInSphere != 0 ) { ++g_errorCount; fprintf(stdout, "CNearTreeTest: testEmptyTree: FindInSphere incorrect for empty tree\n" ); } if (CVectorFree(&v)) { ++g_errorCount; fprintf(stdout, "CNearTreeTest: testEmptyTree: CNearVectorFree failed\n"); } if (CNearTreeFree(&tree)) { ++g_errorCount; fprintf(stdout, "CNearTreeTest: testEmptyTree: CNearTreeFree failed\n"); } } /* Test CNearTree using a tree built only using int's. This is not a robust test in some ways because the tree is only composed of right branches and left leaves. Perform some general tests. */ /*=======================================================================*/ void testLinearTree( const int n ) { CNearTreeHandle tree; CVectorHandle v; bool bInsert, bClose, bFar, bInSphere, bResult; int CNEARTREE_FAR * closest; void CNEARTREE_FAR * vclosest; int CNEARTREE_FAR * farthest; void CNEARTREE_FAR * vfarthest; int probe[1]; size_t lFoundPointsInSphere; int i; size_t found; long localErrorCount = 0; long localErrorMax = 0; if (CNearTreeCreate(&tree,1,CNEARTREE_TYPE_INTEGER)) { ++g_errorCount; fprintf(stdout,"CNearTreeTest: testLinearTree: CNearTreeCreate failed.\n"); } /* generate an unbalanced tree*/ for( i=1; i<=n; ++i ) { probe[0] = i; bInsert = !CNearTreeImmediateInsert(tree, probe, NULL); if (!bInsert) { ++g_errorCount; fprintf(stdout, "CNearTreeTest: testLinearTree: CNearTreeImmediateInsert failed.\n"); } } /* Search for the nearest value using a probe point that is larger than the largest value that was input. The returned values should be the last value entered into the tree. */ probe[0] = 2*n; bClose = !CNearTreeNearestNeighbor(tree,22.,&vclosest,NULL,probe); closest = (int CNEARTREE_FAR *)vclosest; if( ! bClose || closest[0] != n ) { ++g_errorCount; fprintf(stdout, "CNearTreeTest: testLinearTree: NearestNeighbor failed, got %d, should be %d\n", closest[0], n ); } /* Search for the farthest value using a probe point that is larger than the largest value that was input. The returned values should be the first value entered into the tree. */ probe[0] = 2*n; bFar = !CNearTreeFarthestNeighbor(tree,&vfarthest,NULL,probe); farthest = (int CNEARTREE_FAR *)vfarthest; if( ! bFar || farthest[0] != 1 ) { ++g_errorCount; fprintf(stdout, "CNearTreeTest: testLinearTree: FarthestNeighbor failed, got %d, should be %d\n", farthest[0], 1 ); } /* Find all of the points in the tree using a negative radius, using the first input point as the probe point. Nothing should be found. */ if (CVectorCreate(&v,sizeof(int CNEARTREE_FAR *),10)) { ++g_errorCount; fprintf(stdout,"CNearTreeTest: testLinearTree: CVectorCreate failed\n" ); } probe[0] = 1; bInSphere = !CNearTreeFindInSphere( tree, -100., v, NULL, probe, 1); lFoundPointsInSphere = CVectorSize(v); if( bInSphere || lFoundPointsInSphere != 0 ) { ++g_errorCount; fprintf(stdout, "CNearTreeTest: testLinearTree: FindInSphere found points for negative radius\n" ); } CVectorClear(v); /* Find all of the points in the tree using a small radius. Do separate searches for every point entered. In every case, only a single point should be found. */ for( i=1; i<=n; ++i ) { size_t found; probe[0] = i; bInSphere = !CNearTreeFindInSphere( tree, 0.1, v, NULL, probe, 1); found = CVectorSize(v); if( found != 1 ) { ++localErrorCount; if( found > (size_t)localErrorMax ) { localErrorMax = (long)found; } } } if( localErrorCount != 0 ) { ++g_errorCount; fprintf(stdout, "CNearTreeTest: testLinearTree: FindInSphere found too many points (as many as %ld) %ld times\n", localErrorMax, localErrorCount ); } CVectorClear(v); /* Find all of the points in the tree that are within a large radius, using the first input point as the probe point. All of the input points should be found within the radius. */ probe[0] = 0; bInSphere = !CNearTreeFindInSphere( tree,(double)(10*n), v, NULL, probe, 1); found = CVectorSize(v); if( found != (size_t)n ) { ++g_errorCount; fprintf(stdout, "CNearTreeTest: testLinearTree: FindInSphere did not find all the points, found %lu\n", (long unsigned int)found ); } bResult = !CVectorFree(&v); if (!bResult) { ++g_errorCount; fprintf(stdout, "CNearTreeTest: testLinearTree: CVectorFree has failed\n" ); } bResult = !CNearTreeFree(&tree); if (!bResult) { ++g_errorCount; fprintf(stdout, "CNearTreeTest: testLinearTree: CNearTreeFree has failed\n" ); } } /* Perform general tests using floating point numbers. For the C vesion only one set of tests is performed, for double. The values are computed starting from some initial value, and each succeeding value is one half of the previous until zero is computed (the zero is NOT inserted into the tree). The tree will consist of only right branches and left leaves. */ /*=======================================================================*/ void testFindFirstObject( void ) { double fFinal = DBL_MAX; /* just initialization */ CNearTreeHandle tree; CVectorHandle v; bool bReturn, bResult; bool bReturnNear; bool bReturnFar; long count = 0; double f[1]; double CNEARTREE_FAR * closest; void CNEARTREE_FAR * vclosest; double CNEARTREE_FAR * farthest; void CNEARTREE_FAR * vfarthest; size_t lFound; bReturn = !CNearTreeCreate(&tree,1,CNEARTREE_TYPE_DOUBLE); if (!bReturn) { ++g_errorCount; fprintf(stdout, "CNearTreeTest: testFindFirstObject: CNearTreeCreate failed\n" ); } /* build the double tree starting with 1.0 */ f[0] = 1.0; while( f[0]*f[0] > DBL_MIN ) { bReturn = !CNearTreeImmediateInsert(tree,f, NULL); fFinal = f[0]; f[0] /= 2.0; ++count; } if( (!CNearTreeZeroIfEmpty(tree) ) ) { ++g_errorCount; fprintf(stdout, "CNearTreeTest: testFindFirstObject: incorrectly found empty tree for double\n" ); } /* Search for the value closest to zero. It should be a very small, probably denormalized number. */ f[0] = 0.0; bReturnNear = !CNearTreeNearestNeighbor(tree, 1.0e-10, &vclosest, NULL, f); closest = (double CNEARTREE_FAR *)vclosest; if( ! bReturnNear ) { ++g_errorCount; fprintf(stdout, "CNearTreeTest: testFindFirstObject: failed for double\n" ); } if( bReturnNear && fabs(closest[0]-fFinal)> fFinal*DBL_EPSILON ) { ++g_errorCount; fprintf(stdout, "CNearTreeTest: testFindFirstObject: failed for double, got %g != %g, abs error %g\n", closest[0], fFinal, fabs(closest[0]-fFinal)); } /* Search for the value farthest from a large number. It should be a very small, probably denormalized number. */ f[0] = 100.0; bReturnFar = !CNearTreeFarthestNeighbor(tree, &vfarthest, NULL,f); farthest = (double CNEARTREE_FAR *)vfarthest; if( ! bReturnFar || fabs(farthest[0]-fFinal)> fabs(f[0]-fFinal)*DBL_EPSILON ) { ++g_errorCount; fprintf(stdout, "CNearTreeTest: testFindFirstObject: failed for double, got %g != %g, abs error %g\n", farthest[0], fFinal, fabs(farthest[0]-fFinal) ); } /* Determine if FindInSphere can find all of the input data. */ f[0] = 1.0; bReturn = !CVectorCreate(&v,sizeof(double CNEARTREE_FAR *),10); if (!bReturn) { ++g_errorCount; fprintf(stdout, "CNearTreeTest: testFindFirstObject: CVectorCreate failed\n" ); } bReturn = !CNearTreeFindInSphere( tree, 100.0, v, NULL, f, 1); lFound = CVectorSize(v); if( lFound != (size_t)count ) { ++g_errorCount; fprintf(stdout, "CNearTreeTest: testFindFirstObject: found wrong count for FindInSphere for float, should be%ld, got %lu\n", count, (long unsigned int)lFound ); } bResult = !CVectorFree(&v); if (!bResult) { ++g_errorCount; fprintf(stdout, "CNearTreeTest: testFindFirstObject: CVectorFree has failed\n" ); } bResult = !CNearTreeFree(&tree); if (!bResult) { ++g_errorCount; fprintf(stdout, "CNearTreeTest: testFindFirstObject: CNearTreeFree has failed\n" ); } } /* Perform general tests using floating point numbers. Build a tree of floats. The values are computed starting from some initial value, and each succeeding value is one half of the previous until zero is computed (the zero is NOT inserted into the tree). The tree will consist of only right branches and left leaves. */ /*=======================================================================*/ void testFindLastObject( void ) { double fFinal; CNearTreeHandle tree; bool bReturn, bResult; double f[1]; double CNEARTREE_FAR * closest; void CNEARTREE_FAR * vclosest; int count; count = 0; fFinal = DBL_MAX; bReturn = !CNearTreeCreate(&tree,1,CNEARTREE_TYPE_DOUBLE); if (!bReturn) { ++g_errorCount; fprintf(stdout, "CNearTreeTest: testFindLastObject: CNearTreeCreate failed\n" ); } f[0] = 1.0; /* generate an unbalanced tree*/ while( f[0] > 2.0*sqrt(DBL_MIN) ) { bReturn = !CNearTreeImmediateInsert(tree,f, NULL); fFinal = f[0]; f[0] /= 2.0; ++count; } if (dbgflg) { size_t depth, size; #ifdef CNEARTREE_INSTRUMENTED size_t height; #endif bResult = !(CNearTreeGetDepth(tree,&depth)) && !(CNearTreeGetSize(tree,&size)); if (bResult) { fprintf(stderr,"CNearTreeTest: testFindLastObject: depth=%lu, size=%lu\n", (unsigned long)depth,(unsigned long)size); } else { fprintf(stderr,"CNearTreeTest: testFindLastObject: get size and depth failed\n"); } #ifdef CNEARTREE_INSTRUMENTED bResult = !(CNearTreeGetDepth(tree,&height)); if (bResult) { fprintf(stderr,"CNearTreeTest: testFindLastObject: height=%lu\n", (unsigned long)height); } else { fprintf(stderr,"CNearTreeTest: testFindLastObject: get height failed\n"); } #endif } f[0] = 11.0; bReturn = !CNearTreeNearestNeighbor(tree, 100.0, &vclosest, NULL, f); closest = (double CNEARTREE_FAR *)vclosest; if( ! bReturn || closest[0] != 1.0 ) { ++g_errorCount; fprintf(stdout, "CNearTreeTest: testFindLastObject: CNearTreeNearestNeighbor failed for double, got %g\n", closest[0] ); } f[0] = -11.0; bReturn = !CNearTreeFarthestNeighbor(tree, &vclosest, NULL, f); closest = (double CNEARTREE_FAR *)vclosest; if( ! bReturn || closest[0] != 1.0 ) { ++g_errorCount; fprintf(stdout, "CNearTreeTest: testFindLastObject: CNearTreeFarthestNeighbor failed for double, got %g\n", closest[0] ); } bResult = !CNearTreeFree(&tree); if (!bResult) { ++g_errorCount; fprintf(stdout, "CNearTreeTest: testFindLastObject: CNearTreeFree has failed\n" ); } count = 0; fFinal = DBL_MAX; bReturn = !CNearTreeCreate(&tree,1,CNEARTREE_TYPE_DOUBLE|CNEARTREE_FLIP); if (!bReturn) { ++g_errorCount; fprintf(stdout, "CNearTreeTest: testFindLastObject: CNearTreeCreate with flip failed\n" ); } f[0] = 1.0; /* generate an unbalanced tree*/ while( f[0] > 2.0*sqrt(DBL_MIN) ) { bReturn = !CNearTreeImmediateInsert(tree,f, NULL); fFinal = f[0]; f[0] /= 2.0; ++count; } if (dbgflg) { size_t depth, size; bResult = !(CNearTreeGetDepth(tree,&depth)) && !(CNearTreeGetSize(tree,&size)); if (bResult) { fprintf(stderr,"CNearTreeTest: testFindLastObject: with flip depth=%lu, size=%lu\n", (unsigned long)depth,(unsigned long)size); } else { fprintf(stderr,"CNearTreeTest: testFindLastObject: with flip get size and depth failed\n"); } } f[0] = 11.0; bReturn = !CNearTreeNearestNeighbor(tree, 100.0, &vclosest, NULL, f); closest = (double CNEARTREE_FAR *)vclosest; if( ! bReturn || closest[0] != 1.0 ) { ++g_errorCount; fprintf(stdout, "CNearTreeTest: testFindLastObject: CNearTreeNearestNeighbor with flip failed for double, got %g\n", closest[0] ); } f[0] = -11.0; bReturn = !CNearTreeFarthestNeighbor(tree, &vclosest, NULL, f); closest = (double CNEARTREE_FAR *)vclosest; if( ! bReturn || closest[0] != 1.0 ) { ++g_errorCount; fprintf(stdout, "CNearTreeTest: testFindLastObject: CNearTreeFarthestNeighbor with flip failed for double, got %g\n", closest[0] ); } bResult = !CNearTreeFree(&tree); if (!bResult) { ++g_errorCount; fprintf(stdout, "CNearTreeTest: testFindLastObject: CNearTreeFree with flip has failed\n" ); } } /*=======================================================================*/ void testFindInSphereFromBottom( void ) { const int nmax = 100; CNearTreeHandle tree; CVectorHandle v; bool bReturn; double f[1]; double radius; size_t lReturned; int i; bReturn = !CNearTreeCreate(&tree,1,CNEARTREE_TYPE_DOUBLE); if (!bReturn) { ++g_errorCount; fprintf(stdout, "CNearTreeTest: testFindInSphereFromBottom: CNearTreeCreate failed\n" ); } bReturn = !CVectorCreate(&v,sizeof(double CNEARTREE_FAR *),10); if (!bReturn) { ++g_errorCount; fprintf(stdout, "CNearTreeTest: testFindInSphereFromBottom: CVectorCreate failed\n" ); } for( i=1; i<=nmax; ++i ) { f[0] = (double)i; bReturn = !CNearTreeImmediateInsert(tree,f, NULL); if (!bReturn) { ++g_errorCount; fprintf(stdout, "CNearTreeTest: testFindInSphereFromBottom: CNearTreeImmediateInsert failed\n" ); } } /* generate an unbalanced tree*/ for( i=1; i<=nmax; ++i ) { bReturn = !CVectorClear(v); radius = 0.05 + (double)i; f[0] = 0.9; bReturn = !CNearTreeFindInSphere( tree, radius, v, NULL, f, 1); lReturned = CVectorSize(v); if( lReturned != (size_t)i ) { ++g_errorCount; fprintf(stdout, "CNearTreeTest: FindInSphere failed in testFindInSphereFromBottom for i=%d\n", i ); } } } /*=======================================================================*/ void testFindInSphereFromTop( void ) { const int nmax = 100; CNearTreeHandle tree; CVectorHandle v; double f[1]; int i; bool bReturn; double radius; size_t lReturned; bReturn = !CNearTreeCreate(&tree,1,CNEARTREE_TYPE_DOUBLE); if (!bReturn) { ++g_errorCount; fprintf(stdout, "CNearTreeTest: testFindInSphereFromTop: CNearTreeCreate failed\n" ); } for( i=1; i<=nmax; ++i ) { f[0] = (double)i; bReturn = !CNearTreeImmediateInsert(tree,f, NULL); } bReturn = !CVectorCreate(&v,sizeof(double CNEARTREE_FAR *),10); if (!bReturn) { ++g_errorCount; fprintf(stdout, "CNearTreeTest: testFindInSphereFromTop: CVectorCreate failed\n" ); } for( i=1; i<=nmax; ++i ) { CVectorClear(v); f[0] = 0.1 + (double)nmax; radius = 0.05 + (double)i; bReturn = !CNearTreeFindInSphere( tree, radius, v, NULL, f, 1); lReturned = CVectorSize(v); if( lReturned != (size_t)i ) { ++g_errorCount; fprintf(stdout, "CNearTreeTest: testFindInSphereFromTop: CNearTreeFindInSphere failed for i=%d\n", i ); } } bReturn = !CVectorFree(&v); if (!bReturn) { ++g_errorCount; fprintf(stdout, "CNearTreeTest: testFindInSphereFromTop: CVectorFree failed\n"); } bReturn = !CNearTreeFree(&tree); if (!bReturn) { ++g_errorCount; fprintf(stdout, "CNearTreeTest: testFindInSphereFromTop: CNearTreeFree failed\n"); } } /*=======================================================================*/ void testFindOutSphere( void ) { const int nmax = 100; CNearTreeHandle tree; CNearTreeHandle sphereReturn; CVectorHandle v; bool bReturn; double f[1]; double radius; size_t lReturned; int i; bReturn = !CNearTreeCreate(&tree,1,CNEARTREE_TYPE_DOUBLE); if (!bReturn) { ++g_errorCount; fprintf(stdout, "CNearTreeTest: testFindOutSphere: CNearTreeCreate failed\n" ); } bReturn = !CNearTreeCreate(&sphereReturn,1,CNEARTREE_TYPE_DOUBLE); if (!bReturn) { ++g_errorCount; fprintf(stdout, "CNearTreeTest: testFindOutSphere: CNearTreeCreate failed\n" ); } bReturn = !CVectorCreate(&v,sizeof(double CNEARTREE_FAR *),10); if (!bReturn) { ++g_errorCount; fprintf(stdout, "CNearTreeTest: testFindOutSphere: CVectorCreate failed\n" ); } for( i=1; i<=nmax; ++i ) { f[0] = (double)i; bReturn = !CNearTreeImmediateInsert(tree,f, NULL); if (!bReturn) { ++g_errorCount; fprintf(stdout, "CNearTreeTest: testFindOutSphere: CNearTreeImmediateInsert failed\n" ); } } /* now test the NearTree return */ for( i=1; i<=nmax; ++i ) { radius = 0.05 + (double)i; f[0] = 0.1 + (double)nmax; bReturn = !CNearTreeFindTreeOutSphere( tree, radius, sphereReturn, f, 1); lReturned = CNearTreeSize(sphereReturn); if( lReturned != 100-(size_t)i ) { ++g_errorCount; fprintf(stdout, "CNearTreeTest: testFindOutSphere: FindOutSphere failed for i=%d\n", i ); } } /* now test the vector return */ for( i=1; i<=nmax; ++i ) { bReturn = !CVectorClear(v); radius = 0.05 + (double)i; f[0] = 0.1 + (double)nmax; bReturn = !CNearTreeFindOutSphere( tree, radius, v, NULL, f, 1); lReturned = CVectorSize(v); if( lReturned != 100-(size_t)i ) { ++g_errorCount; fprintf(stdout, "CNearTreeTest: testFindOutSphere: FindOutSphere failed for for vector for i=%d\n", i ); } } bReturn = !CVectorFree(&v); if (!bReturn) { ++g_errorCount; fprintf(stdout, "CNearTreeTest: testFindOutSphere: CVectorFree failed\n"); } bReturn = !CNearTreeFree(&sphereReturn); if (!bReturn) { ++g_errorCount; fprintf(stdout, "CNearTreeTest: testFindOutSphere: CNearTreeFree failed\n"); } bReturn = !CNearTreeFree(&tree); if (!bReturn) { ++g_errorCount; fprintf(stdout, "CNearTreeTest: testFindOutSphere: CNearTreeFree failed\n"); } } /*=======================================================================*/ void testFindInAnnulus( void ) { const int nmax = 1000; CNearTreeHandle tree; CNearTreeHandle annulusReturn; CVectorHandle v; bool bReturn; double f[1]; double CNEARTREE_FAR * nearest; void CNEARTREE_FAR * vnearest; double radiusin, radiusout; size_t lReturned; int i; bReturn = !CNearTreeCreate(&tree,1,CNEARTREE_TYPE_DOUBLE); if (!bReturn) { ++g_errorCount; fprintf(stdout, "CNearTreeTest: testFindInAnnulus: CNearTreeCreate failed\n" ); } bReturn = !CNearTreeCreate(&annulusReturn,1,CNEARTREE_TYPE_DOUBLE); if (!bReturn) { ++g_errorCount; fprintf(stdout, "CNearTreeTest: testFindInAnnulus: CNearTreeCreate failed\n" ); } bReturn = !CVectorCreate(&v,sizeof(double CNEARTREE_FAR *),10); if (!bReturn) { ++g_errorCount; fprintf(stdout, "CNearTreeTest: testFindInAnnulus: CVectorCreate failed\n" ); } for( i=1; i<=nmax; ++i ) { f[0] = (double)i; bReturn = !CNearTreeImmediateInsert(tree,f, NULL); if (!bReturn) { ++g_errorCount; fprintf(stdout, "CNearTreeTest: testFindInAnnulus: CNearTreeImmediateInsert failed\n" ); } } radiusin = 100.1; radiusout = 299.9; /* now test the NearTree return */ { f[0] = 0.; bReturn = !CNearTreeFindTreeInAnnulus( tree, radiusin, radiusout, annulusReturn, f, 1); lReturned = CNearTreeSize(annulusReturn); if( lReturned != (299-101+1) ) { ++g_errorCount; fprintf(stdout, "CNearTreeTest: testFindInAnnulus: wrong number of objects found\n" ); } f[0] = 0.; bReturn = !CNearTreeNearestNeighbor(annulusReturn,1000.,&vnearest,NULL,f); nearest = (double CNEARTREE_FAR *)vnearest; if (!bReturn) { ++g_errorCount; fprintf(stdout, "testFindInAnnulus: no lowest value found\n" ); } else if( nearest[0] != 101. ) { ++g_errorCount; fprintf(stdout, "testFindInAnnulus: lowest value (%g) is incorrect\n", nearest[0] ); } } /* now test the vector return */ { f[0] = 0.; bReturn = !CNearTreeFindInAnnulus( tree, radiusin, radiusout, v, NULL, f, 1); lReturned = CVectorSize(v); if( lReturned != (299-101+1) ) { ++g_errorCount; fprintf(stdout, "CNearTreeTest: testFindInAnnulus: for vector, wrong number of objects found\n" ); } } bReturn = !CVectorFree(&v); if (!bReturn) { ++g_errorCount; fprintf(stdout, "CNearTreeTest: testFindOutSphere: CVectorFree failed\n"); } bReturn = !CNearTreeFree(&annulusReturn); if (!bReturn) { ++g_errorCount; fprintf(stdout, "CNearTreeTest: testFindOutSphere: CNearTreeFree failed\n"); } bReturn = !CNearTreeFree(&tree); if (!bReturn) { ++g_errorCount; fprintf(stdout, "CNearTreeTest: testFindOutSphere: CNearTreeFree failed\n"); } } /* Test CNearTree with a bunch of random numbers (integers). */ /*=======================================================================*/ void testRandomTree1( const int nRequestedRandoms ) { const int n = nRequestedRandoms; CNearTreeHandle tree; CVectorHandle v; int nmax; int nmin; int i; int next[1]; int CNEARTREE_FAR * closest; void CNEARTREE_FAR * vclosest; int CNEARTREE_FAR * farthest; void CNEARTREE_FAR * vfarthest; bool bReturn, bResult, bNear, bFar; double radius; size_t lReturn; nmax = INT_MIN; nmin = INT_MAX; bReturn = !CNearTreeCreate(&tree,1,CNEARTREE_TYPE_INTEGER); if (!bReturn) { ++g_errorCount; fprintf(stdout, "CNearTreeTest: testRandomTree1: CNearTreeCreate failed\n" ); } /* Build the tree with n random numbers. Remember the largest and smallest values. */ for( i=0; i nmax ) nmax = next[0]; if( next[0] < nmin ) nmin = next[0]; } if (dbgflg) { size_t depth, size; #ifdef CNEARTREE_INSTRUMENTED size_t height; #endif bResult = !(CNearTreeGetDepth(tree,&depth)) && !(CNearTreeGetSize(tree,&size)); if (bResult) { fprintf(stderr,"CNearTreeTest: testRandomTree1: depth=%lu, size=%lu\n", (unsigned long)depth,(unsigned long)size); } else { fprintf(stderr,"CNearTreeTest: testRandomTree1: get size and depth failed\n"); } #ifdef CNEARTREE_INSTRUMENTED bResult = !(CNearTreeGetDepth(tree,&height)); if (bResult) { fprintf(stderr,"CNearTreeTest: testRandomTree1: height=%lu\n", (unsigned long)height); } else { fprintf(stderr,"CNearTreeTest: testRandomTree1: get height failed\n"); } #endif } { /*verify that the correct extremal point is detected (from below)*/ next[0] = INT_MIN/2; bNear = !CNearTreeNearestNeighbor(tree, (double)LONG_MAX, &vclosest, NULL, next); closest = (int CNEARTREE_FAR *)vclosest; if( ! bNear || closest[0] != nmin ) { ++g_errorCount; fprintf(stdout, "CNearTreeTest: testRandomTree1: NearestNeighbor failed in testRandomTree for min\n" ); } next[0] = INT_MIN/2; bFar = !CNearTreeFarthestNeighbor(tree, &vfarthest, NULL, next); farthest = (int CNEARTREE_FAR *)vfarthest; if( !bFar || farthest[0] != nmax ) { ++g_errorCount; fprintf(stdout, "CNearTreeTest: testRandomTree1: FarthestNeighbor failed in testRandomTree for min\n" ); } } { /*verify that the correct extremal point is detected (from above)*/ next[0] = INT_MAX/2; bNear = !CNearTreeNearestNeighbor(tree, (double)LONG_MAX, &vclosest, NULL, next); closest = (int CNEARTREE_FAR *)vclosest; if( ! bNear || closest[0] != nmax ) { ++g_errorCount; fprintf(stdout, "CNearTreeTest: testRandomTree1: NearestNeighbor failed for max\n" ); } next[0] = INT_MAX/2; bFar = !CNearTreeFarthestNeighbor(tree, &vfarthest, NULL, next); farthest = (int CNEARTREE_FAR *)vfarthest; if( !bFar || farthest[0] != nmin ) { ++g_errorCount; fprintf(stdout, "CNearTreeTest: testRandomTree1: FarthestNeighbor failed for max\n" ); } } { /*verify that for very large radius, every point is detected (from below)*/ bReturn = !CVectorCreate(&v,sizeof(int CNEARTREE_FAR *), 10); if (!bReturn) { ++g_errorCount; fprintf(stdout, "CNearTreeTest: testRandomTree1: CVectorCreate failed\n" ); } radius = DBL_MAX; next[0] = 1; bReturn = !CNearTreeFindInSphere( tree, radius, v, NULL, next, 1); lReturn = CVectorSize(v); if( lReturn != (size_t)n ) { ++g_errorCount; fprintf(stdout, "CNearTreeTest: testRandomTree1: FindInSphere failed, n=%d, lReturn=%lu\n", n, (long unsigned int)lReturn ); } } { /*verify that we find NO points if we are below the lowest and with too small radius*/ bReturn = !CVectorClear(v); radius = .5; next[0] = nmin-1; bReturn = !CNearTreeFindInSphere( tree, radius, v, NULL, next, 1); lReturn = CVectorSize(v); if( lReturn != 0 ) { ++g_errorCount; fprintf(stdout, "CNearTreeTest: testRandomTree1: FindInSphere failed found points incorrectly, n=%d, lReturn=%lu\n", n, (long unsigned int)lReturn ); } } { /*test that the number of found points in a sphere is non-deceasing with increasing radius*/ int lastFoundCount = 0; int cycleCount = 0; bReturn = !CVectorClear(v); radius = 0.00001; /* start with a very small radius (remember these are int's) */ while( radius < 5*(nmax-nmin) ) { ++cycleCount; next[0] = nmin-1; bReturn = !CNearTreeFindInSphere( tree, radius, v, NULL, next, 1); lReturn = CVectorSize(v); if( lReturn < (size_t)lastFoundCount ) { ++g_errorCount; fprintf(stdout, "CNearTreeTest: testRandomTree1: FindInSphere found DECREASING count on increasing radius for radius=%g\n", radius ); break; } else { lastFoundCount = (int)lReturn; radius *= 1.414; } } /* verify that all points were included in the final check (beyond all reasonable distances) */ if( lReturn != (size_t)n ) { ++g_errorCount; fprintf(stdout, "CNearTreeTest: testRandomTree1: FindInSphere did not find all the points\n" ); } } nmax = INT_MIN; nmin = INT_MAX; bReturn = !CNearTreeCreate(&tree,1,CNEARTREE_TYPE_INTEGER|CNEARTREE_FLIP); if (!bReturn) { ++g_errorCount; fprintf(stdout, "CNearTreeTest: testRandomTree1: CNearTreeCreate with flip failed\n" ); } /* Build the tree with n random numbers. Remember the largest and smallest values. */ for( i=0; i nmax ) nmax = next[0]; if( next[0] < nmin ) nmin = next[0]; } if (dbgflg) { size_t depth, size; #ifdef CNEARTREE_INSTRUMENTED size_t height; #endif bResult = !(CNearTreeGetDepth(tree,&depth)) && !(CNearTreeGetSize(tree,&size)); if (bResult) { fprintf(stderr,"CNearTreeTest: testRandomTree1: with flip depth=%lu, size=%lu\n", (unsigned long)depth,(unsigned long)size); } else { fprintf(stderr,"CNearTreeTest: testRandomTree1: with flip get size and depth failed\n"); } #ifdef CNEARTREE_INSTRUMENTED bResult = !(CNearTreeGetDepth(tree,&height)); if (bResult) { fprintf(stderr,"CNearTreeTest: testRandomTree1: height=%lu\n", (unsigned long)height); } else { fprintf(stderr,"CNearTreeTest: testRandomTree1: get height failed\n"); } #endif } { /*verify that the correct extremal point is detected (from below)*/ next[0] = INT_MIN/2; bNear = !CNearTreeNearestNeighbor(tree, (double)LONG_MAX, &vclosest, NULL, next); closest = (int CNEARTREE_FAR *)vclosest; if( ! bNear || closest[0] != nmin ) { ++g_errorCount; fprintf(stdout, "CNearTreeTest: testRandomTree1: NearestNeighbor with flip failed in testRandomTree for min\n" ); } next[0] = INT_MIN/2; bFar = !CNearTreeFarthestNeighbor(tree, &vfarthest, NULL, next); farthest = (int CNEARTREE_FAR *)vfarthest; if( !bFar || farthest[0] != nmax ) { ++g_errorCount; fprintf(stdout, "CNearTreeTest: testRandomTree1: FarthestNeighbor with flip failed in testRandomTree for min\n" ); } } { /*verify that the correct extremal point is detected (from above)*/ next[0] = INT_MAX/2; bNear = !CNearTreeNearestNeighbor(tree, (double)LONG_MAX, &vclosest, NULL, next); closest = (int CNEARTREE_FAR *)vclosest; if( ! bNear || closest[0] != nmax ) { ++g_errorCount; fprintf(stdout, "CNearTreeTest: testRandomTree1: NearestNeighbor with flip failed for max\n" ); } next[0] = INT_MAX/2; bFar = !CNearTreeFarthestNeighbor(tree, &vfarthest, NULL, next); farthest = (int CNEARTREE_FAR *)vfarthest; if( !bFar || farthest[0] != nmin ) { ++g_errorCount; fprintf(stdout, "CNearTreeTest: testRandomTree1: FarthestNeighbor with flip failed for max\n" ); } } { /*verify that for very large radius, every point is detected (from below)*/ bReturn = !CVectorCreate(&v,sizeof(int CNEARTREE_FAR *), 10); if (!bReturn) { ++g_errorCount; fprintf(stdout, "CNearTreeTest: testRandomTree1: CVectorCreate failed\n" ); } radius = DBL_MAX; next[0] = 1; bReturn = !CNearTreeFindInSphere( tree, radius, v, NULL, next, 1); lReturn = CVectorSize(v); if( lReturn != (size_t)n ) { ++g_errorCount; fprintf(stdout, "CNearTreeTest: testRandomTree1: FindInSphere with flip failed, n=%d, lReturn=%lu\n", n, (long unsigned int)lReturn ); } } { /*verify that we find NO points if we are below the lowest and with too small radius*/ bReturn = !CVectorClear(v); radius = .5; next[0] = nmin-1; bReturn = !CNearTreeFindInSphere( tree, radius, v, NULL, next, 1); lReturn = CVectorSize(v); if( lReturn != 0 ) { ++g_errorCount; fprintf(stdout, "CNearTreeTest: testRandomTree1: FindInSphere with flip failed found points incorrectly, n=%d, lReturn=%lu\n", n, (long unsigned int)lReturn ); } } { /*test that the number of found points in a sphere is non-deceasing with increasing radius*/ int lastFoundCount = 0; int cycleCount = 0; bReturn = !CVectorClear(v); radius = 0.00001; /* start with a very small radius (remember these are int's) */ while( radius < 5*(nmax-nmin) ) { ++cycleCount; next[0] = nmin-1; bReturn = !CNearTreeFindInSphere( tree, radius, v, NULL, next, 1); lReturn = CVectorSize(v); if( lReturn < (size_t)lastFoundCount ) { ++g_errorCount; fprintf(stdout, "CNearTreeTest: testRandomTree1: FindInSphere with flip found DECREASING count on increasing radius for radius=%g\n", radius ); break; } else { lastFoundCount = (int)lReturn; radius *= 1.414; } } /* verify that all points were included in the final check (beyond all reasonable distances) */ if( lReturn != (size_t)n ) { ++g_errorCount; fprintf(stdout, "CNearTreeTest: testRandomTree1: FindInSphere with flip did not find all the points\n" ); } } } /* end testRandomTree1 */ /* Utility routines for 17D double vectors */ int LoadVec17(double vec[17]) { size_t i; for (i = 0; i < 17; i++) { vec[i] = CRHrandRandom(&rhr); } return 0; } int ConstVec17(double vec[17], double d) { size_t i; for (i = 0; i < 17; i++) { vec[i] = d; } return 0; } double NormVec17( const double vec[17]) { size_t i; double sum; sum = vec[0]*vec[0]; for (i = 1; i < 17; i++) { sum += vec[i]*vec[i]; } return sqrt(sum); } int CopyVec17(double dst[17], const double src[17]) { size_t i; for (i = 0; i < 17; i++) { dst[i] = src[i]; } return 0; } /*=======================================================================*/ void testBigVector( ) { CNearTreeHandle tree; CVectorHandle vhand; double vAll[1000][17]; /* keep a list of all of the input so we can find particular entries */ double v17min[17]; /* to be the point nearest to the origin */ double v17max[17]; /* to be the point farthest from the origin */ double v[17], vSearch[17], vCenter[17], vCloseToNearCenter[17]; double CNEARTREE_FAR * vv; double CNEARTREE_FAR * vFarthest; void CNEARTREE_FAR * vvFarthest; double CNEARTREE_FAR * vNearCenter; void CNEARTREE_FAR * vvNearCenter; double CNEARTREE_FAR * vExtreme; void CNEARTREE_FAR * vvExtreme; double rmax = -DBL_MAX; double rmin = DBL_MAX; double dmin, dmax; size_t iFoundNearCenter, iFound, i; bool bResult; bResult = !CNearTreeCreate(&tree,17,CNEARTREE_TYPE_DOUBLE); if (!bResult) { ++g_errorCount; fprintf(stdout,"CNearTreeTest: testBigVector: CNearTreeCreate failed\n"); } /* All of the coordinate values will be in the range 0-CRHRAND_MAX. In other words, all of the data points will be within a 17-D cube that has a corner at the origin of the space. */ for( i=0; i<1000; ++i ) { LoadVec17(v); if( NormVec17( v ) < rmin ) { rmin = NormVec17( v ); CopyVec17(v17min, v); } if( NormVec17( v ) > rmax ) { rmax = NormVec17( v ); CopyVec17(v17max, v); } bResult = !CNearTreeImmediateInsert(tree,v,NULL); if (!bResult) { ++g_errorCount; fprintf(stdout,"CNearTreeTest: testBigVector: CNearTreeImmediateInsert failed\n"); } CopyVec17(vAll[i],v); } { /* Find the point farthest from the point that was nearest the origin. */ bResult = !CNearTreeFarthestNeighbor(tree,&vvFarthest,NULL,v17min); vFarthest = (double CNEARTREE_FAR *)vvFarthest; if (!bResult) { ++g_errorCount; fprintf(stdout,"CNearTreeTest: testBigVector: CNearTreeFarthestNeighbor failed\n"); } /* Brute force search for the farthest */ dmax = -DBL_MAX; for( i=0; i<1000; ++i ) { if (CNearTreeDist(tree,vAll[i],v17min) > dmax) { dmax = CNearTreeDist(tree,vAll[i],v17min); CopyVec17(vSearch, vAll[i]); } } if( CNearTreeDist(tree,vSearch,vFarthest) > DBL_MIN ) { ++g_errorCount; fprintf(stdout, "CNearTreeTest: testBigVector: FarthestNeighbor has failed\n" ); } } { /* somewhere in the middle, find a point and its nearest neighbor */ /* make sure that each includes the other in sphere search */ ConstVec17(vCenter, (double)(CRHRAND_MAX/2) ); CVectorCreate(&vhand,sizeof(double CNEARTREE_FAR *),10); bResult = !CNearTreeNearestNeighbor( tree, 100000.0, &vvNearCenter, NULL, vCenter ); vNearCenter = (double CNEARTREE_FAR *)vvNearCenter; if (!bResult) { ++g_errorCount; fprintf(stdout, "CNearTreeTest: testBigVector: CNearTreeNearestNeighbor has failed\n" ); } bResult = !CNearTreeFindInSphere(tree, 1000000.0, vhand, NULL, vNearCenter,1); if (!bResult) { ++g_errorCount; fprintf(stdout, "CNearTreeTest: testBigVector: CNearTreeFindInSphere has failed\n" ); } iFoundNearCenter = CVectorSize(vhand); /* Brute force search for the point closest to the point closest to the center */ dmin = DBL_MAX; for( i=0; i DBL_MIN ) { ++g_errorCount; fprintf(stdout, "CNearTreeTest: testBackForward: NearestNeighbor failed to find %g, found %g instead\n", (double)i+0.25, closest[0] ); } } bResult = !CNearTreeFree(&tree); if (!bResult) { ++g_errorCount; fprintf(stdout, "CNearTreeTest: testBackwardForward: CNearTreeFree has failed\n" ); } bResult = !CNearTreeCreate(&tree,1,CNEARTREE_TYPE_DOUBLE|CNEARTREE_FLIP); if (!bResult) { ++g_errorCount; fprintf(stdout,"CNearTreeTest: testBackwardForward: CNearTreeCreate failed\n"); } for( i=0; i DBL_MIN ) { ++g_errorCount; fprintf(stdout, "CNearTreeTest: testBackForward: NearestNeighbor failed to find %g, found %g instead\n", (double)i+0.25, closest[0] ); } } bResult = !CNearTreeFree(&tree); if (!bResult) { ++g_errorCount; fprintf(stdout, "CNearTreeTest: testBackwardForward: CNearTreeFree has failed\n" ); } } /*=======================================================================*/ void testDelayedInsertion( void ) { CNearTreeHandle tree; CVectorHandle v; const long nmax = 100; double data[1]; double probe[1]; double radius; double fFinal; double CNEARTREE_FAR * closest; double CNEARTREE_FAR * farthest; size_t lReturned; bool bResult, bResult1, bResult2; int i; { /* make sure that CompleteDelayInsert works - note there is no way in the final test to differentiate that from FindInSphere completing the flush. */ bResult = !CNearTreeCreate(&tree,1,CNEARTREE_TYPE_DOUBLE); if (!bResult) { ++g_errorCount; fprintf(stdout,"CNearTreeTest: testDelayedInsertion: CNearTreeCreate (first block) failed\n"); } for( i=1; i<=nmax; ++i ) { if( (i%2) == 0 ) { data[0]=(double)i; bResult1 = ! CNearTreeImmediateInsert(tree,data,NULL); if (!bResult1) { ++g_errorCount; fprintf(stdout,"CNearTreeTest: testDelayedInsertion: CNearTreeImmediateInsert failed for i = %d\n", i); } } else { data[0]=(double)i; bResult2 = ! CNearTreeInsert(tree,data,NULL); if (!bResult2) { ++g_errorCount; fprintf(stdout,"CNearTreeTest: testDelayedInsertion: CNearTreeInsert failed for i = %d\n", i); } } } bResult = !CVectorCreate(&v,sizeof(double CNEARTREE_FAR *),10); if (!bResult) { ++g_errorCount; fprintf(stdout,"CNearTreeTest: testDelayedInsertion: CVectorCreate failed\n"); } radius = 1000.0; if (dbgflg) { size_t depth, size; #ifdef CNEARTREE_INSTRUMENTED size_t height; #endif bResult = !(CNearTreeGetDepth(tree,&depth)) && !(CNearTreeGetSize(tree,&size)); if (bResult) { fprintf(stderr,"CNearTreeTest: testDelayedInsertion: before CNearTreeCompleteDelayedInsert depth=%lu, size=%lu\n", (unsigned long)depth,(unsigned long)size); } else { fprintf(stderr,"CNearTreeTest: testDelayedInsertion: before CNearTreeCompleteDelayedInsert get size and depth failed\n"); } #ifdef CNEARTREE_INSTRUMENTED bResult = !(CNearTreeGetDepth(tree,&height)); if (bResult) { fprintf(stderr,"CNearTreeTest: testDelayedInsertion: height=%lu\n", (unsigned long)height); } else { fprintf(stderr,"CNearTreeTest: testDelayedInsertion: get height failed\n"); } #endif } bResult = !CNearTreeCompleteDelayedInsert(tree); if (!bResult) { ++g_errorCount; fprintf(stdout,"CNearTreeTest: testDelayedInsertion: CNearTreeCompleteDelayedInsert failed\n"); } if (dbgflg) { size_t depth, size; #ifdef CNEARTREE_INSTRUMENTED size_t height; #endif bResult = !(CNearTreeGetDepth(tree,&depth)) && !(CNearTreeGetSize(tree,&size)); if (bResult) { fprintf(stderr,"CNearTreeTest: testDelayedInsertion: after CNearTreeCompleteDelayedInsert depth=%lu, size=%lu\n", (unsigned long)depth,(unsigned long)size); } else { fprintf(stderr,"CNearTreeTest: testDelayedInsertion: after CNearTreeCompleteDelayedInsert get size and depth failed\n"); } #ifdef CNEARTREE_INSTRUMENTED bResult = !(CNearTreeGetDepth(tree,&height)); if (bResult) { fprintf(stderr,"CNearTreeTest: testDelayedInsertion: height=%lu\n", (unsigned long)height); } else { fprintf(stderr,"CNearTreeTest: testDelayedInsertion: get height failed\n"); } #endif } probe[0] = 0.9; bResult = !CNearTreeFindInSphere(tree, radius,v,NULL,probe,1); if (!bResult) { ++g_errorCount; fprintf(stdout,"CNearTreeTest: testDelayedInsertion: CNearTreeFindInSphere failed\n"); } else { lReturned = CVectorSize(v); if( lReturned != (size_t)nmax ) { ++g_errorCount; printf( "CNearTreeTest: testDelayedInsertion: CNearTreeFindInSphere failed for nmax=%ld, found %lu points\n", nmax, (unsigned long)lReturned ); } } bResult = !CVectorFree(&v); if (!bResult) { ++g_errorCount; fprintf(stdout, "CNearTreeTest: testDelayedInsertion: CVectorFree (first block) has failed\n" ); } bResult = !CNearTreeFree(&tree); if (!bResult) { ++g_errorCount; fprintf(stdout, "CNearTreeTest: testDelayedInsertion: CNearTreeFree (first block) has failed\n" ); } } { /* make sure that CompleteDelayInsert works - note there is no way in the final test to differentiate that from FindInSphere completing the flush. */ bResult = !CNearTreeCreate(&tree,1,CNEARTREE_TYPE_DOUBLE|CNEARTREE_FLIP); if (!bResult) { ++g_errorCount; fprintf(stdout,"CNearTreeTest: testDelayedInsertion: CNearTreeCreate (first block) with flip failed\n"); } for( i=1; i<=nmax; ++i ) { if( (i%2) == 0 ) { data[0]=(double)i; bResult1 = ! CNearTreeImmediateInsert(tree,data,NULL); if (!bResult1) { ++g_errorCount; fprintf(stdout,"CNearTreeTest: testDelayedInsertion: CNearTreeImmediateInsert with flip failed for i = %d\n", i); } } else { data[0]=(double)i; bResult2 = ! CNearTreeInsert(tree,data,NULL); if (!bResult2) { ++g_errorCount; fprintf(stdout,"CNearTreeTest: testDelayedInsertion: CNearTreeInsert with flip failed for i = %d\n", i); } } } bResult = !CVectorCreate(&v,sizeof(double CNEARTREE_FAR *),10); if (!bResult) { ++g_errorCount; fprintf(stdout,"CNearTreeTest: testDelayedInsertion: CVectorCreate failed\n"); } radius = 1000.0; if (dbgflg) { size_t depth, size; #ifdef CNEARTREE_INSTRUMENTED size_t height; #endif bResult = !(CNearTreeGetDepth(tree,&depth)) && !(CNearTreeGetSize(tree,&size)); if (bResult) { fprintf(stderr,"CNearTreeTest: testDelayedInsertion: before CNearTreeCompleteDelayedInsert with flip depth=%lu, size=%lu\n", (unsigned long)depth,(unsigned long)size); } else { fprintf(stderr,"CNearTreeTest: testDelayedInsertion: before CNearTreeCompleteDelayedInsert with flip get size and depth failed\n"); } #ifdef CNEARTREE_INSTRUMENTED bResult = !(CNearTreeGetDepth(tree,&height)); if (bResult) { fprintf(stderr,"CNearTreeTest: testDelayedInsertion: height=%lu\n", (unsigned long)height); } else { fprintf(stderr,"CNearTreeTest: testDelayedInsertion: get height failed\n"); } #endif } bResult = !CNearTreeCompleteDelayedInsert(tree); if (!bResult) { ++g_errorCount; fprintf(stdout,"CNearTreeTest: testDelayedInsertion: CNearTreeCompleteDelayedInsert failed\n"); } if (dbgflg) { size_t depth, size; #ifdef CNEARTREE_INSTRUMENTED size_t height; #endif bResult = !(CNearTreeGetDepth(tree,&depth)) && !(CNearTreeGetSize(tree,&size)); if (bResult) { fprintf(stderr,"CNearTreeTest: testDelayedInsertion: after CNearTreeCompleteDelayedInsert depth=%lu, size=%lu\n", (unsigned long)depth,(unsigned long)size); } else { fprintf(stderr,"CNearTreeTest: testDelayedInsertion: after CNearTreeCompleteDelayedInsert get size and depth failed\n"); } #ifdef CNEARTREE_INSTRUMENTED bResult = !(CNearTreeGetDepth(tree,&height)); if (bResult) { fprintf(stderr,"CNearTreeTest: testDelayedInsertion: height=%lu\n", (unsigned long)height); } else { fprintf(stderr,"CNearTreeTest: testDelayedInsertion: get height failed\n"); } #endif } probe[0] = 0.9; bResult = !CNearTreeFindInSphere(tree, radius,v,NULL,probe,1); if (!bResult) { ++g_errorCount; fprintf(stdout,"CNearTreeTest: testDelayedInsertion: CNearTreeFindInSphere failed\n"); } else { lReturned = CVectorSize(v); if( lReturned != (size_t)nmax ) { ++g_errorCount; printf( "CNearTreeTest: testDelayedInsertion: CNearTreeFindInSphere failed for nmax=%ld, found %lu points\n", nmax, (unsigned long)lReturned ); } } bResult = !CVectorFree(&v); if (!bResult) { ++g_errorCount; fprintf(stdout, "CNearTreeTest: testDelayedInsertion: CVectorFree (first block) has failed\n" ); } bResult = !CNearTreeFree(&tree); if (!bResult) { ++g_errorCount; fprintf(stdout, "CNearTreeTest: testDelayedInsertion: CNearTreeFree (first block) has failed\n" ); } } { /* make sure that FindInSphere flushes the delayed data */ bResult = !CNearTreeCreate(&tree,1,CNEARTREE_TYPE_DOUBLE); if (!bResult) { ++g_errorCount; fprintf(stdout,"CNearTreeTest: testDelayedInsertion: CNearTreeCreate (second block) failed\n"); } for( i=1; i<=nmax; ++i ) { if( (i%2) == 0 ) { data[0]=(double)i; bResult1 = ! CNearTreeImmediateInsert(tree,data,NULL); if (!bResult1) { ++g_errorCount; fprintf(stdout,"CNearTreeTest: testDelayedInsertion: CNearTreeImmediateInsert (second block) failed for i = %d\n", i); } } else { data[0]=(double)i; bResult2 = ! CNearTreeInsert(tree,data,NULL); if (!bResult2) { ++g_errorCount; fprintf(stdout,"CNearTreeTest: testDelayedInsertion: CNearTreeInsert (second block) failed for i = %d\n", i); } } } bResult = !CVectorCreate(&v,sizeof(double CNEARTREE_FAR *),10); if (!bResult) { ++g_errorCount; fprintf(stdout,"CNearTreeTest: testDelayedInsertion: CVectorCreate (second block) failed\n"); } radius = 1000.0; probe[0] = 0.9; bResult = !CNearTreeFindInSphere(tree, radius,v,NULL,probe,1); if (!bResult) { ++g_errorCount; fprintf(stdout,"CNearTreeTest: testDelayedInsertion: CNearTreeFindInSphere (second block) failed\n"); } else { lReturned = CVectorSize(v); if( lReturned != (size_t)nmax ) { ++g_errorCount; printf( "CNearTreeTest: testDelayedInsertion: CNearTreeFindInSphere (second block) failed for nmax=%ld, found %lu points\n", nmax, (unsigned long)lReturned ); } } bResult = !CVectorFree(&v); if (!bResult) { ++g_errorCount; fprintf(stdout, "CNearTreeTest: testDelayedInsertion: CVectorFree (second block) has failed\n" ); } bResult = !CNearTreeFree(&tree); if (!bResult) { ++g_errorCount; fprintf(stdout, "CNearTreeTest: testDelayedInsertion: CNearTreeFree (second block) has failed\n" ); } } { /* make sure that NearestNeighbor flushes the delayed data */ fFinal = DBL_MAX; bResult = !CNearTreeCreate(&tree,1,CNEARTREE_TYPE_DOUBLE); if (!bResult) { ++g_errorCount; fprintf(stdout,"CNearTreeTest: testDelayedInsertion: CNearTreeCreate (third block) failed\n"); } for( i=1; i<=nmax; ++i ) { if( (i%2) == 0 && i!=nmax) /* ensure that the last one is delayed */ { data[0]=(double)i; bResult1 = ! CNearTreeImmediateInsert(tree,data,NULL); if (!bResult1) { ++g_errorCount; fprintf(stdout,"CNearTreeTest: testDelayedInsertion: CNearTreeImmediateInsert failed for i = %d\n", i); } } else { data[0]=(double)i; bResult2 = ! CNearTreeInsert(tree,data,NULL); if (!bResult2) { ++g_errorCount; fprintf(stdout,"CNearTreeTest: testDelayedInsertion: CNearTreeInsert (third block) failed for i = %d\n", i); } fFinal = (double)i; } } radius = 0.1; probe[0] = fFinal; bResult = !CNearTreeNearestNeighbor( tree, radius, (void CNEARTREE_FAR *)&closest, NULL, probe ); if( ! bResult ) { ++g_errorCount; fprintf(stdout,"CNearTreeTest: testDelayedInsertion: CNearTreeNearestNeighbor failed \n" ); } else if( closest[0] != fFinal ) { ++g_errorCount; fprintf(stdout,"CNearTreeTest: testDelayedInsertion: NearestNeighbor failed to find the data\n" ); } bResult = !CNearTreeFree(&tree); if (!bResult) { ++g_errorCount; fprintf(stdout, "CNearTreeTest: testDelayedInsertion: CNearTreeFree (third block) has failed\n" ); } } { /* make sure that FarthestNeighbor flushes the delayed data */ bResult = !CNearTreeCreate(&tree,1,CNEARTREE_TYPE_DOUBLE); if (!bResult) { ++g_errorCount; fprintf(stdout,"CNearTreeTest: testDelayedInsertion: CNearTreeCreate (fourth block) failed\n"); } fFinal = DBL_MAX; for( i=1; i<=nmax; ++i ) { if( (i%2) == 0 && i!=nmax) /* ensure that the last one is delayed */ { data[0]=(double)i; bResult1 = ! CNearTreeImmediateInsert(tree,data,NULL); if (!bResult1) { ++g_errorCount; fprintf(stdout,"CNearTreeTest: testDelayedInsertion: CNearTreeImmediateInsert (fourth block) failed for i = %d\n", i); } } else { data[0]=(double)i; bResult2 = ! CNearTreeInsert(tree,data,NULL); if (!bResult2) { ++g_errorCount; fprintf(stdout,"CNearTreeTest: testDelayedInsertion: CNearTreeInsert (fourth block) failed for i = %d\n", i); } fFinal = (double)i; } } probe[0] = -100; bResult = !CNearTreeFarthestNeighbor( tree, (void CNEARTREE_FAR *)&farthest, NULL, probe ); if( ! bResult ) { ++g_errorCount; fprintf(stdout,"CNearTreeTest: testDelayedInsertion: CNearTreeFarthestNeighbor failed \n" ); } else if( farthest[0] != fFinal ) { ++g_errorCount; fprintf(stdout,"CNearTreeTest: testDelayedInsertion: FarthestNeighbor failed to find the data\n" ); } bResult = !CNearTreeFree(&tree); if (!bResult) { ++g_errorCount; fprintf(stdout, "CNearTreeTest: testDelayedInsertion: CNearTreeFree (third block) has failed\n" ); } } } /*=======================================================================*/ void testKNearFar( void ) { CNearTreeHandle tree; CNearTreeHandle outTree; CVectorHandle v; bool bReturn; int searchPoint[1]; double radius; size_t lReturned; int i; bReturn = !CNearTreeCreate(&tree,1,CNEARTREE_TYPE_INTEGER); if (!bReturn) { ++g_errorCount; fprintf(stdout, "CNearTreeTest: testKNearFar: CNearTreeCreate failed\n" ); } bReturn = !CNearTreeCreate(&outTree,1,CNEARTREE_TYPE_INTEGER); if (!bReturn) { ++g_errorCount; fprintf(stdout, "CNearTreeTest: testKNearFar: CNearTreeCreate failed\n" ); } bReturn = !CVectorCreate(&v,sizeof(double CNEARTREE_FAR *),10); if (!bReturn) { ++g_errorCount; fprintf(stdout, "CNearTreeTest: testKNearFar: CVectorCreate failed\n" ); } searchPoint[0] = 50; radius = 1000.; bReturn = !CNearTreeFindKTreeNearest(tree,0,radius,outTree,searchPoint,1); lReturned = CNearTreeSize(outTree); if (lReturned != 0) { ++g_errorCount; fprintf(stdout, "CNearTreeTest: testKNearFar: Near: found wrong count #0\n" ); } for( i=1; i<=100; ++i ) { searchPoint[0] = i; bReturn = !CNearTreeImmediateInsert(tree,searchPoint, NULL); if (!bReturn) { ++g_errorCount; fprintf(stdout, "CNearTreeTest: testKNearFar: CNearTreeImmediateInsert failed\n" ); } } searchPoint[0] = 50; radius = 3.5; bReturn = !CNearTreeFindKTreeNearest(tree,13,radius,outTree,searchPoint,1); lReturned = CNearTreeSize(outTree); if (lReturned != 7) { ++g_errorCount; fprintf(stdout, "CNearTreeTest: testKNearFar: Near: found wrong tree count #1\n" ); } bReturn = !CNearTreeFindKNearest(tree,13,radius,v,NULL,searchPoint,1); lReturned = CVectorSize(v); if (lReturned != 7) { ++g_errorCount; fprintf(stdout, "CNearTreeTest: testKNearFar: Near: found wrong vector count #1\n" ); } searchPoint[0] = 98; radius = 3.5; bReturn = !CNearTreeFindKTreeNearest(tree,13,radius,outTree,searchPoint,1); lReturned = CNearTreeSize(outTree); if (lReturned != 6) { ++g_errorCount; fprintf(stdout, "CNearTreeTest: testKNearFar: Near: found wrong tree count #2\n" ); } bReturn = !CNearTreeFindKNearest(tree,13,radius,v,NULL,searchPoint,1); lReturned = CVectorSize(v); if (lReturned != 6) { ++g_errorCount; fprintf(stdout, "CNearTreeTest: testKNearFar: Near: found wrong vector count #2\n" ); } searchPoint[0] = 50; radius = 12.; bReturn = !CNearTreeFindKTreeNearest(tree,7,radius,outTree,searchPoint,1); lReturned = CNearTreeSize(outTree); if (lReturned != 7) { ++g_errorCount; fprintf(stdout, "CNearTreeTest: testKNearFar: Near: found wrong tree count #3\n" ); } bReturn = !CNearTreeFindKNearest(tree,7,radius,v,NULL,searchPoint,1); lReturned = CVectorSize(v); if (lReturned != 7) { ++g_errorCount; fprintf(stdout, "CNearTreeTest: testKNearFar: Near: found wrong vector count #3\n" ); } searchPoint[0] = 2; radius = 12.; bReturn = !CNearTreeFindKTreeNearest(tree,7,radius,outTree,searchPoint,1); lReturned = CNearTreeSize(outTree); if (lReturned != 7) { ++g_errorCount; fprintf(stdout, "CNearTreeTest: testKNearFar: Near: found wrong tree count #4\n" ); } bReturn = !CNearTreeFindKNearest(tree,7,radius,v,NULL,searchPoint,1); lReturned = CVectorSize(v); if (lReturned != 7) { ++g_errorCount; fprintf(stdout, "CNearTreeTest: testKNearFar: Near: found wrong vector count #4\n" ); } searchPoint[0] = 2; radius = 3.5; bReturn = !CNearTreeFindKTreeNearest(tree,7,radius,outTree,searchPoint,1); lReturned = CNearTreeSize(outTree); if (lReturned != 5) { ++g_errorCount; fprintf(stdout, "CNearTreeTest: testKNearFar: Near: found wrong tree count #5\n" ); } bReturn = !CNearTreeFindKNearest(tree,7,radius,v,NULL,searchPoint,1); lReturned = CVectorSize(v); if (lReturned != 5) { ++g_errorCount; fprintf(stdout, "CNearTreeTest: testKNearFar: Near: found wrong vector count #5\n" ); } searchPoint[0] = -1; radius = 0.; bReturn = !CNearTreeFindKTreeFarthest(tree,13,radius,outTree,searchPoint,1); lReturned = CNearTreeSize(outTree); if (lReturned != 13) { ++g_errorCount; fprintf(stdout, "CNearTreeTest: testKNearFar: CNEARTREE_FAR: found wrong tree count #1\n" ); } bReturn = !CNearTreeFindKFarthest(tree,13,radius,v,NULL,searchPoint,1); lReturned = CVectorSize(v); if (lReturned != 13) { ++g_errorCount; fprintf(stdout, "CNearTreeTest: testKNearFar: CNEARTREE_FAR: found wrong vector count #1\n" ); } searchPoint[0] = 50; radius = 0.; bReturn = !CNearTreeFindKTreeFarthest(tree,13,radius,outTree,searchPoint,1); lReturned = CNearTreeSize(outTree); if (lReturned != 13) { ++g_errorCount; fprintf(stdout, "CNearTreeTest: testKNearFar: CNEARTREE_FAR: found wrong tree count #2\n" ); } bReturn = !CNearTreeFindKFarthest(tree,13,radius,v,NULL,searchPoint,1); lReturned = CVectorSize(v); if (lReturned != 13) { ++g_errorCount; fprintf(stdout, "CNearTreeTest: testKNearFar: CNEARTREE_FAR: found wrong vector count #2\n" ); } searchPoint[0] = 150; radius = 0.; bReturn = !CNearTreeFindKTreeFarthest(tree,7,radius,outTree,searchPoint,1); lReturned = CNearTreeSize(outTree); if (lReturned != 7) { ++g_errorCount; fprintf(stdout, "CNearTreeTest: testKNearFar: CNEARTREE_FAR: found wrong tree count #3\n" ); } bReturn = !CNearTreeFindKFarthest(tree,7,radius,v,NULL,searchPoint,1); lReturned = CVectorSize(v); if (lReturned != 7) { ++g_errorCount; fprintf(stdout, "CNearTreeTest: testKNearFar: CNEARTREE_FAR: found wrong vector count #3\n" ); } searchPoint[0] = 46; radius = 0.; bReturn = !CNearTreeFindKTreeFarthest(tree,12,radius,outTree,searchPoint,1); lReturned = CNearTreeSize(outTree); if (lReturned != 12) { ++g_errorCount; fprintf(stdout, "CNearTreeTest: testKNearFar: CNEARTREE_FAR: found wrong tree count #4\n" ); } bReturn = !CNearTreeFindKFarthest(tree,12,radius,v,NULL,searchPoint,1); lReturned = CVectorSize(v); if (lReturned != 12) { ++g_errorCount; fprintf(stdout, "CNearTreeTest: testKNearFar: CNEARTREE_FAR: found wrong vector count #4\n" ); } searchPoint[0] = 2; radius = 0.; bReturn = !CNearTreeFindKTreeFarthest(tree,7,radius,outTree,searchPoint,1); lReturned = CNearTreeSize(outTree); if (lReturned != 7) { ++g_errorCount; fprintf(stdout, "CNearTreeTest: testKNearFar: CNEARTREE_FAR: found wrong tree count #5\n" ); } bReturn = !CNearTreeFindKFarthest(tree,7,radius,v,NULL,searchPoint,1); lReturned = CVectorSize(v); if (lReturned != 7) { ++g_errorCount; fprintf(stdout, "CNearTreeTest: testKNearFar: CNEARTREE_FAR: found wrong vector count #5\n" ); } searchPoint[0] = 200; radius = 0.; bReturn = !CNearTreeFindKTreeFarthest(tree,7,radius,outTree,searchPoint,1); lReturned = CNearTreeSize(outTree); if (lReturned != 7) { ++g_errorCount; fprintf(stdout, "CNearTreeTest: testKNearFar: CNEARTREE_FAR: found wrong tree count #6\n" ); } bReturn = !CNearTreeFindKFarthest(tree,7,radius,v,NULL,searchPoint,1); lReturned = CVectorSize(v); if (lReturned != 7) { ++g_errorCount; fprintf(stdout, "CNearTreeTest: testKNearFar: CNEARTREE_FAR: found wrong vector count #6\n" ); } searchPoint[0] = 2; radius = 95.; bReturn = !CNearTreeFindKTreeFarthest(tree,7,radius,outTree,searchPoint,1); lReturned = CNearTreeSize(outTree); if (lReturned != 4) { ++g_errorCount; fprintf(stdout, "CNearTreeTest: testKNearFar: CNEARTREE_FAR: found wrong tree count #7\n" ); } bReturn = !CNearTreeFindKFarthest(tree,7,radius,v,NULL,searchPoint,1); lReturned = CVectorSize(v); if (lReturned != 4) { ++g_errorCount; fprintf(stdout, "CNearTreeTest: testKNearFar: CNEARTREE_FAR: found wrong vector count #7\n" ); } bReturn = !CVectorFree(&v); if (!bReturn) { ++g_errorCount; fprintf(stdout, "CNearTreeTest: testKNearFar: CVectorFree failed\n"); } bReturn = !CNearTreeFree(&outTree); if (!bReturn) { ++g_errorCount; fprintf(stdout, "CNearTreeTest: testKNearFar: CNearTreeFree failed\n"); } bReturn = !CNearTreeFree(&tree); if (!bReturn) { ++g_errorCount; fprintf(stdout, "CNearTreeTest: testKNearFar: CNearTreeFree failed\n"); } } /*=======================================================================*/ void test4Sphere( void ) { CNearTreeHandle tree; bool bReturn; double searchPoint[4]; double vect[4]; double CNEARTREE_FAR * v; void CNEARTREE_FAR * vv; int ii, jj; bReturn = !CNearTreeCreate(&tree,4,CNEARTREE_TYPE_DOUBLE|CNEARTREE_NORM_SPHERE); if (!bReturn) { ++g_errorCount; fprintf(stdout, "CNearTreeTest: test4Sphere: CNearTreeCreate failed\n" ); } vect[0] = vect[1] = vect[2] = vect[3] = 0.; bReturn = !CNearTreeImmediateInsert(tree,vect, NULL); if (!bReturn) { ++g_errorCount; fprintf(stdout, "CNearTreeTest: test4Sphere: CNearTreeImmediateInsert failed at origin\n" ); } for (ii=0; ii < 4; ii++) { for (jj=0; jj < 10; jj++) { vect[0] = vect[1] = vect[2] = vect[3] = 0.; vect[ii] = (double)jj; bReturn = !CNearTreeImmediateInsert(tree,vect, NULL); if (!bReturn) { ++g_errorCount; fprintf(stdout, "CNearTreeTest: test4Sphere: CNearTreeImmediateInsert failed at [%g,%g,%g,%g]\n", vect[0],vect[1],vect[2],vect[3]); } } } searchPoint[0] = searchPoint[1] = searchPoint[2] = searchPoint[3] = 0.49999; bReturn = !CNearTreeNearestNeighbor(tree, 1.999, &vv, NULL, searchPoint); v = (double CNEARTREE_FAR *)vv; if (!bReturn || v[0] !=0. || v[1] !=0. || v[2] != 0. || v[3] != 0.) { ++g_errorCount; fprintf(stdout, "CNearTreeTest: test4Sphere: NearestNeighbor failed, got [%g,%g,%g,%g], should be [0,0,0,0]\n", v[0], v[1], v[2], v[3] ); } searchPoint[0] = searchPoint[1] = 0.; searchPoint[2] = 0.700; searchPoint[3] = 0.710; bReturn = !CNearTreeNearestNeighbor(tree, 6.0, &vv, NULL, searchPoint); v = (double CNEARTREE_FAR *)vv; if (!bReturn || v[0] !=0. || v[1] !=0. || v[2] != 0. || v[3] != 1.) { ++g_errorCount; fprintf(stdout, "CNearTreeTest: test4Sphere: NearestNeighbor failed, got [%g,%g,%g,%g], should be [0,0,0,1]\n", v[0], v[1], v[2], v[3] ); } searchPoint[0] = searchPoint[1] = 0.; searchPoint[2] = 0.700*1.75; searchPoint[3] = 0.710*1.75; bReturn = !CNearTreeNearestNeighbor(tree, 6.0, &vv, NULL, searchPoint); v = (double CNEARTREE_FAR *)vv; if (!bReturn || v[0] !=0. || v[1] !=0. || v[2] != 0. || v[3] != 1.) { ++g_errorCount; fprintf(stdout, "CNearTreeTest: test4Sphere: NearestNeighbor failed, got [%g,%g,%g,%g], should be [0,0,0,1]\n", v[0], v[1], v[2], v[3] ); } } /*=======================================================================*/ void testStrings( void ) { CNearTreeHandle tree; bool bReturn; char searchPoint[4]; char vstring[4]; char CNEARTREE_FAR * v; void CNEARTREE_FAR * vv; int ii, jj; bReturn = !CNearTreeCreate(&tree,4,CNEARTREE_TYPE_STRING|CNEARTREE_NORM_HAMMING); if (!bReturn) { ++g_errorCount; fprintf(stdout, "CNearTreeTest: testStrings: CNearTreeCreate failed\n" ); } strncpy(vstring,"",4); bReturn = !CNearTreeImmediateInsert(tree,vstring, NULL); if (!bReturn) { ++g_errorCount; fprintf(stdout, "CNearTreeTest: testStrings: CNearTreeImmediateInsert failed on all blanks\n" ); } for (ii=0; ii < 4; ii++) { for (jj=0; jj < 10; jj++) { vstring[0] = vstring[1] = vstring[2] = vstring[3] = ' '; vstring[ii] = 'a'+jj; bReturn = !CNearTreeImmediateInsert(tree,vstring, NULL); if (!bReturn) { ++g_errorCount; fprintf(stdout, "CNearTreeTest: test4Sphere: CNearTreeImmediateInsert failed at %c%c%c%c\n", vstring[0],vstring[1],vstring[2],vstring[3]); } } } searchPoint[0] = searchPoint[1] = searchPoint[2] = searchPoint[3] = 'a'; bReturn = !CNearTreeNearestNeighbor(tree, 3.999, &vv, NULL, searchPoint); v = (char CNEARTREE_FAR *)vv; if (!bReturn || (v[0] !='a' && v[1] !='a' && v[2] != 'a' && v[3] != 'a')) { ++g_errorCount; fprintf(stdout, "CNearTreeTest: test4Sphere: NearestNeighbor failed, got %c%c%c%c, should have one 'a' \n", v[0], v[1], v[2], v[3] ); } searchPoint[0] = searchPoint[1] = ' '; searchPoint[2] = 'b'; searchPoint[3] = 'b'; bReturn = !CNearTreeNearestNeighbor(tree, 3.999, &vv, NULL, searchPoint); v = (char CNEARTREE_FAR *)vv; if (!bReturn || (v[0] !=' ' || v[1] !=' ' || (v[2] != 'b' && v[3] != 'b'))) { ++g_errorCount; fprintf(stdout, "CNearTreeTest: test4Sphere: NearestNeighbor failed, got %c%c%c%c, should have one 'b'\n", v[0], v[1], v[2], v[3] ); } } ./NearTree-3.1.1/lgpl.txt0000644002342100234170000006350011640401607015126 0ustar bernstehfaculty GNU LESSER GENERAL PUBLIC LICENSE Version 2.1, February 1999 Copyright (C) 1991, 1999 Free Software Foundation, Inc. 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. [This is the first released version of the Lesser GPL. It also counts as the successor of the GNU Library Public License, version 2, hence the version number 2.1.] Preamble The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public Licenses are intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This license, the Lesser General Public License, applies to some specially designated software packages--typically libraries--of the Free Software Foundation and other authors who decide to use it. You can use it too, but we suggest you first think carefully about whether this license or the ordinary General Public License is the better strategy to use in any particular case, based on the explanations below. When we speak of free software, we are referring to freedom of use, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for this service if you wish); that you receive source code or can get it if you want it; that you can change the software and use pieces of it in new free programs; and that you are informed that you can do these things. To protect your rights, we need to make restrictions that forbid distributors to deny you these rights or to ask you to surrender these rights. These restrictions translate to certain responsibilities for you if you distribute copies of the library or if you modify it. For example, if you distribute copies of the library, whether gratis or for a fee, you must give the recipients all the rights that we gave you. You must make sure that they, too, receive or can get the source code. If you link other code with the library, you must provide complete object files to the recipients, so that they can relink them with the library after making changes to the library and recompiling it. And you must show them these terms so they know their rights. We protect your rights with a two-step method: (1) we copyright the library, and (2) we offer you this license, which gives you legal permission to copy, distribute and/or modify the library. To protect each distributor, we want to make it very clear that there is no warranty for the free library. Also, if the library is modified by someone else and passed on, the recipients should know that what they have is not the original version, so that the original author's reputation will not be affected by problems that might be introduced by others. Finally, software patents pose a constant threat to the existence of any free program. We wish to make sure that a company cannot effectively restrict the users of a free program by obtaining a restrictive license from a patent holder. Therefore, we insist that any patent license obtained for a version of the library must be consistent with the full freedom of use specified in this license. Most GNU software, including some libraries, is covered by the ordinary GNU General Public License. This license, the GNU Lesser General Public License, applies to certain designated libraries, and is quite different from the ordinary General Public License. We use this license for certain libraries in order to permit linking those libraries into non-free programs. When a program is linked with a library, whether statically or using a shared library, the combination of the two is legally speaking a combined work, a derivative of the original library. The ordinary General Public License therefore permits such linking only if the entire combination fits its criteria of freedom. The Lesser General Public License permits more lax criteria for linking other code with the library. We call this license the "Lesser" General Public License because it does Less to protect the user's freedom than the ordinary General Public License. It also provides other free software developers Less of an advantage over competing non-free programs. These disadvantages are the reason we use the ordinary General Public License for many libraries. However, the Lesser license provides advantages in certain special circumstances. For example, on rare occasions, there may be a special need to encourage the widest possible use of a certain library, so that it becomes a de-facto standard. To achieve this, non-free programs must be allowed to use the library. A more frequent case is that a free library does the same job as widely used non-free libraries. In this case, there is little to gain by limiting the free library to free software only, so we use the Lesser General Public License. In other cases, permission to use a particular library in non-free programs enables a greater number of people to use a large body of free software. For example, permission to use the GNU C Library in non-free programs enables many more people to use the whole GNU operating system, as well as its variant, the GNU/Linux operating system. Although the Lesser General Public License is Less protective of the users' freedom, it does ensure that the user of a program that is linked with the Library has the freedom and the wherewithal to run that program using a modified version of the Library. The precise terms and conditions for copying, distribution and modification follow. Pay close attention to the difference between a "work based on the library" and a "work that uses the library". The former contains code derived from the library, whereas the latter must be combined with the library in order to run. GNU LESSER GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License Agreement applies to any software library or other program which contains a notice placed by the copyright holder or other authorized party saying it may be distributed under the terms of this Lesser General Public License (also called "this License"). Each licensee is addressed as "you". A "library" means a collection of software functions and/or data prepared so as to be conveniently linked with application programs (which use some of those functions and data) to form executables. The "Library", below, refers to any such software library or work which has been distributed under these terms. A "work based on the Library" means either the Library or any derivative work under copyright law: that is to say, a work containing the Library or a portion of it, either verbatim or with modifications and/or translated straightforwardly into another language. (Hereinafter, translation is included without limitation in the term "modification".) "Source code" for a work means the preferred form of the work for making modifications to it. For a library, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the library. Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running a program using the Library is not restricted, and output from such a program is covered only if its contents constitute a work based on the Library (independent of the use of the Library in a tool for writing it). Whether that is true depends on what the Library does and what the program that uses the Library does. 1. You may copy and distribute verbatim copies of the Library's complete source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and distribute a copy of this License along with the Library. You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. 2. You may modify your copy or copies of the Library or any portion of it, thus forming a work based on the Library, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions: a) The modified work must itself be a software library. b) You must cause the files modified to carry prominent notices stating that you changed the files and the date of any change. c) You must cause the whole of the work to be licensed at no charge to all third parties under the terms of this License. d) If a facility in the modified Library refers to a function or a table of data to be supplied by an application program that uses the facility, other than as an argument passed when the facility is invoked, then you must make a good faith effort to ensure that, in the event an application does not supply such function or table, the facility still operates, and performs whatever part of its purpose remains meaningful. (For example, a function in a library to compute square roots has a purpose that is entirely well-defined independent of the application. Therefore, Subsection 2d requires that any application-supplied function or table used by this function must be optional: if the application does not supply it, the square root function must still compute square roots.) These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Library, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Library, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it. Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Library. In addition, mere aggregation of another work not based on the Library with the Library (or with a work based on the Library) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. 3. You may opt to apply the terms of the ordinary GNU General Public License instead of this License to a given copy of the Library. To do this, you must alter all the notices that refer to this License, so that they refer to the ordinary GNU General Public License, version 2, instead of to this License. (If a newer version than version 2 of the ordinary GNU General Public License has appeared, then you can specify that version instead if you wish.) Do not make any other change in these notices. Once this change is made in a given copy, it is irreversible for that copy, so the ordinary GNU General Public License applies to all subsequent copies and derivative works made from that copy. This option is useful when you wish to copy part of the code of the Library into a program that is not a library. 4. You may copy and distribute the Library (or a portion or derivative of it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange. If distribution of object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place satisfies the requirement to distribute the source code, even though third parties are not compelled to copy the source along with the object code. 5. A program that contains no derivative of any portion of the Library, but is designed to work with the Library by being compiled or linked with it, is called a "work that uses the Library". Such a work, in isolation, is not a derivative work of the Library, and therefore falls outside the scope of this License. However, linking a "work that uses the Library" with the Library creates an executable that is a derivative of the Library (because it contains portions of the Library), rather than a "work that uses the library". The executable is therefore covered by this License. Section 6 states terms for distribution of such executables. When a "work that uses the Library" uses material from a header file that is part of the Library, the object code for the work may be a derivative work of the Library even though the source code is not. Whether this is true is especially significant if the work can be linked without the Library, or if the work is itself a library. The threshold for this to be true is not precisely defined by law. If such an object file uses only numerical parameters, data structure layouts and accessors, and small macros and small inline functions (ten lines or less in length), then the use of the object file is unrestricted, regardless of whether it is legally a derivative work. (Executables containing this object code plus portions of the Library will still fall under Section 6.) Otherwise, if the work is a derivative of the Library, you may distribute the object code for the work under the terms of Section 6. Any executables containing that work also fall under Section 6, whether or not they are linked directly with the Library itself. 6. As an exception to the Sections above, you may also combine or link a "work that uses the Library" with the Library to produce a work containing portions of the Library, and distribute that work under terms of your choice, provided that the terms permit modification of the work for the customer's own use and reverse engineering for debugging such modifications. You must give prominent notice with each copy of the work that the Library is used in it and that the Library and its use are covered by this License. You must supply a copy of this License. If the work during execution displays copyright notices, you must include the copyright notice for the Library among them, as well as a reference directing the user to the copy of this License. Also, you must do one of these things: a) Accompany the work with the complete corresponding machine-readable source code for the Library including whatever changes were used in the work (which must be distributed under Sections 1 and 2 above); and, if the work is an executable linked with the Library, with the complete machine-readable "work that uses the Library", as object code and/or source code, so that the user can modify the Library and then relink to produce a modified executable containing the modified Library. (It is understood that the user who changes the contents of definitions files in the Library will not necessarily be able to recompile the application to use the modified definitions.) b) Use a suitable shared library mechanism for linking with the Library. A suitable mechanism is one that (1) uses at run time a copy of the library already present on the user's computer system, rather than copying library functions into the executable, and (2) will operate properly with a modified version of the library, if the user installs one, as long as the modified version is interface-compatible with the version that the work was made with. c) Accompany the work with a written offer, valid for at least three years, to give the same user the materials specified in Subsection 6a, above, for a charge no more than the cost of performing this distribution. d) If distribution of the work is made by offering access to copy from a designated place, offer equivalent access to copy the above specified materials from the same place. e) Verify that the user has already received a copy of these materials or that you have already sent this user a copy. For an executable, the required form of the "work that uses the Library" must include any data and utility programs needed for reproducing the executable from it. However, as a special exception, the materials to be distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable. It may happen that this requirement contradicts the license restrictions of other proprietary libraries that do not normally accompany the operating system. Such a contradiction means you cannot use both them and the Library together in an executable that you distribute. 7. You may place library facilities that are a work based on the Library side-by-side in a single library together with other library facilities not covered by this License, and distribute such a combined library, provided that the separate distribution of the work based on the Library and of the other library facilities is otherwise permitted, and provided that you do these two things: a) Accompany the combined library with a copy of the same work based on the Library, uncombined with any other library facilities. This must be distributed under the terms of the Sections above. b) Give prominent notice with the combined library of the fact that part of it is a work based on the Library, and explaining where to find the accompanying uncombined form of the same work. 8. You may not copy, modify, sublicense, link with, or distribute the Library except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense, link with, or distribute the Library is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance. 9. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Library or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Library (or any work based on the Library), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Library or works based on it. 10. Each time you redistribute the Library (or any work based on the Library), the recipient automatically receives a license from the original licensor to copy, distribute, link with or modify the Library subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties with this License. 11. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Library at all. For example, if a patent license would not permit royalty-free redistribution of the Library by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Library. If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply, and the section as a whole is intended to apply in other circumstances. It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice. This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. 12. If the distribution and/or use of the Library is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Library under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License. 13. The Free Software Foundation may publish revised and/or new versions of the Lesser General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Library specifies a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Library does not specify a license version number, you may choose any version ever published by the Free Software Foundation. 14. If you wish to incorporate parts of the Library into other free programs whose distribution conditions are incompatible with these, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. NO WARRANTY 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. END OF TERMS AND CONDITIONS How to Apply These Terms to Your New Libraries If you develop a new library, and you want it to be of the greatest possible use to the public, we recommend making it free software that everyone can redistribute and change. You can do so by permitting redistribution under these terms (or, alternatively, under the terms of the ordinary General Public License). To apply these terms, attach the following notices to the library. It is safest to attach them to the start of each source file to most effectively convey the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. Copyright (C) This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA Also add information on how to contact you by electronic and paper mail. You should also get your employer (if you work as a programmer) or your school, if any, to sign a "copyright disclaimer" for the library, if necessary. Here is a sample; alter the names: Yoyodyne, Inc., hereby disclaims all copyright interest in the library `Frob' (a library for tweaking knobs) written by James Random Hacker. , 1 April 1990 Ty Coon, President of Vice That's all there is to it! ./NearTree-3.1.1/main_flip.cpp0000644002342100234170000001175711640401607016100 0ustar bernstehfaculty//* //* main.cpp //* NearTree //* //* Copyright 2001, 2008 Larry Andrews. All rights reserved //* Revised 12 Dec 2008 for sourceforge release -- H. J. Bernstein //********************************************************************** //* * //* YOU MAY REDISTRIBUTE NearTree UNDER THE TERMS OF THE LGPL * //* * //**********************************************************************/ //************************* LGPL NOTICES ******************************* //* * //* This library is free software; you can redistribute it and/or * //* modify it under the terms of the GNU Lesser General Public * //* License as published by the Free Software Foundation; either * //* version 2.1 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 * //* Lesser General Public License for more details. * //* * //* You should have received a copy of the GNU Lesser General Public * //* License along with this library; if not, write to the Free * //* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, * //* MA 02110-1301 USA * //* * //**********************************************************************/ #include #include #include #include #include #include #include #include "TNear.h" #include "v.h" #ifndef USE_LOCAL_HEADERS #include #else #include "rhrand.h" #endif RHrand rhr; int main ( int argc, char* argv[] ) { CNearTree vTree; v vBest = DBL_MAX; long i,j,k; const long lMaxRow = 10; std::vector vReturn; if (argc <= 1) { rhr.srandom( (unsigned int)time( NULL ) ); /* use the current time to seed the random number generator */ } else { rhr.srandom((unsigned int)atoi(argv[1])); } vTree.SetFlags(CNearTree ::NTF_ForceFlip,CNearTree ::NTF_ForceFlip|CNearTree ::NTF_NoFlip); //--------------------------------------- // build up a library of points to search among //--------------------------------------- for ( k=-1; k<=lMaxRow; k++ ) { for ( j=-1; j<=lMaxRow; j++) { for ( i= lMaxRow ; i>=-1; i-- ) { vTree.insert( v((double)i, (double)j, (double)k) ); } // for i } // for j } // for k std::cout << std::endl; //--------------------------------------- // Done building the tree; now try a retrieval //--------------------------------------- double dRad = 0.6; long lReturn; for ( i=0; i<10; i++ ) { dRad += 0.05; double x = rhr.urand() * double( lMaxRow ) ; double y = x; double z = ( 1.25 * double(lMaxRow) - 1.5 * x ); v vSearch( x, 0.5*(x+y), z ); std::cout << "Trial " << i << " from probe point " << vSearch << std::endl; // find the nearest point to vSearch if ( vTree.NearestNeighbor( dRad, vBest, vSearch ) ) { std::cout << " Closest distance " << (double) ( vSearch - vBest ) << " to " << vBest << std::endl; } else { std::cout << " ***** nothing within " << dRad << " of " << vSearch << std::endl; } // find the farthest point from vSearch if ( vTree.FarthestNeighbor ( vBest, vSearch ) ) { std::cout << " Farthest distance " << (double) ( vSearch - vBest ) << " to " << vBest << std::endl; } else { std::cout << " No Farthest object found" << std::endl; } // search for all points within a "sphere" out to radius dRad if ( ( lReturn = vTree.FindInSphere( dRad, vReturn, vSearch )) > 0 ) { std::cout << " Returned " << lReturn << " items within " << dRad << " of "<< vSearch << std::endl; std::sort(vReturn.begin( ),vReturn.end( )); std::vector ::iterator iv; for ( iv=vReturn.begin( ); iv #else #include "CNearTree.h" #endif #include #ifdef CNEARTREE_SAFE_TRIANG #define TRIANG(a,b,c) ( (((b)+(c))-(a) >= 0) \ || ((b)-((a)-(c)) >= 0) \ || ((c)-((a)-(b)) >= 0)) #else #define TRIANG(a,b,c) ( (((b)+(c))-(a) >= 0)) #endif #define max2(x,y) ((x)>=(y)?(x):(y)) /* ======================================================================= double CNearTreeDistsq(void CNEARTREE_FAR * coord1, void CNEARTREE_FAR * coord2, size_t treedim, long treetype) function to return the square of the Euclidean distance between two coordinate vectors. treedim -- the dimension of the vectors treetype -- a long integer flag for type of the vectors CNEARTREE_TYPE_DOUBLE for double CNEARTREE_TYPE_INTEGER for integer CNEARTREE_TYPE_STRING for strings ======================================================================= */ double CNearTreeDistsq(void CNEARTREE_FAR * coord1, void CNEARTREE_FAR * coord2, size_t treedim, long treetype) { size_t index; double distsq; if (treetype == CNEARTREE_TYPE_DOUBLE) { double CNEARTREE_FAR * dcoord1; double CNEARTREE_FAR * dcoord2; dcoord1 = (double CNEARTREE_FAR *)coord1; dcoord2 = (double CNEARTREE_FAR *)coord2; distsq = (dcoord1[0]-dcoord2[0])*(dcoord1[0]-dcoord2[0]); for (index=1; index < treedim; index++) { distsq += (dcoord1[index]-dcoord2[index]) *(dcoord1[index]-dcoord2[index]); } return distsq; } else if (treetype == CNEARTREE_TYPE_INTEGER) { int CNEARTREE_FAR * icoord1; int CNEARTREE_FAR * icoord2; icoord1 = (int CNEARTREE_FAR *)coord1; icoord2 = (int CNEARTREE_FAR *)coord2; distsq = ((double)(icoord1[0]-icoord2[0]))*((double)(icoord1[0]-icoord2[0])); for (index=1; index < treedim; index++) { distsq += ((double)(icoord1[index]-icoord2[index])) *((double)(icoord1[index]-icoord2[index])); } return distsq; } else if (treetype == CNEARTREE_TYPE_STRING) { char CNEARTREE_FAR * string1; char CNEARTREE_FAR * string2; char CNEARTREE_FAR * stringx; char c1, c2; string1 = (char CNEARTREE_FAR *)coord1; string2 = (char CNEARTREE_FAR *)coord2; distsq = 0; c1=c2=0; stringx = NULL; for (index=0; index < treedim; index++) { c1 = string1[index]; c2 = string2[index]; if (c1 == 0) { if (c2 == 0) break; stringx = (char CNEARTREE_FAR *)coord2; break; } else if (c2 == 0) { stringx = (char CNEARTREE_FAR *)coord1; break; } if (c1 != c2) distsq++; } if (index < treedim && stringx) { for (; index < treedim; index++) { if (stringx[index] == 0) break; distsq++; } } return distsq*distsq; } else return -1.0; } /* ======================================================================= int CNearTreeSetNorm(const CNearTreeHandle treehandle, int treenorm); function to set the norm to use for this tree treenorm should be one of CNEARTREE_NORM_L1 for an L-1 norm CNEARTREE_NORM_L2 for an L-2 norm CNEARTREE_NORM_LINF for an L-infinity norm CNEARTREE_NORM_L2LAZY for an L-2 norm close in, but an L-1 norm for pruning. CNEARTREE_NORM_SPHERE for a sphere-based norm CNEARTREE_NORM_HSPHERE for a hemisphere-based norm CNEARTREE_NORM_HAMMING for a Hamming distance norm the function returns CNEARTREE_BAD_ARGUMENT for an invalid argument CNEARTREE_SUCCESS (0) otherwise ======================================================================= */ int CNearTreeSetNorm(const CNearTreeHandle treehandle, int treenorm) { if (!treehandle || (treenorm != CNEARTREE_NORM_L1 && treenorm != CNEARTREE_NORM_L2 && treenorm != CNEARTREE_NORM_LINF && treenorm != CNEARTREE_NORM_L2LAZY && treenorm != CNEARTREE_NORM_SPHERE && treenorm != CNEARTREE_NORM_HSPHERE && treenorm != CNEARTREE_NORM_HAMMING) || (treehandle->m_iflags & CNEARTREE_NORM)!=CNEARTREE_NORM_UNKNOWN ) return CNEARTREE_BAD_ARGUMENT; treehandle->m_iflags &= ~CNEARTREE_NORM_UNKNOWN; treehandle->m_iflags |= treenorm; return CNEARTREE_SUCCESS; } /* ======================================================================= double CNearTreeDist(const CNearTreeHandle treehandle, void CNEARTREE_FAR * coord1, void CNEARTREE_FAR * coord2)) function to return the distance (L1, L2 or L-infinity) between two coordinate vectors according to the parameters of the given tree For L2LAZY tree this returns the L2 norm distance. ======================================================================= */ double CNearTreeDist(const CNearTreeHandle treehandle, void CNEARTREE_FAR * coord1, void CNEARTREE_FAR * coord2) { size_t index; double dist, distsq; size_t treedim; long treetype; long treenorm; double CNEARTREE_FAR * dcoord1 = NULL; double CNEARTREE_FAR * dcoord2 = NULL; int CNEARTREE_FAR * icoord1 = NULL; int CNEARTREE_FAR * icoord2 = NULL; char CNEARTREE_FAR * svalue1 = NULL; char CNEARTREE_FAR * svalue2 = NULL; treedim = treehandle->m_szdimension; treetype = treehandle->m_iflags&CNEARTREE_TYPE; treenorm = treehandle->m_iflags&CNEARTREE_NORM; if (!treehandle || !coord1 || !coord2) return -1.; if (treenorm == CNEARTREE_NORM_UNKNOWN || treenorm == 0) { treehandle->m_iflags &= ~CNEARTREE_NORM; if (treetype == CNEARTREE_TYPE_STRING) { treehandle->m_iflags |= CNEARTREE_NORM_HAMMING; treenorm = CNEARTREE_NORM_HAMMING; } else { treehandle->m_iflags |= CNEARTREE_NORM_L2; treenorm = CNEARTREE_NORM_L2; } } if (treetype == CNEARTREE_TYPE_DOUBLE) { dcoord1 = (double CNEARTREE_FAR *)coord1; dcoord2 = (double CNEARTREE_FAR *)coord2; } else if (treetype == CNEARTREE_TYPE_INTEGER) { icoord1 = (int CNEARTREE_FAR *)coord1; icoord2 = (int CNEARTREE_FAR *)coord2; } else if (treetype == CNEARTREE_TYPE_STRING) { svalue1 = (char CNEARTREE_FAR *)coord1; svalue2 = (char CNEARTREE_FAR *)coord2; } else return -1.0; if (treedim == 1) { if (treetype == CNEARTREE_TYPE_DOUBLE) { return fabs(dcoord1[0]-dcoord2[0]); } else if (treetype == CNEARTREE_TYPE_INTEGER) { return fabs((double)(icoord1[0]-icoord2[0])); } else if (treetype == CNEARTREE_TYPE_STRING) { return (svalue1[0]==svalue2[0])?0.:1.; } else { return -1.0; } } switch (treenorm) { case CNEARTREE_NORM_HAMMING: if (treetype == CNEARTREE_TYPE_STRING) { char c1, c2; char CNEARTREE_FAR * stringx; dist = 0.; stringx = NULL; for (index=0; index < treedim; index++){ c1 = svalue1[index]; c2 = svalue2[index]; if (c1 == 0) { if (c2 == 0) break; stringx = (char CNEARTREE_FAR *)coord2; break; } else if (c2 == 0) { stringx = (char CNEARTREE_FAR *)coord1; break; } if (c1 != c2) dist++; } if (index < treedim && stringx) { for (; index < treedim; index++) { if (stringx[index] == 0) break; dist++; } } } else return -1.0; return dist; case CNEARTREE_NORM_L1: if (treetype == CNEARTREE_TYPE_DOUBLE) { dist= fabs(dcoord1[0]-dcoord2[0]); for (index=1; index < treedim; index++) { dist += fabs(dcoord1[index]-dcoord2[index]); } } else if (treetype == CNEARTREE_TYPE_INTEGER) { dist = fabs((double)(icoord1[0]-icoord2[0])); for (index=1; index < treedim; index++) { dist += fabs((double)(dcoord1[index]-dcoord2[index])); } } else return -1.0; return dist; case CNEARTREE_NORM_LINF: if (treetype == CNEARTREE_TYPE_DOUBLE) { dist= fabs(dcoord1[0]-dcoord2[0]); for (index=1; index < treedim; index++) { dist = max2(dist,fabs(dcoord1[index]-dcoord2[index])); } } else if (treetype == CNEARTREE_TYPE_INTEGER) { dist = fabs((double)(icoord1[0]-icoord2[0])); for (index=1; index < treedim; index++) { dist = max2(dist,fabs((double)(dcoord1[index]-dcoord2[index]))); } } else return -1.0; return dist; case CNEARTREE_NORM_SPHERE: case CNEARTREE_NORM_HSPHERE: if (treetype == CNEARTREE_TYPE_DOUBLE) { double dot, cosangle, angle, norm1, norm2, norm; dot = norm1 = norm2 = 0.; for (index=0; index < treedim; index++) { dot += dcoord1[index]*dcoord2[index]; norm1 += dcoord1[index]*dcoord1[index]; norm2 += dcoord2[index]*dcoord2[index]; } norm1 = sqrt(norm1); norm2 = sqrt(norm2); if (norm1 <= DBL_MIN) { dist = norm2; } else if (norm2 <= DBL_MIN) { dist = norm1; } else { cosangle = dot/(norm1*norm2); if (cosangle > 1.) cosangle = 1.; if (cosangle < -1.) cosangle = -1.; if (treenorm == CNEARTREE_NORM_HSPHERE && cosangle < 0.) cosangle = -cosangle; angle = atan2(sqrt(1.-cosangle*cosangle),cosangle); norm = (norm1 1.) cosangle = 1.; if (cosangle < -1.) cosangle = -1.; angle = atan2(sqrt(1.-cosangle*cosangle),cosangle); norm = (norm1m_iflags) & CNEARTREE_NORM; if (!treenorm) treenorm = CNEARTREE_NORM_UNKNOWN; treetype = (treehandle->m_iflags) & CNEARTREE_TYPE; if ( (treetype != CNEARTREE_TYPE_DOUBLE) && (treetype != CNEARTREE_TYPE_INTEGER) && (treetype != CNEARTREE_TYPE_STRING) ) return CNEARTREE_BAD_ARGUMENT; treexflags = (treehandle->m_iflags) & CNEARTREE_XFLAGS; *treenodehandle = (CNearTreeNodeHandle)CNEARTREE_MALLOC(sizeof(CNearTreeNode)); if (!(*treenodehandle)) { return CNEARTREE_MALLOC_FAILED; } (*treenodehandle)->m_indexLeft = 0; (*treenodehandle)->m_indexRight = 0; (*treenodehandle)->m_dMaxLeft = -1.; /* negative for an empty branch */ (*treenodehandle)->m_dMaxRight = -1.; /* negative for an empty branch */ (*treenodehandle)->m_iflags = treetype; /* no data, no children */ (*treenodehandle)->m_iflags |= treenorm; (*treenodehandle)->m_iflags |= treexflags; (*treenodehandle)->m_pLeftBranch = NULL; (*treenodehandle)->m_pRightBranch = NULL; (*treenodehandle)->m_iTreeSize = 0; #ifdef CNEARTREE_INSTRUMENTED (*treenodehandle)->m_Height = 0; #endif return CNEARTREE_SUCCESS; } /* ======================================================================= int CNearTreeCreate ( CNearTreeHandle CNEARTREE_FAR * treehandle, size_t treedim, long treetype) Create a CNearTree returns a pointer to the newly allocated block of memory as a CNearTreeHandle in *treehandle treedim -- the dimension of the vectors treetype -- double or integer flag for type of the vectors ored with norm and ored with execution flags CNEARTREE_TYPE_DOUBLE for double CNEARTREE_TYPE_INTEGER for integer CNEARTREE_TYPE_STRING for strings ored with CNEARTREE_NORM_L1 for the sum of the absolute values CNEARTREE_NORM_L2 for the square root of the sum of the squares CNEARTREE_NORM_L2LAZY for the square root of the sum of the squares but with the tree as L1 CNEARTREE_NORM_LINF for the max CNEARTREE_NORM_SPHERE for norm as spherical angular distance CNEARTREE_NORM_HSPHERE for norm as hemispherical angular distance CNEARTREE_NORM_HAMMING for norm as string hamming distance ored with CNTF_NOPREPRUNE 0x10000L flag to suppress all search prepruning CNTF_FORCEPREPRUNE 0x20000L flag to force search prepruning CNTF_NOFLIP 0x40000L flag to suppress flips on insert CNTF_FORCEFLIP 0x80000L flag to force flips on insert CNTF_NODEFER 0x100000L flag to prevent deferred insert creates an empty tree with no right or left node and with the dMax-below set to negative values so that any match found will be stored since it will greater than the negative value ======================================================================= */ int CNearTreeCreate ( CNearTreeHandle CNEARTREE_FAR * treehandle, size_t treedim, long treetype) { long treenorm; long treeflip; long treedefer; long treepreprune; if (!treehandle) return CNEARTREE_BAD_ARGUMENT; treenorm = treetype & CNEARTREE_NORM; treeflip = treetype & CNEARTREE_FLIP; treedefer = treetype & CNTF_NODEFER; treepreprune = treetype & (CNTF_NOPREPRUNE|CNTF_FORCEPREPRUNE); treeflip = treetype & (CNTF_NOFLIP|CNTF_FORCEFLIP); if (!treenorm) treenorm = CNEARTREE_NORM_UNKNOWN; treetype &= CNEARTREE_TYPE; if (treedim == 0 || (treetype != CNEARTREE_TYPE_DOUBLE && treetype != CNEARTREE_TYPE_INTEGER && treetype != CNEARTREE_TYPE_STRING)) return CNEARTREE_BAD_ARGUMENT; *treehandle = (CNearTreeHandle)CNEARTREE_MALLOC(sizeof(CNearTree)); if (!(*treehandle)) { return CNEARTREE_MALLOC_FAILED; } (*treehandle)->m_iflags = treetype; /* no data, no children */ (*treehandle)->m_iflags |= treenorm; /* record the chosen norm */ (*treehandle)->m_iflags |= treeflip; /* record whether to flip */ (*treehandle)->m_iflags |= treedefer; /* record whether to defer */ (*treehandle)->m_iflags |= treeflip; /* record whether to flip */ (*treehandle)->m_iflags |= treepreprune; /* record whether to preprune */ (*treehandle)->m_szdimension = treedim; /* number of ints or doubles */ (*treehandle)->m_szsize = 0; /* number of nodes in the tree */ (*treehandle)->m_szdepth = 0; /* depth of the tree */ if( CNearTreeNodeCreate(*treehandle,&((*treehandle)->m_ptTree))) { CNEARTREE_FREE(*treehandle); return CNEARTREE_MALLOC_FAILED; } (*treehandle)->m_DelayedIndices = NULL; (*treehandle)->m_ObjectStore = NULL; (*treehandle)->m_CoordStore = NULL; (*treehandle)->m_DiamEstimate = 0.; (*treehandle)->m_SumSpacings = 0.; (*treehandle)->m_SumSpacingsSq = 0.; (*treehandle)->m_DimEstimate = 0; (*treehandle)->m_DimEstimateEsd = 0; #ifdef CNEARTREE_INSTRUMENTED (*treehandle)->m_NodeVisits = 0; #endif CRHrandSrandom(&((*treehandle)->m_rhr),0); return CNEARTREE_SUCCESS; } /* ======================================================================= int CNearTreeNodeFree ( CNearTreeNodeHandle CNEARTREE_FAR * treenodehandle ) Free a CNearTreeNode recursively frees the NearTreeNode tree with the handle *trenodeehandle and nulls the treenodehandle. note that the objects referenced are not freed. ======================================================================= */ int CNearTreeNodeFree ( CNearTreeNodeHandle CNEARTREE_FAR * treenodehandle ) { int errorcode; if (!treenodehandle) return CNEARTREE_BAD_ARGUMENT; errorcode = CNEARTREE_SUCCESS; if ((*treenodehandle)->m_pLeftBranch) { errorcode |= CNearTreeNodeFree(&((*treenodehandle)->m_pLeftBranch)); } if ((*treenodehandle)->m_pRightBranch) { errorcode |= CNearTreeNodeFree(&((*treenodehandle)->m_pRightBranch)); } CNEARTREE_FREE(*treenodehandle); *treenodehandle = NULL; return errorcode; } /* ======================================================================= int CNearTreeFree ( CNearTreeHandle CNEARTREE_FAR * treehandle ) Free a CNearTree Frees the NearTree with the handle *treehandle and nulls the treehandle. note that the objects referenced are not freed. ======================================================================= */ int CNearTreeFree ( CNearTreeHandle CNEARTREE_FAR * treehandle ) { int errorcode, errorcodev; if (!treehandle) return CNEARTREE_BAD_ARGUMENT; errorcode = CNEARTREE_SUCCESS; if ((*treehandle)->m_ptTree) { errorcode |= CNearTreeNodeFree(&((*treehandle)->m_ptTree)); } if ((*treehandle)->m_DelayedIndices) { errorcodev = CVectorFree(&((*treehandle)->m_DelayedIndices)); if (errorcodev) errorcode |= CNEARTREE_FREE_FAILED ; } if ((*treehandle)->m_ObjectStore) { errorcodev = CVectorFree(&((*treehandle)->m_ObjectStore)); if (errorcodev) errorcode |= CNEARTREE_FREE_FAILED ; } if ((*treehandle)->m_CoordStore) { errorcodev = CVectorFree(&((*treehandle)->m_CoordStore)); if (errorcodev) errorcode |= CNEARTREE_FREE_FAILED ; } CNEARTREE_FREE(*treehandle); *treehandle = NULL; return errorcode; } /* ======================================================================= int CNearTreeClear ( const CNearTreeHandle treehandle ) Clear a CNearTree Clears the NearTree with the handle *treehandle note that the objects referenced are not freed. ======================================================================= */ int CNearTreeClear ( const CNearTreeHandle treehandle ) { int errorcode, errorcodev; if (!treehandle) return CNEARTREE_BAD_ARGUMENT; errorcode = CNEARTREE_SUCCESS; errorcodev = 0; if (treehandle->m_ptTree) { errorcode |= CNearTreeNodeFree(&(treehandle->m_ptTree)); treehandle->m_ptTree = NULL; } errorcode |= CNearTreeNodeCreate(treehandle,&((treehandle)->m_ptTree)); if (treehandle->m_DelayedIndices) { errorcodev = CVectorFree(&(treehandle->m_DelayedIndices)); if (errorcodev) errorcode |= CNEARTREE_FREE_FAILED ; if (!errorcodev) treehandle->m_DelayedIndices = NULL; } if (treehandle->m_ObjectStore) { errorcodev = CVectorFree(&(treehandle->m_ObjectStore)); if (errorcodev) errorcode |= CNEARTREE_FREE_FAILED ; if (!errorcodev) treehandle->m_ObjectStore = NULL; } if (treehandle->m_CoordStore) { errorcodev = CVectorFree(&(treehandle->m_CoordStore)); if (errorcodev) errorcode |= CNEARTREE_FREE_FAILED ; if (!errorcodev) treehandle->m_CoordStore = NULL; } if (!errorcode) { (treehandle)->m_szsize = 0; /* number of nodes in the tree */ (treehandle)->m_szdepth = 0; /* depth of in the tree */ (treehandle)->m_DiamEstimate = 0.; (treehandle)->m_SumSpacings = 0.; (treehandle)->m_SumSpacingsSq = 0.; (treehandle)->m_DimEstimate = 0; (treehandle)->m_DimEstimateEsd= 0; #ifdef CNEARTREE_INSTRUMENTED (treehandle)->m_NodeVisits = 0; #endif } return errorcode; } /* ======================================================================= int CNearTreeZeroIfEmpty (const CNearTreeHandle treehandle) Test for an empty CNearTree, returning 0 in that case ======================================================================= */ int CNearTreeZeroIfEmpty ( const CNearTreeHandle treehandle ) { return (treehandle == NULL || treehandle->m_CoordStore == NULL || CVectorSize(treehandle->m_CoordStore) == 0)?0:1; } /* ======================================================================= int CNearTreeGetSize (const CNearTreeHandle treehandle, size_t CNEARTREE_FAR * size) Return the number of objects in the tree or delay queue in size ======================================================================= */ int CNearTreeGetSize ( const CNearTreeHandle treehandle, size_t CNEARTREE_FAR * size ) { if (!treehandle || !size ) return CNEARTREE_BAD_ARGUMENT; *size = treehandle->m_szsize; if (treehandle->m_DelayedIndices) *size += CVectorSize(treehandle->m_DelayedIndices); return CNEARTREE_SUCCESS; } /* ======================================================================= int CNearTreeGetDelayedSize (const CNearTreeHandle treehandle, size_t CNEARTREE_FAR * size) Return the number of objects in the delay queue tree in size This is a deprecated alternate name for CNearTreeGetDeferredSize ======================================================================= */ int CNearTreeGetDelayedSize ( const CNearTreeHandle treehandle, size_t CNEARTREE_FAR * size ) { if (!treehandle || !size ) return CNEARTREE_BAD_ARGUMENT; *size = 0; if (treehandle->m_DelayedIndices) *size = CVectorSize(treehandle->m_DelayedIndices); return CNEARTREE_SUCCESS; } /* ======================================================================= int CNearTreeGetDeferredSize (const CNearTreeHandle treehandle, size_t CNEARTREE_FAR * size) Return the number of objects in the delay queue tree in size ======================================================================= */ int CNearTreeGetDeferredSize ( const CNearTreeHandle treehandle, size_t CNEARTREE_FAR * size ) { if (!treehandle || !size ) return CNEARTREE_BAD_ARGUMENT; *size = 0; if (treehandle->m_DelayedIndices) *size = CVectorSize(treehandle->m_DelayedIndices); return CNEARTREE_SUCCESS; } /* ======================================================================= int CNearTreeGetDepth (const CNearTreeHandle treehandle, size_t CNEARTREE_FAR * depth) Return the depth of the tree in depth ======================================================================= */ int CNearTreeGetDepth ( const CNearTreeHandle treehandle, size_t CNEARTREE_FAR * depth ) { if (!treehandle || !depth ) return CNEARTREE_BAD_ARGUMENT; *depth = treehandle->m_szdepth; return CNEARTREE_SUCCESS; } /* ======================================================================= int CNearTreeGetHeight (const CNearTreeHandle treehandle, size_t CNEARTREE_FAR * height) Return the height of the tree in height, of instrumented, otherwise the depth ======================================================================= */ int CNearTreeGetHeight ( const CNearTreeHandle treehandle, size_t CNEARTREE_FAR * height ) { if (!treehandle || !height ) return CNEARTREE_BAD_ARGUMENT; #ifdef CNEARTREE_INSTRUMENTED *height = 0; if (treehandle->m_ptTree) *height = treehandle->m_ptTree->m_Height; *height = treehandle->m_szdepth; return CNEARTREE_SUCCESS; #else return CNearTreeGetDepth (treehandle, height); #endif } /* ======================================================================= int CNearTreeGetFlags(const CNearTreeHandle treehandle, long CNEARTREE_FAR *flags, const long mask) int CNearTreeSetFlags(const CNearTreeHandle treehandle, const long flags, const long mask) functions to get or set the execution control flags: CNTF_NOPREPRUNE to suppress all search prepruning CNTF_FORCEPREPRUNE to force search prepruning CNTF_NOFLIP flag to suppress flips on insert CNTF_FORCEFLIP flag to force flips on insert CNTF_NODEFER flag to prevent deferred insert The desired flags may be ored. If mask is non-zero it is used as a bit mask, so a call with a flags of zero and a mask equal to a particular flag, clears that flag. ======================================================================= */ int CNearTreeGetFlags(const CNearTreeHandle treehandle, long CNEARTREE_FAR *flags, const long mask) { if (!flags) { if (mask) { *flags = (treehandle->m_iflags)&mask; } else { *flags = treehandle->m_iflags; } return CNEARTREE_SUCCESS; } else { return CNEARTREE_BAD_ARGUMENT; } } int CNearTreeSetFlags(const CNearTreeHandle treehandle, const long flags, const long mask){ if (mask) { treehandle->m_iflags = (flags&mask) | ((treehandle->m_iflags)&~mask); } else { treehandle->m_iflags = flags; } return CNEARTREE_SUCCESS; } /* ======================================================================= int CNearTreeGetMeanSpacing ( const CNearTreeHandle treehandle, double CNEARTREE_FAR * spacing ) Get an estimate of the spacing of points ======================================================================= */ int CNearTreeGetMeanSpacing ( const CNearTreeHandle treehandle, double CNEARTREE_FAR * spacing ) { if ( !treehandle || !spacing ) return CNEARTREE_BAD_ARGUMENT; *spacing = treehandle->m_SumSpacings/(double)((1+CVectorSize(treehandle->m_DelayedIndices))); return CNEARTREE_SUCCESS; } /* ======================================================================= int CNearTreeGetVarSpacing ( const CNearTreeHandle treehandle, double CNEARTREE_FAR * varspacing ) Get an estimate of variance of the spacing of points ======================================================================= */ int CNearTreeGetVarSpacing ( const CNearTreeHandle treehandle, double CNEARTREE_FAR * varspacing ) { double meanSpacing; if ( !treehandle || !varspacing ) return CNEARTREE_BAD_ARGUMENT; meanSpacing = treehandle->m_SumSpacings/(double)((1+CVectorSize(treehandle->m_DelayedIndices))); *varspacing = treehandle->m_SumSpacingsSq/ (double)((1+CVectorSize(treehandle->m_DelayedIndices)))-meanSpacing*meanSpacing; return CNEARTREE_SUCCESS; } /* ======================================================================= int CNearTreeCount(const CNearTreeHandle treehandle, size_t CNEARTREE_FAR * count) ======================================================================= */ int CNearTreeCount(const CNearTreeHandle treehandle, size_t CNEARTREE_FAR * count){ *count = 0; return (CNearTreeNodeCount(treehandle->m_ptTree,count)); } #ifndef CNEARTREE_INSTRUMENTED /* ======================================================================= int CNearTreeGetNodeVisits ( const CNearTreeHandle treehandle, size_t CNEARTREE_FAR * visits) Get the number of visits to nodes Dummy version to return 0 ======================================================================= */ int CNearTreeGetNodeVisits ( const CNearTreeHandle treehandle, size_t CNEARTREE_FAR * visits) { if ( !treehandle || !visits ) return CNEARTREE_BAD_ARGUMENT; *visits = 0; return CNEARTREE_SUCCESS; } #endif #ifdef CNEARTREE_INSTRUMENTED /* ======================================================================= int CNearTreeGetNodeVisits ( const CNearTreeHandle treehandle, size_t CNEARTREE_FAR * visits) Get the number of visits to nodes ======================================================================= */ int CNearTreeGetNodeVisits ( const CNearTreeHandle treehandle, size_t CNEARTREE_FAR * visits) { if ( !treehandle || !visits ) return CNEARTREE_BAD_ARGUMENT; *visits = treehandle->m_NodeVisits; return CNEARTREE_SUCCESS; } /* ======================================================================= int CNearTreeSetNodeVisits ( const CNearTreeHandle treehandle, const size_t visits ) Set the number of visits to nodes ======================================================================= */ int CNearTreeSetNodeVisits ( const CNearTreeHandle treehandle, const size_t visits ) { if ( !treehandle ) return CNEARTREE_BAD_ARGUMENT; treehandle->m_NodeVisits = visits; return CNEARTREE_SUCCESS; } #endif /* ======================================================================= int CNearTreeGetDiamEstimate ( const CNearTreeHandle treehandle, double CNEARTREE_FAR * diamest ) Get an estimate of the diameter ======================================================================= */ int CNearTreeGetDiamEstimate ( const CNearTreeHandle treehandle, double CNEARTREE_FAR * diamest ) { if ( !treehandle || !diamest ) return CNEARTREE_BAD_ARGUMENT; if ( treehandle->m_DelayedIndices ) { if (CNearTreeCompleteDelayedInsert(treehandle)!=CNEARTREE_SUCCESS) return CNEARTREE_BAD_ARGUMENT; } if (treehandle->m_DiamEstimate<=0.) { CNearTreeNodeHandle pt = treehandle->m_ptTree; treehandle->m_DiamEstimate = 0.; if (pt) { if ((pt->m_iflags&CNEARTREE_FLAG_LEFT_DATA) &&(pt->m_iflags&CNEARTREE_FLAG_RIGHT_DATA)){ CNTM_DistL2(treehandle->m_DiamEstimate,treehandle, CVectorElementAt(treehandle->m_CoordStore,pt->m_indexLeft), CVectorElementAt(treehandle->m_CoordStore,pt->m_indexRight)); } if ((pt->m_iflags&CNEARTREE_FLAG_LEFT_CHILD) && pt->m_dMaxLeft > treehandle->m_DiamEstimate) treehandle->m_DiamEstimate = pt->m_dMaxLeft; if ((pt->m_iflags&CNEARTREE_FLAG_RIGHT_CHILD) && pt->m_dMaxRight > treehandle->m_DiamEstimate) treehandle->m_DiamEstimate = pt->m_dMaxRight; } } *diamest = treehandle->m_DiamEstimate; return CNEARTREE_SUCCESS; } /* ======================================================================= int CNearTreeGetDimEstimateEsd ( const CNearTreeHandle treehandle, double CNEARTREE_FAR * dimestesd ) Get the current best estimate of the dimension esd ======================================================================= */ int CNearTreeGetDimEstimateEsd ( const CNearTreeHandle treehandle, double CNEARTREE_FAR * dimestesd ) { double dimest; int errorcode; if ( !treehandle || !dimestesd ) return CNEARTREE_BAD_ARGUMENT; if ( treehandle->m_DelayedIndices ) { if (CNearTreeCompleteDelayedInsert(treehandle)!=CNEARTREE_SUCCESS) return CNEARTREE_BAD_ARGUMENT; } if ( treehandle->m_DimEstimate == 0.) { if (!(errorcode=CNearTreeGetDimEstimate(treehandle,&dimest,0.1))) { *dimestesd = DBL_MAX; return errorcode; } } *dimestesd = treehandle->m_DimEstimateEsd; return CNEARTREE_SUCCESS; } /* ======================================================================= int CNearTreeGetDimEstimate ( const CNearTreeHandle treehandle, double CNEARTREE_FAR * diamest, const double DimEstimateEsd ) Get an estimate of the dimension of the collection of points in the tree, to within the specified esd ======================================================================= */ int CNearTreeGetDimEstimate ( const CNearTreeHandle treehandle, double CNEARTREE_FAR * dimest, const double DimEstimateEsd ) { size_t estsize; double estd; double estdim = 0.; double estdimsq = 0.; size_t trials; size_t n, ii; size_t probe_index; double testlim; double meanSpacing; double pointdensity; double targetradius; double rat; double shrinkfactor; double dummy; int bResult; size_t elsize; long goodtrials; size_t poplarge, popsmall, poptrial; CVectorHandle sampledisklarge; if ( !treehandle || !dimest ) return CNEARTREE_BAD_ARGUMENT; if ( treehandle->m_DelayedIndices ) { if (CNearTreeCompleteDelayedInsert(treehandle)!=CNEARTREE_SUCCESS) return CNEARTREE_BAD_ARGUMENT; } elsize = sizeof(double); if ((treehandle->m_iflags)&CNEARTREE_TYPE_DOUBLE) { elsize = sizeof(double); } else if ((treehandle->m_iflags)&CNEARTREE_TYPE_INTEGER) { elsize = sizeof(int); } else elsize = sizeof(char); if ( treehandle->m_DimEstimate == DBL_MAX ) { *dimest = 0.; return CNEARTREE_NOT_FOUND; } if ( treehandle->m_DimEstimate > 0. && (treehandle->m_DimEstimateEsd <= DimEstimateEsd || DimEstimateEsd <= 0.) ) { *dimest = treehandle->m_DimEstimate; return CNEARTREE_SUCCESS; } estsize = CVectorSize(treehandle->m_CoordStore); testlim = (DimEstimateEsd<=0.)?0.01:(DimEstimateEsd*DimEstimateEsd); meanSpacing = treehandle->m_SumSpacings/(double)((1+treehandle->m_szsize)); probe_index = 0; /* Do not try to get a dimension extimate with fewer than 32 points or a diameter less than DBL_EPSILON*/ if (estsize < 32 || (double)treehandle->m_DiamEstimate < DBL_EPSILON) { treehandle->m_DimEstimate = treehandle->m_DimEstimateEsd = DBL_MAX; *dimest = 0.; return CNEARTREE_NOT_FOUND; } /* Estimate the number of points per unit distance and a target radius that would produce 4096 points in dimension 1. If this would bring us beyond the diameter/1.1, reduce to that size. */ pointdensity = ((double)estsize)/((double)treehandle->m_DiamEstimate); targetradius = 4096./pointdensity; if (targetradius < meanSpacing*10.) targetradius = meanSpacing*10.; if (targetradius > (double)treehandle->m_DiamEstimate/1.1) targetradius = (double)treehandle->m_DiamEstimate/1.1; /* Now try to find a smaller adjusted target radius that will contain a reasonable number of points*/ shrinkfactor = 4.; n = (size_t)(((double)estsize-1u) * (CRHrandUrand(&(treehandle->m_rhr)))); dummy = CRHrandUrand(&(treehandle->m_rhr)); dummy=CRHrandUrand(&(treehandle->m_rhr)); if (CVectorCreate(&(sampledisklarge), (treehandle->m_szdimension)*elsize,10)) { return CNEARTREE_MALLOC_FAILED; } bResult=!CNearTreeFindInSphere( treehandle, (double)targetradius/shrinkfactor, sampledisklarge, NULL, CVectorElementAt(treehandle->m_CoordStore,n), 1); poptrial = CVectorSize(sampledisklarge); do { shrinkfactor = shrinkfactor/1.1; popsmall=poptrial; bResult=!CNearTreeFindInSphere( treehandle, (double)targetradius/shrinkfactor, sampledisklarge, NULL, CVectorElementAt(treehandle->m_CoordStore,n), 1); poptrial = CVectorSize(sampledisklarge); n = (size_t)(((double)estsize-1u) * (CRHrandUrand(&(treehandle->m_rhr)))); dummy = CRHrandUrand(&(treehandle->m_rhr)); dummy=CRHrandUrand(&(treehandle->m_rhr)); } while (poptrial < 256 && shrinkfactor > 1. && poptrial <= popsmall+10); targetradius /= shrinkfactor; targetradius *= 1.1; goodtrials = 0; trials = (size_t)sqrt(0.5+(double)estsize); if (trials < 10) trials = 10; for(ii = 0; ii < trials; ii++) { n = (size_t)(((double)estsize-1u) * (CRHrandUrand(&(treehandle->m_rhr)))); dummy=CRHrandUrand(&(treehandle->m_rhr)); dummy=CRHrandUrand(&(treehandle->m_rhr)); bResult=!CNearTreeFindInSphere( treehandle, (double)targetradius, sampledisklarge, NULL, CVectorElementAt(treehandle->m_CoordStore,n), 1); poplarge = CVectorSize(sampledisklarge); if (poplarge > 0) { bResult=!CNearTreeFindInSphere( treehandle, (double)targetradius/1.1, sampledisklarge, NULL, CVectorElementAt(treehandle->m_CoordStore,n), 1); popsmall = CVectorSize(sampledisklarge); if (popsmall > 0 && popsmall< poplarge) { rat = (double)poplarge/(double)popsmall; estd = log(rat)/log(1.1); estdim += estd; estdimsq += estd*estd; goodtrials++; if (goodtrials > (1L+(long)(trials))/2 && fabs(estdimsq/((double)goodtrials) - estdim*estdim/((double)(goodtrials*goodtrials))) <= testlim) break; } } } if (goodtrials < 1) { treehandle->m_DimEstimate = treehandle->m_DimEstimateEsd = DBL_MAX; *dimest = 0.; CVectorFree(&sampledisklarge); return CNEARTREE_NOT_FOUND; } treehandle->m_DimEstimate = estdim/((double)goodtrials); treehandle->m_DimEstimateEsd = sqrt(fabs(estdimsq/((double)goodtrials) - treehandle->m_DimEstimate*treehandle->m_DimEstimate)); if (treehandle->m_DimEstimate + 3.*treehandle->m_DimEstimateEsd< 0.) { treehandle->m_DimEstimate = treehandle->m_DimEstimateEsd = DBL_MAX; *dimest = 0.; CVectorFree(&sampledisklarge); return CNEARTREE_NOT_FOUND; } *dimest = treehandle->m_DimEstimate; return CNEARTREE_SUCCESS; } /* ======================================================================= int CNearTreeImmediateInsert ( const CNearTreeHandle treehandle, const void CNEARTREE_FAR * coord, const void * obj ) Function to insert some "point" as an object into a CNearTree for later searching coord is a coordinate vector for an object, obj, to be inserted into a Neartree. A static copy of the coordinates and a pointer to the object are inserted Three possibilities exist: put the datum into the left position (first test),into the right position, or else into a node descending from the nearer of those positions when they are both already used. return 0 for success, nonzero for an error ======================================================================= */ int CNearTreeImmediateInsert( const CNearTreeHandle treehandle, const void CNEARTREE_FAR * coord, const void CNEARTREE_FAR * obj ) { /* do a bit of precomputing if it is possible so that we can reduce the number of calls to sqrt */ size_t depth; size_t index; size_t elsize; int errorcode; if ( !treehandle || !coord ) return CNEARTREE_BAD_ARGUMENT; if ( !(treehandle->m_ptTree) ) return CNEARTREE_BAD_ARGUMENT; if ( treehandle->m_ObjectStore == NULL) { if (CVectorCreate(&(treehandle->m_ObjectStore),sizeof(void *),10)) { return CNEARTREE_MALLOC_FAILED; } } if ( treehandle->m_CoordStore == NULL) { elsize = sizeof(double); if ((treehandle->m_iflags)&CNEARTREE_TYPE_DOUBLE) { elsize = sizeof(double); } else if ((treehandle->m_iflags)&CNEARTREE_TYPE_INTEGER) { elsize = sizeof(int); } else elsize = sizeof(char); if (CVectorCreate(&(treehandle->m_CoordStore), (treehandle->m_szdimension)*elsize,10)) { return CNEARTREE_MALLOC_FAILED; } } index = CVectorSize(treehandle->m_ObjectStore); if (CVectorAddElement(treehandle->m_ObjectStore,(void CNEARTREE_FAR *)&obj)) return CNEARTREE_CVECTOR_FAILED; if (CVectorAddElement(treehandle->m_CoordStore,(void CNEARTREE_FAR *)coord)) return CNEARTREE_CVECTOR_FAILED; depth = 0; if ((treehandle->m_iflags& CNTF_FORCEFLIP)||!(treehandle->m_iflags& CNTF_NOFLIP)) { errorcode = CNearTreeNodeInsert_Flip( treehandle, treehandle->m_ptTree, index, &depth); } else { errorcode = CNearTreeNodeInsert( treehandle, treehandle->m_ptTree, index, &depth); } if (errorcode == 0) { if (depth > treehandle->m_szdepth) treehandle->m_szdepth = depth; (treehandle->m_szsize)++; } return errorcode; } /* int CNearTreeNodeCount(const CNearTreeNodeHandle treenodehandle, size_t CNEARTREE_FAR * count) */ int CNearTreeNodeCount(const CNearTreeNodeHandle treenodehandle, size_t CNEARTREE_FAR * count){ int errorcode=0; if ( (treenodehandle->m_iflags)&CNEARTREE_FLAG_RIGHT_DATA ) { (*count)++; } if ( (treenodehandle->m_iflags)&CNEARTREE_FLAG_LEFT_DATA ) { (*count)++; } if ( (treenodehandle->m_iflags)&CNEARTREE_FLAG_RIGHT_CHILD ) { errorcode |= CNearTreeNodeCount(treenodehandle->m_pRightBranch, count); } if ( (treenodehandle->m_iflags)&CNEARTREE_FLAG_LEFT_CHILD ) { errorcode |= CNearTreeNodeCount(treenodehandle->m_pLeftBranch,count); } return errorcode; } /* ======================================================================= int CNearTreeNodeReInsert_Flip ( const CNearTreeHandle treehandle, const CNearTreeNodeHandle treenodehandle, const CNearTreeNodeHandle pntn, size_t CNEARTREE_FAR * depth) Function to reinsert the elements from a detached a node into a CNearTree for later searching treehandle is the handle of the overall neartree being used treenodehandle is the handle of the node in the existing tree at which to start the insertion pntn is the handle of the previously detached node from which to extract the nodes for insertion depth is used to keep track of the depth at which the insertion is done return 0 for success, nonzero for an error ======================================================================= */ int CNearTreeNodeReInsert_Flip( const CNearTreeHandle treehandle, const CNearTreeNodeHandle treenodehandle, const CNearTreeNodeHandle pntn, size_t CNEARTREE_FAR * depth) { size_t tempdepth1, tempdepth2, tempdepth3, tempdepth4; double SumSpacings, SumSpacingsSq; int errorcode; errorcode = 0; tempdepth1 = tempdepth2 = tempdepth3 = tempdepth4 = *depth; SumSpacings = treehandle->m_SumSpacings; SumSpacingsSq = treehandle->m_SumSpacingsSq; if ( (pntn->m_iflags)&CNEARTREE_FLAG_RIGHT_DATA ) { errorcode |= CNearTreeNodeInsert_Flip(treehandle,treenodehandle, pntn->m_indexRight, &tempdepth1); } if ( (pntn->m_iflags)&CNEARTREE_FLAG_LEFT_DATA ) { errorcode |= CNearTreeNodeInsert_Flip(treehandle,treenodehandle, pntn->m_indexLeft, &tempdepth2); } if ( (pntn->m_iflags)&CNEARTREE_FLAG_RIGHT_CHILD ) { errorcode |= CNearTreeNodeReInsert_Flip(treehandle, treenodehandle, pntn->m_pRightBranch, &tempdepth3); } if ( (pntn->m_iflags)&CNEARTREE_FLAG_LEFT_CHILD ) { errorcode |= CNearTreeNodeReInsert_Flip(treehandle, treenodehandle, pntn->m_pLeftBranch, &tempdepth4); } *depth = tempdepth1>*depth?tempdepth1:*depth; *depth = tempdepth2>*depth?tempdepth2:*depth; *depth = tempdepth3>*depth?tempdepth3:*depth; *depth = tempdepth4>*depth?tempdepth4:*depth; treehandle->m_SumSpacings = SumSpacings; treehandle->m_SumSpacingsSq = SumSpacingsSq; return errorcode; } /* ======================================================================= int CNearTreeNodeInsert ( const CNearTreeHandle treehandle, const const CNearTreeNodeHandle treenodehandle, size_t index; size_t CNEARTREE_FAR * depth) Function to insert some "point" as an object into a node in a CNearTree for later searching treenodehandle is the handle of the node at which to start the insertion index is the index of the object and coordinates to add from treehandle->m_ObjectStore and treehandle->CoordStore into a NearTree. A static copy of the coordinates and a pointer to the object are inserted Three possibilities exist: put the datum into the left position (first test),into the right position, or else into a node descending from the nearer of those positions when they are both already used. depth is used to keep track of the depth at which the insertion is done return 0 for success, nonzero for an error ======================================================================= ======================================================================= int CNearTreeNodeInsert_Flip ( const CNearTreeHandle treehandle, const const CNearTreeNodeHandle treenodehandle, size_t index; size_t CNEARTREE_FAR * depth) Function to insert some "point" as an object into a node in a CNearTree for later searching treenodehandle is the handle of the node at which to start the insertion index is the index of the object and coordinates to add from treehandle->m_ObjectStore and treehandle->CoordStore into a NearTree. A static copy of the coordinates and a pointer to the object are inserted Three possibilities exist: put the datum into the left position (first test),into the right position, or else into a node descending from the nearer of those positions when they are both already used. depth is used to keep track of the depth at which the insertion is done return 0 for success, nonzero for an error ======================================================================= */ int CNearTreeNodeInsert( const CNearTreeHandle treehandle, const CNearTreeNodeHandle treenodehandle, const size_t index, size_t CNEARTREE_FAR * depth) { /* do a bit of precomputing if it is possible so that we can reduce the number of calls to sqrt */ double dTempRight = 0.; double dTempLeft = 0.; double dTempLeftRight = 0; int errorcode = 0; void CNEARTREE_FAR * coord; void CNEARTREE_FAR * coordLeft; void CNEARTREE_FAR * coordRight; const void CNEARTREE_FAR * obj; size_t n = index; (*depth)++; if ( !treehandle || !treenodehandle || index+1 > CVectorSize(treehandle->m_ObjectStore)) return CNEARTREE_BAD_ARGUMENT; obj = CVectorElementAt(treehandle->m_ObjectStore,index); coord = CVectorElementAt(treehandle->m_CoordStore,index); coordLeft = NULL; coordRight = NULL; (treenodehandle->m_iTreeSize)++; if ( !((treenodehandle->m_iflags)&CNEARTREE_FLAG_LEFT_DATA) ) { treenodehandle->m_indexLeft = n; treenodehandle->m_dMaxLeft = -1.; treenodehandle->m_iflags |= CNEARTREE_FLAG_LEFT_DATA; #ifdef CNEARTREE_INSTRUMENTED treenodehandle->m_Height = 1; #endif return CNEARTREE_SUCCESS; } coordLeft = CVectorElementAt(treehandle->m_CoordStore,treenodehandle->m_indexLeft); dTempLeft = CNearTreeDist(treehandle, coord, coordLeft); if ( !((treenodehandle->m_iflags)&CNEARTREE_FLAG_RIGHT_DATA) ){ treenodehandle->m_indexRight = n; treenodehandle->m_dMaxRight = -1.; treenodehandle->m_iflags |= CNEARTREE_FLAG_RIGHT_DATA; treehandle->m_SumSpacings += dTempLeft; treehandle->m_SumSpacingsSq += dTempLeft*dTempLeft; return CNEARTREE_SUCCESS; } coordRight = CVectorElementAt(treehandle->m_CoordStore,treenodehandle->m_indexRight); dTempRight = CNearTreeDist(treehandle, coord, coordRight); dTempLeftRight = CNearTreeDist(treehandle, coordLeft, coordRight); if ( dTempLeft > dTempRight ) { if ( !((treenodehandle->m_iflags)&CNEARTREE_FLAG_RIGHT_CHILD) ) { if ( (errorcode = CNearTreeNodeCreate(treehandle, &(treenodehandle->m_pRightBranch)))) return errorcode; treenodehandle->m_iflags |= CNEARTREE_FLAG_RIGHT_CHILD; treenodehandle->m_dMaxRight = dTempRight; } else if ( treenodehandle->m_dMaxRight < dTempRight ) { treenodehandle->m_dMaxRight = dTempRight; } /* If the left branch is empty, we are going to put something here */ if (!((treenodehandle->m_pRightBranch->m_iflags) & CNEARTREE_FLAG_LEFT_DATA )) { treenodehandle->m_pRightBranch->m_indexLeft = n; treenodehandle->m_pRightBranch->m_dMaxLeft = -1.; treenodehandle->m_pRightBranch->m_iflags |= CNEARTREE_FLAG_LEFT_DATA; treenodehandle->m_pRightBranch->m_iTreeSize = 1; treehandle->m_SumSpacings += dTempRight; treehandle->m_SumSpacingsSq += dTempRight*dTempRight; #ifdef CNEARTREE_INSTRUMENTED treenodehandle->m_pRightBranch->m_Height = 1; if (treenodehandle->m_Height < 2) treenodehandle->m_Height=2; #endif (*depth)++; return CNEARTREE_SUCCESS; } if ( (errorcode=CNearTreeNodeInsert(treehandle, treenodehandle->m_pRightBranch, n, depth))) return errorcode; #ifdef CNEARTREE_INSTRUMENTED treenodehandle->m_Height = 1+(treenodehandle->m_pRightBranch->m_Height); if ((treenodehandle->m_iflags & CNEARTREE_FLAG_LEFT_CHILD) && (treenodehandle->m_pLeftBranch->m_Height) >= treenodehandle->m_Height) treenodehandle->m_Height = 1+(treenodehandle->m_pLeftBranch->m_Height); #endif return CNEARTREE_SUCCESS; } else { /* ((double)(t - *m_tLeft) <= (double)(t - *m_tRight) ) */ if ( !((treenodehandle->m_iflags)&CNEARTREE_FLAG_LEFT_CHILD) ) { if ( (errorcode = CNearTreeNodeCreate(treehandle, &(treenodehandle->m_pLeftBranch)))) return errorcode; treenodehandle->m_iflags |= CNEARTREE_FLAG_LEFT_CHILD; treenodehandle->m_dMaxLeft = dTempLeft; } else if ( treenodehandle->m_dMaxLeft < dTempLeft ) { treenodehandle->m_dMaxLeft = dTempLeft; } /* If the left branch is empty, we are going to put something here */ if (!((treenodehandle->m_pLeftBranch->m_iflags) & CNEARTREE_FLAG_LEFT_DATA )) { treenodehandle->m_pLeftBranch->m_indexLeft = n; treenodehandle->m_pLeftBranch->m_dMaxLeft = -1.; treenodehandle->m_pLeftBranch->m_iflags |= CNEARTREE_FLAG_LEFT_DATA; treenodehandle->m_pLeftBranch->m_iTreeSize = 1; treehandle->m_SumSpacings += dTempLeft; treehandle->m_SumSpacingsSq += dTempLeft*dTempLeft; #ifdef CNEARTREE_INSTRUMENTED treenodehandle->m_pLeftBranch->m_Height = 1; if (treenodehandle->m_Height < 2) treenodehandle->m_Height=2; #endif (*depth)++; return CNEARTREE_SUCCESS; } if ( (errorcode=CNearTreeNodeInsert(treehandle, treenodehandle->m_pLeftBranch, n, depth))) return errorcode; #ifdef CNEARTREE_INSTRUMENTED treenodehandle->m_Height = 1+(treenodehandle->m_pLeftBranch->m_Height); if ((treenodehandle->m_iflags & CNEARTREE_FLAG_RIGHT_CHILD) && (treenodehandle->m_pRightBranch->m_Height) >= treenodehandle->m_Height) treenodehandle->m_Height = 1+(treenodehandle->m_pRightBranch->m_Height); #endif return CNEARTREE_SUCCESS; } } int CNearTreeNodeInsert_Flip( const CNearTreeHandle treehandle, const CNearTreeNodeHandle treenodehandle, const size_t index, size_t CNEARTREE_FAR * depth) { /* do a bit of precomputing if it is possible so that we can reduce the number of calls to sqrt */ double dTempRight = 0.; double dTempLeft = 0.; double dTempLeftRight = 0; int errorcode = 0; void CNEARTREE_FAR * coord; void CNEARTREE_FAR * coordLeft; void CNEARTREE_FAR * coordRight; const void CNEARTREE_FAR * obj; size_t n = index; (*depth)++; if ( !treehandle || !treenodehandle || index+1 > CVectorSize(treehandle->m_ObjectStore)) return CNEARTREE_BAD_ARGUMENT; obj = CVectorElementAt(treehandle->m_ObjectStore,index); coord = CVectorElementAt(treehandle->m_CoordStore,index); coordLeft = NULL; coordRight = NULL; (treenodehandle->m_iTreeSize)++; if ( !((treenodehandle->m_iflags)&CNEARTREE_FLAG_LEFT_DATA) ) { treenodehandle->m_indexLeft = n; treenodehandle->m_dMaxLeft = -1.; treenodehandle->m_iflags |= CNEARTREE_FLAG_LEFT_DATA; #ifdef CNEARTREE_INSTRUMENTED treenodehandle->m_Height = 1; #endif return CNEARTREE_SUCCESS; } coordLeft = CVectorElementAt(treehandle->m_CoordStore,treenodehandle->m_indexLeft); dTempLeft = CNearTreeDist(treehandle, coord, coordLeft); if ( !((treenodehandle->m_iflags)&CNEARTREE_FLAG_RIGHT_DATA) ){ treenodehandle->m_indexRight = n; treenodehandle->m_dMaxRight = -1.; treenodehandle->m_iflags |= CNEARTREE_FLAG_RIGHT_DATA; treehandle->m_SumSpacings += dTempLeft; treehandle->m_SumSpacingsSq += dTempLeft*dTempLeft; return CNEARTREE_SUCCESS; } coordRight = CVectorElementAt(treehandle->m_CoordStore,treenodehandle->m_indexRight); dTempRight = CNearTreeDist(treehandle, coord, coordRight); dTempLeftRight = CNearTreeDist(treehandle, coordLeft, coordRight); if ( dTempLeft > dTempRight ) { if ( !((treenodehandle->m_iflags)&CNEARTREE_FLAG_RIGHT_CHILD) ) { if ( (errorcode = CNearTreeNodeCreate(treehandle, &(treenodehandle->m_pRightBranch)))) return errorcode; treenodehandle->m_iflags |= CNEARTREE_FLAG_RIGHT_CHILD; treenodehandle->m_dMaxRight = dTempRight; } else if ( treenodehandle->m_dMaxRight < dTempRight ) { treenodehandle->m_dMaxRight = dTempRight; } /* If the left branch is empty, we are going to put something here */ if (!((treenodehandle->m_pRightBranch->m_iflags) & CNEARTREE_FLAG_LEFT_DATA )) { treenodehandle->m_pRightBranch->m_indexLeft = n; treenodehandle->m_pRightBranch->m_dMaxLeft = -1.; treenodehandle->m_pRightBranch->m_iflags |= CNEARTREE_FLAG_LEFT_DATA; treenodehandle->m_pRightBranch->m_iTreeSize = 1; treehandle->m_SumSpacings += dTempRight; treehandle->m_SumSpacingsSq += dTempRight*dTempRight; #ifdef CNEARTREE_INSTRUMENTED treenodehandle->m_pRightBranch->m_Height = 1; if (treenodehandle->m_Height < 2) treenodehandle->m_Height=2; #endif (*depth)++; /* See if it would be better to put the new node at this level and drop the current Right node down one level */ if (dTempRight > dTempLeftRight) { treenodehandle->m_pRightBranch->m_indexLeft = treenodehandle->m_indexRight; treenodehandle->m_indexRight = n; } return CNEARTREE_SUCCESS; } if ( (errorcode=CNearTreeNodeInsert(treehandle, treenodehandle->m_pRightBranch, n, depth))) return errorcode; #ifdef CNEARTREE_INSTRUMENTED treenodehandle->m_Height = 1+(treenodehandle->m_pRightBranch->m_Height); if ((treenodehandle->m_iflags & CNEARTREE_FLAG_LEFT_CHILD) && (treenodehandle->m_pLeftBranch->m_Height) >= treenodehandle->m_Height) treenodehandle->m_Height = 1+(treenodehandle->m_pLeftBranch->m_Height); #endif return CNEARTREE_SUCCESS; } else { /* ((double)(t - *m_tLeft) <= (double)(t - *m_tRight) ) */ if ( !((treenodehandle->m_iflags)&CNEARTREE_FLAG_LEFT_CHILD) ) { if ( (errorcode = CNearTreeNodeCreate(treehandle, &(treenodehandle->m_pLeftBranch)))) return errorcode; treenodehandle->m_iflags |= CNEARTREE_FLAG_LEFT_CHILD; treenodehandle->m_dMaxLeft = dTempLeft; } else if ( treenodehandle->m_dMaxLeft < dTempLeft ) { treenodehandle->m_dMaxLeft = dTempLeft; } /* If the left branch is empty, we are going to put something here */ if (!((treenodehandle->m_pLeftBranch->m_iflags) & CNEARTREE_FLAG_LEFT_DATA )) { treenodehandle->m_pLeftBranch->m_indexLeft = n; treenodehandle->m_pLeftBranch->m_dMaxLeft = -1.; treenodehandle->m_pLeftBranch->m_iflags |= CNEARTREE_FLAG_LEFT_DATA; treenodehandle->m_pLeftBranch->m_iTreeSize = 1; treehandle->m_SumSpacings += dTempLeft; treehandle->m_SumSpacingsSq += dTempLeft*dTempLeft; #ifdef CNEARTREE_INSTRUMENTED treenodehandle->m_pLeftBranch->m_Height = 1; if (treenodehandle->m_Height < 2) treenodehandle->m_Height=2; #endif (*depth)++; /* See if it would be better to put the new node at this level and drop the current Left node down one level */ if (dTempLeft > dTempLeftRight ) { treenodehandle->m_pLeftBranch->m_indexLeft = treenodehandle->m_indexLeft; treenodehandle->m_indexLeft = n; } return CNEARTREE_SUCCESS; } if ( (errorcode=CNearTreeNodeInsert(treehandle, treenodehandle->m_pLeftBranch, n, depth))) return errorcode; #ifdef CNEARTREE_INSTRUMENTED treenodehandle->m_Height = 1+(treenodehandle->m_pLeftBranch->m_Height); if ((treenodehandle->m_iflags & CNEARTREE_FLAG_RIGHT_CHILD) && (treenodehandle->m_pRightBranch->m_Height) >= treenodehandle->m_Height) treenodehandle->m_Height = 1+(treenodehandle->m_pRightBranch->m_Height); #endif return CNEARTREE_SUCCESS; } } /* ======================================================================= int CNearTreeInsert ( const CNearTreeHandle treehandle, const void CNEARTREE_FAR * coord, const void * obj ) Function to queue some "point" as an object for future insertion into a CNearTree for later searching coord is a coordinate vector for an object, obj, to be inserted into a Neartree. A static copy of the coordinates and a pointer to the object are queued for insertion. The exact order of insertion is not predetermined. It will be partially randomized to help to balance the tree. The insertions will be completed by a call to CNearTreeCompleteDelayedInsert(const CNearTreeHandle treehandle) or by execution of any search. return 0 for success, nonzero for an error ======================================================================= */ int CNearTreeInsert( const CNearTreeHandle treehandle, const void CNEARTREE_FAR * coord, const void CNEARTREE_FAR * obj ) { int treetype; size_t treedim; size_t index; int errorcode; errorcode = CNEARTREE_SUCCESS; if (!treehandle || !coord ) return CNEARTREE_BAD_ARGUMENT; treetype = (treehandle->m_iflags) & CNEARTREE_TYPE; treedim = treehandle->m_szdimension; if ( treehandle->m_ObjectStore == NULL) { if (CVectorCreate(&(treehandle->m_ObjectStore),sizeof(void *),10)) { return CNEARTREE_MALLOC_FAILED; } } if ( treehandle->m_CoordStore == NULL) { if (CVectorCreate(&(treehandle->m_CoordStore), treedim*((treetype&CNEARTREE_TYPE_DOUBLE)?sizeof(double):sizeof(int)),10)) { return CNEARTREE_MALLOC_FAILED; } } index = CVectorSize(treehandle->m_ObjectStore); if (CVectorAddElement(treehandle->m_ObjectStore,(void CNEARTREE_FAR *)&obj)) return CNEARTREE_CVECTOR_FAILED; if (CVectorAddElement(treehandle->m_CoordStore,(void CNEARTREE_FAR *)coord)) return CNEARTREE_CVECTOR_FAILED; if (treehandle->m_DelayedIndices==NULL) { if (CVectorCreate(&(treehandle->m_DelayedIndices),sizeof(size_t),10)) { return CNEARTREE_MALLOC_FAILED; } } if (CVectorAddElement(treehandle->m_DelayedIndices,&index)) return CNEARTREE_CVECTOR_FAILED; if (treehandle->m_iflags & CNTF_NODEFER && treehandle->m_szdepth < 100) { errorcode = CNearTreeCompleteDelayedInsert(treehandle); } treehandle->m_DimEstimate = 0; treehandle->m_DimEstimateEsd= 0; return errorcode; } /* ======================================================================= int CNearTreeDelayedInsert ( const CNearTreeHandle treehandle, const void CNEARTREE_FAR * coord, const void * obj ) *** THIS IS A DEPRECATED ALTLERNATE CALL TO CNearTreeInsert *** Function to queue some "point" as an object for future insertion into a CNearTree for later searching coord is a coordinate vector for an object, obj, to be inserted into a Neartree. A static copy of the coordinates and a pointer to the object are queued for insertion. The exact order of insertion is not predetermined. It will be partially randomized to help to balance the tree. The insertions will be completed by a call to CNearTreeCompleteDelayedInsert(const CNearTreeHandle treehandle) or by execution of any search. return 0 for success, nonzero for an error ======================================================================= */ int CNearTreeDelayedInsert( const CNearTreeHandle treehandle, const void CNEARTREE_FAR * coord, const void CNEARTREE_FAR * obj ) { return CNearTreeInsert(treehandle,coord,obj); } /* ======================================================================= int CNearTreeCompleteDelayedInsert ( const CNearTreeHandle treehandle ) Function to dequeue the "points" queued as an objects for future insertion into a CNearTree for later searching return 0 for success, nonzero for an error ======================================================================= */ int CNearTreeCompleteDelayedInsert ( const CNearTreeHandle treehandle ) { size_t nqueued; size_t ntarget; size_t nrandom; int npass; size_t ielement, kelement=0, oelement; int errorcode; size_t depth; size_t errsize; size_t added; size_t dummyindex; size_t index; double dummyrand; if (!treehandle) return CNEARTREE_BAD_ARGUMENT; if (treehandle->m_DelayedIndices == NULL ) return CNEARTREE_SUCCESS; if (treehandle->m_ObjectStore == NULL || treehandle->m_CoordStore == NULL || CVectorSize(treehandle->m_ObjectStore) != CVectorSize(treehandle->m_CoordStore)) return CNEARTREE_BAD_ARGUMENT; errorcode = 0; nqueued = CVectorSize(treehandle->m_DelayedIndices); ntarget = nqueued + treehandle->m_szsize; dummyindex = CVectorSize(treehandle->m_ObjectStore); nrandom = (size_t)sqrt((double)nqueued); if ((treehandle->m_iflags& CNTF_FORCEFLIP)||!(treehandle->m_iflags& CNTF_NOFLIP)){ for (ielement = 0; ielement < nrandom; ielement++) { kelement = (int)(CRHrandUrand(&(treehandle->m_rhr))*((double)(nqueued))); dummyrand = CRHrandUrand(&(treehandle->m_rhr)) + CRHrandUrand(&(treehandle->m_rhr)); oelement = kelement; do { if (kelement >= nqueued) { kelement = 0; CVectorSetSize(treehandle->m_DelayedIndices,oelement); nqueued = oelement; } if (CVectorGetElement(treehandle->m_DelayedIndices,&index,kelement)) return CNEARTREE_BAD_ARGUMENT; kelement ++; } while (index == dummyindex); if (kelement == nqueued) { nqueued--; CVectorSetSize(treehandle->m_DelayedIndices,nqueued); } kelement--; if (CVectorSetElement(treehandle->m_DelayedIndices,&dummyindex,kelement)) errorcode |= CNEARTREE_CVECTOR_FAILED; depth = 0; errorcode |= CNearTreeNodeInsert_Flip(treehandle,treehandle->m_ptTree,index,&depth); if (depth > treehandle->m_szdepth) treehandle->m_szdepth = depth; (treehandle->m_szsize)++; } npass = 0; while (treehandle->m_szsize < ntarget) { npass++; errsize = (treehandle->m_ptTree->m_iTreeSize)>>(-1+treehandle->m_szdepth); if ( errsize < 1 ) { kelement = (int)(CRHrandUrand(&(treehandle->m_rhr))*((double)(nqueued))); dummyrand = CRHrandUrand(&(treehandle->m_rhr)) + CRHrandUrand(&(treehandle->m_rhr)); oelement = kelement; do { if (kelement >= nqueued) { kelement = 0; CVectorSetSize(treehandle->m_DelayedIndices,oelement); nqueued = oelement; } if (CVectorGetElement(treehandle->m_DelayedIndices,&index,kelement)) return CNEARTREE_BAD_ARGUMENT; kelement ++; } while (index == dummyindex); if (kelement == nqueued) { nqueued--; CVectorSetSize(treehandle->m_DelayedIndices,nqueued); } kelement--; if (CVectorSetElement(treehandle->m_DelayedIndices,&dummyindex,kelement)) errorcode |= CNEARTREE_CVECTOR_FAILED; depth = 0; errorcode |= CNearTreeNodeInsert_Flip(treehandle,treehandle->m_ptTree,index,&depth); if (depth > treehandle->m_szdepth) treehandle->m_szdepth = depth; (treehandle->m_szsize)++; } else { added=0; for (ielement = 0; ielement < nqueued; ielement++) { if (CVectorGetElement(treehandle->m_DelayedIndices,&index,ielement)) return CNEARTREE_CVECTOR_FAILED; if (index == dummyindex) continue; depth = 0; errorcode |= CNearTreeNodeInsert_Flip(treehandle,treehandle->m_ptTree,index,&depth); if (CVectorSetElement(treehandle->m_DelayedIndices,&dummyindex,ielement)) errorcode |= CNEARTREE_CVECTOR_FAILED; if (depth > treehandle->m_szdepth) treehandle->m_szdepth = depth; (treehandle->m_szsize)++; added++; if (added > 100 || added > 8*npass) { errsize = (treehandle->m_ptTree->m_iTreeSize)>>(-1+treehandle->m_szdepth); if ( errsize < 1 ) break; } } } } } else { for (ielement = 0; ielement < nrandom; ielement++) { kelement = (int)(CRHrandUrand(&(treehandle->m_rhr))*((double)(nqueued))); dummyrand = CRHrandUrand(&(treehandle->m_rhr)) + CRHrandUrand(&(treehandle->m_rhr)); oelement = kelement; do { if (kelement >= nqueued) { kelement = 0; CVectorSetSize(treehandle->m_DelayedIndices,oelement); nqueued = oelement; } if (CVectorGetElement(treehandle->m_DelayedIndices,&index,kelement)) return CNEARTREE_BAD_ARGUMENT; kelement ++; } while (index == dummyindex); if (kelement == nqueued) { nqueued--; CVectorSetSize(treehandle->m_DelayedIndices,nqueued); } kelement--; if (CVectorSetElement(treehandle->m_DelayedIndices,&dummyindex,kelement)) errorcode |= CNEARTREE_CVECTOR_FAILED; depth = 0; errorcode |= CNearTreeNodeInsert(treehandle,treehandle->m_ptTree,index,&depth); if (depth > treehandle->m_szdepth) treehandle->m_szdepth = depth; (treehandle->m_szsize)++; } npass = 0; while (treehandle->m_szsize < ntarget) { npass++; errsize = (treehandle->m_ptTree->m_iTreeSize)>>(-1+treehandle->m_szdepth); if ( errsize < 1 ) { kelement = (int)(CRHrandUrand(&(treehandle->m_rhr))*((double)(nqueued))); dummyrand = CRHrandUrand(&(treehandle->m_rhr)) + CRHrandUrand(&(treehandle->m_rhr)); oelement = kelement; do { if (kelement >= nqueued) { kelement = 0; CVectorSetSize(treehandle->m_DelayedIndices,oelement); nqueued = oelement; } if (CVectorGetElement(treehandle->m_DelayedIndices,&index,ielement)) return CNEARTREE_BAD_ARGUMENT; kelement ++; } while (index == dummyindex); if (kelement == nqueued) { nqueued--; CVectorSetSize(treehandle->m_DelayedIndices,nqueued); } kelement--; if (CVectorSetElement(treehandle->m_DelayedIndices,&dummyindex,kelement)) errorcode |= CNEARTREE_CVECTOR_FAILED; depth = 0; errorcode |= CNearTreeNodeInsert(treehandle,treehandle->m_ptTree,index,&depth); if (depth > treehandle->m_szdepth) treehandle->m_szdepth = depth; (treehandle->m_szsize)++; } else { added = 0; for (ielement = 0; ielement < nqueued; ielement++) { if (CVectorGetElement(treehandle->m_DelayedIndices,&index,ielement)) return CNEARTREE_CVECTOR_FAILED; if (index == dummyindex) continue; depth = 0; errorcode |= CNearTreeNodeInsert(treehandle,treehandle->m_ptTree,index,&depth); if (CVectorSetElement(treehandle->m_DelayedIndices,&dummyindex,ielement)) errorcode |= CNEARTREE_CVECTOR_FAILED; if (depth > treehandle->m_szdepth) treehandle->m_szdepth = depth; (treehandle->m_szsize)++; added++; if (added > 100 || added > 8*npass) { errsize = (treehandle->m_ptTree->m_iTreeSize)>>(-1+treehandle->m_szdepth); if ( errsize < 1 ) break; } } } } } if (CVectorFree(&(treehandle->m_DelayedIndices))) errorcode |= CNEARTREE_CVECTOR_FAILED; return (errorcode != 0)?errorcode:CNEARTREE_SUCCESS; } /* ======================================================================= int CNearTreeNearestNeighbor ( const CNearTreeHandle treehandle, const double dRadius, void CNEARTREE_FAR * CNEARTREE_FAR * coordClosest, void CNEARTREE_FAR * CNEARTREE_FAR * objClosest, const void CNEARTREE_FAR * coord ) Function to search a Neartree for the object closest to some probe point, coord. This function is only here so that the function CNearTreeNearest can be called without having dRadius const dRadius is the maximum search radius - any point farther than dRadius from the probe point will be ignored coordClosest is a pointer to the coordinate vector of the nearest point objClosest is the address into which a pointer to the object associated with coordClosest will be stored coord is the probe point the return value is true only if a point was found This version does a balanced search ======================================================================= ======================================================================= int CNearTreeLeftNearestNeighbor ( const CNearTreeHandle treehandle, const double dRadius, void CNEARTREE_FAR * CNEARTREE_FAR * coordClosest, void CNEARTREE_FAR * CNEARTREE_FAR * objClosest, const void CNEARTREE_FAR * coord ) Function to search a Neartree for the object closest to some probe point, coord. This function is only here so that the function CNearTreeNearest can be called without having dRadius const dRadius is the maximum search radius - any point farther than dRadius from the probe point will be ignored coordClosest is a pointer to the coordinate vector of the nearest point objClosest is the address into which a pointer to the object associated with coordClosest will be stored coord is the probe point the return value is true only if a point was found This version does a left search first ======================================================================= */ int CNearTreeNearestNeighbor (const CNearTreeHandle treehandle, const double dRadius, void CNEARTREE_FAR * CNEARTREE_FAR * coordClosest, void CNEARTREE_FAR * CNEARTREE_FAR * objClosest, const void CNEARTREE_FAR * coord ) { double dSearchRadius = dRadius; if (!treehandle || ! coord ) return CNEARTREE_BAD_ARGUMENT; if ( treehandle->m_DelayedIndices ) { if (CNearTreeCompleteDelayedInsert(treehandle)!=CNEARTREE_SUCCESS) return CNEARTREE_BAD_ARGUMENT; } if (!(treehandle->m_ptTree->m_iflags&CNEARTREE_FLAG_LEFT_DATA)) return CNEARTREE_NOT_FOUND; return ( CNearTreeNearest ( treehandle, &dSearchRadius, coordClosest, objClosest, coord ) ); } int CNearTreeLeftNearestNeighbor (const CNearTreeHandle treehandle, const double dRadius, void CNEARTREE_FAR * CNEARTREE_FAR * coordClosest, void CNEARTREE_FAR * CNEARTREE_FAR * objClosest, const void CNEARTREE_FAR * coord ) { double dSearchRadius = dRadius; if (!treehandle || ! coord ) return CNEARTREE_BAD_ARGUMENT; if ( treehandle->m_DelayedIndices ) { if (CNearTreeCompleteDelayedInsert(treehandle)!=CNEARTREE_SUCCESS) return CNEARTREE_BAD_ARGUMENT; } if (!(treehandle->m_ptTree->m_iflags&CNEARTREE_FLAG_LEFT_DATA)) return CNEARTREE_NOT_FOUND; return ( CNearTreeLeftNearest ( treehandle, &dSearchRadius, coordClosest, objClosest, coord ) ); } /* ======================================================================= int CNearTreeFarthestNeighbor ( const CNearTreeHandle treehandle, void CNEARTREE_FAR * CNEARTREE_FAR * coordFarthest, void CNEARTREE_FAR * CNEARTREE_FAR * objFarthest, const void CNEARTREE_FAR * coord ) Function to search a Neartree for the object farthest some probe point, coord. coordClosest is a pointer to the coordinate vector of the nearest point objClosest is the address into which a pointer to the object associated with coordClosest will be stored coord is the probe point the return value is 0 only if a point was found ======================================================================= */ int CNearTreeFarthestNeighbor (const CNearTreeHandle treehandle, void CNEARTREE_FAR * CNEARTREE_FAR * coordFarthest, void CNEARTREE_FAR * CNEARTREE_FAR * objFarthest, const void CNEARTREE_FAR * coord ) { double dSearchRadius = DBL_MIN; if ( !treehandle || !coord ) return CNEARTREE_BAD_ARGUMENT; if ( treehandle->m_DelayedIndices ) { if (CNearTreeCompleteDelayedInsert(treehandle)!=CNEARTREE_SUCCESS) return CNEARTREE_BAD_ARGUMENT; } if (!(treehandle->m_ptTree->m_iflags&CNEARTREE_FLAG_LEFT_DATA)) return CNEARTREE_NOT_FOUND; return ( CNearTreeFindFarthest ( treehandle, &dSearchRadius, coordFarthest, objFarthest, coord ) ); } /* ======================================================================= int CNearTreeFindInSphere ( const CNearTreeHandle treehandle, const double dRadius, CVectorHandle coordclosest, CVectorHandle objClosest, const void CNEARTREE_FAR * coord, int resetcount) Function to search a Neartree for the set of objects closer to some probe point, coord, than dRadius. This is only here so that objClosest can be cleared before starting the work. dRadius is the maximum search radius - any point farther than dRadius from the probe point will be ignored coordClosest is a vector of pointers to coordinate tuples of nearest points objClosest is a vector of objects and is the returned set of nearest points to the probe point that can be found in the Neartree coord is the probe point resetcount should be non-zero to clear coordclosest and objClosest on entry return value is 0 if points were found ======================================================================= */ int CNearTreeFindInSphereL2LAZY ( const CNearTreeHandle treehandle, const double dRadius, CVectorHandle coordClosest, CVectorHandle objClosest, const void CNEARTREE_FAR * coord, int resetcount) { double dDR, dDL; int nopoints; CVectorHandle sStack; CVectorHandle coords; CVectorHandle objs; void CNEARTREE_FAR * xcoord; void CNEARTREE_FAR * xobj; CNearTreeNodeHandle pt; double dist, drat; enum { left, right, end } eDir; eDir = left; /* examine the left nodes first */ nopoints = 1; dist = 0.; dDR = dDL = DBL_MAX; if (dRadius < 0.) return 1; if ( !treehandle || !coord ) return CNEARTREE_BAD_ARGUMENT; if ( treehandle->m_DelayedIndices ) { if (CNearTreeCompleteDelayedInsert(treehandle)!=CNEARTREE_SUCCESS) return CNEARTREE_BAD_ARGUMENT; } if (!(treehandle->m_iflags & CNEARTREE_NORM_L2LAZY)) return CNEARTREE_BAD_ARGUMENT; drat = sqrt((double)(treehandle->m_szdimension)); pt = treehandle->m_ptTree; coords=treehandle->m_CoordStore; objs=treehandle->m_ObjectStore; if (!pt) return CNEARTREE_BAD_ARGUMENT; if (!(pt->m_iflags&CNEARTREE_FLAG_LEFT_DATA)) return CNEARTREE_NOT_FOUND; #ifdef CNEARTREE_INSTRUMENTED (treehandle->m_NodeVisits)++; #endif CVectorCreate(&sStack,sizeof(CNearTreeNodeHandle),10); /* clear the contents of the return vector so that things don't accidentally accumulate */ if (resetcount) { if (coordClosest) CVectorClear( coordClosest ); if (objClosest) CVectorClear( objClosest ); } while (!(eDir == end && CVectorSize(sStack) == 0)) { if ( eDir == right ) { dDR = DBL_MAX; if ((pt->m_iflags)&CNEARTREE_FLAG_RIGHT_DATA) { CNTM_DistL1(dDR,treehandle, (void CNEARTREE_FAR *)coord, CVectorElementAt(coords,pt->m_indexRight)); if (dDR <= dRadius ){ nopoints = 0; if (coordClosest) { xcoord = CVectorElementAt(coords,pt->m_indexRight); CVectorAddElement(coordClosest,&xcoord); } if (objClosest) { xobj = CVectorElementAt(objs,pt->m_indexRight); CVectorAddElement(objClosest,&xobj); } } else if (dDR <= dRadius*drat) { CNTM_DistL2(dist,treehandle, (void CNEARTREE_FAR *)coord, CVectorElementAt(coords,pt->m_indexRight)); if (dist <= dRadius) { nopoints = 0; if (coordClosest) { xcoord = CVectorElementAt(coords,pt->m_indexRight); CVectorAddElement(coordClosest,&xcoord); } if (objClosest) { xobj = CVectorElementAt(objs,pt->m_indexRight); CVectorAddElement(objClosest,&xobj); } } } } if ((pt->m_iflags&CNEARTREE_FLAG_RIGHT_CHILD)&& (TRIANG(dDR,pt->m_dMaxRight,dRadius))){ /* we did the left and now we finished the right, go down */ pt = pt->m_pRightBranch; #ifdef CNEARTREE_INSTRUMENTED (treehandle->m_NodeVisits)++; #endif eDir = left; } else { eDir = end; } } if ( eDir == left ) { if ((pt->m_iflags)&CNEARTREE_FLAG_LEFT_DATA) { CNTM_DistL1(dDL,treehandle, (void CNEARTREE_FAR *)coord, CVectorElementAt(coords,pt->m_indexLeft)); if (dDL <= dRadius) { nopoints = 0; if (coordClosest) { xcoord = CVectorElementAt(coords,pt->m_indexLeft); CVectorAddElement(coordClosest,&xcoord); } if (objClosest) { xobj = CVectorElementAt(objs,pt->m_indexLeft); CVectorAddElement(objClosest,&xobj); } } else if ( dDL <= dRadius*drat ) { CNTM_DistL2(dist,treehandle, (void CNEARTREE_FAR *)coord, CVectorElementAt(coords,pt->m_indexLeft)) if (dist <= dRadius){ nopoints = 0; if (coordClosest) { xcoord = CVectorElementAt(coords,pt->m_indexLeft); CVectorAddElement(coordClosest,&xcoord); } if (objClosest) { xobj = CVectorElementAt(objs,pt->m_indexLeft); CVectorAddElement(objClosest,&xobj); } } } } if (pt->m_iflags&CNEARTREE_FLAG_RIGHT_DATA) { CVectorAddElement(sStack,&pt); } if ((pt->m_iflags&CNEARTREE_FLAG_LEFT_CHILD)&& (TRIANG(dDL,pt->m_dMaxLeft,dRadius))){ pt = pt->m_pLeftBranch; #ifdef CNEARTREE_INSTRUMENTED (treehandle->m_NodeVisits)++; #endif } else { eDir = end; } } if ( eDir == end && CVectorSize(sStack) != 0 ) { CVectorGetElement(sStack,&pt,CVectorSize(sStack)-1); CVectorRemoveElement(sStack,CVectorSize(sStack)-1); eDir = right; } } CVectorFree(&sStack); return nopoints?CNEARTREE_NOT_FOUND:CNEARTREE_SUCCESS; } int CNearTreeFindInSphere ( const CNearTreeHandle treehandle, const double dRadius, CVectorHandle coordClosest, CVectorHandle objClosest, const void CNEARTREE_FAR * coord, int resetcount) { double dDR, dDL; int nopoints; CVectorHandle sStack; CVectorHandle coords; CVectorHandle objs; void CNEARTREE_FAR * xcoord; void CNEARTREE_FAR * xobj; CNearTreeNodeHandle pt; enum { left, right, end } eDir; if ((treehandle->m_iflags & CNEARTREE_NORM_L2LAZY)) return CNearTreeFindInSphereL2LAZY(treehandle,dRadius,coordClosest, objClosest,coord,resetcount); eDir = left; /* examine the left nodes first */ nopoints = 1; dDR = dDL = DBL_MAX; if (dRadius < 0.) return 1; if ( !treehandle || !coord ) return CNEARTREE_BAD_ARGUMENT; if ( treehandle->m_DelayedIndices ) { if (CNearTreeCompleteDelayedInsert(treehandle)!=CNEARTREE_SUCCESS) return CNEARTREE_BAD_ARGUMENT; } pt = treehandle->m_ptTree; coords=treehandle->m_CoordStore; objs=treehandle->m_ObjectStore; if (!pt) return CNEARTREE_BAD_ARGUMENT; if (!(pt->m_iflags&CNEARTREE_FLAG_LEFT_DATA)) return CNEARTREE_NOT_FOUND; #ifdef CNEARTREE_INSTRUMENTED (treehandle->m_NodeVisits)++; #endif CVectorCreate(&sStack,sizeof(CNearTreeNodeHandle),10); /* clear the contents of the return vector so that things don't accidentally accumulate */ if (resetcount) { if (coordClosest) CVectorClear( coordClosest ); if (objClosest) CVectorClear( objClosest ); } while (!(eDir == end && CVectorSize(sStack) == 0)) { if ( eDir == right ) { dDR = DBL_MAX; if ((pt->m_iflags)&CNEARTREE_FLAG_RIGHT_DATA) { dDR = CNearTreeDist(treehandle, (void CNEARTREE_FAR *)coord, CVectorElementAt(coords,pt->m_indexRight)); if (dDR <= dRadius ) { nopoints = 0; if (coordClosest) { xcoord = CVectorElementAt(coords,pt->m_indexRight); CVectorAddElement(coordClosest,&xcoord); } if (objClosest) { xobj = CVectorElementAt(objs,pt->m_indexRight); CVectorAddElement(objClosest,&xobj); } } } if ((pt->m_iflags&CNEARTREE_FLAG_RIGHT_CHILD)&& (TRIANG(dDR,pt->m_dMaxRight,dRadius))){ /* we did the left and now we finished the right, go down */ pt = pt->m_pRightBranch; #ifdef CNEARTREE_INSTRUMENTED (treehandle->m_NodeVisits)++; #endif eDir = left; } else { eDir = end; } } if ( eDir == left ) { if ((pt->m_iflags)&CNEARTREE_FLAG_LEFT_DATA) { dDL = CNearTreeDist(treehandle, (void CNEARTREE_FAR *)coord, CVectorElementAt(coords,pt->m_indexLeft)); if (dDL <= dRadius ) { nopoints = 0; if (coordClosest) { xcoord = CVectorElementAt(coords,pt->m_indexLeft); CVectorAddElement(coordClosest,&xcoord); } if (objClosest) { xobj = CVectorElementAt(objs,pt->m_indexLeft); CVectorAddElement(objClosest,&xobj); } } } if (pt->m_iflags&CNEARTREE_FLAG_RIGHT_DATA) { CVectorAddElement(sStack,&pt); } if ((pt->m_iflags&CNEARTREE_FLAG_LEFT_CHILD)&& (TRIANG(dDL,pt->m_dMaxLeft,dRadius))){ pt = pt->m_pLeftBranch; #ifdef CNEARTREE_INSTRUMENTED (treehandle->m_NodeVisits)++; #endif } else { eDir = end; } } if ( eDir == end && CVectorSize(sStack) != 0 ) { CVectorGetElement(sStack,&pt,CVectorSize(sStack)-1); CVectorRemoveElement(sStack,CVectorSize(sStack)-1); eDir = right; } } CVectorFree(&sStack); return nopoints?CNEARTREE_NOT_FOUND:CNEARTREE_SUCCESS; } /* ======================================================================= int CNearTreeFindTreeInSphere ( const CNearTreeHandle treehandle, const double dRadius, CNearTreeHandle foundClosest, const void CNEARTREE_FAR * coord, int resetcount) Function to search a Neartree for the set of objects closer to some probe point, coord, than dRadius. This is only here so that objClosest can be cleared before starting the work. dRadius is the maximum search radius - any point farther than dRadius from the probe point will be ignored foundClosest is an existing CNearTree to which the found points will be added coord is the probe point resetcount should be non-zero to clear found closest on entry return value is 0 if points were found ======================================================================= */ int CNearTreeFindTreeInSphere ( const CNearTreeHandle treehandle, const double dRadius, CNearTreeHandle foundClosest, const void CNEARTREE_FAR * coord, int resetcount) { CVectorHandle objs; CVectorHandle coords; size_t ii; int errorcode; if ( !treehandle || !coord || !foundClosest ) return CNEARTREE_BAD_ARGUMENT; if ( treehandle->m_DelayedIndices ) { if (CNearTreeCompleteDelayedInsert(treehandle)!=CNEARTREE_SUCCESS) return CNEARTREE_BAD_ARGUMENT; } /* clear the contents of the return tree so that things don't accidentally accumulate */ if (resetcount) { CNearTreeClear( foundClosest ); } if (CVectorCreate(&objs,sizeof(void *),10)) { return CNEARTREE_MALLOC_FAILED; } if (CVectorCreate(&coords,sizeof(void *),10)) { return CNEARTREE_MALLOC_FAILED; } CNearTreeFindInSphere(treehandle, dRadius, coords, objs, coord, 0); for (ii=0; iim_DelayedIndices ) { if (CNearTreeCompleteDelayedInsert(treehandle)!=CNEARTREE_SUCCESS) return CNEARTREE_BAD_ARGUMENT; } drat = sqrt((double)(treehandle->m_szdimension)); pt = treehandle->m_ptTree; coords=treehandle->m_CoordStore; objs=treehandle->m_ObjectStore; if (!pt) return CNEARTREE_BAD_ARGUMENT; if (!(pt->m_iflags&CNEARTREE_FLAG_LEFT_DATA)) return CNEARTREE_NOT_FOUND; #ifdef CNEARTREE_INSTRUMENTED (treehandle->m_NodeVisits)++; #endif CVectorCreate(&sStack,sizeof(CNearTreeNodeHandle),10); /* clear the contents of the return vector so that things don't accidentally accumulate */ if (resetcount) { if (coordOutside) CVectorClear( coordOutside ); if (objOutside) CVectorClear( objOutside ); } while (!(eDir == end && CVectorSize(sStack) == 0)) { if ( eDir == right ) { dDR = DBL_MAX; if ((pt->m_iflags)&CNEARTREE_FLAG_RIGHT_DATA) { CNTM_DistL1(dDR,treehandle, (void CNEARTREE_FAR *)coord, CVectorElementAt(coords,pt->m_indexRight)); if (dDR >= dRadius*drat ) { nopoints = 0; if (coordOutside) { xcoord = CVectorElementAt(coords,pt->m_indexRight); CVectorAddElement(coordOutside,&xcoord); } if (objOutside) { xobj = CVectorElementAt(objs,pt->m_indexRight); CVectorAddElement(objOutside,&xobj); } } else if (dDR >= dRadius ) { CNTM_DistL2(dist,treehandle, (void CNEARTREE_FAR *)coord, CVectorElementAt(coords,pt->m_indexRight)); if (dist >= dRadius) { nopoints = 0; if (coordOutside) { xcoord = CVectorElementAt(coords,pt->m_indexRight); CVectorAddElement(coordOutside,&xcoord); } if (objOutside) { xobj = CVectorElementAt(objs,pt->m_indexRight); CVectorAddElement(objOutside,&xobj); } } } } if ((pt->m_iflags&CNEARTREE_FLAG_RIGHT_CHILD)&& (TRIANG(dRadius,dDR,pt->m_dMaxRight))){ /* we did the left and now we finished the right, go down */ pt = pt->m_pRightBranch; #ifdef CNEARTREE_INSTRUMENTED (treehandle->m_NodeVisits)++; #endif eDir = left; } else { eDir = end; } } if ( eDir == left ) { if ((pt->m_iflags)&CNEARTREE_FLAG_LEFT_DATA) { CNTM_DistL1(dDL,treehandle, (void CNEARTREE_FAR *)coord, CVectorElementAt(coords,pt->m_indexLeft)); if (dDL >= dRadius*drat ) { nopoints = 0; if (coordOutside) { xcoord = CVectorElementAt(coords,pt->m_indexLeft); CVectorAddElement(coordOutside,&xcoord); } if (objOutside) { xobj = CVectorElementAt(objs,pt->m_indexLeft); CVectorAddElement(objOutside,&xobj); } } else if (dDL >= dRadius) { CNTM_DistL2(dist,treehandle, (void CNEARTREE_FAR *)coord, CVectorElementAt(coords,pt->m_indexLeft)); if (dist >= dRadius) { nopoints = 0; if (coordOutside) { xcoord = CVectorElementAt(coords,pt->m_indexLeft); CVectorAddElement(coordOutside,&xcoord); } if (objOutside) { xobj = CVectorElementAt(objs,pt->m_indexLeft); CVectorAddElement(objOutside,&xobj); } } } } if (pt->m_iflags&CNEARTREE_FLAG_RIGHT_DATA) { CVectorAddElement(sStack,&pt); } if ((pt->m_iflags&CNEARTREE_FLAG_LEFT_CHILD)&& (TRIANG(dRadius,dDL,pt->m_dMaxLeft))){ pt = pt->m_pLeftBranch; #ifdef CNEARTREE_INSTRUMENTED (treehandle->m_NodeVisits)++; #endif } else { eDir = end; } } if ( eDir == end && CVectorSize(sStack) != 0 ) { CVectorGetElement(sStack,&pt,CVectorSize(sStack)-1); CVectorRemoveElement(sStack,CVectorSize(sStack)-1); eDir = right; } } CVectorFree(&sStack); return nopoints?CNEARTREE_NOT_FOUND:CNEARTREE_SUCCESS; } int CNearTreeFindOutSphere ( const CNearTreeHandle treehandle, const double dRadius, CVectorHandle coordOutside, CVectorHandle objOutside, const void * coord, int resetcount){ double dDR, dDL; int nopoints; CVectorHandle sStack; CVectorHandle coords; CVectorHandle objs; void CNEARTREE_FAR * xcoord; void CNEARTREE_FAR * xobj; CNearTreeNodeHandle pt; enum { left, right, end } eDir; eDir = left; /* examine the left nodes first */ nopoints = 1; dDR = dDL = DBL_MAX; if (dRadius < 0.) return 1; if ( !treehandle || !coord ) return CNEARTREE_BAD_ARGUMENT; if ((treehandle->m_iflags & CNEARTREE_NORM_L2LAZY)) return CNearTreeFindOutSphereL2LAZY(treehandle,dRadius,coordOutside,objOutside,coord,resetcount); if ( treehandle->m_DelayedIndices ) { if (CNearTreeCompleteDelayedInsert(treehandle)!=CNEARTREE_SUCCESS) return CNEARTREE_BAD_ARGUMENT; } pt = treehandle->m_ptTree; coords=treehandle->m_CoordStore; objs=treehandle->m_ObjectStore; if (!pt) return CNEARTREE_BAD_ARGUMENT; if (!(pt->m_iflags&CNEARTREE_FLAG_LEFT_DATA)) return CNEARTREE_NOT_FOUND; #ifdef CNEARTREE_INSTRUMENTED (treehandle->m_NodeVisits)++; #endif CVectorCreate(&sStack,sizeof(CNearTreeNodeHandle),10); /* clear the contents of the return vector so that things don't accidentally accumulate */ if (resetcount) { if (coordOutside) CVectorClear( coordOutside ); if (objOutside) CVectorClear( objOutside ); } while (!(eDir == end && CVectorSize(sStack) == 0)) { if ( eDir == right ) { dDR = DBL_MAX; if ((pt->m_iflags)&CNEARTREE_FLAG_RIGHT_DATA) { dDR = CNearTreeDist(treehandle, (void CNEARTREE_FAR *)coord, CVectorElementAt(coords,pt->m_indexRight)); if (dDR >= dRadius ) { nopoints = 0; if (coordOutside) { xcoord = CVectorElementAt(coords,pt->m_indexRight); CVectorAddElement(coordOutside,&xcoord); } if (objOutside) { xobj = CVectorElementAt(objs,pt->m_indexRight); CVectorAddElement(objOutside,&xobj); } } } if ((pt->m_iflags&CNEARTREE_FLAG_RIGHT_CHILD)&& (TRIANG(dRadius,dDR,pt->m_dMaxRight))){ /* we did the left and now we finished the right, go down */ pt = pt->m_pRightBranch; #ifdef CNEARTREE_INSTRUMENTED (treehandle->m_NodeVisits)++; #endif eDir = left; } else { eDir = end; } } if ( eDir == left ) { if ((pt->m_iflags)&CNEARTREE_FLAG_LEFT_DATA) { dDL = CNearTreeDist(treehandle, (void CNEARTREE_FAR *)coord, CVectorElementAt(coords,pt->m_indexLeft)); if (dDL >= dRadius ) { nopoints = 0; if (coordOutside) { xcoord = CVectorElementAt(coords,pt->m_indexLeft); CVectorAddElement(coordOutside,&xcoord); } if (objOutside) { xobj = CVectorElementAt(objs,pt->m_indexLeft); CVectorAddElement(objOutside,&xobj); } } } if (pt->m_iflags&CNEARTREE_FLAG_RIGHT_DATA) { CVectorAddElement(sStack,&pt); } if ((pt->m_iflags&CNEARTREE_FLAG_LEFT_CHILD)&& (TRIANG(dRadius,dDL,pt->m_dMaxLeft))){ pt = pt->m_pLeftBranch; #ifdef CNEARTREE_INSTRUMENTED (treehandle->m_NodeVisits)++; #endif } else { eDir = end; } } if ( eDir == end && CVectorSize(sStack) != 0 ) { CVectorGetElement(sStack,&pt,CVectorSize(sStack)-1); CVectorRemoveElement(sStack,CVectorSize(sStack)-1); eDir = right; } } CVectorFree(&sStack); return nopoints?CNEARTREE_NOT_FOUND:CNEARTREE_SUCCESS; } /* ======================================================================= int CNearTreeFindTreeOutSphere ( const CNearTreeHandle treehandle, const double dRadius, CNearTreeHandle foundOutside, const void CNEARTREE_FAR * coord, int resetcount) Function to search a Neartree for the set of objects further from some probe point, coord, than dRadius. dRadius is the maximum search radius - any point closer than dRadius from the probe point will be ignored foundOutside is an existing CNearTree to which the found points will be added coord is the probe point resetcount should be non-zero to clear found closest on entry return value is 0 if points were found ======================================================================= */ int CNearTreeFindTreeOutSphere ( const CNearTreeHandle treehandle, const double dRadius, CNearTreeHandle foundOutside, const void CNEARTREE_FAR * coord, int resetcount){ CVectorHandle objs; CVectorHandle coords; size_t ii; int errorcode; if ( !treehandle || !coord || !foundOutside ) return CNEARTREE_BAD_ARGUMENT; if ( treehandle->m_DelayedIndices ) { if (CNearTreeCompleteDelayedInsert(treehandle)!=CNEARTREE_SUCCESS) return CNEARTREE_BAD_ARGUMENT; } /* clear the contents of the return tree so that things don't accidentally accumulate */ if (resetcount) { CNearTreeClear( foundOutside ); } if (CVectorCreate(&objs,sizeof(void *),10)) { return CNEARTREE_MALLOC_FAILED; } if (CVectorCreate(&coords,sizeof(void *),10)) { return CNEARTREE_MALLOC_FAILED; } CNearTreeFindOutSphere(treehandle, dRadius, coords, objs, coord, 0); for (ii=0; ii dRadiusOuter) return CNEARTREE_BAD_ARGUMENT; if ( !treehandle || !coord ) return CNEARTREE_BAD_ARGUMENT; if ( treehandle->m_DelayedIndices ) { if (CNearTreeCompleteDelayedInsert(treehandle)!=CNEARTREE_SUCCESS) return CNEARTREE_BAD_ARGUMENT; } drat = sqrt((double)(treehandle->m_szdimension)); pt = treehandle->m_ptTree; coords=treehandle->m_CoordStore; objs=treehandle->m_ObjectStore; if (!pt) return CNEARTREE_BAD_ARGUMENT; if (!(pt->m_iflags&CNEARTREE_FLAG_LEFT_DATA)) return CNEARTREE_NOT_FOUND; #ifdef CNEARTREE_INSTRUMENTED (treehandle->m_NodeVisits)++; #endif CVectorCreate(&sStack,sizeof(CNearTreeNodeHandle),10); /* clear the contents of the return vector so that things don't accidentally accumulate */ if (resetcount) { if (coordInRing) CVectorClear( coordInRing ); if (objInRing) CVectorClear( objInRing ); } while (!(eDir == end && CVectorSize(sStack) == 0)) { if ( eDir == right ) { dDR = DBL_MAX; if ((pt->m_iflags)&CNEARTREE_FLAG_RIGHT_DATA) { CNTM_DistL1(dDR,treehandle, (void CNEARTREE_FAR *)coord, CVectorElementAt(coords,pt->m_indexRight)); if (dDR <= dRadiusOuter && dDR >= dRadiusInner*drat ) { nopoints = 0; if (coordInRing) { xcoord = CVectorElementAt(coords,pt->m_indexRight); CVectorAddElement(coordInRing,&xcoord); } if (objInRing) { xobj = CVectorElementAt(objs,pt->m_indexRight); CVectorAddElement(objInRing,&xobj); } } else if (dDR <= dRadiusOuter*drat && dDR >= dRadiusInner ) { CNTM_DistL2(dist,treehandle, (void CNEARTREE_FAR *)coord, CVectorElementAt(coords,pt->m_indexRight)); if (dist <= dRadiusOuter && dist >= dRadiusInner ) { nopoints = 0; if (coordInRing) { xcoord = CVectorElementAt(coords,pt->m_indexRight); CVectorAddElement(coordInRing,&xcoord); } if (objInRing) { xobj = CVectorElementAt(objs,pt->m_indexRight); CVectorAddElement(objInRing,&xobj); } } } } if ((pt->m_iflags&CNEARTREE_FLAG_RIGHT_CHILD)&& (TRIANG(dDR,pt->m_dMaxRight,dRadiusOuter))&& (TRIANG(dRadiusInner,dDR,pt->m_dMaxRight))){ /* we did the left and now we finished the right, go down */ pt = pt->m_pRightBranch; #ifdef CNEARTREE_INSTRUMENTED (treehandle->m_NodeVisits)++; #endif eDir = left; } else { eDir = end; } } if ( eDir == left ) { if ((pt->m_iflags)&CNEARTREE_FLAG_LEFT_DATA) { dDL = CNearTreeDist(treehandle, (void CNEARTREE_FAR *)coord, CVectorElementAt(coords,pt->m_indexLeft)); if (dDL <= dRadiusOuter && dDL >= dRadiusInner*drat) { nopoints = 0; if (coordInRing) { xcoord = CVectorElementAt(coords,pt->m_indexLeft); CVectorAddElement(coordInRing,&xcoord); } if (objInRing) { xobj = CVectorElementAt(objs,pt->m_indexLeft); CVectorAddElement(objInRing,&xobj); } } else if (dDL <= dRadiusOuter*drat && dDL >= dRadiusInner ) { CNTM_DistL2(dist,treehandle, (void CNEARTREE_FAR *)coord, CVectorElementAt(coords,pt->m_indexLeft)); if (dist <= dRadiusOuter && dist >= dRadiusInner ) { nopoints = 0; if (coordInRing) { xcoord = CVectorElementAt(coords,pt->m_indexLeft); CVectorAddElement(coordInRing,&xcoord); } if (objInRing) { xobj = CVectorElementAt(objs,pt->m_indexLeft); CVectorAddElement(objInRing,&xobj); } } } } if (pt->m_iflags&CNEARTREE_FLAG_RIGHT_DATA) { CVectorAddElement(sStack,&pt); } if ((pt->m_iflags&CNEARTREE_FLAG_LEFT_CHILD)&& (TRIANG(dDL,pt->m_dMaxLeft,dRadiusOuter))&& (TRIANG(dRadiusInner,dDL,pt->m_dMaxRight))){ pt = pt->m_pLeftBranch; #ifdef CNEARTREE_INSTRUMENTED (treehandle->m_NodeVisits)++; #endif } else { eDir = end; } } if ( eDir == end && CVectorSize(sStack) != 0 ) { CVectorGetElement(sStack,&pt,CVectorSize(sStack)-1); CVectorRemoveElement(sStack,CVectorSize(sStack)-1); eDir = right; } } CVectorFree(&sStack); return nopoints?CNEARTREE_NOT_FOUND:CNEARTREE_SUCCESS; } int CNearTreeFindInAnnulus ( const CNearTreeHandle treehandle, const double dRadiusInner, const double dRadiusOuter, CVectorHandle coordInRing, CVectorHandle objInRing, const void CNEARTREE_FAR * coord, int resetcount) { double dDR, dDL; int nopoints; CVectorHandle sStack; CVectorHandle coords; CVectorHandle objs; void CNEARTREE_FAR * xcoord; void CNEARTREE_FAR * xobj; CNearTreeNodeHandle pt; enum { left, right, end } eDir; eDir = left; /* examine the left nodes first */ nopoints = 1; dDR = dDL = DBL_MAX; if (dRadiusInner < 0. || dRadiusOuter < 0. || dRadiusInner > dRadiusOuter) return CNEARTREE_BAD_ARGUMENT; if ( !treehandle || !coord ) return CNEARTREE_BAD_ARGUMENT; if ((treehandle->m_iflags & CNEARTREE_NORM_L2LAZY)) return CNearTreeFindInAnnulusL2LAZY(treehandle,dRadiusInner,dRadiusOuter,coordInRing,objInRing,coord,resetcount); if ( treehandle->m_DelayedIndices ) { if (CNearTreeCompleteDelayedInsert(treehandle)!=CNEARTREE_SUCCESS) return CNEARTREE_BAD_ARGUMENT; } pt = treehandle->m_ptTree; coords=treehandle->m_CoordStore; objs=treehandle->m_ObjectStore; if (!pt) return CNEARTREE_BAD_ARGUMENT; if (!(pt->m_iflags&CNEARTREE_FLAG_LEFT_DATA)) return CNEARTREE_NOT_FOUND; #ifdef CNEARTREE_INSTRUMENTED (treehandle->m_NodeVisits)++; #endif CVectorCreate(&sStack,sizeof(CNearTreeNodeHandle),10); /* clear the contents of the return vector so that things don't accidentally accumulate */ if (resetcount) { if (coordInRing) CVectorClear( coordInRing ); if (objInRing) CVectorClear( objInRing ); } while (!(eDir == end && CVectorSize(sStack) == 0)) { if ( eDir == right ) { dDR = DBL_MAX; if ((pt->m_iflags)&CNEARTREE_FLAG_RIGHT_DATA) { dDR = CNearTreeDist(treehandle, (void CNEARTREE_FAR *)coord, CVectorElementAt(coords,pt->m_indexRight)); if (dDR <= dRadiusOuter && dDR >= dRadiusInner ) { nopoints = 0; if (coordInRing) { xcoord = CVectorElementAt(coords,pt->m_indexRight); CVectorAddElement(coordInRing,&xcoord); } if (objInRing) { xobj = CVectorElementAt(objs,pt->m_indexRight); CVectorAddElement(objInRing,&xobj); } } } if ((pt->m_iflags&CNEARTREE_FLAG_RIGHT_CHILD)&& (TRIANG(dDR,pt->m_dMaxRight,dRadiusOuter))&& (TRIANG(dRadiusInner,dDR,pt->m_dMaxRight))){ /* we did the left and now we finished the right, go down */ pt = pt->m_pRightBranch; #ifdef CNEARTREE_INSTRUMENTED (treehandle->m_NodeVisits)++; #endif eDir = left; } else { eDir = end; } } if ( eDir == left ) { if ((pt->m_iflags)&CNEARTREE_FLAG_LEFT_DATA) { dDL = CNearTreeDist(treehandle, (void CNEARTREE_FAR *)coord, CVectorElementAt(coords,pt->m_indexLeft)); if (dDL <= dRadiusOuter && dDL >= dRadiusInner) { nopoints = 0; if (coordInRing) { xcoord = CVectorElementAt(coords,pt->m_indexLeft); CVectorAddElement(coordInRing,&xcoord); } if (objInRing) { xobj = CVectorElementAt(objs,pt->m_indexLeft); CVectorAddElement(objInRing,&xobj); } } } if (pt->m_iflags&CNEARTREE_FLAG_RIGHT_DATA) { CVectorAddElement(sStack,&pt); } if ((pt->m_iflags&CNEARTREE_FLAG_LEFT_CHILD)&& (TRIANG(dDL,pt->m_dMaxLeft,dRadiusOuter))&& (TRIANG(dRadiusInner,dDL,pt->m_dMaxRight))){ pt = pt->m_pLeftBranch; #ifdef CNEARTREE_INSTRUMENTED (treehandle->m_NodeVisits)++; #endif } else { eDir = end; } } if ( eDir == end && CVectorSize(sStack) != 0 ) { CVectorGetElement(sStack,&pt,CVectorSize(sStack)-1); CVectorRemoveElement(sStack,CVectorSize(sStack)-1); eDir = right; } } CVectorFree(&sStack); return nopoints?CNEARTREE_NOT_FOUND:CNEARTREE_SUCCESS; } /* ======================================================================= int CNearTreeFindTreeInAnnulus ( const CNearTreeHandle treehandle, const double dRadiusInner, const double dRadiusOuter, CNearTreeHandle foundInRing, const void CNEARTREE_FAR * coord, int resetcount) Function to search a Neartree for the set of objects closer to some probe point, coord, than dRadiusOuter and further than dRadiusInner. dRadiusInner is the minimum search radius - any point closer than dRadius from the probe point will be ignored dRadiusOuter is the maximum search radius - any point further than dRadius from the probe point will be ignored foundInRing is an existing CNearTree to which the found points will be added coord is the probe point resetcount should be non-zero to clear found InRing on entry return value is 0 if points were found ======================================================================= */ int CNearTreeFindTreeInAnnulus ( const CNearTreeHandle treehandle, const double dRadiusInner, const double dRadiusOuter, CNearTreeHandle foundInRing, const void CNEARTREE_FAR * coord, int resetcount) { CVectorHandle objs; CVectorHandle coords; size_t ii; int errorcode; if ( !treehandle || !coord || !foundInRing ) return CNEARTREE_BAD_ARGUMENT; if ( treehandle->m_DelayedIndices ) { if (CNearTreeCompleteDelayedInsert(treehandle)!=CNEARTREE_SUCCESS) return CNEARTREE_BAD_ARGUMENT; } /* clear the contents of the return tree so that things don't accidentally accumulate */ if (resetcount) { CNearTreeClear( foundInRing ); } if (CVectorCreate(&objs,sizeof(void *),10)) { return CNEARTREE_MALLOC_FAILED; } if (CVectorCreate(&coords,sizeof(void *),10)) { return CNEARTREE_MALLOC_FAILED; } CNearTreeFindInAnnulus(treehandle, dRadiusInner, dRadiusOuter, coords, objs, coord, 0); for (ii=0; ii low; mid--) { ((double *)localmetrics)[mid] = ((double *)localmetrics)[mid-1]; ((size_t *)localindices)[mid] = ((size_t *)localindices)[mid-1]; } ((double *)localmetrics)[low] = localmetric; ((size_t *)localindices)[low] = localindex; CVectorSetFlags(metrics,0); CVectorSetFlags(indices,0); if (k==0 || CVectorSize(metrics) < k) { CVectorAddElement(metrics,&tempmetric); CVectorAddElement(indices,&tempindex); } } else if (localmetric >= ((double *)localmetrics)[high]) { CVectorSetFlags(metrics,0); CVectorSetFlags(indices,0); if (k==0 || CVectorSize(metrics) < k) { CVectorAddElement(metrics,&localmetric); CVectorAddElement(indices,&localindex); } } else { /* ((double *)localmetrics)[low] < localmetric < ((double *)localmetrics)[high]*/ while (low < high-1) { mid = (low+high)/2; if (localmetric == ((double *)localmetrics)[mid]) { low = mid; break; } if (localmetric < ((double *)localmetrics)[mid]) { high = mid; } else { low = mid; } } /* Insert the new item just above low */ if (low < high) { tempmetric = ((double *)localmetrics)[high]; tempindex = ((size_t *)localindices)[high]; for (mid = high; mid > low+1; mid--) { ((double *)localmetrics)[mid] = ((double *)localmetrics)[mid-1]; ((size_t *)localindices)[mid] = ((size_t *)localindices)[mid-1]; } ((double *)localmetrics)[low+1] = localmetric; ((size_t *)localindices)[low+1] = localindex; } else { tempmetric = localmetric; tempindex = localindex; } CVectorSetFlags(metrics,0); CVectorSetFlags(indices,0); if (k==0 || CVectorSize(metrics) < k) { CVectorAddElement(metrics,&tempmetric); CVectorAddElement(indices,&tempindex); } } return CNEARTREE_SUCCESS; } /* ======================================================================= int CNearTreeFindKNearest ( const CNearTreeHandle treehandle, const size_t k, const double dRadius, CVectorHandle coordClosest, CVectorHandle objClosest, const void * coord, int resetcount); Function to search a Neartree for the set of objects closer to some probe point, coord, than dRadius. k is the maximum number of closest neighbors to return. Finds this many if passible. dRadius is the maximum search radius - any point further than dRadius from the probe point will be ignored coordClosest is a vector of pointers to coordinate tuples and is the returned set of farthest points from the probe point that can be found in the Neartree objClosest is a vector of objects and is the returned set of farthest points from the probe point that can be found in the Neartree coord is the probe point resetcount should be non-zero to clear objClosest on entry return value is 0 if points were found ======================================================================= */ int CNearTreeFindKNearest (const CNearTreeHandle treehandle, const size_t k, const double dRadius, CVectorHandle coordClosest, CVectorHandle objClosest, const void * coord, int resetcount){ double dDR, dDL, dTarget, dist, drat; int nopoints, l2lazy; CVectorHandle sStack; CVectorHandle coords; CVectorHandle objs; CVectorHandle dDs; CVectorHandle stIndices; void CNEARTREE_FAR * xcoord; void CNEARTREE_FAR * xobj; CNearTreeNodeHandle pt; size_t ii, index; enum { left, right, end } eDir; eDir = left; /* examine the left nodes first */ nopoints = 1; dDR = dDL = DBL_MAX; dTarget = dRadius; drat = 1.; l2lazy = 0; if ((treehandle->m_iflags&CNEARTREE_NORM_L2LAZY)) { drat = sqrt((double)(treehandle->m_szdimension)); l2lazy = 1; } if (dRadius < 0.) return CNEARTREE_BAD_ARGUMENT; if ( !treehandle || !coord ) return CNEARTREE_BAD_ARGUMENT; if ( treehandle->m_DelayedIndices ) { if (CNearTreeCompleteDelayedInsert(treehandle)!=CNEARTREE_SUCCESS) return CNEARTREE_BAD_ARGUMENT; } pt = treehandle->m_ptTree; coords=treehandle->m_CoordStore; objs=treehandle->m_ObjectStore; if (!pt) return CNEARTREE_BAD_ARGUMENT; if (!(pt->m_iflags&CNEARTREE_FLAG_LEFT_DATA)) return CNEARTREE_NOT_FOUND; #ifdef CNEARTREE_INSTRUMENTED (treehandle->m_NodeVisits)++; #endif if (CVectorCreate(&sStack,sizeof(CNearTreeNodeHandle),10) || CVectorCreate(&dDs,sizeof(double),k) || CVectorCreate(&stIndices,sizeof(size_t),k)) return CNEARTREE_MALLOC_FAILED; /* clear the contents of the return vector so that things don't accidentally accumulate */ if (resetcount) { if (coordClosest) CVectorClear( coordClosest ); if (objClosest) CVectorClear( objClosest ); } while (!(eDir == end && CVectorSize(sStack) == 0)) { if ( eDir == right ) { dDR = DBL_MAX; if ((pt->m_iflags)&CNEARTREE_FLAG_RIGHT_DATA) { dist = dDR = CNearTreeDist(treehandle, (void CNEARTREE_FAR *)coord, CVectorElementAt(coords,pt->m_indexRight)); if (dDR <= dTarget*drat ) { if (l2lazy) { CNTM_DistL2(dist,treehandle, (void CNEARTREE_FAR *)coord, CVectorElementAt(coords,pt->m_indexRight)); } if (!l2lazy || dist <= dTarget) { nopoints = 0; CNearTreeSortIn(dDs,stIndices,dist,pt->m_indexRight,k); if (CVectorSize(dDs)==k) { CVectorGetElement(dDs,&dTarget,k-1); } } } } if ((pt->m_iflags&CNEARTREE_FLAG_RIGHT_CHILD)&& (TRIANG(dDR,pt->m_dMaxRight,dTarget))){ /* we did the left and now we finished the right, go down */ pt = pt->m_pRightBranch; #ifdef CNEARTREE_INSTRUMENTED (treehandle->m_NodeVisits)++; #endif eDir = left; } else { eDir = end; } } if ( eDir == left ) { if ((pt->m_iflags)&CNEARTREE_FLAG_LEFT_DATA) { dist = dDL = CNearTreeDist(treehandle, (void CNEARTREE_FAR *)coord, CVectorElementAt(coords,pt->m_indexLeft)); if (dDL <= dTarget*drat ) { if (l2lazy) { CNTM_DistL2(dist,treehandle, (void CNEARTREE_FAR *)coord, CVectorElementAt(coords,pt->m_indexLeft)); } if (!l2lazy || dist <= dTarget) { nopoints = 0; CNearTreeSortIn(dDs,stIndices,dist,pt->m_indexLeft,k); if (CVectorSize(dDs)==k) { CVectorGetElement(dDs,&dTarget,k-1); } } } } if (pt->m_iflags&CNEARTREE_FLAG_RIGHT_DATA) { CVectorAddElement(sStack,&pt); } if ((pt->m_iflags&CNEARTREE_FLAG_LEFT_CHILD)&& (TRIANG(dDL,pt->m_dMaxLeft,dTarget))){ pt = pt->m_pLeftBranch; #ifdef CNEARTREE_INSTRUMENTED (treehandle->m_NodeVisits)++; #endif } else { eDir = end; } } if ( eDir == end && CVectorSize(sStack) != 0 ) { CVectorGetElement(sStack,&pt,CVectorSize(sStack)-1); CVectorRemoveElement(sStack,CVectorSize(sStack)-1); eDir = right; } } CVectorFree(&sStack); if (!nopoints) { for (ii = 0; ii < CVectorSize(stIndices); ii++) { CVectorGetElement(stIndices,&index,ii); if (coordClosest) { xcoord = CVectorElementAt(coords,index); CVectorAddElement(coordClosest,&xcoord); } if (objClosest) { xobj = CVectorElementAt(objs,index); CVectorAddElement(objClosest,&xobj); } } } CVectorFree(&dDs); CVectorFree(&stIndices); return nopoints?CNEARTREE_NOT_FOUND:CNEARTREE_SUCCESS; } /* ======================================================================= int CNearTreeFindKTreeNearest ( const CNearTreeHandle treehandle, const size_t k, const double dRadius, CNearTreeHandle foundNearest, const void CNEARTREE_FAR * coord, int resetcount); Function to search a Neartree for the set of k objects closer to some probe point, coord, than dRadius. k is the maximum number of closest neighbors to return. Finds this many if passible. dRadius is the minimum search radius - any point closer than dRadius to the probe point will be ignored foundClosest is an existing CNearTree to which the found points will be added coord is the probe point resetcount should be non-zero to clear foundClosest on entry return value is 0 if points were found ======================================================================= */ int CNearTreeFindKTreeNearest (const CNearTreeHandle treehandle, const size_t k, const double dRadius, CNearTreeHandle foundClosest, const void CNEARTREE_FAR * coord, int resetcount){ CVectorHandle objs; CVectorHandle coords; size_t ii; int errorcode; if ( !treehandle || !coord || !foundClosest ) return CNEARTREE_BAD_ARGUMENT; if ( treehandle->m_DelayedIndices ) { if (CNearTreeCompleteDelayedInsert(treehandle)!=CNEARTREE_SUCCESS) return CNEARTREE_BAD_ARGUMENT; } /* clear the contents of the return tree so that things don't accidentally accumulate */ if (resetcount) { CNearTreeClear( foundClosest ); } if (CVectorCreate(&objs,sizeof(void *),10)) { return CNEARTREE_MALLOC_FAILED; } if (CVectorCreate(&coords,sizeof(void *),10)) { return CNEARTREE_MALLOC_FAILED; } CNearTreeFindKNearest(treehandle, k, dRadius, coords, objs, coord, 0); for (ii=0; iim_iflags&CNEARTREE_NORM_L2LAZY)) { drat = sqrt((double)(treehandle->m_szdimension)); l2lazy = 1; } if (dRadius < 0.) return 1; if ( !treehandle || !coord ) return CNEARTREE_BAD_ARGUMENT; if ( treehandle->m_DelayedIndices ) { if (CNearTreeCompleteDelayedInsert(treehandle)!=CNEARTREE_SUCCESS) return CNEARTREE_BAD_ARGUMENT; } pt = treehandle->m_ptTree; coords=treehandle->m_CoordStore; objs=treehandle->m_ObjectStore; if (!pt) return CNEARTREE_BAD_ARGUMENT; if (!(pt->m_iflags&CNEARTREE_FLAG_LEFT_DATA)) return CNEARTREE_NOT_FOUND; #ifdef CNEARTREE_INSTRUMENTED (treehandle->m_NodeVisits)++; #endif if (CVectorCreate(&sStack,sizeof(CNearTreeNodeHandle),10) || CVectorCreate(&dDs,sizeof(double),k) || CVectorCreate(&stIndices,sizeof(size_t),k)) return CNEARTREE_MALLOC_FAILED; /* clear the contents of the return vector so that things don't accidentally accumulate */ if (resetcount) { if (coordFarthest) CVectorClear( coordFarthest ); if (objFarthest) CVectorClear( objFarthest ); } while (!(eDir == end && CVectorSize(sStack) == 0)) { if ( eDir == right ) { dDR = DBL_MAX; if ((pt->m_iflags)&CNEARTREE_FLAG_RIGHT_DATA) { dist = dDR = CNearTreeDist(treehandle, (void CNEARTREE_FAR *)coord, CVectorElementAt(coords,pt->m_indexRight)); if (dDR >= dTarget/drat ) { if (l2lazy) { CNTM_DistL2(dist,treehandle, (void CNEARTREE_FAR *)coord, CVectorElementAt(coords,pt->m_indexRight)); } if (!l2lazy || dist >= dTarget ) { nopoints = 0; CNearTreeSortIn(dDs,stIndices,-dist,pt->m_indexRight,k); if (CVectorSize(dDs)==k) { CVectorGetElement(dDs,&dTarget,k-1); dTarget = -dTarget; } } } } if ((pt->m_iflags&CNEARTREE_FLAG_RIGHT_CHILD)&& (TRIANG(dTarget,dDR,pt->m_dMaxRight))){ /* we did the left and now we finished the right, go down */ pt = pt->m_pRightBranch; #ifdef CNEARTREE_INSTRUMENTED (treehandle->m_NodeVisits)++; #endif eDir = left; } else { eDir = end; } } if ( eDir == left ) { if ((pt->m_iflags)&CNEARTREE_FLAG_LEFT_DATA) { dist = dDL = CNearTreeDist(treehandle, (void CNEARTREE_FAR *)coord, CVectorElementAt(coords,pt->m_indexLeft)); if (dDL >= dTarget/drat ) { if (l2lazy) { CNTM_DistL2(dist,treehandle, (void CNEARTREE_FAR *)coord, CVectorElementAt(coords,pt->m_indexLeft)); } if (!l2lazy || dist >= dTarget ) { nopoints = 0; CNearTreeSortIn(dDs,stIndices,-dist,pt->m_indexLeft,k); if (CVectorSize(dDs)==k) { CVectorGetElement(dDs,&dTarget,k-1); dTarget = -dTarget; } } } } if (pt->m_iflags&CNEARTREE_FLAG_RIGHT_DATA) { CVectorAddElement(sStack,&pt); } if ((pt->m_iflags&CNEARTREE_FLAG_LEFT_CHILD)&& (TRIANG(dTarget,dDL,pt->m_dMaxLeft))){ pt = pt->m_pLeftBranch; #ifdef CNEARTREE_INSTRUMENTED (treehandle->m_NodeVisits)++; #endif } else { eDir = end; } } if ( eDir == end && CVectorSize(sStack) != 0 ) { CVectorGetElement(sStack,&pt,CVectorSize(sStack)-1); CVectorRemoveElement(sStack,CVectorSize(sStack)-1); eDir = right; } } CVectorFree(&sStack); if (!nopoints) { for (ii = 0; ii < CVectorSize(stIndices); ii++) { CVectorGetElement(stIndices,&index,ii); if (coordFarthest) { xcoord = CVectorElementAt(coords,index); CVectorAddElement(coordFarthest,&xcoord); } if (objFarthest) { xobj = CVectorElementAt(objs,index); CVectorAddElement(objFarthest,&xobj); } } } CVectorFree(&dDs); CVectorFree(&stIndices); return nopoints?CNEARTREE_NOT_FOUND:CNEARTREE_SUCCESS; } /* ======================================================================= int CNearTreeFindKTreeFarthest ( const CNearTreeHandle treehandle, const size_t k, const double dRadius, CNearTreeHandle foundFarthest, const void CNEARTREE_FAR * coord, int resetcount); Function to search a Neartree for the set of k objects farther from some probe point, coord, than dRadius. k is the maximum number of farthest neighbors to return. Finds this many if passible. dRadius is the minimum search radius - any point farther than dRadius from the probe point will be ignored foundFarthest is an existing CNearTree to which the found points will be added coord is the probe point resetcount should be non-zero to clear foundFarthest on entry return value is 0 if points were found ======================================================================= */ int CNearTreeFindKTreeFarthest ( const CNearTreeHandle treehandle, const size_t k, const double dRadius, CNearTreeHandle foundFarthest, const void CNEARTREE_FAR * coord, int resetcount) { CVectorHandle objs; CVectorHandle coords; size_t ii; int errorcode; if ( !treehandle || !coord || !foundFarthest ) return CNEARTREE_BAD_ARGUMENT; if ( treehandle->m_DelayedIndices ) { if (CNearTreeCompleteDelayedInsert(treehandle)!=CNEARTREE_SUCCESS) return CNEARTREE_BAD_ARGUMENT; } /* clear the contents of the return tree so that things don't accidentally accumulate */ if (resetcount) { CNearTreeClear( foundFarthest ); } if (CVectorCreate(&objs,sizeof(void *),10)) { return CNEARTREE_MALLOC_FAILED; } if (CVectorCreate(&coords,sizeof(void *),10)) { return CNEARTREE_MALLOC_FAILED; } CNearTreeFindKFarthest(treehandle, k, dRadius, coords, objs, coord, 0); for (ii=0; iim_szdimension)); if ( !treehandle || !coord ) return CNEARTREE_BAD_ARGUMENT; if ( treehandle->m_DelayedIndices ) { if (CNearTreeCompleteDelayedInsert(treehandle)!=CNEARTREE_SUCCESS) return CNEARTREE_BAD_ARGUMENT; } pt = treehandle->m_ptTree; if (!pt) return CNEARTREE_BAD_ARGUMENT; if (!(pt->m_iflags&CNEARTREE_FLAG_LEFT_DATA)) return CNEARTREE_NOT_FOUND; coords=treehandle->m_CoordStore; objs=treehandle->m_ObjectStore; CVectorCreate(&sStack,sizeof(CNearTreeNodeHandle),10); #ifdef CNEARTREE_INSTRUMENTED (treehandle->m_NodeVisits)++; #endif if (!(pt->m_iflags&(CNEARTREE_FLAG_LEFT_DATA|CNEARTREE_FLAG_RIGHT_DATA))) { CVectorFree(&sStack); return CNEARTREE_NOT_FOUND; } while ((pt->m_iflags&(CNEARTREE_FLAG_LEFT_DATA|CNEARTREE_FLAG_RIGHT_DATA)) || CVectorSize(sStack) != 0) { if (!(pt->m_iflags&(CNEARTREE_FLAG_LEFT_DATA|CNEARTREE_FLAG_RIGHT_DATA))) { if (CVectorSize(sStack) !=0 ) { CVectorGetElement(sStack,&pt,CVectorSize(sStack)-1); CVectorRemoveElement(sStack,CVectorSize(sStack)-1); #ifdef CNEARTREE_INSTRUMENTED (treehandle->m_NodeVisits)++; #endif continue; } break; } if ((pt->m_iflags&(CNEARTREE_FLAG_LEFT_DATA))) { CNTM_DistL1(dDL,treehandle, (void CNEARTREE_FAR *)coord, CVectorElementAt(coords,pt->m_indexLeft)); dDLC = dDL; if (dDL <= *dRadius) { *dRadius = dDL; pobjClosest = CVectorElementAt(objs,pt->m_indexLeft); pcoordClosest = CVectorElementAt(coords,pt->m_indexLeft); } else if (dDL <= (*dRadius)*drat) { CNTM_DistL2sq(dDLCsq,treehandle, (void CNEARTREE_FAR *)coord, CVectorElementAt(coords,pt->m_indexLeft)); if (dDLCsq <= (*dRadius)*(*dRadius)) { *dRadius = dDLC = sqrt(dDLCsq); pobjClosest = CVectorElementAt(objs,pt->m_indexLeft); pcoordClosest = CVectorElementAt(coords,pt->m_indexLeft); } } } if ((pt->m_iflags&(CNEARTREE_FLAG_RIGHT_DATA))) { #ifdef CNEARTREE_INSTRUMENTED (treehandle->m_NodeVisits)++; #endif CNTM_DistL1(dDR,treehandle, (void CNEARTREE_FAR *)coord, CVectorElementAt(coords,pt->m_indexLeft)); dDRC = dDR; if (dDR <= *dRadius) { *dRadius = dDR; pobjClosest = CVectorElementAt(objs,pt->m_indexRight); pcoordClosest = CVectorElementAt(coords,pt->m_indexRight); } else if (dDR <= (*dRadius)*drat) { CNTM_DistL2sq(dDRCsq,treehandle, (void CNEARTREE_FAR *)coord, CVectorElementAt(coords,pt->m_indexRight)); if (dDRCsq <= (*dRadius)*(*dRadius)) { *dRadius = dDRC = sqrt(dDRCsq); pobjClosest = CVectorElementAt(objs,pt->m_indexRight); pcoordClosest = CVectorElementAt(coords,pt->m_indexRight); } } } /* See if both branches are populated. In that case, save one branch on the stack, and process the other one based on which one seems smaller, but useful first] */ if ((pt->m_iflags&CNEARTREE_FLAG_RIGHT_CHILD) && (pt->m_iflags&CNEARTREE_FLAG_LEFT_CHILD)){ if (dDLC+pt->m_dMaxLeft < dDRC+pt->m_dMaxRight ) { if ( TRIANG(dDLC,pt->m_dMaxLeft,*dRadius)) { if ( TRIANG(dDRC,pt->m_dMaxRight,*dRadius)) { CVectorAddElement(sStack,&(pt->m_pRightBranch)); } pt = pt->m_pLeftBranch; #ifdef CNEARTREE_INSTRUMENTED (treehandle->m_NodeVisits)++; #endif continue; } /* If we are here, the left branch was not useful Fall through to use the right */ } /* We come here either because pursuing the left branch was not useful or the right branch looks shorter */ if ( TRIANG(dDRC,pt->m_dMaxRight,*dRadius)) { if ( TRIANG(dDLC,pt->m_dMaxLeft,*dRadius)) { CVectorAddElement(sStack,&(pt->m_pLeftBranch)); } pt = pt->m_pRightBranch; #ifdef CNEARTREE_INSTRUMENTED (treehandle->m_NodeVisits)++; #endif continue; } } /* Only one branch is viable, try them one at a time */ if ( (pt->m_iflags&CNEARTREE_FLAG_LEFT_CHILD) && TRIANG(dDLC,pt->m_dMaxLeft,*dRadius)) { pt = pt->m_pLeftBranch; #ifdef CNEARTREE_INSTRUMENTED (treehandle->m_NodeVisits)++; #endif continue; } if ( (pt->m_iflags&CNEARTREE_FLAG_RIGHT_CHILD) && TRIANG(dDRC,pt->m_dMaxRight,*dRadius)) { pt = pt->m_pRightBranch; #ifdef CNEARTREE_INSTRUMENTED (treehandle->m_NodeVisits)++; #endif continue; } if ( CVectorSize(sStack) != 0 ) { CVectorGetElement(sStack,&pt,CVectorSize(sStack)-1); CVectorRemoveElement(sStack,CVectorSize(sStack)-1); #ifdef CNEARTREE_INSTRUMENTED (treehandle->m_NodeVisits)++; #endif continue; } break; } CVectorFree(&sStack); if (coordClosest) *coordClosest = pcoordClosest; if (objClosest) *objClosest = pobjClosest; return pcoordClosest?CNEARTREE_SUCCESS:CNEARTREE_NOT_FOUND; } /* NearestL2LAZY*/ int CNearTreeNearest ( const CNearTreeHandle treehandle, double CNEARTREE_FAR * dRadius, void CNEARTREE_FAR * CNEARTREE_FAR * coordClosest, void CNEARTREE_FAR * CNEARTREE_FAR * objClosest, const void CNEARTREE_FAR * coord ) { double dDR, dDL; CVectorHandle sStack; CVectorHandle coords; CVectorHandle objs; CNearTreeNodeHandle pt; void CNEARTREE_FAR * pobjClosest; void CNEARTREE_FAR * pcoordClosest; pobjClosest = NULL; pcoordClosest = NULL; if ((treehandle->m_iflags&CNEARTREE_NORM_L2LAZY)) return CNearTreeNearestL2LAZY(treehandle,dRadius,coordClosest,objClosest,coord); dDR = dDL = -1.; if ( !treehandle || !coord ) return CNEARTREE_BAD_ARGUMENT; if ( treehandle->m_DelayedIndices ) { if (CNearTreeCompleteDelayedInsert(treehandle)!=CNEARTREE_SUCCESS) return CNEARTREE_BAD_ARGUMENT; } pt = treehandle->m_ptTree; if (!pt) return CNEARTREE_BAD_ARGUMENT; if (!(pt->m_iflags&CNEARTREE_FLAG_LEFT_DATA)) return CNEARTREE_NOT_FOUND; coords=treehandle->m_CoordStore; objs=treehandle->m_ObjectStore; CVectorCreate(&sStack,sizeof(CNearTreeNodeHandle),10); #ifdef CNEARTREE_INSTRUMENTED (treehandle->m_NodeVisits)++; #endif if (!(pt->m_iflags&(CNEARTREE_FLAG_LEFT_DATA|CNEARTREE_FLAG_RIGHT_DATA))) { CVectorFree(&sStack); return CNEARTREE_NOT_FOUND; } while ((pt->m_iflags&(CNEARTREE_FLAG_LEFT_DATA|CNEARTREE_FLAG_RIGHT_DATA)) || CVectorSize(sStack) != 0) { if (!(pt->m_iflags&(CNEARTREE_FLAG_LEFT_DATA|CNEARTREE_FLAG_RIGHT_DATA))) { if (CVectorSize(sStack) !=0 ) { CVectorGetElement(sStack,&pt,CVectorSize(sStack)-1); CVectorRemoveElement(sStack,CVectorSize(sStack)-1); #ifdef CNEARTREE_INSTRUMENTED (treehandle->m_NodeVisits)++; #endif continue; } break; } if ((pt->m_iflags&(CNEARTREE_FLAG_LEFT_DATA))) { dDL = CNearTreeDist(treehandle, (void CNEARTREE_FAR *)coord, CVectorElementAt(coords,pt->m_indexLeft)); if (dDL <= *dRadius ) { *dRadius = dDL; pobjClosest = CVectorElementAt(objs,pt->m_indexLeft); pcoordClosest = CVectorElementAt(coords,pt->m_indexLeft); } } if ((pt->m_iflags&(CNEARTREE_FLAG_RIGHT_DATA))) { #ifdef CNEARTREE_INSTRUMENTED (treehandle->m_NodeVisits)++; #endif dDR = CNearTreeDist(treehandle, (void CNEARTREE_FAR *)coord, CVectorElementAt(coords,pt->m_indexRight)); if (dDR <= *dRadius ) { *dRadius = dDR; pobjClosest = CVectorElementAt(objs,pt->m_indexRight); pcoordClosest = CVectorElementAt(coords,pt->m_indexRight); } } /* See if both branches are populated. In that case, save one branch on the stack, and process the other one based on which one seems smaller, but useful first] */ if ((pt->m_iflags&CNEARTREE_FLAG_RIGHT_CHILD) && (pt->m_iflags&CNEARTREE_FLAG_LEFT_CHILD)){ if (dDL+pt->m_dMaxLeft < dDR+pt->m_dMaxRight ) { if ( TRIANG(dDL,pt->m_dMaxLeft,*dRadius)) { if ( TRIANG(dDR,pt->m_dMaxRight,*dRadius)) { CVectorAddElement(sStack,&(pt->m_pRightBranch)); } pt = pt->m_pLeftBranch; #ifdef CNEARTREE_INSTRUMENTED (treehandle->m_NodeVisits)++; #endif continue; } /* If we are here, the left branch was not useful Fall through to use the right */ } /* We come here either because pursuing the left branch was not useful of the right branch look shorter */ if ( TRIANG(dDR,pt->m_dMaxRight,*dRadius)) { if ( TRIANG(dDL,pt->m_dMaxLeft,*dRadius)) { CVectorAddElement(sStack,&(pt->m_pLeftBranch)); } pt = pt->m_pRightBranch; #ifdef CNEARTREE_INSTRUMENTED (treehandle->m_NodeVisits)++; #endif continue; } } /* Only one branch is viable, try them one at a time */ if ( (pt->m_iflags&CNEARTREE_FLAG_LEFT_CHILD) && TRIANG(dDL,pt->m_dMaxLeft,*dRadius)) { pt = pt->m_pLeftBranch; #ifdef CNEARTREE_INSTRUMENTED (treehandle->m_NodeVisits)++; #endif continue; } if ( (pt->m_iflags&CNEARTREE_FLAG_RIGHT_CHILD) && TRIANG(dDR,pt->m_dMaxRight,*dRadius)) { pt = pt->m_pRightBranch; #ifdef CNEARTREE_INSTRUMENTED (treehandle->m_NodeVisits)++; #endif continue; } if ( CVectorSize(sStack) != 0 ) { CVectorGetElement(sStack,&pt,CVectorSize(sStack)-1); CVectorRemoveElement(sStack,CVectorSize(sStack)-1); #ifdef CNEARTREE_INSTRUMENTED (treehandle->m_NodeVisits)++; #endif continue; } break; } CVectorFree(&sStack); if (coordClosest) *coordClosest = pcoordClosest; if (objClosest) *objClosest = pobjClosest; return pcoordClosest?CNEARTREE_SUCCESS:CNEARTREE_NOT_FOUND; } /* Nearest */ int CNearTreeLeftNearest ( const CNearTreeHandle treehandle, double CNEARTREE_FAR * dRadius, void CNEARTREE_FAR * CNEARTREE_FAR * coordClosest, void CNEARTREE_FAR * CNEARTREE_FAR * objClosest, const void CNEARTREE_FAR * coord ) { double dDR, dDL; CVectorHandle sStack; CVectorHandle coords; CVectorHandle objs; CNearTreeNodeHandle pt; void CNEARTREE_FAR * pobjClosest; void CNEARTREE_FAR * pcoordClosest; enum { left, right, end } eDir; eDir = left; /* examine the left nodes first */ pobjClosest = NULL; pcoordClosest = NULL; if ( !treehandle || !coord ) return CNEARTREE_BAD_ARGUMENT; if ( treehandle->m_DelayedIndices ) { if (CNearTreeCompleteDelayedInsert(treehandle)!=CNEARTREE_SUCCESS) return CNEARTREE_BAD_ARGUMENT; } pt = treehandle->m_ptTree; if (!pt) return CNEARTREE_BAD_ARGUMENT; if (!(pt->m_iflags&CNEARTREE_FLAG_LEFT_DATA)) return CNEARTREE_NOT_FOUND; coords=treehandle->m_CoordStore; objs=treehandle->m_ObjectStore; CVectorCreate(&sStack,sizeof(CNearTreeNodeHandle),10); #ifdef CNEARTREE_INSTRUMENTED (treehandle->m_NodeVisits)++; #endif while (!(eDir == end && CVectorSize(sStack) == 0)) { if ( eDir == right ) { dDR = CNearTreeDist(treehandle, (void CNEARTREE_FAR *)coord, CVectorElementAt(coords,pt->m_indexRight)); if (dDR <= *dRadius ) { *dRadius = dDR; pobjClosest = CVectorElementAt(objs,pt->m_indexRight); pcoordClosest = CVectorElementAt(coords,pt->m_indexRight); } if ((pt->m_iflags&CNEARTREE_FLAG_RIGHT_CHILD)&& (TRIANG(dDR,pt->m_dMaxRight,*dRadius))) { /* we did the left and now we finished the right, go down */ pt = pt->m_pRightBranch; #ifdef CNEARTREE_INSTRUMENTED (treehandle->m_NodeVisits)++; #endif eDir = left; } else { eDir = end; } } if ( eDir == left ) { dDL = CNearTreeDist(treehandle, (void CNEARTREE_FAR *)coord, CVectorElementAt(coords,pt->m_indexLeft)); if (dDL <= *dRadius ) { *dRadius = dDL; pobjClosest = CVectorElementAt(objs,pt->m_indexLeft); pcoordClosest = CVectorElementAt(coords,pt->m_indexLeft); } if (pt->m_iflags&CNEARTREE_FLAG_RIGHT_DATA) { CVectorAddElement(sStack,&pt); } if ((pt->m_iflags&CNEARTREE_FLAG_LEFT_CHILD)&& (TRIANG(dDL,pt->m_dMaxLeft,*dRadius))) { pt = pt->m_pLeftBranch; #ifdef CNEARTREE_INSTRUMENTED (treehandle->m_NodeVisits)++; #endif } else { eDir = end; } } if ( eDir == end && CVectorSize(sStack) != 0 ) { CVectorGetElement(sStack,&pt,CVectorSize(sStack)-1); CVectorRemoveElement(sStack,CVectorSize(sStack)-1); eDir = right; #ifdef CNEARTREE_INSTRUMENTED (treehandle->m_NodeVisits)++; #endif } } CVectorFree(&sStack); if (coordClosest) *coordClosest = pcoordClosest; if (objClosest) *objClosest = pobjClosest; return pcoordClosest?CNEARTREE_SUCCESS:CNEARTREE_NOT_FOUND; } /* LeftNearest */ /* ======================================================================= int CNearTreeFindFarthest ( const CNearTreeHandle treehandle, double CNEARTREE_FAR * dRadius, void CNEARTREE_FAR * CNEARTREE_FAR * coordFarthest, void CNEARTREE_FAR * CNEARTREE_FAR * objFarthest, const void CNEARTREE_FAR * coord ) Function to search a Neartree for the object farthest from some probe point, coord. This function is called by CNearTreeFarthestNeighbor. *dRadius is the largest currently known distance of an object from the probe point and is modified as the search progresses. coordFarthest is a pointer to the returned farthest point from the probe point that can be found in the Neartree objFarthest is a pointer to a pointer to hold the corresponding object or is NULL coord is the probe point the return value is 0 only if a point was found. ======================================================================= */ int CNearTreeFindFarthest ( const CNearTreeHandle treehandle, double CNEARTREE_FAR * dRadius, void CNEARTREE_FAR * CNEARTREE_FAR * coordFarthest, void CNEARTREE_FAR * CNEARTREE_FAR * objFarthest, const void CNEARTREE_FAR * coord ) { double dDR, dDL; CVectorHandle sStack; CVectorHandle coords; CVectorHandle objs; CNearTreeNodeHandle pt; void CNEARTREE_FAR * pobjFarthest; void CNEARTREE_FAR * pcoordFarthest; enum { left, right, end } eDir; eDir = left; /* examine the left nodes first */ pobjFarthest = NULL; pcoordFarthest = NULL; if ( !treehandle || !coord ) return CNEARTREE_BAD_ARGUMENT; if ( treehandle->m_DelayedIndices ) { if (CNearTreeCompleteDelayedInsert(treehandle)!=CNEARTREE_SUCCESS) return CNEARTREE_BAD_ARGUMENT; } pt = treehandle->m_ptTree; if (!pt) return CNEARTREE_BAD_ARGUMENT; if (!(pt->m_iflags&CNEARTREE_FLAG_LEFT_DATA)) return CNEARTREE_NOT_FOUND; #ifdef CNEARTREE_INSTRUMENTED (treehandle->m_NodeVisits)++; #endif coords=treehandle->m_CoordStore; objs=treehandle->m_ObjectStore; CVectorCreate(&sStack,sizeof(CNearTreeNodeHandle),10); while (!(eDir == end && CVectorSize(sStack) == 0)) { if ( eDir == right ) { dDR = CNearTreeDist(treehandle, (void CNEARTREE_FAR *)coord, CVectorElementAt(coords,pt->m_indexRight)); if (dDR >= *dRadius ) { *dRadius = dDR; pobjFarthest = CVectorElementAt(objs,pt->m_indexRight); pcoordFarthest = CVectorElementAt(coords,pt->m_indexRight); } if ((pt->m_iflags&CNEARTREE_FLAG_RIGHT_CHILD)&& (TRIANG(*dRadius,dDR,pt->m_dMaxRight))) { /* we did the left and now we finished the right, go down */ pt = pt->m_pRightBranch; #ifdef CNEARTREE_INSTRUMENTED (treehandle->m_NodeVisits)++; #endif eDir = left; } else { eDir = end; } } if ( eDir == left ) { dDL = CNearTreeDist(treehandle, (void CNEARTREE_FAR *)coord, CVectorElementAt(coords,pt->m_indexLeft)); if (dDL >= *dRadius ) { *dRadius = dDL; pobjFarthest = CVectorElementAt(objs,pt->m_indexLeft); pcoordFarthest = CVectorElementAt(coords,pt->m_indexLeft); } if (pt->m_iflags&CNEARTREE_FLAG_RIGHT_DATA) { CVectorAddElement(sStack,&pt); } if ((pt->m_iflags&CNEARTREE_FLAG_LEFT_CHILD)&& (TRIANG(*dRadius,dDL,pt->m_dMaxLeft))) { pt = pt->m_pLeftBranch; #ifdef CNEARTREE_INSTRUMENTED (treehandle->m_NodeVisits)++; #endif } else { eDir = end; } } if ( eDir == end && CVectorSize(sStack) != 0 ) { CVectorGetElement(sStack,&pt,CVectorSize(sStack)-1); CVectorRemoveElement(sStack,CVectorSize(sStack)-1); eDir = right; } } CVectorFree(&sStack); if (coordFarthest) *coordFarthest = pcoordFarthest; if (objFarthest) *objFarthest = pobjFarthest; return pcoordFarthest?CNEARTREE_SUCCESS:CNEARTREE_NOT_FOUND; } /* ======================================================================= int CNearTreeObjects ( const CNearTreeHandle treehandle, CVectorHandle CNEARTREE_FAR * vectorhandle) Function to return the vector of objects in the tree. This vector is not guaranteed to be in the same order as the order of insertion vectorhandle -- a pointer to a CVectorHandle ======================================================================= */ int CNearTreeObjects ( const CNearTreeHandle treehandle, CVectorHandle CNEARTREE_FAR * vectorhandle) { if ( !treehandle || !vectorhandle ) return CNEARTREE_BAD_ARGUMENT; *vectorhandle = treehandle->m_ObjectStore; return CNEARTREE_SUCCESS; } /* ======================================================================= int CNearTreeCoords ( const CNearTreeHandle treehandle, CVectorHandle CNEARTREE_FAR * vectorhandle) Function to return the vector of coordinates in the tree. This vector is not guaranteed to be in the same order as the order of insertion vectorhandle -- a pointer to a CVectorHandle ======================================================================= */ int CNearTreeCoords ( const CNearTreeHandle treehandle, CVectorHandle CNEARTREE_FAR * vectorhandle) { if ( !treehandle || !vectorhandle ) return CNEARTREE_BAD_ARGUMENT; *vectorhandle = treehandle->m_CoordStore; return CNEARTREE_SUCCESS; } #ifdef __cplusplus } #endif ./NearTree-3.1.1/CNearTree.h0000644002342100234170000017555711640401607015430 0ustar bernstehfaculty/* * CNearTree.h * NearTree * * Based on TNear.h C++ Template * Copyright 2001 Larry Andrews. All rights reserved * * C Version created by Herbert J. Bernstein on 11/29/08 * with permission from Larry Andrews. * Copyright 2008 Larry Andrews and Herbert J. Bernstein. * All rights reserved. * * Revised 30 May 2009, release with full containerization of C++ * version and KNear/Far in C++ and C, LCA + HJB */ /********************************************************************** * * * YOU MAY REDISTRIBUTE THE CNearTree API UNDER THE TERMS OF THE LGPL * * * **********************************************************************/ /************************* LGPL NOTICES ******************************* * * * This library is free software; you can redistribute it and/or * * modify it under the terms of the GNU Lesser General Public * * License as published by the Free Software Foundation; either * * version 2.1 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 * * Lesser General Public License for more details. * * * * You should have received a copy of the GNU Lesser General Public * * License along with this library; if not, write to the Free * * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, * * MA 02110-1301 USA * * * **********************************************************************/ /* Notices from original C++ template: Nearest Neighbor algorithm after Kalantari and McDonald, (IEEE Transactions on Software Engineering, v. SE-9, pp. 631-634,1983) modified to use recursion instead of a double-linked tree and simplified so that it does a bit less checking for things like is the distance to the right less than the distance to the left; it was found that these checks little to no difference. copyright by Larry Andrews, 2001 may be freely distributed or used as long as this copyright notice is included */ #ifndef CNEARTREE_H_INCLUDED #define CNEARTREE_H_INCLUDED #ifdef __cplusplus extern "C" { #endif #ifdef CNEARTREE_USE_FAR #include #define CNEARTREE_FAR __far #define CNEARTREE_MALLOC _fmalloc #define CNEARTREE_FREE _ffree #define CNEARTREE_MEMSET _fmemset #define CNEARTREE_MEMMOVE _fmemmove #else #include #define CNEARTREE_FAR #define CNEARTREE_MALLOC malloc #define CNEARTREE_FREE free #define CNEARTREE_MEMSET memset #define CNEARTREE_MEMMOVE memmove #endif #include #include #include #ifndef USE_LOCAL_HEADERS #include #else #include "CVector.h" #endif #ifndef CVECTOR_FAR #define CVECTOR_FAR CNEARTREE_FAR #endif #ifndef USE_LOCAL_HEADERS #include #else #include "rhrand.h" #endif /* function returns */ #define CNEARTREE_SUCCESS 0 #define CNEARTREE_MALLOC_FAILED 1 #define CNEARTREE_BAD_ARGUMENT 2 #define CNEARTREE_NOT_FOUND 4 #define CNEARTREE_FREE_FAILED 8 #define CNEARTREE_CVECTOR_FAILED 16 /* flags 0 for n data, n children */ #define CNEARTREE_FLAG_LEFT_DATA 1L /* 0x0001 */ #define CNEARTREE_FLAG_RIGHT_DATA 2L /* 0x0002 */ #define CNEARTREE_FLAG_LEFT_CHILD 4L /* 0x0004 */ #define CNEARTREE_FLAG_RIGHT_CHILD 8L /* 0x0008 */ #define CNEARTREE_DATA_OR_CHILDREN 15L /* 0x000F */ #define CNEARTREE_TYPE_DOUBLE 16L /* 0x0010 */ #define CNEARTREE_TYPE_INTEGER 32L /* 0x0020 */ #define CNEARTREE_TYPE_STRING 64L /* 0x0040 */ #define CNEARTREE_TYPE 112L /* 0x0070 */ #define CNEARTREE_NORM_UNKNOWN 128L /* 0x0080 */ #define CNEARTREE_NORM_L1 256L /* 0x0100 */ #define CNEARTREE_NORM_L2 512L /* 0x0200 */ #define CNEARTREE_NORM_LINF 1024L /* 0x0400 */ #define CNEARTREE_NORM_SPHERE 2048L /* 0x0800 */ #define CNEARTREE_NORM_HSPHERE 4096L /* 0x1000 */ #define CNEARTREE_NORM_HAMMING 8192L /* 0x2000 */ #define CNEARTREE_NORM_L2LAZY 16384L /* 0x4000 */ #define CNEARTREE_NORM 32640L /* 0x7F80 */ /* Execution Control Flags */ #define CNTF_NOPREPRUNE 0x10000L /*flag to supress all search prepruning */ #define CNTF_FORCEPREPRUNE 0x20000L /*flag to force search prepruning */ #define CNTF_NOFLIP 0x40000L /*flag to suppress flips on insert */ #define CNTF_FORCEFLIP 0x80000L /*flag to force flips on insert */ #define CNTF_NODEFER 0x100000L /*flag to prevent deferred insert */ #define CNEARTREE_XFLAGS 0x1F0000L /*mask for execution flags */ #ifdef CNEARTREE_FORCEPREPRUNE #define CNFT_FLAGDEFAULTPRUNE CNTF_FORCEPREPRUNE #ifdef CNEARTREE_NOPREPRUNE #error "CNEARTREE_NOPREPRUNE conflicts with CNEARTREE_FORCEPREPRUNE" #endif #else #ifdef CNEARTREE_NOPREPRUNE #define CNFT_FLAGDEFAULTPRUNE CNTF_NOPREPRUNE #else #define CNFT_FLAGDEFAULTPRUNE 0 #endif #endif #ifdef CNEARTREE_FORCEFLIP #define CNFT_FLAGDEFAULTFLIP CNTF_FORCEFLIP #ifdef CNEARTREE_NOFLIP #error "CNEARTREE_NOFLIP conflicts with CNEARTREE_FORCEFLIP" #endif #else #ifdef CNEARTREE_NOFLIP #define CNFT_FLAGDEFAULTFLIP CNTF_NOFLIP #else #define CNFT_FLAGDEFAULTFLIP 0 #endif #endif #ifdef CNEARTREE_NODEFER #define CNFT_FLAGDEFAULTDEFER CNTF_NODEFER #else #define CNFT_FLAGDEFAULTDEFER 0 #endif #define CNTF_FLAGSDEFAULT (CNFT_FLAGDEFAULTPRUNE|CNFT_FLAGDEFAULTFLIP|CNFT_FLAGDEFAULTDEFER) #define CNEARTREE_FLIP 0 /* Not used, defined for compatibility */ #define CNEARTREE_DEFER_ALL 0 /* Not used, defined for compatibility */ typedef struct _CNearTreeNode { size_t m_indexLeft; /* index of left coords in m_CoordStore and of left object in m_ObjectStore */ size_t m_indexRight; /* index of right coords in m_CoordStore and of right object in m_ObjectStore */ double m_dMaxLeft; /* longest distance from the left object to anything below it in the tree */ double m_dMaxRight; /* longest distance from the right object to anything below it in the tree */ struct _CNearTreeNode CNEARTREE_FAR * m_pLeftBranch; /* tree descending from the left object */ struct _CNearTreeNode CNEARTREE_FAR * m_pRightBranch; /* tree descending from the right object */ long m_iflags; /* flags */ size_t m_iTreeSize; /* size of this node tree */ #ifdef CNEARTREE_INSTRUMENTED size_t m_Height; /* height of this node */ #endif } CNearTreeNode; typedef CNearTreeNode CNEARTREE_FAR * CNearTreeNodeHandle; typedef struct { CNearTreeNodeHandle m_ptTree; /* pointer to the actual tree */ size_t m_szdimension; /* dimension of the coordinates */ size_t m_szsize; /* size of this tree */ size_t m_szdepth; /* depth of this tree */ long m_iflags; /* flags */ CVectorHandle m_ObjectStore; /* all inserted objects */ CVectorHandle m_CoordStore; /* all inserted coordinates */ CVectorHandle m_DelayedIndices;/* objects queued for insertion */ CRHrand m_rhr; /* random number generator */ double m_DiamEstimate; /* estimated diameter */ double m_SumSpacings; /* sum of spacings at time of insertion */ double m_SumSpacingsSq; /* sum of spacings squared at time of insertion */ double m_DimEstimate; /* estimated dimension */ double m_DimEstimateEsd;/* estimated dimension estimated standard deviation */ #ifdef CNEARTREE_INSTRUMENTED size_t m_NodeVisits; /* number of node visits */ #endif } CNearTree; typedef CNearTree CNEARTREE_FAR * CNearTreeHandle; /* Distance Macros for L2LAZY */ #define CNTM_Abs(x) (((x)<0.)?(-(x)):(x)) #define CNTM_DistL2sq(distsq,treehandle,coord1,coord2) { \ size_t index; \ size_t treedim; \ long treetype; \ double CNEARTREE_FAR * dcoord1 = NULL; \ double CNEARTREE_FAR * dcoord2 = NULL; \ int CNEARTREE_FAR * icoord1 = NULL; \ int CNEARTREE_FAR * icoord2 = NULL; \ treedim = (treehandle)->m_szdimension; \ treetype = (treehandle)->m_iflags&CNEARTREE_TYPE; \ if (treetype == CNEARTREE_TYPE_DOUBLE) { \ dcoord1 = (double CNEARTREE_FAR *)(coord1);\ dcoord2 = (double CNEARTREE_FAR *)(coord2);\ } else if (treetype == CNEARTREE_TYPE_INTEGER) { \ icoord1 = (int CNEARTREE_FAR *)(coord1); \ icoord2 = (int CNEARTREE_FAR *)(coord2); \ } \ distsq = 0.; \ if (treetype == CNEARTREE_TYPE_DOUBLE) { \ distsq = (dcoord1[0]-dcoord2[0])*(dcoord1[0]-dcoord2[0]); \ \ for (index=1; index < treedim; index++) { \ distsq += (dcoord1[index]-dcoord2[index]) \ *(dcoord1[index]-dcoord2[index]); \ } \ } else if (treetype == CNEARTREE_TYPE_INTEGER) { \ distsq = ((double)(icoord1[0]-icoord2[0]))*((double)(icoord1[0]-icoord2[0])); \ \ for (index=1; index < treedim; index++) { \ distsq += ((double)(icoord1[index]-icoord2[index])) \ *((double)(icoord1[index]-icoord2[index])); \ } \ } \ } #define CNTM_DistL2(dist,treehandle,coord1,coord2) { \ size_t index; \ double distsq=0.; \ size_t treedim; \ long treetype; \ double CNEARTREE_FAR * dcoord1 = NULL; \ double CNEARTREE_FAR * dcoord2 = NULL; \ int CNEARTREE_FAR * icoord1 = NULL; \ int CNEARTREE_FAR * icoord2 = NULL; \ treedim = (treehandle)->m_szdimension; \ treetype = (treehandle)->m_iflags&CNEARTREE_TYPE; \ if (treetype == CNEARTREE_TYPE_DOUBLE) { \ dcoord1 = (double CNEARTREE_FAR *)(coord1);\ dcoord2 = (double CNEARTREE_FAR *)(coord2);\ } else if (treetype == CNEARTREE_TYPE_INTEGER) { \ icoord1 = (int CNEARTREE_FAR *)(coord1); \ icoord2 = (int CNEARTREE_FAR *)(coord2); \ } \ if (treedim == 1) { \ if (treetype == CNEARTREE_TYPE_DOUBLE) { \ (dist) = CNTM_Abs(dcoord1[0]-dcoord2[0]); \ } else if (treetype == CNEARTREE_TYPE_INTEGER) { \ (dist) = CNTM_Abs((double)(icoord1[0]-icoord2[0])); \ } \ } else { \ if (treetype == CNEARTREE_TYPE_DOUBLE) { \ distsq = (dcoord1[0]-dcoord2[0])*(dcoord1[0]-dcoord2[0]); \ \ for (index=1; index < treedim; index++) { \ distsq += (dcoord1[index]-dcoord2[index]) \ *(dcoord1[index]-dcoord2[index]); \ } \ } else if (treetype == CNEARTREE_TYPE_INTEGER) { \ distsq = ((double)(icoord1[0]-icoord2[0]))*((double)(icoord1[0]-icoord2[0])); \ \ for (index=1; index < treedim; index++) { \ distsq += ((double)(icoord1[index]-icoord2[index])) \ *((double)(icoord1[index]-icoord2[index])); \ } \ } \ (dist) = sqrt(distsq);\ }\ } #define CNTM_DistL1(dist,treehandle,coord1,coord2) {\ size_t index; \ size_t treedim; \ long treetype; \ double CNEARTREE_FAR * dcoord1 = NULL; \ double CNEARTREE_FAR * dcoord2 = NULL; \ int CNEARTREE_FAR * icoord1 = NULL; \ int CNEARTREE_FAR * icoord2 = NULL; \ \ treedim = treehandle->m_szdimension; \ treetype = treehandle->m_iflags&CNEARTREE_TYPE; \ (dist) = 0.; \ \ if (treetype == CNEARTREE_TYPE_DOUBLE) { \ dcoord1 = (double CNEARTREE_FAR *)(coord1);\ dcoord2 = (double CNEARTREE_FAR *)(coord2);\ } else if (treetype == CNEARTREE_TYPE_INTEGER) { \ icoord1 = (int CNEARTREE_FAR *)(coord1); \ icoord2 = (int CNEARTREE_FAR *)(coord2); \ } \ if (treetype == CNEARTREE_TYPE_DOUBLE) { \ (dist)= fabs(dcoord1[0]-dcoord2[0]); \ for (index=1; index < treedim; index++) { \ (dist) += CNTM_Abs(dcoord1[index]-dcoord2[index]); \ } \ } else if (treetype == CNEARTREE_TYPE_INTEGER) { \ (dist) = fabs((double)(icoord1[0]-icoord2[0])); \ for (index=1; index < treedim; index++) { \ (dist) += CNTM_Abs((double)(dcoord1[index]-dcoord2[index])); \ } \ } \ } /* ======================================================================= double CNearTreeDistsq(void CNEARTREE_FAR * coord1, void CNEARTREE_FAR * coord2, size_t treedim, int treetype) function to return the square of the Euclidean distance between two coordinate vectors. THIS FUNCTION IS DEPRECATED treedim -- the dimension of the vectors treetype -- and integer flag for type of the vectors CNEARTREE_TYPE_DOUBLE for double CNEARTREE_TYPE_INTEGER for integer ======================================================================= */ double CNearTreeDistsq(void CNEARTREE_FAR * coord1, void CNEARTREE_FAR * coord2, size_t treedim, long treetype); /* ======================================================================= double CNearTreeDist(const CNearTreeHandle treehandle, void CNEARTREE_FAR * coord1, void CNEARTREE_FAR * coord2) function to return the distance (L1, L2 or L-infinity) between two coordinate vectors according to the parameters of the given tree For L2LAZY tree this returns the L2 norm distance. ======================================================================= */ double CNearTreeDist(const CNearTreeHandle treehandle, void CNEARTREE_FAR * coord1, void CNEARTREE_FAR * coord2); /* ======================================================================= int CNearTreeSetNorm(const CNearTreeHandle treehandle, int treenorm); function to set the norm to use used for this tree treenorm should be one of CNEARTREE_NORM_L1 for an L-1 norm CNEARTREE_NORM_L2 for an L-2 norm CNEARTREE_NORM_LINF for an L-infinity norm CNEARTREE_NORM_LAZY for an L-1 norm used for L-2 searching the function returns CNEARTREE_BAD_ARGUMENT for an invalid argument CNEARTREE_SUCCESS (0) otherwise ======================================================================= */ int CNearTreeSetNorm(const CNearTreeHandle treehandle, int treenorm); /* ======================================================================= int CNearTreeNodeCreate ( const CNearTreeHandle treehandle, CNearTreeNodeHandle CNEARTREE_FAR * treenodehandle) Create a CNearTreeNode returns a pointer to the newly allocated block of memory as a CNearTreeNodeHandle in *treenodehandle flags are inherited from the treehandle creates an empty tree with no right or left node and with the dMax-below set to negative values so that any match found will be stored since it will greater than the negative value ======================================================================= */ int CNearTreeNodeCreate ( const CNearTreeHandle treehandle, CNearTreeNodeHandle CNEARTREE_FAR * treenodehandle); /* ======================================================================= int CNearTreeCreate ( CNearTreeHandle CNEARTREE_FAR * treehandle, size_t treedim, long treetype) Create a CNearTree returns a pointer to the newly allocated block of memory as a CNearTreeHandle in *treehandle treedim -- the dimension of the vectors treetype -- double or integer flag for type of the vectors ored with norm and ored with execution flags CNEARTREE_TYPE_DOUBLE for double CNEARTREE_TYPE_INTEGER for integer CNEARTREE_TYPE_STRING for strings ored with CNEARTREE_NORM_L1 for the sum of the absolute values CNEARTREE_NORM_L2 for the square root of the sum of the squares CNEARTREE_NORM_LINF for the max CNEARTREE_NORM_SPHERE for norm as spherical angular distance CNEARTREE_NORM_HSPHERE for norm as hemispherical angular distance CNEARTREE_NORM_HAMMING for norm as string hamming distance ored with CNTF_NOPREPRUNE 0x10000L flag to supress all search prepruning CNTF_FORCEPREPRUNE 0x20000L flag to force search prepruning CNTF_NOFLIP 0x40000L flag to suppress flips on insert CNTF_FORCEFLIP 0x80000L flag to force flips on insert CNTF_NODEFER 0x100000L flag to prevent deferred insert creates an empty tree with no right or left node and with the dMax-below set to negative values so that any match found will be stored since it will greater than the negative value ======================================================================= */ int CNearTreeCreate(CNearTreeHandle CNEARTREE_FAR * treehandle, size_t treedim, long treetype); /* ======================================================================= int CNearTreeFree ( CNearTreeHandle CNEARTREE_FAR * treehandle ) Free a CNearTree recursively frees the NearTree with the handle *treehandle and nulls the treehandle. note that the objects referenced are not freed. ======================================================================= */ int CNearTreeFree(CNearTreeHandle CNEARTREE_FAR * treehandle); /* ======================================================================= int CNearTreeClear ( const CNearTreeHandle treehandle ) Clear a CNearTree Clears the NearTree with the handle *treehandle note that the objects referenced are not freed. ======================================================================= */ int CNearTreeClear ( const CNearTreeHandle treehandle ); /* ======================================================================= size_t CNearTreeSize (const CNearTreeHandle treehandle) Macro to get Tree Size with no error checking ======================================================================= */ #define CNearTreeSize(treehandle) \ ((treehandle)?(((treehandle)->m_CoordStore)?(CVectorSize((treehandle)->m_CoordStore)):0):0) /* ======================================================================= int CNearTreeGetSize (const CNearTreeHandle treehandle, size_t CNEARTREE_FAR * size) Return the number of objects in the tree in size ======================================================================= */ int CNearTreeGetSize (const CNearTreeHandle treehandle, size_t CNEARTREE_FAR * size); /* ======================================================================= int CNearTreeGetDelayedSize (const CNearTreeHandle treehandle, size_t CNEARTREE_FAR * size) Return the number of objects in the delay queue tree in size This is a deprecated alternate name for CNearTreeGetDeferredSize ======================================================================= */ int CNearTreeGetDelayedSize (const CNearTreeHandle treehandle, size_t CNEARTREE_FAR * size); /* ======================================================================= int CNearTreeGetDeferredSize (const CNearTreeHandle treehandle, size_t CNEARTREE_FAR * size) Return the number of objects in the delay queue tree in size ======================================================================= */ int CNearTreeGetDeferredSize ( const CNearTreeHandle treehandle, size_t CNEARTREE_FAR * size ); /* ======================================================================= int CNearTreeGetTotalSize (const CNearTreeHandle treehandle, size_t CNEARTREE_FAR * size) Return the number of objects in both in the tree and in the delay queue tree in size Identical to CNearTreeGetSize, retained to support older code ======================================================================= */ #define CNearTreeGetTotalSize(treehandle,size) CNearTreeGetSize(treehandle,size) /* ======================================================================= int CNearTreeGetDepth (const CNearTreeHandle treehandle, size_t CNEARTREE_FAR * depth) Return the depth of the tree in depth ======================================================================= */ int CNearTreeGetDepth (const CNearTreeHandle treehandle, size_t CNEARTREE_FAR * depth); /* ======================================================================= int CNearTreeGetHeight (const CNearTreeHandle treehandle, size_t CNEARTREE_FAR * height) Return the height of the tree in height, of instrumented, otherwise the depth ======================================================================= */ int CNearTreeGetHeight ( const CNearTreeHandle treehandle, size_t CNEARTREE_FAR * height ); /* ======================================================================= int CNearTreeGetFlags(const CNearTreeHandle treehandle, long CNEARTREE_FAR *flags, const long mask) int CNearTreeSetFlags(const CNearTreeHandle treehandle, const long flags, const long mask) functions to get or set the execution control flags: CNTF_NOPREPRUNE to supress all search prepruning CNTF_FORCEPREPRUNE to force search prepruning CNTF_NOFLIP flag to suppress flips on insert CNTF_FORCEFLIP flag to force flips on insert CNTF_NODEFER flag to prevent deferred insert The desired flags may be ored. If mask is no zero it is used as a bit mask, so a call with a flags of zero and a mask equal to a particular flag, clears that flag. ======================================================================= */ int CNearTreeGetFlags(const CNearTreeHandle treehandle, long CNEARTREE_FAR *flags, const long mask); int CNearTreeSetFlags(const CNearTreeHandle treehandle, const long flags, const long mask); /* ======================================================================= int CNearTreeGetMeanSpacing ( const CNearTreeHandle treehandle, double CNEARTREE_FAR * spacing ) Get an estimate of the spacing of points ======================================================================= */ int CNearTreeGetMeanSpacing ( const CNearTreeHandle treehandle, double CNEARTREE_FAR * spacing ); /* ======================================================================= int CNearTreeGetVarSpacing ( const CNearTreeHandle treehandle, double CNEARTREE_FAR * varspacing ) Get an estimate of variance of the spacing of points ======================================================================= */ int CNearTreeGetVarSpacing ( const CNearTreeHandle treehandle, double CNEARTREE_FAR * varspacing ); /* ======================================================================= int CNearTreeCount(const CNearTreeHandle treehandle, size_t CNEARTREE_FAR * count) ======================================================================= */ int CNearTreeCount(const CNearTreeHandle treehandle, size_t CNEARTREE_FAR * count); #ifndef CNEARTREE_INSTRUMENTED /* ======================================================================= int CNearTreeGetNodeVisits ( const CNearTreeHandle treehandle, size_t CNEARTREE_FAR * visits) Get the number of visits to nodes Dummy version to return 0 ======================================================================= */ int CNearTreeGetNodeVisits ( const CNearTreeHandle treehandle, size_t CNEARTREE_FAR * visits); #endif #ifdef CNEARTREE_INSTRUMENTED /* ======================================================================= int CNearTreeGetNodeVisits ( const CNearTreeHandle treehandle, size_t CNEARTREE_FAR * visits) Get the number of visits to nodes ======================================================================= */ int CNearTreeGetNodeVisits ( const CNearTreeHandle treehandle, size_t CNEARTREE_FAR * visits); /* ======================================================================= int CNearTreeSetNodeVisits ( const CNearTreeHandle treehandle, const size_t visits ) Set the number of visits to nodes ======================================================================= */ int CNearTreeSetNodeVisits ( const CNearTreeHandle treehandle, const size_t visits ); #endif /* ======================================================================= int CNearTreeGetDiamEstimate ( const CNearTreeHandle treehandle, double CNEARTREE_FAR * diamest ) Get an estimate of the diameter ======================================================================= */ int CNearTreeGetDiamEstimate ( const CNearTreeHandle treehandle, double CNEARTREE_FAR * diamest ); /* ======================================================================= int CNearTreeGetDimEstimateEsd ( const CNearTreeHandle treehandle, double CNEARTREE_FAR * dimestesd ) Get the current best estimate of the dimension esd ======================================================================= */ int CNearTreeGetDimEstimateEsd ( const CNearTreeHandle treehandle, double CNEARTREE_FAR * dimestesd ); /* ======================================================================= int CNearTreeGetDimEstimate ( const CNearTreeHandle treehandle, double CNEARTREE_FAR * diamest, const double DimEstimateEsd ) Get an estimate of the dimension of the collection of points in the tree, to within the specified esd ======================================================================= */ int CNearTreeGetDimEstimate ( const CNearTreeHandle treehandle, double CNEARTREE_FAR * dimest, const double DimEstimateEsd ); /* ======================================================================= int CNearTreeNodeCount(const CNearTreeNodeHandle treenodehandle, size_t CNEARTREE_FAR * count) ======================================================================= */ int CNearTreeNodeCount(const CNearTreeNodeHandle treenodehandle, size_t CNEARTREE_FAR * count); /* ======================================================================= int CNearTreeImmediateInsert ( const CNearTreeHandle treehandle, const void CNEARTREE_FAR * coord, const void CNEARTREE_FAR * obj ) Function to insert some "point" as an object into a CNearTree for later searching, but immediately, not into the queue used for normal insertions coord is a coordinate vector for an object, obj, to be inserted into a Neartree. A static copy of the coordinates and a pointer to the object are inserted Three possibilities exist: put the datum into the left position (first test),into the right position, or else into a node descending from the nearer of those positions when they are both already used. return 0 for success, nonzero for an error ======================================================================= */ int CNearTreeImmediateInsert( const CNearTreeHandle treehandle, const void CNEARTREE_FAR * coord, const void CNEARTREE_FAR * obj ); /* ======================================================================= int CNearTreeNodeReInsert_Flip ( const CNearTreeHandle treehandle, const const CNearTreeNodeHandle treenodehandle, size_t CNEARTREE_FAR * depth) Function to reinsert the elements from a detached a node into a CNearTree for later searching treehandle is the handle of the overall neartree being used treenodehandle is the handle of the node in the existing tree at which to start the insertion pntn is the handle of the previously detached node from which to extract the nodes for insertion depth is used to keep track of the depth at which the insertion is done return 0 for success, nonzero for an error ======================================================================= */ int CNearTreeNodeReInsert_Flip( const CNearTreeHandle treehandle, const CNearTreeNodeHandle treenodehandle, const CNearTreeNodeHandle pntn, size_t CNEARTREE_FAR * depth); /* ======================================================================= int CNearTreeNodeInsert ( const CNearTreeHandle treehandle, const const CNearTreeNodeHandle treenodehandle, size_t index; size_t CNEARTREE_FAR * depth) Function to insert some "point" as an object into a node in a CNearTree for later searching treenodehandle is the handle of the node at which to start the insertion index is the index of the object and coordinates to add from treehandle->m_ObjectStore and treehandle->CoordStore into a NearTree. A static copy of the coordinates and a pointer to the object are inserted Three possibilities exist: put the datum into the left position (first test),into the right position, or else into a node descending from the nearer of those positions when they are both already used. depth is used to keep track of the depth at which the insertion is done return 0 for success, nonzero for an error ======================================================================= ======================================================================= int CNearTreeNodeInsert_Flip ( const CNearTreeHandle treehandle, const const CNearTreeNodeHandle treenodehandle, size_t index; size_t CNEARTREE_FAR * depth) Function to insert some "point" as an object into a node in a CNearTree for later searching treenodehandle is the handle of the node at which to start the insertion index is the index of the object and coordinates to add from treehandle->m_ObjectStore and treehandle->CoordStore into a NearTree. A static copy of the coordinates and a pointer to the object are inserted Three possibilities exist: put the datum into the left position (first test),into the right position, or else into a node descending from the nearer of those positions when they are both already used. depth is used to keep track of the depth at which the insertion is done return 0 for success, nonzero for an error ======================================================================= */ int CNearTreeNodeInsert( const CNearTreeHandle treehandle, const CNearTreeNodeHandle treenodehandle, const size_t index, size_t CNEARTREE_FAR * depth ); int CNearTreeNodeInsert_Flip( const CNearTreeHandle treehandle, const CNearTreeNodeHandle treenodehandle, const size_t index, size_t CNEARTREE_FAR * depth ); /* ======================================================================= int CNearTreeInsert ( const CNearTreeHandle treehandle, const void CNEARTREE_FAR * coord, const void * obj ) Function to queue some "point" as an object for future insertion into a CNearTree for later searching coord is a coordinate vector for an object, obj, to be inserted into a Neartree. A static copy of the coordinates and a pointer to the object are queued for insertion. The exact order of insertion is not predetermined. It will be partially randomized to help to balance the tree. The insertions will be completed by a call to CNearTreeCompleteDelayedInsert(const CNearTreeHandle treehandle) or by execution of any search. return 0 for success, nonzero for an error ======================================================================= */ int CNearTreeInsert( const CNearTreeHandle treehandle, const void CNEARTREE_FAR * coord, const void * obj ); /* ======================================================================= int CNearTreeDelayedInsert ( const CNearTreeHandle treehandle, const void CNEARTREE_FAR * coord, const void * obj ) *** THIS IS A DEPRECATED ALTLERNATE CALL TO CNearTreeInsert *** Function to queue some "point" as an object for future insertion into a CNearTree for later searching coord is a coordinate vector for an object, obj, to be inserted into a Neartree. A static copy of the coordinates and a pointer to the object are queued for insertion. The exact order of insertion is not predetermined. It will be partially randomized to help to balance the tree. The insertions will be completed by a call to CNearTreeCompleteDelayedInsert(const CNearTreeHandle treehandle) or by execution of any search. return 0 for success, nonzero for an error ======================================================================= */ int CNearTreeDelayedInsert( const CNearTreeHandle treehandle, const void CNEARTREE_FAR * coord, const void CNEARTREE_FAR * obj ); /* ======================================================================= int CNearTreeCompleteDelayedInsert ( const CNearTreeHandle treehandle ) Function to dequeue the "points" queued as an objects for future insertion into a CNearTree for later searching return 0 for success, nonzero for an error ======================================================================= */ int CNearTreeCompleteDelayedInsert( const CNearTreeHandle treehandle ); /* ======================================================================= int CNearTreeZeroIfEmpty (const CNearTreeHandle treehandle) Test for an empty CNearTree, returning 0 in that case ======================================================================= */ int CNearTreeZeroIfEmpty (const CNearTreeHandle treehandle); /* ======================================================================= int CNearTreeNearestNeighbor ( const CNearTreeHandle treehandle, const double dRadius, void CNEARTREE_FAR * CNEARTREE_FAR * coordClosest, void CNEARTREE_FAR * CNEARTREE_FAR * objClosest, const void CNEARTREE_FAR * coord ) Function to search a Neartree for the object closest to some probe point, coord. This function is only here so that the function CNearTreeNearest can be called without having dRadius const dRadius is the maximum search radius - any point farther than dRadius from the probe point will be ignored coordClosest is the coordinate vector into which the coordinates of the nearest point will be stored objClosest is the address into which a pointer to the object associated with coordClosest will be stored coord is the probe point the return value is true only if a point was found this version searches down the shortest branch first ======================================================================= ======================================================================= int CNearTreeLeftNearestNeighbor ( const CNearTreeHandle treehandle, const double dRadius, void CNEARTREE_FAR * CNEARTREE_FAR * coordClosest, void CNEARTREE_FAR * CNEARTREE_FAR * objClosest, const void CNEARTREE_FAR * coord ) Function to search a Neartree for the object closest to some probe point, coord. This function is only here so that the function CNearTreeNearest can be called without having dRadius const dRadius is the maximum search radius - any point farther than dRadius from the probe point will be ignored coordClosest is the coordinate vector into which the coordinates of the nearest point will be stored objClosest is the address into which a pointer to the object associated with coordClosest will be stored coord is the probe point the return value is true only if a point was found this version searches down the left branch first ======================================================================= */ int CNearTreeNearestNeighbor (const CNearTreeHandle treehandle, const double dRadius, void CNEARTREE_FAR * CNEARTREE_FAR * coordClosest, void CNEARTREE_FAR * CNEARTREE_FAR * objClosest, const void CNEARTREE_FAR * coord ); int CNearTreeLeftNearestNeighbor (const CNearTreeHandle treehandle, const double dRadius, void CNEARTREE_FAR * CNEARTREE_FAR * coordClosest, void CNEARTREE_FAR * CNEARTREE_FAR * objClosest, const void CNEARTREE_FAR * coord ); /* ======================================================================= int CNearTreeFarthestNeighbor ( const CNearTreeHandle treehandle, void CNEARTREE_FAR * CNEARTREE_FAR * coordFarthest, void CNEARTREE_FAR * CNEARTREE_FAR * objFarthest, const void CNEARTREE_FAR * coord ) Function to search a Neartree for the object farthest some probe point, coord. coordClosest is the coordinate vector into which the coordinates of the nearest point will be stored objClosest is the address into which a pointer to the object associated with coordClosest will be stored coord is the probe point the return value is true only if a point was found ======================================================================= */ int CNearTreeFarthestNeighbor (const CNearTreeHandle treehandle, void CNEARTREE_FAR * CNEARTREE_FAR * coordFarthest, void CNEARTREE_FAR * CNEARTREE_FAR * objFarthest, const void CNEARTREE_FAR * coord ); /* ======================================================================= int CNearTreeFindInSphere ( const CNearTreeHandle treehandle, const double CNEARTREE_FAR * dRadius, CVectorHandle coordClosest, CVectorHandle objClosest, const void CNEARTREE_FAR * coord, int resetcount) Function to search a Neartree for the set of objects closer to some probe point, coord, than dRadius. This is only here so that objClosest can be cleared before starting the work. dRadius is the maximum search radius - any point farther than dRadius from the probe point will be ignored coordClosest is a vector of pointers to coordinate tuples and is the returned set of nearest points to the probe point that can be found in the Neartree objClosest is a vector of objects and is the returned set of nearest points to the probe point that can be found in the Neartree coord is the probe point resetcount should be non-zero to clear objClosest on entry return value is 0 if points were found ======================================================================= */ int CNearTreeFindInSphere ( const CNearTreeHandle treehandle, const double dRadius, CVectorHandle coordClosest, CVectorHandle objClosest, const void * coord, int resetcount); /* ======================================================================= int CNearTreeFindTreeInSphere ( const CNearTreeHandle treehandle, const double CNEARTREE_FAR * dRadius, CNearTreeHandle foundClosest, const void CNEARTREE_FAR * coord, int resetcount) Function to search a Neartree for the set of objects closer to some probe point, coord, than dRadius. dRadius is the maximum search radius - any point farther than dRadius from the probe point will be ignored foundClosest is an existing CNearTree to which the found points will be added coord is the probe point resetcount should be non-zero to clear found closest on entry return value is 0 if points were found ======================================================================= */ int CNearTreeFindTreeInSphere ( const CNearTreeHandle treehandle, const double dRadius, CNearTreeHandle foundClosest, const void CNEARTREE_FAR * coord, int resetcount); /* ======================================================================= int CNearTreeFindOutSphere ( const CNearTreeHandle treehandle, const double CNEARTREE_FAR * dRadius, CVectorHandle coordOutside, CVectorHandle objOutside, const void CNEARTREE_FAR * coord, int resetcount) Function to search a Neartree for the set of objects further from some probe point, coord, than dRadius. dRadius is the maximum search radius - any point closer than dRadius from the probe point will be ignored coordOutside is a vector of pointers to coordinate tuples and is the returned set of distant points from the probe point that can be found in the Neartree objOutside is a vector of objects and is the returned set of distant points from the probe point that can be found in the Neartree coord is the probe point resetcount should be non-zero to clear objClosest on entry return value is 0 if points were found ======================================================================= */ int CNearTreeFindOutSphere ( const CNearTreeHandle treehandle, const double dRadius, CVectorHandle coordOutside, CVectorHandle objOutside, const void * coord, int resetcount); /* ======================================================================= int CNearTreeFindTreeOutSphere ( const CNearTreeHandle treehandle, const double dRadius, CNearTreeHandle foundOutside, const void CNEARTREE_FAR * coord, int resetcount) Function to search a Neartree for the set of objects further from some probe point, coord, than dRadius. dRadius is the maximum search radius - any point closer than dRadius from the probe point will be ignored foundOutside is an existing CNearTree to which the found points will be added coord is the probe point resetcount should be non-zero to clear found closest on entry return value is 0 if points were found ======================================================================= */ int CNearTreeFindTreeOutSphere ( const CNearTreeHandle treehandle, const double dRadius, CNearTreeHandle foundOutside, const void CNEARTREE_FAR * coord, int resetcount); /* ======================================================================= int CNearTreeFindInAnnulus ( const CNearTreeHandle treehandle, const double dRadiusInner, const double dRadiusOuter, CVectorHandle coordInRing, CVectorHandle objInRing, const void CNEARTREE_FAR * coord, int resetcount) Function to search a Neartree for the set of objects closer to some probe point, coord, than dRadiusOuter and further than dRadiusInner. dRadiusInner is the minimum search radius - any point closer than dRadius from the probe point will be ignored dRadiusOuter is the maximum search radius - any point further than dRadius from the probe point will be ignored coordInRing is a vector of pointers to coordinate tuples of nearest points objInRing is a vector of objects and is the returned set of nearest points to the probe point that can be found in the Neartree coord is the probe point resetcount should be non-zero to clear coordInRing and objInRing on entry return value is 0 if points were found ======================================================================= */ int CNearTreeFindInAnnulus ( const CNearTreeHandle treehandle, const double dRadiusInner, const double dRadiusOuter, CVectorHandle coordInRing, CVectorHandle objInRing, const void CNEARTREE_FAR * coord, int resetcount); /* ======================================================================= int CNearTreeFindTreeInAnnulus ( const CNearTreeHandle treehandle, const double dRadiusInner, const double dRadiusOuter, CNearTreeHandle foundInRing, const void CNEARTREE_FAR * coord, int resetcount) Function to search a Neartree for the set of objects closer to some probe point, coord, than dRadiusOuter and further than dRadiusInner. dRadiusInner is the minimum search radius - any point closer than dRadius from the probe point will be ignored dRadiusOuter is the maximum search radius - any point further than dRadius from the probe point will be ignored foundInRing is an existing CNearTree to which the found points will be added coord is the probe point resetcount should be non-zero to clear found InRing on entry return value is 0 if points were found ======================================================================= */ int CNearTreeFindTreeInAnnulus ( const CNearTreeHandle treehandle, const double dRadiusInner, const double dRadiusOuter, CNearTreeHandle foundInRing, const void CNEARTREE_FAR * coord, int resetcount); /* ======================================================================= int CNearTreeSortIn(CVectorHandle metrics, CVectorHandle indices, double metric, size_t index, size_t k); CNearTreeSortIn inserts a new metric and index into the vectors metrics and indices, sorted on non-decreasing metric, with the size of the vectors capped at k, or uncapped if k = 0; ======================================================================= */ int CNearTreeSortIn(CVectorHandle metrics, CVectorHandle indices, double metric, size_t index, size_t k); /* ======================================================================= int CNearTreeNearest ( const CNearTreeHandle treehandle, double CNEARTREE_FAR *dRadius, void CNEARTREE_FAR * CNEARTREE_FAR * coordClosest, void CNEARTREE_FAR * CNEARTREE_FAR * objClosest, const void CNEARTREE_FAR * coord ) Function to search a Neartree for the object closest to some probe point, coord. This function is called by CNearTreeNearestNeighbor. *dRadius is the smallest currently known distance of an object from the probe point and is modified as the search progresses. coordClosest is the returned closest point to the probe point that can be found in the Neartree objClosest is a pointer to a pointer to hold the corresponding object or is NULL coord is the probe point the return value is 0 only if a point was found within dRadius this version search down the shortest branch first ======================================================================= ======================================================================= int CNearTreeLeftNearest ( const CNearTreeHandle treehandle, double CNEARTREE_FAR *dRadius, void CNEARTREE_FAR * CNEARTREE_FAR * coordClosest, void CNEARTREE_FAR * CNEARTREE_FAR * objClosest, const void CNEARTREE_FAR * coord ) Function to search a Neartree for the object closest to some probe point, coord. This function is called by CNearTreeNearestNeighbor. *dRadius is the smallest currently known distance of an object from the probe point and is modified as the search progresses. coordClosest is the returned closest point to the probe point that can be found in the Neartree objClosest is a pointer to a pointer to hold the corresponding object or is NULL coord is the probe point the return value is 0 only if a point was found within dRadius this version searches down the left branch first ======================================================================= */ int CNearTreeNearest ( const CNearTreeHandle treehandle, double CNEARTREE_FAR * dRadius, void CNEARTREE_FAR * CNEARTREE_FAR * coordClosest, void CNEARTREE_FAR * CNEARTREE_FAR * objClosest, const void CNEARTREE_FAR * coord ); int CNearTreeLeftNearest ( const CNearTreeHandle treehandle, double CNEARTREE_FAR * dRadius, void CNEARTREE_FAR * CNEARTREE_FAR * coordClosest, void CNEARTREE_FAR * CNEARTREE_FAR * objClosest, const void CNEARTREE_FAR * coord ); /* ======================================================================= int CNearTreeFindFarthest ( const CNearTreeHandle treehandle, double CNEARTREE_FAR * dRadius, void CNEARTREE_FAR * CNEARTREE_FAR * coordFarthest, void CNEARTREE_FAR * CNEARTREE_FAR * objFarthest, const void CNEARTREE_FAR * coord ) Function to search a Neartree for the object farthest from some probe point, coord. This function is called by CNearTreeFarthestNeighbor. *dRadius is the largest currently known distance of an object from the probe point and is modified as the search progresses. coordFarthest is the returned farthest point from the probe point that can be found in the Neartree objFarthest is a pointer to a pointer to hold the corresponding object or is NULL coord is the probe point the return value is 0 only if a point was found. ======================================================================= */ int CNearTreeFindFarthest ( const CNearTreeHandle treehandle, double CNEARTREE_FAR * dRadius, void CNEARTREE_FAR * CNEARTREE_FAR * coordFarthest, void CNEARTREE_FAR * CNEARTREE_FAR * objFarthest, const void CNEARTREE_FAR * coord ); /* ======================================================================= int CNearTreeFindKNearest ( const CNearTreeHandle treehandle, const size_t k, const double dRadius, CVectorHandle coordClosest, CVectorHandle objClosest, const void * coord, int resetcount); Function to search a Neartree for the set of objects closer to some probe point, coord, than dRadius. k is the maximum number of closest neighbors to return. Finds this many if passible. dRadius is the maximum search radius - any point closer than dRadius to the probe point will be ignored coordClosest is a vector of pointers to coordinate tuples and is the returned set of farthest points from the probe point that can be found in the Neartree objClosest is a vector of objects and is the returned set of farthest points from the probe point that can be found in the Neartree coord is the probe point resetcount should be non-zero to clear objClosest on entry return value is 0 if points were found ======================================================================= */ int CNearTreeFindKNearest ( const CNearTreeHandle treehandle, const size_t k, const double dRadius, CVectorHandle coordClosest, CVectorHandle objClosest, const void * coord, int resetcount); /* ======================================================================= int CNearTreeFindKTreeNearest ( const CNearTreeHandle treehandle, const size_t k, const double dRadius, CNearTreeHandle foundNearest, const void CNEARTREE_FAR * coord, int resetcount); Function to search a Neartree for the set of k objects closer to some probe point, coord, than dRadius. k is the maximum number of closest neighbors to return. Finds this many if passible. dRadius is the minimum search radius - any point closer than dRadius to the probe point will be ignored foundClosest is an existing CNearTree to which the found points will be added coord is the probe point resetcount should be non-zero to clear foundClosest on entry return value is 0 if points were found ======================================================================= */ int CNearTreeFindKTreeNearest ( const CNearTreeHandle treehandle, const size_t k, const double dRadius, CNearTreeHandle foundClosest, const void CNEARTREE_FAR * coord, int resetcount); /* ======================================================================= int CNearTreeFindKFarthest ( const CNearTreeHandle treehandle, const size_t k, const double dRadius, CVectorHandle coordFarthest, CVectorHandle objFarthest, const void * coord, int resetcount); Function to search a Neartree for the set of objects farther from some probe point, coord, than dRadius. k is the maximum number of farthest neighbors to return. Finds this many if passible. dRadius is the maximum search radius - any point farther than dRadius from the probe point will be ignored coordFarthest is a vector of pointers to coordinate tuples and is the returned set of farthest points from the probe point that can be found in the Neartree objFarthest is a vector of objects and is the returned set of farthest points from the probe point that can be found in the Neartree coord is the probe point resetcount should be non-zero to clear objFarthest on entry return value is 0 if points were found ======================================================================= */ int CNearTreeFindKFarthest ( const CNearTreeHandle treehandle, const size_t k, const double dRadius, CVectorHandle coordFarthest, CVectorHandle objFarthest, const void * coord, int resetcount); /* ======================================================================= int CNearTreeFindKTreeFarthest ( const CNearTreeHandle treehandle, const size_t k, const double dRadius, CNearTreeHandle foundFarthest, const void CNEARTREE_FAR * coord, int resetcount); Function to search a Neartree for the set of k objects farther from some probe point, coord, than dRadius. k is the maximum number of farthest neighbors to return. Finds this many if passible. dRadius is the minimum search radius - any point farther than dRadius from the probe point will be ignored foundFarthest is an existing CNearTree to which the found points will be added coord is the probe point resetcount should be non-zero to clear foundFarthest on entry return value is 0 if points were found ======================================================================= */ int CNearTreeFindKTreeFarthest ( const CNearTreeHandle treehandle, const size_t k, const double dRadius, CNearTreeHandle foundFarthest, const void CNEARTREE_FAR * coord, int resetcount); /* ======================================================================= The following macro is provided here to ensure operation with older versions of CVector ======================================================================= */ #ifndef CVectorElementAt /* CVectorElementAt -- return the element at the given index as a void pointer without checking and without protection against relocation */ #define CVectorElementAt(vectorhandle,index) ((void CNEARTREE_FAR *)(((char *)((vectorhandle)->array))+(index)*(vectorhandle)->elementsize)) #endif /* ======================================================================= int CNearTreeObjects ( const CNearTreeHandle treehandle, CVectorHandle CNEARTREE_FAR * vectorhandle) Function to return the vector of objects in the tree. This vector is not guaranteed to be in the same order as the order of insertion vectorhandle -- a pointer to a CVectorHandle ======================================================================= */ int CNearTreeObjects ( const CNearTreeHandle treehandle, CVectorHandle CNEARTREE_FAR * vectorhandle); /* ======================================================================= int CNearTreeCoords ( const CNearTreeHandle treehandle, CVectorHandle CNEARTREE_FAR * vectorhandle) Function to return the vector of coordinates in the tree. This vector is not guaranteed to be in the same order as the order of insertion vectorhandle -- a pointer to a CVectorHandle ======================================================================= */ int CNearTreeCoords ( const CNearTreeHandle treehandle, CVectorHandle CNEARTREE_FAR * vectorhandle); /* ======================================================================= void CNEARTREE_FAR * CNearTreeObjectAt ( const CNearTreeHandle treehandle, size_t index) Function to return the an object pointer at the given index implemented as a macro ======================================================================= */ #define CNearTreeObjectAt(treehandle,index) CVectorElementAt(treehandle->m_ObjectStore,index) /* ======================================================================= void CNEARTREE_FAR * CNearTreeCoordAt ( const CNearTreeHandle treehandle, size_t index) Function to return the a coordinate pointer at the given index implemented as a macro ======================================================================= */ #define CNearTreeCoordAt(treehandle,index) CVectorElementAt(treehandle->m_CoordStore,index) #ifdef __cplusplus } #endif #endif ./NearTree-3.1.1/README_NearTree.txt0000644002342100234170000016647211640404060016722 0ustar bernstehfaculty NearTree Release 3.1.1 23 April 2011 (revised 27 September 2011) (c) Copyright 2001, 2008, 2009, 2010, 2011 Larry Andrews. All rights reserved based on Larry Andrews, "A template for the nearest neighbor problem", C/C++ Users Journal, Volume 19 , Issue 11 (November 2001), 40 - 49 (2001), ISSN:1075-2838, www.ddj.com/architect/184401449 Revised 12 Dec 2008, for sourceforge release, Larry Andrews and Herbert J. Bernstein 8 Jan 2009 Release 1.0 LCA and HJB 11 Jan 2009 Release 1.0.1 LCA and HJB 21 March 2009 Release 2.0 LCA and HJB 30 May 2009 Release 2.1 LCA and HJB 4 June 2009 Release 2.1.1 LCA and HJB 7 June 2009 Release 2.1.2 LCA and HJB 7 July 2009 Release 2.1.3 LCA and HJB 29 November 2009 Release 2.1.4 LCA 23 April 2010 Release 2.1.5 LCA and HJB 18 July 2010 Release 2.2 HJB 25 July 2010 Release 2.2.1 HJB 31 August 2010 Release 2.3 LCA 7 September 2010 Release 2.3.1 LCA 30 October 2010 Release 2.3.2 LCA 22 March 2011 Release 3.0 LCA and HJB 5 April 2011 Release 3.0.1 LCA and HJB 19 April 2011 Release 3.0.2 HJB 23 April 2011 Release 3.1 HJB 27 September 2011 Release 3.1.1 HJB YOU MAY REDISTRIBUTE NearTree UNDER THE TERMS OF THE LGPL +------------------------------------------------------------------------------+ | LGPL NOTICES | | | | This library is free software; you can redistribute it and/or modify it | | under the terms of the GNU Lesser General Public License as published by the | | Free Software Foundation; either version 2.1 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* Lesser General Public License | | for more details. | | | | You should have received a copy of the GNU Lesser General Public License | | along with this library; if not, write to the Free Software Foundation, | | Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | +------------------------------------------------------------------------------+ This is a release of an API for finding nearest neighbors among points in spaces of arbitrary dimensions. This release provides a C++ template, TNear.h, and a C library, CNearTree.c, with example/test programs. Release 3.1.1 adjusted the libtool version from 5:0:1 to 6:0:1 to avoid confusion on the SONAME of the library as requested by Teemu Ikonen for use as a Debian package. Release 3.1 adjusted the randomization to be based on the depth rather than the population and added an optional detailed height calculation. Release 3.0.2 added to randomization on insertion when the tree is not well balanced. Release 3.0.1 updated the diameter calculation and fixed some documentation errors. Release 3.0 (formerly named Release 2.4) is a major change to NearTree, restructuring the default search from left-first to balanced and adding hooks to collect information about the tree. Release 2.3.2 adds optional returns of vectors of ordinals of found objects Release 2.3.1 adds Centroid method for Lloyd clustering. Release 2.3 added methods for clustering. Release 2.2.1 was a minor revision to Release 2.2 to add an include of limits.h to TNear.h, primarily for MINGW use. Release 2.2 added support for C code for fixed length string searches using a hamming distance norm, and for spherical and hemispherical geodesic norm based searches. Because of the addition of new type and norm flags, the version 2.2 shared libraries cannot be used to support binaries compiled against earlier headers and vice-versa. Release 2.1.5 was a cleanup update to the 2.1 release of 30 May 2009 to increase portability, in five stages (2.1.1 on 4 June 2009, 2.1.2 on 7 June 2009, 2.1.3 on 7 July 2009, 2.1.4 on 29 November 2009 and 2.1.5 on 23 April 2010) dealing with the following issues: * Convert to use of a self-contained portable random-number generator from Rob Harrison (2.1.1) * Ensure wider use of const where appropriate (2.1.1) * Correct typos and unclear wording in the README (2.1.2) * Reorganize use of USE_LOCAL_HEADERS in CNearTreeTest.cpp (2.1.2) * Change FAR macro to CNEARTREE_FAR (2.1.3) * Add BelongsToPoints and SeparateByRadius (2.1.4) * Fix dimensions for rhrand (2.1.5) The 2.1 release was a minor update to the 2.0 release of 21 March 2009 to deal with the following issues: * Make delayed insertion the default * Complete the containerization of TNear.h * Add code for K-nearest/farthest in TNear.h and in CNearTree.c * Correct the InAnnulus search filter Release 2.0 was a major update to the 1.0 release of 8 January 2009 to deal with the following issues: * Replace use recursion with a stack, except in insertion logic * Replace use of double with templated DistanceType (usually double) * Provide constuctors to build NearTree from vectors, lists or sets * Change "Insert" to "insert" for consistency with other containers * Add access function "at" or array type references [], and provide contents of a neartree as a vector * Add iterator support * Provide delayed insertion logic * Functions added for searches outside of a sphere or in an annular region Our thanks to Nicolas Brodu for suggesting the more general handling of the distance type. Note: As Nicolas Brodu has noted, CNearTree is particularly well-suited to multi-threaded applications. However, if the same CNearTree is to be searched in multiple threads, it is important to complete all insertions and/or delayed insertions before parallel execution of parallel searches. ---------------------------------------------------------------------- Contents * Installation * The C++ template: TNear.h * The C NearTree API: CNearTree.c * A Portable pseudo-random number generator: rhrand.h ---------------------------------------------------------------------- ---------------------------------------------------------------------- Installation The NearTree package is available at www.sourceforge.net/projects/neartree. A source tarball is available at downloads.sourceforge.net/neartree/NearTree-3.1.1.tar.gz. Later tarballs may be available. If you decide to simply use the TNear.h header to add nearest neighbor support to C++ code under Visual Studio, be sure to also use the rhrand.h and triple.h headers. It is no longer necessary to define USE_LOCAL_HEADERS, which is automatically defined if _MSC_VER is defined. For unix or MINGW, you will need to use the Makefile and to have libtool on your system. Be warned that the default libtool under Mac OS X will not work for this installation. When the source tarball is downloaded and unpacked, you should have a directory NearTree-3.1.1. To see the current settings for a build execute make which should give the following information: PLEASE READ README_NearTree.txt and lgpl.txt Before making the NearTree libraries and example programs, check that the chosen settings are correct The current C++ and C compile commands are: libtool --mode=compile g++ -g -O2 -Wall -ansi -pedantic \ -DCNEARTREE_SAFE_TRIANG=1 -I. -c libtool --mode=compile gcc -g -O2 -Wall -ansi -pedantic \ -DCNEARTREE_SAFE_TRIANG=1 -I. -c The C API, CNearTree.c, depends on the sourceforge project CVector You are currently setup to use the system defaults for CVector If that is not correct, define the variable CVECTOR_INCLUDE The current library link command is: libtool --mode=link gcc -version-info 6:0:1 \ -no-undefined -rpath /usr/local/lib The current C++ and C library local, and C dynamic and static build commands are: libtool --mode=link g++ -no-undefined -g -O2 -Wall -ansi -pedantic \ -DCNEARTREE_SAFE_TRIANG=1 -I. libtool --mode=link gcc -g -O2 -Wall -ansi -pedantic \ -DCNEARTREE_SAFE_TRIANG=1 -I. libtool --mode=link gcc -no-undefined -g -O2 -Wall -ansi -pedantic \ -DCNEARTREE_SAFE_TRIANG=1 -shared -I/usr/local/include libtool --mode=link gcc -g -O2 -Wall -ansi -pedantic \ -DCNEARTREE_SAFE_TRIANG=1 -static-libtool-libs -I/usr/local/include Before installing the NearTree library and example programs, check that the install directory and install commands are correct: The current values are : /usr/local libtool --mode=install cp To compile the NearTree library and example programs type: make clean make all To run a set of tests type: make tests To clean up the directories type: make clean To install the library and headers type: make install If these settings need to be changed, edit Makefile. On some systems, e.g. Mac OS X, the default libtool is not appropriate. In that case you should install a recent version of libtool. The CVector kit has been tested with libtool versions 1.3.5 and 1.5.4. For MINGW, libtool version 2.2.6 and gcc version 4 are needed to work with shared libraries (DLLs). If the system libtool is not to be used, define the variable LIBTOOL to be the path to the libtool executable, e.g. in bash export LIBTOOL=$HOME/bin/libtool or in the Makefile LIBTOOL = $(HOME)/bin/libtool If you need to include local header files using #include "..." instead of #include <...>, define the variable USE_LOCAL_HEADERS. USE_LOCAL_HEADERS is the default for Visual Studio under Microsoft Windows. Optionally, you may also define CNEARTREE_FORCEFLIP to maximize tree reorganization on insertion, CNEARTREE_NOFLIP to suppress tree reorganization on insertion, CNEARTREE_NODEFER to make all insertions immediate, CNEARTREE_FORCEPREPUNE to do searches first with a tighter estimate on the search radius, and CNEARTREE_NOPREPRUNE to suppress that behavior. The defaults are to do tree reorganization on insertion, to defer insertions, but not to preprune the search radius. If you define CNEARTREE_INSTRUMENTED, code will be enabled to track node visits in searching the tree. The triangle inequality that must be evaluated in building trees and retrieving data may not be evaluated correctly if the range of the three values is extremely large (>10**15 or so for doubles) or may be evaluated differently by some compilers in different parts of a program (due to differing usage of registers). The default in this API is to do the triangle inequality three different ways under the control of CNEARTREE_SAFE_TRIANG #ifdef CNEARTREE_SAFE_TRIANG #define TRIANG(a,b,c) ( (((b)+(c))-(a) >= 0) \ || ((b)-((a)-(c)) >= 0) \ || ((c)-((a)-(b)) >= 0)) #else #define TRIANG(a,b,c) ( (((b)+(c))-(a) >= 0)) #endif Problems with the unsafe definition of TRIANG have been seen in Linux under gcc version 4 and in MS Window under VS 2003. There is a slight performance hit from the triple test. If maximal speed is critical and misidentification of nearest points by relative distance errors of about 1 part in 10**15 is not a serious problem, the definition of -DCNEARTREE_SAFE_TRIANG=1 can be removed from the definition of CFLAGS in the Makefile. NOTE: A range of 10**15 is comparable to the diameter of the earth vs. the separation of two bonded atoms. ---------------------------------------------------------------------- ---------------------------------------------------------------------- The C++ template: TNear.h This is a revised release of template class CNearTree; implementing the Nearest Neighbor algorithm after Kalantari and McDonald, (IEEE Transactions on Software Engineering, v. SE-9, pp. 631-634,1983) modified to use recursion for insertions and recursion (original version) or a stack (current version) for searches instead of a double-linked tree and simplified. The default search algorithm no longer favors the left branch first, but follows the more balanced Kalantari and McDonald approach. The prior search algorithm is available in "Left" versions of the search routines doing a bit less checking for things like is the distance to the right less than the distance to the left. This template is used to contain a collection of objects. After the collection has been loaded into this structure, it can be quickly queried for which object is "closest" to some probe object of the same type. The major restriction on applicability of the near-tree is that the algorithm only works if the objects obey the triangle inequality. The triangle rule states that the length of any side of a triangle cannot exceed the sum of the lengths of the other two sides. CNearTree is the root class for the neartree. The actual data of the tree is stored in NearTreeNode objects descending from a CNearTree. The types of objects that can be stored in the tree is quite broad. The biggest limitation is that the objects must reside in some sort of metric space and must obey the triangle rule. They must also be all of the same size because they are stored in an std::vector. If your application requires objects of varying storage, then your best way to use this code is to store pointers or handles and to write your own distance functions. Note that std::string is a pointer type variable and so can be stored directly. The type of the objects to be stored is the only required template argument. The type of the distance measure (DistanceType) defaults to double. If your application is for an integer type, then the type for DistanceType can be your integer type. This has the potential for speeding the calculations by avoiding FP computation. Other general types can be used if desired, but you may need to also input a value of distMinValue. The template argument distMinValue must be something that your class will understand as a negative number. The default input is negative one. Internally, that is cast to DistanceType. Since most uses will be for DistanceType to be double, that is a simple conversion. Obviously, for integer types, there is no problem either. The need for this value is to have something internally that is recognizable as smaller than the smallest "distance" that can exist between any two objects in your type. For most users, there is no need to input anything other than the default, -1. -1 must be castable to DistanceType. It seems unlikely that anyone would actually need this optional parameter, but it is here for completeness. It is a design decision that this class cannot work for unsigned types. Verifying the triangle rule for unsigned types is more complex. Sorry, unsigned types are left as an exercise for the reader. The user of this class needs to provide at least the following functionality for the template to work. For the built-in numerics of C++, they are provided by the system. DistanceType Norm( void ); // a function "Norm( void )" of the templated class // to return DistanceType (usually will return a // "length" of type double) operator- ( ); // geometrical (vector) difference of two objects // a copy constructor would be nice // a constructor would be nice // a destructor would be nice The provided interface is: #include CNearTree( void ) // constructor instantiated by something like: CNearTree vTree; for some type T CNearTree( const ContainerType & o) // constructor from containers, e.g. ... CNearTree( const std::vector & o ) // constructor CNearTree( const std::list & o ) // constructor CNearTree( const std::set & o ) // constructor CNearTree( const CNearTree & o ) // constructor CNearTree( const ContainerType & o1, const ContainerType & o2) // constructor merging 2 containers, e.g. ... ~CNearTree( void ) // destructor void clear( void ) // clear the NearTree long GetFlags( void ) const // Get all execution flags void SetFlags( const long flags ) // Set all execution flags long GetFlags( const long mask ) const // Get execution flags within mask void SetFlags( const long flags, const long mask ) // Set execution flags within mask // The available execution flags are static const long NTF_NoPrePrune = 1; //flag to suppress all search prepruning static const long NTF_ForcePrePrune = 2; //flag to force search prepruning static const long NTF_NoFlip = 4; //flag to suppress flips on insert static const long NTF_ForceFlip = 8; //flag to force flips on insert static const long NTF_NoDefer =16; //flag to prevent deferred insert template CNearTree& operator=( const InputContainer& o ) // put container's contents into a NearTree, // wiping out the current contents template CNearTree& operator=( InputContainer& o ) // put container's contents into a NearTree, // wiping out the current contents template CNearTree& operator+=( const InputContainer& o ) // add a container's contents to a NearTree template CNearTree& operator-=( const InputContainer& o ) // remove a container's contents from a NearTree template CNearTree& set_symmetric_difference( const InputContainer&, o ) // remove the part of a container's // contents from a NearTree that is // already in the Neartree and add // in the contents of the container // that is not already in the Neartree // i.e. the exclusive or void insert( const T& t ) where t is an object of the type T all inserts are delayed until a search is performed or until an explicit call to CompleteDelayedInsertions is called or a search is called. The purpose is to distribute the objects a bit more randomly. Excessively ordered objects leads to less than optimal trees. Starting with the 2.1 release, places objects in a queue for insertion later when CompleteDelayInsert is called. In earlier releases the default was immediate insertion. The following additional convenience insert template allow insertion of containers of objects template< typename InputContainer > void insert( ContainerType & o ) // e. g. ... void insert( const std::vector & o ) void insert( const std::list & o ) void insert( const std::set & o ) void insert( const CNearTree & o ) iterator NearestNeighbor ( const DistanceType & dRadius, const T& t ) const returns an iterator to the nearest point to the probe point t or end() if there is none bool NearestNeighbor ( const DistanceType& dRadius, T& tClosest, const T& t ) const dRadius is the largest radius within which to search; make it very large if you want to include every point that was loaded. tClosest is returned as the object that was found closest to the probe point (if any were within radius dRadius of the probe) t is the probe point, used to search in the group of points insert'ed return value is true if some object was found within the search radius, false otherwise. If false is returned, tClosest is invalid (at best). iterator FarthestNeighbor ( T& const T& t ) const returns an iterator to the nearest point to the probe point t or end() if there is none bool FarthestNeighbor ( T& tFarthest, const T& t ) const tFarthest is returned as the object that was found farthest from the probe point t is the probe point, used to search in the group of points Insert'ed return value is true if some object was found, false otherwise If false is returned, tFarthest is invalid (at best). iterator LeftNearestNeighbor ( const DistanceType & dRadius, const T& t ) const returns an iterator to the nearest point to the probe point t or end() if there is none bool LeftNearestNeighbor ( const DistanceType& dRadius, T& tClosest, const T& t ) const dRadius is the largest radius within which to search; make it very large if you want to include every point that was loaded. tClosest is returned as the object that was found closest to the probe point (if any were within radius dRadius of the probe) t is the probe point, used to search in the group of points insert'ed return value is true if some object was found within the search radius, false otherwise. If false is returned, tClosest is invalid (at best). iterator LeftFarthestNeighbor ( T& const T& t ) const returns an iterator to the nearest point to the probe point t or end() if there is none bool LeftFarthestNeighbor ( T& tFarthest, const T& t ) const tFarthest is returned as the object that was found farthest from the probe point t is the probe point, used to search in the group of points Insert'ed return value is true if some object was found, false otherwise If false is returned, tFarthest is invalid (at best). The "Left..." versions of NearestNeighbor and FarthestNeighbor are deprecated versions provided for compatibility with earlier releases of NearTree. There are also "Short..." and "LeftShort..." versions of NearestNeighbor to support experimental prepruning logic. The following functions (BelongsToPoints, SeparateByRadius, FindInSphere, FindOutSphere, and FindInAnnulus) all return a container (ContainerType) that can be any standard library container (such as std::vector< T >) or CNearTree. In each case option arguments allow a parallel vector of indices to be returned for each container, giving the indices of the returned objects within the original NearTree. template void BelongsToPoints ( const T& t1, const T& t2, ContainerType& group1, ContainerType& group2 ) template void BelongsToPoints ( const T& t1, const T& t2, ContainerType& group1, ContainerType& group2, std::vector& group1_ordinals, std::vector& group2_ordinals) returns the points closer to t1 than to t2 in group1 and the rest in group 2 if group1_ordinals and group2_ordinals are provided the ordinals of the found objects in the object store are put into those vectors. The ordinals can be used as indices into the CNearTree itself. template void SeparateByRadius ( const DistanceType radius, const T& probe, ContainerTypeInside& inside, ContainerTypeOutside& outside ) template void SeparateByRadius ( const DistanceType radius, const T& probe, ContainerTypeInside& inside, ContainerTypeOutside& outside, std::vector& inside_ordinals, std::vector& outside_ordinals) return the points within radius of the probe in inside and the rest in outside if inside_ordinals and outside_ordinals are provided the ordinals of the found objects in the object store are put into those vectors. The ordinals can be used as indices into the CNearTree itself. long FindInSphere ( const DistanceType& dRadius, ContainerType& tInside, const T& t ) const long FindInSphere ( const DistanceType& dRadius, ContainerType& tInside, std::vector& tIndices, const T& t ) const long FindInSphere ( const DistanceType& dRadius, CNearTree< T >& tInside, const T& t ) const long LeftFindInSphere ( const DistanceType& dRadius, ContainerType& tInside, const T& t ) const long LeftFindInSphere ( const DistanceType& dRadius, ContainerType& tInside, std::vector& tIndices, const T& t ) const long LeftFindInSphere ( const DistanceType& dRadius, CNearTree< T >& tInside, const T& t ) const dRadius is the radius within which to search; make it very large if you want to include every point that was loaded; tInside is returned as the NearTree or container of objects that were found within a radius dRadius of the probe point if the tIndices argument is given it will be returned as a vector of indices in the near tree of the objects returned. t is the probe point, used to search in the group of points Insert'ed return value is the count of the number of points found within the search radius the "Left..." versions are deprecated versions provided for compatibility with earlier NearTree releases. long FindOutSphere ( const DistanceType& dRadius, ContainerType& tOutside, const T& t ) const long FindOutSphere ( const DistanceType& dRadius, ContainerType& tOutside, std::vector& tIndices, const T& t ) const long FindOutSphere ( const DistanceType& dRadius, CNearTree< T >& tOutside, const T& t ) const long LeftFindOutSphere ( const DistanceType& dRadius, ContainerType& tOutside, const T& t ) const long LeftFindOutSphere ( const DistanceType& dRadius, ContainerType& tOutside, std::vector& tIndices, const T& t ) const long LeftFindOutSphere ( const DistanceType& dRadius, CNearTree< T >& tOutside, const T& t ) const dRadius is the radius outside of which to search tOutside is returned as the NearTree or container of objects that were found at or outside of radius dRadius of the probe point if the tIndices argument is given it will be returned as a vector of indices in the near tree of the objects returned. t is the probe point, used to search in the group of points Insert'ed return value is the count of the number of points found outside the search radius the "Left..." versions are deprecated versions provided for compatibility with earlier NearTree releases. long FindInAnnulus ( const DistanceType& dRadius1, const DistanceType& dRadius2, ContainerType& tInRing, const T& t ) const long FindInAnnulus ( const DistanceType& dRadius1, const DistanceType& dRadius2, ContainerType& tInRing, std::vector& tIndices, const T& t ) const long FindInAnnulus ( const DistanceType& dRadius1, const DistanceType& dRadius2, CNearTree< T >& tInRing, const T& t ) const long LeftFindInAnnulus ( const DistanceType& dRadius1, const DistanceType& dRadius2, ContainerType& tInRing, const T& t ) const long LeftFindInAnnulus ( const DistanceType& dRadius1, const DistanceType& dRadius2, ContainerType& tInRing, std::vector& tIndices, const T& t ) const long LeftFindInAnnulus ( const DistanceType& dRadius1, const DistanceType& dRadius2, CNearTree< T >& tInRing, const T& t ) const dRadius1 and dRadius2 are the two radii between which to find data points tInRing is returned as the NearTree or container of objects that were found at or outside of a radius dRadius1 and at or inside of radius dRadius2 of the probe point if the tIndices argument is given it will be returned as a vector of indices in the near tree of the objects returned. t is the probe point, used to search in the group of points Insert'ed return value is the count of the number of points found within the annulus the "Left..." versions are deprecated versions provided for compatibility with earlier NearTree releases. long FindK_NearestNeighbors ( const size_t k, const DistanceType& dRadius, ContainerType& tClosest, const T& t ) long FindK_NearestNeighbors ( const size_t k, const DistanceType& dRadius, ContainerType& tClosest, std::vector& tIndices, const T& t ) long FindK_NearestNeighbors ( const size_t k, const DistanceType& dRadius, CNearTree< T >& tClosest, const T& t ) long LeftFindK_NearestNeighbors ( const size_t k, const DistanceType& dRadius, ContainerType& tClosest, const T& t ) long LeftFindK_NearestNeighbors ( const size_t k, const DistanceType& dRadius, ContainerType& tClosest, std::vector& tIndices, const T& t ) long LeftFindK_NearestNeighbors ( const size_t k, const DistanceType& dRadius, CNearTree< T >& tClosest, const T& t ) k is the maximum number of nearest neighbors to return. Finds this many if possible dRadius within a sphere defined by dRadius, to search for the k-nearest-neighbors tClosest is returned as the ContainerType or NearTree of the objects found if the tIndices argument is given it will be returned as a vector of indices in the near tree of the objects returned. t is the probe point, used to search in the group of points insert'ed return value is the count of the number of points found within the sphere the "Left..." versions are deprecated versions provided for compatibility with earlier NearTree releases. long FindK_FarthestNeighbors ( const size_t k, ContainerType& tFarthest, const T& t ) long FindK_FarthestNeighbors ( const size_t k, ContainerType& tFarthest, std::vector& tIndices, const T& t ) long FindK_FarthestNeighbors ( const size_t k, CNearTree< T >& tFarthest, const T& t ) long LeftFindK_FarthestNeighbors ( const size_t k, ContainerType& tFarthest, const T& t ) long LeftFindK_FarthestNeighbors ( const size_t k, ContainerType& tFarthest, std::vector& tIndices, const T& t ) long LeftFindK_FarthestNeighbors ( const size_t k, CNearTree< T >& tFarthest, const T& t ) k is the maximum number of farthest neighbors to return. Finds this many if possible tFarthest is returned as the ContainerType or NearTree of the objects found if the tIndices argument is given it will be returned as a vector of indices in the near tree of the objects returned. t is the probe point, used to search in the group of points insert'ed return value is the count of the number of points found within the sphere the "Left..." versions are deprecated versions provided for compatibility with earlier NearTree releases. ---------------------------------------------------------------------- Access Functions: T at ( const size_t n ) const returns the n'th item of the internal data store. This is not guaranteed to be in the order of insertion. T operator[] ( const size_t n ) returns the n'th item of the internal data store. This is not guaranteed to be in the order of insertion. template operator ContainerType ( void ) const returns all of the inserted objects in the tree in a container of type ContainerType. ContainerType can be std::vector, etc, or other containers, including CNearTree. The returned vector contents are not guaranteed to be returned in the order loaded. iterator begin ( void ) const returns an iterator to the beginning of the internal data store iterator end ( void ) const returns an iterator to the end of the data store (one beyond the last item) iterator back ( void ) const returns an iterator to the last data item of the internal data store ---------------------------------------------------------------------- Information and special operation functions: void ImmediateInsert( const T&aamp; t ) insert places objects in a queue for insertion later when CompleteDelayInsert is called or a search is called. ImmediateInsert inserts the data immediately into the tree (with the potential of a less balanced tree). ImmediateInsert is not intended for the ordinary user. void CompleteDelayedInsert ( void ) completes insertion for all delayed objects. sqrt(n) of them are inserted by random choice. The rest are inserted in linear order as originally queued. CompleteDelayedInsert is invoked at the beginning of all searches, so the average user will never need to call it. size_t GetDeferredSize ( void ) returns the number of delayed objects that have not yet completed insertion. This is mainly for information about details of the tree. size_t GetTotalSize ( void ) returns the number of objects that have been insert'ed plus those DelayInsert'ed size_t size ( void ) identical to GetTotalSize size_t GetDepth ( void ) returns the maximum tree layers from the root. This is mainly for information about details of the tree. double GetDimEstimate ( void ) // returns an estimate of the Hausdorff dimension double GetDimEstimate ( const double DimEstimateEsd ) // returns an estimate of the Hausdorff dimension // to within the given esd double GetDimEstimateEsd ( void ) // returns an estimate of the esd double GetDiamEstimate ( void ) // returns an estimate of the diameter DistanceType GetMeanSpacing ( void ) // returns an estimate object spacing DistanceType GetVarSpacing ( void ) // returns an estimate object spacing variance size_t GetNodeVisits ( void ) // returns the number of node visits if // CNEARTREE_INSTRUMENTED as defined, 0 otherwise void SetNodeVisits,/b> ( const size_t visits) // set the number of node visits T Centroid ( void ) returns the centroid of a neartree. bool empty ( void ) returns true if the tree is empty, otherwise false ---------------------------------------------------------------------- Iterators: Random access iterators are provided for accessing the data in a CNearTree. The most important expected use is to retrieve the objects returned from one of the sphere search functions that can return a CNearTree. However, they can be used with any CNearTree. They should function in a fashion essentially the same as STL iterators. There is no assurance that data will be returned in the order it was loaded, just that it is accessible. This is the list of iterators. The same set is available for const_iterator. iterator ( void ) { }; // constructor iterator ( const const_iterator& s ) iterator& operator= ( const iterator& s ) iterator& operator= ( const const_iterator& s ) iterator operator++ ( const int n ) iterator operator-- ( const int n ) iterator& operator++ ( void ) iterator& operator-- ( void ) iterator operator+ ( const long n ) const iterator operator- ( const long n ) const iterator& operator+= ( const long n ) iterator& operator-= ( const long n ) T operator* ( void ) const bool operator== ( const iterator& t ) const bool operator!= ( const iterator& t ) const bool operator== ( const const_iterator& t ) const bool operator!= ( const const_iterator& t ) const bool operator> ( const iterator& t ) const bool operator> ( const const_iterator& t ) const bool operator< ( const iterator& t ) const bool operator< ( const const_iterator& t ) const const T * const operator-> ( void ) const ---------------------------------------------------------------------- So a complete program is: #include "TNear.h" #include void main() { CNearTree< double > dT; double dNear; dT.Insert( 1.5 ); if ( dT.NearestNeighbor( 10000.0, dNear, 2.0 )) printf( "%f\n",double(dNear-2.0) ); } and it should print 0.5 (that's how for 2.0 is from 1.5). For more examples of the use of TNear.h, see main.cpp and CNearTreeTest.cpp. ---------------------------------------------------------------------- ---------------------------------------------------------------------- The C NearTree API: CNearTree.c Synopsis #include double CNearTreeDistsq ( CNearTreeHandle treehandle, void * coord1, void * coord2 ); double CNearTreeDist ( CNearTreeHandle treehandle, void * coord1, void * coord2 ); int CNearTreeSetNorm ( const CNearTreeHandle treehandle, int treenorm ); int CNearTreeNodeCreate ( const CNearTreeHandle treehandle, CNearTreeNodeHandle * treenodehandle ) int CNearTreeCreate ( CNearTreeHandle * treehandle, size_t treedim, int treetype ); int CNearTreeFree ( const CNearTreeHandle treehandle ); int CNearTreeClear ( CNearTreeHandle * treehandle ); int CNearTreeNodeFree ( CNearTreeNodeHandle * treenodehandle ); int CNearTreeInsert( const CNearTreeHandle treehandle, const void * coord, const void * obj ); int CNearTreeImmediateInsert ( const CNearTreeHandle treehandle, const void * coord, const void * obj ); int CNearTreeDelayedInsert ( const CNearTreeHandle treehandle, const void * coord, const void * obj ); /* ***DEPRECATED*** */ int CNearTreeNodeInsert ( const CNearTreeHandle treehandle, CNearTreeNodeHandle treenodehandle, size_t index; size_t * depth ); int CNearTreeNodeInsert_Flip ( const CNearTreeHandle treehandle, CNearTreeNodeHandle treenodehandle, size_t index; size_t * depth ); int CNearTreeNodeReInsert_Flip ( const CNearTreeHandle treehandle, const CNearTreeNodeHandle treenodehandle, const CNearTreeNodeHandle pntn, size_t * depth ); int CNearTreeCompleteDelayedInsert ( const CNearTreeHandle treehandle ) int CNearTreeZeroIfEmpty ( const CNearTreeHandle treehandle ); int CNearTreeGetSize ( const CNearTreeHandle treehandle, size_t * size ); int CNearTreeGetTotalSize ( const CNearTreeHandle treehandle, size_t * size ); /* ***DEPRECATED*** */ size_t CNearTreeSize ( const CNearTreeHandle treehandle); int CNearTreeGetDeferredSize ( const CNearTreeHandle treehandle, size_t * size ); int CNearTreeGetDelayedSize ( const CNearTreeHandle treehandle, size_t * size ); /* ***DEPRECATED*** */ int CNearTreeGetDepth ( const CNearTreeHandle treehandle, size_t * depth ) int CNearTreeGetFlags ( const CNearTreeHandle treehandle, long * flags, const long mask ) int CNearTreeSetFlags ( const CNearTreeHandle treehandle, const long flags, const long mask ) int CNearTreeGetMeanSpacing ( const CNearTreeHandle treehandle, double * spacing ); int CNearTreeGetVarSpacing ( const CNearTreeHandle treehandle, double * varspacing ); int CNearTreeCount ( const CNearTreeHandle treehandle, size_t * count ); int CNearTreeNodeCount ( const CNearTreeNodeHandle treenodehandle, size_t * count ); #ifdef CNEARTREE_INSTRUMENTED int CNearTreeGetNodeVisits ( const CNearTreeHandle treehandle, size_t * visits); int CNearTreeSetNodeVisits ( const CNearTreeHandle treehandle, const size_t visits ); #endif int CNearTreeGetDiamEstimate ( const CNearTreeHandle treehandle, double * diamest ); int CNearTreeGetDimEstimateEsd ( const CNearTreeHandle treehandle, double * dimestesd ); int CNearTreeGetDimEstimate ( const CNearTreeHandle treehandle, double * dimest, const double DimEstimateEsd ); int CNearTreeNearestNeighbor ( const CNearTreeHandle treehandle, const double dRadius, void * * coordClosest, void * * objClosest, const void * coord ); int CNearLeftTreeNearestNeighbor ( const CNearTreeHandle treehandle, const double dRadius, void * * coordClosest, void * * objClosest, const void * coord ); /* ***DEPRECATED*** */ int CNearTreeFarthestNeighbor ( const CNearTreeHandle treehandle, void * * coordFarthest, void * * objFarthest, const void * coord ); int CNearTreeFindInSphere ( const CNearTreeHandle treehandle, const double dRadius, CVectorHandle coordInside, CVectorHandle objInside, const void * coord, int resetcount ); int CNearTreeFindTreeInSphere ( const CNearTreeHandle treehandle, const double dRadius, CNearTreeHandle foundInside, const void * coord, int resetcount ) int CNearTreeFindOutSphere ( const CNearTreeHandle treehandle, const double dRadius, CVectorHandle coordOutside, CVectorHandle objOutside, const void * coord, int resetcount ); int CNearTreeFindTreeOutSphere ( const CNearTreeHandle treehandle, const double dRadius, CNearTreeHandle foundOutside, const void * coord, int resetcount ) int CNearTreeFindInAnnulus ( const CNearTreeHandle treehandle, const double dRadiusInner, const double dRadiusOuter, CVectorHandle coordInRing, CVectorHandle objInRing, const void * coord, int resetcount ); int CNearTreeFindTreeInAnnulus ( const CNearTreeHandle treehandle, const double dRadiusInner, const double dRadiusOuter, CNearTreeHandle foundInRing, const void * coord, int resetcount ) int CNearTreeFindKNearest ( const CNearTreeHandle treehandle, const size_t k, const double dRadius, CVectorHandle coordClosest, CVectorHandle objClosest, const void * coord, int resetcount ); int CNearTreeFindKTreeNearest ( const CNearTreeHandle treehandle, const size_t k, const double dRadius, CNearTreeHandle foundClosest, const void * coord, int resetcount ) int CNearTreeFindKFarthest ( const CNearTreeHandle treehandle, const size_t k, const double dRadius, CVectorHandle coordFarthest, CVectorHandle objFarthest, const void * coord, int resetcount ); int CNearTreeFindKTreeFarthest ( const CNearTreeHandle treehandle, const size_t k, const double dRadius, CNearTreeHandle foundFarthest, const void * coord, int resetcount ) int CNearTreeNearest ( const CNearTreeHandle treehandle, double * dRadius, void * * coordClosest, void * * objClosest, const void * coord ); int CNearTreeLeftNearest ( const CNearTreeHandle treehandle, double * dRadius, void * * coordClosest, void * * objClosest, const void * coord ); /* ***DEPRECATED*** */ int CNearTreeFindFarthest ( const CNearTreeHandle treehandle, double * dRadius, void * * coordFarthest, void * * objFarthest, const void * coord ); int CNearTreeObjects ( const CNearTreeHandle treehandle, CVectorHandle * vectorhandle ); void * CNearTreeObjectAt ( const CNearTreeHandle treehandle, size_t index ); int CNearTreeCoords ( const CNearTreeHandle treehandle, CVectorHandle * vectorhandle ); void * CNearTreeCoordAt ( const CNearTreeHandle treehandle, size_t index ); The NearTree API works with coordinate vectors in an arbitrary number of dimensions. Each neartree is accessed by a pointer of type CNearTreeHandle which points to a struct of type CNearTree, which points to a tree of nodes of type CNearTreeNode: typedef struct _CNearTreeNode { size_t m_indexLeft; /* index of left coords in m_CoordStore and of left object in m_ObjectStore */ size_t m_indexRight; /* index of right coords in m_CoordStore and of right object in m_ObjectStore */ double m_dMaxLeft; /* longest distance from the left object to anything below it in the tree */ double m_dMaxRight; /* longest distance from the right object to anything below it in the tree */ struct _CNearTreeNode * m_pLeftBranch; /* tree descending from the left object */ struct _CNearTreeNode * m_pRightBranch; /* tree descending from the right object */ int m_iflags; /* flags */ } CNearTreeNode; typedef CNearTreeNode * CNearTreeNodeHandle; typedef struct { CNearTreeNodeHandle m_ptTree; /* pointer to the actual tree */ size_t m_szdimension; /* dimension of the coordinates */ size_t m_szsize; /* size of this tree */ size_t m_szdepth; /* depth of this tree */ int m_iflags; /* flags */ CVectorHandle m_ObjectStore; /* all inserted objects */ CVectorHandle m_CoordStore; /* all inserted coordinates */ CVectorHandle m_DelayedIndices;/* objects queued for insertion */ } CNearTree; typedef CNearTree FAR * CNearTreeHandle; /* Execution Control Flags */ #define CNTF_NOPREPRUNE 0x10000L /*flag to suppress all search prepruning */ #define CNTF_FORCEPREPRUNE 0x20000L /*flag to force search prepruning */ #define CNTF_NOFLIP 0x40000L /*flag to suppress flips on insert */ #define CNTF_FORCEFLIP 0x80000L /*flag to force flips on insert */ #define CNTF_NODEFER 0x100000L /*flag to prevent deferred insert */ The internal operation of the API depends on the function CNearTreeDist that returns the distance (L1, L2 or L-infinity) between two coordinate vectors as a double according to the parameters of the given tree. Note that the tree may store the coordinates as integers or as doubles, but the distance is always computed as a double. If this function is replaced by a user function, it is important that the replacement obey the triangle inequality. A neartree is created by CNearTreeCreate and freed by CNearTreeFree. treedim is the dimension of the coordinate vectors and treetype is one of the three predefined constants CNEARTREE_TYPE_DOUBLE for double or CNEARTREE_TYPE_INTEGER for integer or CNEARTREE_TYPE_STRING, optionally ORed with CNEARTREE_NORM_L1, CNEARTREE_NORM_L2 or CNEARTREE_NORM_LINF for L1, L2 or L-infinity norms, CNEARTREE_NORM_SPHERE or CNEARTREE_NORM_HSPHERE for a spherical or hemispherical norm (L1-norm combination of radial and spherical/hemispherical triangle distances), or CNEARTREE_NORM_HAMMING for the string-Hamming distance norm (add one for each differing character position). Starting with release 2.1, all insertions are delayed by default, unless the insertions is done by a call to CNearTreeImmediateInsert. The insertions that have been queued are completed by a call to CNearTreeCompleteDelayedInsert or by any search. The insertions are actually done in a randomized order, either for an initial block of sqrt(#queue) by default. or for the entire queue if the flag CNEARTREE_DEFER_ALL is ored with treetype. Starting with release 3 (formerly called release 2.4) optionally, you may also define CNEARTREE_FORCEFLIP to maximize tree reorganization on insertion, CNEARTREE_NOFLIP to suppress tree reorganization on insertion, CNEARTREE_NODEFER to make all insertions immediate, CNEARTREE_FORCEPREPUNE to do searches first with a tighter estimate on the search radius, and CNEARTREE_NOPREPRUNE to suppress that behavior. The defaults are to do tree reorganization on insertion, to defer insertions, but not to preprune the search radius. If you define CNEARTREE_INSTRUMENTED, code will be enabled to track node visits in searching the tree. The flags CNEARTREE_DEFER_ALL and CNEARTREE_FLIP used in prior releases are deprecated, but are still defined. They have no effect. When first created, a neartree has no right or left node and with the dMax-below set to negative values so that any match found will be stored since it will greater than the negative value. The tree is then populated by calls to CNearTreeInsert, with each call providing a coordinate vector coord and an optional object pointer obj. The API copies the coordinate vector, but does not copy the object. Later, when a search is requested or an explicit call to CNearTreeCompleteDelayedInsert is made, the tree is populated in the order left, right and then the nearer child, working from a randomized selection from the items queued for insertion. Optionally, the actual insertions may done immediately by calling CNearTreeImmediateInsert instead of CNearTreeInsert. For upwards compatibility of the library for existing code, the deprecated CNearTreeDelayedInsert is provided as an deprecated alternate call to CNearTreeInsert. The neartree is searched for the nearest or farthest coordinate vector in the neartree to a given probe coordinate vector coord by CNearTreeNearestNeighbor and CNearTreeFarthestNeighbor, respectively. Starting with release 3, the search is balanced, following the left or right branch first depending on which child node is closest. The former left-first behavior is deprecated, but still available in CNearLeftTreeNearestNeighbor. The given radius confines the search to a sphere around the probe. If more than a single extremal coordinate point is needed, CNearTreeFindInSphere can be used to obtain a CVector result vector of all the coordinate vectors that satisfy the constraint of being within a specified radius, or CNearTreeFindOutSphere can be used to obtain a CVector result vector of all the coordinates that satisfy the constraint of being outside a specified radius. CNearTreeFindIn Annulus can be used to obtain a CVector result vector of all the coordinates that satisfy the constraint of being between two specified radii from the probe. CNearTreeFindKNearest can be used to obtain a CVector result vector of the k coordinates closest to the probe point such that all results are within the specified radius of the probe point, or CNearTreeFindKFarthest to obtain a CVector result vector of the k coordinates farthest from the probe point such that all results are at or outside the specified radius of the probe point. The vectors themselves are not copied into the result vector. If the parameter resetcount is true (non zero) the result vector is cleared before the search. A CVector result vector of the matching object pointers is returned if objs is not NULL. Aternatively the forms CNearTreeFindTreeInSphere, CNearTreeFindTreeOutSphere, CNearTreeFindTreeInAnnulus, CNearTreeFindKTreeNearest, CNearTreeFindKTreeFarthest can be used to obtain CNearTrees rather than CVectors of results. The functions CNearTreeNearest and CNearTreeFindFarthest implement CNearTreeNearestNeighbor and CNearTreeFarthestNeighbor, respectively, adjusting the radius of the search while the search is in progress and are not normally used by users. The size of the tree as a count of objects can be obtained using the function NearTreeGetSize or the macro NearTreeSize. The size of the tree as a count of nodes and the depth of the tree can be obtained using the functions CNearTreeCount and CNearTreeGetDepth. Estimates of the Hausdorff dimension, the esd of that estimate, the diameter, the spacing and the variance of the spacing can be obtained with CNearTreeGetDimEstimate, CNearTreeGetDimEstimateEsd, CNearTreeGetDiamEstimate, CNearTreeGetMeanSpacing and CNearTreeGetVarSpacing. Returns If CNearTreeDist fails, it returns -1. Except for CNearTreeDist, all the functions in the API return 0 ( CNEARTREE_SUCCESS ) for success. If dynamic memory allocation fails, CNEARTREE_MALLOC_FAILED is returned. If a call is made with an improper argument, CNEARTREE_BAD_ARGUMENT is returned. If a search fails to find anything, CNEARTREE_NOT_FOUND is returned. If there is a failure in an attempt to free a CNearTree, CNEARTREE_FREE_FAILED is returned. If any of the internal call to CVector fail, CNEARTREE_CVECTOR_FAILED is returned. For convenience in debugging, the formerly negative values of these returns are now positive. Examples To create a neartree for 3-dimensional vectors of doubles: #include CNearTreeHandle treehandle; int bReturn; ... bReturn = !CNearTreeCreate(&treehandle,3,CNEARTREE_TYPE_DOUBLE); To insert a copy of a 3-dimensional vector of doubles into this tree, with no associated object: double v[3]; ... v[0] = 1.; v[1] = 2.; v[2] = 3.; bReturn = !CNearTreeInsert(treehandle,&v[0],NULL); To search for the nearest neighbor to a probe vector vSearch in a radius of 3., returning a pointer to the resulting vector in vBest: double * vBest; void * vvBest; double vSearch[3]; double dRad = =3.; ... if ( !CNearTreeNearestNeighbor(treehandle,dRad,&vvBest,NULL,vSearch)) { vBest = (double *)vvBest; } Note the use of a separate void * vvBest instead of a cast of &vBest to avoid compiler type punning warnings. For more examples of the use of CNearTree.c, see main.c and CNearTreeTest.c in the release kit. ---------------------------------------------------------------------- ---------------------------------------------------------------------- A Portable pseudo-random number generator: rhrand.h rhrand.h is a portable pseudo-random number generator based one by Rob Harrison, derived from "one in J.M.Hammersley and D.C. Handscomb, 'Monte Carlo Methods,' Methuen & Co., London and Wiley & Sons, New York, 1964, p47". See also, D. E. Knuth "The Art of Computer Programming", Volume 2, "Seminumerical Alogorithms, Third Edition, Addison-Wesley, Reading MA, 1997. rhrand.h is a header file in which a C++ class, RHrand, is defined, and a C struct typedef CRHrand is defined. The C++ interface is static const int RHRAND_MAX = 32767; /* the integer range accessible as RHrand::RHRAND_MAX */ RHrand(void) /* the default constructor */ RHrand( const int iseed ) /* a constructor to start with the given seed */ ~RHrand( void) /* a destructor */ void srandom( const int iseed) /* reset the generator based on the given seed */ double urand( void ) /* return a random double uniformly distributed in [0,1) */ int random ( void ) /* return a random integer uniformly distributed in [0, RHRAND_MAX-1] */ In C++ code, typical use is #include RHrand rhr; ... x = rhr.urand(); The C interface is suppressed in RHRAND_NOCCODE is defined. Otherwise the C interface is based on defining a struct of type CRHRrand and calling macros that refer to a handle of type RCRHrandHandle. typedef struct CRHrand_ { /* the struct used in random number generattion */ double buffer[55]; int indx; int jndx; int kndx; double dTemp; } CRHrand; typedef CRHrand * CRHrandHandle; /* the type to be used in maro calls */ #define CRHRAND_MAX 32767 /* the integer range */ #define CRHrandSrandom(randhandle,iseed) ... /* a macro to call to initialize CHRrandHandle randhandle using see int iseed */ #define CRHrandUrand(randhandle) ... /* a macro to return a random double uniformly distributed in [0,1) */ #define CRHrandRandom(randhandle) ((int)(CRHrandUrand(randhandle)*(double)CRHRAND_MAX)) /* a macro to return a random integer uniformly distributed in [0, CRHRAND_MAX-1] */ Typical use is #include CRHrand rhr; ... CRHrandSrandom(&rhr, 0 ); ... x = CRHrandUrand(&rhr); ---------------------------------------------------------------------- ---------------------------------------------------------------------- Updated 27 September 2011 andrewsl@ix.netcom.com