├── README.md └── nn ├── .indent.pro ├── CHANGELOG ├── CUSTOMISE ├── LICENSE ├── README ├── config.h.in ├── configure ├── configure.in ├── delaunay.c ├── delaunay.h ├── delaunay_internal.h ├── distribute.c ├── distribute.h ├── examples ├── 1 │ ├── README │ ├── generate.awk │ ├── makefile │ ├── suptitle.m │ ├── test.sh │ └── viewexample.m ├── 2 │ ├── README │ ├── data.txt │ ├── makefile │ ├── mpitest.sh │ ├── suptitle.m │ ├── test.sh │ ├── viewdata.m │ ├── viewexample.m │ └── viewinterp.m ├── 3 │ ├── README │ ├── generate-data.awk │ ├── generate-points.awk │ ├── makefile │ └── test.sh ├── 4 │ ├── README │ ├── data.txt │ ├── makefile │ ├── test.sh │ ├── viewdata.m │ ├── viewexample.m │ └── viewinterp.m ├── 5 │ ├── README │ ├── data.txt │ ├── makefile │ ├── test.sh │ ├── viewexample.m │ ├── viewinterp.m │ └── viewinterp2.m ├── 6 │ ├── README │ ├── data.txt │ ├── makefile │ ├── test.sh │ ├── viewexample.m │ └── viewinterp.m └── README ├── hash.c ├── hash.h ├── install-sh ├── istack.c ├── istack.h ├── istack_internal.h ├── lpi.c ├── makefile.example ├── makefile.in ├── minell.c ├── minell.h ├── mkinstalldirs ├── nan.h ├── nn.h ├── nn_internal.h ├── nnai.c ├── nnbathy.c ├── nncommon-vulnerable.c ├── nncommon.c ├── nncommon.h ├── nnconfig.h.in ├── nnpi.c ├── nnpi.h ├── preader.c ├── preader.h ├── triangle.c ├── triangle.h └── version.c /README.md: -------------------------------------------------------------------------------- 1 | ## nn ## 2 | (Natural Neighbours interpolation) 3 | 4 | **nn** is a C code for Natural Neighbours interpolation of 2D scattered data. It provides a C library and a command line 5 | utility **nnbathy**. 6 | 7 | Algorithmically, it was initially loosely based on the Dave Watson's description of nngridr; code-wise it is an 8 | independent development. You may see a comparison of performance of a (rather old) version of **nn** with nngridr in 9 | 10 | Quanfu Fan, Alon Efrat, Vladlen Koltun, Shankar Krishnan, and Suresh 11 | Venkatasubramanian. Hardware-assisted Natural Neighbor Interpolation. 12 | In Proc. 7th Workshop on Algorithm Engineering and Experiments (ALENEX), 2005. 13 | [pdf](https://www.researchgate.net/publication/220981984_Hardware-Assisted_Natural_Neighbor_Interpolation) 14 | 15 | **nn** is coded for robustness (to handle degenerate data) and scalability (to handle millions of data points), subject 16 | to using double precision calculations. For the underlying Delaunay triangulation it calls exact arithmetic code from 17 | [triangle](http://www.cs.cmu.edu/~quake/triangle.html). From v2 it is possible to run **nnbathy** on multiple CPUs with 18 | triangulation stored in shared memory. 19 | 20 | 21 | Checkout **nn** by running `git clone https://github.com/sakov/nn-c`. 22 | -------------------------------------------------------------------------------- /nn/.indent.pro: -------------------------------------------------------------------------------- 1 | --original 2 | 3 | // overwrites to --original 4 | --blank-lines-after-declarations 5 | --blank-lines-after-procedures 6 | --no-blank-lines-after-commas 7 | --declaration-indentation1 8 | --comment-line-length78 9 | --dont-break-procedure-type 10 | --dont-break-function-decl-args 11 | --line-length999 12 | --pointers-to-type-definitions 13 | // works only with the tweaked version of indent 14 | // available from: 15 | // http://www.marine.csiro.au/~sakov/indent-2.2.8a-mod.tar.gz 16 | --swallow-optional-blank-lines 17 | --no-tabs 18 | 19 | // add-ons for my code 20 | --dont-format-first-column-comments // or there will be a mess 21 | -------------------------------------------------------------------------------- /nn/CHANGELOG: -------------------------------------------------------------------------------- 1 | v. 2.0.9, 19 July 2024 2 | -- Made str2double() static everywhere. 3 | v. 2.0.8, 22 March 2024 4 | -- Corrected lpi_build() to improve handling of nearly singular cases 5 | when y12 is nearly 0. 6 | v. 2.0.7, 13 January 2022 7 | -- Removed redundant field "edges" from struct delaunay. Replaced 8 | tio_init() by memsetting to 0. 9 | v. 2.0.6, 20 July 2021 10 | -- Got rid of redundant delaunay_getmemsize() in delaynay.c. 11 | v. 2.0.5, 11 May 2021 12 | -- Added 2nd parallelisation algorithm to nnbathy.c, activated by 13 | -DVIAFILE. 14 | v. 2.0.4, 7 May 2021 15 | -- A minor correction of #if defined for NMAX in nnbathy.c. 16 | -- Reduced MPIBUFSIZE in nnbathy.c from 4096 to 1024. This has a 17 | marginal effect, but seems to work better for larger number of CPUs. 18 | v. 2.0.3, 7 May 2021 19 | -- Tuned a bit the distribution of load in the MPI version of nnbathy. 20 | Now the master interpolates if the number of CPUs <= 3; otherwise it 21 | only collects and writes the results. 22 | v. 2.0.2, 7 May 2021 23 | -- Corrected defect in MPI section of nnbathy.c. 24 | v. 2.0.1, 5 May 2021 25 | -- Added fflush() to points_write(), which seems to be the problem with 26 | large number of CPUs. 27 | v. 2.0.0, 5 May 2021 28 | -- Quite a few structural changes. Split `struct delaunay' into 29 | `struct delaunay' and `struct dsearch'. 30 | -- Put some MPI code into delaunay.c and nnbathy.c. See README and 31 | examples/2/README for details. It targets (but not limited to) very 32 | large datasets. In particular, it puts the triangulation into shared 33 | memory. This shared memory functionality of MPI3 can be stripped by 34 | compiling without -DUSE_SHMEM. 35 | v. 1.86.2, 8 June 2017 36 | -- Minor portability realated changes in hash.[ch] 37 | -- A minor change in makefile 38 | v. 1.86.1, 24 November 2016 39 | -- Some internal changes in hash.c. 40 | v. 1.86.0, 14 March 2016 41 | -- A minor modification in an attempt to alleviate a potential 42 | exception in the degenerate case. Not thoroughly tested yet. 43 | v. 1.85.1, 25 Sep 2015 44 | -- Replaced points_generate2() by points_generate(), seems to work. 45 | This eliminates compilation error for target "tests" -- thanks to 46 | @ocefpaf for the report. 47 | v. 1.85, 1 May 2012 48 | -- A change in nan.h to distinguish between gcc and icc 49 | v. 1.84, 25 January 2012 50 | -- Cosmetic: modified descriptions of nnai and nnhpi. 51 | v. 1.83, 19 January 2012 52 | -- A cosmetic change to avoid compiler warning for delaunay.c 53 | -- Another cosmetic change - updated the list of structure names to be 54 | recognised by `indent' when running "make indent" 55 | v. 1.82, 12 May 2010 56 | -- Modified "configure" to check whether compiler option 57 | "-fno-force-mem" is supported. 58 | v. 1.81, 29 May 2009 59 | -- Added flag NN_SERIAL to the default compiler options for building 60 | nnbathy. 61 | v. 1.80, 12 December 2008 62 | -- Changed the license for compatibility with GPL. Added the file 63 | LICENSE. 64 | v. 1.79, 24 September 2008 65 | -- Fixed some minor deficiencies in `minell' - thanks to Glen Low for 66 | the bug report and extensive testing. This fix does not affect 67 | performance of `nn'. 68 | v. 1.78, 18 January 2008 69 | -- Modified Matlab code in the examples to take care of what seems to 70 | be a new behaviour of RANGE function. 71 | v. 1.77, 19 November 2007 72 | -- Reduced writing the % of the job completed to stderr to the instances 73 | when the reported value has actually changed (with the precision of 74 | 0.1%). 75 | v. 1.76, 16 November 2007 76 | -- Fixed a defect in nnpi_calculate_weights() that caused double 77 | deallocation in some rare cases (a degenerate point on the convex 78 | hall). Thanks for Maciek Sieczka for reporting this bug. 79 | v. 1.75, 30 October 2007 80 | -- Modified delaunay_circles_find() and nnpi_reset(). Got rid of the 81 | non-scalable stuff that slowed down processing of big datasets. 82 | Many thanks to John Gerschwitz, Petroleum Geo-Services, for finding 83 | this defect. 84 | v. 1.74, 30 October 2007 85 | -- Modified treatment of degenerate cases in nnpi_triangle_process(), 86 | many thanks to John Gerschwitz, Petroleum Geo-Services, for exposing 87 | the defect introduced in v. 1.69. Changed EPS_SAME from 1.0e-15 to 88 | 1.0e-8. A number of cosmetic changes. 89 | v. 1.73, 5 July 2007 90 | -- Removed functional code from within assert()s, which caused problems 91 | for production builds on Visual Studio. Thanks to Alok Saldanha for 92 | reporting this defect. 93 | v. 1.72, 4 July 2007 94 | -- Moved division by "denom" in circle_build2() and circle_build1() to 95 | after the check on denom == 0; otherwise division on 0 raised 96 | exception on some systems. Thanks to Alok Saldanha for reporting this 97 | bug. 98 | v. 1.71, 17 January 2007 99 | -- Made the test on whether an output point exactly coincides with 100 | an input point in nnpi_triangle_process() approximate. 101 | v. 1.70, 24 November 2006 102 | -- Added example 6. 103 | v. 1.69, 22 November 2006 104 | -- Substantial changes in processing of the degenerate case for Sibson 105 | interpolation. This is the case when an interpolation point is close 106 | to being in between data points. It is no longer handled by a pair 107 | of symmetric displacements of this point; instead, the center of the 108 | corresponding circumcircle is moved elsewhere in a specific way. 109 | v. 1.68, 28 September 2006 110 | -- Edited README 111 | v. 1.67, 30 August 2006 112 | -- Introduced -% option (available only when built with -DNN_SERIAL) 113 | v. 1.66, 26 June 2006 114 | -- Introduced this file 115 | -- Fixed error in reading the command-line input after "-L" 116 | -- Made a few cosmetic changes 117 | -------------------------------------------------------------------------------- /nn/CUSTOMISE: -------------------------------------------------------------------------------- 1 | # This file is for customizing the configuation process performed by 2 | # `./configure'. This file consists of sh(1) variable-definition lines. 3 | # The value given to those variables by this file will override their default 4 | # values. 5 | # 6 | # Be sure to test whether the variable doesn't exists before setting it. 7 | # 8 | # You can also customize the configuration process via the environment 9 | # variables seen by ./configure. For example: 10 | # 11 | # In csh(1): 12 | # % setenv CC acc 13 | # & setenv CFLAGS -g 14 | # % ./configure 15 | # 16 | # In sh(1) or ksh(1): 17 | # $ CC=acc CFLAGS=-g ./configure 18 | # 19 | # Variables in this file override the environmental ones. 20 | # 21 | ############################################################################# 22 | 23 | # C compiler 24 | if [ -z "$CC" ]; then 25 | CC=gcc 26 | fi 27 | 28 | # C compiler flags 29 | if [ -z "$CFLAGS" ]; then 30 | CFLAGS="-g -O2 -Wall -pedantic -D_GNU_SOURCE -std=c99" 31 | fi 32 | 33 | CFLAGS_TRIANGLE="-O2 -w -ffloat-store" 34 | CFLAGS_VULNERABLE="-ffloat-store" 35 | 36 | # Installation prefix (default is /usr/local) 37 | if [ "${prefix}" = "NONE" ]; then 38 | prefix=/usr/local 39 | fi 40 | 41 | if [ "${libdir}" = "\${exec_prefix}/lib" ]; then 42 | libdir="${prefix}/lib${LIBEXT}" 43 | fi 44 | 45 | echo "Using prefix ${prefix}" 46 | echo "Using libdir ${libdir}" 47 | -------------------------------------------------------------------------------- /nn/LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (C) 2000-2008 Pavel Sakov and CSIRO 2 | 3 | Redistribution and use of material from the package `nn', with or without 4 | modification, are permitted provided that the following conditions are 5 | met: 6 | 7 | 1. Redistributions of material must retain the above copyright notice, this 8 | list of conditions and the following disclaimer. 9 | 2. The names of the authors may not be used to endorse or promote products 10 | derived from this software without specific prior written permission. 11 | 12 | THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR IMPLIED 13 | WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 14 | MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO 15 | EVENT SHALL THE AUTHORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 16 | EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT 17 | OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 18 | INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 19 | CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING 20 | IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY 21 | OF SUCH DAMAGE. 22 | 23 | Note: this software makes use of the Triangle software, which is non-free for 24 | commercial use. See the triangle.c and triangle.h files for details. 25 | -------------------------------------------------------------------------------- /nn/README: -------------------------------------------------------------------------------- 1 | nn 2 | Natural Neighbours interpolation library 3 | Version 1.86 4 | 5 | Provides Natural Neighbours interpolation library "libnn.a" and a command line 6 | Natural Neighbours interpolation utility "nnbathy". 7 | 8 | `nn' is a free software. See LICENSE for details. 9 | 10 | (Note that however that `triangle' is not a free softwre.) 11 | 12 | Please send comments and bugs to Pavel.Sakovgmail.com . 13 | 14 | 15 | 1. This code has been developed and used mainly on pc-linux platform, however, 16 | it should compile on other platforms. Beware that the configure script 17 | currently does not do much more than a couple of checks. It should be viewed 18 | rather as a prototype for the future than a multi-platform configuration tool. 19 | 20 | `nn' was initially based on the Dave Watson's `nngridr'. Over time, there were 21 | numerous improvements of this original version. You may see comparison of 22 | performance of a rather old version `nn' with `nngridr' in 23 | 24 | Quanfu Fan, Alon Efrat, Vladlen Koltun, Shankar Krishnan, and 25 | Suresh Venkatasubramanian. Hardware-assisted Natural Neighbor Interpolation. 26 | In Proc. 7th Workshop on Algorithm Engineering and Experiments (ALENEX), 2005. 27 | 28 | Note that the current version of `nn' outperforms the version tested in the 29 | above paper both in terms of scalability and robustness. 30 | 31 | 32 | 2. To compile, run: 33 | 34 | configure 35 | make 36 | (make install) 37 | 38 | For a few quick tests, run: 39 | 40 | make tests 41 | ./nnphi_test 42 | ./nnai_test 43 | ./ht_test 44 | 45 | From v2.0.0 some MPI code has been added to delaunay.c and nnbathy.c. To compile 46 | it change "MPI = no" in the makefile to "MPI = yes". To test MPI code run 47 | "make mpi" and "make cmp" in examples/2. 48 | 49 | 3. Apart from the `nn' library, this code contains `nnbathy' -- a simple 50 | interpolation utility/example based on `nn'. 51 | 52 | Initially, `nnbathy' has been introduced to provide an example of using library 53 | functions from `nn'. Later, evolving along with user requests, it became a quite 54 | functional command-line utility. 55 | 56 | 57 | 4. There are a number of examples of using `nnbathy' in "examples" directory: 58 | 59 | examples/1 -- reconstruction of Franke test function 60 | examples/2 -- reconstruction of bathymetry from sonar data 61 | examples/3 -- performance on degenerate data 62 | examples/4 -- reconstruction of topography from satellite altimeter data 63 | examples/5 -- reconstruction of topography from digitised contours 64 | examples/6 -- reconstruction of topography from digitised contours 65 | 66 | These examples has been put up over a a number of years. Some of them used to 67 | cause failures for the older versions of the code. See examples/README for 68 | descriptions. 69 | 70 | 71 | 5. Calling `nn' code from a client code is supposed to be straightforward and 72 | simple. Have a look at nnbathy.c for an example. For a basic description of 73 | structures and functions available from `nn', have a look at "nn.h". 74 | 75 | 76 | 6. Acknowledgments: 77 | 78 | This library uses the following public code/algorithms: 79 | 1. `triangle' by Jonathan Richard Shewchuk -- for Delaunay triangulation; 80 | 2. Dave Watson's algorithm for Sibson interpolation; 81 | 3. Belikov and Semenov's formulas for non-Sibsonian interpolation. 82 | 83 | Many thanks to David A. Paige, Maciek Sieczka, Nick Cahill and John Gerschwitz 84 | for submitting bug reports and/or data for examples. 85 | 86 | 87 | 7. Please acknowledge the use of this software in publications. 88 | 89 | Good luck! 90 | Pavel Sakov 91 | -------------------------------------------------------------------------------- /nn/config.h.in: -------------------------------------------------------------------------------- 1 | #if defined(_WIN32) 2 | #define isnan _isnan 3 | #define copysign _copysign 4 | #define rint (int) 5 | #define M_PI 3.14159265358979323846 6 | #define TRILIBRARY 7 | #define NO_TIMER 8 | #endif 9 | -------------------------------------------------------------------------------- /nn/configure.in: -------------------------------------------------------------------------------- 1 | dnl Configure.in for nn 2 | 3 | AC_INIT(CUSTOMISE) 4 | AC_CONFIG_HEADER(config.h) 5 | 6 | AC_DEFUN(AC_FIND_HEADER, 7 | [AC_MSG_CHECKING(for $1) 8 | header_path= 9 | found_header=no 10 | # Look for the header file in a standard set of common directories. 11 | for ac_dir in \ 12 | $includedir \ 13 | $prefix/include \ 14 | $secondary_prefix/include \ 15 | /usr/include \ 16 | /usr/include/sys \ 17 | /opt/gnu/include \ 18 | /opt/misc/include \ 19 | /usr/local/include \ 20 | ; \ 21 | do 22 | if test -r "$ac_dir/$1"; then 23 | header_path=$ac_dir 24 | found_header=yes 25 | break 26 | fi 27 | done 28 | AC_MSG_RESULT($found_header) 29 | 30 | test "$found_header" = yes && $2 31 | test "$found_header" = no && $3 32 | ]) 33 | 34 | AC_DEFUN(AC_FIND_LIB, 35 | [AC_MSG_CHECKING(for -l$1) 36 | rqst_lib=$1 37 | lib_path= 38 | found_lib=no 39 | # Look for the library file in a standard set of common directories. 40 | for ac_dir in \ 41 | $libdir \ 42 | $prefix/lib${LIBEXT} \ 43 | $secondary_prefix/lib${LIBEXT} \ 44 | /usr/lib${LIBEXT} \ 45 | /usr/unsupported/lib${LIBEXT} \ 46 | /opt/gnu/lib${LIBEXT} \ 47 | /opt/misc/lib${LIBEXT} \ 48 | /usr/local/lib${LIBEXT} \ 49 | ; \ 50 | do 51 | for ac_extension in a so sl; do 52 | if test -r $ac_dir/lib${rqst_lib}.$ac_extension; then 53 | lib_path=$ac_dir 54 | found_lib=yes 55 | break 2 56 | fi 57 | done 58 | done 59 | AC_MSG_RESULT($found_lib) 60 | 61 | test "$found_lib" = yes && $2 62 | test "$found_lib" = no && $3 63 | ]) 64 | 65 | dnl Get the shell variable to override local customisations. 66 | AC_DEFUN([AC_CUSTOMISE], 67 | [dnl 68 | AC_BEFORE([$0], [AC_DEFAULT])dnl 69 | if test -r CUSTOMISE; then 70 | . ./CUSTOMISE 71 | fi 72 | ]) 73 | 74 | AC_CUSTOMISE 75 | 76 | dnl Checks for programs. 77 | AC_PROG_CC 78 | AC_PROG_INSTALL 79 | AC_CHECK_PROG(AR, ar, ar, :) 80 | 81 | dnl Checks for header files. 82 | AC_HEADER_STDC 83 | AC_CHECK_HEADERS(math.h,,AC_MSG_ERROR([unable to find header])) 84 | 85 | dnl Checks for typedefs, structures, and compiler characteristics. 86 | 87 | dnl Check for libraries. 88 | AC_HAVE_LIBRARY(m,,AC_MSG_ERROR([unable to find library])) 89 | 90 | dnl Checks for library functions. 91 | AC_CHECK_FUNCS(realloc strtod strtok hypot,,AC_MSG_ERROR([unable to find function])) 92 | 93 | dnl check compiler option "-fno-force-mem" 94 | OLD_CFLAGS=$CFLAGS 95 | CFLAGS="$CFLAGS -fno-force-mem" 96 | AC_MSG_CHECKING(for -fno-force-mem option) 97 | AC_CACHE_VAL(ac_cv_fnoforcemem, 98 | AC_TRY_COMPILE([], [char a;], ac_cv_fnoforcemem=yes, ac_cv_fnoforcemem=no)) 99 | echo $ac_cv_fnoforcemem 100 | if test $ac_cv_fnoforcemem = no; then 101 | CFLAGS=$OLD_CFLAGS 102 | fi 103 | 104 | if test "$ac_cv_fnoforcemem" = yes; then 105 | CFLAGS_VULNERABLE="$CFLAGS_VULNERABLE -fno-force-mem" 106 | fi 107 | 108 | AC_SUBST(CC) 109 | AC_SUBST(CFLAGS) 110 | AC_SUBST(LDFLAGS) 111 | AC_SUBST(CFLAGS_TRIANGLE) 112 | AC_SUBST(CFLAGS_VULNERABLE) 113 | 114 | AC_OUTPUT(makefile) 115 | -------------------------------------------------------------------------------- /nn/delaunay.c: -------------------------------------------------------------------------------- 1 | /****************************************************************************** 2 | * 3 | * File: delaunay.c 4 | * 5 | * Created: 04/08/2000 6 | * 7 | * Author: Pavel Sakov 8 | * CSIRO Marine Research 9 | * 10 | * Purpose: Delaunay triangulation - a wrapper to triangulate() 11 | * 12 | * Description: None 13 | * 14 | * Revisions: 10/06/2003 PS: delaunay_build(); delaunay_destroy(); 15 | * struct delaunay: from now on, only shallow copy of the 16 | * input data is contained in struct delaunay. This saves 17 | * memory and is consistent with libcsa. 18 | * 30/10/2007 PS: added delaunay_addflag() and 19 | * delaunay_resetflags(); modified delaunay_circles_find() 20 | * to reset the flags to 0 on return. This is very important 21 | * for large datasets, many thanks to John Gerschwitz, 22 | * Petroleum Geo-Services, for identifying the problem. 23 | * 05/05/2021 PS: added MPI code. 24 | * 25 | *****************************************************************************/ 26 | 27 | #define ANSI_DECLARATORS /* for triangle.h */ 28 | 29 | #include 30 | #include 31 | #include 32 | #include 33 | #include 34 | #include 35 | #include 36 | #include "triangle.h" 37 | #include "istack_internal.h" 38 | #include "nn.h" 39 | #include "nncommon.h" 40 | #include "delaunay_internal.h" 41 | 42 | #if defined(MPI) 43 | #include 44 | 45 | int nprocesses = 1; 46 | int rank = 0; 47 | 48 | #if defined(USE_SHMEM) 49 | /* 50 | * "sm" stands for "shared memory" 51 | */ 52 | MPI_Comm sm_comm = MPI_COMM_NULL; 53 | int sm_comm_rank = -1; 54 | int sm_comm_size = 0; 55 | #endif 56 | extern int make_iso_compilers_happy; 57 | #endif /* MPI */ 58 | 59 | /* 60 | * This parameter is used in search of tricircles containing a given point: 61 | * if there are no more triangles than N_SEARCH_TURNON 62 | * do linear search 63 | * else 64 | * do more complicated stuff 65 | */ 66 | #define N_SEARCH_TURNON 20 67 | #define N_FLAGS_TURNON 1000 68 | #define N_FLAGS_INC 100 69 | 70 | static void tio_destroy(struct triangulateio* tio) 71 | { 72 | if (tio->pointlist != NULL) 73 | free(tio->pointlist); 74 | if (tio->pointattributelist != NULL) 75 | free(tio->pointattributelist); 76 | if (tio->pointmarkerlist != NULL) 77 | free(tio->pointmarkerlist); 78 | if (tio->trianglelist != NULL) 79 | free(tio->trianglelist); 80 | if (tio->triangleattributelist != NULL) 81 | free(tio->triangleattributelist); 82 | if (tio->trianglearealist != NULL) 83 | free(tio->trianglearealist); 84 | if (tio->neighborlist != NULL) 85 | free(tio->neighborlist); 86 | if (tio->segmentlist != NULL) 87 | free(tio->segmentlist); 88 | if (tio->segmentmarkerlist != NULL) 89 | free(tio->segmentmarkerlist); 90 | if (tio->holelist != NULL) 91 | free(tio->holelist); 92 | if (tio->regionlist != NULL) 93 | free(tio->regionlist); 94 | if (tio->edgelist != NULL) 95 | free(tio->edgelist); 96 | if (tio->edgemarkerlist != NULL) 97 | free(tio->edgemarkerlist); 98 | if (tio->normlist != NULL) 99 | free(tio->normlist); 100 | } 101 | 102 | static delaunay* delaunay_create() 103 | { 104 | delaunay* d = calloc(1, sizeof(delaunay)); 105 | 106 | d->xmin = DBL_MAX; 107 | d->xmax = -DBL_MAX; 108 | d->ymin = DBL_MAX; 109 | d->ymax = -DBL_MAX; 110 | 111 | return d; 112 | } 113 | 114 | static void tio2delaunay(struct triangulateio* tio, delaunay* d, void* data) 115 | { 116 | int i, j; 117 | 118 | if (tio != NULL) { 119 | 120 | /* 121 | * I assume that all input points appear in tio in the same order 122 | * as they were written to tio_in. I have seen no exceptions so far, 123 | * even if duplicate points were presented. Just in case, let us make 124 | * a couple of checks. 125 | */ 126 | assert(tio->numberofpoints == d->npoints); 127 | assert(tio->pointlist[2 * d->npoints - 2] == d->points[d->npoints - 1].x && tio->pointlist[2 * d->npoints - 1] == d->points[d->npoints - 1].y); 128 | 129 | d->ntriangles = tio->numberoftriangles; 130 | } 131 | #if defined(USE_SHMEM) 132 | MPI_Bcast(&d->ntriangles, 1, MPI_INT, 0, MPI_COMM_WORLD); 133 | #endif 134 | 135 | d->triangles = data; 136 | d->neighbours = (triangle_neighbours*) &d->triangles[d->ntriangles]; 137 | d->circles = (circle*) &d->neighbours[d->ntriangles]; 138 | d->n_point_triangles = (int*) &d->circles[d->ntriangles]; 139 | d->point_triangles_offset = (int*) &d->n_point_triangles[d->npoints]; 140 | d->point_triangles = (int*) &d->point_triangles_offset[d->npoints]; 141 | 142 | if (tio != NULL) { 143 | if (nn_verbose) 144 | fprintf(stderr, "triangles:\n"); 145 | for (i = 0; i < d->ntriangles; ++i) { 146 | int offset = i * 3; 147 | triangle* t = &d->triangles[i]; 148 | triangle_neighbours* n = &d->neighbours[i]; 149 | circle* c = &d->circles[i]; 150 | int status; 151 | 152 | t->vids[0] = tio->trianglelist[offset]; 153 | t->vids[1] = tio->trianglelist[offset + 1]; 154 | t->vids[2] = tio->trianglelist[offset + 2]; 155 | 156 | n->tids[0] = tio->neighborlist[offset]; 157 | n->tids[1] = tio->neighborlist[offset + 1]; 158 | n->tids[2] = tio->neighborlist[offset + 2]; 159 | 160 | status = circle_build1(c, &d->points[t->vids[0]], &d->points[t->vids[1]], &d->points[t->vids[2]]); 161 | assert(status); 162 | 163 | if (nn_verbose) 164 | fprintf(stderr, " %d: (%d,%d,%d)\n", i, t->vids[0], t->vids[1], t->vids[2]); 165 | } 166 | 167 | for (i = 0; i < d->ntriangles; ++i) { 168 | triangle* t = &d->triangles[i]; 169 | 170 | for (j = 0; j < 3; ++j) 171 | d->n_point_triangles[t->vids[j]]++; 172 | } 173 | for (i = 1; i < d->npoints; ++i) 174 | d->point_triangles_offset[i] = d->point_triangles_offset[i - 1] + d->n_point_triangles[i - 1]; 175 | memset(d->n_point_triangles, 0, d->npoints * sizeof(int)); 176 | 177 | for (i = 0; i < d->ntriangles; ++i) { 178 | triangle* t = &d->triangles[i]; 179 | 180 | for (j = 0; j < 3; ++j) { 181 | int vid = t->vids[j]; 182 | 183 | d->point_triangles[d->point_triangles_offset[vid] + d->n_point_triangles[vid]] = i; 184 | d->n_point_triangles[vid]++; 185 | } 186 | } 187 | } 188 | #if defined(USE_SHMEM) 189 | MPI_Win_fence(0, d->sm_win_delaunaydata); 190 | MPI_Barrier(sm_comm); 191 | #endif 192 | } 193 | 194 | static size_t delaunay_getdatasize(struct triangulateio* tio) 195 | { 196 | return tio->numberoftriangles * (sizeof(triangle) + sizeof(triangle_neighbours) + sizeof(circle) + sizeof(int) * 3) + tio->numberofpoints * sizeof(int) * 2; 197 | } 198 | 199 | /* Builds Delaunay triangulation of the given array of points. 200 | * 201 | * @param np Number of points 202 | * @param points Array of points [np] (input) 203 | * @param ns Number of forced segments 204 | * @param segments Array of (forced) segment endpoint indices [2*ns] 205 | * @param nh Number of holes 206 | * @param holes Array of hole (x,y) coordinates [2*nh] 207 | * @return Delaunay triangulation structure with triangulation results 208 | */ 209 | delaunay* delaunay_build(int np, point points[], int ns, int segments[], int nh, double holes[]) 210 | { 211 | delaunay* d = NULL; 212 | struct triangulateio tio_in; 213 | struct triangulateio tio_out; 214 | int i, j; 215 | 216 | #if defined(USE_SHMEM) 217 | int ntriangles; 218 | 219 | if (sm_comm_rank == 0) { 220 | #endif 221 | char cmd[64] = "eznC"; 222 | 223 | if (np == 0) 224 | return NULL; 225 | 226 | assert(sizeof(REAL) == sizeof(double)); 227 | 228 | memset(&tio_in, 0, sizeof(struct triangulateio)); 229 | memset(&tio_out, 0, sizeof(struct triangulateio)); 230 | 231 | tio_in.pointlist = malloc(np * 2 * sizeof(double)); 232 | tio_in.numberofpoints = np; 233 | for (i = 0, j = 0; i < np; ++i) { 234 | tio_in.pointlist[j++] = points[i].x; 235 | tio_in.pointlist[j++] = points[i].y; 236 | } 237 | 238 | if (ns > 0) { 239 | tio_in.segmentlist = malloc(ns * 2 * sizeof(int)); 240 | tio_in.numberofsegments = ns; 241 | memcpy(tio_in.segmentlist, segments, ns * 2 * sizeof(int)); 242 | } 243 | 244 | if (nh > 0) { 245 | tio_in.holelist = malloc(nh * 2 * sizeof(double)); 246 | tio_in.numberofholes = nh; 247 | memcpy(tio_in.holelist, holes, nh * 2 * sizeof(double)); 248 | } 249 | 250 | if (!nn_verbose) 251 | strcat(cmd, "Q"); 252 | else if (nn_verbose > 1) 253 | strcat(cmd, "VV"); 254 | if (ns != 0) 255 | strcat(cmd, "p"); 256 | 257 | if (nn_verbose) 258 | fflush(stderr); 259 | 260 | /* 261 | * climax 262 | */ 263 | triangulate(cmd, &tio_in, &tio_out, NULL); 264 | 265 | if (nn_verbose) 266 | fflush(stderr); 267 | 268 | #if defined(USE_SHMEM) 269 | ntriangles = tio_out.numberoftriangles; 270 | } 271 | (void) MPI_Bcast(&ntriangles, 1, MPI_INT, 0, MPI_COMM_WORLD); 272 | if (ntriangles == 0) 273 | goto finish; 274 | #endif 275 | 276 | #if !defined(USE_SHMEM) 277 | if (tio_out.numberoftriangles == 0) 278 | goto finish; 279 | #endif 280 | 281 | d = delaunay_create(); 282 | d->npoints = np; 283 | d->points = points; /* (shallow copy) */ 284 | for (i = 0, j = 0; i < np; ++i) { 285 | point* p = &points[i]; 286 | 287 | if (p->x < d->xmin) 288 | d->xmin = p->x; 289 | if (p->x > d->xmax) 290 | d->xmax = p->x; 291 | if (p->y < d->ymin) 292 | d->ymin = p->y; 293 | if (p->y > d->ymax) 294 | d->ymax = p->y; 295 | } 296 | 297 | #if defined(USE_SHMEM) 298 | if (sm_comm_rank == 0) { 299 | #endif 300 | if (nn_verbose) { 301 | fprintf(stderr, "input:\n"); 302 | for (i = 0, j = 0; i < d->npoints; ++i) { 303 | point* p = &d->points[i]; 304 | 305 | fprintf(stderr, " %d: %15.7g %15.7g %15.7g\n", i, p->x, p->y, p->z); 306 | } 307 | } 308 | #if defined(USE_SHMEM) 309 | } 310 | #endif 311 | 312 | { 313 | size_t size = 0; 314 | void* data = NULL; 315 | 316 | #if !defined(USE_SHMEM) 317 | size = delaunay_getdatasize(&tio_out); 318 | data = calloc(1, size); 319 | #else 320 | if (rank == 0) { 321 | size = delaunay_getdatasize(&tio_out); 322 | assert(sizeof(size_t) == sizeof(MPI_UNSIGNED_LONG)); 323 | } 324 | (void) MPI_Bcast(&size, 1, MPI_UNSIGNED_LONG, 0, MPI_COMM_WORLD); 325 | 326 | (void) MPI_Win_allocate_shared((sm_comm_rank == 0) ? size : 0, sizeof(char), MPI_INFO_NULL, sm_comm, &data, &d->sm_win_delaunaydata); 327 | if (sm_comm_rank == 0) { 328 | memset(data, 0, size); 329 | if (nn_verbose) 330 | fprintf(stderr, " MPI: put %u bytes of triangulation data into shared memory\n", (unsigned int) size); 331 | } else { 332 | int disp_unit; 333 | MPI_Aint my_size; 334 | 335 | MPI_Win_shared_query(d->sm_win_delaunaydata, 0, &my_size, &disp_unit, &data); 336 | assert(my_size == size); 337 | assert(disp_unit == sizeof(char)); 338 | assert(data != NULL); 339 | } 340 | MPI_Win_fence(0, d->sm_win_delaunaydata); 341 | MPI_Barrier(sm_comm); 342 | #endif 343 | 344 | #if defined(USE_SHMEM) 345 | if (sm_comm_rank == 0) 346 | #endif 347 | tio2delaunay(&tio_out, d, data); 348 | #if defined(USE_SHMEM) 349 | else 350 | tio2delaunay(NULL, d, data); 351 | #endif 352 | } 353 | 354 | finish: 355 | #if defined(USE_SHMEM) 356 | if (sm_comm_rank == 0) { 357 | #endif 358 | tio_destroy(&tio_in); 359 | tio_destroy(&tio_out); 360 | #if defined(USE_SHMEM) 361 | } 362 | #endif 363 | 364 | return d; 365 | } 366 | 367 | /** Destroys Delaunay triangulation. 368 | * 369 | * @param d Structure to be destroyed 370 | */ 371 | void delaunay_destroy(delaunay* d) 372 | { 373 | if (d == NULL) 374 | return; 375 | 376 | #if !defined(USE_SHMEM) 377 | if (d->triangles != NULL) 378 | free(d->triangles); 379 | #else 380 | MPI_Win_free(&d->sm_win_delaunaydata); 381 | #endif 382 | free(d); 383 | } 384 | 385 | /** 386 | */ 387 | dsearch* dsearch_build(delaunay* d) 388 | { 389 | dsearch* ds = calloc(1, sizeof(dsearch)); 390 | 391 | ds->d = d; 392 | ds->first_id = -1; 393 | if (d->ntriangles > 0) 394 | ds->flags = calloc(d->ntriangles, sizeof(int)); 395 | 396 | return ds; 397 | } 398 | 399 | /** 400 | */ 401 | void dsearch_destroy(dsearch* ds) 402 | { 403 | if (ds->flags != NULL) 404 | free(ds->flags); 405 | if (ds->t_in != NULL) 406 | istack_destroy(ds->t_in); 407 | if (ds->t_out != NULL) 408 | istack_destroy(ds->t_out); 409 | if (ds->flagids != NULL) 410 | free(ds->flagids); 411 | free(ds); 412 | } 413 | 414 | /* Returns whether the point p is on the right side of the vector (p0, p1). 415 | */ 416 | static int onrightside(point* p, point* p0, point* p1) 417 | { 418 | return (p1->x - p->x) * (p0->y - p->y) > (p0->x - p->x) * (p1->y - p->y); 419 | } 420 | 421 | /* Finds triangle specified point belongs to (if any). 422 | * 423 | * @param d Delaunay triangulation 424 | * @param p Point to be mapped 425 | * @param seed Triangle index to start with 426 | * @return Triangle id if successful, -1 otherwhile 427 | */ 428 | int delaunay_xytoi(delaunay* d, point* p, int id) 429 | { 430 | triangle* t; 431 | int i; 432 | 433 | if (p->x < d->xmin || p->x > d->xmax || p->y < d->ymin || p->y > d->ymax) 434 | return -1; 435 | 436 | if (id < 0 || id > d->ntriangles) 437 | id = 0; 438 | t = &d->triangles[id]; 439 | do { 440 | for (i = 0; i < 3; ++i) { 441 | int i1 = (i + 1) % 3; 442 | 443 | if (onrightside(p, &d->points[t->vids[i]], &d->points[t->vids[i1]])) { 444 | id = d->neighbours[id].tids[(i + 2) % 3]; 445 | if (id < 0) 446 | return id; 447 | t = &d->triangles[id]; 448 | break; 449 | } 450 | } 451 | } while (i < 3); 452 | 453 | return id; 454 | } 455 | 456 | static void dsearch_addflag(dsearch* ds, int i) 457 | { 458 | if (ds->nflags == ds->nflagsallocated) { 459 | ds->nflagsallocated += N_FLAGS_INC; 460 | ds->flagids = realloc(ds->flagids, ds->nflagsallocated * sizeof(int)); 461 | } 462 | ds->flagids[ds->nflags] = i; 463 | ds->nflags++; 464 | } 465 | 466 | static void dsearch_resetflags(dsearch* ds) 467 | { 468 | int i; 469 | 470 | for (i = 0; i < ds->nflags; ++i) 471 | ds->flags[ds->flagids[i]] = 0; 472 | ds->nflags = 0; 473 | } 474 | 475 | /** Find all tricircles specified point belongs to. 476 | * 477 | * @param ds `dsearch' structure 478 | * @param p Point to be mapped 479 | * @param n Pointer to the number of tricircles within `d' containing `p' 480 | * (output) 481 | * @param out Pointer to an array of indices of the corresponding triangles 482 | * [n] (output) 483 | * 484 | * There is a standard search procedure involving search through triangle 485 | * neighbours (not through vertex neighbours). It must be a bit faster due to 486 | * the smaller number of triangle neighbours (3 per triangle) but may fail 487 | * for a point outside convex hall. 488 | * 489 | * We may wish to modify this procedure in future: first check if the point 490 | * is inside the convex hall, and depending on that use one of the two 491 | * search algorithms. It not 100% clear though whether this will lead to a 492 | * substantial speed gains because of the check on convex hall involved. 493 | */ 494 | void dsearch_circles_find(dsearch* ds, point* p, int* n, int** out) 495 | { 496 | delaunay* d = ds->d; 497 | 498 | /* 499 | * This flag was introduced as a hack to handle some degenerate cases. It 500 | * is set to 1 only if the triangle associated with the first circle is 501 | * already known to contain the point. In this case the circle is assumed 502 | * to contain the point without a check. In my practice this turned 503 | * useful in some cases when point p coincided with one of the vertices 504 | * of a thin triangle. 505 | */ 506 | int contains = 0; 507 | int i; 508 | 509 | if (ds->t_in == NULL) { 510 | ds->t_in = istack_create(); 511 | ds->t_out = istack_create(); 512 | } 513 | 514 | /* 515 | * if there are only a few data points, do linear search 516 | */ 517 | if (d->ntriangles <= N_SEARCH_TURNON) { 518 | istack_reset(ds->t_out); 519 | 520 | for (i = 0; i < d->ntriangles; ++i) { 521 | if (circle_contains(&d->circles[i], p)) { 522 | istack_push(ds->t_out, i); 523 | } 524 | } 525 | 526 | *n = ds->t_out->n; 527 | *out = ds->t_out->v; 528 | 529 | return; 530 | } 531 | /* 532 | * otherwise, do a more complicated stuff 533 | */ 534 | 535 | /* 536 | * It is important to have a reasonable seed here. If the last search 537 | * was successful -- start with the last found tricircle, otherwhile (i) 538 | * try to find a triangle containing p; if fails then (ii) check 539 | * tricircles from the last search; if fails then (iii) make linear 540 | * search through all tricircles 541 | */ 542 | if (ds->first_id < 0 || !circle_contains(&d->circles[ds->first_id], p)) { 543 | /* 544 | * if any triangle contains p -- start with this triangle 545 | */ 546 | ds->first_id = delaunay_xytoi(d, p, ds->first_id); 547 | contains = (ds->first_id >= 0); 548 | 549 | /* 550 | * if no triangle contains p, there still is a chance that it is 551 | * inside some of circumcircles 552 | */ 553 | if (ds->first_id < 0) { 554 | int nn = ds->t_out->n; 555 | int tid = -1; 556 | 557 | /* 558 | * first check results of the last search 559 | */ 560 | for (i = 0; i < nn; ++i) { 561 | tid = ds->t_out->v[i]; 562 | if (circle_contains(&d->circles[tid], p)) 563 | break; 564 | } 565 | /* 566 | * if unsuccessful, search through all circles 567 | */ 568 | if (tid < 0 || i == nn) { 569 | double nt = d->ntriangles; 570 | 571 | for (tid = 0; tid < nt; ++tid) { 572 | if (circle_contains(&d->circles[tid], p)) 573 | break; 574 | } 575 | if (tid == nt) { 576 | istack_reset(ds->t_out); 577 | *n = 0; 578 | *out = NULL; 579 | return; /* failed */ 580 | } 581 | } 582 | ds->first_id = tid; 583 | } 584 | } 585 | 586 | istack_reset(ds->t_in); 587 | istack_reset(ds->t_out); 588 | 589 | istack_push(ds->t_in, ds->first_id); 590 | ds->flags[ds->first_id] = 1; 591 | dsearch_addflag(ds, ds->first_id); 592 | 593 | /* 594 | * main cycle 595 | */ 596 | while (ds->t_in->n > 0) { 597 | int tid = istack_pop(ds->t_in); 598 | triangle* t = &d->triangles[tid]; 599 | 600 | if (contains || circle_contains(&d->circles[tid], p)) { 601 | istack_push(ds->t_out, tid); 602 | for (i = 0; i < 3; ++i) { 603 | int vid = t->vids[i]; 604 | int nt = d->n_point_triangles[vid]; 605 | int j; 606 | 607 | for (j = 0; j < nt; ++j) { 608 | int ntid = d->point_triangles[d->point_triangles_offset[vid] + j]; 609 | 610 | if (ds->flags[ntid] == 0) { 611 | istack_push(ds->t_in, ntid); 612 | ds->flags[ntid] = 1; 613 | dsearch_addflag(ds, ntid); 614 | } 615 | } 616 | } 617 | } 618 | contains = 0; 619 | } 620 | 621 | *n = ds->t_out->n; 622 | *out = ds->t_out->v; 623 | dsearch_resetflags(ds); 624 | } 625 | -------------------------------------------------------------------------------- /nn/delaunay.h: -------------------------------------------------------------------------------- 1 | /****************************************************************************** 2 | * 3 | * File: delaunay.h 4 | * 5 | * Created: 04/08/2000 6 | * 7 | * Author: Pavel Sakov 8 | * CSIRO Marine Research 9 | * 10 | * Purpose: Header for delaunay triangulation wrapper 11 | * 12 | * Description: None 13 | * 14 | * Revisions: 30/10/2007 PS: Added fields nflags, nflagsallocated and 15 | * flagids for flag accounting, to make it possible to reset 16 | * only engaged flags rather than the whole array. 17 | * 18 | *****************************************************************************/ 19 | 20 | #if !defined(_DELAUNAY_H) 21 | #define _DELAUNAY_H 22 | 23 | typedef struct { 24 | int vids[3]; 25 | } triangle; 26 | 27 | typedef struct { 28 | int tids[3]; 29 | } triangle_neighbours; 30 | 31 | #if !defined(_STRUCT_DELAUNAY) 32 | #define _STRUCT_DELAUNAY 33 | struct delaunay; 34 | typedef struct delaunay delaunay; 35 | #endif 36 | 37 | delaunay* delaunay_build(int np, point points[], int ns, int segments[], int nh, double holes[]); 38 | void delaunay_destroy(delaunay* d); 39 | 40 | #if defined(MPI) 41 | #include 42 | 43 | extern int nprocesses; 44 | extern int rank; 45 | 46 | #if defined(USE_SHMEM) 47 | /* 48 | * "sm" stands for "shared memory" 49 | */ 50 | extern MPI_Comm sm_comm; 51 | extern int sm_comm_rank; 52 | extern int sm_comm_size; 53 | #endif 54 | #endif 55 | 56 | #endif 57 | -------------------------------------------------------------------------------- /nn/delaunay_internal.h: -------------------------------------------------------------------------------- 1 | /****************************************************************************** 2 | * 3 | * File: delaunay_internal.h 4 | * 5 | * Created: 05/05/2021 6 | * 7 | * Author: Pavel Sakov 8 | * BoM 9 | * 10 | * Purpose: Internal header for delaunay triangulation. 11 | * 12 | * Description: Internal header for delaunay triangulation. 13 | * Revisions: 14 | * 15 | *****************************************************************************/ 16 | 17 | #if !defined(_DELAUNAY_INTERNAL_H) 18 | #define _DELAUNAY_INTERNAL_H 19 | 20 | #if defined(MPI) 21 | #include 22 | #endif 23 | #include "istack.h" 24 | #include "delaunay.h" 25 | 26 | /** Structure to perform the Delaunay triangulation of a given array of points. 27 | * 28 | * Contains a deep copy of the input array of points. 29 | * Contains triangles, circles and edges resulted from the triangulation. 30 | * Contains neighbour triangles for each triangle. 31 | * Contains point to triangle map. 32 | */ 33 | struct delaunay { 34 | int npoints; 35 | point* points; 36 | double xmin; 37 | double xmax; 38 | double ymin; 39 | double ymax; 40 | 41 | int ntriangles; 42 | 43 | triangle* triangles; 44 | circle* circles; 45 | triangle_neighbours* neighbours; /* for delaunay_xytoi() */ 46 | int* n_point_triangles; /* n_point_triangles[i] is number of 47 | * triangles i-th point belongs to */ 48 | int* point_triangles_offset; 49 | int* point_triangles; /* point_triangles[point_triangles_offset[i] 50 | * + j] is the index of j-th triangle i-th 51 | * point belongs to */ 52 | 53 | #if defined(USE_SHMEM) 54 | MPI_Win sm_win_delaunaydata; 55 | #endif 56 | }; 57 | 58 | typedef struct { 59 | delaunay* d; 60 | 61 | int ntriangles; 62 | int* flags; 63 | int first_id; /* last search result, used in start up of a 64 | * new search */ 65 | istack* t_in; 66 | istack* t_out; 67 | 68 | /* 69 | * to keep track of flags set to 1 in the case of very large data sets 70 | */ 71 | int nflags; 72 | int nflagsallocated; 73 | int* flagids; 74 | } dsearch; 75 | 76 | int delaunay_xytoi(delaunay* d, point* p, int seed); 77 | 78 | dsearch* dsearch_build(delaunay* d); 79 | void dsearch_destroy(dsearch* ds); 80 | void dsearch_circles_find(dsearch* d, point* p, int* n, int** out); 81 | 82 | #endif /* _DELAUNAY_INTERNAL_H */ 83 | -------------------------------------------------------------------------------- /nn/distribute.c: -------------------------------------------------------------------------------- 1 | /****************************************************************************** 2 | * 3 | * File: distribute.c 4 | * 5 | * Created: 12/2012 6 | * 7 | * Author: Pavel Sakov 8 | * Bureau of Meteorology 9 | * 10 | * Description: Distributes indices in the interval [i1, i2] between `nproc' 11 | * processes. Process IDs are assumed to be in the interval 12 | * [0, nproc-1]. The calling process has ID `rank'. The results 13 | * are stored in 6 global variables, with the following relations 14 | * between them: 15 | * my_number_of_iterations = my_last_iteration 16 | * - my_first_iteration + 1 17 | * my_number_of_iterations = number_of_iterations[rank] 18 | * my_first_iteration = first_iteratin[rank] 19 | * my_last_iteration = last_iteration[rank] 20 | * 21 | * Revisions: 18/04/2018 PS: `nproc' was supposed to be an alias for 22 | * `nprocesses'; now it can be arbitrary number such that 23 | * 0 < nproc < nprocesses. 24 | * 25 | *****************************************************************************/ 26 | 27 | #include 28 | #include 29 | #include 30 | #include 31 | #include 32 | #if defined(MPI) 33 | #include 34 | #endif 35 | #include "distribute.h" 36 | 37 | int my_number_of_iterations = -1; 38 | int my_first_iteration = -1; 39 | int my_last_iteration = -1; 40 | int* number_of_iterations = NULL; 41 | int* first_iteration = NULL; 42 | int* last_iteration = NULL; 43 | 44 | /** Distributes indices in the interval [i1, i2] between `nproc' processes. 45 | * @param i1 Start of the interval 46 | * @param i2 End of the interval 47 | * @param nproc Number of processes (CPUs) to be be used 48 | * @param myrank ID of the process 49 | * @param prefix Prefix for log printing; NULL to print no log. 50 | * Note that `nprocesses' and `rank' are supposed to be external (global) 51 | * variables. 52 | */ 53 | void distribute_iterations(int i1, int i2, int nproc, int myrank) 54 | { 55 | int n, npp, i; 56 | 57 | #if defined(MPI) 58 | fflush(stdout); 59 | MPI_Barrier(MPI_COMM_WORLD); 60 | #endif 61 | assert(i2 >= i1); 62 | 63 | if (number_of_iterations == NULL) { 64 | number_of_iterations = malloc(nprocesses * sizeof(int)); 65 | first_iteration = malloc(nprocesses * sizeof(int)); 66 | last_iteration = malloc(nprocesses * sizeof(int)); 67 | } 68 | #if defined(MPI) 69 | MPI_Barrier(MPI_COMM_WORLD); 70 | #endif 71 | 72 | assert(nproc > 0 && nproc <= nprocesses); 73 | 74 | n = i2 - i1 + 1; 75 | npp = n / nproc; 76 | if (n % nproc == 0) { 77 | for (i = 0; i < nproc; ++i) 78 | number_of_iterations[i] = npp; 79 | } else { 80 | int j = n - nproc * npp; 81 | 82 | for (i = 0; i < j; ++i) 83 | number_of_iterations[i] = npp + 1; 84 | for (i = j; i < nproc; ++i) 85 | number_of_iterations[i] = npp; 86 | } 87 | for (i = nproc; i < nprocesses; ++i) 88 | number_of_iterations[i] = 0; 89 | #if defined(MPI) 90 | MPI_Barrier(MPI_COMM_WORLD); 91 | #endif 92 | 93 | first_iteration[0] = i1; 94 | last_iteration[0] = i1 + number_of_iterations[0] - 1; 95 | for (i = 1; i < nproc; ++i) { 96 | first_iteration[i] = last_iteration[i - 1] + 1; 97 | last_iteration[i] = first_iteration[i] + number_of_iterations[i] - 1; 98 | } 99 | for (i = nproc; i < nprocesses; ++i) { 100 | first_iteration[i] = last_iteration[i - 1] + 1; 101 | last_iteration[i] = first_iteration[i] + number_of_iterations[i] - 1; 102 | } 103 | 104 | my_first_iteration = first_iteration[myrank]; 105 | my_last_iteration = last_iteration[myrank]; 106 | my_number_of_iterations = number_of_iterations[myrank]; 107 | } 108 | 109 | /** 110 | */ 111 | void distribute_free(void) 112 | { 113 | if (number_of_iterations == NULL) 114 | return; 115 | free(number_of_iterations); 116 | number_of_iterations = NULL; 117 | free(first_iteration); 118 | first_iteration = NULL; 119 | free(last_iteration); 120 | last_iteration = NULL; 121 | my_number_of_iterations = -1; 122 | my_first_iteration = -1; 123 | my_last_iteration = -1; 124 | } 125 | -------------------------------------------------------------------------------- /nn/distribute.h: -------------------------------------------------------------------------------- 1 | /****************************************************************************** 2 | * 3 | * File: distribute.h 4 | * 5 | * Created: 12/2012 6 | * 7 | * Author: Pavel Sakov 8 | * Bureau of Meteorology 9 | * 10 | * Description: 11 | * 12 | * Revisions: 13 | * 14 | *****************************************************************************/ 15 | 16 | #if !defined(_DISTRIBUTE_H) 17 | 18 | extern int nprocesses; 19 | extern int rank; 20 | extern int my_number_of_iterations; 21 | extern int my_first_iteration; 22 | extern int my_last_iteration; 23 | extern int* number_of_iterations; 24 | extern int* first_iteration; 25 | extern int* last_iteration; 26 | 27 | void distribute_iterations(int i1, int i2, int nproc, int rank); 28 | void distribute_free(void); 29 | 30 | #define _DISTRIBUTE_H 31 | #endif 32 | -------------------------------------------------------------------------------- /nn/examples/1/README: -------------------------------------------------------------------------------- 1 | This example reconstructs the Franke test function from 100, 300 and 1000 2 | random data points in [0,1]^2 square. 3 | 4 | To generate and approximate the data, run ./test.sh. 5 | To visualize, in Matlab run "viewexample". 6 | 7 | Good luck! 8 | Pavel Sakov 9 | -------------------------------------------------------------------------------- /nn/examples/1/generate.awk: -------------------------------------------------------------------------------- 1 | BEGIN { 2 | r = 1; 3 | T = 10000000; 4 | N = 100; 5 | } 6 | 7 | { 8 | for (i = 0; i < N; ++i) { 9 | x = random(); 10 | y = random(); 11 | xx = x * 9.0; 12 | yy = y * 9.0; 13 | z = 0.75 * exp(- (xx-2) * (xx-2) / 4 - (yy-2) * (yy-2) / 4) + 0.75 * exp(- (xx-2) * (xx-2) / 49 - (yy-2) / 10) + 0.5 * exp(- (xx-7) * (xx-7) / 4 - (yy-3) * (yy-3) / 4) - 0.2 * exp(- (xx-4) * (xx-4) - (yy-7)*(yy-7)); 14 | printf("%.10g %.10g %.10g\n", x, y, z); 15 | } 16 | } 17 | 18 | END { 19 | } 20 | 21 | # One could use in-built generator rand(), but its output may depend on the 22 | # awk implementation used... 23 | # 24 | function random() 25 | { 26 | r = (r * 40353607) % T; 27 | return r / T; 28 | } 29 | -------------------------------------------------------------------------------- /nn/examples/1/makefile: -------------------------------------------------------------------------------- 1 | all: 2 | ./test.sh 3 | clean: 4 | rm -f data-*.txt out-*.txt *~ core *.ps 5 | -------------------------------------------------------------------------------- /nn/examples/1/suptitle.m: -------------------------------------------------------------------------------- 1 | function hout=suptitle(str) 2 | %SUPTITLE Puts a title above all subplots. 3 | % SUPTITLE('text') adds text to the top of the figure 4 | % above all subplots (a "super title"). Use this function 5 | % after all subplot commands. 6 | 7 | % Drea Thomas 6/15/95 drea@mathworks.com 8 | % John Cristion 12/13/00 modified 9 | % Mark Histed 03/13/04 histed@mit.edu: fix disappearing legend on last plot 10 | % 11 | % $Id: suptitle.m,v 1.1.1.1 2008/12/12 16:07:41 pavels Exp $ 12 | 13 | % Warning: If the figure or axis units are non-default, this 14 | % will break. 15 | 16 | % Parameters used to position the supertitle. 17 | 18 | % Amount of the figure window devoted to subplots 19 | plotregion = .92; 20 | 21 | % Y position of title in normalized coordinates 22 | titleypos = .95; 23 | 24 | % Fontsize for supertitle 25 | fs = get(gcf,'defaultaxesfontsize'); 26 | 27 | % Fudge factor to adjust y spacing between subplots 28 | fudge = 1; 29 | 30 | haold = gca; 31 | figunits = get(gcf, 'units'); 32 | 33 | % Get the (approximate) difference between full height (plot + title 34 | % + xlabel) and bounding rectangle. 35 | 36 | if (~strcmp(figunits, 'pixels')), 37 | set(gcf,'units', 'pixels'); 38 | pos = get(gcf, 'position'); 39 | set(gcf, 'units', figunits); 40 | else, 41 | pos = get(gcf, 'position'); 42 | end 43 | ff = (fs - 4) * 1.27 * 5 / pos(4) * fudge; 44 | 45 | % The 5 here reflects about 3 characters of height below 46 | % an axis and 2 above. 1.27 is pixels per point. 47 | 48 | % Determine the bounding rectange for all the plots 49 | 50 | % findobj is a 4.2 thing.. if you don't have 4.2 comment out 51 | % the next line and uncomment the following block. 52 | % 53 | %h = findobj(gcf,'Type','axes'); % Change suggested by Stacy J. Hills 54 | % 55 | % If you don't have 4.2, use this code instead 56 | ch = get(gcf, 'children'); 57 | h = []; 58 | for i = 1:length(ch), 59 | if strcmp(get(ch(i), 'type'), 'axes'), 60 | h = [h, ch(i)]; 61 | end 62 | end 63 | 64 | max_y = 0; 65 | min_y = 1; 66 | 67 | oldtitle = 0; 68 | for i = 1 : length(h), 69 | if (~strcmp(get(h(i), 'Tag'), 'suptitle')), 70 | pos = get(h(i), 'pos'); 71 | if (pos(2) < min_y) 72 | min_y = pos(2) - ff / 5 * 3; 73 | end; 74 | if (pos(4) + pos(2) > max_y) 75 | max_y = pos(4) + pos(2) + ff / 5 * 2; 76 | end; 77 | else 78 | oldtitle = h(i); 79 | end 80 | end 81 | 82 | if max_y > plotregion, 83 | scale = (plotregion - min_y) / (max_y - min_y); 84 | for i = 1 : length(h), 85 | pos = get(h(i), 'position'); 86 | pos(2) = (pos(2)-min_y) * scale + min_y; 87 | pos(4) = pos(4) * scale - (1 - scale) * ff / 5 * 3; 88 | set(h(i),'position',pos); 89 | end 90 | end 91 | 92 | np = get(gcf, 'nextplot'); 93 | set(gcf, 'nextplot', 'add'); 94 | if (oldtitle) 95 | delete(oldtitle); 96 | end 97 | ha = axes('pos', [0 1 1 1], 'visible', 'off', 'Tag', 'suptitle'); 98 | ht = text(.5, titleypos - 1, str); 99 | set(ht, 'horizontalalignment', 'center', 'fontsize', fs); 100 | set(gcf, 'nextplot', np); 101 | axes(haold); 102 | 103 | % fix legend if one exists 104 | legH = findobj(gcf, 'Type', 'Legend'); 105 | if ~isempty(legH) 106 | axes(legH); 107 | end 108 | 109 | if nargout 110 | hout = ht; 111 | end 112 | 113 | -------------------------------------------------------------------------------- /nn/examples/1/test.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | if [ ! -x ../../nnbathy ] 4 | then 5 | echo "error: no executable found" 6 | echo 'Run "./configure" and "make" in the source directory' 7 | exit 1 8 | fi 9 | 10 | echo " Example of Natural Neighbours interpolation:" 11 | echo " Franke test function reconstruction by 100, 300 and 1000 random points" 12 | 13 | for N in 100 300 1000 14 | do 15 | echo " N = $N:" 16 | echo -n " Generating..." 17 | echo "1" | awk -f ./generate.awk N=$N > data-${N}.txt 18 | echo "done" 19 | echo -n " Interpolating into 256x256 grid..." 20 | ../../nnbathy -i data-$N.txt -n 256x256 > out-${N}.txt 21 | echo "done" 22 | done 23 | 24 | echo " Finished" 25 | echo " To visualize, in Matlab run \"viewexample\"" 26 | -------------------------------------------------------------------------------- /nn/examples/1/viewexample.m: -------------------------------------------------------------------------------- 1 | function viewexample() 2 | 3 | subplot(3, 1, 1); 4 | view('data-100.txt', 'out-100.txt'); 5 | title('100 data points'); 6 | pause(0.1); 7 | 8 | subplot(3, 1, 2); 9 | view('data-300.txt', 'out-300.txt'); 10 | title('300 data points'); 11 | pause(0.1); 12 | 13 | subplot(3, 1, 3); 14 | view('data-1000.txt', 'out-1000.txt'); 15 | title('1000 data points'); 16 | 17 | suptitle('Interpolation of Franke test function using nnbathy'); 18 | 19 | return 20 | 21 | function view(data, output) 22 | 23 | N = 256; 24 | for i = 0:15 25 | V(i+1) = i * 0.1; 26 | end 27 | points = load(output); 28 | k = 1; 29 | x = zeros(N, N); 30 | y = zeros(N, N); 31 | z = zeros(N, N); 32 | z1 = zeros(N, N); 33 | for j = N:-1:1 34 | for i = 1:N 35 | x(j, i) = points(k, 1); 36 | y(j, i) = points(k, 2); 37 | z(j, i) = points(k, 3); 38 | xx = x(j, i) * 9.0; 39 | yy = y(j, i) * 9.0; 40 | z1(j, i) = 0.75 * exp(- (xx-2.0) * (xx-2.0) / 4.0 - (yy-2.0) * (yy-2.0) / 4.0) + 0.75 * exp(- (xx-2.0) * (xx-2.0) / 49.0 - (yy-2.0) / 10.0) + 0.5 * exp(- (xx-7.0) * (xx-7.0) / 4.0 - (yy-3.0) * (yy-3.0) / 4.0) - 0.2 * exp(- (xx-4.0) * (xx-4.0) - (yy-7.0)*(yy-7.0)); 41 | k = k + 1; 42 | end 43 | end 44 | 45 | contour(x, y, z1, V, 'k'); 46 | hold on; 47 | [c, h] = contour(x, y, z, V); 48 | clabel(c, h); 49 | 50 | points = load(data); 51 | x = points(:, 1); 52 | y = points(:, 2); 53 | plot(x, y, 'k+', 'markersize', 3); 54 | axis([0 1 0 1]); 55 | axis square; 56 | 57 | return 58 | -------------------------------------------------------------------------------- /nn/examples/2/README: -------------------------------------------------------------------------------- 1 | This example represents interpolation of some real-life bathymetry data 2 | along the shiptrack. 3 | 4 | It is quite tough for interpolation because of the instrumental round-up 5 | of the position of the ship (resulting in a lot of close/duplicate data 6 | points and in data points aligned to nodes of a regular grid) and because 7 | of clustering of data along the track (resulting in a lot of very thin 8 | triangles). 9 | 10 | Early versions if `nn' miserably failed for this data set when interpolating 11 | the raw data, and were dealt with by replacing data in each cell of a 256x256 12 | subgrid by an averaged value by means of "-d" option of `nnbathy'. The current 13 | version of `nn' is doing much better job; still "-d" option is used because 14 | it speeds up things and because this is the right way to deal with such 15 | clustered data. 16 | 17 | I need to add that `triangle' really shines in this example. 18 | 19 | To reproduce the example, run "./test.sh" or "make". 20 | To visualize, in Matlab run "viewexample". 21 | To clean up, run "make clean" 22 | 23 | From v2.0.0 some MPI code has been added to nnbathy. To compile the parallelised 24 | version change "MPI = no" in ../../makefile to "MPI = yes". To test it run 25 | "make mpi" and "run cmp". To set the number of cores used change NCPU in 26 | mpitest.sh. 27 | 28 | Good luck! 29 | Pavel Sakov 30 | -------------------------------------------------------------------------------- /nn/examples/2/makefile: -------------------------------------------------------------------------------- 1 | all: 2 | ./test.sh 3 | mpi: 4 | ./mpitest.sh 5 | cmp: 6 | @echo -n " running mpitest.sh..." 7 | @time -f " %es" sh -c '"$$0" "$$1" >/dev/null 2>&1' ./mpitest.sh 512x512 8 | @for file in lin.txt nn-inf.txt nn-0.txt nn-ns.txt; do mv $$file $${file}.mpi; done 9 | @echo -n " running test.sh..." 10 | @time -f " %es" sh -c '"$$0" "$$1" >/dev/null 2>&1' ./test.sh 512x512 11 | @echo " comparing results:" 12 | @for file in lin.txt nn-inf.txt nn-0.txt nn-ns.txt; do echo -n " "; diff -qs $$file $${file}.mpi; done 13 | clean: 14 | rm -f lin*.txt* nn-*.txt* *~ core 15 | -------------------------------------------------------------------------------- /nn/examples/2/mpitest.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | NCPU=4 4 | RES=256x256 5 | 6 | if (($# > 0)) 7 | then 8 | RES=$1 9 | fi 10 | 11 | if [ ! -x ../../nnbathy ] 12 | then 13 | echo "error: no executable found" 14 | echo 'Run "./configure" and "make" in the source directory' 15 | exit 1 16 | fi 17 | 18 | echo "" 19 | echo -n "Linear interpolation..." 20 | mpirun -np $NCPU ../../nnbathy -i data.txt -n $RES -P alg=l > lin.txt 21 | echo "done" 22 | echo -n "Natural Neighbours Sibson interpolation..." 23 | mpirun -np $NCPU ../../nnbathy -i data.txt -n $RES > nn-inf.txt 24 | echo "done" 25 | echo -n "Natural Neighbours Sibson interpolation with wmin = 0..." 26 | mpirun -np $NCPU ../../nnbathy -i data.txt -n $RES -W 0 > nn-0.txt 27 | echo "done" 28 | echo -n "Natural Neighbours Non-Sibsonian interpolation with wmin = 0..." 29 | mpirun -np $NCPU ../../nnbathy -i data.txt -n $RES -W 0 -P alg=ns > nn-ns.txt 30 | echo "done" 31 | echo "" 32 | echo 'To visualize, in Matlab run "viewexample"' 33 | -------------------------------------------------------------------------------- /nn/examples/2/suptitle.m: -------------------------------------------------------------------------------- 1 | function hout=suptitle(str) 2 | %SUPTITLE Puts a title above all subplots. 3 | % SUPTITLE('text') adds text to the top of the figure 4 | % above all subplots (a "super title"). Use this function 5 | % after all subplot commands. 6 | 7 | % Drea Thomas 6/15/95 drea@mathworks.com 8 | % John Cristion 12/13/00 modified 9 | % Mark Histed 03/13/04 histed@mit.edu: fix disappearing legend on last plot 10 | % 11 | % $Id: suptitle.m,v 1.1.1.1 2008/12/12 16:07:41 pavels Exp $ 12 | 13 | % Warning: If the figure or axis units are non-default, this 14 | % will break. 15 | 16 | % Parameters used to position the supertitle. 17 | 18 | % Amount of the figure window devoted to subplots 19 | plotregion = .92; 20 | 21 | % Y position of title in normalized coordinates 22 | titleypos = .95; 23 | 24 | % Fontsize for supertitle 25 | fs = get(gcf,'defaultaxesfontsize'); 26 | 27 | % Fudge factor to adjust y spacing between subplots 28 | fudge = 1; 29 | 30 | haold = gca; 31 | figunits = get(gcf, 'units'); 32 | 33 | % Get the (approximate) difference between full height (plot + title 34 | % + xlabel) and bounding rectangle. 35 | 36 | if (~strcmp(figunits, 'pixels')), 37 | set(gcf,'units', 'pixels'); 38 | pos = get(gcf, 'position'); 39 | set(gcf, 'units', figunits); 40 | else, 41 | pos = get(gcf, 'position'); 42 | end 43 | ff = (fs - 4) * 1.27 * 5 / pos(4) * fudge; 44 | 45 | % The 5 here reflects about 3 characters of height below 46 | % an axis and 2 above. 1.27 is pixels per point. 47 | 48 | % Determine the bounding rectange for all the plots 49 | 50 | % findobj is a 4.2 thing.. if you don't have 4.2 comment out 51 | % the next line and uncomment the following block. 52 | % 53 | %h = findobj(gcf,'Type','axes'); % Change suggested by Stacy J. Hills 54 | % 55 | % If you don't have 4.2, use this code instead 56 | ch = get(gcf, 'children'); 57 | h = []; 58 | for i = 1:length(ch), 59 | if strcmp(get(ch(i), 'type'), 'axes'), 60 | h = [h, ch(i)]; 61 | end 62 | end 63 | 64 | max_y = 0; 65 | min_y = 1; 66 | 67 | oldtitle = 0; 68 | for i = 1 : length(h), 69 | if (~strcmp(get(h(i), 'Tag'), 'suptitle')), 70 | pos = get(h(i), 'pos'); 71 | if (pos(2) < min_y) 72 | min_y = pos(2) - ff / 5 * 3; 73 | end; 74 | if (pos(4) + pos(2) > max_y) 75 | max_y = pos(4) + pos(2) + ff / 5 * 2; 76 | end; 77 | else 78 | oldtitle = h(i); 79 | end 80 | end 81 | 82 | if max_y > plotregion, 83 | scale = (plotregion - min_y) / (max_y - min_y); 84 | for i = 1 : length(h), 85 | pos = get(h(i), 'position'); 86 | pos(2) = (pos(2)-min_y) * scale + min_y; 87 | pos(4) = pos(4) * scale - (1 - scale) * ff / 5 * 3; 88 | set(h(i),'position',pos); 89 | end 90 | end 91 | 92 | np = get(gcf, 'nextplot'); 93 | set(gcf, 'nextplot', 'add'); 94 | if (oldtitle) 95 | delete(oldtitle); 96 | end 97 | ha = axes('pos', [0 1 1 1], 'visible', 'off', 'Tag', 'suptitle'); 98 | ht = text(.5, titleypos - 1, str); 99 | set(ht, 'horizontalalignment', 'center', 'fontsize', fs); 100 | set(gcf, 'nextplot', np); 101 | axes(haold); 102 | 103 | % fix legend if one exists 104 | legH = findobj(gcf, 'Type', 'Legend'); 105 | if ~isempty(legH) 106 | axes(legH); 107 | end 108 | 109 | if nargout 110 | hout = ht; 111 | end 112 | 113 | -------------------------------------------------------------------------------- /nn/examples/2/test.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | RES=256x256 4 | 5 | if (($# > 0)) 6 | then 7 | RES=$1 8 | fi 9 | 10 | if [ ! -x ../../nnbathy ] 11 | then 12 | echo "error: no executable found" 13 | echo 'Run "./configure" and "make" in the source directory' 14 | exit 1 15 | fi 16 | 17 | echo "" 18 | echo -n "Linear interpolation..." 19 | ../../nnbathy -i data.txt -n $RES -P alg=l > lin.txt 20 | echo "done" 21 | echo -n "Natural Neighbours Sibson interpolation..." 22 | ../../nnbathy -i data.txt -n $RES > nn-inf.txt 23 | echo "done" 24 | echo -n "Natural Neighbours Sibson interpolation with wmin = 0..." 25 | ../../nnbathy -i data.txt -n $RES -W 0 > nn-0.txt 26 | echo "done" 27 | echo -n "Natural Neighbours Non-Sibsonian interpolation with wmin = 0..." 28 | ../../nnbathy -i data.txt -n $RES -W 0 -P alg=ns > nn-ns.txt 29 | echo "done" 30 | echo "" 31 | echo 'To visualize, in Matlab run "viewexample"' 32 | -------------------------------------------------------------------------------- /nn/examples/2/viewdata.m: -------------------------------------------------------------------------------- 1 | function [] = viewdata(fname, verbose) 2 | 3 | if nargin == 1 4 | verbose = 1; 5 | end 6 | 7 | if verbose 8 | fprintf('plotting data from "%s"\n', fname); 9 | fprintf(' reading %s...', fname); 10 | end 11 | data = load(fname); 12 | x = data(:, 1); 13 | y = data(:, 2); 14 | z = data(:, 3); 15 | clear data; 16 | 17 | if verbose 18 | fprintf('\n'); 19 | end 20 | 21 | if verbose 22 | fprintf(' plotting...'); 23 | end 24 | 25 | xmin = min(x); 26 | xmax = max(x); 27 | ymin = min(y); 28 | ymax = max(y); 29 | zmin = min(z); 30 | zmax = max(z); 31 | n = length(z); 32 | 33 | map = colormap; 34 | axis([xmin xmax ymin ymax]); 35 | axis square; 36 | set(gca, 'box', 'on'); 37 | hold on; 38 | for i = 1 : n 39 | plot(x(i), y(i), 's-', 'color', zcolor(z(i), zmin, zmax, map), 'markersize', 2); 40 | end 41 | 42 | if verbose 43 | fprintf('\n'); 44 | end 45 | 46 | return 47 | 48 | function c = zcolor(z, zmin, zmax, map) 49 | 50 | ind = floor((z - zmin) / (zmax - zmin) * 64 + 1); 51 | ind = min(ind, 64); 52 | c = map(ind, :); 53 | 54 | return 55 | -------------------------------------------------------------------------------- /nn/examples/2/viewexample.m: -------------------------------------------------------------------------------- 1 | figure 2 | 3 | subplot(3, 2, 1); 4 | fname = 'data.txt'; 5 | fprintf('plotting data points from "%s"\n', fname); 6 | fprintf(' reading %s...', fname); 7 | data = load(fname); 8 | xrange = [min(data(:, 1)) max(data(:, 1))]; 9 | yrange = [min(data(:, 2)) max(data(:, 2))]; 10 | zrange = [min(data(:, 3)) max(data(:, 3))]; 11 | fprintf('\n'); 12 | fprintf(' plotting...'); 13 | axis([xrange yrange]); 14 | axis tight; 15 | axis square; 16 | set(gca, 'box', 'on'); 17 | hold on; 18 | plot(data(:, 1), data(:, 2), 'k.', 'markersize', 1); 19 | fprintf('\n'); 20 | clear data; 21 | title('Data points'); 22 | pause(0.1); 23 | 24 | subplot(3, 2, 2); 25 | viewdata('data.txt'); 26 | title('Data'); 27 | pause(0.1); 28 | 29 | subplot(3, 2, 3); 30 | viewinterp('data.txt', 'lin.txt'); 31 | title('Linear interpolation'); 32 | pause(0.1); 33 | 34 | subplot(3, 2, 4); 35 | viewinterp('data.txt', 'nn-inf.txt'); 36 | caxis(zrange); 37 | title(sprintf('Natural Neighbours interpolation\n(extrapolation allowed)')); 38 | pause(0.1); 39 | 40 | subplot(3, 2, 5); 41 | viewinterp('data.txt', 'nn-0.txt'); 42 | caxis(zrange); 43 | title(sprintf('Natural Neighbours interpolation\n(interpolation only)')); 44 | pause(0.1); 45 | 46 | subplot(3, 2, 6); 47 | viewinterp('data.txt', 'nn-ns.txt'); 48 | caxis(zrange); 49 | title(sprintf('Non-Sibsonian NN interpolation\n(interpolation only)')); 50 | pause(0.1); 51 | 52 | suptitle('Interpolation of bathymetry data from sonar using nnbathy'); 53 | -------------------------------------------------------------------------------- /nn/examples/2/viewinterp.m: -------------------------------------------------------------------------------- 1 | function [h] = viewinterp(fin, fout, verbose) 2 | 3 | if nargin == 2 4 | verbose = 1; 5 | end 6 | 7 | if verbose 8 | fprintf('plotting data from "%s" and "%s"\n', fin, fout); 9 | fprintf(' reading "%s"...', fin); 10 | end 11 | 12 | data = load(fin); 13 | xin = data(:, 1); 14 | yin = data(:, 2); 15 | 16 | if verbose 17 | fprintf('\n reading "%s"...', fout); 18 | end 19 | 20 | data = load(fout); 21 | x = data(:, 1); 22 | y = data(:, 2); 23 | z = data(:, 3); 24 | clear data; 25 | 26 | if verbose 27 | fprintf('\n'); 28 | end 29 | 30 | if verbose 31 | fprintf(' working out the grid dimensions...') 32 | end 33 | n = length(x); 34 | if x(2) - x(1) ~= 0 & y(2) - y(1) == 0 35 | xfirst = 1; 36 | xinc = x(2) > x(1); 37 | if xinc 38 | nx = min(find(diff(x) < 0)); 39 | else 40 | nx = min(find(diff(x) > 0)); 41 | end 42 | if mod(n, nx) ~= 0 43 | error(sprintf('\n Error: could not work out the grid size, n = %d, nx = %d, n / nx = %f\n', n, nx, n / nx)); 44 | end 45 | ny = n / nx; 46 | x = x(1 : nx); 47 | y = y(1 : nx : n); 48 | z = reshape(z, nx, ny)'; 49 | elseif x(2) - x(1) == 0 & y(2) - y(1) ~= 0 50 | xfirst = 0; 51 | yinc = y(2) > y(1); 52 | if yinc 53 | ny = min(find(diff(y) < 0)); 54 | else 55 | ny = min(find(diff(y) > 0)); 56 | end 57 | if mod(n, ny) ~= 0 58 | error(sprintf('\n Error: could not work out the grid size, n = %d, ny = %d, n / ny = %.3f\n', n, ny, n / ny)); 59 | end 60 | nx = n / ny; 61 | y = y(1 : ny); 62 | x = x(1 : ny : n); 63 | z = reshape(z, ny, nx); 64 | else 65 | error(' Error: not a rectangular grid'); 66 | end 67 | if verbose 68 | if xfirst 69 | fprintf('%d x %d, stored by rows\n', nx, ny); 70 | else 71 | fprintf('%d x %d, stored by columns\n', nx, ny); 72 | end 73 | end 74 | 75 | if verbose 76 | fprintf(' plotting...'); 77 | end 78 | 79 | h = pcolor_ps(x, y, z); 80 | zrange = [min(min(z)) max(max(z))]; 81 | caxis(zrange); 82 | set(h, 'LineStyle', 'none'); 83 | axis square; 84 | hold on; 85 | plot(xin, yin, 'w.', 'markersize', 1); 86 | 87 | if verbose 88 | fprintf('\n'); 89 | end 90 | 91 | return 92 | 93 | function [h] = pcolor_ps(x, y, A); 94 | 95 | if nargin == 1 96 | A = x; 97 | [n, m] = size(A); 98 | xx = (0.5 : m + 0.5)'; 99 | yy = (0.5 : n + 0.5)'; 100 | elseif nargin == 3 101 | n = length(y); 102 | m = length(x); 103 | A = reshape(A, n, m); % just in case 104 | xx = getcorners(x); 105 | yy = getcorners(y); 106 | else 107 | error(sprintf('\n Error: pcolor_ps(): nargin = %d (expected 1 or 3)\n', nargin)); 108 | end 109 | 110 | TMP = zeros(n + 1, m + 1); 111 | TMP(1 : n, 1 : m) = A; 112 | 113 | if nargout == 0 114 | pcolor(xx, yy, TMP); 115 | else 116 | h = pcolor(xx, yy, TMP); 117 | end 118 | 119 | return 120 | 121 | function [c] = getcorners(x) 122 | 123 | n = length(x); 124 | c = zeros(n + 1, 1); 125 | c(2 : n) = (x(2 : n) + x(1 : n - 1)) / 2; 126 | c(1) = 2 * x(1) - c(2); 127 | c(n + 1) = 2 * x(n) - c(n); 128 | 129 | return 130 | -------------------------------------------------------------------------------- /nn/examples/3/README: -------------------------------------------------------------------------------- 1 | This example tests interpolation of degenerate data, when both input and 2 | output points belong to nodes of 101 x 101 regular grid. As a consequence, 3 | a lot of output points turn out to be exactly on edges of Delaunay 4 | triangulation. In this case, Watson's algorithm used for Sibson interpolation 5 | in this package does not work, and the output vertices have to be perturbed. 6 | (The same applies to Belikov and Semenov's formulas for non-Sibsonian 7 | interpolation.) 8 | 9 | A linear function z = 5x - 3y has been chosen for interpolation because 10 | both Sibsonian and non-Sibsonian interpolation should (in theory) reproduce 11 | it exactly, and for both Sibsonian and non-Sibsonian interpolation sum of 12 | absolute discrepancy is calculated. 13 | 14 | I think that this example is a good test of numerical robustness of the 15 | NN interpolation. 16 | 17 | To conduct the test, run "./test.sh" or "make". 18 | To clean up, run "make clean". 19 | 20 | On pc-linux platform v. 1.55 yields: 21 | sum(|z_sibson_i - z_i|) = 4.91393e-10 22 | sum(|z_nonsibson_i - z_i|) = 3.28898e-14 23 | 24 | For comparison, libnn version 1.52 gives: 25 | sum(|z_sibson_i - z_i|) = 312.976 26 | sum(|z_nonsibson_i - z_i|) = 489.882 27 | 28 | Update 24 November 2006: version 1.69 gives now 29 | sum(|z_sibson_i - z_i|) = 2.07804e-12 30 | sum(|z_nonsibson_i - z_i|) = 3.53031e-14 31 | on my Linux box. 32 | 33 | Good luck! 34 | Pavel Sakov 35 | -------------------------------------------------------------------------------- /nn/examples/3/generate-data.awk: -------------------------------------------------------------------------------- 1 | BEGIN { 2 | r = 1; 3 | T = 10000000; 4 | N = 300; 5 | } 6 | 7 | { 8 | for (i = 0; i < N; ++i) { 9 | x = (int(random() * 121.0) - 10.0) / 100.0; 10 | y = (int(random() * 121.0) - 10.0) / 100.0; 11 | z = 5.0 * x - 3.0 * y; 12 | printf("%.10g %.10g %.10g\n", x, y, z); 13 | } 14 | } 15 | 16 | END { 17 | } 18 | 19 | # One could use in-built generator rand(), but its output may depend on the 20 | # awk implementation used... 21 | # 22 | function random() 23 | { 24 | r = (r * 40353607) % T; 25 | return r / T; 26 | } 27 | -------------------------------------------------------------------------------- /nn/examples/3/generate-points.awk: -------------------------------------------------------------------------------- 1 | BEGIN { 2 | N = 101; 3 | inc = 1.0 / (N - 1); 4 | } 5 | 6 | { 7 | y = 0.0; 8 | for (j = 0; j < N; ++j) { 9 | x = 0.0; 10 | for (i = 0; i < N; ++i) { 11 | printf("%.2f %.2f %.2f\n", x, y, 5.0 * x - 3.0 * y); 12 | x += inc; 13 | } 14 | y += inc; 15 | } 16 | } 17 | 18 | END { 19 | } 20 | -------------------------------------------------------------------------------- /nn/examples/3/makefile: -------------------------------------------------------------------------------- 1 | all: 2 | @./test.sh 3 | clean: 4 | @rm -f *.txt *~ core 5 | -------------------------------------------------------------------------------- /nn/examples/3/test.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | if [ ! -x ../../nnbathy ] 4 | then 5 | echo "error: no executable found" 6 | echo 'Run "./configure" and "make" in the source directory' 7 | exit 1 8 | fi 9 | 10 | echo | awk -f generate-data.awk > data.txt 11 | echo | awk -f generate-points.awk > points.txt 12 | 13 | ../../nnbathy -i data.txt -o points.txt > results.txt 14 | ../../nnbathy -i data.txt -o points.txt -P alg=ns > results-ns.txt 15 | 16 | paste -d" " results.txt results-ns.txt points.txt |\ 17 | cut -f"1 2 3 6 9" -d" " |\ 18 | awk '{a = $3 - $5; s1 += (a > 0) ? a : -a; b = $4 - $5; s2 += (b > 0) ? b : -b;} END {print " sum(|z_sibson_i - z_i|) =", s1; print " sum(|z_nonsibson_i - z_i|) =", s2;}' 19 | -------------------------------------------------------------------------------- /nn/examples/4/README: -------------------------------------------------------------------------------- 1 | This real-life example is run on a topographic data from satellite altimeter. 2 | (Thanks to Prof. David A. Paige, Dept. of Earth and Space Sciences, UCLA.) 3 | Similar to example 3, the data points belong to nodes of a rectangular grid, 4 | but also there is a large gap between two main clusters of data. 5 | 6 | To reproduce the example, run "./test.sh" or "make". 7 | To visualize, in Matlab run "viewexample" or 8 | "viewinterp('data.txt', 'nn-0.txt');". 9 | To clean up, run "make clean". 10 | 11 | Note that the locations of data points are marked by white dots. 12 | 13 | Good luck! 14 | Pavel Sakov 15 | -------------------------------------------------------------------------------- /nn/examples/4/makefile: -------------------------------------------------------------------------------- 1 | all: 2 | ./test.sh 3 | clean: 4 | rm -f lin*.txt nn-*.txt *~ core 5 | -------------------------------------------------------------------------------- /nn/examples/4/test.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | N=201 4 | 5 | if [ ! -x ../../nnbathy ] 6 | then 7 | echo "error: no executable found" 8 | echo 'Run "./configure" and "make" in the source directory' 9 | exit 1 10 | fi 11 | 12 | echo "" 13 | echo -n "Linear interpolation..." 14 | ../../nnbathy -i data.txt -n "$N"x"$N" -P alg=l > lin.txt 15 | echo "done" 16 | echo -n "Natural Neighbours Sibson interpolation..." 17 | ../../nnbathy -i data.txt -n "$N"x"$N" > nn-inf.txt 18 | echo "done" 19 | echo -n "Natural Neighbours Sibson interpolation with wmin = 0..." 20 | ../../nnbathy -i data.txt -n "$N"x"$N" -W 0 > nn-0.txt 21 | echo "done" 22 | echo -n "Natural Neighbours Non-Sibsonian interpolation with wmin = 0..." 23 | ../../nnbathy -i data.txt -n "$N"x"$N" -P alg=ns -W 0 > nn-ns.txt 24 | echo "done" 25 | echo "" 26 | echo 'To visualize, in Matlab run "viewexample"' 27 | -------------------------------------------------------------------------------- /nn/examples/4/viewdata.m: -------------------------------------------------------------------------------- 1 | function [] = viewdata(fname, verbose) 2 | 3 | if nargin == 1 4 | verbose = 1; 5 | end 6 | 7 | if verbose 8 | fprintf('plotting data from "%s"\n', fname); 9 | fprintf(' reading %s...', fname); 10 | end 11 | data = load(fname); 12 | x = data(:, 1); 13 | y = data(:, 2); 14 | z = data(:, 3); 15 | clear data; 16 | 17 | if verbose 18 | fprintf('\n'); 19 | end 20 | 21 | if verbose 22 | fprintf(' plotting...'); 23 | end 24 | 25 | xmin = min(x); 26 | xmax = max(x); 27 | ymin = min(y); 28 | ymax = max(y); 29 | zmin = min(z); 30 | zmax = max(z); 31 | n = length(z); 32 | 33 | map = colormap; 34 | axis([xmin xmax ymin ymax]); 35 | axis square; 36 | set(gca, 'box', 'on'); 37 | hold on; 38 | for i = 1 : n 39 | plot(x(i), y(i), 's-', 'color', zcolor(z(i), zmin, zmax, map), 'markersize', 2); 40 | end 41 | 42 | if verbose 43 | fprintf('\n'); 44 | end 45 | 46 | return 47 | 48 | function c = zcolor(z, zmin, zmax, map) 49 | 50 | ind = floor((z - zmin) / (zmax - zmin) * 64 + 1); 51 | ind = min(ind, 64); 52 | c = map(ind, :); 53 | 54 | return 55 | -------------------------------------------------------------------------------- /nn/examples/4/viewexample.m: -------------------------------------------------------------------------------- 1 | figure 2 | 3 | subplot(3, 2, 1); 4 | fname = 'data.txt'; 5 | fprintf('plotting data points from "%s"\n', fname); 6 | fprintf(' reading %s...', fname); 7 | data = load(fname); 8 | xrange = [min(data(:, 1)) max(data(:, 1))]; 9 | yrange = [min(data(:, 2)) max(data(:, 2))]; 10 | zrange = [min(data(:, 3)) max(data(:, 3))]; 11 | fprintf('\n'); 12 | fprintf(' plotting...'); 13 | axis([xrange yrange]); 14 | axis tight; 15 | axis square; 16 | set(gca, 'box', 'on'); 17 | hold on; 18 | plot(data(:, 1), data(:, 2), 'k.', 'markersize', 1); 19 | fprintf('\n'); 20 | clear data; 21 | title('Data points'); 22 | pause(0.1); 23 | 24 | subplot(3, 2, 2); 25 | viewdata('data.txt'); 26 | title('Data'); 27 | pause(0.1); 28 | 29 | subplot(3, 2, 3); 30 | viewinterp('data.txt', 'lin.txt'); 31 | title('Linear interpolation'); 32 | pause(0.1); 33 | 34 | subplot(3, 2, 4); 35 | viewinterp('data.txt', 'nn-inf.txt'); 36 | caxis(zrange); 37 | title(sprintf('Natural Neighbours interpolation\n(extrapolation allowed)')); 38 | pause(0.1); 39 | 40 | subplot(3, 2, 5); 41 | viewinterp('data.txt', 'nn-0.txt'); 42 | caxis(zrange); 43 | title(sprintf('Natural Neighbours interpolation\n(interpolation only)')); 44 | pause(0.1); 45 | 46 | subplot(3, 2, 6); 47 | viewinterp('data.txt', 'nn-ns.txt'); 48 | caxis(zrange); 49 | title(sprintf('Non-Sibsonian NN interpolation\n(interpolation only)')); 50 | pause(0.1); 51 | 52 | suptitle('Interpolation of topographic data from satellite altimeter using nnbathy'); 53 | -------------------------------------------------------------------------------- /nn/examples/4/viewinterp.m: -------------------------------------------------------------------------------- 1 | function [h] = viewinterp(fin, fout, verbose) 2 | 3 | if nargin == 2 4 | verbose = 1; 5 | end 6 | 7 | if verbose 8 | fprintf('plotting data from "%s" and "%s"\n', fin, fout); 9 | fprintf(' reading "%s"...', fin); 10 | end 11 | 12 | data = load(fin); 13 | xin = data(:, 1); 14 | yin = data(:, 2); 15 | 16 | if verbose 17 | fprintf('\n reading "%s"...', fout); 18 | end 19 | 20 | data = load(fout); 21 | x = data(:, 1); 22 | y = data(:, 2); 23 | z = data(:, 3); 24 | clear data; 25 | 26 | if verbose 27 | fprintf('\n'); 28 | end 29 | 30 | if verbose 31 | fprintf(' working out the grid dimensions...') 32 | end 33 | n = length(x); 34 | if x(2) - x(1) ~= 0 & y(2) - y(1) == 0 35 | xfirst = 1; 36 | xinc = x(2) > x(1); 37 | if xinc 38 | nx = min(find(diff(x) < 0)); 39 | else 40 | nx = min(find(diff(x) > 0)); 41 | end 42 | if mod(n, nx) ~= 0 43 | error(sprintf('\n Error: could not work out the grid size, n = %d, nx = %d, n / nx = %f\n', n, nx, n / nx)); 44 | end 45 | ny = n / nx; 46 | x = x(1 : nx); 47 | y = y(1 : nx : n); 48 | z = reshape(z, nx, ny)'; 49 | elseif x(2) - x(1) == 0 & y(2) - y(1) ~= 0 50 | xfirst = 0; 51 | yinc = y(2) > y(1); 52 | if yinc 53 | ny = min(find(diff(y) < 0)); 54 | else 55 | ny = min(find(diff(y) > 0)); 56 | end 57 | if mod(n, ny) ~= 0 58 | error(sprintf('\n Error: could not work out the grid size, n = %d, ny = %d, n / ny = %.3f\n', n, ny, n / ny)); 59 | end 60 | nx = n / ny; 61 | y = y(1 : ny); 62 | x = x(1 : ny : n); 63 | z = reshape(z, ny, nx); 64 | else 65 | error(' Error: not a rectangular grid'); 66 | end 67 | if verbose 68 | if xfirst 69 | fprintf('%d x %d, stored by rows\n', nx, ny); 70 | else 71 | fprintf('%d x %d, stored by columns\n', nx, ny); 72 | end 73 | end 74 | 75 | if verbose 76 | fprintf(' plotting...'); 77 | end 78 | 79 | h = pcolor_ps(x, y, z); 80 | zrange = [min(min(z)) max(max(z))]; 81 | caxis(zrange); 82 | set(h, 'LineStyle', 'none'); 83 | axis square; 84 | hold on; 85 | plot(xin, yin, 'w.', 'markersize', 1); 86 | 87 | if verbose 88 | fprintf('\n'); 89 | end 90 | 91 | return 92 | 93 | function [h] = pcolor_ps(x, y, A); 94 | 95 | if nargin == 1 96 | A = x; 97 | [n, m] = size(A); 98 | xx = (0.5 : m + 0.5)'; 99 | yy = (0.5 : n + 0.5)'; 100 | elseif nargin == 3 101 | n = length(y); 102 | m = length(x); 103 | A = reshape(A, n, m); % just in case 104 | xx = getcorners(x); 105 | yy = getcorners(y); 106 | else 107 | error(sprintf('\n Error: pcolor_ps(): nargin = %d (expected 1 or 3)\n', nargin)); 108 | end 109 | 110 | TMP = zeros(n + 1, m + 1); 111 | TMP(1 : n, 1 : m) = A; 112 | 113 | if nargout == 0 114 | pcolor(xx, yy, TMP); 115 | else 116 | h = pcolor(xx, yy, TMP); 117 | end 118 | 119 | return 120 | 121 | function [c] = getcorners(x) 122 | 123 | n = length(x); 124 | c = zeros(n + 1, 1); 125 | c(2 : n) = (x(2 : n) + x(1 : n - 1)) / 2; 126 | c(1) = 2 * x(1) - c(2); 127 | c(n + 1) = 2 * x(n) - c(n); 128 | 129 | return 130 | -------------------------------------------------------------------------------- /nn/examples/5/README: -------------------------------------------------------------------------------- 1 | This example is run on elevation data obtained from digitised contours. 2 | (Thanks to Maciej Sieczka, Institute of Plant Biology, Wroclaw University.) 3 | It is characterised by strong clustering of data points and big gaps between 4 | clusters. 5 | 6 | To reproduce the example, run "./test.sh" or "make". 7 | To visualize, in Matlab run "viewexample" (which takes time to plot) or 8 | "viewinterp('data.txt', 'nn.txt');". 9 | To clean up, run "make clean". 10 | 11 | Good luck! 12 | Pavel Sakov 13 | -------------------------------------------------------------------------------- /nn/examples/5/makefile: -------------------------------------------------------------------------------- 1 | all: 2 | ./test.sh 3 | clean: 4 | rm -f lin*.txt nn.txt *~ core 5 | -------------------------------------------------------------------------------- /nn/examples/5/test.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | N=373 4 | M=455 5 | 6 | if [ ! -x ../../nnbathy ] 7 | then 8 | echo "error: no executable found" 9 | echo 'Run "./configure" and "make" in the source directory' 10 | exit 1 11 | fi 12 | 13 | echo "" 14 | echo -n "Linear interpolation..." 15 | ../../nnbathy -i data.txt -n "$N"x"$M" -P alg=l > lin.txt 16 | echo "done" 17 | echo -n "Natural Neighbours Sibson interpolation..." 18 | ../../nnbathy -i data.txt -n "$N"x"$M" -W 0 > nn.txt 19 | echo "done" 20 | echo "" 21 | echo 'To visualize, in Matlab run "viewexample"' 22 | -------------------------------------------------------------------------------- /nn/examples/5/viewexample.m: -------------------------------------------------------------------------------- 1 | figure 2 | 3 | subplot(2, 2, 1); 4 | viewinterp2('data.txt', 'lin.txt'); 5 | title('Linear interpolation (contours)'); 6 | pause(0.1); 7 | 8 | subplot(2, 2, 2); 9 | viewinterp('data.txt', 'lin.txt'); 10 | title('Linear interpolation (colour coded image)'); 11 | pause(0.1); 12 | 13 | subplot(2, 2, 3); 14 | viewinterp2('data.txt', 'nn.txt'); 15 | title(sprintf('NN interpolation (contours)')); 16 | pause(0.1); 17 | 18 | subplot(2, 2, 4); 19 | viewinterp('data.txt', 'nn.txt'); 20 | title(sprintf('NN interpolation (colour coded image)')); 21 | pause(0.1); 22 | 23 | suptitle('Interpolation from elevation contours using nnbathy'); 24 | -------------------------------------------------------------------------------- /nn/examples/5/viewinterp.m: -------------------------------------------------------------------------------- 1 | function [h] = viewinterp(fin, fout, verbose) 2 | 3 | if nargin == 2 4 | verbose = 1; 5 | end 6 | 7 | if verbose 8 | fprintf('plotting data from "%s" and "%s"\n', fin, fout); 9 | fprintf(' reading "%s"...', fin); 10 | end 11 | 12 | data = load(fin); 13 | xin = data(:, 1); 14 | yin = data(:, 2); 15 | 16 | if verbose 17 | fprintf('\n reading "%s"...', fout); 18 | end 19 | 20 | data = load(fout); 21 | x = data(:, 1); 22 | y = data(:, 2); 23 | z = data(:, 3); 24 | clear data; 25 | 26 | if verbose 27 | fprintf('\n'); 28 | end 29 | 30 | if verbose 31 | fprintf(' working out the grid dimensions...') 32 | end 33 | n = length(x); 34 | if x(2) - x(1) ~= 0 & y(2) - y(1) == 0 35 | xfirst = 1; 36 | xinc = x(2) > x(1); 37 | if xinc 38 | nx = min(find(diff(x) < 0)); 39 | else 40 | nx = min(find(diff(x) > 0)); 41 | end 42 | if mod(n, nx) ~= 0 43 | error(sprintf('\n Error: could not work out the grid size, n = %d, nx = %d, n / nx = %f\n', n, nx, n / nx)); 44 | end 45 | ny = n / nx; 46 | x = x(1 : nx); 47 | y = y(1 : nx : n); 48 | z = reshape(z, nx, ny)'; 49 | elseif x(2) - x(1) == 0 & y(2) - y(1) ~= 0 50 | xfirst = 0; 51 | yinc = y(2) > y(1); 52 | if yinc 53 | ny = min(find(diff(y) < 0)); 54 | else 55 | ny = min(find(diff(y) > 0)); 56 | end 57 | if mod(n, ny) ~= 0 58 | error(sprintf('\n Error: could not work out the grid size, n = %d, ny = %d, n / ny = %.3f\n', n, ny, n / ny)); 59 | end 60 | nx = n / ny; 61 | y = y(1 : ny); 62 | x = x(1 : ny : n); 63 | z = reshape(z, ny, nx); 64 | else 65 | error(' Error: not a rectangular grid'); 66 | end 67 | if verbose 68 | if xfirst 69 | fprintf('%d x %d, stored by rows\n', nx, ny); 70 | else 71 | fprintf('%d x %d, stored by columns\n', nx, ny); 72 | end 73 | end 74 | 75 | if verbose 76 | fprintf(' plotting...'); 77 | end 78 | 79 | h = pcolor_ps(x, y, z); 80 | zrange = [min(min(z)) max(max(z))]; 81 | caxis(zrange); 82 | set(h, 'LineStyle', 'none'); 83 | axis equal; 84 | axis tight; 85 | hold on; 86 | plot(xin, yin, 'w.', 'markersize', 1); 87 | 88 | if verbose 89 | fprintf('\n'); 90 | end 91 | 92 | return 93 | 94 | function [h] = pcolor_ps(x, y, A); 95 | 96 | if nargin == 1 97 | A = x; 98 | [n, m] = size(A); 99 | xx = (0.5 : m + 0.5)'; 100 | yy = (0.5 : n + 0.5)'; 101 | elseif nargin == 3 102 | n = length(y); 103 | m = length(x); 104 | A = reshape(A, n, m); % just in case 105 | xx = getcorners(x); 106 | yy = getcorners(y); 107 | else 108 | error(sprintf('\n Error: pcolor_ps(): nargin = %d (expected 1 or 3)\n', nargin)); 109 | end 110 | 111 | TMP = zeros(n + 1, m + 1); 112 | TMP(1 : n, 1 : m) = A; 113 | 114 | if nargout == 0 115 | pcolor(xx, yy, TMP); 116 | else 117 | h = pcolor(xx, yy, TMP); 118 | end 119 | 120 | return 121 | 122 | function [c] = getcorners(x) 123 | 124 | n = length(x); 125 | c = zeros(n + 1, 1); 126 | c(2 : n) = (x(2 : n) + x(1 : n - 1)) / 2; 127 | c(1) = 2 * x(1) - c(2); 128 | c(n + 1) = 2 * x(n) - c(n); 129 | 130 | return 131 | -------------------------------------------------------------------------------- /nn/examples/5/viewinterp2.m: -------------------------------------------------------------------------------- 1 | function [h] = viewinterp2(fin, fout, verbose) 2 | 3 | if nargin == 2 4 | verbose = 1; 5 | end 6 | 7 | if verbose 8 | fprintf('plotting data from "%s" and "%s"\n', fin, fout); 9 | fprintf(' reading "%s"...', fin); 10 | end 11 | 12 | data = load(fin); 13 | xin = data(:, 1); 14 | yin = data(:, 2); 15 | zin = data(:, 3); 16 | zmin = min(zin); 17 | zmax = max(zin); 18 | nz = length(zin); 19 | 20 | if verbose 21 | fprintf('\n reading "%s"...', fout); 22 | end 23 | 24 | data = load(fout); 25 | x = data(:, 1); 26 | y = data(:, 2); 27 | z = data(:, 3); 28 | clear data; 29 | 30 | if verbose 31 | fprintf('\n'); 32 | end 33 | 34 | if verbose 35 | fprintf(' working out the grid dimensions...') 36 | end 37 | n = length(x); 38 | if x(2) - x(1) ~= 0 & y(2) - y(1) == 0 39 | xfirst = 1; 40 | xinc = x(2) > x(1); 41 | if xinc 42 | nx = min(find(diff(x) < 0)); 43 | else 44 | nx = min(find(diff(x) > 0)); 45 | end 46 | if mod(n, nx) ~= 0 47 | error(sprintf('\n Error: could not work out the grid size, n = %d, nx = %d, n / nx = %f\n', n, nx, n / nx)); 48 | end 49 | ny = n / nx; 50 | x = x(1 : nx); 51 | y = y(1 : nx : n); 52 | z = reshape(z, nx, ny)'; 53 | elseif x(2) - x(1) == 0 & y(2) - y(1) ~= 0 54 | xfirst = 0; 55 | yinc = y(2) > y(1); 56 | if yinc 57 | ny = min(find(diff(y) < 0)); 58 | else 59 | ny = min(find(diff(y) > 0)); 60 | end 61 | if mod(n, ny) ~= 0 62 | error(sprintf('\n Error: could not work out the grid size, n = %d, ny = %d, n / ny = %.3f\n', n, ny, n / ny)); 63 | end 64 | nx = n / ny; 65 | y = y(1 : ny); 66 | x = x(1 : ny : n); 67 | z = reshape(z, ny, nx); 68 | else 69 | error(' Error: not a rectangular grid'); 70 | end 71 | if verbose 72 | if xfirst 73 | fprintf('%d x %d, stored by rows\n', nx, ny); 74 | else 75 | fprintf('%d x %d, stored by columns\n', nx, ny); 76 | end 77 | end 78 | 79 | if verbose 80 | fprintf(sprintf(' plotting "%s"...', fin)); 81 | end 82 | 83 | map = colormap; 84 | hold on; 85 | for i = 1 : nz 86 | plot(xin(i), yin(i), '.', 'color', zcolor(zin(i), zmin, zmax, map), 'markersize', 2); 87 | end 88 | axis equal; 89 | axis tight; 90 | set(gca, 'box', 'on'); 91 | 92 | if verbose 93 | fprintf(sprintf('\n plotting "%s"...', fout)); 94 | end 95 | 96 | dv = floor((zmax - zmin) / 15); 97 | V = [floor(zmin) : dv : ceil(zmax)]; 98 | contour(x, y, z, V, 'k'); 99 | 100 | if verbose 101 | fprintf('\n'); 102 | end 103 | 104 | return 105 | 106 | function c = zcolor(z, zmin, zmax, map) 107 | 108 | ind = floor((z - zmin) / (zmax - zmin) * 64 + 1); 109 | ind = min(ind, 64); 110 | c = map(ind, :); 111 | 112 | return 113 | -------------------------------------------------------------------------------- /nn/examples/6/README: -------------------------------------------------------------------------------- 1 | This is yet another example based on digitised elevation contours. It provides 2 | a particularly good torture test for the numerics involved in Sibson 3 | interpolation using Watson's method. In fact, it forced me to make changes to 4 | the code that handles degenerate cases during Sibson interpolation in v. 1.69. 5 | Many thanks to Nick Cahill for identifying the problem and providing the data 6 | and to Maciej Sieczka for putting up the bug report. 7 | 8 | To reproduce the example, run "./test.sh" or "make". 9 | To visualize, in Matlab run "viewinterp('data.txt', 'nn.txt');". 10 | To clean up, run "make clean". 11 | 12 | Good luck! 13 | Pavel Sakov 14 | -------------------------------------------------------------------------------- /nn/examples/6/makefile: -------------------------------------------------------------------------------- 1 | all: 2 | ./test.sh 3 | clean: 4 | rm -f nn.txt *~ core 5 | -------------------------------------------------------------------------------- /nn/examples/6/test.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | if [ ! -x ../../nnbathy ] 4 | then 5 | echo "error: no executable found" 6 | echo 'Run "./configure" and "make" in the source directory' 7 | exit 1 8 | fi 9 | 10 | echo "" 11 | echo -n "Natural Neighbours Sibson interpolation with -W 0 ..." 12 | ../../nnbathy -W 0 -n 152x114 -x 591020.57127923 591321.93673645 -y 4260093.61151167 4259867.85217794 -i data.txt > nn.txt 13 | echo "done" 14 | echo "" 15 | echo 'To visualize, in Matlab run "viewexample"' 16 | -------------------------------------------------------------------------------- /nn/examples/6/viewexample.m: -------------------------------------------------------------------------------- 1 | viewinterp('data.txt', 'nn.txt'); 2 | -------------------------------------------------------------------------------- /nn/examples/6/viewinterp.m: -------------------------------------------------------------------------------- 1 | function [h] = viewinterp(fin, fout, verbose) 2 | 3 | if nargin == 2 4 | verbose = 1; 5 | end 6 | 7 | if verbose 8 | fprintf('plotting data from "%s" and "%s"\n', fin, fout); 9 | fprintf(' reading "%s"...', fin); 10 | end 11 | 12 | data = load(fin); 13 | xin = data(:, 1); 14 | yin = data(:, 2); 15 | 16 | if verbose 17 | fprintf('\n reading "%s"...', fout); 18 | end 19 | 20 | data = load(fout); 21 | x = data(:, 1); 22 | y = data(:, 2); 23 | z = data(:, 3); 24 | clear data; 25 | 26 | if verbose 27 | fprintf('\n'); 28 | end 29 | 30 | if verbose 31 | fprintf(' working out the grid dimensions...') 32 | end 33 | n = length(x); 34 | if x(2) - x(1) ~= 0 & y(2) - y(1) == 0 35 | xfirst = 1; 36 | xinc = x(2) > x(1); 37 | if xinc 38 | nx = min(find(diff(x) < 0)); 39 | else 40 | nx = min(find(diff(x) > 0)); 41 | end 42 | if mod(n, nx) ~= 0 43 | error(sprintf('\n Error: could not work out the grid size, n = %d, nx = %d, n / nx = %f\n', n, nx, n / nx)); 44 | end 45 | ny = n / nx; 46 | x = x(1 : nx); 47 | y = y(1 : nx : n); 48 | z = reshape(z, nx, ny)'; 49 | elseif x(2) - x(1) == 0 & y(2) - y(1) ~= 0 50 | xfirst = 0; 51 | yinc = y(2) > y(1); 52 | if yinc 53 | ny = min(find(diff(y) < 0)); 54 | else 55 | ny = min(find(diff(y) > 0)); 56 | end 57 | if mod(n, ny) ~= 0 58 | error(sprintf('\n Error: could not work out the grid size, n = %d, ny = %d, n / ny = %.3f\n', n, ny, n / ny)); 59 | end 60 | nx = n / ny; 61 | y = y(1 : ny); 62 | x = x(1 : ny : n); 63 | z = reshape(z, ny, nx); 64 | else 65 | error(' Error: not a rectangular grid'); 66 | end 67 | if verbose 68 | if xfirst 69 | fprintf('%d x %d, stored by rows\n', nx, ny); 70 | else 71 | fprintf('%d x %d, stored by columns\n', nx, ny); 72 | end 73 | end 74 | 75 | if verbose 76 | fprintf(' plotting...'); 77 | end 78 | 79 | h = pcolor_ps(x, y, z); 80 | zrange = [min(min(z)) max(max(z))]; 81 | caxis(zrange); 82 | set(h, 'LineStyle', 'none'); 83 | axis equal; 84 | axis tight; 85 | hold on; 86 | plot(xin, yin, 'k.', 'markersize', 1); 87 | 88 | if verbose 89 | fprintf('\n'); 90 | end 91 | 92 | return 93 | 94 | function [h] = pcolor_ps(x, y, A); 95 | 96 | if nargin == 1 97 | A = x; 98 | [n, m] = size(A); 99 | xx = (0.5 : m + 0.5)'; 100 | yy = (0.5 : n + 0.5)'; 101 | elseif nargin == 3 102 | n = length(y); 103 | m = length(x); 104 | A = reshape(A, n, m); % just in case 105 | xx = getcorners(x); 106 | yy = getcorners(y); 107 | else 108 | error(sprintf('\n Error: pcolor_ps(): nargin = %d (expected 1 or 3)\n', nargin)); 109 | end 110 | 111 | TMP = zeros(n + 1, m + 1); 112 | TMP(1 : n, 1 : m) = A; 113 | 114 | if nargout == 0 115 | pcolor(xx, yy, TMP); 116 | else 117 | h = pcolor(xx, yy, TMP); 118 | end 119 | 120 | return 121 | 122 | function [c] = getcorners(x) 123 | 124 | n = length(x); 125 | c = zeros(n + 1, 1); 126 | c(2 : n) = (x(2 : n) + x(1 : n - 1)) / 2; 127 | c(1) = 2 * x(1) - c(2); 128 | c(n + 1) = 2 * x(n) - c(n); 129 | 130 | return 131 | -------------------------------------------------------------------------------- /nn/examples/README: -------------------------------------------------------------------------------- 1 | This directory contains some tough (or not so tough) tests based mainly on 2 | some real data (except Examples 1 and 3), on which `nn' has initially failed. 3 | Example 1 is added for a comparison with the `csa' package in the case of 4 | uniformly distributed data. 5 | 6 | Example 1: uniformly distributed random measurements of Franke test fuction. 7 | 8 | Example 2: bathymetry from sonar. This example also includes scripts for 9 | testing parallel nnbathy. 10 | 11 | Example 3: degenerate case: both interpolation points and data points lie in 12 | the nodes of a rectangular grid. 13 | 14 | Example 4: topographic data from a satellite altimeter. 15 | 16 | Example 5: topographic data from digitised contours. 17 | 18 | Example 6: topographic data from digitised contours. 19 | -------------------------------------------------------------------------------- /nn/hash.c: -------------------------------------------------------------------------------- 1 | /****************************************************************************** 2 | * 3 | * File: hash.c 4 | * 5 | * Purpose: Hash table implementation 6 | * 7 | * Author: Jerry Coffin 8 | * 9 | * Description: Public domain code by Jerry Coffin, with improvements by 10 | * HenkJan Wolthuis. 11 | * 12 | * Revisions: 18-09-2002 -- Pavel Sakov: modified 13 | * 07-06-2017 -- Pavel Sakov: changed the hash type from 14 | * unsigned int to uint32_t 15 | * 16 | *****************************************************************************/ 17 | 18 | #include 19 | #include 20 | #include 21 | #include 22 | #include "hash.h" 23 | 24 | #define SIZEOFDOUBLE 8 25 | 26 | /** A hash table consists of an array of these buckets. 27 | */ 28 | typedef struct ht_bucket { 29 | void* key; 30 | void* data; 31 | int id; /* unique id -- just in case */ 32 | struct ht_bucket* next; 33 | } ht_bucket; 34 | 35 | /** Hash table structure. 36 | * Note that more nodes than `size' can be inserted in the table, 37 | * but performance degrades as this happens. 38 | */ 39 | struct hashtable { 40 | int size; /* table size */ 41 | int n; /* current number of entries */ 42 | int naccum; /* number of inserted entries */ 43 | int nhash; /* number of used table elements */ 44 | ht_keycp cp; 45 | ht_keyeq eq; 46 | ht_key2hash hash; 47 | ht_bucket** table; 48 | }; 49 | 50 | /** Creates a hash table of specified size. 51 | * 52 | * @param size Size of hash table for output points 53 | * @param cp Key copy function 54 | * @param eq Key equality check function 55 | * @param hash Hash value calculation function 56 | */ 57 | hashtable* ht_create(int size, ht_keycp cp, ht_keyeq eq, ht_key2hash hash) 58 | { 59 | hashtable* table = malloc(sizeof(hashtable)); 60 | ht_bucket** bucket; 61 | int i; 62 | 63 | assert(table != NULL); 64 | 65 | if (size <= 0) { 66 | free(table); 67 | return NULL; 68 | } 69 | 70 | table->size = size; 71 | table->table = malloc(sizeof(ht_bucket*) * size); 72 | assert(table->table != NULL); 73 | bucket = table->table; 74 | 75 | if (bucket == NULL) { 76 | free(table); 77 | return NULL; 78 | } 79 | 80 | for (i = 0; i < size; ++i) 81 | bucket[i] = NULL; 82 | table->n = 0; 83 | table->naccum = 0; 84 | table->nhash = 0; 85 | table->eq = eq; 86 | table->cp = cp; 87 | table->hash = hash; 88 | 89 | return table; 90 | } 91 | 92 | /* Destroys a hash table. 93 | * (Take care of deallocating data by ht_process() prior to destroying the 94 | * table if necessary.) 95 | * 96 | * @param table Hash table to be destroyed 97 | */ 98 | void ht_destroy(hashtable* table) 99 | { 100 | int i; 101 | 102 | if (table == NULL) 103 | return; 104 | 105 | for (i = 0; i < table->size; ++i) { 106 | ht_bucket* bucket; 107 | 108 | for (bucket = (table->table)[i]; bucket != NULL;) { 109 | ht_bucket* prev = bucket; 110 | 111 | free(bucket->key); 112 | bucket = bucket->next; 113 | free(prev); 114 | } 115 | } 116 | 117 | free(table->table); 118 | free(table); 119 | } 120 | 121 | /* Inserts a new entry into the hash table. 122 | * 123 | * @param table The hash table 124 | * @param key Ponter to entry's key 125 | * @param data Pointer to associated data 126 | * @return Pointer to the old data associated with the key, NULL if the key 127 | * wasn't in the table previously 128 | */ 129 | void* ht_insert(hashtable* table, void* key, void* data) 130 | { 131 | uint32_t val = table->hash(key) % table->size; 132 | ht_bucket* bucket; 133 | 134 | /* 135 | * NULL means this bucket hasn't been used yet. We'll simply allocate 136 | * space for our new bucket and put our data there, with the table 137 | * pointing at it. 138 | */ 139 | if ((table->table)[val] == NULL) { 140 | bucket = malloc(sizeof(ht_bucket)); 141 | assert(bucket != NULL); 142 | 143 | bucket->key = table->cp(key); 144 | bucket->next = NULL; 145 | bucket->data = data; 146 | bucket->id = table->naccum; 147 | 148 | (table->table)[val] = bucket; 149 | table->n++; 150 | table->naccum++; 151 | table->nhash++; 152 | 153 | return NULL; 154 | } 155 | 156 | /* 157 | * This spot in the table is already in use. See if the current string 158 | * has already been inserted, and if so, return corresponding data. 159 | */ 160 | for (bucket = (table->table)[val]; bucket != NULL; bucket = bucket->next) 161 | if (table->eq(key, bucket->key) == 1) { 162 | void* old_data = bucket->data; 163 | 164 | bucket->data = data; 165 | bucket->id = table->naccum; 166 | table->naccum++; 167 | 168 | return old_data; 169 | } 170 | 171 | /* 172 | * This key must not be in the table yet. We'll add it to the head of 173 | * the list at this spot in the hash table. Speed would be slightly 174 | * improved if the list was kept sorted instead. In this case, this 175 | * code would be moved into the loop above, and the insertion would take 176 | * place as soon as it was determined that the present key in the list 177 | * was larger than this one. 178 | */ 179 | bucket = (ht_bucket*) malloc(sizeof(ht_bucket)); 180 | assert(bucket != NULL); 181 | bucket->key = table->cp(key); 182 | bucket->data = data; 183 | bucket->next = (table->table)[val]; 184 | bucket->id = table->naccum; 185 | 186 | (table->table)[val] = bucket; 187 | table->n++; 188 | table->naccum++; 189 | 190 | return NULL; 191 | } 192 | 193 | /* Returns a pointer to the data associated with a key. If the key has 194 | * not been inserted in the table, returns NULL. 195 | * 196 | * @param table The hash table 197 | * @param key The key 198 | * @return The associated data or NULL 199 | */ 200 | void* ht_find(hashtable* table, void* key) 201 | { 202 | uint32_t val = table->hash(key) % table->size; 203 | ht_bucket* bucket; 204 | 205 | if ((table->table)[val] == NULL) 206 | return NULL; 207 | 208 | for (bucket = (table->table)[val]; bucket != NULL; bucket = bucket->next) 209 | if (table->eq(key, bucket->key) == 1) 210 | return bucket->data; 211 | 212 | return NULL; 213 | } 214 | 215 | /** Returns id of the bucket associated with a key. If the key has 216 | * not been inserted in the table, returns -1. 217 | * 218 | * @param table The hash table 219 | * @param key The key 220 | * @return id or -1 221 | */ 222 | int ht_findid(hashtable* table, void* key) 223 | { 224 | uint32_t val = table->hash(key) % table->size; 225 | ht_bucket* bucket; 226 | 227 | if ((table->table)[val] == NULL) 228 | return -1; 229 | 230 | for (bucket = (table->table)[val]; bucket != NULL; bucket = bucket->next) 231 | if (table->eq(key, bucket->key) == 1) 232 | return bucket->id; 233 | 234 | return -1; 235 | } 236 | 237 | /* Deletes an entry from the table. Returns a pointer to the data that 238 | * was associated with the key so that the calling code can dispose it 239 | * properly. 240 | * 241 | * @param table The hash table 242 | * @param key The key 243 | * @return The associated data or NULL 244 | */ 245 | void* ht_delete(hashtable* table, void* key) 246 | { 247 | uint32_t val = table->hash(key) % table->size; 248 | ht_bucket* prev; 249 | ht_bucket* bucket; 250 | void* data; 251 | 252 | if ((table->table)[val] == NULL) 253 | return NULL; 254 | 255 | /* 256 | * Traverse the list, keeping track of the previous node in the list. 257 | * When we find the node to delete, we set the previous node's next 258 | * pointer to point to the node after ourself instead. We then delete 259 | * the key from the present node, and return a pointer to the data it 260 | * contains. 261 | */ 262 | for (prev = NULL, bucket = (table->table)[val]; bucket != NULL; prev = bucket, bucket = bucket->next) { 263 | if (table->eq(key, bucket->key) == 1) { 264 | data = bucket->data; 265 | if (prev != NULL) 266 | prev->next = bucket->next; 267 | else { 268 | /* 269 | * If 'prev' still equals NULL, it means that we need to 270 | * delete the first node in the list. This simply consists 271 | * of putting our own 'next' pointer in the array holding 272 | * the head of the list. We then dispose of the current 273 | * node as above. 274 | */ 275 | (table->table)[val] = bucket->next; 276 | table->nhash--; 277 | } 278 | free(bucket->key); 279 | free(bucket); 280 | table->n--; 281 | 282 | return data; 283 | } 284 | } 285 | 286 | /* 287 | * If we get here, it means we didn't find the item in the table. Signal 288 | * this by returning NULL. 289 | */ 290 | return NULL; 291 | } 292 | 293 | /* For each entry, calls a specified function with corresponding data as a 294 | * parameter. 295 | * 296 | * @param table The hash table 297 | * @param func The action function 298 | */ 299 | void ht_process(hashtable* table, void (*func) (void*)) 300 | { 301 | int i; 302 | 303 | for (i = 0; i < table->size; ++i) 304 | if ((table->table)[i] != NULL) { 305 | ht_bucket* bucket; 306 | 307 | for (bucket = (table->table)[i]; bucket != NULL; bucket = bucket->next) 308 | func(bucket->data); 309 | } 310 | } 311 | 312 | /* 313 | * functions for for string keys 314 | */ 315 | 316 | static uint32_t strhash(void* key) 317 | { 318 | char* str = key; 319 | uint32_t hashvalue = 0; 320 | 321 | while (*str != 0) { 322 | hashvalue ^= (uint32_t) str[0]; 323 | hashvalue <<= 1; 324 | str++; 325 | } 326 | 327 | return hashvalue; 328 | } 329 | 330 | static void* strcp(void* key) 331 | { 332 | return strdup(key); 333 | } 334 | 335 | static int streq(void* key1, void* key2) 336 | { 337 | return !strcmp(key1, key2); 338 | } 339 | 340 | /* functions for for double keys */ 341 | 342 | static uint32_t d1hash(void* key) 343 | { 344 | uint32_t* v = key; 345 | 346 | return v[0] + v[1]; 347 | } 348 | 349 | static void* d1cp(void* key) 350 | { 351 | double* newkey = malloc(sizeof(double)); 352 | 353 | *newkey = *(double*) key; 354 | 355 | return newkey; 356 | } 357 | 358 | static int d1eq(void* key1, void* key2) 359 | { 360 | return *(double*) key1 == *(double*) key2; 361 | } 362 | 363 | /* 364 | * functions for for double[2] keys 365 | */ 366 | 367 | static uint32_t d2hash(void* key) 368 | { 369 | uint32_t* v = key; 370 | 371 | /* 372 | * PS: here multiplications suppose to make (a,b) and (b,a) generate 373 | * different hash values 374 | */ 375 | return v[0] + v[1] + v[2] * 3 + v[3] * 7; 376 | } 377 | 378 | static void* d2cp(void* key) 379 | { 380 | double* newkey = malloc(sizeof(double) * 2); 381 | 382 | newkey[0] = ((double*) key)[0]; 383 | newkey[1] = ((double*) key)[1]; 384 | 385 | return newkey; 386 | } 387 | 388 | static int d2eq(void* key1, void* key2) 389 | { 390 | return (((double*) key1)[0] == ((double*) key2)[0]) && (((double*) key1)[1] == ((double*) key2)[1]); 391 | } 392 | 393 | /* 394 | * functions for for int[1] keys 395 | */ 396 | 397 | static uint32_t i1hash(void* key) 398 | { 399 | return (uint32_t) ((uint32_t *) key)[0]; 400 | } 401 | 402 | static void* i1cp(void* key) 403 | { 404 | uint32_t* newkey = malloc(sizeof(int)); 405 | 406 | newkey[0] = ((uint32_t *) key)[0]; 407 | 408 | return newkey; 409 | } 410 | 411 | static int i1eq(void* key1, void* key2) 412 | { 413 | return (((uint32_t *) key1)[0] == ((uint32_t *) key2)[0]); 414 | } 415 | 416 | /* 417 | * functions for for int[2] keys 418 | */ 419 | 420 | static uint32_t i2hash(void* key) 421 | { 422 | uint32_t* v = key; 423 | 424 | return v[0] + (v[1] << 16); 425 | } 426 | 427 | static void* i2cp(void* key) 428 | { 429 | uint32_t* newkey = malloc(sizeof(uint32_t) * 2); 430 | 431 | newkey[0] = ((uint32_t *) key)[0]; 432 | newkey[1] = ((uint32_t *) key)[1]; 433 | 434 | return newkey; 435 | } 436 | 437 | static int i2eq(void* key1, void* key2) 438 | { 439 | return (((uint32_t *) key1)[0] == ((uint32_t *) key2)[0]) && (((uint32_t *) key1)[1] == ((uint32_t *) key2)[1]); 440 | } 441 | 442 | /* 443 | * functions for for int[1]short[2] keys 444 | */ 445 | 446 | static uint32_t i1s2hash(void* key) 447 | { 448 | uint32_t* vi = key; 449 | uint16_t* vs = key; 450 | 451 | return vi[0] + ((uint32_t) vs[2] << 16) + ((uint32_t) vs[3] << 24); 452 | } 453 | 454 | static void* i1s2cp(void* key) 455 | { 456 | uint32_t* newkey = malloc(sizeof(uint32_t) * 2); 457 | uint16_t* s = (uint16_t *) newkey; 458 | 459 | newkey[0] = ((uint32_t *) key)[0]; 460 | s[2] = ((uint16_t *) key)[2]; 461 | s[3] = ((uint16_t *) key)[3]; 462 | 463 | return newkey; 464 | } 465 | 466 | static int i1s2eq(void* key1, void* key2) 467 | { 468 | return (((uint32_t *) key1)[0] == ((uint32_t *) key2)[0]) && (((uint16_t *) key1)[2] == ((uint16_t *) key2)[2]) && (((uint16_t *) key1)[3] == ((uint16_t *) key2)[3]); 469 | } 470 | 471 | /* 472 | * functions for for short[4] keys 473 | */ 474 | 475 | static uint32_t s4hash(void* key) 476 | { 477 | uint16_t* v = key; 478 | 479 | return (uint32_t) v[0] + ((uint32_t) v[1] << 8) + ((uint32_t) v[2] << 16) + ((uint32_t) v[3] << 24); 480 | } 481 | 482 | static void* s4cp(void* key) 483 | { 484 | uint16_t* newkey = malloc(sizeof(short) * 4); 485 | 486 | newkey[0] = ((uint16_t *) key)[0]; 487 | newkey[1] = ((uint16_t *) key)[1]; 488 | newkey[2] = ((uint16_t *) key)[2]; 489 | newkey[3] = ((uint16_t *) key)[3]; 490 | 491 | return newkey; 492 | } 493 | 494 | static int s4eq(void* p1, void* p2) 495 | { 496 | uint16_t* key1 = (uint16_t *) p1; 497 | uint16_t* key2 = (uint16_t *) p2; 498 | 499 | return (key1[0] == key2[0] && key1[1] == key2[1] && key1[2] == key2[2] && key1[3] == key2[3]); 500 | } 501 | 502 | hashtable* ht_create_d1(int size) 503 | { 504 | assert(sizeof(double) == SIZEOFDOUBLE); 505 | return ht_create(size, d1cp, d1eq, d1hash); 506 | } 507 | 508 | hashtable* ht_create_d2(int size) 509 | { 510 | assert(sizeof(double) == SIZEOFDOUBLE); 511 | return ht_create(size, d2cp, d2eq, d2hash); 512 | } 513 | 514 | hashtable* ht_create_str(int size) 515 | { 516 | return ht_create(size, strcp, streq, strhash); 517 | } 518 | 519 | hashtable* ht_create_i1(int size) 520 | { 521 | return ht_create(size, i1cp, i1eq, i1hash); 522 | } 523 | 524 | hashtable* ht_create_i2(int size) 525 | { 526 | return ht_create(size, i2cp, i2eq, i2hash); 527 | } 528 | 529 | hashtable* ht_create_i1s2(int size) 530 | { 531 | return ht_create(size, i1s2cp, i1s2eq, i1s2hash); 532 | } 533 | 534 | hashtable* ht_create_s4(int size) 535 | { 536 | return ht_create(size, s4cp, s4eq, s4hash); 537 | } 538 | 539 | int ht_getnentries(hashtable* table) 540 | { 541 | return table->n; 542 | } 543 | 544 | int ht_getsize(hashtable* table) 545 | { 546 | return table->size; 547 | } 548 | 549 | int ht_getnfilled(hashtable* table) 550 | { 551 | return table->nhash; 552 | } 553 | 554 | #if defined(HT_TEST) 555 | 556 | #include 557 | #include 558 | 559 | #define BUFSIZE 1024 560 | 561 | static void print_double(void* data) 562 | { 563 | printf(" \"%d\"", (int)* (double*) data); 564 | } 565 | 566 | static void print_string(void* data) 567 | { 568 | printf(" \"%s\"", (char*) data); 569 | } 570 | 571 | int main() 572 | { 573 | double points[] = { 574 | 922803.7855, 7372394.688, 0, 575 | 922849.2037, 7372307.027, 1, 576 | 922894.657, 7372219.306, 2, 577 | 922940.1475, 7372131.528, 3, 578 | 922985.6777, 7372043.692, 4, 579 | 923031.2501, 7371955.802, 5, 580 | 923076.8669, 7371867.857, 6, 581 | 923122.5307, 7371779.861, 7, 582 | 923168.2439, 7371691.816, 8, 583 | 923214.0091, 7371603.722, 9, 584 | 923259.8288, 7371515.583, 10, 585 | 922891.3958, 7372440.117, 11, 586 | 922936.873, 7372352.489, 12, 587 | 922982.3839, 7372264.804, 13, 588 | 923027.9308, 7372177.064, 14, 589 | 923073.5159, 7372089.268, 15, 590 | 923119.1415, 7372001.42, 16, 591 | 923164.8099, 7371913.521, 17, 592 | 923210.5233, 7371825.572, 18, 593 | 923256.2841, 7371737.575, 19, 594 | 923302.0946, 7371649.534, 20, 595 | 923347.9572, 7371561.45, 21, 596 | 922978.9747, 7372485.605, 22, 597 | 923024.5085, 7372398.009, 23, 598 | 923070.0748, 7372310.358, 24, 599 | 923115.6759, 7372222.654, 25, 600 | 923161.3136, 7372134.897, 26, 601 | 923206.9903, 7372047.09, 27, 602 | 923252.7079, 7371959.233, 28, 603 | 923298.4686, 7371871.33, 29, 604 | 923344.2745, 7371783.381, 30, 605 | 923390.1279, 7371695.389, 31, 606 | 923436.0309, 7371607.357, 32, 607 | 923066.5232, 7372531.148, 33, 608 | 923112.1115, 7372443.583, 34, 609 | 923157.7311, 7372355.966, 35, 610 | 923203.3842, 7372268.296, 36, 611 | 923249.0725, 7372180.577, 37, 612 | 923294.7981, 7372092.808, 38, 613 | 923340.5628, 7372004.993, 39, 614 | 923386.3686, 7371917.132, 40, 615 | 923432.2176, 7371829.229, 41, 616 | 923478.1116, 7371741.284, 42, 617 | 923524.0527, 7371653.302, 43, 618 | 923154.0423, 7372576.746, 44, 619 | 923199.6831, 7372489.211, 45, 620 | 923245.3541, 7372401.625, 46, 621 | 923291.0572, 7372313.989, 47, 622 | 923336.7941, 7372226.305, 48, 623 | 923382.5667, 7372138.574, 49, 624 | 923428.3766, 7372050.798, 50, 625 | 923474.2256, 7371962.978, 51, 626 | 923520.1155, 7371875.118, 52, 627 | 923566.0481, 7371787.218, 53, 628 | 923612.0252, 7371699.282, 54, 629 | 923241.533, 7372622.396, 55, 630 | 923287.2244, 7372534.889, 56, 631 | 923332.9449, 7372447.334, 57, 632 | 923378.6963, 7372359.731, 58, 633 | 923424.4801, 7372272.081, 59, 634 | 923470.2979, 7372184.385, 60, 635 | 923516.1513, 7372096.646, 61, 636 | 923562.0418, 7372008.866, 62, 637 | 923607.9709, 7371921.046, 63, 638 | 923653.9402, 7371833.188, 64, 639 | 923699.9514, 7371745.296, 65, 640 | 923328.9962, 7372668.095, 66, 641 | 923374.7365, 7372580.617, 67, 642 | 923420.5049, 7372493.091, 68, 643 | 923466.303, 7372405.519, 69, 644 | 923512.1321, 7372317.901, 70, 645 | 923557.9936, 7372230.24, 71, 646 | 923603.8889, 7372142.536, 72, 647 | 923649.8192, 7372054.793, 73, 648 | 923695.786, 7371967.011, 74, 649 | 923741.7905, 7371879.193, 75, 650 | 923787.8341, 7371791.342, 76, 651 | 923416.4327, 7372713.844, 77, 652 | 923462.2204, 7372626.393, 78, 653 | 923508.0353, 7372538.895, 79, 654 | 923553.8787, 7372451.353, 80, 655 | 923599.7517, 7372363.766, 81, 656 | 923645.6555, 7372276.137, 82, 657 | 923691.5914, 7372188.467, 83, 658 | 923737.5603, 7372100.757, 84, 659 | 923783.5634, 7372013.011, 85, 660 | 923829.6017, 7371925.231, 86, 661 | 923875.6763, 7371837.419, 87, 662 | 923503.8433, 7372759.64, 88, 663 | 923549.6771, 7372672.214, 89, 664 | 923595.5372, 7372584.744, 90, 665 | 923641.4246, 7372497.23, 91, 666 | 923687.3404, 7372409.673, 92, 667 | 923733.2855, 7372322.074, 93, 668 | 923779.2608, 7372234.436, 94, 669 | 923825.2672, 7372146.759, 95, 670 | 923871.3056, 7372059.047, 96, 671 | 923917.3766, 7371971.301, 97, 672 | 923963.4812, 7371883.524, 98, 673 | 923591.2288, 7372805.481, 99, 674 | 923637.1076, 7372718.081, 100, 675 | 923683.0118, 7372630.638, 101, 676 | 923728.9423, 7372543.151, 102, 677 | 923774.8998, 7372455.622, 103, 678 | 923820.8852, 7372368.052, 104, 679 | 923866.8991, 7372280.443, 105, 680 | 923912.9422, 7372192.797, 106, 681 | 923959.015, 7372105.116, 107, 682 | 924005.118, 7372017.402, 108, 683 | 924051.2518, 7371929.657, 109, 684 | 923678.5898, 7372851.367, 110, 685 | 923724.5126, 7372763.992, 111, 686 | 923770.46, 7372676.574, 112, 687 | 923816.4328, 7372589.113, 113, 688 | 923862.4314, 7372501.611, 114, 689 | 923908.4564, 7372414.069, 115, 690 | 923954.5083, 7372326.488, 116, 691 | 924000.5875, 7372238.87, 117, 692 | 924046.6941, 7372151.218, 118, 693 | 924092.8286, 7372063.533, 119, 694 | 924138.9911, 7371975.818, 120 695 | }; 696 | 697 | int size = sizeof(points) / sizeof(double) / 3; 698 | hashtable* ht; 699 | int i; 700 | 701 | /* 702 | * double[2] key 703 | */ 704 | 705 | printf("\n1. Testing a table with key of double[2] type\n\n"); 706 | 707 | printf(" creating a table..."); 708 | ht = ht_create_d2(size); 709 | printf("done\n"); 710 | 711 | printf(" inserting %d values from a data array...", size); 712 | for (i = 0; i < size; ++i) 713 | ht_insert(ht, &points[i * 3], &points[i * 3 + 2]); 714 | printf("done\n"); 715 | 716 | printf(" stats:\n"); 717 | printf(" %d entries, %d table elements, %d filled elements\n", ht->n, ht->size, ht->nhash); 718 | printf(" %f entries per hash value in use\n", (double) ht->n / ht->nhash); 719 | 720 | printf(" finding and printing each 10th data:\n"); 721 | for (i = 0; i < size; i += 10) { 722 | double* point = &points[i * 3]; 723 | double* data = ht_find(ht, point); 724 | 725 | if (data != NULL) 726 | printf(" i = %d; data = \"%d\"\n", i, (int)* data); 727 | else 728 | printf(" i = %d; data = \n", i); 729 | } 730 | 731 | printf(" removing every 3rd element..."); 732 | for (i = 0; i < size; i += 3) { 733 | double* point = &points[i * 3]; 734 | 735 | ht_delete(ht, point); 736 | } 737 | printf("done\n"); 738 | 739 | printf(" stats:\n"); 740 | printf(" %d entries, %d table elements, %d filled elements\n", ht->n, ht->size, ht->nhash); 741 | printf(" %f entries per hash value in use\n", (double) ht->n / ht->nhash); 742 | 743 | printf(" finding and printing each 10th data:\n"); 744 | for (i = 0; i < size; i += 10) { 745 | double* point = &points[i * 3]; 746 | double* data = ht_find(ht, point); 747 | 748 | if (data != NULL) 749 | printf(" i = %d; data = \"%d\"\n", i, (int)* data); 750 | else 751 | printf(" i = %d; data = \n", i); 752 | } 753 | 754 | printf(" printing all data by calling ht_process():\n "); 755 | ht_process(ht, print_double); 756 | 757 | printf("\n destroying the hash table..."); 758 | ht_destroy(ht); 759 | printf("done\n"); 760 | 761 | /* 762 | * char* key 763 | */ 764 | 765 | printf("\n2. Testing a table with key of char* type\n\n"); 766 | 767 | printf(" creating a table..."); 768 | ht = ht_create_str(size); 769 | printf("done\n"); 770 | 771 | printf(" inserting %d elements with deep copy of each data string...", size); 772 | for (i = 0; i < size; ++i) { 773 | char key[BUFSIZE]; 774 | char str[BUFSIZE]; 775 | char* data; 776 | 777 | snprintf(key, BUFSIZE, "%d-th key", i); 778 | snprintf(str, BUFSIZE, "%d-th data", i); 779 | data = strdup(str); 780 | ht_insert(ht, key, data); 781 | } 782 | printf("done\n"); 783 | 784 | printf(" stats:\n"); 785 | printf(" %d entries, %d table elements, %d filled elements\n", ht->n, ht->size, ht->nhash); 786 | printf(" %f entries per hash value in use\n", (double) ht->n / ht->nhash); 787 | 788 | printf(" finding and printing each 10th data:\n"); 789 | for (i = 0; i < size; i += 10) { 790 | char key[BUFSIZE]; 791 | char* data; 792 | 793 | snprintf(key, BUFSIZE, "%d-th key", i); 794 | data = ht_find(ht, key); 795 | if (data != NULL) 796 | printf(" i = %d; data = \"%s\"\n", i, data); 797 | else 798 | printf(" i = %d; data = \n", i); 799 | } 800 | 801 | printf(" removing every 3rd element..."); 802 | for (i = 0; i < size; i += 3) { 803 | char key[BUFSIZE]; 804 | 805 | snprintf(key, BUFSIZE, "%d-th key", i); 806 | free(ht_delete(ht, key)); 807 | } 808 | printf("done\n"); 809 | 810 | printf(" stats:\n"); 811 | printf(" %d entries, %d table elements, %d filled elements\n", ht->n, ht->size, ht->nhash); 812 | printf(" %f entries per hash value in use\n", (double) ht->n / ht->nhash); 813 | 814 | printf(" finding and printing each 10th data:\n"); 815 | for (i = 0; i < size; i += 10) { 816 | char key[BUFSIZE]; 817 | char* data; 818 | 819 | snprintf(key, BUFSIZE, "%d-th key", i); 820 | data = ht_find(ht, key); 821 | if (data != NULL) 822 | printf(" i = %d; data = \"%s\"\n", i, data); 823 | else 824 | printf(" i = %d; data = \n", i); 825 | } 826 | 827 | printf(" printing all data by calling ht_process():\n "); 828 | ht_process(ht, print_string); 829 | 830 | printf("\n freeing the remaining data by calling ht_process()..."); 831 | ht_process(ht, free); 832 | printf("done\n"); 833 | 834 | printf(" destroying the hash table..."); 835 | ht_destroy(ht); 836 | printf("done\n"); 837 | 838 | return 0; 839 | } 840 | 841 | #endif /* HT_TEST */ 842 | -------------------------------------------------------------------------------- /nn/hash.h: -------------------------------------------------------------------------------- 1 | /****************************************************************************** 2 | * 3 | * File: hash.h 4 | * 5 | * Purpose: Hash table header 6 | * 7 | * Author: Jerry Coffin 8 | * 9 | * Description: Public domain code by Jerry Coffin, with improvements by 10 | * HenkJan Wolthuis. 11 | * Date last modified: 05-Jul-1997 12 | * 13 | * Revisions: 18-09-2002 -- Pavel Sakov: modified 14 | * 07-06-2017 -- Pavel Sakov: changed the hash type from 15 | * unsigned int to uint32_t 16 | * 17 | *****************************************************************************/ 18 | 19 | #ifndef _HASH_H 20 | #define _HASH_H 21 | 22 | #include 23 | 24 | struct hashtable; 25 | typedef struct hashtable hashtable; 26 | 27 | /** Copies a key. The key must permit to be deallocated by free(). 28 | */ 29 | typedef void* (*ht_keycp) (void*); 30 | 31 | /** Returns 1 if two keys are equal, 0 otherwise. 32 | */ 33 | typedef int (*ht_keyeq) (void*, void*); 34 | 35 | /** Converts key to an unsigned 32-bit integer (not necessarily unique). 36 | */ 37 | typedef uint32_t(*ht_key2hash) (void*); 38 | 39 | hashtable* ht_create(int size, ht_keycp cp, ht_keyeq eq, ht_key2hash hash); 40 | 41 | /** Create a hash table of specified size and key type. 42 | */ 43 | hashtable* ht_create_d1(int size); /* double[1] */ 44 | hashtable* ht_create_d2(int size); /* double[2] */ 45 | hashtable* ht_create_str(int size); /* char* */ 46 | hashtable* ht_create_i1(int size); /* uint32_t[1] */ 47 | hashtable* ht_create_i2(int size); /* uint32_t[2] */ 48 | hashtable* ht_create_i1s2(int size); /* uint32_t[1]uint16_t[2] */ 49 | hashtable* ht_create_s4(int size); /* uint16_t[4] */ 50 | 51 | void ht_destroy(hashtable* table); 52 | void* ht_insert(hashtable* table, void* key, void* data); 53 | void* ht_find(hashtable* table, void* key); 54 | int ht_findid(hashtable* table, void* key); 55 | void* ht_delete(hashtable* table, void* key); 56 | void ht_process(hashtable* table, void (*func) (void*)); 57 | int ht_getnentries(hashtable* table); 58 | int ht_getsize(hashtable* table); 59 | int ht_getnfilled(hashtable* table); 60 | 61 | #endif /* _HASH_H */ 62 | -------------------------------------------------------------------------------- /nn/install-sh: -------------------------------------------------------------------------------- 1 | #! /bin/sh 2 | # 3 | # install - install a program, script, or datafile 4 | # This comes from X11R5. 5 | # 6 | # Calling this script install-sh is preferred over install.sh, to prevent 7 | # `make' implicit rules from creating a file called install from it 8 | # when there is no Makefile. 9 | # 10 | # This script is compatible with the BSD install script, but was written 11 | # from scratch. 12 | # 13 | 14 | 15 | # set DOITPROG to echo to test this script 16 | 17 | # Don't use :- since 4.3BSD and earlier shells don't like it. 18 | doit="${DOITPROG-}" 19 | 20 | 21 | # put in absolute paths if you don't have them in your path; or use env. vars. 22 | 23 | mvprog="${MVPROG-mv}" 24 | cpprog="${CPPROG-cp}" 25 | chmodprog="${CHMODPROG-chmod}" 26 | chownprog="${CHOWNPROG-chown}" 27 | chgrpprog="${CHGRPPROG-chgrp}" 28 | stripprog="${STRIPPROG-strip}" 29 | rmprog="${RMPROG-rm}" 30 | mkdirprog="${MKDIRPROG-mkdir}" 31 | 32 | tranformbasename="" 33 | transform_arg="" 34 | instcmd="$mvprog" 35 | chmodcmd="$chmodprog 0755" 36 | chowncmd="" 37 | chgrpcmd="" 38 | stripcmd="" 39 | rmcmd="$rmprog -f" 40 | mvcmd="$mvprog" 41 | src="" 42 | dst="" 43 | dir_arg="" 44 | 45 | while [ x"$1" != x ]; do 46 | case $1 in 47 | -c) instcmd="$cpprog" 48 | shift 49 | continue;; 50 | 51 | -d) dir_arg=true 52 | shift 53 | continue;; 54 | 55 | -m) chmodcmd="$chmodprog $2" 56 | shift 57 | shift 58 | continue;; 59 | 60 | -o) chowncmd="$chownprog $2" 61 | shift 62 | shift 63 | continue;; 64 | 65 | -g) chgrpcmd="$chgrpprog $2" 66 | shift 67 | shift 68 | continue;; 69 | 70 | -s) stripcmd="$stripprog" 71 | shift 72 | continue;; 73 | 74 | -t=*) transformarg=`echo $1 | sed 's/-t=//'` 75 | shift 76 | continue;; 77 | 78 | -b=*) transformbasename=`echo $1 | sed 's/-b=//'` 79 | shift 80 | continue;; 81 | 82 | *) if [ x"$src" = x ] 83 | then 84 | src=$1 85 | else 86 | # this colon is to work around a 386BSD /bin/sh bug 87 | : 88 | dst=$1 89 | fi 90 | shift 91 | continue;; 92 | esac 93 | done 94 | 95 | if [ x"$src" = x ] 96 | then 97 | echo "install: no input file specified" 98 | exit 1 99 | else 100 | true 101 | fi 102 | 103 | if [ x"$dir_arg" != x ]; then 104 | dst=$src 105 | src="" 106 | 107 | if [ -d $dst ]; then 108 | instcmd=: 109 | else 110 | instcmd=mkdir 111 | fi 112 | else 113 | 114 | # Waiting for this to be detected by the "$instcmd $src $dsttmp" command 115 | # might cause directories to be created, which would be especially bad 116 | # if $src (and thus $dsttmp) contains '*'. 117 | 118 | if [ -f $src -o -d $src ] 119 | then 120 | true 121 | else 122 | echo "install: $src does not exist" 123 | exit 1 124 | fi 125 | 126 | if [ x"$dst" = x ] 127 | then 128 | echo "install: no destination specified" 129 | exit 1 130 | else 131 | true 132 | fi 133 | 134 | # If destination is a directory, append the input filename; if your system 135 | # does not like double slashes in filenames, you may need to add some logic 136 | 137 | if [ -d $dst ] 138 | then 139 | dst="$dst"/`basename $src` 140 | else 141 | true 142 | fi 143 | fi 144 | 145 | ## this sed command emulates the dirname command 146 | dstdir=`echo $dst | sed -e 's,[^/]*$,,;s,/$,,;s,^$,.,'` 147 | 148 | # Make sure that the destination directory exists. 149 | # this part is taken from Noah Friedman's mkinstalldirs script 150 | 151 | # Skip lots of stat calls in the usual case. 152 | if [ ! -d "$dstdir" ]; then 153 | defaultIFS=' 154 | ' 155 | IFS="${IFS-${defaultIFS}}" 156 | 157 | oIFS="${IFS}" 158 | # Some sh's can't handle IFS=/ for some reason. 159 | IFS='%' 160 | set - `echo ${dstdir} | sed -e 's@/@%@g' -e 's@^%@/@'` 161 | IFS="${oIFS}" 162 | 163 | pathcomp='' 164 | 165 | while [ $# -ne 0 ] ; do 166 | pathcomp="${pathcomp}${1}" 167 | shift 168 | 169 | if [ ! -d "${pathcomp}" ] ; 170 | then 171 | $mkdirprog "${pathcomp}" 172 | else 173 | true 174 | fi 175 | 176 | pathcomp="${pathcomp}/" 177 | done 178 | fi 179 | 180 | if [ x"$dir_arg" != x ] 181 | then 182 | $doit $instcmd $dst && 183 | 184 | if [ x"$chowncmd" != x ]; then $doit $chowncmd $dst; else true ; fi && 185 | if [ x"$chgrpcmd" != x ]; then $doit $chgrpcmd $dst; else true ; fi && 186 | if [ x"$stripcmd" != x ]; then $doit $stripcmd $dst; else true ; fi && 187 | if [ x"$chmodcmd" != x ]; then $doit $chmodcmd $dst; else true ; fi 188 | else 189 | 190 | # If we're going to rename the final executable, determine the name now. 191 | 192 | if [ x"$transformarg" = x ] 193 | then 194 | dstfile=`basename $dst` 195 | else 196 | dstfile=`basename $dst $transformbasename | 197 | sed $transformarg`$transformbasename 198 | fi 199 | 200 | # don't allow the sed command to completely eliminate the filename 201 | 202 | if [ x"$dstfile" = x ] 203 | then 204 | dstfile=`basename $dst` 205 | else 206 | true 207 | fi 208 | 209 | # Make a temp file name in the proper directory. 210 | 211 | dsttmp=$dstdir/#inst.$$# 212 | 213 | # Move or copy the file name to the temp name 214 | 215 | $doit $instcmd $src $dsttmp && 216 | 217 | trap "rm -f ${dsttmp}" 0 && 218 | 219 | # and set any options; do chmod last to preserve setuid bits 220 | 221 | # If any of these fail, we abort the whole thing. If we want to 222 | # ignore errors from any of these, just make sure not to ignore 223 | # errors from the above "$doit $instcmd $src $dsttmp" command. 224 | 225 | if [ x"$chowncmd" != x ]; then $doit $chowncmd $dsttmp; else true;fi && 226 | if [ x"$chgrpcmd" != x ]; then $doit $chgrpcmd $dsttmp; else true;fi && 227 | if [ x"$stripcmd" != x ]; then $doit $stripcmd $dsttmp; else true;fi && 228 | if [ x"$chmodcmd" != x ]; then $doit $chmodcmd $dsttmp; else true;fi && 229 | 230 | # Now rename the file to the real destination. 231 | 232 | $doit $rmcmd -f $dstdir/$dstfile && 233 | $doit $mvcmd $dsttmp $dstdir/$dstfile 234 | 235 | fi && 236 | 237 | 238 | exit 0 239 | -------------------------------------------------------------------------------- /nn/istack.c: -------------------------------------------------------------------------------- 1 | /****************************************************************************** 2 | * 3 | * File: istack.c 4 | * 5 | * Created: 06/06/2001 6 | * 7 | * Author: Pavel Sakov 8 | * CSIRO Marine Research 9 | * 10 | * Purpose: Handling stack of integers 11 | * 12 | * Description: None 13 | * 14 | * Revisions: None 15 | * 16 | *****************************************************************************/ 17 | 18 | #define STACK_NSTART 50 19 | #define STACK_NINC 50 20 | 21 | #include 22 | #include 23 | #include "istack.h" 24 | #include "istack_internal.h" 25 | 26 | istack* istack_create(void) 27 | { 28 | istack* s = malloc(sizeof(istack)); 29 | 30 | s->n = 0; 31 | s->nallocated = STACK_NSTART; 32 | s->v = malloc(STACK_NSTART * sizeof(int)); 33 | return s; 34 | } 35 | 36 | void istack_destroy(istack* s) 37 | { 38 | if (s != NULL) { 39 | free(s->v); 40 | free(s); 41 | } 42 | } 43 | 44 | void istack_reset(istack* s) 45 | { 46 | s->n = 0; 47 | } 48 | 49 | int istack_contains(istack* s, int v) 50 | { 51 | int i; 52 | 53 | for (i = 0; i < s->n; ++i) 54 | if (s->v[i] == v) 55 | return 1; 56 | return 0; 57 | } 58 | 59 | void istack_push(istack* s, int v) 60 | { 61 | if (s->n == s->nallocated) { 62 | s->nallocated *= 2; 63 | s->v = realloc(s->v, s->nallocated * sizeof(int)); 64 | } 65 | 66 | s->v[s->n] = v; 67 | s->n++; 68 | } 69 | 70 | int istack_pop(istack* s) 71 | { 72 | s->n--; 73 | return s->v[s->n]; 74 | } 75 | 76 | int istack_getnentries(istack* s) 77 | { 78 | return s->n; 79 | } 80 | 81 | int* istack_getentries(istack* s) 82 | { 83 | return s->v; 84 | } 85 | -------------------------------------------------------------------------------- /nn/istack.h: -------------------------------------------------------------------------------- 1 | /****************************************************************************** 2 | * 3 | * File: istack.h 4 | * 5 | * Created: 06/06/2001 6 | * 7 | * Author: Pavel Sakov 8 | * CSIRO Marine Research 9 | * 10 | * Purpose: Header for handling stack of integers. 11 | * 12 | * Description: None 13 | * 14 | * Revisions: None 15 | * 16 | *****************************************************************************/ 17 | 18 | #if !defined(_ISTACK_H) 19 | #define _ISTACK_H 20 | 21 | #if !defined(_ISTACK_STRUCT) 22 | #define _ISTACK_STRUCT 23 | struct istack; 24 | typedef struct istack istack; 25 | #endif 26 | 27 | istack* istack_create(void); 28 | void istack_destroy(istack* s); 29 | void istack_push(istack* s, int v); 30 | int istack_pop(istack* s); 31 | int istack_contains(istack* s, int v); 32 | void istack_reset(istack* s); 33 | 34 | #endif 35 | -------------------------------------------------------------------------------- /nn/istack_internal.h: -------------------------------------------------------------------------------- 1 | /****************************************************************************** 2 | * 3 | * File: istack_internal.h 4 | * 5 | * Created: 05/05/2021 6 | * 7 | * Author: Pavel Sakov 8 | * BoM 9 | * 10 | * Purpose: Internal header for istack. 11 | * 12 | * Description: None 13 | * 14 | * Revisions: None 15 | * 16 | *****************************************************************************/ 17 | 18 | #if !defined(_ISTACK_INTERNAL_H) 19 | #define _ISTACK_INTERNAL_H 20 | 21 | #include "istack.h" 22 | 23 | struct istack { 24 | int n; 25 | int nallocated; 26 | int* v; 27 | }; 28 | 29 | #endif /* _ISTACK_INTERNAL_H */ 30 | -------------------------------------------------------------------------------- /nn/lpi.c: -------------------------------------------------------------------------------- 1 | /****************************************************************************** 2 | * 3 | * File: linear.c 4 | * 5 | * Created: 04/08/2000 6 | * 7 | * Author: Pavel Sakov 8 | * CSIRO Marine Research 9 | * 10 | * Purpose: 2D linear interpolation 11 | * 12 | * Description: `lpi' -- "Linear Point Interpolator" -- is 13 | * a structure for conducting linear interpolation on a given 14 | * data on a "point-to-point" basis. It interpolates linearly 15 | * within each triangle resulted from the Delaunay 16 | * triangluation of input data. `lpi' is much 17 | * faster than all Natural Neighbours interpolators in `nn' 18 | * library. 19 | * 20 | * Revisions: None 21 | * 22 | *****************************************************************************/ 23 | 24 | #include 25 | #include 26 | #include "nan.h" 27 | #include "nn.h" 28 | #include "nncommon.h" 29 | #include "delaunay_internal.h" 30 | 31 | typedef struct { 32 | double w[3]; 33 | } lweights; 34 | 35 | struct lpi { 36 | delaunay* d; 37 | lweights* weights; 38 | int first_id; 39 | }; 40 | 41 | int delaunay_xytoi(delaunay* d, point* p, int seed); 42 | 43 | /* Builds linear interpolator. 44 | * 45 | * @param d Delaunay triangulation 46 | * @return Linear interpolator 47 | */ 48 | lpi* lpi_build(delaunay* d) 49 | { 50 | int i; 51 | lpi* l = malloc(sizeof(lpi)); 52 | 53 | l->d = d; 54 | l->weights = malloc(d->ntriangles * sizeof(lweights)); 55 | l->first_id = -1; 56 | 57 | for (i = 0; i < d->ntriangles; ++i) { 58 | triangle* t = &d->triangles[i]; 59 | lweights* lw = &l->weights[i]; 60 | double x0 = d->points[t->vids[0]].x; 61 | double y0 = d->points[t->vids[0]].y; 62 | double z0 = d->points[t->vids[0]].z; 63 | double x1 = d->points[t->vids[1]].x; 64 | double y1 = d->points[t->vids[1]].y; 65 | double z1 = d->points[t->vids[1]].z; 66 | double x2 = d->points[t->vids[2]].x; 67 | double y2 = d->points[t->vids[2]].y; 68 | double z2 = d->points[t->vids[2]].z; 69 | double x02 = x0 - x2; 70 | double y02 = y0 - y2; 71 | double z02 = z0 - z2; 72 | double x12 = x1 - x2; 73 | double y12 = y1 - y2; 74 | double z12 = z1 - z2; 75 | 76 | if (fabs(y12) > fabs(x12)) { 77 | double y0212 = y02 / y12; 78 | 79 | lw->w[0] = (z02 - z12 * y0212) / (x02 - x12 * y0212); 80 | lw->w[1] = (z12 - lw->w[0] * x12) / y12; 81 | lw->w[2] = (z2 - lw->w[0] * x2 - lw->w[1] * y2); 82 | } else { 83 | double x0212 = x02 / x12; 84 | 85 | lw->w[1] = (z02 - z12 * x0212) / (y02 - y12 * x0212); 86 | lw->w[0] = (z12 - lw->w[1] * y12) / x12; 87 | lw->w[2] = (z2 - lw->w[0] * x2 - lw->w[1] * y2); 88 | } 89 | } 90 | 91 | return l; 92 | } 93 | 94 | /* Destroys linear interpolator. 95 | * 96 | * @param l Structure to be destroyed 97 | */ 98 | void lpi_destroy(lpi* l) 99 | { 100 | free(l->weights); 101 | free(l); 102 | } 103 | 104 | /* Finds linearly interpolated value in a point. 105 | * 106 | * @param l Linear interpolation 107 | * @param p Point to be interpolated (p->x, p->y -- input; p->z -- output) 108 | */ 109 | void lpi_interpolate_point(lpi* l, point* p) 110 | { 111 | delaunay* d = l->d; 112 | int tid = delaunay_xytoi(d, p, l->first_id); 113 | 114 | if (tid >= 0) { 115 | lweights* lw = &l->weights[tid]; 116 | 117 | l->first_id = tid; 118 | p->z = p->x * lw->w[0] + p->y * lw->w[1] + lw->w[2]; 119 | } else 120 | p->z = NaN; 121 | } 122 | 123 | /* Linearly interpolates data in an array of points. 124 | * 125 | * @param nin Number of input points 126 | * @param pin Array of input points [pin] 127 | * @param nout Number of ouput points 128 | * @param pout Array of output points [nout] 129 | */ 130 | void lpi_interpolate_points(delaunay* d, int nout, point pout[]) 131 | { 132 | lpi* l = lpi_build(d); 133 | int seed = 0; 134 | int i; 135 | 136 | if (nn_verbose) { 137 | fprintf(stderr, "xytoi:\n"); 138 | for (i = 0; i < nout; ++i) { 139 | point* p = &pout[i]; 140 | 141 | fprintf(stderr, "(%.7g,%.7g) -> %d\n", p->x, p->y, delaunay_xytoi(d, p, seed)); 142 | } 143 | } 144 | 145 | for (i = 0; i < nout; ++i) 146 | lpi_interpolate_point(l, &pout[i]); 147 | 148 | if (nn_verbose) { 149 | fprintf(stderr, "output:\n"); 150 | for (i = 0; i < nout; ++i) { 151 | point* p = &pout[i];; 152 | fprintf(stderr, " %d:%15.7g %15.7g %15.7g\n", i, p->x, p->y, p->z); 153 | } 154 | } 155 | 156 | lpi_destroy(l); 157 | } 158 | -------------------------------------------------------------------------------- /nn/makefile.example: -------------------------------------------------------------------------------- 1 | SHELL = /bin/sh 2 | 3 | prefix = /usr/local 4 | exec_prefix = ${prefix} 5 | bindir = ${exec_prefix}/bin 6 | libdir = ${exec_prefix}/lib64 7 | includedir = ${prefix}/include 8 | 9 | INSTALLDIRS =\ 10 | $(bindir)\ 11 | $(libdir)\ 12 | $(includedir) 13 | 14 | INSTALL = /usr/bin/install -c 15 | INSTALL_PROGRAM = ${INSTALL} 16 | INSTALL_DATA = ${INSTALL} -m 644 17 | 18 | MPI = yes 19 | # only matters if MPI = yes 20 | VIAFILE = no 21 | CC = gcc 22 | CFLAGS = -g -O2 -Wall -pedantic -D_GNU_SOURCE -std=c99 23 | CFLAGS_TRIANGLE = -O2 -w -ffloat-store 24 | CFLAGS_VULNERABLE = -ffloat-store 25 | LDFLAGS = 26 | 27 | AR = ar 28 | ARFLAGS = cr 29 | 30 | MLIB = -lm 31 | 32 | SRC_LIB =\ 33 | delaunay.c\ 34 | hash.c\ 35 | istack.c\ 36 | lpi.c\ 37 | minell.c\ 38 | nnai.c\ 39 | nnpi.c\ 40 | nncommon.c\ 41 | nncommon-vulnerable.c\ 42 | preader.c\ 43 | version.c 44 | 45 | HDR_LIB =\ 46 | delaunay.h\ 47 | delaunay_internal.h\ 48 | hash.h\ 49 | istack.h\ 50 | istack_internal.h\ 51 | minell.h\ 52 | nan.h\ 53 | nn.h\ 54 | nnpi.h\ 55 | preader.h 56 | 57 | SRC_NNBATHY=\ 58 | nnbathy.c 59 | HDR_NNBATHY = 60 | 61 | PROGRAMS =\ 62 | minell\ 63 | nnbathy 64 | 65 | TESTS=\ 66 | nnai_test\ 67 | nnphi_test\ 68 | ht_test 69 | 70 | OBJ_LIB = $(SRC_LIB:.c=.o) 71 | 72 | all: libnn.a $(PROGRAMS) 73 | 74 | minell: minell.c 75 | $(CC) -o minell minell.c -DME_STANDALONE $(CFLAGS) -I. $(LDFLAGS) $(MLIB) 76 | 77 | ifeq ($(MPI), yes) 78 | delaunay.o: override CC = mpicc 79 | delaunay.o: override CFLAGS += -DMPI -DUSE_SHMEM 80 | nnbathy: override CC = mpicc 81 | nnbathy: override CFLAGS += -DMPI -DUSE_SHMEM 82 | ifeq ($(VIAFILE), yes) 83 | nnbathy: override CFLAGS += -DVIAFILE 84 | SRC_NNBATHY += distribute.c 85 | HDR_NNBATHY += distribute.h 86 | endif 87 | else 88 | nnbathy: override CFLAGS += -DNN_SERIAL 89 | endif 90 | 91 | nnbathy: libnn.a nnbathy.c $(SRC_NNBATHY) $(HDR_NNBATHY) 92 | $(CC) -o nnbathy $(SRC_NNBATHY) $(CFLAGS) -I. $(LDFLAGS) libnn.a $(MLIB) 93 | 94 | standalone: override LDFLAGS+=-static 95 | standalone: $(PROGRAMS) 96 | strip $(PROGRAMS) 97 | 98 | libnn.a: triangle.o $(OBJ_LIB) 99 | $(AR) $(ARFLAGS) libnn.a $(OBJ_LIB) triangle.o 100 | chmod go+r libnn.a 101 | 102 | nncommon-vulnerable.o: override CFLAGS+=$(CFLAGS_VULNERABLE) 103 | 104 | triangle.o: triangle.c triangle.h 105 | $(CC) -c -DTRILIBRARY $(CFLAGS_TRIANGLE) -I. triangle.c 106 | 107 | tests: libnn.a $(TESTS) 108 | 109 | nnai_test: 110 | $(CC) -o nnai_test nnai.c -DNNAI_TEST $(CFLAGS) -I. $(MLIB) libnn.a 111 | 112 | nnphi_test: 113 | $(CC) -o nnphi_test nnpi.c -DNNPHI_TEST $(CFLAGS) -I. $(MLIB) libnn.a 114 | 115 | ht_test: 116 | $(CC) -o ht_test hash.c -DHT_TEST $(CFLAGS) -I. $(MLIB) 117 | 118 | %.o: %.c makefile $(HDR_LIB) 119 | $(CC) $(CFLAGS) -c $< -o $@ 120 | 121 | installdirs: 122 | $(SHELL) mkinstalldirs $(INSTALLDIRS) 123 | 124 | install: all installdirs 125 | for i in libnn.a; do \ 126 | $(INSTALL_DATA) $$i $(libdir)/$$i; \ 127 | done 128 | 129 | for i in nn.h; do \ 130 | $(INSTALL_DATA) $$i $(includedir); \ 131 | done 132 | 133 | for i in $(PROGRAMS); do \ 134 | fname=`basename $$i`; \ 135 | $(INSTALL_PROGRAM) $$i $(bindir); \ 136 | done 137 | 138 | clean: 139 | rm -f *.o libnn.a $(PROGRAMS) $(TESTS) *~ core 140 | 141 | configclean: 142 | rm -f config.h makefile config.cache config.status config.log 143 | 144 | ex1clean: 145 | cd examples/1; make clean; 146 | 147 | ex2clean: 148 | cd examples/2; make clean; 149 | 150 | ex3clean: 151 | cd examples/3; make clean; 152 | 153 | ex4clean: 154 | cd examples/4; make clean; 155 | 156 | ex5clean: 157 | cd examples/5; make clean; 158 | 159 | ex6clean: 160 | cd examples/6; make clean; 161 | 162 | distclean: clean configclean ex1clean ex2clean ex3clean ex4clean ex5clean ex6clean 163 | 164 | indent: 165 | indent -T FILE -T NN_ALGORITHM -T point -T delaunay -Tdsearch -T lpi -T nnpi -T nnhpi -T indexedpoint -T nnai -T ht_bucket -T hashtable -T istack -T triangle -T triangle_neighbours -T circle -T nn_weights -T lweights -T minell -T specs -T reader -T preader -T grid $(SRC_LIB) $(SRC_NNBATHY) $(HDR_NNBATHY) 166 | rm -f *~ 167 | -------------------------------------------------------------------------------- /nn/makefile.in: -------------------------------------------------------------------------------- 1 | SHELL = /bin/sh 2 | 3 | prefix = @prefix@ 4 | exec_prefix = @exec_prefix@ 5 | bindir = @bindir@ 6 | libdir = @libdir@ 7 | includedir = @includedir@ 8 | 9 | INSTALLDIRS =\ 10 | $(bindir)\ 11 | $(libdir)\ 12 | $(includedir) 13 | 14 | INSTALL = @INSTALL@ 15 | INSTALL_PROGRAM = @INSTALL_PROGRAM@ 16 | INSTALL_DATA = @INSTALL_DATA@ 17 | 18 | MPI = no 19 | # only matters if MPI = yes 20 | VIAFILE = no 21 | CC = @CC@ 22 | CFLAGS = @CFLAGS@ 23 | CFLAGS_TRIANGLE = @CFLAGS_TRIANGLE@ 24 | CFLAGS_VULNERABLE = @CFLAGS_VULNERABLE@ 25 | LDFLAGS = @LDFLAGS@ 26 | 27 | AR = @AR@ 28 | ARFLAGS = cr 29 | 30 | MLIB = -lm 31 | 32 | SRC_LIB =\ 33 | delaunay.c\ 34 | hash.c\ 35 | istack.c\ 36 | lpi.c\ 37 | minell.c\ 38 | nnai.c\ 39 | nnpi.c\ 40 | nncommon.c\ 41 | nncommon-vulnerable.c\ 42 | preader.c\ 43 | version.c 44 | 45 | HDR_LIB =\ 46 | delaunay.h\ 47 | delaunay_internal.h\ 48 | hash.h\ 49 | istack.h\ 50 | istack_internal.h\ 51 | minell.h\ 52 | nan.h\ 53 | nn.h\ 54 | nnpi.h\ 55 | preader.h 56 | 57 | SRC_NNBATHY=\ 58 | nnbathy.c 59 | HDR_NNBATHY = 60 | 61 | PROGRAMS =\ 62 | minell\ 63 | nnbathy 64 | 65 | TESTS=\ 66 | nnai_test\ 67 | nnphi_test\ 68 | ht_test 69 | 70 | OBJ_LIB = $(SRC_LIB:.c=.o) 71 | 72 | all: libnn.a $(PROGRAMS) 73 | 74 | minell: minell.c 75 | $(CC) -o minell minell.c -DME_STANDALONE $(CFLAGS) -I. $(LDFLAGS) $(MLIB) 76 | 77 | ifeq ($(MPI), yes) 78 | delaunay.o: override CC = mpicc 79 | delaunay.o: override CFLAGS += -DMPI -DUSE_SHMEM 80 | nnbathy: override CC = mpicc 81 | nnbathy: override CFLAGS += -DMPI -DUSE_SHMEM 82 | ifeq ($(VIAFILE), yes) 83 | nnbathy: override CFLAGS += -DVIAFILE 84 | SRC_NNBATHY += distribute.c 85 | HDR_NNBATHY += distribute.h 86 | endif 87 | else 88 | nnbathy: override CFLAGS += -DNN_SERIAL 89 | endif 90 | 91 | nnbathy: libnn.a nnbathy.c $(SRC_NNBATHY) $(HDR_NNBATHY) 92 | $(CC) -o nnbathy $(SRC_NNBATHY) $(CFLAGS) -I. $(LDFLAGS) libnn.a $(MLIB) 93 | 94 | standalone: override LDFLAGS+=-static 95 | standalone: $(PROGRAMS) 96 | strip $(PROGRAMS) 97 | 98 | libnn.a: triangle.o $(OBJ_LIB) 99 | $(AR) $(ARFLAGS) libnn.a $(OBJ_LIB) triangle.o 100 | chmod go+r libnn.a 101 | 102 | nncommon-vulnerable.o: override CFLAGS+=$(CFLAGS_VULNERABLE) 103 | 104 | triangle.o: triangle.c triangle.h 105 | $(CC) -c -DTRILIBRARY $(CFLAGS_TRIANGLE) -I. triangle.c 106 | 107 | tests: libnn.a $(TESTS) 108 | 109 | nnai_test: 110 | $(CC) -o nnai_test nnai.c -DNNAI_TEST $(CFLAGS) -I. $(MLIB) libnn.a 111 | 112 | nnphi_test: 113 | $(CC) -o nnphi_test nnpi.c -DNNPHI_TEST $(CFLAGS) -I. $(MLIB) libnn.a 114 | 115 | ht_test: 116 | $(CC) -o ht_test hash.c -DHT_TEST $(CFLAGS) -I. $(MLIB) 117 | 118 | %.o: %.c makefile $(HDR_LIB) 119 | $(CC) $(CFLAGS) -c $< -o $@ 120 | 121 | installdirs: 122 | $(SHELL) mkinstalldirs $(INSTALLDIRS) 123 | 124 | install: all installdirs 125 | for i in libnn.a; do \ 126 | $(INSTALL_DATA) $$i $(libdir)/$$i; \ 127 | done 128 | 129 | for i in nn.h delaunay.h; do \ 130 | $(INSTALL_DATA) $$i $(includedir); \ 131 | done 132 | 133 | for i in $(PROGRAMS); do \ 134 | fname=`basename $$i`; \ 135 | $(INSTALL_PROGRAM) $$i $(bindir); \ 136 | done 137 | 138 | clean: 139 | rm -f *.o libnn.a $(PROGRAMS) $(TESTS) *~ core 140 | 141 | configclean: 142 | rm -f config.h makefile config.cache config.status config.log 143 | 144 | ex1clean: 145 | cd examples/1; make clean; 146 | 147 | ex2clean: 148 | cd examples/2; make clean; 149 | 150 | ex3clean: 151 | cd examples/3; make clean; 152 | 153 | ex4clean: 154 | cd examples/4; make clean; 155 | 156 | ex5clean: 157 | cd examples/5; make clean; 158 | 159 | ex6clean: 160 | cd examples/6; make clean; 161 | 162 | distclean: clean configclean ex1clean ex2clean ex3clean ex4clean ex5clean ex6clean 163 | 164 | indent: 165 | indent -T FILE -T NN_ALGORITHM -T point -T delaunay -Tdsearch -T lpi -T nnpi -T nnhpi -T indexedpoint -T nnai -T ht_bucket -T hashtable -T istack -T triangle -T triangle_neighbours -T circle -T nn_weights -T lweights -T minell -T specs -T reader -T preader -T grid $(SRC_LIB) $(SRC_NNBATHY) $(HDR_NNBATHY) 166 | rm -f *~ 167 | -------------------------------------------------------------------------------- /nn/minell.h: -------------------------------------------------------------------------------- 1 | /****************************************************************************** 2 | * 3 | * File: minell.h 4 | * 5 | * Created: 24/02/2003 6 | * 7 | * Author: Pavel Sakov 8 | * CSIRO Marine Research 9 | * 10 | * Purpose: A header for the minimal ellipse stuff 11 | * 12 | * Revisions: None 13 | * 14 | *****************************************************************************/ 15 | 16 | #if !defined(_MINELL_H) 17 | #define _MINELL_H 18 | 19 | #if !defined(_STRUCT_POINT) 20 | #define _STRUCT_POINT 21 | typedef struct { 22 | double x; 23 | double y; 24 | double z; 25 | } point; 26 | #endif 27 | 28 | #if !defined(_MINELL_STRUCT) 29 | #define _MINELL_STRUCT 30 | struct minell; 31 | typedef struct minell minell; 32 | #endif 33 | 34 | /* Note that minell_build() shuffles the input point array */ 35 | minell* minell_build(int n, point p[]); 36 | void minell_destroy(minell* me); 37 | void minell_scalepoints(minell* me, int n, point p[]); 38 | void minell_rescalepoints(minell* me, int n, point p[]); 39 | 40 | #endif 41 | -------------------------------------------------------------------------------- /nn/mkinstalldirs: -------------------------------------------------------------------------------- 1 | #! /bin/sh 2 | # mkinstalldirs --- make directory hierarchy 3 | # Author: Noah Friedman 4 | # Created: 1993-05-16 5 | # Public domain 6 | 7 | errstatus=0 8 | 9 | for file 10 | do 11 | set fnord `echo ":$file" | sed -ne 's/^:\//#/;s/^://;s/\// /g;s/^#/\//;p'` 12 | shift 13 | 14 | pathcomp= 15 | for d 16 | do 17 | pathcomp="$pathcomp$d" 18 | case "$pathcomp" in 19 | -* ) pathcomp=./$pathcomp ;; 20 | esac 21 | 22 | if test ! -d "$pathcomp"; then 23 | echo "mkdir $pathcomp" 1>&2 24 | 25 | mkdir "$pathcomp" || lasterr=$? 26 | 27 | if test ! -d "$pathcomp"; then 28 | errstatus=$lasterr 29 | fi 30 | fi 31 | 32 | pathcomp="$pathcomp/" 33 | done 34 | done 35 | 36 | exit $errstatus 37 | 38 | # mkinstalldirs ends here 39 | -------------------------------------------------------------------------------- /nn/nan.h: -------------------------------------------------------------------------------- 1 | /****************************************************************************** 2 | * 3 | * File: nan.h 4 | * 5 | * Created: 18/10/2001 6 | * 7 | * Author: Pavel Sakov 8 | * CSIRO Marine Research 9 | * 10 | * Purpose: NaN definition 11 | * 12 | * Description: Should cover machines with 64 bit doubles or other machines 13 | * with GCC 14 | * 15 | * Revisions: None 16 | * 17 | *****************************************************************************/ 18 | 19 | #if !defined(_NAN_H) 20 | #define _NAN_H 21 | 22 | #include 23 | 24 | #if defined(NAN) 25 | #define NaN NAN 26 | 27 | #elif defined(__GNUC__) && !defined(__INTEL_COMPILER) 28 | static const double NaN = 0.0 / 0.0; 29 | 30 | #elif defined(_WIN32) 31 | static unsigned _int64 lNaN = ((unsigned _int64) 1 << 63) - 1; 32 | 33 | #define NaN (*(double*)&lNaN) 34 | 35 | #else 36 | static const long long lNaN = ((unsigned long long) 1 << 63) - 1; 37 | 38 | #define NaN (*(double*)&lNaN) 39 | #endif 40 | 41 | #endif 42 | -------------------------------------------------------------------------------- /nn/nn.h: -------------------------------------------------------------------------------- 1 | /****************************************************************************** 2 | * 3 | * File: nn.h 4 | * 5 | * Created: 04/08/2000 6 | * 7 | * Author: Pavel Sakov 8 | * CSIRO Marine Research 9 | * 10 | * Purpose: Header file for nn library 11 | * 12 | * Description: None 13 | * 14 | * Revisions: None 15 | * 16 | *****************************************************************************/ 17 | 18 | #if !defined(_NN_H) 19 | #define _NN_H 20 | 21 | /* Contains version string for the nn package. 22 | */ 23 | extern char* nn_version; 24 | 25 | /* Sets the verbosity level within nn package. 26 | * 0 (default) - silent 27 | * 1 - verbose 28 | * 2 - very verbose 29 | */ 30 | extern int nn_verbose; 31 | 32 | /* Switches between different formulations for NN weights. 33 | * SIBSON -- classic formulation by Sibson 34 | * NON_SIBSONIAN -- alternative formulation by Belikov & Semenov 35 | * 36 | */ 37 | typedef enum { SIBSON, NON_SIBSONIAN } NN_RULE; 38 | extern NN_RULE nn_rule; 39 | 40 | /* Limits verbose information to a particular vertex (used mainly for 41 | * debugging purposes). 42 | */ 43 | extern int nn_test_vertice; 44 | 45 | /* "point" is a basic data structure in this package. 46 | */ 47 | #if !defined(_STRUCT_POINT) 48 | #define _STRUCT_POINT 49 | typedef struct { 50 | double x; 51 | double y; 52 | double z; 53 | } point; 54 | #endif 55 | 56 | #if !defined(_STRUCT_DELAUNAY) 57 | #define _STRUCT_DELAUNAY 58 | struct delaunay; 59 | typedef struct delaunay delaunay; 60 | #endif 61 | 62 | /** Smoothes the input point array by averaging the input x,y and z values 63 | ** for each cell within virtual rectangular nx by ny grid. The corners of the 64 | ** grid are created from min and max values of the input array. It also frees 65 | ** the original array and returns results and new dimension via original 66 | ** data and size pointers. 67 | * 68 | * @param n Pointer to number of points (input/output) 69 | * @param p Pointer to array of points (input/output) [*n] 70 | * @param nx Number of x nodes in decimation 71 | * @param ny Number of y nodes in decimation 72 | */ 73 | void points_thingrid(int* n, point** p, int nx, int ny); 74 | 75 | /** Smoothes the input point array by averaging the input data (X,Y and Z 76 | ** values) until the sum of the distances between points does not exceed the 77 | ** specified maximum value. It also frees the original array and returns 78 | ** results and new dimension via original data and size pointers. 79 | * 80 | * @param n Pointer to number of points (input/output) 81 | * @param p Pointer to array of points (input/output) [*n] 82 | * @param rmax Maximum allowed accumulated distance 83 | */ 84 | void points_thinlin(int* n, point** p, double rmax); 85 | 86 | /* Calculates X and/or Y ranges of the input array of points. If necessary, 87 | * adjusts the range according to the zoom value. 88 | * 89 | * @param n Number of points 90 | * @param points Array of points 91 | * @param xmin Min X value if *xmin = NaN on input, not changed otherwise 92 | * @param xmax Max X value if *xmax = NaN on input, not changed otherwise 93 | * @param ymin Min Y value if *ymin = NaN on input, not changed otherwise 94 | * @param ymax Max Y value if *ymax = NaN on input, not changed otherwise 95 | */ 96 | void points_getrange(int n, point points[], double zoom, double* xmin, double* xmax, double* ymin, double* ymax); 97 | 98 | /** Generates rectangular grid nx by ny using specified min and max x and y 99 | ** values. Allocates space for the output point array, be sure to free it 100 | ** when necessary! 101 | * 102 | * @param xmin Min x value 103 | * @param xmax Max x value 104 | * @param ymin Min y value 105 | * @param ymax Max y value 106 | * @param nx Number of x nodes 107 | * @param ny Number of y nodes 108 | * @param zoom Zoom coefficient 109 | * @param nout Pointer to number of output points 110 | * @param pout Pointer to array of output points [*nout] 111 | */ 112 | void points_generate(double xmin, double xmax, double ymin, double ymax, int nx, int ny, int* nout, point** pout); 113 | 114 | /** Reads array of points from a columnar file. 115 | * 116 | * @param fname File name (can be "stdin" dor stndard input) 117 | * @param dim Number of dimensions (must be 2 or 3) 118 | * @param n Pointer to number of points (output) 119 | * @param points Pointer to array of points [*n] (output) 120 | */ 121 | void points_read(char* fname, int dim, int* n, point** points); 122 | 123 | /** Scales Y coordinate so that the resulting set fits into square: 124 | ** xmax - xmin = ymax - ymin 125 | * 126 | * @param n Number of points 127 | * @param points The points to scale 128 | * @return Y axis compression coefficient 129 | */ 130 | double points_scaletosquare(int n, point* points); 131 | 132 | /** Compresses Y domain by a given multiple. 133 | * 134 | * @param n Number of points 135 | * @param points The points to scale 136 | * @param Y axis compression coefficient as returned by points_scaletosquare() 137 | */ 138 | void points_scale(int n, point* points, double k); 139 | 140 | /** `lpi' -- "Linear Point Interpolator" is a structure for linear 141 | ** interpolation of data on a "point-to-point" basis. 142 | * 143 | * `lpi' interpolates linearly within each triangle resulted from the Delaunay 144 | * triangluation of the input data. `lpi' is much faster than all Natural 145 | * Neighbours interpolators below. 146 | */ 147 | struct lpi; 148 | typedef struct lpi lpi; 149 | 150 | /** Builds linear interpolator. 151 | * 152 | * @param d Delaunay triangulation 153 | * @return Linear interpolator 154 | */ 155 | lpi* lpi_build(delaunay* d); 156 | 157 | /** Destroys linear interpolator. 158 | * 159 | * @param l Structure to be destroyed 160 | */ 161 | void lpi_destroy(lpi* l); 162 | 163 | /** Finds linearly interpolated value in a point. 164 | * 165 | * @param l Linear point interpolator 166 | * @param p Point to be interpolated (p->x, p->y -- input; p->z -- output) 167 | */ 168 | void lpi_interpolate_point(lpi* l, point* p); 169 | 170 | /** Linearly interpolates data in an array of points. 171 | * 172 | * @param nin Number of input points 173 | * @param pin Array of input points [pin] 174 | * @param nout Number of ouput points 175 | * @param pout Array of output points [nout] 176 | */ 177 | void lpi_interpolate_points(delaunay* d, int nout, point pout[]); 178 | 179 | /** `nnpi' -- "Natural Neighbours Point Interpolator" is a structure for 180 | ** Natural Neighbours interpolation of data on a "point-to-point" basis. 181 | * 182 | * Because it involves weight calculation for each output point, it is not 183 | * designed to take advantage of consequitive interpolations on the same 184 | * sets of input and output points -- use `nnhpi' or `nnai' in these cases. 185 | */ 186 | struct nnpi; 187 | typedef struct nnpi nnpi; 188 | 189 | /** Creates Natural Neighbours point interpolator. 190 | * 191 | * @param d Delaunay triangulation 192 | * @return Natural Neighbours interpolation 193 | */ 194 | nnpi* nnpi_create(delaunay* d); 195 | 196 | /** Destroys Natural Neighbours point interpolation. 197 | * 198 | * @param nn Structure to be destroyed 199 | */ 200 | void nnpi_destroy(nnpi* nn); 201 | 202 | /** Performs Natural Neighbours interpolation in a point. 203 | * 204 | * @param nn NN point interpolator 205 | * @param p Point to be interpolated (p->x, p->y -- input; p->z -- output) 206 | */ 207 | void nnpi_interpolate_point(nnpi* nn, point* p); 208 | 209 | /** Performs Natural Neighbours interpolation in an array of points. 210 | * 211 | * @param nin Number of input points 212 | * @param pin Array of input points [pin] 213 | * @param wmin Minimal allowed weight 214 | * @param nout Number of output points 215 | * @param pout Array of output points [nout] 216 | */ 217 | void nnpi_interpolate_points(delaunay* d, double wmin, int nout, point pout[]); 218 | 219 | /** Sets minimal allowed weight for Natural Neighbours interpolation. 220 | * 221 | * For Sibson interpolation, setting wmin = 0 is equivalent to interpolating 222 | * inside convex hall of the data only (returning NaNs otherwise). 223 | * 224 | * @param nn Natural Neighbours point interpolator 225 | * @param wmin Minimal allowed weight 226 | */ 227 | void nnpi_setwmin(nnpi* nn, double wmin); 228 | 229 | /** `nnhpi' -- "Natural Neighbours Hashing Point Interpolator" -- is a 230 | ** structure for conducting consequitive Natural Neighbours interpolations 231 | ** from the same set of observation points, designed to take advantage of 232 | ** repeated interpolations in the same point. It allows to modify Z 233 | ** coordinate of observed data between interpolations (because this does not 234 | ** affect the interpolant weights). 235 | */ 236 | struct nnhpi; 237 | typedef struct nnhpi nnhpi; 238 | 239 | /** Creates Natural Neighbours hashing point interpolator. 240 | * 241 | * @param d Delaunay triangulation 242 | * @param size Hash table size (should be of order of number of output points) 243 | * @return Natural Neighbours interpolation 244 | */ 245 | nnhpi* nnhpi_create(delaunay* d, int size); 246 | 247 | /** Destroys Natural Neighbours hashing point interpolation. 248 | * 249 | * @param nn Structure to be destroyed 250 | */ 251 | void nnhpi_destroy(nnhpi* nn); 252 | 253 | /** Performs Natural Neighbours interpolation in a point. 254 | * 255 | * @param nnhpi NN hashing point interpolator 256 | * @param p Point to be interpolated (p->x, p->y -- input; p->z -- output) 257 | */ 258 | void nnhpi_interpolate(nnhpi* nn, point* p); 259 | 260 | /** Modifies interpolated data. 261 | * 262 | * Finds point* pd in the underlying Delaunay triangulation such that 263 | * pd->x = p->x and pd->y = p->y, and copies p->z to pd->z. Exits with error 264 | * if the point is not found. 265 | * 266 | * @param nn Natural Neighbours hashing point interpolator 267 | * @param p New data 268 | */ 269 | void nnhpi_modify_data(nnhpi* nn, point* p); 270 | 271 | /** Sets minimal allowed weight for Natural Neighbours interpolation. 272 | * 273 | * For Sibson interpolation, setting wmin = 0 is equivalent to interpolating 274 | * inside convex hall of the data only (returning NaNs otherwise). 275 | * 276 | * @param nn Natural Neighbours point hashing interpolator 277 | * @param wmin Minimal allowed weight 278 | */ 279 | void nnhpi_setwmin(nnhpi* nn, double wmin); 280 | 281 | /** `nnai' -- "Natural Neighbours Array Interpolator" is a structure for 282 | ** conducting consequitive Natural Neighbours interpolations from the same 283 | ** set of observation points in the same set of points. It allows to modify Z 284 | ** coordinate of data between interpolations (because this does not 285 | ** affect the interpolant weights). 286 | * 287 | * `nnai' is the fastest of the three Natural Neighbours interpolators in `nn' 288 | * library. 289 | */ 290 | struct nnai; 291 | typedef struct nnai nnai; 292 | 293 | /** Builds Natural Neighbours array interpolator. 294 | * 295 | * This includes calculation of weights used in nnai_interpolate(). 296 | * 297 | * @param d Delaunay triangulation 298 | * @return Natural Neighbours interpolation 299 | */ 300 | nnai* nnai_build(delaunay* d, int n, double* x, double* y); 301 | 302 | /** Destroys Natural Neighbours array interpolator. 303 | * 304 | * @param nn Structure to be destroyed 305 | */ 306 | void nnai_destroy(nnai* nn); 307 | 308 | /** Conducts NN interpolation in a fixed array of output points using 309 | ** data specified in a fixed array of input points. Uses pre-calculated 310 | ** weights. 311 | * 312 | * @param nn NN array interpolator 313 | * @param zin input data [nn->d->npoints] 314 | * @param zout output data [nn->n]. Must be pre-allocated! 315 | */ 316 | void nnai_interpolate(nnai* nn, double* zin, double* zout); 317 | 318 | /** Sets minimal allowed weight for Natural Neighbours interpolation. 319 | * 320 | * For Sibson interpolation, setting wmin = 0 is equivalent to interpolating 321 | * inside convex hall of the input data only (returning NaNs otherwise). 322 | * 323 | * @param nn Natural Neighbours array interpolator 324 | * @param wmin Minimal allowed weight 325 | */ 326 | void nnai_setwmin(nnai* nn, double wmin); 327 | 328 | #endif /* _NN_H */ 329 | -------------------------------------------------------------------------------- /nn/nn_internal.h: -------------------------------------------------------------------------------- 1 | /****************************************************************************** 2 | * 3 | * File: nn_internal.h 4 | * 5 | * Created: 11/03/2005 6 | * 7 | * Author: Pavel Sakov 8 | * CSIRO Marine Research 9 | * 10 | * Purpose: Header for internal stuff in the nn library 11 | * 12 | * Description: None 13 | * 14 | * Revisions: None 15 | * 16 | *****************************************************************************/ 17 | 18 | #if !defined(_NN_INTERNAL_H) 19 | #define _NN_INTERNAL_H 20 | 21 | /* 22 | * nnpi.c 23 | */ 24 | void nnpi_calculate_weights(nnpi* nn, point* p); 25 | int nnpi_get_nvertices(nnpi* nn); 26 | int* nnpi_get_vertices(nnpi* nn); 27 | double* nnpi_get_weights(nnpi* nn); 28 | 29 | /* 30 | * nncommon.c, nncommon-vulnerable.c 31 | */ 32 | int circle_build1(circle* c, point* p0, point* p1, point* p2); 33 | int circle_build2(circle* c, point* p0, point* p1, point* p2); 34 | int circle_contains(circle* c, point* p); 35 | void nn_quit(char* format, ...); 36 | int str2double(char* token, double* value); 37 | 38 | #endif 39 | -------------------------------------------------------------------------------- /nn/nnai.c: -------------------------------------------------------------------------------- 1 | /****************************************************************************** 2 | * 3 | * File: nnai.c 4 | * 5 | * Created: 15/11/2002 6 | * 7 | * Author: Pavel Sakov 8 | * CSIRO Marine Research 9 | * 10 | * Purpose: Code for: 11 | * -- Natural Neighbours Array Interpolator 12 | * 13 | * Description: `nnai' is a structure for conducting repeated Natural 14 | * Neighbours interpolations when locations of input and output 15 | * data points do not change. It re-uses interpolation weights 16 | * calculated during initialisation and can be substantially 17 | * faster than the more generic Natural Neighbours Point 18 | * Interpolator `nnpi'. 19 | * 20 | * Revisions: None 21 | * 22 | *****************************************************************************/ 23 | 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include "nan.h" 29 | #include "nn.h" 30 | #include "nncommon.h" 31 | #include "delaunay.h" 32 | #include "nnpi.h" 33 | 34 | typedef struct { 35 | int nvertices; 36 | int* vertices; /* vertex indices [nvertices] */ 37 | double* weights; /* vertex weights [nvertices] */ 38 | } nn_weights; 39 | 40 | struct nnai { 41 | delaunay* d; 42 | double wmin; 43 | double n; /* number of output points */ 44 | double* x; /* [n] */ 45 | double* y; /* [n] */ 46 | nn_weights* weights; 47 | }; 48 | 49 | /** Builds Natural Neighbours array interpolator. 50 | * 51 | * This includes calculation of weights used in nnai_interpolate(). 52 | * 53 | * @param d Delaunay triangulation 54 | * @return Natural Neighbours interpolation 55 | */ 56 | nnai* nnai_build(delaunay* d, int n, double* x, double* y) 57 | { 58 | nnai* nn = malloc(sizeof(nnai)); 59 | nnpi* nnpi = nnpi_create(d); 60 | int* vertices; 61 | double* weights; 62 | int i; 63 | 64 | if (n <= 0) 65 | nn_quit("nnai_create(): n = %d\n", n); 66 | 67 | nn->d = d; 68 | nn->n = n; 69 | nn->x = malloc(n * sizeof(double)); 70 | memcpy(nn->x, x, n * sizeof(double)); 71 | nn->y = malloc(n * sizeof(double)); 72 | memcpy(nn->y, y, n * sizeof(double)); 73 | nn->weights = malloc(n * sizeof(nn_weights)); 74 | 75 | for (i = 0; i < n; ++i) { 76 | nn_weights* w = &nn->weights[i]; 77 | point p; 78 | 79 | p.x = x[i]; 80 | p.y = y[i]; 81 | 82 | nnpi_calculate_weights(nnpi, &p); 83 | 84 | vertices = nnpi_get_vertices(nnpi); 85 | weights = nnpi_get_weights(nnpi); 86 | 87 | w->nvertices = nnpi_get_nvertices(nnpi); 88 | w->vertices = malloc(w->nvertices * sizeof(int)); 89 | memcpy(w->vertices, vertices, w->nvertices * sizeof(int)); 90 | w->weights = malloc(w->nvertices * sizeof(double)); 91 | memcpy(w->weights, weights, w->nvertices * sizeof(double)); 92 | } 93 | 94 | nnpi_destroy(nnpi); 95 | 96 | return nn; 97 | } 98 | 99 | /* Destroys Natural Neighbours array interpolator. 100 | * 101 | * @param nn Structure to be destroyed 102 | */ 103 | void nnai_destroy(nnai* nn) 104 | { 105 | int i; 106 | 107 | for (i = 0; i < nn->n; ++i) { 108 | nn_weights* w = &nn->weights[i]; 109 | 110 | free(w->vertices); 111 | free(w->weights); 112 | } 113 | 114 | free(nn->x); 115 | free(nn->y); 116 | free(nn->weights); 117 | free(nn); 118 | } 119 | 120 | /* Conducts NN interpolation in a fixed array of output points using 121 | * data specified in a fixed array of input points. Uses pre-calculated 122 | * weights. 123 | * 124 | * @param nn NN array interpolator 125 | * @param zin input data [nn->d->npoints] 126 | * @param zout output data [nn->n]. Must be pre-allocated! 127 | */ 128 | void nnai_interpolate(nnai* nn, double* zin, double* zout) 129 | { 130 | int i; 131 | 132 | for (i = 0; i < nn->n; ++i) { 133 | nn_weights* w = &nn->weights[i]; 134 | double z = 0.0; 135 | int j; 136 | 137 | for (j = 0; j < w->nvertices; ++j) { 138 | double weight = w->weights[j]; 139 | 140 | if (weight < nn->wmin) { 141 | z = NaN; 142 | break; 143 | } 144 | z += weight * zin[w->vertices[j]]; 145 | } 146 | 147 | zout[i] = z; 148 | } 149 | } 150 | 151 | /* Sets minimal allowed weight for Natural Neighbours interpolation. 152 | * 153 | * For Sibson interpolation, setting wmin = 0 is equivalent to interpolating 154 | * inside convex hall of the data only (returning NaNs otherwise). 155 | * 156 | * @param nn Natural Neighbours array interpolator 157 | * @param wmin Minimal allowed weight 158 | */ 159 | void nnai_setwmin(nnai* nn, double wmin) 160 | { 161 | nn->wmin = wmin; 162 | } 163 | 164 | /* The rest of this file contains a number of test programs. 165 | */ 166 | #if defined(NNAI_TEST) 167 | 168 | #include 169 | 170 | #define NPOINTSIN 10000 171 | #define NMIN 10 172 | #define NX 101 173 | #define NXMIN 1 174 | 175 | #define SQ(x) ((x) * (x)) 176 | 177 | static double franke(double x, double y) 178 | { 179 | x *= 9.0; 180 | y *= 9.0; 181 | return 0.75 * exp((-SQ(x - 2.0) - SQ(y - 2.0)) / 4.0) 182 | + 0.75 * exp(-SQ(x - 2.0) / 49.0 - (y - 2.0) / 10.0) 183 | + 0.5 * exp((-SQ(x - 7.0) - SQ(y - 3.0)) / 4.0) 184 | - 0.2 * exp(-SQ(x - 4.0) - SQ(y - 7.0)); 185 | } 186 | 187 | static void usage() 188 | { 189 | printf("Usage: nnai_test [-v|-V] [-n ]\n"); 190 | printf("Options:\n"); 191 | printf(" -a -- use non-Sibsonian interpolation rule\n"); 192 | printf(" -n :\n"); 193 | printf(" -- number of input points (default = 10000)\n"); 194 | printf(" -- number of output points per side (default = 64)\n"); 195 | printf(" -v -- verbose\n"); 196 | printf(" -V -- very verbose\n"); 197 | } 198 | 199 | int main(int argc, char* argv[]) 200 | { 201 | int nin = NPOINTSIN; 202 | int nx = NX; 203 | int nout = 0; 204 | point* pin = NULL; 205 | delaunay* d = NULL; 206 | point* pout = NULL; 207 | nnai* nn = NULL; 208 | double* zin = NULL; 209 | double* xout = NULL; 210 | double* yout = NULL; 211 | double* zout = NULL; 212 | int cpi = -1; /* control point index */ 213 | struct timeval tv0, tv1, tv2; 214 | struct timezone tz; 215 | int i; 216 | 217 | i = 1; 218 | while (i < argc) { 219 | switch (argv[i][1]) { 220 | case 'a': 221 | i++; 222 | nn_rule = NON_SIBSONIAN; 223 | break; 224 | case 'n': 225 | i++; 226 | if (i >= argc) 227 | nn_quit("no number of data points found after -i\n"); 228 | nin = atoi(argv[i]); 229 | i++; 230 | if (i >= argc) 231 | nn_quit("no number of ouput points per side found after -i\n"); 232 | nx = atoi(argv[i]); 233 | i++; 234 | break; 235 | case 'v': 236 | i++; 237 | nn_verbose = 1; 238 | break; 239 | case 'V': 240 | i++; 241 | nn_verbose = 2; 242 | break; 243 | default: 244 | usage(); 245 | break; 246 | } 247 | } 248 | 249 | if (nin < NMIN) 250 | nin = NMIN; 251 | if (nx < NXMIN) 252 | nx = NXMIN; 253 | 254 | printf("\nTest of Natural Neighbours array interpolator:\n\n"); 255 | printf(" %d data points\n", nin); 256 | printf(" %d output points\n", nx * nx); 257 | 258 | /* 259 | * generate data 260 | */ 261 | printf(" generating data:\n"); 262 | fflush(stdout); 263 | pin = malloc(nin * sizeof(point)); 264 | zin = malloc(nin * sizeof(double)); 265 | for (i = 0; i < nin; ++i) { 266 | point* p = &pin[i]; 267 | 268 | p->x = (double) random() / RAND_MAX; 269 | p->y = (double) random() / RAND_MAX; 270 | p->z = franke(p->x, p->y); 271 | zin[i] = p->z; 272 | if (nn_verbose) 273 | printf(" (%f, %f, %f)\n", p->x, p->y, p->z); 274 | } 275 | 276 | /* 277 | * triangulate 278 | */ 279 | printf(" triangulating:\n"); 280 | fflush(stdout); 281 | d = delaunay_build(nin, pin, 0, NULL, 0, NULL); 282 | 283 | /* 284 | * generate output points 285 | */ 286 | points_generate(-0.1, 1.1, -0.1, 1.1, nx, nx, &nout, &pout); 287 | xout = malloc(nout * sizeof(double)); 288 | yout = malloc(nout * sizeof(double)); 289 | zout = malloc(nout * sizeof(double)); 290 | for (i = 0; i < nout; ++i) { 291 | point* p = &pout[i]; 292 | 293 | xout[i] = p->x; 294 | yout[i] = p->y; 295 | zout[i] = NaN; 296 | } 297 | cpi = (nx / 2) * (nx + 1); 298 | 299 | gettimeofday(&tv0, &tz); 300 | 301 | /* 302 | * create interpolator 303 | */ 304 | printf(" creating interpolator:\n"); 305 | fflush(stdout); 306 | nn = nnai_build(d, nout, xout, yout); 307 | 308 | fflush(stdout); 309 | gettimeofday(&tv1, &tz); 310 | { 311 | long dt = 1000000 * (tv1.tv_sec - tv0.tv_sec) + tv1.tv_usec - tv0.tv_usec; 312 | 313 | printf(" interpolator creation time = %ld us (%.2f us / point)\n", dt, (double) dt / nout); 314 | } 315 | 316 | /* 317 | * interpolate 318 | */ 319 | printf(" interpolating:\n"); 320 | fflush(stdout); 321 | nnai_interpolate(nn, zin, zout); 322 | if (nn_verbose) 323 | for (i = 0; i < nout; ++i) 324 | printf(" (%f, %f, %f)\n", xout[i], yout[i], zout[i]); 325 | 326 | fflush(stdout); 327 | gettimeofday(&tv2, &tz); 328 | { 329 | long dt = 1000000.0 * (tv2.tv_sec - tv1.tv_sec) + tv2.tv_usec - tv1.tv_usec; 330 | 331 | printf(" interpolation time = %ld us (%.2f us / point)\n", dt, (double) dt / nout); 332 | } 333 | 334 | if (!nn_verbose) 335 | printf(" control point: (%f, %f, %f) (expected z = %f)\n", xout[cpi], yout[cpi], zout[cpi], franke(xout[cpi], yout[cpi])); 336 | 337 | /* 338 | * interpolate one more time 339 | */ 340 | printf(" interpolating one more time:\n"); 341 | fflush(stdout); 342 | nnai_interpolate(nn, zin, zout); 343 | if (nn_verbose) 344 | for (i = 0; i < nout; ++i) 345 | printf(" (%f, %f, %f)\n", xout[i], yout[i], zout[i]); 346 | 347 | fflush(stdout); 348 | gettimeofday(&tv0, &tz); 349 | { 350 | long dt = 1000000.0 * (tv0.tv_sec - tv2.tv_sec) + tv0.tv_usec - tv2.tv_usec; 351 | 352 | printf(" interpolation time = %ld us (%.2f us / point)\n", dt, (double) dt / nout); 353 | } 354 | 355 | if (!nn_verbose) 356 | printf(" control point: (%f, %f, %f) (expected z = %f)\n", xout[cpi], yout[cpi], zout[cpi], franke(xout[cpi], yout[cpi])); 357 | 358 | /* 359 | * change the data 360 | */ 361 | printf(" entering new data:\n"); 362 | fflush(stdout); 363 | for (i = 0; i < nin; ++i) { 364 | point* p = &pin[i]; 365 | 366 | p->z = p->x * p->x - p->y * p->y; 367 | zin[i] = p->z; 368 | if (nn_verbose) 369 | printf(" (%f, %f, %f)\n", p->x, p->y, p->z); 370 | } 371 | 372 | /* 373 | * interpolate 374 | */ 375 | printf(" interpolating:\n"); 376 | fflush(stdout); 377 | nnai_interpolate(nn, zin, zout); 378 | if (nn_verbose) 379 | for (i = 0; i < nout; ++i) 380 | printf(" (%f, %f, %f)\n", xout[i], yout[i], zout[i]); 381 | 382 | if (!nn_verbose) 383 | printf(" control point: (%f, %f, %f) (expected z = %f)\n", xout[cpi], yout[cpi], zout[cpi], xout[cpi] * xout[cpi] - yout[cpi] * yout[cpi]); 384 | 385 | /* 386 | * restore old data 387 | */ 388 | printf(" restoring data:\n"); 389 | fflush(stdout); 390 | for (i = 0; i < nin; ++i) { 391 | point* p = &pin[i]; 392 | 393 | p->z = franke(p->x, p->y); 394 | zin[i] = p->z; 395 | if (nn_verbose) 396 | printf(" (%f, %f, %f)\n", p->x, p->y, p->z); 397 | } 398 | 399 | /* 400 | * interpolate 401 | */ 402 | printf(" interpolating:\n"); 403 | fflush(stdout); 404 | nnai_interpolate(nn, zin, zout); 405 | if (nn_verbose) 406 | for (i = 0; i < nout; ++i) 407 | printf(" (%f, %f, %f)\n", xout[i], yout[i], zout[i]); 408 | 409 | if (!nn_verbose) 410 | printf(" control point: (%f, %f, %f) (expected z = %f)\n", xout[cpi], yout[cpi], zout[cpi], franke(xout[cpi], yout[cpi])); 411 | 412 | printf("\n"); 413 | 414 | nnai_destroy(nn); 415 | free(zin); 416 | free(xout); 417 | free(yout); 418 | free(zout); 419 | free(pout); 420 | delaunay_destroy(d); 421 | free(pin); 422 | 423 | return 0; 424 | } 425 | 426 | #endif 427 | -------------------------------------------------------------------------------- /nn/nncommon-vulnerable.c: -------------------------------------------------------------------------------- 1 | /****************************************************************************** 2 | * 3 | * File: nncommon-vulnerable.c 4 | * 5 | * Created: 05/08/2004 6 | * 7 | * Author: Pavel Sakov 8 | * CSIRO Marine Research 9 | * 10 | * Purpose: Stuff for NN interpolation library found to be vulnerable 11 | * from -O2 optimisation by gcc. 12 | * 13 | * Description: None 14 | * 15 | * Revisions: 07/04/2005 PS: Changed numerics to force underflow when 16 | * there is a substantial loss of precision. 17 | * 15/04/2005 PS: Further improved numerics. Looks like it 18 | * became pretty good, so I had to split circle_build() into 19 | * circle_build1() -- for general use, and circle_build2() -- 20 | * for use in nnpi_triangle_process() (it signals loss of 21 | * precision in Watson's algorithm). 22 | * 23 | *****************************************************************************/ 24 | 25 | #include 26 | #include 27 | #include "nan.h" 28 | #include "nn.h" 29 | #include "nncommon.h" 30 | 31 | #define MULT 1.0e+7 32 | 33 | int circle_build1(circle* c, point* p1, point* p2, point* p3) 34 | { 35 | double x2 = p2->x - p1->x; 36 | double y2 = p2->y - p1->y; 37 | double x3 = p3->x - p1->x; 38 | double y3 = p3->y - p1->y; 39 | 40 | double denom = x2 * y3 - y2 * x3; 41 | double frac; 42 | 43 | if (denom == 0.0) { 44 | c->x = NaN; 45 | c->y = NaN; 46 | c->r = NaN; 47 | return 0; 48 | } 49 | 50 | frac = (x2 * (x2 - x3) + y2 * (y2 - y3)) / denom; 51 | c->x = (x3 + frac * y3) / 2.0; 52 | c->y = (y3 - frac * x3) / 2.0; 53 | c->r = hypot(c->x, c->y); 54 | c->x += p1->x; 55 | c->y += p1->y; 56 | 57 | return 1; 58 | } 59 | 60 | int circle_build2(circle* c, point* p1, point* p2, point* p3) 61 | { 62 | double x2 = p2->x - p1->x; 63 | double y2 = p2->y - p1->y; 64 | double x3 = p3->x - p1->x; 65 | double y3 = p3->y - p1->y; 66 | 67 | double denom = x2 * y3 - y2 * x3; 68 | double frac; 69 | 70 | if (denom == 0) { 71 | c->x = NaN; 72 | c->y = NaN; 73 | c->r = NaN; 74 | return 0; 75 | } 76 | 77 | frac = (x2 * (x2 - x3) + y2 * (y2 - y3)) / denom; 78 | c->x = (x3 + frac * y3) / 2.0; 79 | c->y = (y3 - frac * x3) / 2.0; 80 | c->r = hypot(c->x, c->y); 81 | if (c->r > (fabs(x2) + fabs(x3) + fabs(y2) + fabs(y3)) * MULT) { 82 | c->x = NaN; 83 | c->y = NaN; 84 | } else { 85 | c->x += p1->x; 86 | c->y += p1->y; 87 | } 88 | 89 | return 1; 90 | } 91 | -------------------------------------------------------------------------------- /nn/nncommon.c: -------------------------------------------------------------------------------- 1 | /****************************************************************************** 2 | * 3 | * File: nncommon.c 4 | * 5 | * Created: 04/08/2000 6 | * 7 | * Author: Pavel Sakov 8 | * CSIRO Marine Research 9 | * 10 | * Purpose: Common stuff for NN interpolation library 11 | * 12 | * Description: None 13 | * 14 | * Revisions: 15/11/2002 PS: Changed name from "utils.c" 15 | * 28/02/2003 PS: Modified points_read() to do the job without 16 | * rewinding the file. This allows to read from stdin when 17 | * necessary. 18 | * 09/04/2003 PS: Modified points_read() to read from a 19 | * file specified by name, not by handle. 20 | * 05/08/2004 PS: Moved circle_build() to 21 | * nncommon-vulnerable.c. 22 | * 23 | *****************************************************************************/ 24 | 25 | #include 26 | #include 27 | #include 28 | #include 29 | #include 30 | #include 31 | #include 32 | #include 33 | #include 34 | #include "config.h" 35 | #include "nan.h" 36 | #include "nn.h" 37 | #include "nncommon.h" 38 | 39 | #define BUFSIZE 1024 40 | #define EPS 1.0e-15 41 | #define NALLOCATED_START 1024 42 | 43 | int nn_verbose = 0; 44 | int nn_test_vertice = -1; 45 | NN_RULE nn_rule = SIBSON; 46 | 47 | void nn_quit(char* format, ...) 48 | { 49 | va_list args; 50 | 51 | fflush(stdout); /* just in case, to have the exit message 52 | * last */ 53 | 54 | fprintf(stderr, " error: libnn: "); 55 | va_start(args, format); 56 | vfprintf(stderr, format, args); 57 | va_end(args); 58 | 59 | exit(1); 60 | } 61 | 62 | int circle_contains(circle* c, point* p) 63 | { 64 | return hypot(c->x - p->x, c->y - p->y) <= c->r; 65 | } 66 | 67 | /* Smoothes the input point array by averaging the input x, y and z values 68 | * for each cell within virtual rectangular nx by ny grid. The corners of the 69 | * grid are created from min and max values of the input array. It also frees 70 | * the original array and returns results and new dimension via original 71 | * data and size pointers. 72 | * 73 | * @param pn Pointer to number of points (input/output) 74 | * @param ppoints Pointer to array of points (input/output) [*pn] 75 | * @param nx Number of x nodes in decimation 76 | * @param ny Number of y nodes in decimation 77 | */ 78 | void points_thingrid(int* pn, point** ppoints, int nx, int ny) 79 | { 80 | int n = *pn; 81 | point* points = *ppoints; 82 | double xmin = DBL_MAX; 83 | double xmax = -DBL_MAX; 84 | double ymin = DBL_MAX; 85 | double ymax = -DBL_MAX; 86 | int nxy = nx * ny; 87 | double* sumx = calloc(nxy, sizeof(double)); 88 | double* sumy = calloc(nxy, sizeof(double)); 89 | double* sumz = calloc(nxy, sizeof(double)); 90 | int* count = calloc(nxy, sizeof(int)); 91 | double stepx = 0.0; 92 | double stepy = 0.0; 93 | int nnew = 0; 94 | point* pointsnew = NULL; 95 | int i, j, ii, index; 96 | 97 | if (nn_verbose) 98 | fprintf(stderr, "thinned: %d points -> ", *pn); 99 | 100 | if (nx < 1 || ny < 1) { 101 | free(points); 102 | *ppoints = NULL; 103 | *pn = 0; 104 | if (nn_verbose) 105 | fprintf(stderr, "0 points"); 106 | return; 107 | } 108 | 109 | for (ii = 0; ii < n; ++ii) { 110 | point* p = &points[ii]; 111 | 112 | if (p->x < xmin) 113 | xmin = p->x; 114 | if (p->x > xmax) 115 | xmax = p->x; 116 | if (p->y < ymin) 117 | ymin = p->y; 118 | if (p->y > ymax) 119 | ymax = p->y; 120 | } 121 | 122 | stepx = (nx > 1) ? (xmax - xmin) / nx : 0.0; 123 | stepy = (ny > 1) ? (ymax - ymin) / ny : 0.0; 124 | 125 | for (ii = 0; ii < n; ++ii) { 126 | point* p = &points[ii]; 127 | int index; 128 | 129 | if (nx == 1) 130 | i = 0; 131 | else { 132 | double fi = (p->x - xmin) / stepx; 133 | 134 | if (fabs(rint(fi) - fi) < EPS) 135 | i = rint(fi); 136 | else 137 | i = (int) floor(fi); 138 | } 139 | if (ny == 1) 140 | j = 0; 141 | else { 142 | double fj = (p->y - ymin) / stepy; 143 | 144 | if (fabs(rint(fj) - fj) < EPS) 145 | j = rint(fj); 146 | else 147 | j = (int) floor(fj); 148 | } 149 | 150 | if (i == nx) 151 | i--; 152 | if (j == ny) 153 | j--; 154 | index = i + j * nx; 155 | sumx[index] += p->x; 156 | sumy[index] += p->y; 157 | sumz[index] += p->z; 158 | count[index]++; 159 | } 160 | 161 | for (j = 0; j < ny; ++j) { 162 | for (i = 0; i < nx; ++i) { 163 | int index = i + j * nx; 164 | 165 | if (count[index] > 0) 166 | nnew++; 167 | } 168 | } 169 | 170 | pointsnew = malloc(nnew * sizeof(point)); 171 | 172 | for (j = 0, index = 0, ii = 0; j < ny; ++j) { 173 | for (i = 0; i < nx; ++i, ++index) { 174 | int nn = count[index]; 175 | 176 | if (nn > 0) { 177 | point* p = &pointsnew[ii]; 178 | 179 | p->x = sumx[index] / nn; 180 | p->y = sumy[index] / nn; 181 | p->z = sumz[index] / nn; 182 | ii++; 183 | } 184 | } 185 | } 186 | 187 | if (nn_verbose) 188 | fprintf(stderr, "%d points\n", nnew); 189 | 190 | free(sumx); 191 | free(sumy); 192 | free(sumz); 193 | free(count); 194 | 195 | free(points); 196 | *ppoints = pointsnew; 197 | *pn = nnew; 198 | } 199 | 200 | /* Smoothes the input point array by averaging the input data (X,Y and Z 201 | * values) until the sum of the distances between points does not exceed the 202 | * specified maximum value. It also frees the original array and returns 203 | * results and new dimension via original data and size pointers. 204 | * 205 | * @param pn Pointer to number of points (input/output) 206 | * @param ppoints Pointer to array of points (input/output) [*pn] 207 | * @param rmax Maximum allowed accumulated distance 208 | */ 209 | void points_thinlin(int* nin, point** pin, double rmax) 210 | { 211 | int nout = 0; 212 | int nallocated = NALLOCATED_START; 213 | point* pout = malloc(nallocated * sizeof(point)); 214 | double n = 0; 215 | double sum_x = 0.0; 216 | double sum_y = 0.0; 217 | double sum_z = 0.0; 218 | double sum_r = 0.0; 219 | point* pprev = NULL; 220 | int i; 221 | 222 | for (i = 0; i < *nin; ++i) { 223 | point* p = &(*pin)[i]; 224 | double dist; 225 | 226 | if (isnan(p->x) || isnan(p->y) || isnan(p->z)) { 227 | if (pprev != NULL) { 228 | /* 229 | * write point 230 | */ 231 | if (nout == nallocated) { 232 | nallocated = nallocated * 2; 233 | pout = realloc(pout, nallocated * sizeof(point)); 234 | } 235 | pout[nout].x = sum_x / (double) n; 236 | pout[nout].y = sum_y / (double) n; 237 | pout[nout].z = sum_z / (double) n; 238 | nout++; 239 | /* 240 | * reset cluster 241 | */ 242 | pprev = NULL; 243 | } 244 | continue; 245 | } 246 | 247 | /* 248 | * init cluster 249 | */ 250 | if (pprev == NULL) { 251 | sum_x = p->x; 252 | sum_y = p->y; 253 | sum_z = p->z; 254 | sum_r = 0.0; 255 | n = 1; 256 | pprev = p; 257 | continue; 258 | } 259 | 260 | dist = hypot(p->x - pprev->x, p->y - pprev->y); 261 | if (sum_r + dist > rmax) { 262 | /* 263 | * write point 264 | */ 265 | if (nout == nallocated) { 266 | nallocated = nallocated * 2; 267 | pout = realloc(pout, nallocated * sizeof(point)); 268 | } 269 | pout[nout].x = sum_x / (double) n; 270 | pout[nout].y = sum_y / (double) n; 271 | pout[nout].z = sum_z / (double) n; 272 | nout++; 273 | /* 274 | * reset cluster 275 | */ 276 | pprev = NULL; 277 | } else { 278 | /* 279 | * add to cluster 280 | */ 281 | sum_x += p->x; 282 | sum_y += p->y; 283 | sum_z += p->z; 284 | sum_r += dist; 285 | n++; 286 | pprev = p; 287 | } 288 | } 289 | 290 | free(*pin); 291 | *pin = realloc(pout, nout * sizeof(point)); 292 | *nin = nout; 293 | } 294 | 295 | /* Calculates X and/or Y ranges of the input array of points. If necessary, 296 | * adjusts the range according to the zoom value. 297 | * 298 | * @param n Number of points 299 | * @param points Array of points 300 | * @param xmin Min X value if *xmin = NaN on input, not changed otherwise 301 | * @param xmax Max X value if *xmax = NaN on input, not changed otherwise 302 | * @param ymin Min Y value if *ymin = NaN on input, not changed otherwise 303 | * @param ymax Max Y value if *ymax = NaN on input, not changed otherwise 304 | */ 305 | void points_getrange(int n, point points[], double zoom, double* xmin, double* xmax, double* ymin, double* ymax) 306 | { 307 | int i; 308 | 309 | if (xmin != NULL) { 310 | if (isnan(*xmin)) 311 | *xmin = DBL_MAX; 312 | else 313 | xmin = NULL; 314 | } 315 | if (xmax != NULL) { 316 | if (isnan(*xmax)) 317 | *xmax = -DBL_MAX; 318 | else 319 | xmax = NULL; 320 | } 321 | if (ymin != NULL) { 322 | if (isnan(*ymin)) 323 | *ymin = DBL_MAX; 324 | else 325 | ymin = NULL; 326 | } 327 | if (ymax != NULL) { 328 | if (isnan(*ymax)) 329 | *ymax = -DBL_MAX; 330 | else 331 | ymax = NULL; 332 | } 333 | 334 | for (i = 0; i < n; ++i) { 335 | point* p = &points[i]; 336 | 337 | if (xmin != NULL && p->x < *xmin) 338 | *xmin = p->x; 339 | if (xmax != NULL && p->x > *xmax) 340 | *xmax = p->x; 341 | if (ymin != NULL && p->y < *ymin) 342 | *ymin = p->y; 343 | if (ymax != NULL && p->y > *ymax) 344 | *ymax = p->y; 345 | } 346 | 347 | if (isnan(zoom) || zoom <= 0.0 || zoom == 1.0) 348 | return; 349 | 350 | if (xmin != NULL && xmax != NULL) { 351 | double xdiff2 = (*xmax - *xmin) / 2.0; 352 | double xav = (*xmax + *xmin) / 2.0; 353 | 354 | *xmin = xav - xdiff2 * zoom; 355 | *xmax = xav + xdiff2 * zoom; 356 | } 357 | if (ymin != NULL && ymax != NULL) { 358 | double ydiff2 = (*ymax - *ymin) / 2.0; 359 | double yav = (*ymax + *ymin) / 2.0; 360 | 361 | *ymin = yav - ydiff2 * zoom; 362 | *ymax = yav + ydiff2 * zoom; 363 | } 364 | } 365 | 366 | /* Generates rectangular grid nx by ny using specified min and max x and y 367 | * values. Allocates space for the output point array, be sure to free it 368 | * when necessary! 369 | * 370 | * @param xmin Min x value 371 | * @param xmax Max x value 372 | * @param ymin Min y value 373 | * @param ymax Max y value 374 | * @param nx Number of x nodes 375 | * @param ny Number of y nodes 376 | * @param nout Pointer to number of output points 377 | * @param pout Pointer to array of output points [*nout] 378 | */ 379 | void points_generate(double xmin, double xmax, double ymin, double ymax, int nx, int ny, int* nout, point** pout) 380 | { 381 | double stepx, stepy; 382 | double x0, xx, yy; 383 | int i, j, ii; 384 | 385 | if (nx < 1 || ny < 1) { 386 | *pout = NULL; 387 | *nout = 0; 388 | return; 389 | } 390 | 391 | *nout = nx * ny; 392 | *pout = malloc(*nout * sizeof(point)); 393 | 394 | stepx = (nx > 1) ? (xmax - xmin) / (nx - 1) : 0.0; 395 | stepy = (ny > 1) ? (ymax - ymin) / (ny - 1) : 0.0; 396 | x0 = (nx > 1) ? xmin : (xmin + xmax) / 2.0; 397 | yy = (ny > 1) ? ymin : (ymin + ymax) / 2.0; 398 | 399 | ii = 0; 400 | for (j = 0; j < ny; ++j) { 401 | xx = x0; 402 | for (i = 0; i < nx; ++i) { 403 | point* p = &(*pout)[ii]; 404 | 405 | p->x = xx; 406 | p->y = yy; 407 | xx += stepx; 408 | ii++; 409 | } 410 | yy += stepy; 411 | } 412 | } 413 | 414 | static int str2double(char* token, double* value) 415 | { 416 | char* end = NULL; 417 | 418 | if (token == NULL) { 419 | *value = NaN; 420 | return 0; 421 | } 422 | 423 | *value = strtod(token, &end); 424 | 425 | if (end == token) { 426 | *value = NaN; 427 | return 0; 428 | } 429 | 430 | return 1; 431 | } 432 | 433 | /* Reads array of points from a columnar file. 434 | * 435 | * @param fname File name (can be "stdin" for standard input) 436 | * @param dim Number of dimensions (must be 2 or 3) 437 | * @param n Pointer to number of points (output) 438 | * @param points Pointer to array of points [*n] (output) (to be freed) 439 | */ 440 | void points_read(char* fname, int dim, int* n, point** points) 441 | { 442 | FILE* f = NULL; 443 | int nallocated = NALLOCATED_START; 444 | char buf[BUFSIZE]; 445 | char seps[] = " ,;\t"; 446 | char* token; 447 | 448 | if (dim < 2 || dim > 3) { 449 | *n = 0; 450 | *points = NULL; 451 | return; 452 | } 453 | 454 | if (fname == NULL) 455 | f = stdin; 456 | else { 457 | if (strcmp(fname, "stdin") == 0 || strcmp(fname, "-") == 0) 458 | f = stdin; 459 | else { 460 | f = fopen(fname, "r"); 461 | if (f == NULL) 462 | nn_quit("%s: %s\n", fname, strerror(errno)); 463 | } 464 | } 465 | 466 | *points = malloc(nallocated * sizeof(point)); 467 | *n = 0; 468 | while (fgets(buf, BUFSIZE, f) != NULL) { 469 | point* p; 470 | 471 | if (*n == nallocated) { 472 | nallocated *= 2; 473 | *points = realloc(*points, nallocated * sizeof(point)); 474 | } 475 | 476 | p = &(*points)[*n]; 477 | 478 | if (buf[0] == '#') 479 | continue; 480 | if ((token = strtok(buf, seps)) == NULL) 481 | continue; 482 | if (!str2double(token, &p->x)) 483 | continue; 484 | if ((token = strtok(NULL, seps)) == NULL) 485 | continue; 486 | if (!str2double(token, &p->y)) 487 | continue; 488 | if (dim == 2) 489 | p->z = NaN; 490 | else { 491 | if ((token = strtok(NULL, seps)) == NULL) 492 | continue; 493 | if (!str2double(token, &p->z)) 494 | continue; 495 | } 496 | (*n)++; 497 | } 498 | 499 | if (*n == 0) { 500 | free(*points); 501 | *points = NULL; 502 | } else 503 | *points = realloc(*points, *n * sizeof(point)); 504 | 505 | if (f != stdin) 506 | if (fclose(f) != 0) 507 | nn_quit("%s: %s\n", fname, strerror(errno)); 508 | } 509 | 510 | /** Scales Y coordinate so that the resulting set fits into square: 511 | ** xmax - xmin = ymax - ymin 512 | * 513 | * @param n Number of points 514 | * @param points The points to scale 515 | * @return Y axis compression coefficient 516 | */ 517 | double points_scaletosquare(int n, point* points) 518 | { 519 | double xmin, ymin, xmax, ymax; 520 | double k; 521 | int i; 522 | 523 | if (n <= 0) 524 | return NaN; 525 | 526 | xmin = xmax = points[0].x; 527 | ymin = ymax = points[0].y; 528 | 529 | for (i = 1; i < n; ++i) { 530 | point* p = &points[i]; 531 | 532 | if (p->x < xmin) 533 | xmin = p->x; 534 | else if (p->x > xmax) 535 | xmax = p->x; 536 | if (p->y < ymin) 537 | ymin = p->y; 538 | else if (p->y > ymax) 539 | ymax = p->y; 540 | } 541 | 542 | if (xmin == xmax || ymin == ymax) 543 | return NaN; 544 | else 545 | k = (ymax - ymin) / (xmax - xmin); 546 | 547 | for (i = 0; i < n; ++i) 548 | points[i].y /= k; 549 | 550 | return k; 551 | } 552 | 553 | /** Compresses Y domain by a given multiple. 554 | * 555 | * @param n Number of points 556 | * @param points The points to scale 557 | * @param Y axis compression coefficient as returned by points_scaletosquare() 558 | */ 559 | void points_scale(int n, point* points, double k) 560 | { 561 | int i; 562 | 563 | for (i = 0; i < n; ++i) 564 | points[i].y /= k; 565 | } 566 | -------------------------------------------------------------------------------- /nn/nncommon.h: -------------------------------------------------------------------------------- 1 | #if !defined(_NNCOMMON_H) 2 | #define _NN_COMMON_H 3 | 4 | typedef struct { 5 | double x; 6 | double y; 7 | double r; 8 | } circle; 9 | 10 | int circle_build1(circle* c, point* p0, point* p1, point* p2); 11 | int circle_build2(circle* c, point* p0, point* p1, point* p2); 12 | int circle_contains(circle* c, point* p); 13 | void nn_quit(char* format, ...); 14 | 15 | #endif /* _NN_COMMON_H */ 16 | -------------------------------------------------------------------------------- /nn/nnconfig.h.in: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sakov/nn-c/3e7309e8f5f689dcce6af77adbb0b177504ec5df/nn/nnconfig.h.in -------------------------------------------------------------------------------- /nn/nnpi.c: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sakov/nn-c/3e7309e8f5f689dcce6af77adbb0b177504ec5df/nn/nnpi.c -------------------------------------------------------------------------------- /nn/nnpi.h: -------------------------------------------------------------------------------- 1 | void nnpi_calculate_weights(nnpi* nn, point* p); 2 | int nnpi_get_nvertices(nnpi* nn); 3 | int* nnpi_get_vertices(nnpi* nn); 4 | double* nnpi_get_weights(nnpi* nn); 5 | -------------------------------------------------------------------------------- /nn/preader.c: -------------------------------------------------------------------------------- 1 | /****************************************************************************** 2 | * 3 | * File: preader.c 4 | * 5 | * Created: 29/05/2006 6 | * 7 | * Author: Pavel Sakov 8 | * CSIRO Marine Research 9 | * 10 | * Purpose: Serial "reader" of the output point locations 11 | * 12 | * Description: The `reader' object enables the client code to "read" one 13 | * output point at a time, either from a file or from a virtual 14 | * nx x ny grid. As a result, using `reader' makes it possible 15 | * to interpolate on a point-by-point basis, avoiding allocation 16 | * of the whole output array in memory. 17 | * 18 | * Revisions: None 19 | * 20 | *****************************************************************************/ 21 | 22 | #include 23 | #include 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include 29 | #include "config.h" 30 | #include "nan.h" 31 | #include "nn.h" 32 | #include "nncommon.h" 33 | #include "preader.h" 34 | 35 | #define BUFSIZE 1024 36 | 37 | typedef struct { 38 | char* fname; 39 | FILE* f; 40 | int n; 41 | point p; 42 | } reader; 43 | 44 | typedef struct { 45 | int nx; 46 | int ny; 47 | int nmax; 48 | double stepx; 49 | double stepy; 50 | double x0; 51 | int n; 52 | point p; 53 | } grid; 54 | 55 | struct preader { 56 | grid* g; 57 | reader* r; 58 | }; 59 | 60 | static int str2double(char* token, double* value) 61 | { 62 | char* end = NULL; 63 | 64 | if (token == NULL) { 65 | *value = NaN; 66 | return 0; 67 | } 68 | 69 | *value = strtod(token, &end); 70 | 71 | if (end == token) { 72 | *value = NaN; 73 | return 0; 74 | } 75 | 76 | return 1; 77 | } 78 | 79 | static grid* grid_create(double xmin, double xmax, double ymin, double ymax, int nx, int ny, int j1, int j2) 80 | { 81 | grid* g = NULL; 82 | int i; 83 | 84 | if (nx < 1 || ny < 1) 85 | return NULL; 86 | 87 | g = malloc(sizeof(grid)); 88 | g->nx = nx; 89 | g->ny = ny; 90 | g->nmax = nx * ny; 91 | 92 | if (j1 < 0 || j2 < 0) 93 | j1 = 0; 94 | else 95 | g->nmax = nx * (j2 - j1 + 1); 96 | 97 | g->stepx = (nx > 1) ? (xmax - xmin) / (nx - 1) : 0.0; 98 | g->stepy = (ny > 1) ? (ymax - ymin) / (ny - 1) : 0.0; 99 | g->x0 = (nx > 1) ? xmin : (xmin + xmax) / 2.0; 100 | g->p.y = (ny > 1) ? ymin - g->stepy : (ymin + ymax) / 2.0; 101 | for (i = 0; i < j1; ++i) 102 | g->p.y += g->stepy; 103 | g->n = 0; 104 | 105 | return g; 106 | } 107 | 108 | static point* grid_getpoint(grid* g) 109 | { 110 | if (g->n >= g->nmax) 111 | return NULL; 112 | 113 | if (g->n % g->nx == 0) { 114 | g->p.x = g->x0; 115 | g->p.y += g->stepy; 116 | } else 117 | g->p.x += g->stepx; 118 | 119 | g->n++; 120 | 121 | return &g->p; 122 | } 123 | 124 | static void grid_destroy(grid* g) 125 | { 126 | free(g); 127 | } 128 | 129 | static reader* reader_create(char* fname) 130 | { 131 | reader* r = malloc(sizeof(reader)); 132 | 133 | r->fname = NULL; 134 | r->f = NULL; 135 | r->p.x = NaN; 136 | r->p.y = NaN; 137 | r->p.z = NaN; 138 | r->n = 0; 139 | 140 | if (fname == NULL) { 141 | r->fname = strdup("stdin"); 142 | r->f = stdin; 143 | } else { 144 | if (strcmp(fname, "stdin") == 0 || strcmp(fname, "-") == 0) { 145 | r->fname = strdup("stdin"); 146 | r->f = stdin; 147 | } else { 148 | r->fname = strdup(fname); 149 | r->f = fopen(fname, "r"); 150 | if (r->f == NULL) 151 | nn_quit("%s: %s\n", fname, strerror(errno)); 152 | } 153 | } 154 | 155 | return r; 156 | } 157 | 158 | static point* reader_getpoint(reader* r) 159 | { 160 | char buf[BUFSIZE]; 161 | char seps[] = " ,;\t"; 162 | char* token; 163 | point* p = &r->p; 164 | 165 | if (r->f == NULL) 166 | return NULL; 167 | 168 | while (1) { 169 | if (fgets(buf, BUFSIZE, r->f) == NULL) { 170 | if (r->f != stdin) 171 | if (fclose(r->f) != 0) 172 | nn_quit("%s: %s\n", r->fname, strerror(errno)); 173 | r->f = NULL; 174 | 175 | return NULL; 176 | } 177 | 178 | if (buf[0] == '#') 179 | continue; 180 | if ((token = strtok(buf, seps)) == NULL) 181 | continue; 182 | if (!str2double(token, &p->x)) 183 | continue; 184 | if ((token = strtok(NULL, seps)) == NULL) 185 | continue; 186 | if (!str2double(token, &p->y)) 187 | continue; 188 | r->n++; 189 | 190 | return p; 191 | } 192 | } 193 | 194 | static void reader_destroy(reader* r) 195 | { 196 | if (r->f != stdin && r->f != NULL) 197 | if (fclose(r->f) != 0) 198 | nn_quit("%s: %s\n", r->fname, strerror(errno)); 199 | free(r->fname); 200 | free(r); 201 | } 202 | 203 | preader* preader_create1(double xmin, double xmax, double ymin, double ymax, int nx, int ny, int j1, int j2) 204 | { 205 | preader* pr = malloc(sizeof(preader)); 206 | 207 | pr->r = NULL; 208 | pr->g = grid_create(xmin, xmax, ymin, ymax, nx, ny, j1, j2); 209 | 210 | return pr; 211 | } 212 | 213 | preader* preader_create2(char* fname) 214 | { 215 | preader* pr = malloc(sizeof(preader)); 216 | 217 | pr->g = NULL; 218 | pr->r = reader_create(fname); 219 | 220 | return pr; 221 | } 222 | 223 | int preader_istype1(preader* pr) 224 | { 225 | return (pr->g != NULL); 226 | } 227 | 228 | point* preader_getpoint(preader* pr) 229 | { 230 | if (pr->g != NULL) 231 | return grid_getpoint(pr->g); 232 | else 233 | return reader_getpoint(pr->r); 234 | } 235 | 236 | void preader_destroy(preader* pr) 237 | { 238 | if (pr->g != NULL) 239 | grid_destroy(pr->g); 240 | else 241 | reader_destroy(pr->r); 242 | 243 | free(pr); 244 | } 245 | -------------------------------------------------------------------------------- /nn/preader.h: -------------------------------------------------------------------------------- 1 | /****************************************************************************** 2 | * 3 | * File: preader.h 4 | * 5 | * Created: 29/05/2006 6 | * 7 | * Author: Pavel Sakov 8 | * CSIRO Marine Research 9 | * 10 | * Purpose: A header file with preader.c 11 | * 12 | * Revisions: None 13 | * 14 | *****************************************************************************/ 15 | 16 | #if !defined(_PREADER_H) 17 | #define _PREADER_H 18 | 19 | struct preader; 20 | typedef struct preader preader; 21 | 22 | preader* preader_create1(double xmin, double xmax, double ymin, double ymax, int nx, int ny, int j1, int j2); 23 | preader* preader_create2(char* fname); 24 | point* preader_getpoint(preader* pr); 25 | void preader_destroy(preader* pr); 26 | int preader_istype1(preader* pr); 27 | 28 | #endif 29 | -------------------------------------------------------------------------------- /nn/triangle.h: -------------------------------------------------------------------------------- 1 | /*****************************************************************************/ 2 | /* */ 3 | /* (triangle.h) */ 4 | /* */ 5 | /* Include file for programs that call Triangle. */ 6 | /* */ 7 | /* Accompanies Triangle Versions 1.3 and 1.4 */ 8 | /* July 19, 1996 */ 9 | /* */ 10 | /* Copyright 1996 */ 11 | /* Jonathan Richard Shewchuk */ 12 | /* 2360 Woolsey #H */ 13 | /* Berkeley, California 94705-1927 */ 14 | /* jrs@cs.berkeley.edu */ 15 | /* */ 16 | /*****************************************************************************/ 17 | 18 | /*****************************************************************************/ 19 | /* */ 20 | /* How to call Triangle from another program */ 21 | /* */ 22 | /* */ 23 | /* If you haven't read Triangle's instructions (run "triangle -h" to read */ 24 | /* them), you won't understand what follows. */ 25 | /* */ 26 | /* Triangle must be compiled into an object file (triangle.o) with the */ 27 | /* TRILIBRARY symbol defined (preferably by using the -DTRILIBRARY compiler */ 28 | /* switch). The makefile included with Triangle will do this for you if */ 29 | /* you run "make trilibrary". The resulting object file can be called via */ 30 | /* the procedure triangulate(). */ 31 | /* */ 32 | /* If the size of the object file is important to you, you may wish to */ 33 | /* generate a reduced version of triangle.o. The REDUCED symbol gets rid */ 34 | /* of all features that are primarily of research interest. Specifically, */ 35 | /* the -DREDUCED switch eliminates Triangle's -i, -F, -s, and -C switches. */ 36 | /* The CDT_ONLY symbol gets rid of all meshing algorithms above and beyond */ 37 | /* constrained Delaunay triangulation. Specifically, the -DCDT_ONLY switch */ 38 | /* eliminates Triangle's -r, -q, -a, -S, and -s switches. */ 39 | /* */ 40 | /* IMPORTANT: These definitions (TRILIBRARY, REDUCED, CDT_ONLY) must be */ 41 | /* made in the makefile or in triangle.c itself. Putting these definitions */ 42 | /* in this file will not create the desired effect. */ 43 | /* */ 44 | /* */ 45 | /* The calling convention for triangulate() follows. */ 46 | /* */ 47 | /* void triangulate(triswitches, in, out, vorout) */ 48 | /* char *triswitches; */ 49 | /* struct triangulateio *in; */ 50 | /* struct triangulateio *out; */ 51 | /* struct triangulateio *vorout; */ 52 | /* */ 53 | /* `triswitches' is a string containing the command line switches you wish */ 54 | /* to invoke. No initial dash is required. Some suggestions: */ 55 | /* */ 56 | /* - You'll probably find it convenient to use the `z' switch so that */ 57 | /* points (and other items) are numbered from zero. This simplifies */ 58 | /* indexing, because the first item of any type always starts at index */ 59 | /* [0] of the corresponding array, whether that item's number is zero or */ 60 | /* one. */ 61 | /* - You'll probably want to use the `Q' (quiet) switch in your final code, */ 62 | /* but you can take advantage of Triangle's printed output (including the */ 63 | /* `V' switch) while debugging. */ 64 | /* - If you are not using the `q' or `a' switches, then the output points */ 65 | /* will be identical to the input points, except possibly for the */ 66 | /* boundary markers. If you don't need the boundary markers, you should */ 67 | /* use the `N' (no nodes output) switch to save memory. (If you do need */ 68 | /* boundary markers, but need to save memory, a good nasty trick is to */ 69 | /* set out->pointlist equal to in->pointlist before calling triangulate(),*/ 70 | /* so that Triangle overwrites the input points with identical copies.) */ 71 | /* - The `I' (no iteration numbers) and `g' (.off file output) switches */ 72 | /* have no effect when Triangle is compiled with TRILIBRARY defined. */ 73 | /* */ 74 | /* `in', `out', and `vorout' are descriptions of the input, the output, */ 75 | /* and the Voronoi output. If the `v' (Voronoi output) switch is not used, */ 76 | /* `vorout' may be NULL. `in' and `out' may never be NULL. */ 77 | /* */ 78 | /* Certain fields of the input and output structures must be initialized, */ 79 | /* as described below. */ 80 | /* */ 81 | /*****************************************************************************/ 82 | 83 | /*****************************************************************************/ 84 | /* */ 85 | /* The `triangulateio' structure. */ 86 | /* */ 87 | /* Used to pass data into and out of the triangulate() procedure. */ 88 | /* */ 89 | /* */ 90 | /* Arrays are used to store points, triangles, markers, and so forth. In */ 91 | /* all cases, the first item in any array is stored starting at index [0]. */ 92 | /* However, that item is item number `1' unless the `z' switch is used, in */ 93 | /* which case it is item number `0'. Hence, you may find it easier to */ 94 | /* index points (and triangles in the neighbor list) if you use the `z' */ 95 | /* switch. Unless, of course, you're calling Triangle from a Fortran */ 96 | /* program. */ 97 | /* */ 98 | /* Description of fields (except the `numberof' fields, which are obvious): */ 99 | /* */ 100 | /* `pointlist': An array of point coordinates. The first point's x */ 101 | /* coordinate is at index [0] and its y coordinate at index [1], followed */ 102 | /* by the coordinates of the remaining points. Each point occupies two */ 103 | /* REALs. */ 104 | /* `pointattributelist': An array of point attributes. Each point's */ 105 | /* attributes occupy `numberofpointattributes' REALs. */ 106 | /* `pointmarkerlist': An array of point markers; one int per point. */ 107 | /* */ 108 | /* `trianglelist': An array of triangle corners. The first triangle's */ 109 | /* first corner is at index [0], followed by its other two corners in */ 110 | /* counterclockwise order, followed by any other nodes if the triangle */ 111 | /* represents a nonlinear element. Each triangle occupies */ 112 | /* `numberofcorners' ints. */ 113 | /* `triangleattributelist': An array of triangle attributes. Each */ 114 | /* triangle's attributes occupy `numberoftriangleattributes' REALs. */ 115 | /* `trianglearealist': An array of triangle area constraints; one REAL per */ 116 | /* triangle. Input only. */ 117 | /* `neighborlist': An array of triangle neighbors; three ints per */ 118 | /* triangle. Output only. */ 119 | /* */ 120 | /* `segmentlist': An array of segment endpoints. The first segment's */ 121 | /* endpoints are at indices [0] and [1], followed by the remaining */ 122 | /* segments. Two ints per segment. */ 123 | /* `segmentmarkerlist': An array of segment markers; one int per segment. */ 124 | /* */ 125 | /* `holelist': An array of holes. The first hole's x and y coordinates */ 126 | /* are at indices [0] and [1], followed by the remaining holes. Two */ 127 | /* REALs per hole. Input only, although the pointer is copied to the */ 128 | /* output structure for your convenience. */ 129 | /* */ 130 | /* `regionlist': An array of regional attributes and area constraints. */ 131 | /* The first constraint's x and y coordinates are at indices [0] and [1], */ 132 | /* followed by the regional attribute and index [2], followed by the */ 133 | /* maximum area at index [3], followed by the remaining area constraints. */ 134 | /* Four REALs per area constraint. Note that each regional attribute is */ 135 | /* used only if you select the `A' switch, and each area constraint is */ 136 | /* used only if you select the `a' switch (with no number following), but */ 137 | /* omitting one of these switches does not change the memory layout. */ 138 | /* Input only, although the pointer is copied to the output structure for */ 139 | /* your convenience. */ 140 | /* */ 141 | /* `edgelist': An array of edge endpoints. The first edge's endpoints are */ 142 | /* at indices [0] and [1], followed by the remaining edges. Two ints per */ 143 | /* edge. Output only. */ 144 | /* `edgemarkerlist': An array of edge markers; one int per edge. Output */ 145 | /* only. */ 146 | /* `normlist': An array of normal vectors, used for infinite rays in */ 147 | /* Voronoi diagrams. The first normal vector's x and y magnitudes are */ 148 | /* at indices [0] and [1], followed by the remaining vectors. For each */ 149 | /* finite edge in a Voronoi diagram, the normal vector written is the */ 150 | /* zero vector. Two REALs per edge. Output only. */ 151 | /* */ 152 | /* */ 153 | /* Any input fields that Triangle will examine must be initialized. */ 154 | /* Furthermore, for each output array that Triangle will write to, you */ 155 | /* must either provide space by setting the appropriate pointer to point */ 156 | /* to the space you want the data written to, or you must initialize the */ 157 | /* pointer to NULL, which tells Triangle to allocate space for the results. */ 158 | /* The latter option is preferable, because Triangle always knows exactly */ 159 | /* how much space to allocate. The former option is provided mainly for */ 160 | /* people who need to call Triangle from Fortran code, though it also makes */ 161 | /* possible some nasty space-saving tricks, like writing the output to the */ 162 | /* same arrays as the input. */ 163 | /* */ 164 | /* Triangle will not free() any input or output arrays, including those it */ 165 | /* allocates itself; that's up to you. */ 166 | /* */ 167 | /* Here's a guide to help you decide which fields you must initialize */ 168 | /* before you call triangulate(). */ 169 | /* */ 170 | /* `in': */ 171 | /* */ 172 | /* - `pointlist' must always point to a list of points; `numberofpoints' */ 173 | /* and `numberofpointattributes' must be properly set. */ 174 | /* `pointmarkerlist' must either be set to NULL (in which case all */ 175 | /* markers default to zero), or must point to a list of markers. If */ 176 | /* `numberofpointattributes' is not zero, `pointattributelist' must */ 177 | /* point to a list of point attributes. */ 178 | /* - If the `r' switch is used, `trianglelist' must point to a list of */ 179 | /* triangles, and `numberoftriangles', `numberofcorners', and */ 180 | /* `numberoftriangleattributes' must be properly set. If */ 181 | /* `numberoftriangleattributes' is not zero, `triangleattributelist' */ 182 | /* must point to a list of triangle attributes. If the `a' switch is */ 183 | /* used (with no number following), `trianglearealist' must point to a */ 184 | /* list of triangle area constraints. `neighborlist' may be ignored. */ 185 | /* - If the `p' switch is used, `segmentlist' must point to a list of */ 186 | /* segments, `numberofsegments' must be properly set, and */ 187 | /* `segmentmarkerlist' must either be set to NULL (in which case all */ 188 | /* markers default to zero), or must point to a list of markers. */ 189 | /* - If the `p' switch is used without the `r' switch, then */ 190 | /* `numberofholes' and `numberofregions' must be properly set. If */ 191 | /* `numberofholes' is not zero, `holelist' must point to a list of */ 192 | /* holes. If `numberofregions' is not zero, `regionlist' must point to */ 193 | /* a list of region constraints. */ 194 | /* - If the `p' switch is used, `holelist', `numberofholes', */ 195 | /* `regionlist', and `numberofregions' is copied to `out'. (You can */ 196 | /* nonetheless get away with not initializing them if the `r' switch is */ 197 | /* used.) */ 198 | /* - `edgelist', `edgemarkerlist', `normlist', and `numberofedges' may be */ 199 | /* ignored. */ 200 | /* */ 201 | /* `out': */ 202 | /* */ 203 | /* - `pointlist' must be initialized (NULL or pointing to memory) unless */ 204 | /* the `N' switch is used. `pointmarkerlist' must be initialized */ 205 | /* unless the `N' or `B' switch is used. If `N' is not used and */ 206 | /* `in->numberofpointattributes' is not zero, `pointattributelist' must */ 207 | /* be initialized. */ 208 | /* - `trianglelist' must be initialized unless the `E' switch is used. */ 209 | /* `neighborlist' must be initialized if the `n' switch is used. If */ 210 | /* the `E' switch is not used and (`in->numberofelementattributes' is */ 211 | /* not zero or the `A' switch is used), `elementattributelist' must be */ 212 | /* initialized. `trianglearealist' may be ignored. */ 213 | /* - `segmentlist' must be initialized if the `p' or `c' switch is used, */ 214 | /* and the `P' switch is not used. `segmentmarkerlist' must also be */ 215 | /* initialized under these circumstances unless the `B' switch is used. */ 216 | /* - `edgelist' must be initialized if the `e' switch is used. */ 217 | /* `edgemarkerlist' must be initialized if the `e' switch is used and */ 218 | /* the `B' switch is not. */ 219 | /* - `holelist', `regionlist', `normlist', and all scalars may be ignored.*/ 220 | /* */ 221 | /* `vorout' (only needed if `v' switch is used): */ 222 | /* */ 223 | /* - `pointlist' must be initialized. If `in->numberofpointattributes' */ 224 | /* is not zero, `pointattributelist' must be initialized. */ 225 | /* `pointmarkerlist' may be ignored. */ 226 | /* - `edgelist' and `normlist' must both be initialized. */ 227 | /* `edgemarkerlist' may be ignored. */ 228 | /* - Everything else may be ignored. */ 229 | /* */ 230 | /* After a call to triangulate(), the valid fields of `out' and `vorout' */ 231 | /* will depend, in an obvious way, on the choice of switches used. Note */ 232 | /* that when the `p' switch is used, the pointers `holelist' and */ 233 | /* `regionlist' are copied from `in' to `out', but no new space is */ 234 | /* allocated; be careful that you don't free() the same array twice. On */ 235 | /* the other hand, Triangle will never copy the `pointlist' pointer (or any */ 236 | /* others); new space is allocated for `out->pointlist', or if the `N' */ 237 | /* switch is used, `out->pointlist' remains uninitialized. */ 238 | /* */ 239 | /* All of the meaningful `numberof' fields will be properly set; for */ 240 | /* instance, `numberofedges' will represent the number of edges in the */ 241 | /* triangulation whether or not the edges were written. If segments are */ 242 | /* not used, `numberofsegments' will indicate the number of boundary edges. */ 243 | /* */ 244 | /*****************************************************************************/ 245 | 246 | #ifdef SINGLE 247 | #define REAL float 248 | #else /* not SINGLE */ 249 | #define REAL double 250 | #endif /* not SINGLE */ 251 | 252 | struct triangulateio { 253 | REAL *pointlist; /* In / out */ 254 | REAL *pointattributelist; /* In / out */ 255 | int *pointmarkerlist; /* In / out */ 256 | int numberofpoints; /* In / out */ 257 | int numberofpointattributes; /* In / out */ 258 | 259 | int *trianglelist; /* In / out */ 260 | REAL *triangleattributelist; /* In / out */ 261 | REAL *trianglearealist; /* In only */ 262 | int *neighborlist; /* Out only */ 263 | int numberoftriangles; /* In / out */ 264 | int numberofcorners; /* In / out */ 265 | int numberoftriangleattributes; /* In / out */ 266 | 267 | int *segmentlist; /* In / out */ 268 | int *segmentmarkerlist; /* In / out */ 269 | int numberofsegments; /* In / out */ 270 | 271 | REAL *holelist; /* In / pointer to array copied out */ 272 | int numberofholes; /* In / copied out */ 273 | 274 | REAL *regionlist; /* In / pointer to array copied out */ 275 | int numberofregions; /* In / copied out */ 276 | 277 | int *edgelist; /* Out only */ 278 | int *edgemarkerlist; /* Not used with Voronoi diagram; out only */ 279 | REAL *normlist; /* Used only with Voronoi diagram; out only */ 280 | int numberofedges; /* Out only */ 281 | }; 282 | 283 | #ifdef ANSI_DECLARATORS 284 | void triangulate(char *, struct triangulateio *, struct triangulateio *, 285 | struct triangulateio *); 286 | #else /* not ANSI_DECLARATORS */ 287 | void triangulate(); 288 | #endif /* not ANSI_DECLARATORS */ 289 | -------------------------------------------------------------------------------- /nn/version.c: -------------------------------------------------------------------------------- 1 | /****************************************************************************** 2 | * 3 | * File: version.c 4 | * 5 | * Created: 05/05/2021 6 | * 7 | * Author: Pavel Sakov 8 | * BoM 9 | * 10 | * Purpose: NN library version. 11 | * 12 | * Description: NN library version. 13 | * 14 | * Revisions: None 15 | * 16 | *****************************************************************************/ 17 | 18 | char* nn_version = "2.0.9"; 19 | --------------------------------------------------------------------------------