This commit is contained in:
Ivan
2022-05-27 08:26:38 +03:00
parent 9b54c48dc3
commit 5909db4eec
3849 changed files with 2165811 additions and 0 deletions

159
thirdparty/oscpack_1_1_0/CHANGES vendored Normal file
View File

@@ -0,0 +1,159 @@
April 9, 2013
-------------
Changes for the 1.1.0 release (vs 1.0.2) are listed below. Unless
otherwise indicated these changes have been made since
January 2013. The focus has been on general clean-up, fixing bugs,
compiler errors and warnings, and fixing issues on 64 bit platforms.
A few improvements such as support for OSC arrays, functions
for setting broadcast and reuse socket options have been added.
This update merges changes from the openFrameworks version
of oscpack.
- Added support for arrays in messages (see OscUnitTests.cpp
for example usage). (patch thanks to Tim Blechmann)
- Fixed bugs relating to 64 bit usage (e.g. crashes in 64 bit
builds on OS X).
- Some member functions that previously used the "int" or
"unsigned long" type for parameters or return values now use
std::size_t (platform-defined) or
osc_bundle_element_size_t (a.k.a. int32).
This change was made to better support 64 bit platforms.
See SVN revision 70 for details.
- The previous point introduces a breaking change on Linux/x86_64
for callers of AsBlob() and AsBlobUnchecked():
The type of the second argument (the "size" argument) to
ReceivedMessageArgument::AsBlob() and
ReceivedMessageArgument::AsBlobUnchecked() has changed
from unsigned long & to osc_bundle_element_size_t (an int32).
You should declare your size argument variables as
osc_bundle_element_size_t to avoid incompatibilities between
32 and 64 bit builds.
- Note that oscpack does not support packets larger than
0x7FFFFFFC (see comments in class ReceivedPacket for
details).
- Oscpack defines an osc::Nil value used for sending the nil
message argument value. This conflicts with Objective-C.
Therefore osc::Nil is no longer defined in Obj-C++ code.
There is now an osc::OscNil value, which should be preferred.
osc::Nil is still available when writing C++.
(fix thanks to openFrameworks)
- Added UdpSocket::SetEnableBroadcast(). This needs to
be called to enable sending to the broadcast address on some
platforms (e.g. Mac OS X). (thanks to openFrameworks)
- Added UdpSocket::SetAllowReuse(). This is useful for
sharing sockets on some platforms (Mac?), and not so useful
on other platforms. (thanks to openFrameworks)
- Added IpEndpointName::IsMulticastAddress() (2010)
- Cleaned up C++ header usage and std:: namespace usage
to be more standards compliant (fixes issues on recent compilers
such as clang and gcc4.6).
- Improved host endianness detection. Should auto-detect
endianness on most platforms now.
(thanks to Tim Blechmann for help with this)
- Fixed two memory leaks: (1) in OscPrintReceivedElements.cpp
when printing time tag message arguments (thanks to Gwydion ap Dafydd).
(2) in the posix SocketReceiveMultiplexer::Run() method if an exception
was thrown while listening.
- Fixed bug in posix SocketReceiveMultiplexer::Run() that would cause
packets to stop being received if select() returned EINTR.
(thanks to Björn Wöldecke)
- Updated and improved Makefile to avoid redundant re-linking
(thanks to Douglas Mandell)
- Added CMakeLists.txt CMake build file (2010, thanks to David Doria)
- Switched license to plain MIT license with non binding request
for contribution of improvements (same as current PortAudio
boilerplate). See LICENSE file.
Thanks to Tim Blechmann, Rob Canning, Gwydion ap Dafydd, David Doria,
Christopher Delaney, Jon McCormack, Douglas Mandell, Björn Wöldecke,
all the guys at openFrameworks, and everyone who reported bugs,
submitted patches and helped out with testing this release.
Thanks to Syneme at the University of Calgary for providing financial
support for the 1.1.0 update.
September 28, 2005
------------------
Compared to the previous official snapshot (November 2004) the
current version of oscpack includes a re-written set of network
classes and some changes to the syntax of the networking code. It no
longer uses threads, which means that you don't need to use sleep()
if you are writing a simple single-threaded server, or you need to
spawn your own threads in a more complex application.
The list below summarises the changes if you are porting code from
the previous release.
- There are no longer any threads in oscpack. if you need to
set up an asynchronous listener you can create your own thread
and call Run on an instance of SocketReceiveMultiplexer or
UdpListeningReceiveSocket (see ip/UdpSocket.h) yourself.
- Host byte order is now used for network (IP) addresses
- Functions which used to take two parameters <address, port>
now take an instance of IpEndpointName (see
ip/IpEndpointName.h) this class has a number of convenient
constructors for converting numbers and strings to internet
addresses. For example there is one which takes a string and
another that take the dotted address components as separate
parameters.
- The UdpTransmitPort class, formerly in UdpTransmitPort.h, is
now called UdpTransmitSocket, which is simply a convenience
class derived from UdpSocket (see ip/UdpSocket.h). Where you
used to use the constructor UdpTransmitPort( address, port) now
you can use UdpTransmitSocket( IpEndpointName( address, port )
) or you can any of the other possible ctors to IpEndpointName
() (see above). The Send() method is unchanged.
- The packet listener base class is now located in
ip/PacketListener.h instead of PacketListenerPort.h. The
ProcessPacket method now has an additional parameter indicating
the remote endpoint
- The preferred way to set up listeners is with
SocketReceiveMultiplexer (in ip/UdpSocket.h), this also allows
attaching periodic timers. For simple applications which only
listen to a single socket with no timers you can use
UdpListeningReceiveSocket (also in UdpSocket.h) See
osc/OscReceiveTest.cpp or osc/OscDump.cpp for examples of this.
This is more or less equivalent to the UdpPacketListenerPort
object in the old oscpack versions except that you need to
explicitly call Run() before it will start receiving packets
and it runs in the same thread, not a separate thread so Run()
won't usually return.
- Explicit calls to InitializeNetworking() and
TerminateNetworking() are no longer required for simple
applications (more complex windows applications should
instantiate NetworkInitializer in main() or WinMain (see
ip/NetworkingUtils.h/.cpp)
- The OscPacketListener base class (OscPacketListener.h) was
added to make traversing OSC packets easier, it handles bundle
traversal automatically so you only need to process messages in
your derived classes.
- On Windows be sure to link with ws2_32.lib or you will see
a linker error about WSAEventSelect not being found. Also you
will need to link with winmm.lib for timeGetTime()

76
thirdparty/oscpack_1_1_0/CMakeLists.txt vendored Normal file
View File

@@ -0,0 +1,76 @@
cmake_minimum_required(VERSION 2.6)
PROJECT(TestOscpack)
INCLUDE_DIRECTORIES(${CMAKE_SOURCE_DIR})
# separate versions of NetworkingUtils.cpp and UdpSocket.cpp are provided for Win32 and POSIX
# the IpSystemTypePath selects the correct ones based on the current platform
IF(WIN32)
set(IpSystemTypePath ip/win32)
set(LIBS ${LIBS} Ws2_32 winmm)
ELSE(WIN32)
set(IpSystemTypePath ip/posix)
ENDIF(WIN32)
ADD_LIBRARY(oscpack
ip/IpEndpointName.h
ip/IpEndpointName.cpp
ip/NetworkingUtils.h
${IpSystemTypePath}/NetworkingUtils.cpp
ip/UdpSocket.h
${IpSystemTypePath}/UdpSocket.cpp
ip/PacketListener.h
ip/TimerListener.h
osc/OscTypes.h
osc/OscTypes.cpp
osc/OscHostEndianness.h
osc/OscException.h
osc/OscPacketListener.h
osc/MessageMappingOscPacketListener.h
osc/OscReceivedElements.h
osc/OscReceivedElements.cpp
osc/OscPrintReceivedElements.h
osc/OscPrintReceivedElements.cpp
osc/OscOutboundPacketStream.h
osc/OscOutboundPacketStream.cpp
)
ADD_EXECUTABLE(OscUnitTests tests/OscUnitTests.cpp)
TARGET_LINK_LIBRARIES(OscUnitTests oscpack ${LIBS})
ADD_EXECUTABLE(OscSendTests tests/OscSendTests.cpp)
TARGET_LINK_LIBRARIES(OscSendTests oscpack ${LIBS})
ADD_EXECUTABLE(OscReceiveTest tests/OscReceiveTest.cpp)
TARGET_LINK_LIBRARIES(OscReceiveTest oscpack ${LIBS})
ADD_EXECUTABLE(OscDump examples/OscDump.cpp)
TARGET_LINK_LIBRARIES(OscDump oscpack ${LIBS})
ADD_EXECUTABLE(SimpleReceive examples/SimpleReceive.cpp)
TARGET_LINK_LIBRARIES(SimpleReceive oscpack ${LIBS})
ADD_EXECUTABLE(SimpleSend examples/SimpleSend.cpp)
TARGET_LINK_LIBRARIES(SimpleSend oscpack ${LIBS})
if(MSVC)
# Force to always compile with W4
if(CMAKE_CXX_FLAGS MATCHES "/W[0-4]")
string(REGEX REPLACE "/W[0-4]" "/W4" CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}")
else()
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /W4")
endif()
elseif(CMAKE_COMPILER_IS_GNUCC OR CMAKE_COMPILER_IS_GNUCXX)
# Update if necessary
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wextra -Wno-long-long -pedantic")
endif()

34
thirdparty/oscpack_1_1_0/LICENSE vendored Normal file
View File

@@ -0,0 +1,34 @@
oscpack -- Open Sound Control (OSC) packet manipulation library
http://www.rossbencina.com/code/oscpack
Copyright (c) 2004-2013 Ross Bencina <rossb@audiomulch.com>
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files
(the "Software"), to deal in the Software without restriction,
including without limitation the rights to use, copy, modify, merge,
publish, distribute, sublicense, and/or sell copies of the Software,
and to permit persons to whom the Software is furnished to do so,
subject to the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
###
The text above constitutes the entire oscpack license; however,
the oscpack developer(s) also make the following non-binding requests:
Any person wishing to distribute modifications to the Software is
requested to send the modifications to the original developer so that
they can be incorporated into the canonical version. It is also
requested that these non-binding requests be included whenever the
above license is reproduced.

148
thirdparty/oscpack_1_1_0/Makefile vendored Normal file
View File

@@ -0,0 +1,148 @@
# oscpack makefile
# the source code should auto-detect endianess for most systems
# (see osc/OscHostEndianness.h)
# otherwise you need to explicitly set ENDIANESS below
# to either OSC_HOST_BIG_ENDIAN or OSC_HOST_LITTLE_ENDIAN
# Apple Mac OS X (PowerPC): OSC_HOST_BIG_ENDIAN
# Apple Mac OS X (Intel): OSC_HOST_LITTLE_ENDIAN
# Win32: OSC_HOST_LITTLE_ENDIAN
# i386 GNU/Linux: OSC_HOST_LITTLE_ENDIAN
ENDIANESS=OSC_DETECT_ENDIANESS #source code will detect using preprocessor
#ENDIANESS=OSC_HOST_LITTLE_ENDIAN
UNAME := $(shell uname)
CXX := g++
INCLUDES := -I.
COPTS := -Wall -Wextra -O3
CDEBUG := -Wall -Wextra -g
CXXFLAGS := $(COPTS) $(INCLUDES) -D$(ENDIANESS)
BINDIR := bin
PREFIX := /usr/local
INSTALL := install -c
#Name definitions
UNITTESTS := $(BINDIR)/OscUnitTests
SENDTESTS := $(BINDIR)/OscSendTests
RECEIVETEST := $(BINDIR)/OscReceiveTest
SIMPLESEND := $(BINDIR)/SimpleSend
SIMPLERECEIVE := $(BINDIR)/SimpleReceive
DUMP := $(BINDIR)/OscDump
INCLUDEDIR := oscpack
LIBNAME := liboscpack
LIBSONAME := $(LIBNAME).so
LIBFILENAME := $(LIBSONAME).1.1.0
# Common source groups
RECEIVESOURCES := osc/OscReceivedElements.cpp osc/OscPrintReceivedElements.cpp
SENDSOURCES := osc/OscOutboundPacketStream.cpp
NETSOURCES := ip/posix/UdpSocket.cpp ip/IpEndpointName.cpp ip/posix/NetworkingUtils.cpp
COMMONSOURCES := osc/OscTypes.cpp
RECEIVEOBJECTS := $(RECEIVESOURCES:.cpp=.o)
SENDOBJECTS := $(SENDSOURCES:.cpp=.o)
NETOBJECTS := $(NETSOURCES:.cpp=.o)
COMMONOBJECTS := $(COMMONSOURCES:.cpp=.o)
# Test source
UNITTESTSOURCES := tests/OscUnitTests.cpp
UNITTESTOBJECTS := $(UNITTESTSOURCES:.cpp=.o)
SENDTESTSSOURCES := tests/OscSendTests.cpp
SENDTESTSOBJECTS := $(SENDTESTSSOURCES:.cpp=.o)
RECEIVETESTSOURCES := tests/OscReceiveTest.cpp
RECEIVETESTOBJECTS := $(RECEIVETESTSOURCES:.cpp=.o)
# Example source
SIMPLESENDSOURCES := examples/SimpleSend.cpp
SIMPLESENDOBJECTS := $(SIMPLESENDSOURCES:.cpp=.o)
SIMPLERECEIVESOURCES := examples/SimpleReceive.cpp
SIMPLERECEIVEOBJECTS := $(SIMPLERECEIVESOURCES:.cpp=.o)
DUMPSOURCES := examples/OscDump.cpp
DUMPOBJECTS := $(DUMPSOURCES:.cpp=.o)
#Library objects
LIBOBJECTS := $(COMMONOBJECTS) $(SENDOBJECTS) $(RECEIVEOBJECTS) $(NETOBJECTS)
.PHONY: all unittests sendtests receivetest simplesend simplereceive dump library clean install install-local
all: unittests sendtests receivetest simplesend simplereceive dump
unittests : $(UNITTESTS)
sendtests: $(SENDTESTS)
receivetest : $(RECEIVETEST)
simplesend : $(SIMPLESEND)
simplereceive : $(SIMPLERECEIVE)
dump : $(DUMP)
# Build rule and common dependencies for all programs
# | specifies an order-only dependency so changes to bin dir modified date don't trigger recompile
$(UNITTESTS) $(SENDTESTS) $(RECEIVETEST) $(SIMPLESEND) $(SIMPLERECEIVE) $(DUMP) : $(COMMONOBJECTS) | $(BINDIR)
$(CXX) -o $@ $^
# Additional dependencies for each program (make accumulates dependencies from multiple declarations)
$(UNITTESTS) : $(UNITTESTOBJECTS) $(SENDOBJECTS) $(RECEIVEOBJECTS)
$(SENDTESTS) : $(SENDTESTSOBJECTS) $(SENDOBJECTS) $(NETOBJECTS)
$(RECEIVETEST) : $(RECEIVETESTOBJECTS) $(RECEIVEOBJECTS) $(NETOBJECTS)
$(SIMPLESEND) : $(SIMPLESENDOBJECTS) $(SENDOBJECTS) $(NETOBJECTS)
$(SIMPLERECEIVE) : $(SIMPLERECEIVEOBJECTS) $(RECEIVEOBJECTS) $(NETOBJECTS)
$(DUMP) : $(DUMPOBJECTS) $(RECEIVEOBJECTS) $(NETOBJECTS)
$(BINDIR):
mkdir $@
clean:
rm -rf $(BINDIR) $(UNITTESTOBJECTS) $(SENDTESTSOBJECTS) $(RECEIVETESTOBJECTS) $(DUMPOBJECTS) $(LIBOBJECTS) $(SIMPLESENDOBJECTS) $(SIMPLERECEIVEOBJECTS) $(LIBFILENAME) include lib oscpack &> /dev/null
$(LIBFILENAME): $(LIBOBJECTS)
ifeq ($(UNAME), Darwin)
#Mac OS X case
$(CXX) -dynamiclib -Wl,-install_name,$(LIBSONAME) -o $(LIBFILENAME) $(LIBOBJECTS) -lc
else
#GNU/Linux case
$(CXX) -shared -Wl,-soname,$(LIBSONAME) -o $(LIBFILENAME) $(LIBOBJECTS) -lc
endif
lib: $(LIBFILENAME)
#Installs the library on a system global location
install: $(LIBFILENAME)
@$(INSTALL) -m 755 $(LIBFILENAME) $(PREFIX)/lib/$(LIBFILENAME)
@ln -s -f $(PREFIX)/lib/$(LIBFILENAME) $(PREFIX)/lib/$(LIBSONAME)
@mkdir -p $(PREFIX)/include/oscpack/ip $(PREFIX)/include/oscpack/osc
@$(INSTALL) -m 644 ip/*.h $(PREFIX)/include/oscpack/ip
@$(INSTALL) -m 644 osc/*.h $(PREFIX)/include/oscpack/osc
@echo "SUCCESS! oscpack has been installed in $(PREFIX)/lib and $(PREFIX)/include/ospack/"
ifneq ($(UNAME), Darwin)
@echo "now doing ldconfig..."
@ldconfig
endif
#Installs the include/lib structure locally
install-local: $(LIBFILENAME)
@echo ""
@echo " Installing in local directory <$(INCLUDEDIR)>"
@echo " > Creating symbolic link"
@ln -s $(LIBFILENAME) $(LIBSONAME)
@echo " > Creating directories"
@mkdir -p oscpack/lib
@mkdir -p oscpack/include/ip
@mkdir -p oscpack/include/osc
@echo " > Copying files"
@mv $(LIBFILENAME) $(LIBSONAME) oscpack/lib
@cp ip/*.h oscpack/include/ip
@cp osc/*.h oscpack/include/osc
@echo ""
@echo " > Success!"

150
thirdparty/oscpack_1_1_0/README vendored Normal file
View File

@@ -0,0 +1,150 @@
oscpack -- Open Sound Control packet manipulation library
A simple C++ library for packing and unpacking OSC packets.
http://www.rossbencina.com/code/oscpack
Copyright (c) 2004-2013 Ross Bencina <rossb@audiomulch.com>
Oscpack is simply a set of C++ classes for packing and unpacking OSC packets.
Oscpack includes a minimal set of UDP networking classes for Windows and POSIX.
The networking classes are sufficient for writing many OSC applications and servers,
but you are encouraged to use another networking framework if it better suits your needs.
Oscpack is not an OSC application framework. It doesn't include infrastructure for
constructing or routing OSC namespaces, just classes for easily constructing,
sending, receiving and parsing OSC packets. The library should also be easy to use
for other transport methods (e.g. serial).
The key goals of the oscpack library are:
- Be a simple and complete implementation of OSC
- Be portable to a wide variety of platforms
- Allow easy development of robust OSC applications
(for example it should be impossible to crash a server
by sending it malformed packets, and difficult to create
malformed packets.)
Here's a quick run down of the key files:
osc/OscReceivedElements -- classes for parsing a packet
osc/OscPrintRecievedElements -- iostream << operators for printing packet elements
osc/OscOutboundPacketStream -- a class for packing messages into a packet
osc/OscPacketListener -- base class for listening to OSC packets on a UdpSocket
ip/IpEndpointName -- class that represents an IP address and port number
ip/UdpSocket -- classes for UDP transmission and listening sockets
tests/OscUnitTests -- unit test program for the OSC modules
tests/OscSendTests -- examples of how to send messages
tests/OscReceiveTest -- example of how to receive the messages sent by OSCSendTests
examples/OscDump -- a program that prints received OSC packets
examples/SimpleSend -- a minimal program to send an OSC message
examples/SimpleReceive -- a minimal program to receive an OSC message
osc/ contains all of the OSC related classes
ip/ contains the networking classes
ip/windows contains the Windows implementation of the networking classes
ip/posix contains the POSIX implementation of the networking classes
Building
--------
The idea is that you will embed this source code in your projects as you
see fit. The Makefile has an install rule for building a shared library and
installing headers in usr/local. It can also build a static library.
There is a CMakeLists.txt for building with cmake.
Makefile builds
...............
The Makefile works for Linux and Max OS X. It should also work on other platforms
that have make. Just run:
$ make
You can run "make install" if you like.
Cmake builds
............
There is a CMakeLists.txt file which has been tested with cmake on
Windows and Linux. It should work on other platforms too.
For example, to generate a Visual Studio 10 project, run cmake
like this:
> cmake -G "Visual Studio 10"
Run cmake without any parameters to get a list of available generators.
Mingw build batch file
......................
For Windows there is a batch file for doing a simple test build with
MinGW gcc called make.MinGW32.bat. This will build the test executables
and oscdump in ./bin and run the unit tests.
Note:
In some rare instances you may need to edit the Makefile or
osc/OscHostEndianness.h to configure oscpack for the endianness of your
processor (see the comments at the top of the Makefile for details).
Verification test
-----------------
To run the unit tests:
$ ./bin/OscUnitTests
To run the send and receive tests. Open two terminals. In one run:
$ ./bin/OscReceiveTest
Then in the other terminal run:
$./bin/OscSendTests
You should see an indication that the messages were received
in the first terminal.
Note that OscSendTests intentionally sends some unexpected
message parameters to test exception handling in the receiver.
You will see some "error while parsing message" messages printed.
You can use ./bin/OscDump to print out OSC messages received
from any program, including the test programs.
--
If you fix anything or write a set of TCP send/receive classes
please consider sending me a patch. My email address is
rossb@audiomulch.com. Thanks :)
For more information about Open Sound Control, see:
http://opensoundcontrol.org/
Thanks to Till Bovermann for helping with POSIX networking code and
Mac compatibility, and to Martin Kaltenbrunner and the rest of the
reacTable team for giving me a reason to finish this library. Thanks
to Merlijn Blaauw for reviewing the interfaces. Thanks to Xavier Oliver
for additional help with Linux builds and POSIX implementation details.
Portions developed at the Music Technology Group, Audiovisual Institute,
University Pompeu Fabra, Barcelona, during my stay as a visiting
researcher, November 2004 - September 2005.
Thanks to Syneme at the University of Calgary for providing financial
support for the 1.1.0 update, December 2012 - March 2013.
See the file CHANGES for information about recent updates.
See the file LICENSE for information about distributing and using this code.
###

52
thirdparty/oscpack_1_1_0/TODO vendored Normal file
View File

@@ -0,0 +1,52 @@
TODO:
- consider adding the local endpoint name to PacketListener::PacketReceived() params
- consider adding ListenerThread class to support old seperate thread listener functionality, something like:
class UdpSocketListenerThread{
public:
UdpSocketListenerThread( UdpSocket& socket, Listener *listener );
UdpSocketListenerThread( UdpSocketReceiveMultiplexer *mux );
~UdpSocketListenerThread();
void Run();
void Stop();
};
- work out a way to make the parsing classes totally safe. at a minimum this
means adding functions to test for invalid float/doublevalues,
making sure the iterators never pass the end of the message, ...
(passing end of message can happen if:
- too many args in type tags
a. typetags overflow message size
b. args fulfilling typetags overflow message size
- strings too long or not terminated correctly
- blobs too long or not terminated correctly
if the message was fully checked during construction, the end() iterator
could be moved back until only arguments which fit withing size() may
be interated (this could be none). A flag could be set to indicate that
something was wrong.
- other packet badness could include:
- time tags too far into the future (the scheduler should deal with
that i guess).
- message address patterns which aren't correctly terminated
- improve the ability to parse messages without tags (SC uses methods which
get the data and advance the iterator in one step.)
- Check* could be modified to do this - ie if typetags are not present
it could check that reading the field won't escape the message size
and return the data, or return false if some consistency
constraint is violated.
(or alternately drop support for messages without type tags)
- add a method to discard an inprogress message if it gets half
constructed and the buffer is full in OutboundPacket
- write a stress testing app which can send garbage packets to try to flush out other bugs in the parsing code.

BIN
thirdparty/oscpack_1_1_0/bin/OscDump vendored Executable file

Binary file not shown.

BIN
thirdparty/oscpack_1_1_0/bin/OscReceiveTest vendored Executable file

Binary file not shown.

BIN
thirdparty/oscpack_1_1_0/bin/OscSendTests vendored Executable file

Binary file not shown.

BIN
thirdparty/oscpack_1_1_0/bin/OscUnitTests vendored Executable file

Binary file not shown.

BIN
thirdparty/oscpack_1_1_0/bin/SimpleReceive vendored Executable file

Binary file not shown.

BIN
thirdparty/oscpack_1_1_0/bin/SimpleSend vendored Executable file

Binary file not shown.

Binary file not shown.

View File

@@ -0,0 +1,300 @@
===========================================================
List of GDAL/OGR committers
===========================================================
Folks who have agreed to RFC 3 terms:
==================================
Developers with github push rights
==================================
github nickname Name/Contact Area of Interest
=============== ============ ================
rouault Even Rouault all
even.rouault at spatialys.com
warmerdam Frank Warmerdam all
warmerdam@pobox.com
dmorissette Daniel Morissette mitab, avc, cpl
dmorissette at mapgears.com
hobu Howard Butler swig/python, sde
hobu.inc at gmail.com
szekerest Tamas Szekeres c# swig bindings
szekerest at gmail.com
ksshannon Kyle Shannon lcp, netcdf, apps
kyle@pobox.com
avalentino Antonio Valentino SAR formats
antonio.valentino@tiscali.it
jef-n Juergen E. Fischer OGR: NAS
jef at norbit dot de
ajolma Ari Jolma perl bindings
ari.jolma at gmail.com
mloskot Mateusz Loskot geojson, wince
mateusz at loskot.net
strezen Andrey Kiselev HDF, geotiff, informix, core
dron at ak4719.spb.edu
pka Pirmin Kalberer interlis
pka at sourcepole.ch
lucianpls Lucian Plesea mrf, wms
lplesea@esri.com
atlight Alan Thomas DXF
athomas@thinkspatial.com.au
avalentino Antonio Valentino SAR formats
antonio.valentino@tiscali.it
pramsey Paul Ramsey OGR: FGDB, PostGIS
pramsey@cleverelephant.ca
etiennesky Etienne Tourigny netcdf, hdf
etourigny.dev at gmail dot com
rcoup Robert Coup OGR: FGDB
robert@coup.net.nz
dzwarg David Zwarg PostGIS Raster
dzwarg@azavea.com
IvanLucena Ivan Lucena georaster, oci
ivan.lucena at outlook.com
BishopGIS Dmitry Baryshnikov core, sxf, cad, shp
bishop.dev at gmail dot com
schwehr Kurt Schwehr ocean related drivers, python
schwehr@gmail.com
===================
Past SVN developers
===================
SVN Login(s) Name/Contact Area of Interest
============ ============ ================
warmerda Frank Warmerdam all
fwarmerdam warmerdam@pobox.com
warmerdam
tamas Tamas Szekeres c# swig bindings
szekerest at gmail.com
dmorissette Daniel Morissette mitab, avc, cpl
danmo dmorissette at mapgears.com
hobu Howard Butler swig/python, sde
hobu.inc at gmail.com
kdejong Kor de Jong pcraster
k.dejong at geo.uu.nl
rblazek Radim Blazek grass drivers
radim.blazek at gmail.com
osemykin Oleg Semykin postgis, informix
oss-dev at rambler.ru
sperkins Simon Perkins fits, windows builds.
sy at perkins.net
kmelero Ken Melero mrsid
kmelero at sanz.com
ajolma Ari Jolma perl bindings
ari.jolma at gmail.com
shalasz Steve Halasz DebianGIS Packaging
debian at adkgis.org
mloskot Mateusz Loskot wince, geojson
mateusz at loskot.net
mbrudka Marek Brudka thread safety
mbrudka at aster.pl
jlacroix Julien-Samuel Lacroix mitab, avc
jlacroix at mapgears.com
dnadeau Denis Nadeau netcdf, hdf, opendap
denis.nadeau@gmail.com
cfis Charles F. I. Savage ruby
cfis at savagexi.com
lichun Lichun Wang ilwis
lichun at itc.nl
dron Andrey Kiselev HDF, geotiff, informix, core
dron at ak4719.spb.edu
dreamil Swapnil Harjare
dreamil at gmail.com
mchapman Martin Chapman mysql, postgres, etc
mchapman at sanz.com
hannah Hannah Valbonesi hdf, png, gif, geotiff
Hannah.Valvonesi at safe.com
gaopeng Gao Peng
pgao at esri.com
aaime Andrea Aime swig java bindings
aaime at openplans.org
pka Pirmin Kalberer interlis
pka at sourcepole.ch
kosta Dr. Konstantin Baumann MySQL, SQLite
Konstantin.Baumann at hpi.uni-potsdam.de
rayg Ray Gardener DEM drivers, leveller, terragen
rayg@daylongraphics.com
rouault Even Rouault all
even.rouault at spatialys.com
retsios Bas Retsios ILWIS, GRIB
retsios at itc.nl
condit Chris Condit Python, KML
condit at sdsc.edu
klokan Petr Pridal gdal2tiles
klokan at klokan.cz
pvachon Phil Vachon jaxapalsar, radar in general.
philippe at cowpig.ca
moratto Stefano Moratto delphi bindings, OGR: shp
stefano.moratto@gmail.com
dgrichard Didier Richard geoconcept, coordinate systems.
didier.richard@ign.fr
chaitanya Chaitanya Kumar CH
chaitanya.ch at gmail.com
rprinceley Robin Princeley ESRI branches.
rprinceley at esri.com
jorgearevalo Jorge Arevalo PostGIS Raster driver.
jorgearevalo at libregis.org
martinl Martin Landa OGR: VFK and GRASS drivers
landa.martin at gmail.com
gaige Gaige B Paulsen
osgeo at gbp.gaige.net
kyle Kyle Shannon netcdf, lcp
kyle at pobox.com
winkey Brian Case libkml
rush at winkey.org
nowakpl Adam Nowacki wms
nowak at xpam.de
harshgovind Harsh Govind kmlsuperoverlay, sde
harsh.govind at spadac.com
aboudreault Alan Boudreault
aboudreault at mapgears.com mitab, DebianGIS Packaging
rburhum Ragi Yaser Burhum OGR: ArcObjects, filegdb
ragi at burhum.com
kirk Kirk McKelvey mrsid, raster
kmckelvey@lizardtech.com
antonio Antonio Valentino SAR formats
antonio.valentino@tiscali.it
pramsey Paul Ramsey OGR: FGDB, PostGIS
pramsey@cleverelephant.ca
etourigny Etienne Tourigny netcdf, hdf
etourigny.dev at gmail dot com
(old osgeo id etiennesky)
bishop Dmitry Baryshnikov postgis, hdf, geotiff, mitab, shp
polimax at mail.ru
rcoup Robert Coup OGR: FGDB
robert@coup.net.nz
dzwarg David Zwarg PostGIS Raster
dzwarg@azavea.com
wolf Wolf Bergenheim GME, vector, python
wolf+grass@bergenheim.net
goatbar Kurt Schwehr ocean related drivers, python
schwehr@google.com
jef Juergen Fischer OGR: NAS
jef@norbit.de
vmo Vincent Mora wasp
vincent.mora@oslandia.com
jratike80 Jukka Rahkonen documentation
jukka.rahkonen@latuviitta.fi
dadler David Adler DB2
dadler@adtechgeospatial.com
lplesea Lucian Plesea mrf, wms
lplesea@esri.com
atlight Alan Thomas DXF
athomas@thinkspatial.com.au
===================
Past CVS developers
===================
CVS Login(s) Name Email / Contact Project
============ ==== =============== =======
gwalter Gillian Walter gillian.walter at vexcel.com gdal
bfreisen Bob Friesenhahn bfriesen at simple.dallas.tx.us libtiff
andrea Alessandro Amici alexamici at tiscali.it gdal
dgilbert Dave Gilbert dgilbert at dclg.ca libjpeg
nhv Norman Vine nhv at cape.com gdal
kruland Kevin Ruland kruland at ku.edu gdal
fvdbergh Frans van der Bergh fvdbergh at csir.co.za gdal
dwallner Daniel Wallner daniel.wallner at bredband.net gdal
pnagy Peter Nagy peter.nagy at vexcel.com gdal
joris Joris Van Damme joris.at.lebbeke at skynet.be libtiff
kintel Marius Kintel kintel at sim.no dgnlib
nbrodin Nacho Brodin brodin_ign at gva.es gdal
collinsb Benjamin Collins collinsb at mitre.org gdal
marit Marit Jentoft-Nilson jentoft-nilsen at agnes.gsfc.nasa.gov geotiff
vgough Valient Gough vgough at remotesensing.org

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,204 @@
<doxygenlayout version="1.0">
<!-- Generated by doxygen 1.8.12 -->
<!-- Navigation index tabs for HTML output -->
<!-- see "Changing the layout of pages" at http://www.stack.nl/~dimitri/doxygen/manual/customize.html -->
<navindex>
<tab type="mainpage" visible="yes" title=""/>
<tab type="pages" visible="yes" title="" intro=""/>
<tab type="modules" visible="yes" title="" intro=""/>
<tab type="namespaces" visible="yes" title="">
<tab type="namespacelist" visible="yes" title="" intro=""/>
<tab type="namespacemembers" visible="yes" title="" intro=""/>
</tab>
<tab type="classes" visible="yes" title="">
<tab type="classlist" visible="yes" title="" intro=""/>
<tab type="classindex" visible="$ALPHABETICAL_INDEX" title=""/>
<tab type="hierarchy" visible="yes" title="" intro=""/>
<tab type="classmembers" visible="yes" title="" intro=""/>
</tab>
<tab type="files" visible="yes" title="">
<tab type="filelist" visible="yes" title="" intro=""/>
<tab type="globals" visible="yes" title="" intro=""/>
</tab>
<tab type="examples" visible="yes" title="" intro=""/>
<!-- beginning GDAL customization -->
<tab type="usergroup" title="Download">
<tab type="user" url="http://trac.osgeo.org/gdal/wiki/DownloadSource" title="Source"/>
<tab type="user" url="http://trac.osgeo.org/gdal/wiki/DownloadingGdalBinaries" title="Binaries"/>
</tab>
<tab type="user" url="https://github.com/OSGeo/gdal/issues/" title="Issue Tracker"/>
<!-- end GDAL customization -->
</navindex>
<!-- Layout definition for a class page -->
<class>
<briefdescription visible="yes"/>
<includes visible="$SHOW_INCLUDE_FILES"/>
<inheritancegraph visible="$CLASS_GRAPH"/>
<collaborationgraph visible="$COLLABORATION_GRAPH"/>
<memberdecl>
<nestedclasses visible="yes" title=""/>
<publictypes title=""/>
<services title=""/>
<interfaces title=""/>
<publicslots title=""/>
<signals title=""/>
<publicmethods title=""/>
<publicstaticmethods title=""/>
<publicattributes title=""/>
<publicstaticattributes title=""/>
<protectedtypes title=""/>
<protectedslots title=""/>
<protectedmethods title=""/>
<protectedstaticmethods title=""/>
<protectedattributes title=""/>
<protectedstaticattributes title=""/>
<packagetypes title=""/>
<packagemethods title=""/>
<packagestaticmethods title=""/>
<packageattributes title=""/>
<packagestaticattributes title=""/>
<properties title=""/>
<events title=""/>
<privatetypes title=""/>
<privateslots title=""/>
<privatemethods title=""/>
<privatestaticmethods title=""/>
<privateattributes title=""/>
<privatestaticattributes title=""/>
<friends title=""/>
<related title="" subtitle=""/>
<membergroups visible="yes"/>
</memberdecl>
<detaileddescription title=""/>
<memberdef>
<inlineclasses title=""/>
<typedefs title=""/>
<enums title=""/>
<services title=""/>
<interfaces title=""/>
<constructors title=""/>
<functions title=""/>
<related title=""/>
<variables title=""/>
<properties title=""/>
<events title=""/>
</memberdef>
<allmemberslink visible="yes"/>
<usedfiles visible="$SHOW_USED_FILES"/>
<authorsection visible="yes"/>
</class>
<!-- Layout definition for a namespace page -->
<namespace>
<briefdescription visible="yes"/>
<memberdecl>
<nestednamespaces visible="yes" title=""/>
<constantgroups visible="yes" title=""/>
<classes visible="yes" title=""/>
<typedefs title=""/>
<enums title=""/>
<functions title=""/>
<variables title=""/>
<membergroups visible="yes"/>
</memberdecl>
<detaileddescription title=""/>
<memberdef>
<inlineclasses title=""/>
<typedefs title=""/>
<enums title=""/>
<functions title=""/>
<variables title=""/>
</memberdef>
<authorsection visible="yes"/>
</namespace>
<!-- Layout definition for a file page -->
<file>
<briefdescription visible="yes"/>
<includes visible="$SHOW_INCLUDE_FILES"/>
<includegraph visible="$INCLUDE_GRAPH"/>
<includedbygraph visible="$INCLUDED_BY_GRAPH"/>
<sourcelink visible="yes"/>
<memberdecl>
<classes visible="yes" title=""/>
<namespaces visible="yes" title=""/>
<constantgroups visible="yes" title=""/>
<defines title=""/>
<typedefs title=""/>
<enums title=""/>
<functions title=""/>
<variables title=""/>
<membergroups visible="yes"/>
</memberdecl>
<detaileddescription title=""/>
<memberdef>
<inlineclasses title=""/>
<defines title=""/>
<typedefs title=""/>
<enums title=""/>
<functions title=""/>
<variables title=""/>
</memberdef>
<authorsection/>
</file>
<!-- Layout definition for a group page -->
<group>
<briefdescription visible="yes"/>
<groupgraph visible="$GROUP_GRAPHS"/>
<memberdecl>
<nestedgroups visible="yes" title=""/>
<dirs visible="yes" title=""/>
<files visible="yes" title=""/>
<namespaces visible="yes" title=""/>
<classes visible="yes" title=""/>
<defines title=""/>
<typedefs title=""/>
<enums title=""/>
<enumvalues title=""/>
<functions title=""/>
<variables title=""/>
<signals title=""/>
<publicslots title=""/>
<protectedslots title=""/>
<privateslots title=""/>
<events title=""/>
<properties title=""/>
<friends title=""/>
<membergroups visible="yes"/>
</memberdecl>
<detaileddescription title=""/>
<memberdef>
<pagedocs/>
<inlineclasses title=""/>
<defines title=""/>
<typedefs title=""/>
<enums title=""/>
<enumvalues title=""/>
<functions title=""/>
<variables title=""/>
<signals title=""/>
<publicslots title=""/>
<protectedslots title=""/>
<privateslots title=""/>
<events title=""/>
<properties title=""/>
<friends title=""/>
</memberdef>
<authorsection visible="yes"/>
</group>
<!-- Layout definition for a directory page -->
<directory>
<briefdescription visible="yes"/>
<directorygraph visible="yes"/>
<memberdecl>
<dirs visible="yes"/>
<files visible="yes"/>
</memberdecl>
<detaileddescription title=""/>
</directory>
</doxygenlayout>

View File

@@ -0,0 +1,690 @@
# -*- Makefile -*- for emacs.
GDAL_ROOT = /home/ivan/ivan/git/work_drivecast2/ue_slam/cv_networking_pipeline_linux/thirdparty/oscpack_1_1_0/bin/gdal-2.4.0
top_builddir = $(GDAL_ROOT)
#
# the library can be built by the native build or with the help of libtool
#
SHELL = /bin/bash
HAVE_LIBTOOL = yes
LIBTOOL = $(SHELL) $(top_builddir)/libtool
ifeq ($(HAVE_LIBTOOL),yes)
LIBTOOL_COMPILE_CC = $(LIBTOOL) --mode=compile --silent --tag=CC
LIBTOOL_COMPILE_CXX = $(LIBTOOL) --mode=compile --silent --tag=CXX
LIBTOOL_LINK = $(LIBTOOL) --mode=link --silent
LIBTOOL_INSTALL = $(LIBTOOL) --mode=install --silent
LIBTOOL_FINISH = $(LIBTOOL) --mode=finish --silent
LIBTOOL_CLEAN = $(LIBTOOL) --mode=clean --silent
OBJ_EXT = lo
else
LIBTOOL_FINISH = /usr/bin/true
OBJ_EXT = o
endif
CC = $(LIBTOOL_COMPILE_CC) gcc
CXX = $(LIBTOOL_COMPILE_CXX) g++
LD = $(LIBTOOL_LINK) g++
RM = $(LIBTOOL_CLEAN) /bin/rm -f *.lo
INSTALL = $(LIBTOOL_INSTALL) $(GDAL_ROOT)/install-sh -c
INSTALL_LIB = $(LIBTOOL_INSTALL) $(GDAL_ROOT)/install-sh -c
INSTALL_DATA = $(GDAL_ROOT)/install-sh -c -m 0644
INSTALL_DIR = $(GDAL_ROOT)/install-sh -d
# SDE_LIB needs to be first because it embeds zlib. We need to use its symbols instead of -lz's
LIBS = $(SDE_LIB) -lcrypto -ljson-c -lfreexl -lqhull -lqhull -L/usr/lib/x86_64-linux-gnu -lgeos_c -lwebp -lsqlite3 -lodbc -lodbcinst -lkmlbase -lkmldom -lkmlengine -lkmlxsd -lkmlregionator -lexpat -lxerces-c -lpthread -lopenjp2 -L/usr/lib/x86_64-linux-gnu -L/usr/lib/x86_64-linux-gnu/hdf5/serial -lnetcdf -L/usr/lib/x86_64-linux-gnu/hdf5/serial -lhdf5 -lmfhdfalt -ldfalt -logdi -lgif -lCharLS -ljpeg -lpng -lcfitsio -L/usr/lib/x86_64-linux-gnu -lpq -lzstd -lz -lpthread -lm -lrt -ldl -lpcre $(KAK_LIBS) $(DWG_LIBS) $(CURL_LIB) \
$(MRSID_LIBS) $(MRSID_LIDAR_LIBS) $(ECW_LIBS) $(INGRES_LIB) \
$(PCIDSK_LIB) $(RASDAMAN_LIB) $(SOSI_LIB) \
$(OPENCL_LIB) $(JVM_LIB) $(LIBICONV) $(FGDB_LIB) $(LIBXML2_LIB) $(MONGODB_LIB) \
$(JNI_LIB) $(HDFS_LIB)
SSEFLAGS =
SSSE3FLAGS = -mssse3
AVXFLAGS = -mavx
PYTHON =
PY_HAVE_SETUPTOOLS=
# Next Generation SWIG bindings
BINDINGS =
HAVE_OGDI = yes
OGR_ENABLED = yes
GNM_ENABLED = yes
OSX_FRAMEWORK_PREFIX = /Library/Frameworks/GDAL.framework
OSX_VERSION_FRAMEWORK_PREFIX = ${OSX_FRAMEWORK_PREFIX}/Versions/2.4
prefix = /usr/local
exec_prefix = ${prefix}
INST_PREFIX = ${prefix}
INST_INCLUDE = ${prefix}/include
INST_DATA = ${prefix}/share/gdal
INST_LIB = ${exec_prefix}/lib
INST_BIN = ${exec_prefix}/bin
INST_PYMOD = @pymoddir@
INST_DOCS = ${prefix}/doc
INST_MAN = ${prefix}/man
INST_HTML = $(HOME)/www/gdal
CPPFLAGS := -I$(GDAL_ROOT)/port -I/usr/include/openjpeg-2.3 -I/usr/include -DGDAL_COMPILATION
CFLAGS = -DHAVE_AVX_AT_COMPILE_TIME -DHAVE_SSSE3_AT_COMPILE_TIME -DHAVE_SSE_AT_COMPILE_TIME -g -O2 -Wall -Wdeclaration-after-statement -Wextra -Winit-self -Wunused-parameter -Wmissing-prototypes -Wmissing-declarations -Wformat -Werror=format-security -Wno-format-nonliteral -Wlogical-op -Wshadow -Werror=vla -Wdeclaration-after-statement -Wdate-time -Wnull-dereference -Wduplicated-cond -Wfloat-conversion -std=gnu89 $(USER_DEFS)
CXXFLAGS = -DHAVE_AVX_AT_COMPILE_TIME -DHAVE_SSSE3_AT_COMPILE_TIME -DHAVE_SSE_AT_COMPILE_TIME -g -O2 -Wall -Wextra -Winit-self -Wunused-parameter -Wformat -Werror=format-security -Wno-format-nonliteral -Wlogical-op -Wshadow -Werror=vla -Wdate-time -Wnull-dereference -Wduplicated-cond -Wextra-semi -Wfloat-conversion -Wmissing-declarations -Wnon-virtual-dtor -Woverloaded-virtual -fno-operator-names -Wzero-as-null-pointer-constant -Wsuggest-override -Wimplicit-fallthrough $(USER_DEFS)
CFLAGS_NOFTRAPV = -g -O2 -Wall -Wdeclaration-after-statement -Wextra -Winit-self -Wunused-parameter -Wmissing-prototypes -Wmissing-declarations -Wformat -Werror=format-security -Wno-format-nonliteral -Wlogical-op -Wshadow -Werror=vla -Wdeclaration-after-statement -Wdate-time -Wnull-dereference -Wduplicated-cond -Wfloat-conversion -std=gnu89 $(USER_DEFS)
CXXFLAGS_NOFTRAPV = -g -O2 -Wall -Wextra -Winit-self -Wunused-parameter -Wformat -Werror=format-security -Wno-format-nonliteral -Wlogical-op -Wshadow -Werror=vla -Wdate-time -Wnull-dereference -Wduplicated-cond -Wextra-semi -Wfloat-conversion -Wmissing-declarations -Wnon-virtual-dtor -Woverloaded-virtual -fno-operator-names -Wzero-as-null-pointer-constant -Wsuggest-override -Wimplicit-fallthrough $(USER_DEFS)
CXXFLAGS_NO_LTO_IF_SSSE3_NONDEFAULT = -DHAVE_AVX_AT_COMPILE_TIME -DHAVE_SSSE3_AT_COMPILE_TIME -DHAVE_SSE_AT_COMPILE_TIME -g -O2 -Wall -Wextra -Winit-self -Wunused-parameter -Wformat -Werror=format-security -Wno-format-nonliteral -Wlogical-op -Wshadow -Werror=vla -Wdate-time -Wnull-dereference -Wduplicated-cond -Wextra-semi -Wfloat-conversion -Wmissing-declarations -Wnon-virtual-dtor -Woverloaded-virtual -fno-operator-names -Wzero-as-null-pointer-constant -Wsuggest-override -Wimplicit-fallthrough $(USER_DEFS)
CXXFLAGS_NO_LTO_IF_AVX_NONDEFAULT = -DHAVE_AVX_AT_COMPILE_TIME -DHAVE_SSSE3_AT_COMPILE_TIME -DHAVE_SSE_AT_COMPILE_TIME -g -O2 -Wall -Wextra -Winit-self -Wunused-parameter -Wformat -Werror=format-security -Wno-format-nonliteral -Wlogical-op -Wshadow -Werror=vla -Wdate-time -Wnull-dereference -Wduplicated-cond -Wextra-semi -Wfloat-conversion -Wmissing-declarations -Wnon-virtual-dtor -Woverloaded-virtual -fno-operator-names -Wzero-as-null-pointer-constant -Wsuggest-override -Wimplicit-fallthrough $(USER_DEFS)
NO_UNUSED_PARAMETER_FLAG = -Wno-unused-parameter
NO_SIGN_COMPARE = -Wno-sign-compare
NO_NON_VIRTUAL_DTOR_FLAG = -Wno-non-virtual-dtor
NO_LOGICAL_OP_FLAG = -Wno-logical-op
WARN_OLD_STYLE_CAST = -Wold-style-cast
WARN_EFFCPLUSPLUS = -Weffc++
# Also available -DAFL_FRIENDLY for strcmp(), etc.. variants that will
# work better with American Fuzzy Lop branch examination logic
# TODO(schwehr): Make these be configure flags.
# CFLAGS += -Werror
# CFLAGS += -std=c11
# CFLAGS += -fsanitize=address
# CFLAGS += -D_FORTIFY_SOURCE=2
# CFLAGS += -fPIE -pie
# CFLAGS += -fstack-protector-all
# CXXFLAGS += -Werror
# CXXFLAGS += -std=c++11
# CXXFLAGS += -fsanitize=address
# CXXFLAGS += -D_FORTIFY_SOURCE=2
# CXXFLAGS += -fPIE -pie
# CXXFLAGS += -fstack-protector-all
LDFLAGS =
# LDFLAGS += -fsanitize=address
RANLIB = ranlib
SO_EXT =
LD_SHARED =
EXE =
ifeq ($(notdir $(LD_SHARED)),true)
HAVE_LD_SHARED = no
else
HAVE_LD_SHARED = yes
endif
GDAL_INCLUDE = -I$(GDAL_ROOT)/port -I$(GDAL_ROOT)/gcore \
-I$(GDAL_ROOT)/alg \
-I$(GDAL_ROOT)/ogr -I$(GDAL_ROOT)/ogr/ogrsf_frmts \
-I$(GDAL_ROOT)/gnm -I$(GDAL_ROOT)/apps
# libtool targets and help variables
LIBGDAL := libgdal.la
LIBGDAL_CURRENT := 25
LIBGDAL_REVISION := 0
LIBGDAL_AGE := 5
# native build targets and variables
GDAL_VER = 2.4.0
# version info
GDAL_VERSION_MAJOR = 2
GDAL_VERSION_MINOR = 4
GDAL_VERSION_REV = 0
GDAL_LIB = $(GDAL_ROOT)/libgdal.a
GDAL_SLIB = $(GDAL_ROOT)/libgdal.$(SO_EXT)
GDAL_SLIB_LINK = -L$(GDAL_ROOT) -lgdal
#GDAL_SLIB_SONAME = -Wl,-soname,libgdal.$(SO_EXT).2
# Mac OS X Framework definition
MACOSX_FRAMEWORK =
#
# GDAL/OGR PostgreSQL support.
#
HAVE_OGR_PG = yes
HAVE_POSTGISRASTER = yes
PG_INC = -I/usr/include/postgresql -I/usr/include/postgresql/12/server
#
# INGRES
#
II_SYSTEM =
HAVE_INGRES = no
INGRES_LIB =
INGRES_INC =
#
# MySQL support.
#
HAVE_MYSQL = no
MYSQL_LIB =
MYSQL_INC =
LIBS += $(MYSQL_LIB)
#
# HDF4 Support.
#
HAVE_HDF4 = yes
HDF4_INCLUDE = -I/usr/include/hdf -I$(GDAL_ROOT)/ogr
HDF4_HAS_MAXOPENFILES = yes
ifeq ($(HDF4_HAS_MAXOPENFILES),yes)
HDF4_FLAGS=-DHDF4_HAS_MAXOPENFILES
endif
#
# HDF5 Support.
#
HAVE_HDF5 = yes
HDF5_INCLUDE = -I/usr/include/hdf5/serial
#
# KEA Support.
#
HAVE_KEA = no
KEA_INC =
KEA_LIB =
LIBS += $(KEA_LIB)
#
# NetCDF Support.
#
NETCDF_MEM = no
NETCDF_ROOT = /usr
NETCDF_HAS_NC4 = yes
NETCDF_HAS_HDF4 = no
#
# DODS Include file location
#
DODS_INC =
ifeq ($(DODS_INC),)
HAVE_DODS = no
else
HAVE_DODS = yes
endif
#
# SQLite
#
SQLITE_INC = -I/usr/include
SQLITE_HAS_COLUMN_METADATA = yes
HAVE_SQLITE = yes
HAVE_SPATIALITE = no
SPATIALITE_SONAME =
SPATIALITE_INC =
SPATIALITE_AMALGAMATION = no
SPATIALITE_412_OR_LATER =
HAVE_PCRE = yes
HAVE_RASTERLITE2 = no
RASTERLITE2_CFLAGS =
#
# JPEG2000 via Kakadu Support.
#
KAKDIR =
ifneq ($(KAKDIR),)
ifeq ($(HAVE_LIBTOOL),yes)
include $(GDAL_ROOT)/frmts/jp2kak/jp2kak.lst
KAK_LIBS = $(KAK_OBJ)
endif
endif
#
# JPEG-2000 Support via JasPer library.
#
HAVE_JASPER = no
JASPER_FLAGS =
#
# MrSID support via LizardTech's DSDK
#
MRSID_FLAGS =
MRSID_INCLUDE =
MRSID_LIBS =
#
#
# MrSID/MG4 support via LizardTech LiDAR SDK
#
MRSID_LIDAR_INCLUDE =
MRSID_LIDAR_LIBS =
#
# ECW Related
#
ECW_FLAGS =
ECW_INCLUDE =
ECW_LIBS =
#
# JP2Lura Related
#
JP2LURA_INCLUDE =
# Xerces C++ XML Parser for GML and ILI
#
HAVE_XERCES = yes
XERCES_INCLUDE = -I/usr/include -I/usr/include/xercesc
ifeq ($(HAVE_XERCES),yes)
CPPFLAGS += -DHAVE_XERCES $(XERCES_INCLUDE) $(CPPFLAGS)
endif
#
# Enable NAS format
#
HAVE_NAS = yes
#
# Expat XML Parser for KML, GPX, GeoRSS (and GML if no Xerces C++)
#
HAVE_EXPAT = yes
EXPAT_INCLUDE = -I/usr/include
#
# Google libkml for the new OGR KML driver written by Brian Case
#
HAVE_LIBKML = yes
LIBKML_INCLUDE =
#
# Oracle Spatial Support
#
HAVE_OCI = no
OCI_INCLUDE =
# GEOS Support
HAVE_GEOS = yes
GEOS_CFLAGS = -I/usr/include
# SFCGAL Support
HAVE_SFCGAL =
SFCGAL_CFLAGS =
# QHull Support
QHULL_SETTING = external
QHULL_INCLUDE_SUBDIR_IS_LIBQHULL = 1
# GRASS Support
GRASS_SETTING = no
GRASS_INCLUDE =
GRASS_GISBASE =
HAVE_GRASS = no
#
# SDE
#
HAVE_SDE = no
SDE_LIB =
SDE_INC =
#
# FileGDB
#
HAVE_FGDB = no
FGDB_LIB =
FGDB_INC =
#
# MongoDB
#
HAVE_MONGODB = no
MONGODB_LIB =
MONGODB_INC =
#
# ArcObjects
#
HAVE_ARCOBJECTS = @ARCOBJECTS_ENABLED@
ARCOBJECTS_LIB = @ARCOBJECTS_LIB@
ARCOBJECTS_INC = @ARCOBJECTS_INC@
#
# Curl
#
CURL_SETTING = yes
CURL_LIB = -lcurl
CURL_INC =
#
# libjson-c
#
LIBJSONC_SETTING = external
JSON_INCLUDE = -I/usr/include/json-c
#
# OpenCL support
#
OPENCL_LIB =
OPENCL_FLAGS =
#
# SOSI support
#
SOSI_INC =
SOSI_LIB =
HAVE_SOSI = no
#
# PCIDSK SDK
#
PCIDSK_SETTING = internal
PCIDSK_LIB =
PCIDSK_INCLUDE =
#
# Iconv
#
LIBICONV =
#
# LIBXML2
#
HAVE_LIBXML2 = yes
LIBXML2_INC = -I/usr/include/libxml2
LIBXML2_LIB = -lxml2
#
# CAD Support
#
HAVE_CAD = yes
#
# Informix DataBlade support
#
HAVE_IDB = no
IDB_INC =
IDB_LIB =
ifeq ($(HAVE_IDB),yes)
LIBS += $(IDB_LIB)
endif
#
# FMEObjects
#
ifeq (,)
HAVE_FME = no
FME_INCLUDE =
else
HAVE_FME = yes
FME_INCLUDE = -I/fmeobjects/cpp
endif
# PCRaster support
PCRASTER_SETTING = internal
#
# LERC support.
#
HAVE_LERC = yes
OGDI_INCLUDE = -I/usr/include/ogdi
PNG_SETTING = external
JPEG_SETTING = external
JPEG12_ENABLED = no
TIFF_JPEG12_ENABLED = no
TIFF_SETTING = internal
TIFF_OPTS = -DBIGTIFF_SUPPORT
RENAME_INTERNAL_LIBTIFF_SYMBOLS = no
GEOTIFF_SETTING = internal
GEOTIFF_INCLUDE =
RENAME_INTERNAL_LIBGEOTIFF_SYMBOLS = no
RENAME_INTERNAL_SHAPELIB_SYMBOLS = no
GIF_SETTING = external
FITS_SETTING = external
OGDI_SETTING = yes
ODBC_SETTING = yes
# PGeo driver is built-in when ODBC is available
PGEO_SETTING = yes
MSSQLSPATIAL_SETTING = yes
GEOMEDIA_SETTING = yes
NETCDF_SETTING = yes
LIBZ_SETTING = external
LIBLZMA_SETTING = no
WEBP_SETTING = yes
ZSTD_SETTING = yes
#
# DDS via Crunch Support.
#
CRUNCHDIR =
#
# Rasdaman stuff
#
RASDAMAN_ENABLED = no
RASDAMAN_INC =
RASDAMAN_LIB =
#
# PDF stuff
#
PDF_PLUGIN = no
#
# Poppler stuff
#
HAVE_POPPLER = no
POPPLER_HAS_OPTCONTENT = no
POPPLER_BASE_STREAM_HAS_TWO_ARGS = no
POPPLER_0_20_OR_LATER = no
POPPLER_0_23_OR_LATER = no
POPPLER_0_58_OR_LATER = no
POPPLER_0_69_OR_LATER = no
POPPLER_INC =
POPPLER_PLUGIN_LIB =
#
# Podofo stuff
#
HAVE_PODOFO = no
PODOFO_INC =
PODOFO_PLUGIN_LIB =
#
# Pdfium stuff
#
HAVE_PDFIUM = no
PDFIUM_INC =
PDFIUM_PLUGIN_LIB =
#
# CharLs stuff
#
HAVE_CHARLS = yes
CHARLS_INC = -DCHARLS_2
#
# Teigha stuff
#
HAVE_TEIGHA = no
TEIGHA_DIR =
TEIGHA_CPPFLAGS =
#
# PROJ.4 stuff
#
PROJ_STATIC = no
ifeq ($(PROJ_STATIC),yes)
PROJ_FLAGS = -DPROJ_STATIC -DPROJ_VERSION=
endif
PROJ_INCLUDE =
PAM_SETTING = -DPAM_ENABLED
GDAL_LIBS := $(GDAL_LIB) $(OCI_LIB) $(GDAL_LIBS)
ifeq ($(GNM_ENABLED),yes)
CPPFLAGS := -DGNM_ENABLED $(CPPFLAGS)
endif
#
# Java stuff
#
JAVA_HOME =
JAVA_INC =
JVM_LIB =
MDB_ENABLED = no
HAVE_ARMADILLO = no
#
# userfaultfd
#
ENABLE_UFFD = yes
#
# HDFS
#
HDFS_LIB =
HDFS_INC =
HDFS_ENABLED = no
JNI_LIB =
#
# freexl stuff
#
HAVE_FREEXL = yes
FREEXL_INCLUDE =
#
# cryptopp stuff
#
HAVE_CRYPTOPP = no
USE_ONLY_CRYPTODLL_ALG = yes
#
# crypto/openssl stuff
#
HAVE_OPENSSL_CRYPTO = yes
#
# Note these codes have to exactly match the format directory names,
# and their uppercase form should be the format portion of the
# format registration entry point. eg. gdb -> GDALRegister_GTiff().
#
GDAL_FORMATS :=
GDAL_FORMATS += gxf gtiff hfa aigrid aaigrid ceos ceos2 iso8211 xpm
GDAL_FORMATS += sdts raw dted mem jdem envisat elas fit vrt usgsdem l1b
GDAL_FORMATS += nitf bmp airsar rs2 ilwis rmf leveller sgi srtmhgt
GDAL_FORMATS += idrisi gsg ingr ers jaxapalsar dimap gff cosar pds adrg
GDAL_FORMATS += coasp tsx terragen blx msgn til r northwood saga xyz hf2
GDAL_FORMATS += kmlsuperoverlay ctg e00grid zmap ngsgeoid iris map cals
GDAL_FORMATS += safe sentinel2 derived
GDAL_FORMATS += prf
GDAL_FORMATS += sigdem
GDAL_FORMATS += ignfheightasciigrid
GDAL_FORMATS += mrf webp wcs wms plmosaic wmts rda eeda grib bsb openjpeg netcdf hdf5 hdf4 gif jpeg png pcraster fits
ifneq ($(PCIDSK_SETTING),no)
GDAL_FORMATS += pcidsk
endif
ifneq ($(LIBZ_SETTING),no)
GDAL_FORMATS := $(GDAL_FORMATS) rik ozi
ifneq ($(PDF_PLUGIN),yes)
GDAL_FORMATS := $(GDAL_FORMATS) pdf
endif
endif
ifeq ($(HAVE_SQLITE),yes)
GDAL_FORMATS := $(GDAL_FORMATS) rasterlite mbtiles
endif
ifeq ($(HAVE_POSTGISRASTER),yes)
GDAL_FORMATS := $(GDAL_FORMATS) postgisraster
endif
ifeq ($(HAVE_CHARLS),yes)
GDAL_FORMATS := $(GDAL_FORMATS) jpegls
endif
GDAL_FORMATS := $(GDAL_FORMATS) arg
#
# CONFIG_LIBS is what local program should link against, and CONFIG_LIBS_INS
# is what will be emitted into the gdal-config script that is installed
# globally.
#
ifeq ($(HAVE_LIBTOOL), yes)
CONFIG_LIBS = $(GDAL_ROOT)/$(LIBGDAL)
ifeq ($(MACOSX_FRAMEWORK),yes)
CONFIG_LIBS_INS = -L$(INST_LIB)/unix/lib -lgdal
else
CONFIG_LIBS_INS = -L$(INST_LIB) -lgdal
endif # MACOSX_FRAMEWORK
EXE_DEP_LIBS = $(GDAL_ROOT)/$(LIBGDAL)
SO_EXT = la
else # HAVE_LIBTOOL
ifeq ($(HAVE_LD_SHARED),yes)
CONFIG_LIBS = $(GDAL_SLIB_LINK) $(LIBS)
ifeq ($(MACOSX_FRAMEWORK),yes)
CONFIG_LIBS_INS = -L$(INST_LIB)/unix/lib -lgdal
else
CONFIG_LIBS_INS = -L$(INST_LIB) -lgdal
endif
EXE_DEP_LIBS = $(GDAL_SLIB)
else
CONFIG_LIBS = $(GDAL_LIBS) $(LIBS)
CONFIG_LIBS_INS = $(foreach LF,$(GDAL_LIBS),$(INST_LIB)/$(notdir $(LF)))\
$(LIBS)
EXE_DEP_LIBS = $(GDAL_LIB)
endif
endif # HAVE_LIBTOOL
#
# generic library rules
#
#
# gdal and ogr low level drivers use the following default rules in order to
# populate the ../o/ directory with all object and library object files
#
O_OBJ = $(foreach file,$(OBJ),../o/$(file))
../o/%.$(OBJ_EXT): %.c
$(CC) $(GDAL_INCLUDE) $(CFLAGS) $(CPPFLAGS) -c -o $@ $<
../o/%.$(OBJ_EXT): %.cpp
$(CXX) $(GDAL_INCLUDE) $(CXXFLAGS) $(CPPFLAGS) -c -o $@ $<
%.$(OBJ_EXT): %.c
$(CC) $(GDAL_INCLUDE) $(CFLAGS) $(CPPFLAGS) -c -o $@ $<
%.$(OBJ_EXT): %.cpp
$(CXX) $(GDAL_INCLUDE) $(CXXFLAGS) $(CPPFLAGS) -c -o $@ $<
#
# default rules for handling subdirectories
#
%-target:
$(MAKE) -C $*
%-clean:
$(MAKE) -C $* clean

View File

@@ -0,0 +1,690 @@
# -*- Makefile -*- for emacs.
GDAL_ROOT = @abs_top_builddir@
top_builddir = $(GDAL_ROOT)
#
# the library can be built by the native build or with the help of libtool
#
SHELL = @SHELL@
HAVE_LIBTOOL = @HAVE_LIBTOOL@
LIBTOOL = @LIBTOOL@
ifeq ($(HAVE_LIBTOOL),yes)
LIBTOOL_COMPILE_CC = $(LIBTOOL) --mode=compile --silent --tag=CC
LIBTOOL_COMPILE_CXX = $(LIBTOOL) --mode=compile --silent --tag=CXX
LIBTOOL_LINK = $(LIBTOOL) --mode=link --silent
LIBTOOL_INSTALL = $(LIBTOOL) --mode=install --silent
LIBTOOL_FINISH = $(LIBTOOL) --mode=finish --silent
LIBTOOL_CLEAN = $(LIBTOOL) --mode=clean --silent
OBJ_EXT = lo
else
LIBTOOL_FINISH = @BINTRUE@
OBJ_EXT = o
endif
CC = $(LIBTOOL_COMPILE_CC) @CC@
CXX = $(LIBTOOL_COMPILE_CXX) @CXX@
LD = $(LIBTOOL_LINK) @CXX@
RM = $(LIBTOOL_CLEAN) /bin/rm -f *.lo
INSTALL = $(LIBTOOL_INSTALL) $(GDAL_ROOT)/install-sh -c
INSTALL_LIB = $(LIBTOOL_INSTALL) $(GDAL_ROOT)/install-sh -c
INSTALL_DATA = $(GDAL_ROOT)/install-sh -c -m 0644
INSTALL_DIR = $(GDAL_ROOT)/install-sh -d
# SDE_LIB needs to be first because it embeds zlib. We need to use its symbols instead of -lz's
LIBS = $(SDE_LIB) @LIBS@ $(KAK_LIBS) $(DWG_LIBS) $(CURL_LIB) \
$(MRSID_LIBS) $(MRSID_LIDAR_LIBS) $(ECW_LIBS) $(INGRES_LIB) \
$(PCIDSK_LIB) $(RASDAMAN_LIB) $(SOSI_LIB) \
$(OPENCL_LIB) $(JVM_LIB) $(LIBICONV) $(FGDB_LIB) $(LIBXML2_LIB) $(MONGODB_LIB) \
$(JNI_LIB) $(HDFS_LIB)
SSEFLAGS = @SSEFLAGS@
SSSE3FLAGS = @SSSE3FLAGS@
AVXFLAGS = @AVXFLAGS@
PYTHON = @PYTHON@
PY_HAVE_SETUPTOOLS=@PY_HAVE_SETUPTOOLS@
# Next Generation SWIG bindings
BINDINGS = @BINDINGS@
HAVE_OGDI = @HAVE_OGDI@
OGR_ENABLED = yes
GNM_ENABLED = @GNM_ENABLED@
OSX_FRAMEWORK_PREFIX = /Library/Frameworks/GDAL.framework
OSX_VERSION_FRAMEWORK_PREFIX = ${OSX_FRAMEWORK_PREFIX}/Versions/@GDAL_VERSION_MAJOR@.@GDAL_VERSION_MINOR@
prefix = @prefix@
exec_prefix = @exec_prefix@
INST_PREFIX = @exec_prefix@
INST_INCLUDE = @includedir@
INST_DATA = @datadir@
INST_LIB = @libdir@
INST_BIN = @bindir@
INST_PYMOD = @pymoddir@
INST_DOCS = @exec_prefix@/doc
INST_MAN = @mandir@
INST_HTML = $(HOME)/www/gdal
CPPFLAGS := @CPPFLAGS@ -I$(GDAL_ROOT)/port @EXTRA_INCLUDES@ -DGDAL_COMPILATION
CFLAGS = @CFLAGS@ @C_WFLAGS@ $(USER_DEFS)
CXXFLAGS = @CXXFLAGS@ @CXX_WFLAGS@ $(USER_DEFS)
CFLAGS_NOFTRAPV = @CFLAGS_NOFTRAPV@ @C_WFLAGS@ $(USER_DEFS)
CXXFLAGS_NOFTRAPV = @CXXFLAGS_NOFTRAPV@ @CXX_WFLAGS@ $(USER_DEFS)
CXXFLAGS_NO_LTO_IF_SSSE3_NONDEFAULT = @CXXFLAGS_NO_LTO_IF_SSSE3_NONDEFAULT@ @CXX_WFLAGS@ $(USER_DEFS)
CXXFLAGS_NO_LTO_IF_AVX_NONDEFAULT = @CXXFLAGS_NO_LTO_IF_AVX_NONDEFAULT@ @CXX_WFLAGS@ $(USER_DEFS)
NO_UNUSED_PARAMETER_FLAG = @NO_UNUSED_PARAMETER_FLAG@
NO_SIGN_COMPARE = @NO_SIGN_COMPARE@
NO_NON_VIRTUAL_DTOR_FLAG = @NO_NON_VIRTUAL_DTOR_FLAG@
NO_LOGICAL_OP_FLAG = @NO_LOGICAL_OP_FLAG@
WARN_OLD_STYLE_CAST = @WARN_OLD_STYLE_CAST@
WARN_EFFCPLUSPLUS = @WARN_EFFCPLUSPLUS@
# Also available -DAFL_FRIENDLY for strcmp(), etc.. variants that will
# work better with American Fuzzy Lop branch examination logic
# TODO(schwehr): Make these be configure flags.
# CFLAGS += -Werror
# CFLAGS += -std=c11
# CFLAGS += -fsanitize=address
# CFLAGS += -D_FORTIFY_SOURCE=2
# CFLAGS += -fPIE -pie
# CFLAGS += -fstack-protector-all
# CXXFLAGS += -Werror
# CXXFLAGS += -std=c++11
# CXXFLAGS += -fsanitize=address
# CXXFLAGS += -D_FORTIFY_SOURCE=2
# CXXFLAGS += -fPIE -pie
# CXXFLAGS += -fstack-protector-all
LDFLAGS = @LDFLAGS@
# LDFLAGS += -fsanitize=address
RANLIB = @RANLIB@
SO_EXT = @SO_EXT@
LD_SHARED = @LD_SHARED@
EXE = @EXE_EXT@
ifeq ($(notdir $(LD_SHARED)),true)
HAVE_LD_SHARED = no
else
HAVE_LD_SHARED = yes
endif
GDAL_INCLUDE = -I$(GDAL_ROOT)/port -I$(GDAL_ROOT)/gcore \
-I$(GDAL_ROOT)/alg \
-I$(GDAL_ROOT)/ogr -I$(GDAL_ROOT)/ogr/ogrsf_frmts \
-I$(GDAL_ROOT)/gnm -I$(GDAL_ROOT)/apps
# libtool targets and help variables
LIBGDAL := libgdal.la
LIBGDAL_CURRENT := 25
LIBGDAL_REVISION := 0
LIBGDAL_AGE := 5
# native build targets and variables
GDAL_VER = @GDAL_VER@
# version info
GDAL_VERSION_MAJOR = @GDAL_VERSION_MAJOR@
GDAL_VERSION_MINOR = @GDAL_VERSION_MINOR@
GDAL_VERSION_REV = @GDAL_VERSION_REV@
GDAL_LIB = $(GDAL_ROOT)/libgdal.a
GDAL_SLIB = $(GDAL_ROOT)/libgdal.$(SO_EXT)
GDAL_SLIB_LINK = -L$(GDAL_ROOT) -lgdal
#GDAL_SLIB_SONAME = -Wl,-soname,libgdal.$(SO_EXT).@GDAL_VERSION_MAJOR@
# Mac OS X Framework definition
MACOSX_FRAMEWORK = @MACOSX_FRAMEWORK@
#
# GDAL/OGR PostgreSQL support.
#
HAVE_OGR_PG = @HAVE_PG@
HAVE_POSTGISRASTER = @HAVE_PG@
PG_INC = @PG_INC@
#
# INGRES
#
II_SYSTEM = @II_SYSTEM@
HAVE_INGRES = @HAVE_INGRES@
INGRES_LIB = @INGRES_LIB@
INGRES_INC = @INGRES_INC@
#
# MySQL support.
#
HAVE_MYSQL = @HAVE_MYSQL@
MYSQL_LIB = @MYSQL_LIB@
MYSQL_INC = @MYSQL_INC@
LIBS += $(MYSQL_LIB)
#
# HDF4 Support.
#
HAVE_HDF4 = @HAVE_HDF4@
HDF4_INCLUDE = @HDF4_INCLUDE@ -I$(GDAL_ROOT)/ogr
HDF4_HAS_MAXOPENFILES = @HDF4_HAS_MAXOPENFILES@
ifeq ($(HDF4_HAS_MAXOPENFILES),yes)
HDF4_FLAGS=-DHDF4_HAS_MAXOPENFILES
endif
#
# HDF5 Support.
#
HAVE_HDF5 = @HAVE_HDF5@
HDF5_INCLUDE = @HDF5_INCLUDE@
#
# KEA Support.
#
HAVE_KEA = @HAVE_KEA@
KEA_INC = @KEA_INC@
KEA_LIB = @KEA_LIB@
LIBS += $(KEA_LIB)
#
# NetCDF Support.
#
NETCDF_MEM = @NETCDF_MEM@
NETCDF_ROOT = @NETCDF_ROOT@
NETCDF_HAS_NC4 = @NETCDF_HAS_NC4@
NETCDF_HAS_HDF4 = @NETCDF_HAS_HDF4@
#
# DODS Include file location
#
DODS_INC = @DODS_INC@
ifeq ($(DODS_INC),)
HAVE_DODS = no
else
HAVE_DODS = yes
endif
#
# SQLite
#
SQLITE_INC = @SQLITE_INC@
SQLITE_HAS_COLUMN_METADATA = @SQLITE_HAS_COLUMN_METADATA@
HAVE_SQLITE = @HAVE_SQLITE@
HAVE_SPATIALITE = @HAVE_SPATIALITE@
SPATIALITE_SONAME = @SPATIALITE_SONAME@
SPATIALITE_INC = @SPATIALITE_INC@
SPATIALITE_AMALGAMATION = @SPATIALITE_AMALGAMATION@
SPATIALITE_412_OR_LATER = @SPATIALITE_412_OR_LATER@
HAVE_PCRE = @HAVE_PCRE@
HAVE_RASTERLITE2 = @HAVE_RASTERLITE2@
RASTERLITE2_CFLAGS = @RASTERLITE2_CFLAGS@
#
# JPEG2000 via Kakadu Support.
#
KAKDIR = @KAKDIR@
ifneq ($(KAKDIR),)
ifeq ($(HAVE_LIBTOOL),yes)
include $(GDAL_ROOT)/frmts/jp2kak/jp2kak.lst
KAK_LIBS = $(KAK_OBJ)
endif
endif
#
# JPEG-2000 Support via JasPer library.
#
HAVE_JASPER = @HAVE_JASPER@
JASPER_FLAGS = @JASPER_FLAGS@
#
# MrSID support via LizardTech's DSDK
#
MRSID_FLAGS = @MRSID_FLAGS@
MRSID_INCLUDE = @MRSID_INCLUDE@
MRSID_LIBS = @MRSID_LIBS@
#
#
# MrSID/MG4 support via LizardTech LiDAR SDK
#
MRSID_LIDAR_INCLUDE = @MRSID_LIDAR_INCLUDE@
MRSID_LIDAR_LIBS = @MRSID_LIDAR_LIBS@
#
# ECW Related
#
ECW_FLAGS = @ECW_FLAGS@
ECW_INCLUDE = @ECW_INCLUDE@
ECW_LIBS = @ECW_LIBS@
#
# JP2Lura Related
#
JP2LURA_INCLUDE = @JP2LURA_INCLUDE@
# Xerces C++ XML Parser for GML and ILI
#
HAVE_XERCES = @HAVE_XERCES@
XERCES_INCLUDE = @XERCES_INCLUDE@
ifeq ($(HAVE_XERCES),yes)
CPPFLAGS += -DHAVE_XERCES $(XERCES_INCLUDE) $(CPPFLAGS)
endif
#
# Enable NAS format
#
HAVE_NAS = @HAVE_NAS@
#
# Expat XML Parser for KML, GPX, GeoRSS (and GML if no Xerces C++)
#
HAVE_EXPAT = @HAVE_EXPAT@
EXPAT_INCLUDE = @EXPAT_INCLUDE@
#
# Google libkml for the new OGR KML driver written by Brian Case
#
HAVE_LIBKML = @HAVE_LIBKML@
LIBKML_INCLUDE = @LIBKML_INCLUDE@
#
# Oracle Spatial Support
#
HAVE_OCI = @HAVE_OCI@
OCI_INCLUDE = @OCI_INCLUDE@
# GEOS Support
HAVE_GEOS = @HAVE_GEOS@
GEOS_CFLAGS = @GEOS_CFLAGS@
# SFCGAL Support
HAVE_SFCGAL = @HAVE_SFCGAL@
SFCGAL_CFLAGS = @SFCGAL_CFLAGS@
# QHull Support
QHULL_SETTING = @QHULL_SETTING@
QHULL_INCLUDE_SUBDIR_IS_LIBQHULL = @QHULL_INCLUDE_SUBDIR_IS_LIBQHULL@
# GRASS Support
GRASS_SETTING = @GRASS_SETTING@
GRASS_INCLUDE = @GRASS_INCLUDE@
GRASS_GISBASE = @GRASS_GISBASE@
HAVE_GRASS = @HAVE_GRASS@
#
# SDE
#
HAVE_SDE = @SDE_ENABLED@
SDE_LIB = @SDE_LIB@
SDE_INC = @SDE_INC@
#
# FileGDB
#
HAVE_FGDB = @FGDB_ENABLED@
FGDB_LIB = @FGDB_LIB@
FGDB_INC = @FGDB_INC@
#
# MongoDB
#
HAVE_MONGODB = @MONGODB_ENABLED@
MONGODB_LIB = @MONGODB_LIB@
MONGODB_INC = @MONGODB_INC@
#
# ArcObjects
#
HAVE_ARCOBJECTS = @ARCOBJECTS_ENABLED@
ARCOBJECTS_LIB = @ARCOBJECTS_LIB@
ARCOBJECTS_INC = @ARCOBJECTS_INC@
#
# Curl
#
CURL_SETTING = @CURL_SETTING@
CURL_LIB = @CURL_LIB@
CURL_INC = @CURL_INC@
#
# libjson-c
#
LIBJSONC_SETTING = @LIBJSONC_SETTING@
JSON_INCLUDE = @JSON_INCLUDE@
#
# OpenCL support
#
OPENCL_LIB = @OPENCL_LIB@
OPENCL_FLAGS = @OPENCL_FLAGS@
#
# SOSI support
#
SOSI_INC = @SOSI_INC@
SOSI_LIB = @SOSI_LIB@
HAVE_SOSI = @SOSI_ENABLED@
#
# PCIDSK SDK
#
PCIDSK_SETTING = @PCIDSK_SETTING@
PCIDSK_LIB = @PCIDSK_LIB@
PCIDSK_INCLUDE = @PCIDSK_INCLUDE@
#
# Iconv
#
LIBICONV = @LIBICONV@
#
# LIBXML2
#
HAVE_LIBXML2 = @HAVE_LIBXML2@
LIBXML2_INC = @LIBXML2_INC@
LIBXML2_LIB = @LIBXML2_LIB@
#
# CAD Support
#
HAVE_CAD = yes
#
# Informix DataBlade support
#
HAVE_IDB = @HAVE_IDB@
IDB_INC = @IDB_INC@
IDB_LIB = @IDB_LIB@
ifeq ($(HAVE_IDB),yes)
LIBS += $(IDB_LIB)
endif
#
# FMEObjects
#
ifeq (@X_FME_HOME@,)
HAVE_FME = no
FME_INCLUDE =
else
HAVE_FME = yes
FME_INCLUDE = -I@X_FME_HOME@/fmeobjects/cpp
endif
# PCRaster support
PCRASTER_SETTING = @PCRASTER_SETTING@
#
# LERC support.
#
HAVE_LERC = @HAVE_LERC@
OGDI_INCLUDE = @OGDI_INCLUDE@
PNG_SETTING = @PNG_SETTING@
JPEG_SETTING = @JPEG_SETTING@
JPEG12_ENABLED = @JPEG12_ENABLED@
TIFF_JPEG12_ENABLED = @TIFF_JPEG12_ENABLED@
TIFF_SETTING = @TIFF_SETTING@
TIFF_OPTS = @TIFF_OPTS@
RENAME_INTERNAL_LIBTIFF_SYMBOLS = @RENAME_INTERNAL_LIBTIFF_SYMBOLS@
GEOTIFF_SETTING = @GEOTIFF_SETTING@
GEOTIFF_INCLUDE = @GEOTIFF_INCLUDE@
RENAME_INTERNAL_LIBGEOTIFF_SYMBOLS = @RENAME_INTERNAL_LIBGEOTIFF_SYMBOLS@
RENAME_INTERNAL_SHAPELIB_SYMBOLS = @RENAME_INTERNAL_SHAPELIB_SYMBOLS@
GIF_SETTING = @GIF_SETTING@
FITS_SETTING = @FITS_SETTING@
OGDI_SETTING = @HAVE_OGDI@
ODBC_SETTING = @ODBC_SETTING@
# PGeo driver is built-in when ODBC is available
PGEO_SETTING = @ODBC_SETTING@
MSSQLSPATIAL_SETTING = @ODBC_SETTING@
GEOMEDIA_SETTING = @ODBC_SETTING@
NETCDF_SETTING = @NETCDF_SETTING@
LIBZ_SETTING = @LIBZ_SETTING@
LIBLZMA_SETTING = @LIBLZMA_SETTING@
WEBP_SETTING = @WEBP_SETTING@
ZSTD_SETTING = @ZSTD_SETTING@
#
# DDS via Crunch Support.
#
CRUNCHDIR = @CRUNCHDIR@
#
# Rasdaman stuff
#
RASDAMAN_ENABLED = @RASDAMAN_ENABLED@
RASDAMAN_INC = @RASDAMAN_INC@
RASDAMAN_LIB = @RASDAMAN_LIB@
#
# PDF stuff
#
PDF_PLUGIN = @PDF_PLUGIN@
#
# Poppler stuff
#
HAVE_POPPLER = @HAVE_POPPLER@
POPPLER_HAS_OPTCONTENT = @POPPLER_HAS_OPTCONTENT@
POPPLER_BASE_STREAM_HAS_TWO_ARGS = @POPPLER_BASE_STREAM_HAS_TWO_ARGS@
POPPLER_0_20_OR_LATER = @POPPLER_0_20_OR_LATER@
POPPLER_0_23_OR_LATER = @POPPLER_0_23_OR_LATER@
POPPLER_0_58_OR_LATER = @POPPLER_0_58_OR_LATER@
POPPLER_0_69_OR_LATER = @POPPLER_0_69_OR_LATER@
POPPLER_INC = @POPPLER_INC@
POPPLER_PLUGIN_LIB = @POPPLER_PLUGIN_LIB@
#
# Podofo stuff
#
HAVE_PODOFO = @HAVE_PODOFO@
PODOFO_INC = @PODOFO_INC@
PODOFO_PLUGIN_LIB = @PODOFO_PLUGIN_LIB@
#
# Pdfium stuff
#
HAVE_PDFIUM = @HAVE_PDFIUM@
PDFIUM_INC = @PDFIUM_INC@
PDFIUM_PLUGIN_LIB = @PDFIUM_PLUGIN_LIB@
#
# CharLs stuff
#
HAVE_CHARLS = @HAVE_CHARLS@
CHARLS_INC = @CHARLS_INC@
#
# Teigha stuff
#
HAVE_TEIGHA = @HAVE_TEIGHA@
TEIGHA_DIR = @TEIGHA_DIR@
TEIGHA_CPPFLAGS = @TEIGHA_CPPFLAGS@
#
# PROJ.4 stuff
#
PROJ_STATIC = @PROJ_STATIC@
ifeq ($(PROJ_STATIC),yes)
PROJ_FLAGS = -DPROJ_STATIC -DPROJ_VERSION=@PROJ_VERSION@
endif
PROJ_INCLUDE = @PROJ_INCLUDE@
PAM_SETTING = @PAM_SETTING@
GDAL_LIBS := $(GDAL_LIB) $(OCI_LIB) $(GDAL_LIBS)
ifeq ($(GNM_ENABLED),yes)
CPPFLAGS := -DGNM_ENABLED $(CPPFLAGS)
endif
#
# Java stuff
#
JAVA_HOME = @JAVA_HOME@
JAVA_INC = @JAVA_INC@
JVM_LIB = @JVM_LIB@
MDB_ENABLED = @MDB_ENABLED@
HAVE_ARMADILLO = @HAVE_ARMADILLO@
#
# userfaultfd
#
ENABLE_UFFD = @ENABLE_UFFD@
#
# HDFS
#
HDFS_LIB = @HDFS_LIB@
HDFS_INC = @HDFS_INC@
HDFS_ENABLED = @HDFS_ENABLED@
JNI_LIB = @JNI_LIB@
#
# freexl stuff
#
HAVE_FREEXL = @HAVE_FREEXL@
FREEXL_INCLUDE = @FREEXL_INCLUDE@
#
# cryptopp stuff
#
HAVE_CRYPTOPP = @HAVE_CRYPTOPP@
USE_ONLY_CRYPTODLL_ALG = @USE_ONLY_CRYPTODLL_ALG@
#
# crypto/openssl stuff
#
HAVE_OPENSSL_CRYPTO = @HAVE_OPENSSL_CRYPTO@
#
# Note these codes have to exactly match the format directory names,
# and their uppercase form should be the format portion of the
# format registration entry point. eg. gdb -> GDALRegister_GTiff().
#
GDAL_FORMATS :=
GDAL_FORMATS += gxf gtiff hfa aigrid aaigrid ceos ceos2 iso8211 xpm
GDAL_FORMATS += sdts raw dted mem jdem envisat elas fit vrt usgsdem l1b
GDAL_FORMATS += nitf bmp airsar rs2 ilwis rmf leveller sgi srtmhgt
GDAL_FORMATS += idrisi gsg ingr ers jaxapalsar dimap gff cosar pds adrg
GDAL_FORMATS += coasp tsx terragen blx msgn til r northwood saga xyz hf2
GDAL_FORMATS += kmlsuperoverlay ctg e00grid zmap ngsgeoid iris map cals
GDAL_FORMATS += safe sentinel2 derived
GDAL_FORMATS += prf
GDAL_FORMATS += sigdem
GDAL_FORMATS += ignfheightasciigrid
GDAL_FORMATS += @OPT_GDAL_FORMATS@
ifneq ($(PCIDSK_SETTING),no)
GDAL_FORMATS += pcidsk
endif
ifneq ($(LIBZ_SETTING),no)
GDAL_FORMATS := $(GDAL_FORMATS) rik ozi
ifneq ($(PDF_PLUGIN),yes)
GDAL_FORMATS := $(GDAL_FORMATS) pdf
endif
endif
ifeq ($(HAVE_SQLITE),yes)
GDAL_FORMATS := $(GDAL_FORMATS) rasterlite mbtiles
endif
ifeq ($(HAVE_POSTGISRASTER),yes)
GDAL_FORMATS := $(GDAL_FORMATS) postgisraster
endif
ifeq ($(HAVE_CHARLS),yes)
GDAL_FORMATS := $(GDAL_FORMATS) jpegls
endif
GDAL_FORMATS := $(GDAL_FORMATS) arg
#
# CONFIG_LIBS is what local program should link against, and CONFIG_LIBS_INS
# is what will be emitted into the gdal-config script that is installed
# globally.
#
ifeq ($(HAVE_LIBTOOL), yes)
CONFIG_LIBS = $(GDAL_ROOT)/$(LIBGDAL)
ifeq ($(MACOSX_FRAMEWORK),yes)
CONFIG_LIBS_INS = -L$(INST_LIB)/unix/lib -lgdal
else
CONFIG_LIBS_INS = -L$(INST_LIB) -lgdal
endif # MACOSX_FRAMEWORK
EXE_DEP_LIBS = $(GDAL_ROOT)/$(LIBGDAL)
SO_EXT = la
else # HAVE_LIBTOOL
ifeq ($(HAVE_LD_SHARED),yes)
CONFIG_LIBS = $(GDAL_SLIB_LINK) $(LIBS)
ifeq ($(MACOSX_FRAMEWORK),yes)
CONFIG_LIBS_INS = -L$(INST_LIB)/unix/lib -lgdal
else
CONFIG_LIBS_INS = -L$(INST_LIB) -lgdal
endif
EXE_DEP_LIBS = $(GDAL_SLIB)
else
CONFIG_LIBS = $(GDAL_LIBS) $(LIBS)
CONFIG_LIBS_INS = $(foreach LF,$(GDAL_LIBS),$(INST_LIB)/$(notdir $(LF)))\
$(LIBS)
EXE_DEP_LIBS = $(GDAL_LIB)
endif
endif # HAVE_LIBTOOL
#
# generic library rules
#
#
# gdal and ogr low level drivers use the following default rules in order to
# populate the ../o/ directory with all object and library object files
#
O_OBJ = $(foreach file,$(OBJ),../o/$(file))
../o/%.$(OBJ_EXT): %.c
$(CC) $(GDAL_INCLUDE) $(CFLAGS) $(CPPFLAGS) -c -o $@ $<
../o/%.$(OBJ_EXT): %.cpp
$(CXX) $(GDAL_INCLUDE) $(CXXFLAGS) $(CPPFLAGS) -c -o $@ $<
%.$(OBJ_EXT): %.c
$(CC) $(GDAL_INCLUDE) $(CFLAGS) $(CPPFLAGS) -c -o $@ $<
%.$(OBJ_EXT): %.cpp
$(CXX) $(GDAL_INCLUDE) $(CXXFLAGS) $(CPPFLAGS) -c -o $@ $<
#
# default rules for handling subdirectories
#
%-target:
$(MAKE) -C $*
%-clean:
$(MAKE) -C $* clean

View File

@@ -0,0 +1,320 @@
include GDALmake.opt
GDAL_OBJ = $(GDAL_ROOT)/frmts/o/*.o \
$(GDAL_ROOT)/gcore/*.o \
$(GDAL_ROOT)/port/*.o \
$(GDAL_ROOT)/alg/*.o \
$(GDAL_ROOT)/third_party/o/*.o \
$(GDAL_ROOT)/apps/commonutils.o \
$(GDAL_ROOT)/apps/gdalinfo_lib.o \
$(GDAL_ROOT)/apps/gdal_translate_lib.o \
$(GDAL_ROOT)/apps/gdalwarp_lib.o \
$(GDAL_ROOT)/apps/ogr2ogr_lib.o \
$(GDAL_ROOT)/apps/gdaldem_lib.o \
$(GDAL_ROOT)/apps/nearblack_lib.o \
$(GDAL_ROOT)/apps/gdal_grid_lib.o \
$(GDAL_ROOT)/apps/gdal_rasterize_lib.o \
$(GDAL_ROOT)/apps/gdalbuildvrt_lib.o
GDAL_OBJ += $(GDAL_ROOT)/ogr/ogrsf_frmts/o/*.o
ifeq ($(GNM_ENABLED),yes)
GDAL_OBJ += $(GDAL_ROOT)/gnm/*.o $(GDAL_ROOT)/gnm/gnm_frmts/o/*.o
endif
include ./ogr/file.lst
GDAL_OBJ += $(addprefix ./ogr/,$(OBJ))
LIBGDAL-yes := $(GDAL_LIB)
LIBGDAL-$(HAVE_LD_SHARED) += $(GDAL_SLIB)
# override if we are using libtool
LIBGDAL-$(HAVE_LIBTOOL) := $(LIBGDAL)
default: lib-target apps-target swig-target gdal.pc
ifeq ($(PDF_PLUGIN),yes)
(cd frmts/pdf; $(MAKE) plugin)
endif
lib-target: check-lib;
force-lib:
$(AR) r $(GDAL_LIB) $(GDAL_OBJ)
$(RANLIB) $(GDAL_LIB)
$(LD_SHARED) $(GDAL_SLIB_SONAME) $(GDAL_OBJ) $(GDAL_LIBS) $(LDFLAGS) $(LIBS) \
-o $(GDAL_SLIB)
static-lib: lib-dependencies GDALmake.opt
$(MAKE) static-lib-stage2
static-lib-stage2: $(GDAL_OBJ)
rm -f libgdal.a
$(AR) r $(GDAL_LIB) $(GDAL_OBJ)
$(GDAL_LIB): $(GDAL_OBJ) GDALmake.opt
rm -f libgdal.a
$(AR) r $(GDAL_LIB) $(GDAL_OBJ)
$(RANLIB) $(GDAL_LIB)
$(GDAL_SLIB): $(GDAL_OBJ) $(GDAL_LIB)
$(LD_SHARED) $(GDAL_SLIB_SONAME) $(GDAL_OBJ) $(GDAL_LIBS) $(LDFLAGS) $(LIBS) \
-o $(GDAL_SLIB)
$(LIBGDAL): $(GDAL_OBJ:.o=.lo)
$(LD) $(LDFLAGS) $(LIBS) -o $@ $(sort $(wildcard $(GDAL_OBJ:.o=.lo))) \
-rpath $(INST_LIB) \
-no-undefined \
-version-info $(LIBGDAL_CURRENT):$(LIBGDAL_REVISION):$(LIBGDAL_AGE)
ifeq ($(MACOSX_FRAMEWORK),yes)
install_name_tool -id ${OSX_VERSION_FRAMEWORK_PREFIX}/GDAL .libs/libgdal.dylib
endif
lib-dependencies: port-target core-target frmts-target third-party-target ogr-target gnm-target appslib-target
check-lib: lib-dependencies
$(MAKE) $(LIBGDAL-yes)
generate_gdal_version_h:
(cd gcore; $(MAKE) generate_gdal_version_h)
appslib-target: generate_gdal_version_h
(cd apps; $(MAKE) appslib)
port-target:
(cd port; $(MAKE))
ogr-target: generate_gdal_version_h
(cd ogr; $(MAKE) lib )
ifeq ($(GNM_ENABLED),yes)
gnm-target: generate_gdal_version_h
(cd gnm; $(MAKE) lib )
else
gnm-target: ;
endif
core-target: generate_gdal_version_h
(cd gcore; $(MAKE))
(cd alg; $(MAKE))
frmts-target: generate_gdal_version_h
(cd frmts; $(MAKE))
third-party-target: generate_gdal_version_h
(cd third_party; $(MAKE))
ogr-all: generate_gdal_version_h
(cd ogr; $(MAKE) all)
apps-target: lib-target
(cd apps; $(MAKE))
ifeq ($(BINDINGS),)
swig-target: ;
else
swig-target: swig-modules;
endif
# Python bindings needs gdal-config, hence apps-target
swig-modules: apps-target
(cd swig; $(MAKE) build)
clean: lclean
(cd port; $(MAKE) clean)
(cd ogr; $(MAKE) clean)
(cd gnm; $(MAKE) clean)
(cd gcore; $(MAKE) clean)
(cd frmts; $(MAKE) clean)
(cd third_party; $(MAKE) clean)
(cd alg; $(MAKE) clean)
(cd apps; $(MAKE) clean)
ifneq ($(BINDINGS),)
(cd swig; $(MAKE) clean)
endif
ifeq ($(PDF_PLUGIN),yes)
(cd frmts/pdf; $(MAKE) clean)
endif
lclean:
rm -f *.a *.so config.log config.cache html/*.*
$(RM) *.la
distclean: dist-clean
dist-clean: clean
rm -f GDALmake.opt port/cpl_config.h config.cache config.status
rm -f libtool
rm -rf autom4te.cache
config: configure
./configure
GDALmake.opt: GDALmake.opt.in config.status
./config.status
config.status: configure
./config.status --recheck
docs:
(cd html; rm -f *.*)
# Generate translated docs. Should go first, because index.html page should
# be overwritten with the main one later
doxygen -w html html/header.html html/footer.html html/stylesheet.css
sed -e 's,iso-8859-1,utf-8,g' html/header.html > html/header_ru.html
cp html/header.html html/header_br.html
(cd doc/ru ; doxygen ; cp html/*.* ../../html/. )
(cd doc/br ; doxygen ; cp html/*.* ../../html/. )
# Generate HTML docs
# Current DoxygenLayout.xml works only with Doxygen >= 1.8
@if [ `doxygen --version | awk -F . '{print $$1}'` -eq "1" ] && [ `doxygen --version | awk -F . '{print $$2}'` -lt "8" ]; then \
echo "Using deprecated doxygen version. Removing custom layout"; \
(cat Doxyfile; echo "LAYOUT_FILE=/dev/null") | doxygen -; \
else \
doxygen Doxyfile; \
fi
cp data/gdalicon.png html
cp doc/images/*.* html
cp doc/grid/*.png html
cp frmts/*.html frmts/*/frmt_*.html frmts/*/drv_*.html html
cp frmts/openjpeg/*.xml html
cp frmts/wms/frmt_*.xml html
cp ogr/ogrsf_frmts/*/frmt_*.html html
cp ogr/ogrsf_frmts/*/drv_*.html html
cp ogr/ogrsf_frmts/ogr_formats.html html
cp ogr/*.html html
cp ogr/ogrsf_frmts/gpkg/geopackage_aspatial.html html
cp ogr/*.gif html
cp ogr/*.png html
.PHONY: man
man:
# Generate man pages
(cat Doxyfile ; echo "ENABLED_SECTIONS=man"; echo "INPUT=apps swig/python/scripts"; echo "FILE_PATTERNS=*.cpp *.dox"; echo "GENERATE_HTML=NO"; echo "GENERATE_MAN=YES" ; echo "LAYOUT_FILE=/dev/null") | doxygen -
# Remove "Directory reference" file. Not sure if there's a better way of doing it.
@find man -name '_home_*_gdal_apps_.1' -exec rm {} \;
all: default ogr-all
install-docs:
$(INSTALL_DIR) $(DESTDIR)$(INST_DOCS)/gdal
cp html/*.* $(DESTDIR)$(INST_DOCS)/gdal
install-man:
$(INSTALL_DIR) $(DESTDIR)$(INST_MAN)/man1
for f in $(wildcard man/man1/*.1) ; do $(INSTALL_DATA) $$f $(DESTDIR)$(INST_MAN)/man1 ; done
web-update: docs
$(INSTALL_DIR) $(INST_HTML)
cp html/*.* $(INST_HTML)
install: install-actions
install-static-lib: static-lib gdal.pc
$(INSTALL_LIB) $(GDAL_LIB) $(DESTDIR)$(INST_LIB)
$(INSTALL_DIR) $(DESTDIR)$(INST_DATA)
$(INSTALL_DIR) $(DESTDIR)$(INST_INCLUDE)
(cd port; $(MAKE) install)
(cd gcore; $(MAKE) install)
(cd frmts; $(MAKE) install)
(cd alg; $(MAKE) install)
(cd ogr; $(MAKE) install)
(cd gnm; $(MAKE) install)
for f in LICENSE.TXT data/*.* ; do $(INSTALL_DATA) $$f $(DESTDIR)$(INST_DATA) ; done
$(LIBTOOL_FINISH) $(DESTDIR)$(INST_LIB)
$(INSTALL_DIR) $(DESTDIR)$(INST_LIB)/pkgconfig
$(INSTALL_DATA) gdal.pc $(DESTDIR)$(INST_LIB)/pkgconfig/gdal.pc
install-actions: install-lib
$(INSTALL_DIR) $(DESTDIR)$(INST_BIN)
$(INSTALL_DIR) $(DESTDIR)$(INST_DATA)
$(INSTALL_DIR) $(DESTDIR)$(INST_INCLUDE)
ifeq ($(MACOSX_FRAMEWORK),yes)
$(INSTALL_DIR) $(DESTDIR)${OSX_VERSION_FRAMEWORK_PREFIX}/PlugIns
$(INSTALL_DIR) $(DESTDIR)${OSX_VERSION_FRAMEWORK_PREFIX}/unix/lib
ln -sfh Versions/Current/unix $(DESTDIR)${OSX_FRAMEWORK_PREFIX}/unix
ln -sfh ../Programs $(DESTDIR)${OSX_VERSION_FRAMEWORK_PREFIX}/unix/bin
ln -sfh ../Headers $(DESTDIR)${OSX_VERSION_FRAMEWORK_PREFIX}/unix/include
ln -sf ../../GDAL $(DESTDIR)${OSX_VERSION_FRAMEWORK_PREFIX}/unix/lib/libgdal.dylib
ln -sfh $(GDAL_VERSION_MAJOR).$(GDAL_VERSION_MINOR) $(DESTDIR)${OSX_FRAMEWORK_PREFIX}/Versions/Current
ln -sfh Versions/Current/Headers $(DESTDIR)${OSX_FRAMEWORK_PREFIX}/Headers
ln -sfh Versions/Current/Programs $(DESTDIR)${OSX_FRAMEWORK_PREFIX}/Programs
ln -sfh Versions/Current/Resources $(DESTDIR)${OSX_FRAMEWORK_PREFIX}/Resources
ln -sfh Versions/Current/GDAL $(DESTDIR)${OSX_FRAMEWORK_PREFIX}/GDAL
endif
(cd port; $(MAKE) install)
(cd gcore; $(MAKE) install)
(cd frmts; $(MAKE) install)
(cd alg; $(MAKE) install)
(cd ogr; $(MAKE) install)
(cd gnm; $(MAKE) install)
(cd apps; $(MAKE) install)
ifneq ($(BINDINGS),)
(cd swig; $(MAKE) install)
endif
(cd scripts; $(MAKE) install)
for f in LICENSE.TXT data/*.* ; do $(INSTALL_DATA) $$f $(DESTDIR)$(INST_DATA) ; done
$(LIBTOOL_FINISH) $(DESTDIR)$(INST_LIB)
$(INSTALL_DIR) $(DESTDIR)$(INST_LIB)/pkgconfig
$(INSTALL_DATA) gdal.pc $(DESTDIR)$(INST_LIB)/pkgconfig/gdal.pc
ifeq ($(HAVE_LIBTOOL),yes)
install-lib: default
$(INSTALL_DIR) $(DESTDIR)$(INST_LIB)
for f in $(LIBGDAL-yes) ; do $(INSTALL_LIB) $$f $(DESTDIR)$(INST_LIB) ; done
ifeq ($(MACOSX_FRAMEWORK),yes)
if [ -f "$(DESTDIR)$(INST_LIB)/libgdal.$(GDAL_VERSION_MAJOR).$(LIBGDAL_AGE).$(LIBGDAL_REVISION).dylib" ] ; then mv -f $(DESTDIR)$(INST_LIB)/libgdal.$(GDAL_VERSION_MAJOR).$(LIBGDAL_AGE).$(LIBGDAL_REVISION).dylib $(DESTDIR)${OSX_VERSION_FRAMEWORK_PREFIX}/GDAL ; fi
if [ -f "$(DESTDIR)$(INST_LIB)/libgdal.$(GDAL_VERSION_MAJOR).$(LIBGDAL_AGE).dylib" ] ; then mv -f $(DESTDIR)$(INST_LIB)/libgdal.$(GDAL_VERSION_MAJOR).$(LIBGDAL_AGE).dylib $(DESTDIR)${OSX_VERSION_FRAMEWORK_PREFIX}/GDAL ; fi
if [ -f "$(DESTDIR)$(INST_LIB)/libgdal.$(GDAL_VERSION_MAJOR).dylib" ] ; then mv -f $(DESTDIR)$(INST_LIB)/libgdal.$(GDAL_VERSION_MAJOR).dylib $(DESTDIR)${OSX_VERSION_FRAMEWORK_PREFIX}/GDAL ; fi
if [ -f "$(DESTDIR)$(INST_LIB)/libgdal.dylib" ] ; then mv -f $(DESTDIR)$(INST_LIB)/libgdal.dylib $(DESTDIR)${OSX_VERSION_FRAMEWORK_PREFIX}/GDAL ; fi
rm -f $(DESTDIR)$(INST_LIB)/libgdal.$(GDAL_VERSION_MAJOR).$(LIBGDAL_AGE).$(LIBGDAL_REVISION).dylib
rm -f $(DESTDIR)$(INST_LIB)/libgdal.$(GDAL_VERSION_MAJOR).$(LIBGDAL_AGE).dylib
rm -f $(DESTDIR)$(INST_LIB)/libgdal.$(GDAL_VERSION_MAJOR).dylib
rm -f $(DESTDIR)$(INST_LIB)/libgdal.dylib
rm -f $(DESTDIR)$(INST_LIB)/libgdal.la
else
$(INSTALL_DIR) $(DESTDIR)$(INST_LIB)/gdalplugins
endif
else
ifeq ($(HAVE_LD_SHARED),yes)
GDAL_SLIB_B = $(notdir $(GDAL_SLIB))
install-lib: default
$(INSTALL_DIR) $(DESTDIR)$(INST_LIB)
ifeq ($(MACOSX_FRAMEWORK),yes)
$(INSTALL_LIB) $(GDAL_SLIB) $(DESTDIR)$(INST_LIB)/GDAL
else
rm -f $(DESTDIR)$(INST_LIB)/$(GDAL_SLIB_B)
rm -f $(DESTDIR)$(INST_LIB)/$(GDAL_SLIB_B).$(GDAL_VERSION_MAJOR)
rm -f $(DESTDIR)$(INST_LIB)/$(GDAL_SLIB_B).$(GDAL_VER)
$(INSTALL_LIB) $(GDAL_SLIB) $(DESTDIR)$(INST_LIB)/$(GDAL_SLIB_B).$(GDAL_VER)
(cd $(DESTDIR)$(INST_LIB) ; \
ln -s $(GDAL_SLIB_B).$(GDAL_VER) $(GDAL_SLIB_B).$(GDAL_VERSION_MAJOR))
(cd $(DESTDIR)$(INST_LIB) ; \
ln -s $(GDAL_SLIB_B).$(GDAL_VERSION_MAJOR) $(GDAL_SLIB_B))
$(INSTALL_DIR) $(DESTDIR)$(INST_LIB)/gdalplugins
endif
else
install-lib: default
$(INSTALL_DIR) $(DESTDIR)$(INST_LIB)
$(INSTALL_LIB) $(GDAL_LIB) $(DESTDIR)$(INST_LIB)
endif # HAVE_LD_SHARED=no
endif # HAVE_LIBTOOL=no
gdal.pc: gdal.pc.in GDALmake.opt ./GNUmakefile VERSION
rm -f gdal.pc
echo 'CONFIG_VERSION='`cat ./VERSION`'' >> gdal.pc
echo 'CONFIG_INST_PREFIX=$(INST_PREFIX)' >> gdal.pc
echo 'CONFIG_INST_LIBS=$(CONFIG_LIBS_INS)' >> gdal.pc
echo 'CONFIG_INST_CFLAGS=-I$(INST_INCLUDE)' >> gdal.pc
echo 'CONFIG_INST_DATA=$(INST_DATA)' >> gdal.pc
cat gdal.pc.in >> gdal.pc

View File

@@ -0,0 +1,274 @@
Notes on Preparing a GDAL Source Release
========================================
Prerequisites:
1) Check that the release is ready to go as far as ABI (binary compatibility)
is concerned. This can be checked by comparing the installed headers of the
candidate release with the installed headers of the previous release
(diff -ur $(OLD_INSTALL_DIR)/include $(NEW_INSTALL_DIR)/include). The API
is defined as all functions and classes exported by the CPL_DLL keyword.
- For major and minor releases, there must be no function signature change
for the C API. Only new functions are allowed.
- For major releases, the allowed changes in C++ API should (or must?) be
such that user calling C++ code can still compile against new headers
without modification (existing methods can become virtual, default
arguments can be added, new methods or members can be added)
- For minor releases (1.6.1 versus 1.6.0), the C++ ABI stability must be
preserved : no method signature change, no addition of virtual methods, no
new members. Only non-virtual methods can be added.
It may also be helpful to check:
https://abi-laboratory.pro/tracker/timeline/gdal/
2) Delete existing fix_typos directory and run scripts/fix_typos.sh
Process :
1) a) Regenerate configure using autogen.sh and commit if changed.
b) Regenerate swig generated files for python bindings and commit if changed.
There is often a reference system on which this should be done (i.e. Frank's
dev workstation) to avoid unnecessary churn from different autoconf or swig
versions.
c) "cd scripts; make completion" to regenerate scripts/gdal-bash-completion.sh
if new command line switches have been added. scripts/completionFinder.py
must also be edited before if new utilities/scripts are added/removed.
2) Update the release date, and number information in gcore/gdal_version.h.in
(*NOT* gdal_version.h which is a generated file)
Note: the format of GDAL_RELEASE_DATE should be YYYYMMDD.
3) Update the VERSION file.
3.1) Update ./swig/python/setup.py version information.
And the version of libgdal in ./swig/python/README.txt
3.2) Update ./swig/include/perl/gdal_perl.i $VERSION and $GDAL_VERSION
strings to current version. Update also $VERSION in
./swig/include/perl/ogr_perl.i to the same as the other $VERSION. Kick
Perl module maintainer to make a CPAN release.
3.3) For major releases update the VERSION macro in nmake.opt (for 1.6, 1.7etc)
4) Update LIBGDAL_CURRENT/REVISION/AGE macros in GDALmake.opt.in.
- For a release with no interface changes just bump REVISION.
- Adding interfaces, bump CURRENT/AGE, set REVISION to 0.
- Deleting interfaces / compatibility issues - bump CURRENT, others to zero.
5) Prepare release overview in the NEWS file. For example, to get all changes
from v2.2.0 to current HEAD (from gdal/ subdirectory)
git log --reverse -v v2.2.0..HEAD .
- commit new version to NEWS file.
6) Update the GDAL http://trac.osgeo.org/gdal/wiki/DownloadSource topic to
refer to the latest available source.
Update http://trac.osgeo.org/gdal/wiki (Releases section)
Update http://trac.osgeo.org/gdal/wiki/NewsAndStatus
7) If this is a major release, prepare a branch.
git checkout master
git pull origin master
git checkout -b release/2.3
git push origin release/2.3
8) Tag the release set in git:
git checkout release/2.3
git pull origin release/2.3
git tag -a -m "Create tag v2.3.0" v2.3.0
git push origin v2.3.0
9) Create the source distributions using the mkgdaldist.sh script. The
argument should be the version number (i.e. 1.4.2). As our process involves
doing betas or RCs, use the -rc option so that the filenames include this
information (after promotion to official release, filename renaming will have
to be done)
% mkgdaldist.sh 2.3.0 -tag v2.3.0 -rc RC1
For a beta version:
% mkgdaldist.sh 2.3.0beta1 -tag v2.3.0beta1
10) Create a snapshot of the documentation.
i.e. On www.gdal.org:
% cd /var/www/gdal
% ./gdal-web-refresh.sh
% zip -r ~/gdal230beta1doc.zip gdal-web --exclude "gdal-web/1.11/*" --exclude "gdal-web/daily/*"
12) Publish the resulting files in download.osgeo.org/gdal/X.Y.Z (where X.Y.Z is the version number)
and add a symlink from X.Y.Z to CURRENT (except for stable releases in a "old" branch).
% ln -sf X.Y.Z CURRENT
13) Announce release to :
- major release: gdal-dev@lists.osgeo.org, gdal-announce@lists.osgeo.org, news_item@osgeo.org.
- bugfix release: gdal-dev@lists.osgeo.org, gdal-announce@lists.osgeo.org
Note: gdal-announce@ is moderated. Make sure that your email address is approved
('mod' tick disabled in https://lists.osgeo.org/mailman/admin/gdal-announce/members),
or your message manually approved, with an administrator of the list.
14) Update the freecode.com (previously freshmeat) entry for GDAL.
15) Update the freegis.org entry for GDAL.
16) Update doc/index.dox to advertize the new release and link to the release notes
17) Create a News page in Trac for the release (like
http://trac.osgeo.org/gdal/wiki/Release/1.7.0-News) and reference it from
http://trac.osgeo.org/gdal/ (Releases) and
http://trac.osgeo.org/gdal/wiki/NewsAndStatus .
18) Add pointers to the source releases at:
http://trac.osgeo.org/gdal/wiki/DownloadSource
19) Update Trac to mark this release milestone as "Completed", and create
a corresponding version. Then create a new milestone for the next release.
20) Upload the new Python bindings to Pypi (requires upload rights to
the GDAL package by one of the current owners : HowardB/FrankW/EvenR)
( procedure taken from http://peterdowns.com/posts/first-time-with-pypi.html )
a) Install twine https://pypi.org/project/twine/
b) Create a $HOME/.pypirc file :
[distutils] # this tells distutils what package indexes you can push to
index-servers = pypi
pypitest
[pypi] # authentication details for live PyPI
repository: https://upload.pypi.org/legacy/
username: yourlogin
password: yourpassword
[pypitest] # authentication details for test PyPI
repository: https://test.pypi.org/legacy/
username: yourlogin
password: yourpassword
c) cd swig/python
d) python setup.py sdist
e) For trial :
twine upload dist/GDAL*.gz -r pypitest
f) For real :
twine upload dist/GDAL*.gz
21) Build and bundle the java bindings.
a) cd swig/java
b) Make any updates to java.opt that might be required for the platform. For
example osx and windows users will have to change JAVA_INCLUDE to contain
include/darwin and include/win32 respectively.
c) Build the bindings:
make
22) Build maven artifacts. NOTE: This step only works on Linux and OSX since it
requires a shell script to build javadocs.
A quick one-liner for this step is:
ant maven_sign -Dgpg.key=... -Dgpg.pass=...
This will build and sign the artifacts with a single command. Read on for
more details.
a) Build the maven artifacts:
ant maven
Upon success maven artifacts should be located in the build/maven directory.
b) Sign maven artifacts with GPG. This step is required in order to deploy the
maven artifacts to the central Maven repository. Before this step can
proceed you must set up a signing key as described here:
http://central.sonatype.org/pages/working-with-pgp-signatures.html
Each developer can use their own signing key although it is usually best to
avoid constantly using a different key for releases as users will need to
import the public key in order to verify the artifacts.
Here are a quick set of steps to generate a signing key key.
gpg --gen-key
gpg --list-keys (and note the key id)
gpg --keyserver hkp://pool.sks-keyservers.net --send-keys <key id>
See the above link for more details.
Once a key is set up run the "maven_sign" ant target. The target takes two
parameters specified as system properties:
1. gpg.key - The identifier for the signing key
2. gpg.pass - The passphrase for the signing key (optional)
ant maven_sign -Dgpg.key=... -Dgpg.pass=...
Upon success you should see maven artifacts along with generated signatures
in the build/maven directory. You will also find a file named "bundle.jar"
that contains all the maven artifacts with signatures. This file is what
will be uploaded to maven central. See the next step.
23) Deploy maven artifacts to Maven central.
NOTE: Before you can deploy to maven central you must set up an account
in Sonatype JIRA. That can be done here:
https://issues.sonatype.org/secure/Signup!default.jspa
Once you have an account set up you must be associated with the gdal
project. Create a ticket here asking to be associated with the project:
https://issues.sonatype.org/browse/OSSRH
The entire deployment process is described in detail here:
http://central.sonatype.org/pages/manual-staging-bundle-creation-and-deployment.html
http://central.sonatype.org/pages/releasing-the-deployment.html
The following steps summarize the process.
a) Log into the Sonatype repository manager at https://oss.sonatype.org. Use the
same credentials as your Sonatype JIRA account.
b) Once log in select "Staging Upload" on the left hand side.
c) Select "Artifact Bundle" under "Upload Mode" and then choose the "bundle.jar"
created in the previous Step 22. Finally "Upload Bundle" to start the upload.
d) When the upload has been completed you will be notified that a staging
repository has been created. Note the name of the repository. It should look
something like "orggdal-100x".
e) From the left hand menu navigate to "Staging Repositories". In the search
box look for the staging repository name you noted from the previous section.
Or just search for "gdal". It should be obvious which repository is the
current one.
f) Select the staging repository. If all is well You should see the option to
"Release" (Located as a button near the top of the page). If not it means
there was an issue with the bundle. Consult the "Activity" tab at the bottom
of the page to find out why.
e) Click the "Release" button and that is it! The release should be available in
Maven Central shortly. You can verify this by going to search.maven.org and
searching for "gdal".

View File

@@ -0,0 +1,379 @@
GDAL/OGR Licensing
==================
This file attempts to include all licenses that apply within the GDAL/OGR
source tree, in particular any that are supposed to be exposed to the end user
for credit requirements for instance. The contents of this file can be
displayed from GDAL commandline utilities using the --license commandline
switch.
GDAL/OGR General
----------------
In general GDAL/OGR is licensed under an MIT/X style license with the
following terms:
Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"),
to deal in the Software without restriction, including without limitation
the rights to use, copy, modify, merge, publish, distribute, sublicense,
and/or sell copies of the Software, and to permit persons to whom the
Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included
in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
DEALINGS IN THE SOFTWARE.
gdal/frmts/gtiff/tif_float.c
----------------------------
Copyright (c) 2002, Industrial Light & Magic, a division of Lucas
Digital Ltd. LLC
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above
copyright notice, this list of conditions and the following disclaimer
in the documentation and/or other materials provided with the
distribution.
* Neither the name of Industrial Light & Magic nor the names of
its contributors may be used to endorse or promote products derived
from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
gdal/frmts/hdf4/hdf-eos/*
------------------------
Copyright (C) 1996 Hughes and Applied Research Corporation
Permission to use, modify, and distribute this software and its documentation
for any purpose without fee is hereby granted, provided that the above
copyright notice appear in all copies and that both that copyright notice and
this permission notice appear in supporting documentation.
gdal/frmts/pcraster/libcsf
--------------------------
Copyright (c) 1997-2003, Utrecht University
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above
copyright notice, this list of conditions and the following
disclaimer in the documentation and/or other materials provided
with the distribution.
* Neither the name of Utrecht University nor the names of its contributors
may be used to endorse or promote products derived from this software
without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
gdal/frmts/grib/degrib/*
------------------------
The degrib and g2clib source code are modified versions of code produced
by NOAA NWS and are in the public domain subject to the following
restrictions:
http://www.weather.gov/im/softa.htm
DISCLAIMER The United States Government makes no warranty, expressed or
implied, as to the usefulness of the software and documentation for any
purpose. The U.S. Government, its instrumentalities, officers, employees,
and agents assumes no responsibility (1) for the use of the software and
documentation listed below, or (2) to provide technical support to users.
http://www.weather.gov/disclaimer.php
The information on government servers are in the public domain, unless
specifically annotated otherwise, and may be used freely by the public so
long as you do not 1) claim it is your own (e.g. by claiming copyright for
NWS information -- see below), 2) use it in a manner that implies an
endorsement or affiliation with NOAA/NWS, or 3) modify it in content and
then present it as official government material. You also cannot present
information of your own in a way that makes it appear to be official
government information..
The user assumes the entire risk related to its use of this data. NWS is
providing this data "as is," and NWS disclaims any and all warranties,
whether express or implied, including (without limitation) any implied
warranties of merchantability or fitness for a particular purpose. In no
event will NWS be liable to you or to any third party for any direct,
indirect, incidental, consequential, special or exemplary damages or lost
profit resulting from any use or misuse of this data.
As required by 17 U.S.C. 403, third parties producing copyrighted works
consisting predominantly of the material appearing in NWS Web pages must
provide notice with such work(s) identifying the NWS material incorporated
and stating that such material is not subject to copyright protection.
port/cpl_minizip*
-----------------
This is version 2005-Feb-10 of the Info-ZIP copyright and license.
The definitive version of this document should be available at
ftp://ftp.info-zip.org/pub/infozip/license.html indefinitely.
Copyright (c) 1990-2005 Info-ZIP. All rights reserved.
For the purposes of this copyright and license, "Info-ZIP" is defined as
the following set of individuals:
Mark Adler, John Bush, Karl Davis, Harald Denker, Jean-Michel Dubois,
Jean-loup Gailly, Hunter Goatley, Ed Gordon, Ian Gorman, Chris Herborth,
Dirk Haase, Greg Hartwig, Robert Heath, Jonathan Hudson, Paul Kienitz,
David Kirschbaum, Johnny Lee, Onno van der Linden, Igor Mandrichenko,
Steve P. Miller, Sergio Monesi, Keith Owens, George Petrov, Greg Roelofs,
Kai Uwe Rommel, Steve Salisbury, Dave Smith, Steven M. Schweda,
Christian Spieler, Cosmin Truta, Antoine Verheijen, Paul von Behren,
Rich Wales, Mike White
This software is provided "as is," without warranty of any kind, express
or implied. In no event shall Info-ZIP or its contributors be held liable
for any direct, indirect, incidental, special or consequential damages
arising out of the use of or inability to use this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. Redistributions of source code must retain the above copyright notice,
definition, disclaimer, and this list of conditions.
2. Redistributions in binary form (compiled executables) must reproduce
the above copyright notice, definition, disclaimer, and this list of
conditions in documentation and/or other materials provided with the
distribution. The sole exception to this condition is redistribution
of a standard UnZipSFX binary (including SFXWiz) as part of a
self-extracting archive; that is permitted without inclusion of this
license, as long as the normal SFX banner has not been removed from
the binary or disabled.
3. Altered versions--including, but not limited to, ports to new operating
systems, existing ports with new graphical interfaces, and dynamic,
shared, or static library versions--must be plainly marked as such
and must not be misrepresented as being the original source. Such
altered versions also must not be misrepresented as being Info-ZIP
releases--including, but not limited to, labeling of the altered
versions with the names "Info-ZIP" (or any variation thereof, including,
but not limited to, different capitalizations), "Pocket UnZip," "WiZ"
or "MacZip" without the explicit permission of Info-ZIP. Such altered
versions are further prohibited from misrepresentative use of the
Zip-Bugs or Info-ZIP e-mail addresses or of the Info-ZIP URL(s).
4. Info-ZIP retains the right to use the names "Info-ZIP," "Zip," "UnZip,"
"UnZipSFX," "WiZ," "Pocket UnZip," "Pocket Zip," and "MacZip" for its
own source and binary releases.
gdal/ogr/ogrsf_frmts/dxf/intronurbs.cpp
---------------------------------------
This code is derived from the code associated with the book "An Introduction
to NURBS" by David F. Rogers. More information on the book and the code is
available at:
http://www.nar-associates.com/nurbs/
Copyright (c) 2009, David F. Rogers
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
* Neither the name of the David F. Rogers nor the names of its contributors
may be used to endorse or promote products derived from this software
without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.
gdal/alg/thinplatespline.cpp
----------------------------
IEEE754 log() code derived from:
@(#)e_log.c 1.3 95/01/18
Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
Developed at SunSoft, a Sun Microsystems, Inc. business.
Permission to use, copy, modify, and distribute this
software is freely granted, provided that this notice
is preserved.
gdal/alg/libqhull
-----------------
Only applies when GDAL is compiled with internal qhull support
Qhull, Copyright (c) 1993-2012
C.B. Barber
Arlington, MA
and
The National Science and Technology Research Center for
Computation and Visualization of Geometric Structures
(The Geometry Center)
University of Minnesota
email: qhull@qhull.org
This software includes Qhull from C.B. Barber and The Geometry Center.
Qhull is copyrighted as noted above. Qhull is free software and may
be obtained via http from www.qhull.org. It may be freely copied, modified,
and redistributed under the following conditions:
1. All copyright notices must remain intact in all files.
2. A copy of this text file must be distributed along with any copies
of Qhull that you redistribute; this includes copies that you have
modified, or copies of programs or other software products that
include Qhull.
3. If you modify Qhull, you must include a notice giving the
name of the person performing the modification, the date of
modification, and the reason for such modification.
4. When distributing modified versions of Qhull, or other software
products that include Qhull, you must provide notice that the original
source code may be obtained as noted above.
5. There is no warranty or other guarantee of fitness for Qhull, it is
provided solely "as is". Bug reports or fixes may be sent to
qhull_bug@qhull.org; the authors may or may not act on them as
they desire.
gdal/frmts/pdf/pdfdataset.cpp (method PDFiumRenderPageBitmap())
---------------------------------------------------------------
Copyright 2014 PDFium Authors. All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above
copyright notice, this list of conditions and the following disclaimer
in the documentation and/or other materials provided with the
distribution.
* Neither the name of Google Inc. nor the names of its
contributors may be used to endorse or promote products derived from
this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
gdal/frmts/mrf/* (apply when MRF driver included in build)
---------------------------------------------------------------
Copyright (c) 2002-2012, California Institute of Technology.
All rights reserved. Based on Government Sponsored Research under contracts NAS7-1407 and/or NAS7-03001.
Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
3. Neither the name of the California Institute of Technology (Caltech), its operating division the Jet Propulsion Laboratory (JPL),
the National Aeronautics and Space Administration (NASA), nor the names of its contributors may be used to
endorse or promote products derived from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
IN NO EVENT SHALL THE CALIFORNIA INSTITUTE OF TECHNOLOGY BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
~~~~~~~~
Copyright 2014-2015 Esri
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.

View File

@@ -0,0 +1,362 @@
MIGRATION GUIDE FROM GDAL 2.3 to GDAL 2.4
-----------------------------------------
1) Out-of-tree drivers: RawRasterBand() constructor changes
RawRasterBand now only accepts a VSILFILE* file. Consequently the void* fpRaw
argument has become a VSILFILE* one. And the bIsVSIL = FALSE argument has
been removed. The int bOwnsFP = FALSE has seen its default value suppressed,
and has seen its type changed to the RawRasterBand::OwnFP::YES/NO enumeration,
to detect places where your code must be changed.
Caution: code like RawRasterBand(..., bNativeOrder, TRUE) must be changed to
RawRasterBand(..., bNativeOrder, RawRasterBand::OwnFP::NO, the TRUE value
being the bIsVSIL value, and the default argument being bOwnsFP == FALSE.
MIGRATION GUIDE FROM GDAL 2.2 to GDAL 2.3
-----------------------------------------
1) RFC 70: Guessing output format from output file name extension for utilities
Link: https://trac.osgeo.org/gdal/wiki/rfc70_output_format_guess
Before GDAL 2.3, if not specifying the output format to utilities, GeoTIFF or
Shapefile were assumed for most utilities. Now, the output format will be
guessed from the output filename extension. This might break usages where
non-standard extensions are used for GeoTIFF or Shapefile output when -f/-of is
not specified (but warnings were already emitted in such situations).
2) RFC 68: C++11 Compilation requirement
Link: https://trac.osgeo.org/gdal/wiki/rfc68_cplusplus11
GDAL now requires a C++11 compatible compiler. External code using GDAL C++ API
will also need to enable at least C++11 compilation mode, if the compiler
defaults to C++98/C++03.
3) Stricter const-ness in OGRGeomFieldDefn, OGRFeatureDefn and OGRFeature
classes, impacting out-of-tree drivers that subclass them.
The following methods are now const qualified:
OGRGeomFieldDefn class:
virtual OGRSpatialReference* GetSpatialRef() const
OGRFeatureDefn class:
virtual const char* GetName() const
virtual int GetFieldCount() const
virtual int GetFieldIndex(const char*) const
virtual int GetGeomFieldCount() const
virtual int GetGeomFieldIndex(const char*) const
virtual OGRwkbGeometryType GetGeomType() const
virtual OGRFeatureDefn* Clone() const
virtual int IsGeometryIgnored() const
virtual int IsSame(const OGRFeatureDefn*) const // argument is const now too
OGRFeature class:
virtual OGRBoolean Equal(const OGRFeature*) const // argument is const now too
virtual const char* GetStyleString() const
virtual OGRStyleTable* GetStyleTable() const
The following virtual methods, offering const alternatives to their
non-const equivalent methods, should be overloaded if the non-const
method is overloaded.
OGRFeatureDefn class:
virtual const OGRFieldDefn* GetFieldDefn(int) const
virtual const OGRGeomFieldDefn* GetGeomFieldDefn(int) const
MIGRATION GUIDE FROM GDAL 2.1 to GDAL 2.2
-----------------------------------------
A) RFC 64: Triangle, Polyhedral surface and TIN
Link: https://trac.osgeo.org/gdal/wiki/rfc64_triangle_polyhedralsurface_tin
Vector drivers can now return geometries of type wkbPolyhedralSurface, wkbTIN
and wkbTriangle; and their Z, M and ZM variants (as well as for the type of
geometry fields). Client code, as well as out-of-tree drivers that support
writing geometries, must be ready to deal with them.
B) RFC 67: Null values in OGR
Link: https://trac.osgeo.org/gdal/wiki/rfc67_nullfieldvalues
Previously, the "unset" state of a field was used both for a unset state
(ie no information for the field of the feature) or the NULL state of the
field. Now there is OGR_F_IsFieldSet() / OGRFeature::IsFieldSet() for the
unset state, and a new OGR_F_IsFieldNull() / OGRFeature::IsFieldNull() for the
new NULL state. Code that used OGR_F_IsFieldSet() / OGRFeature::IsFieldSet()
should also test the NULL state, otherwise empty strings or 0 numeric values
will be returned. A convenient way of migrating is to replace the use of
OGR_F_IsFieldSet() / OGRFeature::IsFieldSet() by OGR_F_IsFieldSetAndNotNull() /
OGRFeature::IsFieldSetAndNotNull() if there is no need to distinguish both
states.
On the writing side, a few drivers will now distinguish between the unset
and null state, namely GeoJSON, CouchDB, Cloudant, MongoDB, ElasticSearch and
GML. For example, for the GeoJSON driver, in GDAL 2.1 or before, a unset field
was written as field_name: null. Starting with GDAL 2.2, only fields explicitly
set as null with OGR_F_SetFieldNull() will be written with a null value.
Unset fields of a feature will not be present in the corresponding JSon feature
element.
MIGRATION GUIDE FROM GDAL 2.0 to GDAL 2.1
------------------------------------------
A) RFC 61: Support for measured geometries
Link: https://trac.osgeo.org/gdal/wiki/rfc61_support_for_measured_geometries
The OGRwkbGeometryType enumeration has been extended with new values for the
M and ZM variants of the geometry types. Client code may have to be upgraded
to take into account those new values. Note that the wkbPolyhedralSurface, wkbTIN
and wkbTriangle types and their Z, M and ZM variants, have also been introduced
as a provision for a potential support in a future version (they are unused in
OGR core and drivers for now).
Previously the ESRI Shapefile driver read XYM data as XYZ. Now it is read
as XYM.
MIGRATION GUIDE FROM GDAL 1.11 to GDAL 2.0
------------------------------------------
This file documents backwards incompatible changes. You are strongly encouraged
to read the relevant RFCs for details and rationale for those changes.
Changes to the Perl bindings API are listed in swig/perl/Changes-in-the-API-in-2.0.
A) RFC 46: Unification of GDAL and OGR driver models
Link: http://trac.osgeo.org/gdal/wiki/rfc46_gdal_ogr_unification
C++ API:
* OGRSFDriverRegistrar and OGRSFDriver are now deprecated. Use GDALDriverManager
and GDALDriver instead.
* The following methods from OGRSFDriverRegistrar are removed : Open(),
OpenShared(), ReleaseDataSource(), DeregisterDriver(), AutoLoadDrivers()
GetDriver() and GetDriverByName() now return a GDALDriver* instance.
* OGRDataSource::CreateLayer() specialized implementations should be renamed
as ICreateLayer() to benefit from layer creation options validation.
* OGRLayer::GetInfo() has been removed.
* All methods of OGRDataSource have been transferred to GDALDataset, except
SyncToDisk() that should now be implemented as FlushCache() in drivers.
* GDALOpenInfo::papszSiblingFiles member is now private. Use the new
GetSiblingFiles() method instead.
* GDALOpenInfo::fp member is replaced by fpL member of type VSILFILE*.
* OGRSFDriver::CopyDataSource() has been removed.
* GDALDriverManager::GetHome() and SetHome() have been removed.
Out-of-tree drivers :
* Read RFC 46 for the needed changes. Changes in GDALOpenInfo will impact GDAL
drivers. GDAL drivers should also declare SetMetadataItem( GDAL_DCAP_RASTER, "YES" ).
OGRDataSource::CreateLayer() and SyncToDisk() changes will affect OGR drivers.
Behaviour changes :
* GDALDriverManager::GetDriverCount() and GetDriver() return both raster and
vector drivers. The nature of a driver can be tested with the GDAL_DCAP_RASTER
and GDAL_DCAP_VECTOR driver metadata item.
* GetRefCount() starts at 1 for OGRDataSource instead of 0.
B) RFC 49: Curve geometries
Link: http://trac.osgeo.org/gdal/wiki/rfc49_curve_geometries
C/C++ API :
* Use of wkb25DBit macro is strongly discouraged, as not compatible with new
geometry types. Use wkbFlatten(), wkbHasZ(), wkbSetZ() instead
* OGRwkbGeometryType enumeration has new values.
Behaviour changes :
* GML, NAS, WFS, PostGIS, VRT, GeoPackage and CSV drivers can return non-linear geometries.
Applications that do not wish to get such geometries can call
OGRSetNonLinearGeometriesEnabledFlag(FALSE)
Out-of-tree drivers :
* Read RFC 49 for the needed changes. CreateFeature() and SetFeature() virtual
methods must be renamed ICreateFeature() and ISetFeature().
C) RFC 51: RasterIO() improvements : resampling and progress callback
Link: http://trac.osgeo.org/gdal/wiki/rfc51_rasterio_resampling_progress
Out-of-tree drivers :
* Read RFC 51 for the needed changes. GDALRasterBand and GDALDataset::IRasterIO()
take a new GDALRasterIOExtraArg* psExtraArg argument.
GDALRasterBand and GDALDataset::RasterIO() take a new
GDALRasterIOExtraArg* psExtraArg argument
D) RFC 31: OGR 64bit Integer Fields and FIDs
Link:http://trac.osgeo.org/gdal/wiki/rfc31_ogr_64
C++ API:
* OGRLayer::GetFeature(), OGRLayer::DeleteFeature(), OGRLayer::SetNextByIndex() take a GIntBig instead of a long
* OGRFeature::GetFID() and OGRLayer::GetFeatureCount() now returns a GIntBig
C API:
* OGR_L_GetFeature(), OGR_L_DeleteFeature(), OGR_L_SetNextByIndex() take a GIntBig instead of a long
* OGR_F_GetFID() and OGR_L_GetFeatureCount() now returns a GIntBig
Behaviour changes :
* OFTInteger64 and OFTIntegerList64 can be returned whereas OGRFieldType is returned.
Out-of-tree drivers :
* Virtual method signature change: OGRLayer::GetFeature(), OGRLayer::DeleteFeature(),
OGRLayer::SetNextByIndex() take a GIntBig argument instead of a long
* Virtual method signature change: OGRLayer::GetFeatureCount() now returns a GIntBig
* OGRFeature::GetFID() returns a GIntBig
E) RFC 52: Strict OGR SQL quoting
Link: http://trac.osgeo.org/gdal/wiki/rfc52_strict_sql_quoting
No API changes
Behaviour changes:
* Identifiers, i.e column names or table names, can no longer be quoted with
single quote characters, but must use double quote characters if quoting is
needed, conforming with SQL 92 syntax. Failure to do the change will not
necessarily need to verbose errors at runtime since an expression like
WHERE 'a_column_name' = 'a_value' will now always evaluate to FALSE whereas
it would have been interpreted as WHERE "a_column_name" = 'a_value" if
a_column_name was indeed a column name.
F) RFC 53: OGR not-null constraints and default values
Link: http://trac.osgeo.org/gdal/wiki/rfc53_ogr_notnull_default
API changes:
* OGRFieldDefn::SetDefault() now takes a const char* as argument.
OGRFieldDefn::GetDefaultRef() removed and replaced by GetDefault() that
returns a const char*
G) RFC 54: Dataset transactions
Link: http://trac.osgeo.org/gdal/wiki/rfc54_dataset_transactions
Only API additions.
Behaviour changes:
* As described in the RFC, subtle behaviour changes can be observed with the PG driver,
related to implicit transactions that were flushed before and are no longer now,
but this should hopefully be restricted to non-typical use cases. So some cases that "worked" before might
no longer work, but the new behaviour should hopefully be more understandable.
* The PG and SQLite drivers could accept apparently nested calls to StartTransaction()
(at the layer level). This is no longer possible since they are now redirected
to dataset transactions, that explicitly do not support it.
H) RFC 55: Refined SetFeature() and DeleteFeature() semantics
Link: http://trac.osgeo.org/gdal/wiki/rfc55_refined_setfeature_deletefeature_semantics
Behaviour changes:
* Drivers will now return OGRERR_NON_EXISTING_FEATURE when calling SetFeature()
or DeleteFeature() with a feature id that does not exist.
I) RFC 56:
Link: https://trac.osgeo.org/gdal/wiki/rfc56_millisecond_precision
API/ABI changes:
* OGRField.Date structure has now a Reserved field that must be set to 0 when
using the OGRFeature::SetField( int i, OGRField * puValue ) method.
The "GByte Second" field is now a "float Second".
* OGRFeature::SetField( int i, int nYear, int nMonth, int nDay,
int nHour=0, int nMinute=0, float fSecond=0.f,
int nTZFlag = 0 )
and the variant that take a const char* as first argument now accept a
floating-point number for seconds.
API additions :
* OGRFeature::GetFieldAsDateTime( int i,
int *pnYear, int *pnMonth, int *pnDay,
int *pnHour, int *pnMinute, float *pfSecond,
int *pnTZFlag );
* OGR_F_GetFieldAsDateTimeEx() and OGR_F_SetFieldDateTimeEx() are added.
Driver related changes:
* The following functions, mainly used by driver implementations, have
seen their signature change :
int CPL_DLL OGRParseXMLDateTime( const char* pszXMLDateTime,
OGRField* psField );
int CPL_DLL OGRParseRFC822DateTime( const char* pszRFC822DateTime,
OGRField* psField );
char CPL_DLL * OGRGetRFC822DateTime(const OGRField* psField);
char CPL_DLL * OGRGetXMLDateTime(const OGRField* psField);
Behaviour changes:
* OGRFeature::GetFieldAsString() will now output milliseconds if a DateTime/Time
field has such precision.
* Drivers will now output milliseconds if a DateTime/Time field has such precision.
J) RFC 57: 64-bit bucket count for histograms
Link: https://trac.osgeo.org/gdal/wiki/rfc57_histogram_64bit_count
C++ API:
* GDALRasterBand::GetHistogram() and GDALRasterBand::SetDefaultHistogram() take a GUIntBig* instead of a int* for bucket counts.
* GDALRasterBand::GetDefaultHistogram() takes a GUIntBig** instead of a int** for bucket counts.
* GDALRasterBand::GetRasterSampleOverview() takes a GUIntBig instead of int.
C API:
* GDALGetRasterHistogramEx(), GDALGetDefaultHistogramEx() and GDALSetDefaultHistogramEx() are added
and deprecate the old interfaces.
* GDALGetRasterSampleOverviewEx() is added.
Out-of-tree drivers :
* See the virtual method API changes mentioned above in the C++ API paragraph.
MIGRATION GUIDE FROM GDAL 1.10 to GDAL 1.11
-------------------------------------------
This file documents backwards incompatible changes.
C++ API:
* GDALRasterAttributeTable is now an abstract class.
See http://trac.osgeo.org/gdal/wiki/rfc40_enhanced_rat_support
The functionality of GDAL 1.X GDALRasterAttributeTable is now in
GDALDefaultRasterAttributeTable.
OGR drivers :
* Due to RFC 41, if a OGR driver calls SetGeomType(wkbNone) on a layer,
it will be impossible to affect geometries to features of that layer.
This worked before, although it was inconsistent, but it does no longer now.
In the development of RFC 41, the CSV and VRT drivers have been upgraded
to fix such errors.
Changes that should likely not impact anybody :
* OGRGeometry::exportToGEOS() and OGRGeometryFactory::createFromGEOS() now
take a GEOSContextHandle_t argument ( GEOS >= 3.1.0 )
* OGRGeometryFactory::getGEOSGeometryFactory() has been removed.
This method returned NULL since 2006
( http://trac.osgeo.org/gdal/changeset/9899/trunk/ogr/ogrgeometryfactory.cpp )

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,230 @@
= GDAL/OGR X.Y.Z Release Notes (r25919 to rXXXXX) =
== In a nutshell... ==
* New GDAL drivers:
* New OGR drivers:
== New installed files ==
== Backward compatibility issues ==
== GDAL/OGR X.Y.Z - General Changes ==
Build(Unix):
Build(Windows):
== GDAL X.Y.Z - Overview of Changes ==
Port:
Core:
Algorithms:
Utilities:
Multi driver changes:
AAIGrid:
ACE2 driver:
ADRG driver:
BAG driver:
BT driver:
CEOS2 driver:
DIMAP driver:
DTED driver:
ECW driver:
ENVI driver:
ENVISAT driver:
GeoRaster driver:
GIF driver:
GMT driver:
GTiff driver:
GRIB driver:
GSAG driver:
GS7BG driver:
GTX driver:
GXF driver:
HDF4 driver:
HDF5 driver:
HFA driver:
INGR driver:
ISIS3 driver:
JP2ECW driver:
JP2KAK driver:
JP2OpenJPEG driver:
JPEG driver:
JPEG2000 driver:
KMLSuperOverlay driver:
L1B driver:
MG4Lidar driver:
NetCDF driver:
NITF driver:
Northwood driver:
PDF driver:
PNG driver:
PostgisRaster driver:
Rasterlite driver:
RMF driver:
RPFTOC driver:
RS2 driver:
SDTS driver:
SRP driver:
TIL driver:
TSX driver:
VRT driver:
WCS driver:
WebP driver:
WMS driver:
XYZ driver:
== OGR X.Y.Z - Overview of Changes ==
Core:
OGRSpatialReference:
Utilities:
Multi driver changes:
AVCE00 driver:
AVCBin driver:
CSV driver:
DGN driver:
DXF driver:
FileGDB driver:
Geoconcept driver:
GeoJSON driver:
Geomedia driver:
GFT driver:
GML driver:
ILI driver:
Ingres driver:
KML driver:
Idrisi driver:
LIBKML driver:
MITAB driver:
MSSQLSpatial driver:
MySQL:
NAS driver:
NULL driver:
OCI driver:
ODBC driver:
NTF driver:
OCI driver:
PGeo driver:
PG driver:
PGDump driver:
REC driver:
SDE driver:
Shapefile driver:
S57 driver:
SQLite/Spatialite driver:
TIGER driver:
VFK driver:
VRT driver:
WFS driver:
XLS driver:
== SWIG Language Bindings ==
All bindings:
CSharp bindings:
Java bindings:
Perl bindings:
Python bindings:

View File

@@ -0,0 +1,586 @@
== Committers ==
Current:
See COMMITTERS file.
Historical and Current:
fwarmerdam & warmerda - Frank Warmerdam
dron - Andrey Kiselev
danmo & daniel & dmorissette - Daniel Morissette (MapGears)
dnadeau & denad21 - Denis Nadeau
kdejong & kor - Kor de Jong (geog.uu.nl / PCRaster)
aubin - Mark Aubin - Keyhole
svillene & stephane - Stephane Villeneuve
kmelero - Ken Melero (SANZ)
nemec - Philip Nemec (Keyhole)
pka - Pirmin Kalberer (Sourcepole)
pgs - Paul Spencer (DM Solutions)
assefa - Assefa Yewondwossen (DM Solutions)
jlacroix & julien - Julie Lacroix (Map Gears)
shadow (shadow @ dementia.org?)
mbrudka - Marek Brudka (Filbico?)
mbp - Mark Phillips (Tiger writer)
gpotts - Garrett Potts (OSSIM)
gwalter - Gillian Walter (Atlantis)
aamici & andrea - Alessandro Amici
kintel - Marius Kintel - dgnlib only
lichun - Lichun Wang at ITC.
hobu - Howard Butler (Hobu Inc)
bsimon - Benjamin Simon - pgchip
kshih - Ken Shih
hsaggu - Harbinder Saggu (Safe Software)
ryan - Ryan Proulx (Safe Software)
geh - Graeme Hiebert (Safe Software)
ssoule - Steve Soule (Vexcel)
pnagy - Peter Nagy (Vexcel)
sperkins - Simon Perkins (LANL)
osemykin - Oleg Semykin
cees - Cees Wesseling (PCRaster)
rblazek - Radim Blazek (GRASS)
cfis - Charles Savage - swig/ruby
mloskot - Mateusz Loskot
dwallner - Daniel Wallner
collinsb - Benjamin Collins (MITRE) - swig/java
jimg - James Gallager (OPeNDAP)
kruland - Kevin Ruland
vgough - Valient Gough - 1999 - configure stuff.
silke - Silke Reimer (Intevation)
ilucena - Ivan Lucena (Oracle)
shalasz - Steve Halasz (Debian)
srioux - Sylvain Rioux (Softmap)
ldjohn - Lowell D. Johnson - 2001 - rawdataset.cpp - one commit
pvachon - Phil Vachon
klokan - Petr Pridal
condit - Chris Condit (SDSC)
retsios - Bas Retsios (ITC)
rouault - Even Rouault
rayg - Ray Gardener (Daylon Graphics)
kosta - Konstantin Baumann
aaime - Andrea Aime (Openplans)
gaopeng - Gao Peng (ESRI)
hannah - hHannah Valbonesi (Safe Software)
mchapman - Martin Chapman
dreamil - Swapnil Harjare (Indictrans)
== Outstanding Issues ==
In gdal/data we have several coordinate system dictionary files derived in one fashion or another from other source (via translation scripts):
* gdal/data/cubewerx_extra.wkt: derived from definitions distributed by Cubewerx, rights unclear. See http://trac.osgeo.org/gdal/ticket/2165
* gdal/data/ecw_cs.wkt: Derived via much processing from ERMapper GDT definitions, rights unclear. See http://trac.osgeo.org/gdal/ticket/2162
* gdal/data/esri_extra.wkt + gdal/data/esri_epsg.wkt: From https://github.com/Esri/projection-engine-db-doc. Apache License 2.0. See http://trac.osgeo.org/gdal/ticket/2163
== Included Libraries ==
* zlib: gdal/frmts/zlib
* libtiff: gdal/frmts/gtiff/libtiff
* libgeotiff: gdal/frmts/gtiff/libgeotiff
* libjpeg: gdal/frmts/jpeg/libjpeg
* libpng: gdal/frmts/png/libpng
* libgif/libungif: gdal/frmts/gif/libungif
* libcsf: gdal/frmts/pcraster/libcsf
* hdfeoslib: gdal/frmts/hdf4/hdf-eos
== Non-free Libraries ==
Note: all the following are build options, not required.
* Oracle OCI for OCI OGR driver.
* ESRI SDE for SDE OGR Driver.
* ECW SDK for ECW/JP2ECW GDAL driver (close to free now I think).
* Kakadu for JP2KAK GDAL driver.
* MrSID SDK for MrSID/JP2MrSID driver.
* DWGdirect library for DWG writing.
== Code Reviewed ==
=== gdal/port ===
* Various contributors including Daniel Morissette, Andrey Kiselev, Frank Warmerdam and Mateusz Loskot.
* cpl_minizip* files come from the "minizip" distribution. Placed under a modified BSD Licence (see port/LICENCE_minizip). Added to gdal/LICENSE.TXT
=== gdal/gcore ===
* Various contributed, but mostly FrankW.
* All copyright held by FrankW.
* Version.rc contributed without copyright notice by Martin Daly, clarification requested. Martin explicitly agreed by email, notice applied, all ok.
=== gdal/alg ===
* contour.cpp: Joint copyright between FrankW and ACT.
* gdal_crs.c: derived from old GRASS/UMichigan code also under MIT/X license, properly noted in headers.
* gdalmediancut.cpp: derived from libtiff tiffmedian.c utility under a GDAL compatible license. Properly noted in headers.
* gdalrasterize.cpp: Derived from OpenEV code. Relicensed from LGPL to MIT/X by explicit grant from copyright holder (Frank Warmerdam).
* gvgcpfit.c: Believed to be derived from Numerical Recipes in C. It has not been used for some time, but was still in the CVS repository. I have now removed it.
* llrasterize.c: Derived from GD which has compatible MIT/X license. Properly noted in header.
* thinplatespline.cpp: Contributed by VIZRT Inc., Relicensed to MIT/X with their explicit permission as noted in the header.
=== gdal/data ===
* Contains various data files without copyright messages embedded.
* cubewerx_extra.wkt: derived from definitions distributed by Cubewerx, rights unclear. See http://trac.osgeo.org/gdal/ticket/2165
* ecw_cs.wkt: Derived via much processing from ERMapper GDT definitions, rights unclear. See http://trac.osgeo.org/gdal/ticket/2162
* esri_extra.wkt + esri_epsg.wkt: Provided by ESRI under Apache v2 license. See http://trac.osgeo.org/gdal/ticket/2163
* ellipsoid.csv, gcs.csv, gdal_datum.csv, pcs.csv, prime_meridian.csv, projop_wparm.csv, unit_of_measure.csv: Derived from EPSG. Modifications to EPSG data violate the EPSG use agreement (if we are to still attribute it to EPSG) so I have segregated changes into override files (i.e. gcs.override.csv).
* seed_2d.dgn, seed_3d.dgn: Exact source of these files is unclear. The files contain no substantial creative content since all but the header elements were stripped. Judged to acceptable use.
* NTS-50kindex.csv: Provided by Matt Wilkie, derived from NRCan dataset, rights unclear. See http://trac.osgeo.org/gdal/ticket/2164 (closed - this file isn't actually in the source tree - it is separately distributed as part of FWTools!)
=== gdal/apps ===
* gdal_contour.cpp: copyright held by ACT.
* gdaltindex.cpp: copyright held by DM Solutions.
* gdalwarp.cpp, gdalwarpsimple.cpp: copyright held by i-cubed.
* gdaldem.cpp: copyright held by Matthew Perry, Even Rouault, and Howard Butler
Derived from code by Michael Shapiro, Olga Waupotitsch, Marjorie Larson, Jim Westervelt :
U.S. Army CERL, 1993. GRASS 4.1 Reference Manual. U.S. Army Corps of Engineers,
Construction Engineering Research Laboratories, Champaign, Illinois, 1-425.
Derived from modules of GRASS 4.1 (public domain), properly noted in the headers.
See http://trac.osgeo.org/gdal/ticket/2975
=== gdal/doc ===
* no copyright messages in .dox files.
* ERMapper logo used with permissions.
* "ru" subdirectory (Russian translations) by Andrey Kiselev.
=== gdal/ogr/ogrsf_frmts/generic ===
* Some files here (and elsewhere in OGR) copyright Softmap Inc (but MIT/X).
=== gdal/ogr/ogrsf_frmts/avc ===
* Some copyright Daniel Morissette, MIT/X.
* Included copy of dbfopen.h from Shapelib. We really ought to reference the one in ../shape.
=== gdal/ogr/ogrsf_frmts/csv ===
* drv_*.html not copyright.
=== gdal/ogr/ogrsf_frmts/dgn ===
* Copyright Avenza Systems (MIT/X).
* dgn_pge.cpp, dgn_pge.h, pge_test.cpp, vbe_pge.cpp: copyright Pacific Gas and Electric, all rights reserved! (this has all been removed from trunk)
* web/* docs lack any copyright message. The isff.txt originally came from Intergraph and dgn.html is a reformatted version of that. Perhaps these ought to move out of GDAL CVS tree - action: this has been removed from svn. (#1813)
=== gdal/ogr/ogrsf_frmts/dods ===
* all FrankW, clean.
=== gdal/ogr/ogrsf_frmts/fme ===
* All code is Copyright Safe Software, "All Rights Reserved"! - License changed to MIT/X with explicit permission from Dale Lutz. Copyright still held by Safe.
=== gdal/ogr/ogrsf_frmts/gml ===
* All FrankW, clean.
=== gdal/ogr/ogrsf_frmts/grass ===
* copyright Radim Blazek, MIT/X.
=== gdal/ogr/ogrsf_frmts/ili ===
* ili level code copyright Pirmin Kalberer (Sourcepole), MIT/X.
* iom/ili2c.jar is ambiguous. (#1812) (removed - ok)
* iom source code is all LGPL (per iom/README.src.txt) but none of the source files have a copyright or license header. Action: this file has been removed. (#1812)
=== gdal/ogr/ogrsf_frmts/mem ===
* All FrankW, clean.
=== gdal/ogr/ogrsf_frmts/mitab ===
* Copyright Daniel Morissette, Stepane Villeneuve, Frank Warmerdam (MIT/X).
* Some code derived from MapServer with credit in headers, no problem foreseen.
* All clean.
=== gdal/ogr/ogrsf_frmts/mysql ===
* FrankW, clean.
* Howard Butler is co-author of some modules (but copyright all FrankW).
=== gdal/ogr/ogrsf_frmts/ntf ===
* FrankW, clean.
=== gdal/ogr/ogrsf_frmts/oci ===
* FrankW, clean.
=== gdal/ogr/ogrsf_frmts/odbc ===
* FrankW, clean.
=== gdal/ogr/ogrsf_frmts/ogdi ===
* Copyright Daniel Morrissette, MIT/X.
=== gdal/ogr/ogrsf_frmts/pg ===
* FrankW, clean.
=== gdal/ogr/ogrsf_frmts/pgeo ===
* FrankW, clean.
=== gdal/ogr/ogrsf_frmts/rec ===
* FrankW, clean.
=== gdal/ogr/ogrsf_frmts/s57 ===
* added copyright messages to s57tables.h (derived from s57objectclasses.csv).
* FrankW, clean.
=== gdal/ogr/ogrsf_frmts/sde ===
* FrankW, clean.
=== gdal/ogr/ogrsf_frmts/sdts ===
* FrankW, clean.
=== gdal/ogr/ogrsf_frmts/shape ===
* inline copy of Shapelib which is dual licensed MIT/X and LGPL.
* Note, Shapelib code was written while I was at PCI, but permission was given to release it as open source.
* Some (OGR) code is Copyright Softmap Inc, MIT/X.
=== gdal/ogr/ogrsf_frmts/sqlite ===
* FrankW, clean.
=== gdal/ogr/ogrsf_frmts/tiger ===
* Copyright mostly FrankW, but also Mark Phillips, clean.
=== gdal/ogr/ogrsf_frmts/vrt ===
* FrankW, clean.
=== gdal/ogr/ogrsf_frmts ===
* Some copyright softmap Inc, all MIT/X.
=== gdal/ogr ===
* SpatialReferenceIdl.idl, GeometryIdl.idl, CoverageIdl.idl: From OGC spec package I believe. (removed)
* ogr_capi_test.c: no copyright message, written by Daniel Morissette. Added copyright.
* oledbgis.h: No copyright message, mostly OGC spec constants.
* swq.h, swq.c: Has alternate form of MIT/X license. On review this license is functionally equivalent to the general GDAL license.
* Copyright holders include Frank Warmerdam, Daniel Morissette, Softmap Inc., Stephane Villeneuve., Andrey Kiselev, Information Interoperability Institute
=== gdal/frmts/aaigrid ===
* FrankW, clean.
=== gdal/frmts/aigrid ===
* aigccitt.c: Derived from libtiff - MIT/X.
* FrankW, clean.
=== gdal/frmts/airsar ===
* FrankW, clean.
=== gdal/frmts/bmp ===
* AndreyK, clean.
=== gdal/frmts/bsb ===
* FrankW, Mike Higgins, clean.
NOTE: This code is implemented on the basis of work by Mike Higgins. The
BSB format is subject to US patent 5,727,090; however, that patent
apparently only covers *writing* BSB files, not reading them, so this code
should not be affected.
See [http://home.gdal.org/projects/bsb/ipi.html]
=== gdal/frmts/ceos ===
* FrankW, clean.
=== gdal/frmts/ceos2 ===
* Atlantis Scientific (now Vexcel Canada), clean.
=== gdal/frmts/dods ===
* OPeNDAP Inc/FrankW, clean.
=== gdal/frmts/dted ===
* FrankW, clean.
=== gdal/frmts/ecw ===
* FrankW, clean.
=== gdal/frmts/elas ===
* FrankW, clean.
=== gdal/frmts/envisat ===
* Atlantis Scientific (now Vexcel Canada), clean.
=== gdal/frmts/fit ===
* Keyhole (Google), clean.
=== gdal/frmts/fits ===
* Simon Perkins (LANL), clean.
=== gdal/frmts/gif ===
* FrankW, clean.
* libungif is under the MIT/X license as established in ticket #1818.
=== gdal/frmts/grass ===
* Frank, clean
* Added copyright header to dist/configure.in
=== gdal/frmts/gtiff ===
* tif_float.c: Industrial Light and Magic - MIT/X style, but with a credit requirement. Added license notice in gdal/LICENSE.TXT, setup ticket #1819 to streamline it's use.
* tif_memio.c: FrankW, Mike Johnson and MancTec AB - MIT/X.
* Contains copy of libtiff, license terms explicit in source files.
* Contains copy of libgeotiff, license terms not made clear. A review of libgeotiff's LICENSE file makes it clear code is public domain unless otherwise noted (which would be FrankW's MIT/X code)
=== gdal/frmts/gxf ===
* README states:
Gilles Clement of Global Geomatics approved this support library
for general OpenSource release six months after it was released
as part of OGDI. This should be approximately September of 1999.
* Frank, clean.
=== gdal/frmts/hdf4 ===
* AndreyK, clean.
* embedded copy of HDF-EOS library with these apparent terms:
Copyright (C) 1996 Hughes and Applied Research Corporation
Permission to use, modify, and distribute this software and its documentation
for any purpose without fee is hereby granted, provided that the above
copyright notice appear in all copies and that both that copyright notice and
this permission notice appear in supporting documentation.
I have added this license to LICENSE.TXT to satisfy the credit requirement.
* cfortHdf.h had "cfortran.h" strings, and has been removed.
=== gdal/frmts/hdf5 ===
* FrankW, clean.
=== gdal/frmts/hfa ===
* Mostly copyright Intergraph Corporation, clean.
* hfacompress.cpp: Sam Gillingham, clean.
=== gdal/frmts/idrisi ===
* Ivan Lucena (Clark University), clean.
* READMEs for rdc and rst format don't have any copyright details.
=== gdal/frmts/ilwis ===
* ITC, clean.
* Fixed ilwiscoordinatesystem.cpp header after review of cvs log.
=== gdal/frmts/iso8211 ===
* FrankW, clean.
=== gdal/frmts/jdem ===
* FrankW, clean.
=== gdal/frmts/jp2kak ===
* dbg_file_source.h: Derived from Kakadu, no copyright or other history. (#1820) (removed - ok)
* jp2kak_roi.h: Derived from Kakadu with proper credit. But re-copyrighted FrankW improperly. (#1820) (removed - ok)
* Otherwise FrankW, clean.
=== gdal/frmts/jpeg ===
* FrankW, clean.
* Contains embedded copy of libjpeg - copyright/license notice README was missing and has been added.
=== gdal/frmts/jpeg2000 ===
* AndreyK, clean.
=== gdal/frmts/l1b ===
* AndreyK, clean.
=== gdal/frmts/leveller ===
* Daylon Graphics, clean.
=== gdal/frmts/mem ===
* FrankW, clean.
=== gdal/frmts/mrsid ===
* AndreyK, clean.
=== gdal/frmts/msg ===
* xritheaderparser.cpp, xritheaderparser.h: Copyright ITC and R. Alblas and released under the GPL. (#1821) The GPL code has been removed and reimplemented a different way. Problem resolved.
* the rest, ITC, clean
=== gdal/frmts/msgn ===
* msg_basic_types.{cpp,h}, msg_reader_core.{cpp,h}: Added copyright headers with explicit permission from Frans van den Bergh, the author/copyright holder.
=== gdal/frmts/netcdf ===
* FrankW, clean.
=== gdal/frmts/nitf ===
* mgrs.h, mgrs.c: Derived from Geotrans (public domain), not current copyright header.
* The rest is FrankW, clean.
=== gdal/frmts/pcidsk ===
* AndreyK/FrankW, clean.
=== gdal/frmts/pcraster ===
* Kor de Jong holds copyright.
* Some missing headers (pcrasterdataset.h, pcrastermisc.cpp, pcrasterrasterband.cpp, pcrasterutil.cpp, pcrasterutil.h (#1822).
* libcsf: license and copyright implicit in AUTHORS and COPYING documents.
* libcsf COPYING indicates an MIT-like agreement but with more explicit requirements for notice in binaries. Added to gdal/LICENSE.TXT
Copyright (c) 1997-2003, Utrecht University
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above
copyright notice, this list of conditions and the following
disclaimer in the documentation and/or other materials provided
with the distribution.
* Neither the name of Utrecht University nor the names of its contributors
may be used to endorse or promote products derived from this software
without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
=== gdal/frmts/png ===
* FrankW, clean.
* includes copy of libpng.
* libpng has a roughly MIT-like license but with explicit indication that notice is only required in source distributions. http://www.gdal.org/srctree/frmts/png/libpng/LICENSE
=== gdal/frmts/raw ===
* FrankW, Derrick J Brashear, AndreyK, clean.
=== gdal/frmts/rik ===
* Daniel Wallner, clean.
=== gdal/frmts/rmf ===
* AndreyK, clean.
=== gdal/frmts/rs2 ===
* FrankW, clean.
=== gdal/frmts/sdts ===
* FrankW, clean.
=== gdal/frmts/sgi ===
* FrankW, clean.
* Original SGI code used with permission of Paul Bourke.
=== gdal/frmts/usgsdem ===
* FrankW, clean.
=== gdal/frmts/vrt ===
* FrankW, Vexcel, clean.
=== gdal/frmts/xpm ===
* FrankW, clean.
=== gdal/frmts/zlib ===
* Using external zlib library
* README includes the license (same as libpng).
=== gdal ===
* aclocal.m4 and configure.in have copyright/license headers.
* Various readme's, Doxyfile, Makefiles, scripts without any licensing info.
=== gdal/swig/include ===
* Kevin Ruland, HowardB, FrankW, TamasS, clean.
=== gdal/swig/include/csharp ===
* Mostly written by TamasS, lacking copyright headers. Emailing Tamas.
=== gdal/swig/include/java ===
* Mostly written by BenC, AndreaA, lacking copyright headers.
=== gdal/swig/include/python ===
* Mostly written by HowardB, KevinR, lacking copyright headers.
=== gdal/swig/include/python/docs ===
* doxy2swig.py is imported from outside, but is under a compatible BSD license
* The rest of the .i files are written or produced by HowardB and lack copyright headers.
=== gdal/swig/include/perl ===
* Written by Kevin and Ari, a few files lack copyright notices.
=== gdal/swig/include/php ===
* Written by Kevin, lacking copyright headers.
=== gdal/swig/include/php ===
* Written by Kevin, lacking copyright headers.
=== gdal/swig/include/ruby ===
* Written by Kevin and Charlie, most files lack copyright headers.
=== gdal/swig/csharp ===
* Just makefiles and stuff, no problems.
=== gdal/swig/csharp/apps ===
* Written by Tamas, lacking copyright headers (emailed).

View File

@@ -0,0 +1 @@
2.4.0

View File

@@ -0,0 +1,74 @@
# generated automatically by aclocal 1.15.1 -*- Autoconf -*-
# Copyright (C) 1996-2017 Free Software Foundation, Inc.
# This file is free software; the Free Software Foundation
# gives unlimited permission to copy and/or distribute it,
# with or without modifications, as long as this notice is preserved.
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
# PARTICULAR PURPOSE.
m4_ifndef([AC_CONFIG_MACRO_DIRS], [m4_defun([_AM_CONFIG_MACRO_DIRS], [])m4_defun([AC_CONFIG_MACRO_DIRS], [_AM_CONFIG_MACRO_DIRS($@)])])
# ===========================================================================
# https://www.gnu.org/software/autoconf-archive/ax_require_defined.html
# ===========================================================================
#
# SYNOPSIS
#
# AX_REQUIRE_DEFINED(MACRO)
#
# DESCRIPTION
#
# AX_REQUIRE_DEFINED is a simple helper for making sure other macros have
# been defined and thus are available for use. This avoids random issues
# where a macro isn't expanded. Instead the configure script emits a
# non-fatal:
#
# ./configure: line 1673: AX_CFLAGS_WARN_ALL: command not found
#
# It's like AC_REQUIRE except it doesn't expand the required macro.
#
# Here's an example:
#
# AX_REQUIRE_DEFINED([AX_CHECK_LINK_FLAG])
#
# LICENSE
#
# Copyright (c) 2014 Mike Frysinger <vapier@gentoo.org>
#
# Copying and distribution of this file, with or without modification, are
# permitted in any medium without royalty provided the copyright notice
# and this notice are preserved. This file is offered as-is, without any
# warranty.
#serial 2
AC_DEFUN([AX_REQUIRE_DEFINED], [dnl
m4_ifndef([$1], [m4_fatal([macro ]$1[ is not defined; is a m4 file missing?])])
])dnl AX_REQUIRE_DEFINED
m4_include([m4/acinclude.m4])
m4_include([m4/ax_cflags_warn_all.m4])
m4_include([m4/ax_check_compile_flag.m4])
m4_include([m4/ax_cxx_compile_stdcxx.m4])
m4_include([m4/ax_cxx_compile_stdcxx_11.m4])
m4_include([m4/ax_lib_expat.m4])
m4_include([m4/ax_lib_libkml.m4])
m4_include([m4/ax_lib_sqlite3.m4])
m4_include([m4/ax_lib_xerces.m4])
m4_include([m4/ax_oracle_oci.m4])
m4_include([m4/geos.m4])
m4_include([m4/iconv.m4])
m4_include([m4/lib-ld.m4])
m4_include([m4/lib-link.m4])
m4_include([m4/lib-prefix.m4])
m4_include([m4/libtool.m4])
m4_include([m4/ltoptions.m4])
m4_include([m4/ltsugar.m4])
m4_include([m4/ltversion.m4])
m4_include([m4/lt~obsolete.m4])
m4_include([m4/pkg.m4])
m4_include([m4/sfcgal.m4])

View File

@@ -0,0 +1,67 @@
include ../GDALmake.opt
OBJ = gdalmediancut.o gdaldither.o gdal_crs.o gdaltransformer.o \
gdalsimplewarp.o gdalwarper.o gdalwarpkernel.o \
gdalwarpoperation.o gdalchecksum.o gdal_rpc.o gdal_tps.o \
thinplatespline.o llrasterize.o gdalrasterize.o gdalgeoloc.o \
gdalgrid.o gdalcutline.o gdalproximity.o rasterfill.o \
gdalrasterpolygonenumerator.o \
gdalsievefilter.o gdalwarpkernel_opencl.o polygonize.o \
contour.o gdaltransformgeolocs.o gdallinearsystem.o \
gdal_octave.o gdal_simplesurf.o gdalmatching.o delaunay.o \
gdalpansharpen.o gdalapplyverticalshiftgrid.o
ifeq ($(HAVE_GEOS),yes)
CPPFLAGS := -DHAVE_GEOS=1 $(GEOS_CFLAGS) $(CPPFLAGS)
endif
ifeq ($(HAVE_SFCGAL),yes)
CPPFLAGS := -DHAVE_SFCGAL=1 $(SFCGAL_CFLAGS) $(CPPFLAGS)
endif
ifeq ($(HAVE_ARMADILLO),yes)
CPPFLAGS := -DHAVE_ARMADILLO $(CPPFLAGS)
endif
ifeq ($(QHULL_SETTING),external)
CPPFLAGS := -DEXTERNAL_QHULL -DQHULL_INCLUDE_SUBDIR_IS_LIBQHULL=$(QHULL_INCLUDE_SUBDIR_IS_LIBQHULL) $(CPPFLAGS)
endif
ifeq ($(QHULL_SETTING),internal)
CPPFLAGS := -DINTERNAL_QHULL $(CPPFLAGS)
endif
CPPFLAGS := -I../frmts/vrt $(CPPFLAGS) $(OPENCL_FLAGS) $(PROJ_FLAGS) $(PROJ_INCLUDE) -Imarching_squares
CXXFLAGS := $(WARN_EFFCPLUSPLUS) $(WARN_OLD_STYLE_CAST) $(CXXFLAGS)
default: $(OBJ:.o=.$(OBJ_EXT)) gdalgridavx.$(OBJ_EXT) gdalgridsse.$(OBJ_EXT)
# We use CXXFLAGS_NO_LTO_IF_AVX_NONDEFAULT to avoid the whole library to be compiled with -mavx
# if -mavx is not the default
gdalgridavx.$(OBJ_EXT): gdalgridavx.cpp
$(CXX) $(GDAL_INCLUDE) $(CXXFLAGS_NO_LTO_IF_AVX_NONDEFAULT) $(WARN_OLD_STYLE_CAST) $(AVXFLAGS) $(CPPFLAGS) -c -o $@ $<
gdalgridsse.$(OBJ_EXT): gdalgridsse.cpp
$(CXX) $(GDAL_INCLUDE) $(CXXFLAGS) $(WARN_OLD_STYLE_CAST) $(SSEFLAGS) $(CPPFLAGS) -c -o $@ $<
clean:
$(RM) *.o $(O_OBJ)
docs:
(cd ..; $(MAKE) docs)
INST_H_FILES = \
gdal_alg.h \
gdal_alg_priv.h \
gdalgrid.h \
gdalgrid_priv.h \
gdalpansharpen.h \
gdal_simplesurf.h \
gdalwarper.h
install:
for f in $(INST_H_FILES) ; do $(INSTALL_DATA) $$f $(DESTDIR)$(INST_INCLUDE) ; done
lib: $(OBJ:.o=.$(OBJ_EXT))
(cd .. ; $(MAKE) force-lib)

View File

@@ -0,0 +1,741 @@
/******************************************************************************
*
* Project: Contour Generation
* Purpose: Core algorithm implementation for contour line generation.
* Author: Frank Warmerdam, warmerdam@pobox.com
*
******************************************************************************
* Copyright (c) 2003, Frank Warmerdam <warmerdam@pobox.com>
* Copyright (c) 2003, Applied Coherent Technology Corporation, www.actgate.com
* Copyright (c) 2007-2013, Even Rouault <even dot rouault at mines-paris dot org>
* Copyright (c) 2018, Oslandia <infos at oslandia dot com>
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included
* in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
****************************************************************************/
#include "level_generator.h"
#include "polygon_ring_appender.h"
#include "utility.h"
#include "contour_generator.h"
#include "segment_merger.h"
#include "gdal.h"
#include "gdal_alg.h"
#include "cpl_conv.h"
#include "cpl_string.h"
#include "ogr_api.h"
#include "ogr_srs_api.h"
#include "ogr_geometry.h"
static CPLErr OGRPolygonContourWriter( double dfLevelMin, double dfLevelMax,
const OGRMultiPolygon& multipoly,
void *pInfo )
{
OGRContourWriterInfo *poInfo = static_cast<OGRContourWriterInfo *>(pInfo);
OGRFeatureDefnH hFDefn =
OGR_L_GetLayerDefn( static_cast<OGRLayerH>(poInfo->hLayer) );
OGRFeatureH hFeat = OGR_F_Create( hFDefn );
if( poInfo->nIDField != -1 )
OGR_F_SetFieldInteger( hFeat, poInfo->nIDField, poInfo->nNextID++ );
if( poInfo->nElevFieldMin != -1 )
OGR_F_SetFieldDouble( hFeat, poInfo->nElevFieldMin, dfLevelMin );
if( poInfo->nElevFieldMax != -1 )
OGR_F_SetFieldDouble( hFeat, poInfo->nElevFieldMax, dfLevelMax );
const bool bHasZ = wkbHasZ(OGR_FD_GetGeomType(hFDefn));
OGRGeometryH hGeom = OGR_G_CreateGeometry(
bHasZ ? wkbMultiPolygon25D : wkbMultiPolygon );
for ( int iPart = 0; iPart < multipoly.getNumGeometries(); iPart++ )
{
OGRPolygon* poNewPoly = new OGRPolygon();
const OGRPolygon* poPolygon = static_cast<const OGRPolygon*>(multipoly.getGeometryRef(iPart));
for ( int iRing = 0; iRing < poPolygon->getNumInteriorRings() + 1; iRing++ )
{
const OGRLinearRing* poRing = iRing == 0 ?
poPolygon->getExteriorRing()
: poPolygon->getInteriorRing(iRing - 1);
OGRLinearRing* poNewRing = new OGRLinearRing();
for ( int iPoint = 0; iPoint < poRing->getNumPoints(); iPoint++ )
{
const double dfX = poInfo->adfGeoTransform[0]
+ poInfo->adfGeoTransform[1] * poRing->getX(iPoint)
+ poInfo->adfGeoTransform[2] * poRing->getY(iPoint);
const double dfY = poInfo->adfGeoTransform[3]
+ poInfo->adfGeoTransform[4] * poRing->getX(iPoint)
+ poInfo->adfGeoTransform[5] * poRing->getY(iPoint);
if( bHasZ )
OGR_G_SetPoint( OGRGeometry::ToHandle( poNewRing ), iPoint, dfX, dfY, dfLevelMax );
else
OGR_G_SetPoint_2D( OGRGeometry::ToHandle( poNewRing ), iPoint, dfX, dfY );
}
poNewPoly->addRingDirectly( poNewRing );
}
OGR_G_AddGeometryDirectly( hGeom, OGRGeometry::ToHandle( poNewPoly ) );
}
OGR_F_SetGeometryDirectly( hFeat, hGeom );
const OGRErr eErr =
OGR_L_CreateFeature(static_cast<OGRLayerH>(poInfo->hLayer), hFeat);
OGR_F_Destroy( hFeat );
return eErr == OGRERR_NONE ? CE_None : CE_Failure;
}
struct PolygonContourWriter
{
CPL_DISALLOW_COPY_ASSIGN(PolygonContourWriter)
explicit PolygonContourWriter( OGRContourWriterInfo* poInfo, double minLevel ) : poInfo_( poInfo ), previousLevel_( minLevel ) {}
void startPolygon( double level )
{
previousLevel_ = currentLevel_;
currentGeometry_.reset( new OGRMultiPolygon() );
currentLevel_ = level;
}
void endPolygon()
{
if ( currentGeometry_ && currentPart_ )
{
currentGeometry_->addGeometryDirectly(currentPart_);
}
OGRPolygonContourWriter( previousLevel_, currentLevel_, *currentGeometry_, poInfo_ );
currentGeometry_.reset( nullptr );
currentPart_ = nullptr;
}
void addPart( const marching_squares::LineString& ring )
{
if ( currentGeometry_ && currentPart_ )
{
currentGeometry_->addGeometryDirectly(currentPart_);
}
OGRLinearRing* poNewRing = new OGRLinearRing();
poNewRing->setNumPoints( int(ring.size()) );
int iPoint = 0;
for ( const auto& p : ring )
{
poNewRing->setPoint( iPoint, p.x, p.y );
iPoint++;
}
currentPart_ = new OGRPolygon();
currentPart_->addRingDirectly(poNewRing);
}
void addInteriorRing( const marching_squares::LineString& ring )
{
OGRLinearRing* poNewRing = new OGRLinearRing();
for ( const auto& p : ring )
{
poNewRing->addPoint( p.x, p.y );
}
currentPart_->addRingDirectly(poNewRing);
}
std::unique_ptr<OGRMultiPolygon> currentGeometry_ = {};
OGRPolygon* currentPart_ = nullptr;
OGRContourWriterInfo* poInfo_ = nullptr;
double currentLevel_ = 0;
double previousLevel_;
};
struct GDALRingAppender
{
CPL_DISALLOW_COPY_ASSIGN(GDALRingAppender)
GDALRingAppender(GDALContourWriter write, void *data)
: write_( write )
, data_( data )
{}
void addLine( double level, marching_squares::LineString& ls, bool /*closed*/ )
{
const size_t sz = ls.size();
std::vector<double> xs( sz ), ys ( sz );
size_t i = 0;
for ( const auto& pt : ls ) {
xs[i] = pt.x;
ys[i] = pt.y;
i++;
}
if ( write_(level, int(sz), &xs[0], &ys[0], data_) != CE_None )
CPLError( CE_Failure, CPLE_AppDefined, "cannot write linestring" );
}
private:
GDALContourWriter write_;
void *data_;
};
/************************************************************************/
/* ==================================================================== */
/* Additional C Callable Functions */
/* ==================================================================== */
/************************************************************************/
/************************************************************************/
/* OGRContourWriter() */
/************************************************************************/
CPLErr OGRContourWriter( double dfLevel,
int nPoints, double *padfX, double *padfY,
void *pInfo )
{
OGRContourWriterInfo *poInfo = static_cast<OGRContourWriterInfo *>(pInfo);
OGRFeatureDefnH hFDefn =
OGR_L_GetLayerDefn( static_cast<OGRLayerH>(poInfo->hLayer) );
OGRFeatureH hFeat = OGR_F_Create( hFDefn );
if( poInfo->nIDField != -1 )
OGR_F_SetFieldInteger( hFeat, poInfo->nIDField, poInfo->nNextID++ );
if( poInfo->nElevField != -1 )
OGR_F_SetFieldDouble( hFeat, poInfo->nElevField, dfLevel );
const bool bHasZ = wkbHasZ(OGR_FD_GetGeomType(hFDefn));
OGRGeometryH hGeom = OGR_G_CreateGeometry(
bHasZ ? wkbLineString25D : wkbLineString );
for( int iPoint = nPoints - 1; iPoint >= 0; iPoint-- )
{
const double dfX = poInfo->adfGeoTransform[0]
+ poInfo->adfGeoTransform[1] * padfX[iPoint]
+ poInfo->adfGeoTransform[2] * padfY[iPoint];
const double dfY = poInfo->adfGeoTransform[3]
+ poInfo->adfGeoTransform[4] * padfX[iPoint]
+ poInfo->adfGeoTransform[5] * padfY[iPoint];
if( bHasZ )
OGR_G_SetPoint( hGeom, iPoint, dfX, dfY, dfLevel );
else
OGR_G_SetPoint_2D( hGeom, iPoint, dfX, dfY );
}
OGR_F_SetGeometryDirectly( hFeat, hGeom );
const OGRErr eErr =
OGR_L_CreateFeature(static_cast<OGRLayerH>(poInfo->hLayer), hFeat);
OGR_F_Destroy( hFeat );
return eErr == OGRERR_NONE ? CE_None : CE_Failure;
}
/************************************************************************/
/* GDALContourGenerate() */
/************************************************************************/
/**
* Create vector contours from raster DEM.
*
* This function is kept for compatibility reason and will call the new
* variant GDALContourGenerateEx that is more extensible and provide more
* options.
*
* Details about the algorithm are also given in the documentation of the
* new GDALContourenerateEx function.
*
* @param hBand The band to read raster data from. The whole band will be
* processed.
*
* @param dfContourInterval The elevation interval between contours generated.
*
* @param dfContourBase The "base" relative to which contour intervals are
* applied. This is normally zero, but could be different. To generate 10m
* contours at 5, 15, 25, ... the ContourBase would be 5.
*
* @param nFixedLevelCount The number of fixed levels. If this is greater than
* zero, then fixed levels will be used, and ContourInterval and ContourBase
* are ignored.
*
* @param padfFixedLevels The list of fixed contour levels at which contours
* should be generated. It will contain FixedLevelCount entries, and may be
* NULL if fixed levels are disabled (FixedLevelCount = 0).
*
* @param bUseNoData If TRUE the dfNoDataValue will be used.
*
* @param dfNoDataValue The value to use as a "nodata" value. That is, a
* pixel value which should be ignored in generating contours as if the value
* of the pixel were not known.
*
* @param hLayer The layer to which new contour vectors will be written.
* Each contour will have a LINESTRING geometry attached to it. This
* is really of type OGRLayerH, but void * is used to avoid pulling the
* ogr_api.h file in here.
*
* @param iIDField If not -1 this will be used as a field index to indicate
* where a unique id should be written for each feature (contour) written.
*
* @param iElevField If not -1 this will be used as a field index to indicate
* where the elevation value of the contour should be written.
*
* @param pfnProgress A GDALProgressFunc that may be used to report progress
* to the user, or to interrupt the algorithm. May be NULL if not required.
*
* @param pProgressArg The callback data for the pfnProgress function.
*
* @return CE_None on success or CE_Failure if an error occurs.
*/
CPLErr GDALContourGenerate( GDALRasterBandH hBand,
double dfContourInterval, double dfContourBase,
int nFixedLevelCount, double *padfFixedLevels,
int bUseNoData, double dfNoDataValue,
void *hLayer, int iIDField, int iElevField,
GDALProgressFunc pfnProgress, void *pProgressArg )
{
char** options = nullptr;
if ( nFixedLevelCount > 0 ) {
std::string values = "FIXED_LEVELS=";
for ( int i = 0; i < nFixedLevelCount; i++ ) {
const int sz = 32;
char* newValue = new char[sz+1];
if ( i == nFixedLevelCount - 1 ) {
CPLsnprintf( newValue, sz+1, "%f", padfFixedLevels[i] );
}
else {
CPLsnprintf( newValue, sz+1, "%f,", padfFixedLevels[i] );
}
values = values + std::string( newValue );
delete[] newValue;
}
options = CSLAddString( options, values.c_str() );
}
else if ( dfContourInterval != 0.0 ) {
options = CSLAppendPrintf( options, "LEVEL_INTERVAL=%f", dfContourInterval );
}
if ( dfContourBase != 0.0 ) {
options = CSLAppendPrintf( options, "LEVEL_BASE=%f", dfContourBase );
}
if ( bUseNoData ) {
options = CSLAppendPrintf( options, "NODATA=%.19g", dfNoDataValue );
}
if ( iIDField != -1 ) {
options = CSLAppendPrintf( options, "ID_FIELD=%d", iIDField );
}
if ( iElevField != -1 ) {
options = CSLAppendPrintf( options, "ELEV_FIELD=%d", iElevField );
}
CPLErr err = GDALContourGenerateEx( hBand, hLayer, options, pfnProgress, pProgressArg );
CSLDestroy( options );
return err;
}
/**
* Create vector contours from raster DEM.
*
* This algorithm is an implementation of "Marching squares" [1] that will
* generate contour vectors for the input raster band on the requested set
* of contour levels. The vector contours are written to the passed in OGR
* vector layer. Also, a NODATA value may be specified to identify pixels
* that should not be considered in contour line generation.
*
* The gdal/apps/gdal_contour.cpp mainline can be used as an example of
* how to use this function.
*
* [1] see https://en.wikipedia.org/wiki/Marching_squares
*
* ALGORITHM RULES
For contouring purposes raster pixel values are assumed to represent a point
value at the center of the corresponding pixel region. For the purpose of
contour generation we virtually connect each pixel center to the values to
the left, right, top and bottom. We assume that the pixel value is linearly
interpolated between the pixel centers along each line, and determine where
(if any) contour lines will appear along these line segments. Then the
contour crossings are connected.
This means that contour lines' nodes will not actually be on pixel edges, but
rather along vertical and horizontal lines connecting the pixel centers.
\verbatim
General Case:
5 | | 3
-- + ---------------- + --
| |
| |
| |
| |
10 + |
|\ |
| \ |
-- + -+-------------- + --
12 | 10 | 1
Saddle Point:
5 | | 12
-- + -------------+-- + --
| \ |
| \|
| +
| |
+ |
|\ |
| \ |
-- + -+-------------- + --
12 | | 1
or:
5 | | 12
-- + -------------+-- + --
| __/ |
| ___/ |
| ___/ __+
| / __/ |
+' __/ |
| __/ |
| ,__/ |
-- + -+-------------- + --
12 | | 1
\endverbatim
Nodata:
In the "nodata" case we treat the whole nodata pixel as a no-mans land.
We extend the corner pixels near the nodata out to half way and then
construct extra lines from those points to the center which is assigned
an averaged value from the two nearby points (in this case (12+3+5)/3).
\verbatim
5 | | 3
-- + ---------------- + --
| |
| |
| 6.7 |
| +---------+ 3
10 +___ |
| \____+ 10
| |
-- + -------+ +
12 | 12 (nodata)
\endverbatim
*
* @param hBand The band to read raster data from. The whole band will be
* processed.
*
* @param hLayer The layer to which new contour vectors will be written.
* Each contour will have a LINESTRING geometry attached to it
* (or POLYGON if POLYGONIZE=YES). This is really of type OGRLayerH, but
* void * is used to avoid pulling the ogr_api.h file in here.
*
* @param pfnProgress A GDALProgressFunc that may be used to report progress
* to the user, or to interrupt the algorithm. May be NULL if not required.
*
* @param pProgressArg The callback data for the pfnProgress function.
*
* @param options List of options
*
* Options:
*
* LEVEL_INTERVAL=f
*
* The elevation interval between contours generated.
*
* LEVEL_BASE=f
*
* The "base" relative to which contour intervals are
* applied. This is normally zero, but could be different. To generate 10m
* contours at 5, 15, 25, ... the LEVEL_BASE would be 5.
*
* LEVEL_EXP_BASE=f
*
* If greater than 0, contour levels are generated on an
* exponential scale. Levels will then be generated by LEVEL_EXP_BASE^k
* where k is a positive integer.
*
* FIXED_LEVELS=f[,f]*
*
* The list of fixed contour levels at which contours should be generated.
* This option has precedence on LEVEL_INTERVAL
*
* NODATA=f
*
* The value to use as a "nodata" value. That is, a pixel value which
* should be ignored in generating contours as if the value of the pixel
* were not known.
*
* ID_FIELD=d
*
* This will be used as a field index to indicate where a unique id should
* be written for each feature (contour) written.
*
* ELEV_FIELD=d
*
* This will be used as a field index to indicate where the elevation value
* of the contour should be written.
*
* ELEV_FIELD_MIN=d
*
* This will be used as a field index to indicate where the minimum elevation value
* of the polygon contour should be written.
*
* ELEV_FIELD_MAX=d
*
* This will be used as a field index to indicate where the maximum elevation value
* of the polygon contour should be written.
*
* POLYGONIZE=YES|NO
*
* If YES, contour polygons will be created, rather than polygon lines.
*
*
* @return CE_None on success or CE_Failure if an error occurs.
*/
CPLErr GDALContourGenerateEx( GDALRasterBandH hBand, void *hLayer,
CSLConstList options,
GDALProgressFunc pfnProgress, void *pProgressArg )
{
VALIDATE_POINTER1( hBand, "GDALContourGenerateEx", CE_Failure );
if( pfnProgress == nullptr )
pfnProgress = GDALDummyProgress;
double contourInterval = 0.0;
const char* opt = CSLFetchNameValue( options, "LEVEL_INTERVAL" );
if ( opt ) {
contourInterval = CPLAtof( opt );
}
double contourBase = 0.0;
opt = CSLFetchNameValue( options, "LEVEL_BASE" );
if ( opt ) {
contourBase = CPLAtof( opt );
}
double expBase = 0.0;
opt = CSLFetchNameValue( options, "LEVEL_EXP_BASE" );
if ( opt ) {
expBase = CPLAtof( opt );
}
std::vector<double> fixedLevels;
opt = CSLFetchNameValue( options, "FIXED_LEVELS" );
if ( opt ) {
char** values = CSLTokenizeStringComplex( opt, ",", FALSE, FALSE );
fixedLevels.resize( CSLCount( values ) );
for ( size_t i = 0; i < fixedLevels.size(); i++ ) {
fixedLevels[i] = CPLAtof(values[i]);
}
CSLDestroy( values );
}
bool useNoData = false;
double noDataValue = 0.0;
opt = CSLFetchNameValue( options, "NODATA" );
if ( opt ) {
useNoData = true;
noDataValue = CPLAtof( opt );
}
int idField = -1;
opt = CSLFetchNameValue( options, "ID_FIELD" );
if ( opt ) {
idField = atoi( opt );
}
int elevField = -1;
opt = CSLFetchNameValue( options, "ELEV_FIELD" );
if ( opt ) {
elevField = atoi( opt );
}
int elevFieldMin = -1;
opt = CSLFetchNameValue( options, "ELEV_FIELD_MIN" );
if ( opt ) {
elevFieldMin = atoi( opt );
}
int elevFieldMax = -1;
opt = CSLFetchNameValue( options, "ELEV_FIELD_MAX" );
if ( opt ) {
elevFieldMax = atoi( opt );
}
bool polygonize = CPLFetchBool( options, "POLYGONIZE", false );
using namespace marching_squares;
OGRContourWriterInfo oCWI;
oCWI.hLayer = static_cast<OGRLayerH>(hLayer);
oCWI.nElevField = elevField;
oCWI.nElevFieldMin = elevFieldMin;
oCWI.nElevFieldMax = elevFieldMax;
oCWI.nIDField = idField;
oCWI.adfGeoTransform[0] = 0.0;
oCWI.adfGeoTransform[1] = 1.0;
oCWI.adfGeoTransform[2] = 0.0;
oCWI.adfGeoTransform[3] = 0.0;
oCWI.adfGeoTransform[4] = 0.0;
oCWI.adfGeoTransform[5] = 1.0;
GDALDatasetH hSrcDS = GDALGetBandDataset( hBand );
if( hSrcDS != nullptr )
GDALGetGeoTransform( hSrcDS, oCWI.adfGeoTransform );
oCWI.nNextID = 0;
try
{
if ( polygonize )
{
int bSuccess;
PolygonContourWriter w( &oCWI, GDALGetRasterMinimum( hBand, &bSuccess ) );
typedef PolygonRingAppender<PolygonContourWriter> RingAppender;
RingAppender appender( w );
if ( ! fixedLevels.empty() ) {
FixedLevelRangeIterator levels( &fixedLevels[0], fixedLevels.size(), GDALGetRasterMaximum( hBand, &bSuccess ) );
SegmentMerger<RingAppender, FixedLevelRangeIterator> writer(appender, levels, /* polygonize */ true);
ContourGeneratorFromRaster<decltype(writer), FixedLevelRangeIterator> cg( hBand, useNoData, noDataValue, writer, levels );
cg.process( pfnProgress, pProgressArg );
}
else if ( expBase > 0.0 ) {
ExponentialLevelRangeIterator levels( expBase );
SegmentMerger<RingAppender, ExponentialLevelRangeIterator> writer(appender, levels, /* polygonize */ true);
ContourGeneratorFromRaster<decltype(writer), ExponentialLevelRangeIterator> cg( hBand, useNoData, noDataValue, writer, levels );
cg.process( pfnProgress, pProgressArg );
}
else {
IntervalLevelRangeIterator levels( contourBase, contourInterval );
SegmentMerger<RingAppender, IntervalLevelRangeIterator> writer(appender, levels, /* polygonize */ true);
ContourGeneratorFromRaster<decltype(writer), IntervalLevelRangeIterator> cg( hBand, useNoData, noDataValue, writer, levels );
cg.process( pfnProgress, pProgressArg );
}
}
else
{
GDALRingAppender appender(OGRContourWriter, &oCWI);
if ( ! fixedLevels.empty() ) {
FixedLevelRangeIterator levels( &fixedLevels[0], fixedLevels.size() );
SegmentMerger<GDALRingAppender, FixedLevelRangeIterator> writer(appender, levels, /* polygonize */ false);
ContourGeneratorFromRaster<decltype(writer), FixedLevelRangeIterator> cg( hBand, useNoData, noDataValue, writer, levels );
cg.process( pfnProgress, pProgressArg );
}
else if ( expBase > 0.0 ) {
ExponentialLevelRangeIterator levels( expBase );
SegmentMerger<GDALRingAppender, ExponentialLevelRangeIterator> writer(appender, levels, /* polygonize */ false);
ContourGeneratorFromRaster<decltype(writer), ExponentialLevelRangeIterator> cg( hBand, useNoData, noDataValue, writer, levels );
cg.process( pfnProgress, pProgressArg );
}
else {
IntervalLevelRangeIterator levels( contourBase, contourInterval );
SegmentMerger<GDALRingAppender, IntervalLevelRangeIterator> writer(appender, levels, /* polygonize */ false);
ContourGeneratorFromRaster<decltype(writer), IntervalLevelRangeIterator> cg( hBand, useNoData, noDataValue, writer, levels );
cg.process( pfnProgress, pProgressArg );
}
}
}
catch (const std::exception & e)
{
CPLError(CE_Failure, CPLE_AppDefined, "%s", e.what());
return CE_Failure;
}
return CE_None;
}
/************************************************************************/
/* GDAL_CG_Create() */
/************************************************************************/
namespace marching_squares {
// Opaque type used by the C API
struct ContourGeneratorOpaque
{
typedef SegmentMerger<GDALRingAppender, IntervalLevelRangeIterator> SegmentMergerT;
typedef ContourGenerator<SegmentMergerT, IntervalLevelRangeIterator> ContourGeneratorT;
ContourGeneratorOpaque( int nWidth, int nHeight, int bNoDataSet, double dfNoDataValue,
double dfContourInterval, double dfContourBase,
GDALContourWriter pfnWriter, void *pCBData )
: levels( dfContourBase, dfContourInterval )
, writer( pfnWriter, pCBData )
, merger( writer, levels, /* polygonize */ false )
, contourGenerator( nWidth, nHeight, bNoDataSet != 0, dfNoDataValue, merger, levels )
{}
IntervalLevelRangeIterator levels;
GDALRingAppender writer;
SegmentMergerT merger;
ContourGeneratorT contourGenerator;
};
}
/** Create contour generator */
GDALContourGeneratorH
GDAL_CG_Create( int nWidth, int nHeight, int bNoDataSet, double dfNoDataValue,
double dfContourInterval, double dfContourBase,
GDALContourWriter pfnWriter, void *pCBData )
{
auto cg = new marching_squares::ContourGeneratorOpaque( nWidth,
nHeight,
bNoDataSet,
dfNoDataValue,
dfContourInterval,
dfContourBase,
pfnWriter,
pCBData );
return reinterpret_cast<GDALContourGeneratorH>(cg);
}
/************************************************************************/
/* GDAL_CG_FeedLine() */
/************************************************************************/
/** Feed a line to the contour generator */
CPLErr GDAL_CG_FeedLine( GDALContourGeneratorH hCG, double *padfScanline )
{
VALIDATE_POINTER1( hCG, "GDAL_CG_FeedLine", CE_Failure );
return reinterpret_cast<marching_squares::ContourGeneratorOpaque*>(hCG)->contourGenerator.feedLine( padfScanline );
}
/************************************************************************/
/* GDAL_CG_Destroy() */
/************************************************************************/
/** Destroy contour generator */
void GDAL_CG_Destroy( GDALContourGeneratorH hCG )
{
delete reinterpret_cast<marching_squares::ContourGeneratorOpaque*>(hCG);
}

View File

@@ -0,0 +1,643 @@
/******************************************************************************
*
* Project: GDAL algorithms
* Purpose: Delaunay triangulation
* Author: Even Rouault, even.rouault at spatialys.com
*
******************************************************************************
* Copyright (c) 2015, Even Rouault <even.rouault at spatialys.com>
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included
* in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
****************************************************************************/
#if defined(__MINGW32__) || defined(__MINGW64__)
/* This avoids i586-mingw32msvc/include/direct.h from including libqhull/io.h ... */
#define _DIRECT_H_
/* For __MINGW64__ */
#define _INC_DIRECT
#define _INC_STAT
#endif
#if defined(INTERNAL_QHULL) && !defined(DONT_DEPRECATE_SPRINTF)
#define DONT_DEPRECATE_SPRINTF
#endif
#include "cpl_error.h"
#include "cpl_conv.h"
#include "cpl_multiproc.h"
#include "gdal_alg.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <math.h>
CPL_CVSID("$Id: delaunay.c d38086d97f76b283f7c6ba57abd60da9e279cbde 2018-10-06 19:02:19 +0200 Even Rouault $")
#if defined(INTERNAL_QHULL) || defined(EXTERNAL_QHULL)
#define HAVE_INTERNAL_OR_EXTERNAL_QHULL 1
#endif
#if HAVE_INTERNAL_OR_EXTERNAL_QHULL
#ifdef INTERNAL_QHULL
#include "internal_qhull_headers.h"
#else /* INTERNAL_QHULL */
#if !defined(QHULL_INCLUDE_SUBDIR_IS_LIBQHULL)
#include "libqhull.h"
#include "qset.h"
#elif QHULL_INCLUDE_SUBDIR_IS_LIBQHULL
#include "libqhull/libqhull.h"
#include "libqhull/qset.h"
#else
#include "qhull/libqhull.h"
#include "qhull/qset.h"
#endif
#endif /* INTERNAL_QHULL */
#endif /* HAVE_INTERNAL_OR_EXTERNAL_QHULL*/
#if HAVE_INTERNAL_OR_EXTERNAL_QHULL
static CPLMutex* hMutex = NULL;
#endif
/************************************************************************/
/* GDALHasTriangulation() */
/************************************************************************/
/** Returns if GDAL is built with Delaunay triangulation support.
*
* @return TRUE if GDAL is built with Delaunay triangulation support.
*
* @since GDAL 2.1
*/
int GDALHasTriangulation()
{
#if HAVE_INTERNAL_OR_EXTERNAL_QHULL
return TRUE;
#else
return FALSE;
#endif
}
/************************************************************************/
/* GDALTriangulationCreateDelaunay() */
/************************************************************************/
/** Computes a Delaunay triangulation of the passed points
*
* @param nPoints number of points
* @param padfX x coordinates of the points.
* @param padfY y coordinates of the points.
* @return triangulation that must be freed with GDALTriangulationFree(), or
* NULL in case of error.
*
* @since GDAL 2.1
*/
GDALTriangulation* GDALTriangulationCreateDelaunay(int nPoints,
const double* padfX,
const double* padfY)
{
#if HAVE_INTERNAL_OR_EXTERNAL_QHULL
coordT* points;
int i, j;
GDALTriangulation* psDT = NULL;
facetT *facet;
GDALTriFacet* pasFacets;
int* panMapQHFacetIdToFacetIdx; /* map from QHull facet ID to the index of our GDALTriFacet* array */
int curlong, totlong; /* memory remaining after qh_memfreeshort */
/* QHull is not thread safe, so we need to protect all operations with a mutex */
CPLCreateOrAcquireMutex(&hMutex, 1000);
#if qh_QHpointer /* see user.h */
if (qh_qh)
{
fprintf (stderr, "QH6238: Qhull link error. The global variable qh_qh was not initialized\n\
to NULL by global.c. Please compile this program with -Dqh_QHpointer_dllimport\n\
as well as -Dqh_QHpointer, or use libqhullstatic, or use a different tool chain.\n\n");
CPLReleaseMutex(hMutex);
return NULL;
}
#endif
points = (coordT*)VSI_MALLOC2_VERBOSE(sizeof(double)*2, nPoints);
if( points == NULL )
{
CPLReleaseMutex(hMutex);
return NULL;
}
for(i=0;i<nPoints;i++)
{
points[2*i] = padfX[i];
points[2*i+1] = padfY[i];
}
/* d: Delaunay */
/* Qbb: scale last coordinate to [0,m] for Delaunay */
/* Qc: keep coplanar points with nearest facet */
/* Qz: add a point-at-infinity for Delaunay triangulation */
/* Qt: triangulated output */
if( qh_new_qhull(2, nPoints, points, FALSE /* ismalloc */,
"qhull d Qbb Qc Qz Qt", NULL, stderr) != 0 )
{
VSIFree(points);
CPLError(CE_Failure, CPLE_AppDefined, "Delaunay triangulation failed");
goto end;
}
VSIFree(points);
points = NULL;
#if qh_QHpointer /* see user.h */
if (qh_qh == NULL)
{
CPLReleaseMutex(hMutex);
return NULL;
}
#endif
/* Establish a map from QHull facet id to the index in our array of sequential facets */
panMapQHFacetIdToFacetIdx = (int*)VSI_MALLOC2_VERBOSE(sizeof(int), qh facet_id);
if( panMapQHFacetIdToFacetIdx == NULL )
{
goto end;
}
memset(panMapQHFacetIdToFacetIdx, 0xFF, sizeof(int) * qh facet_id);
for(j = 0, facet = qh facet_list;
facet != NULL && facet->next != NULL;
facet = facet->next)
{
if( facet->upperdelaunay != qh UPPERdelaunay )
continue;
if( qh_setsize(facet->vertices) != 3 ||
qh_setsize(facet->neighbors) != 3 )
{
CPLError(CE_Failure, CPLE_AppDefined,
"Triangulation resulted in non triangular facet %d: vertices=%d",
facet->id, qh_setsize(facet->vertices));
VSIFree(panMapQHFacetIdToFacetIdx);
goto end;
}
CPLAssert(facet->id < qh facet_id);
panMapQHFacetIdToFacetIdx[facet->id] = j++;
}
pasFacets = (GDALTriFacet*) VSI_MALLOC2_VERBOSE( j, sizeof(GDALTriFacet) );
if(pasFacets == NULL )
{
VSIFree(panMapQHFacetIdToFacetIdx);
goto end;
}
psDT = (GDALTriangulation*)CPLCalloc(1, sizeof(GDALTriangulation));
psDT->nFacets = j;
psDT->pasFacets = pasFacets;
// Store vertex and neighbor information for each triangle.
for(facet = qh facet_list;
facet != NULL && facet->next != NULL;
facet = facet->next)
{
int k;
if( facet->upperdelaunay != qh UPPERdelaunay )
continue;
k = panMapQHFacetIdToFacetIdx[facet->id];
pasFacets[k].anVertexIdx[0] =
qh_pointid(((vertexT*) facet->vertices->e[0].p)->point);
pasFacets[k].anVertexIdx[1] =
qh_pointid(((vertexT*) facet->vertices->e[1].p)->point);
pasFacets[k].anVertexIdx[2] =
qh_pointid(((vertexT*) facet->vertices->e[2].p)->point);
pasFacets[k].anNeighborIdx[0] =
panMapQHFacetIdToFacetIdx[((facetT*) facet->neighbors->e[0].p)->id];
pasFacets[k].anNeighborIdx[1] =
panMapQHFacetIdToFacetIdx[((facetT*) facet->neighbors->e[1].p)->id];
pasFacets[k].anNeighborIdx[2] =
panMapQHFacetIdToFacetIdx[((facetT*) facet->neighbors->e[2].p)->id];
}
VSIFree(panMapQHFacetIdToFacetIdx);
end:
qh_freeqhull(!qh_ALL);
qh_memfreeshort(&curlong, &totlong);
CPLReleaseMutex(hMutex);
return psDT;
#else /* HAVE_INTERNAL_OR_EXTERNAL_QHULL */
/* Suppress unused argument warnings. */
(void)nPoints;
(void)padfX;
(void)padfY;
CPLError(CE_Failure, CPLE_NotSupported,
"GDALTriangulationCreateDelaunay() unavailable since GDAL built without QHull support");
return NULL;
#endif /* HAVE_INTERNAL_OR_EXTERNAL_QHULL */
}
/************************************************************************/
/* GDALTriangulationFree() */
/************************************************************************/
/** Free a triangulation.
*
* @param psDT triangulation.
* @since GDAL 2.1
*/
void GDALTriangulationFree(GDALTriangulation* psDT)
{
if( psDT )
{
VSIFree(psDT->pasFacets);
VSIFree(psDT->pasFacetCoefficients);
VSIFree(psDT);
}
}
/************************************************************************/
/* GDALTriangulationComputeBarycentricCoefficients() */
/************************************************************************/
/** Computes barycentric coefficients for each triangles of the triangulation.
*
* @param psDT triangulation.
* @param padfX x coordinates of the points. Must be identical to the one passed
* to GDALTriangulationCreateDelaunay().
* @param padfY y coordinates of the points. Must be identical to the one passed
* to GDALTriangulationCreateDelaunay().
*
* @return TRUE in case of success.
*
* @since GDAL 2.1
*/
int GDALTriangulationComputeBarycentricCoefficients(GDALTriangulation* psDT,
const double* padfX,
const double* padfY)
{
int i;
if( psDT->pasFacetCoefficients != NULL )
{
return TRUE;
}
psDT->pasFacetCoefficients = (GDALTriBarycentricCoefficients*)VSI_MALLOC2_VERBOSE(
sizeof(GDALTriBarycentricCoefficients), psDT->nFacets);
if( psDT->pasFacetCoefficients == NULL )
{
return FALSE;
}
for(i = 0; i < psDT->nFacets; i++)
{
GDALTriFacet* psFacet = &(psDT->pasFacets[i]);
GDALTriBarycentricCoefficients* psCoeffs = &(psDT->pasFacetCoefficients[i]);
double dfX1 = padfX[psFacet->anVertexIdx[0]];
double dfY1 = padfY[psFacet->anVertexIdx[0]];
double dfX2 = padfX[psFacet->anVertexIdx[1]];
double dfY2 = padfY[psFacet->anVertexIdx[1]];
double dfX3 = padfX[psFacet->anVertexIdx[2]];
double dfY3 = padfY[psFacet->anVertexIdx[2]];
/* See https://en.wikipedia.org/wiki/Barycentric_coordinate_system */
double dfDenom = (dfY2 - dfY3) * (dfX1 - dfX3) + (dfX3 - dfX2) * (dfY1 - dfY3);
if( fabs(dfDenom) < 1e-5 )
{
// Degenerate triangle
psCoeffs->dfMul1X = 0.0;
psCoeffs->dfMul1Y = 0.0;
psCoeffs->dfMul2X = 0.0;
psCoeffs->dfMul2Y = 0.0;
psCoeffs->dfCstX = 0.0;
psCoeffs->dfCstY = 0.0;
}
else
{
psCoeffs->dfMul1X = (dfY2 - dfY3) / dfDenom;
psCoeffs->dfMul1Y = (dfX3 - dfX2) / dfDenom;
psCoeffs->dfMul2X = (dfY3 - dfY1) / dfDenom;
psCoeffs->dfMul2Y = (dfX1 - dfX3) / dfDenom;
psCoeffs->dfCstX = dfX3;
psCoeffs->dfCstY = dfY3;
}
}
return TRUE;
}
/************************************************************************/
/* GDALTriangulationComputeBarycentricCoordinates() */
/************************************************************************/
#define BARYC_COORD_L1(psCoeffs, dfX, dfY) \
(psCoeffs->dfMul1X * ((dfX) - psCoeffs->dfCstX) + psCoeffs->dfMul1Y * ((dfY) - psCoeffs->dfCstY))
#define BARYC_COORD_L2(psCoeffs, dfX, dfY) \
(psCoeffs->dfMul2X * ((dfX) - psCoeffs->dfCstX) + psCoeffs->dfMul2Y * ((dfY) - psCoeffs->dfCstY))
#define BARYC_COORD_L3(l1, l2) (1 - (l1) - (l2))
/** Computes the barycentric coordinates of a point.
*
* @param psDT triangulation.
* @param nFacetIdx index of the triangle in the triangulation
* @param dfX x coordinate of the point.
* @param dfY y coordinate of the point.
* @param pdfL1 (output) pointer to the 1st barycentric coordinate.
* @param pdfL2 (output) pointer to the 2nd barycentric coordinate.
* @param pdfL3 (output) pointer to the 2nd barycentric coordinate.
*
* @return TRUE in case of success.
*
* @since GDAL 2.1
*/
int GDALTriangulationComputeBarycentricCoordinates(const GDALTriangulation* psDT,
int nFacetIdx,
double dfX,
double dfY,
double* pdfL1,
double* pdfL2,
double* pdfL3)
{
const GDALTriBarycentricCoefficients* psCoeffs;
if( psDT->pasFacetCoefficients == NULL )
{
CPLError(CE_Failure, CPLE_AppDefined,
"GDALTriangulationComputeBarycentricCoefficients() should be called before");
return FALSE;
}
CPLAssert(nFacetIdx >= 0 && nFacetIdx < psDT->nFacets);
psCoeffs = &(psDT->pasFacetCoefficients[nFacetIdx]);
*pdfL1 = BARYC_COORD_L1(psCoeffs, dfX, dfY);
*pdfL2 = BARYC_COORD_L2(psCoeffs, dfX, dfY);
*pdfL3 = BARYC_COORD_L3(*pdfL1, *pdfL2);
return TRUE;
}
/************************************************************************/
/* GDALTriangulationFindFacetBruteForce() */
/************************************************************************/
#define EPS 1e-10
/** Returns the index of the triangle that contains the point by iterating
* over all triangles.
*
* If the function returns FALSE and *panOutputFacetIdx >= 0, then it means
* the point is outside the hull of the triangulation, and *panOutputFacetIdx
* is the closest triangle to the point.
*
* @param psDT triangulation.
* @param dfX x coordinate of the point.
* @param dfY y coordinate of the point.
* @param panOutputFacetIdx (output) pointer to the index of the triangle,
* or -1 in case of failure.
*
* @return index >= 0 of the triangle in case of success, -1 otherwise.
*
* @since GDAL 2.1
*/
int GDALTriangulationFindFacetBruteForce(const GDALTriangulation* psDT,
double dfX,
double dfY,
int* panOutputFacetIdx)
{
int nFacetIdx;
*panOutputFacetIdx = -1;
if( psDT->pasFacetCoefficients == NULL )
{
CPLError(CE_Failure, CPLE_AppDefined,
"GDALTriangulationComputeBarycentricCoefficients() should be called before");
return FALSE;
}
for(nFacetIdx=0;nFacetIdx<psDT->nFacets;nFacetIdx++)
{
double l1, l2, l3;
const GDALTriBarycentricCoefficients* psCoeffs =
&(psDT->pasFacetCoefficients[nFacetIdx]);
if( psCoeffs->dfMul1X == 0.0 && psCoeffs->dfMul2X == 0.0 &&
psCoeffs->dfMul1Y == 0.0 && psCoeffs->dfMul2Y == 0.0 )
{
// Degenerate triangle
continue;
}
l1 = BARYC_COORD_L1(psCoeffs, dfX, dfY);
if( l1 < -EPS )
{
int neighbor = psDT->pasFacets[nFacetIdx].anNeighborIdx[0];
if( neighbor < 0 )
{
*panOutputFacetIdx = nFacetIdx;
return FALSE;
}
continue;
}
if( l1 > 1 + EPS )
continue;
l2 = BARYC_COORD_L2(psCoeffs, dfX, dfY);
if( l2 < -EPS )
{
int neighbor = psDT->pasFacets[nFacetIdx].anNeighborIdx[1];
if( neighbor < 0 )
{
*panOutputFacetIdx = nFacetIdx;
return FALSE;
}
continue;
}
if( l2 > 1 + EPS )
continue;
l3 = BARYC_COORD_L3(l1, l2);
if( l3 < -EPS )
{
int neighbor = psDT->pasFacets[nFacetIdx].anNeighborIdx[2];
if( neighbor < 0 )
{
*panOutputFacetIdx = nFacetIdx;
return FALSE;
}
continue;
}
if( l3 > 1 + EPS )
continue;
*panOutputFacetIdx = nFacetIdx;
return TRUE;
}
return FALSE;
}
/************************************************************************/
/* GDALTriangulationFindFacetDirected() */
/************************************************************************/
#define EPS 1e-10
/** Returns the index of the triangle that contains the point by walking in
* the triangulation.
*
* If the function returns FALSE and *panOutputFacetIdx >= 0, then it means
* the point is outside the hull of the triangulation, and *panOutputFacetIdx
* is the closest triangle to the point.
*
* @param psDT triangulation.
* @param nFacetIdx index of first triangle to start with.
* Must be >= 0 && < psDT->nFacets
* @param dfX x coordinate of the point.
* @param dfY y coordinate of the point.
* @param panOutputFacetIdx (output) pointer to the index of the triangle,
* or -1 in case of failure.
*
* @return TRUE in case of success, FALSE otherwise.
*
* @since GDAL 2.1
*/
int GDALTriangulationFindFacetDirected(const GDALTriangulation* psDT,
int nFacetIdx,
double dfX,
double dfY,
int* panOutputFacetIdx)
{
#ifdef DEBUG_VERBOSE
const int nFacetIdxInitial = nFacetIdx;
#endif
int k, nIterMax;
*panOutputFacetIdx = -1;
if( psDT->pasFacetCoefficients == NULL )
{
CPLError(CE_Failure, CPLE_AppDefined,
"GDALTriangulationComputeBarycentricCoefficients() should be called before");
return FALSE;
}
CPLAssert(nFacetIdx >= 0 && nFacetIdx < psDT->nFacets);
nIterMax = 2 + psDT->nFacets / 4;
for(k=0;k<nIterMax;k++)
{
double l1, l2, l3;
int bMatch = TRUE;
const GDALTriFacet* psFacet = &(psDT->pasFacets[nFacetIdx]);
const GDALTriBarycentricCoefficients* psCoeffs =
&(psDT->pasFacetCoefficients[nFacetIdx]);
if( psCoeffs->dfMul1X == 0.0 && psCoeffs->dfMul2X == 0.0 &&
psCoeffs->dfMul1Y == 0.0 && psCoeffs->dfMul2Y == 0.0 )
{
// Degenerate triangle
break;
}
l1 = BARYC_COORD_L1(psCoeffs, dfX, dfY);
if( l1 < -EPS )
{
int neighbor = psFacet->anNeighborIdx[0];
if( neighbor < 0 )
{
#ifdef DEBUG_VERBOSE
CPLDebug("GDAL", "Outside %d in %d iters (initial = %d)",
nFacetIdx, k, nFacetIdxInitial);
#endif
*panOutputFacetIdx = nFacetIdx;
return FALSE;
}
nFacetIdx = neighbor;
continue;
}
else if( l1 > 1 + EPS )
bMatch = FALSE; // outside or degenerate
l2 = BARYC_COORD_L2(psCoeffs, dfX, dfY);
if( l2 < -EPS )
{
int neighbor = psFacet->anNeighborIdx[1];
if( neighbor < 0 )
{
#ifdef DEBUG_VERBOSE
CPLDebug("GDAL", "Outside %d in %d iters (initial = %d)",
nFacetIdx, k, nFacetIdxInitial);
#endif
*panOutputFacetIdx = nFacetIdx;
return FALSE;
}
nFacetIdx = neighbor;
continue;
}
else if( l2 > 1 + EPS )
bMatch = FALSE; // outside or degenerate
l3 = BARYC_COORD_L3(l1, l2);
if( l3 < -EPS )
{
int neighbor = psFacet->anNeighborIdx[2];
if( neighbor < 0 )
{
#ifdef DEBUG_VERBOSE
CPLDebug("GDAL", "Outside %d in %d iters (initial = %d)",
nFacetIdx, k, nFacetIdxInitial);
#endif
*panOutputFacetIdx = nFacetIdx;
return FALSE;
}
nFacetIdx = neighbor;
continue;
}
else if( l3 > 1 + EPS )
bMatch = FALSE; // outside or degenerate
if( bMatch )
{
#ifdef DEBUG_VERBOSE
CPLDebug("GDAL", "Inside %d in %d iters (initial = %d)",
nFacetIdx, k, nFacetIdxInitial);
#endif
*panOutputFacetIdx = nFacetIdx;
return TRUE;
}
else
{
break;
}
}
CPLDebug("GDAL", "Using brute force lookup");
return GDALTriangulationFindFacetBruteForce(psDT, dfX, dfY, panOutputFacetIdx);
}
/************************************************************************/
/* GDALTriangulationTerminate() */
/************************************************************************/
void GDALTriangulationTerminate()
{
#if HAVE_INTERNAL_OR_EXTERNAL_QHULL
if( hMutex != NULL )
{
CPLDestroyMutex(hMutex);
hMutex = NULL;
}
#endif
}

View File

@@ -0,0 +1,640 @@
/******************************************************************************
* $Id: gdal_alg.h b9ddc19f9ccd776cac9388f260aebc24439f10aa 2018-10-09 11:45:33 +0200 Julien Cabieces $
*
* Project: GDAL Image Processing Algorithms
* Purpose: Prototypes, and definitions for various GDAL based algorithms.
* Author: Frank Warmerdam, warmerdam@pobox.com
*
******************************************************************************
* Copyright (c) 2001, Frank Warmerdam
* Copyright (c) 2008-2012, Even Rouault <even dot rouault at mines-paris dot org>
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included
* in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
****************************************************************************/
#ifndef GDAL_ALG_H_INCLUDED
#define GDAL_ALG_H_INCLUDED
/**
* \file gdal_alg.h
*
* Public (C callable) GDAL algorithm entry points, and definitions.
*/
#ifndef DOXYGEN_SKIP
#include "gdal.h"
#include "cpl_minixml.h"
#include "ogr_api.h"
#endif
CPL_C_START
int CPL_DLL CPL_STDCALL GDALComputeMedianCutPCT( GDALRasterBandH hRed,
GDALRasterBandH hGreen,
GDALRasterBandH hBlue,
int (*pfnIncludePixel)(int,int,void*),
int nColors,
GDALColorTableH hColorTable,
GDALProgressFunc pfnProgress,
void * pProgressArg );
int CPL_DLL CPL_STDCALL GDALDitherRGB2PCT( GDALRasterBandH hRed,
GDALRasterBandH hGreen,
GDALRasterBandH hBlue,
GDALRasterBandH hTarget,
GDALColorTableH hColorTable,
GDALProgressFunc pfnProgress,
void * pProgressArg );
int CPL_DLL CPL_STDCALL GDALChecksumImage( GDALRasterBandH hBand,
int nXOff, int nYOff, int nXSize, int nYSize );
CPLErr CPL_DLL CPL_STDCALL
GDALComputeProximity( GDALRasterBandH hSrcBand,
GDALRasterBandH hProximityBand,
char **papszOptions,
GDALProgressFunc pfnProgress,
void * pProgressArg );
CPLErr CPL_DLL CPL_STDCALL
GDALFillNodata( GDALRasterBandH hTargetBand,
GDALRasterBandH hMaskBand,
double dfMaxSearchDist,
int bDeprecatedOption,
int nSmoothingIterations,
char **papszOptions,
GDALProgressFunc pfnProgress,
void * pProgressArg );
CPLErr CPL_DLL CPL_STDCALL
GDALPolygonize( GDALRasterBandH hSrcBand,
GDALRasterBandH hMaskBand,
OGRLayerH hOutLayer, int iPixValField,
char **papszOptions,
GDALProgressFunc pfnProgress,
void * pProgressArg );
CPLErr CPL_DLL CPL_STDCALL
GDALFPolygonize( GDALRasterBandH hSrcBand,
GDALRasterBandH hMaskBand,
OGRLayerH hOutLayer, int iPixValField,
char **papszOptions,
GDALProgressFunc pfnProgress,
void * pProgressArg );
CPLErr CPL_DLL CPL_STDCALL
GDALSieveFilter( GDALRasterBandH hSrcBand, GDALRasterBandH hMaskBand,
GDALRasterBandH hDstBand,
int nSizeThreshold, int nConnectedness,
char **papszOptions,
GDALProgressFunc pfnProgress,
void * pProgressArg );
/*
* Warp Related.
*/
typedef int
(*GDALTransformerFunc)( void *pTransformerArg,
int bDstToSrc, int nPointCount,
double *x, double *y, double *z, int *panSuccess );
/*! @cond Doxygen_Suppress */
#define GDAL_GTI2_SIGNATURE "GTI2"
typedef struct {
GByte abySignature[4];
const char *pszClassName;
GDALTransformerFunc pfnTransform;
void (*pfnCleanup)( void * pTransformerArg );
CPLXMLNode *(*pfnSerialize)( void * pTransformerArg );
void* (*pfnCreateSimilar)( void* pTransformerArg, double dfSrcRatioX, double dfSrcRatioY );
} GDALTransformerInfo;
/*! @endcond */
/*! @cond Doxygen_Suppress */
void CPL_DLL GDALDestroyTransformer( void *pTransformerArg );
int CPL_DLL GDALUseTransformer( void *pTransformerArg,
int bDstToSrc, int nPointCount,
double *x, double *y, double *z,
int *panSuccess );
void* GDALCreateSimilarTransformer( void* psTransformerArg, double dfSrcRatioX, double dfSrcRatioY );
/*! @endcond */
/* High level transformer for going from image coordinates on one file
to image coordinates on another, potentially doing reprojection,
utilizing GCPs or using the geotransform. */
void CPL_DLL *
GDALCreateGenImgProjTransformer( GDALDatasetH hSrcDS, const char *pszSrcWKT,
GDALDatasetH hDstDS, const char *pszDstWKT,
int bGCPUseOK, double dfGCPErrorThreshold,
int nOrder );
void CPL_DLL *
GDALCreateGenImgProjTransformer2( GDALDatasetH hSrcDS, GDALDatasetH hDstDS,
char **papszOptions );
void CPL_DLL *
GDALCreateGenImgProjTransformer3( const char *pszSrcWKT,
const double *padfSrcGeoTransform,
const char *pszDstWKT,
const double *padfDstGeoTransform );
void CPL_DLL GDALSetGenImgProjTransformerDstGeoTransform( void *,
const double * );
void CPL_DLL GDALDestroyGenImgProjTransformer( void * );
int CPL_DLL GDALGenImgProjTransform(
void *pTransformArg, int bDstToSrc, int nPointCount,
double *x, double *y, double *z, int *panSuccess );
void GDALSetTransformerDstGeoTransform( void *, const double * );
void GDALGetTransformerDstGeoTransform( void*, double* );
/* Geo to geo reprojection transformer. */
void CPL_DLL *
GDALCreateReprojectionTransformer( const char *pszSrcWKT,
const char *pszDstWKT );
void CPL_DLL GDALDestroyReprojectionTransformer( void * );
int CPL_DLL GDALReprojectionTransform(
void *pTransformArg, int bDstToSrc, int nPointCount,
double *x, double *y, double *z, int *panSuccess );
/* GCP based transformer ... forward is to georef coordinates */
void CPL_DLL *
GDALCreateGCPTransformer( int nGCPCount, const GDAL_GCP *pasGCPList,
int nReqOrder, int bReversed );
/* GCP based transformer with refinement of the GCPs ... forward is to georef coordinates */
void CPL_DLL *
GDALCreateGCPRefineTransformer( int nGCPCount, const GDAL_GCP *pasGCPList,
int nReqOrder, int bReversed, double tolerance, int minimumGcps);
void CPL_DLL GDALDestroyGCPTransformer( void *pTransformArg );
int CPL_DLL GDALGCPTransform(
void *pTransformArg, int bDstToSrc, int nPointCount,
double *x, double *y, double *z, int *panSuccess );
/* Thin Plate Spine transformer ... forward is to georef coordinates */
void CPL_DLL *
GDALCreateTPSTransformer( int nGCPCount, const GDAL_GCP *pasGCPList,
int bReversed );
void CPL_DLL GDALDestroyTPSTransformer( void *pTransformArg );
int CPL_DLL GDALTPSTransform(
void *pTransformArg, int bDstToSrc, int nPointCount,
double *x, double *y, double *z, int *panSuccess );
/*! @cond Doxygen_Suppress */
char CPL_DLL ** RPCInfoToMD( GDALRPCInfo *psRPCInfo );
/*! @endcond */
/* RPC based transformer ... src is pixel/line/elev, dst is long/lat/elev */
void CPL_DLL *
GDALCreateRPCTransformer( GDALRPCInfo *psRPC, int bReversed,
double dfPixErrThreshold,
char **papszOptions );
void CPL_DLL GDALDestroyRPCTransformer( void *pTransformArg );
int CPL_DLL GDALRPCTransform(
void *pTransformArg, int bDstToSrc, int nPointCount,
double *x, double *y, double *z, int *panSuccess );
/* Geolocation transformer */
void CPL_DLL *
GDALCreateGeoLocTransformer( GDALDatasetH hBaseDS,
char **papszGeolocationInfo,
int bReversed );
void CPL_DLL GDALDestroyGeoLocTransformer( void *pTransformArg );
int CPL_DLL GDALGeoLocTransform(
void *pTransformArg, int bDstToSrc, int nPointCount,
double *x, double *y, double *z, int *panSuccess );
/* Approximate transformer */
void CPL_DLL *
GDALCreateApproxTransformer( GDALTransformerFunc pfnRawTransformer,
void *pRawTransformerArg, double dfMaxError );
void CPL_DLL GDALApproxTransformerOwnsSubtransformer( void *pCBData,
int bOwnFlag );
void CPL_DLL GDALDestroyApproxTransformer( void *pApproxArg );
int CPL_DLL GDALApproxTransform(
void *pTransformArg, int bDstToSrc, int nPointCount,
double *x, double *y, double *z, int *panSuccess );
int CPL_DLL CPL_STDCALL
GDALSimpleImageWarp( GDALDatasetH hSrcDS,
GDALDatasetH hDstDS,
int nBandCount, int *panBandList,
GDALTransformerFunc pfnTransform,
void *pTransformArg,
GDALProgressFunc pfnProgress,
void *pProgressArg,
char **papszWarpOptions );
CPLErr CPL_DLL CPL_STDCALL
GDALSuggestedWarpOutput( GDALDatasetH hSrcDS,
GDALTransformerFunc pfnTransformer,
void *pTransformArg,
double *padfGeoTransformOut,
int *pnPixels, int *pnLines );
CPLErr CPL_DLL CPL_STDCALL
GDALSuggestedWarpOutput2( GDALDatasetH hSrcDS,
GDALTransformerFunc pfnTransformer,
void *pTransformArg,
double *padfGeoTransformOut,
int *pnPixels, int *pnLines,
double *padfExtents,
int nOptions );
/*! @cond Doxygen_Suppress */
CPLXMLNode CPL_DLL *
GDALSerializeTransformer( GDALTransformerFunc pfnFunc, void *pTransformArg );
CPLErr CPL_DLL GDALDeserializeTransformer( CPLXMLNode *psTree,
GDALTransformerFunc *ppfnFunc,
void **ppTransformArg );
/*! @endcond */
CPLErr CPL_DLL
GDALTransformGeolocations( GDALRasterBandH hXBand,
GDALRasterBandH hYBand,
GDALRasterBandH hZBand,
GDALTransformerFunc pfnTransformer,
void *pTransformArg,
GDALProgressFunc pfnProgress,
void *pProgressArg,
char **papszOptions );
/* -------------------------------------------------------------------- */
/* Contour Line Generation */
/* -------------------------------------------------------------------- */
/** Contour writer callback type */
typedef CPLErr (*GDALContourWriter)( double dfLevel, int nPoints,
double *padfX, double *padfY, void * );
/** Contour generator opaque type */
typedef void *GDALContourGeneratorH;
GDALContourGeneratorH CPL_DLL
GDAL_CG_Create( int nWidth, int nHeight,
int bNoDataSet, double dfNoDataValue,
double dfContourInterval, double dfContourBase,
GDALContourWriter pfnWriter, void *pCBData );
CPLErr CPL_DLL GDAL_CG_FeedLine( GDALContourGeneratorH hCG,
double *padfScanline );
void CPL_DLL GDAL_CG_Destroy( GDALContourGeneratorH hCG );
/*! @cond Doxygen_Suppress */
typedef struct
{
void *hLayer;
double adfGeoTransform[6];
int nElevField;
int nElevFieldMin;
int nElevFieldMax;
int nIDField;
int nNextID;
} OGRContourWriterInfo;
CPLErr CPL_DLL
OGRContourWriter( double, int, double *, double *, void *pInfo );
/*! @endcond */
CPLErr CPL_DLL
GDALContourGenerate( GDALRasterBandH hBand,
double dfContourInterval, double dfContourBase,
int nFixedLevelCount, double *padfFixedLevels,
int bUseNoData, double dfNoDataValue,
void *hLayer, int iIDField, int iElevField,
GDALProgressFunc pfnProgress, void *pProgressArg );
CPLErr CPL_DLL
GDALContourGenerateEx( GDALRasterBandH hBand, void *hLayer,
CSLConstList options,
GDALProgressFunc pfnProgress, void *pProgressArg );
/************************************************************************/
/* Rasterizer API - geometries burned into GDAL raster. */
/************************************************************************/
CPLErr CPL_DLL
GDALRasterizeGeometries( GDALDatasetH hDS,
int nBandCount, int *panBandList,
int nGeomCount, OGRGeometryH *pahGeometries,
GDALTransformerFunc pfnTransformer,
void *pTransformArg,
double *padfGeomBurnValue,
char **papszOptions,
GDALProgressFunc pfnProgress,
void * pProgressArg );
CPLErr CPL_DLL
GDALRasterizeLayers( GDALDatasetH hDS,
int nBandCount, int *panBandList,
int nLayerCount, OGRLayerH *pahLayers,
GDALTransformerFunc pfnTransformer,
void *pTransformArg,
double *padfLayerBurnValues,
char **papszOptions,
GDALProgressFunc pfnProgress,
void *pProgressArg );
CPLErr CPL_DLL
GDALRasterizeLayersBuf( void *pData, int nBufXSize, int nBufYSize,
GDALDataType eBufType, int nPixelSpace, int nLineSpace,
int nLayerCount, OGRLayerH *pahLayers,
const char *pszDstProjection,
double *padfDstGeoTransform,
GDALTransformerFunc pfnTransformer,
void *pTransformArg, double dfBurnValue,
char **papszOptions, GDALProgressFunc pfnProgress,
void *pProgressArg );
/************************************************************************/
/* Gridding interface. */
/************************************************************************/
/** Gridding Algorithms */
typedef enum {
/*! Inverse distance to a power */ GGA_InverseDistanceToAPower = 1,
/*! Moving Average */ GGA_MovingAverage = 2,
/*! Nearest Neighbor */ GGA_NearestNeighbor = 3,
/*! Minimum Value (Data Metric) */ GGA_MetricMinimum = 4,
/*! Maximum Value (Data Metric) */ GGA_MetricMaximum = 5,
/*! Data Range (Data Metric) */ GGA_MetricRange = 6,
/*! Number of Points (Data Metric) */ GGA_MetricCount = 7,
/*! Average Distance (Data Metric) */ GGA_MetricAverageDistance = 8,
/*! Average Distance Between Data Points (Data Metric) */
GGA_MetricAverageDistancePts = 9,
/*! Linear interpolation (from Delaunay triangulation. Since GDAL 2.1 */
GGA_Linear = 10,
/*! Inverse distance to a power with nearest neighbor search for max points */
GGA_InverseDistanceToAPowerNearestNeighbor = 11
} GDALGridAlgorithm;
/** Inverse distance to a power method control options */
typedef struct
{
/*! Weighting power. */
double dfPower;
/*! Smoothing parameter. */
double dfSmoothing;
/*! Reserved for future use. */
double dfAnisotropyRatio;
/*! Reserved for future use. */
double dfAnisotropyAngle;
/*! The first radius (X axis if rotation angle is 0) of search ellipse. */
double dfRadius1;
/*! The second radius (Y axis if rotation angle is 0) of search ellipse. */
double dfRadius2;
/*! Angle of ellipse rotation in degrees.
*
* Ellipse rotated counter clockwise.
*/
double dfAngle;
/*! Maximum number of data points to use.
*
* Do not search for more points than this number.
* If less amount of points found the grid node considered empty and will
* be filled with NODATA marker.
*/
GUInt32 nMaxPoints;
/*! Minimum number of data points to use.
*
* If less amount of points found the grid node considered empty and will
* be filled with NODATA marker.
*/
GUInt32 nMinPoints;
/*! No data marker to fill empty points. */
double dfNoDataValue;
} GDALGridInverseDistanceToAPowerOptions;
/** Inverse distance to a power, with nearest neighbour search, control options */
typedef struct
{
/*! Weighting power. */
double dfPower;
/*! The radius of search circle. */
double dfRadius;
/*! Smoothing parameter. */
double dfSmoothing;
/*! Maximum number of data points to use.
*
* Do not search for more points than this number.
* If less amount of points found the grid node considered empty and will
* be filled with NODATA marker.
*/
GUInt32 nMaxPoints;
/*! Minimum number of data points to use.
*
* If less amount of points found the grid node considered empty and will
* be filled with NODATA marker.
*/
GUInt32 nMinPoints;
/*! No data marker to fill empty points. */
double dfNoDataValue;
} GDALGridInverseDistanceToAPowerNearestNeighborOptions;
/** Moving average method control options */
typedef struct
{
/*! The first radius (X axis if rotation angle is 0) of search ellipse. */
double dfRadius1;
/*! The second radius (Y axis if rotation angle is 0) of search ellipse. */
double dfRadius2;
/*! Angle of ellipse rotation in degrees.
*
* Ellipse rotated counter clockwise.
*/
double dfAngle;
/*! Minimum number of data points to average.
*
* If less amount of points found the grid node considered empty and will
* be filled with NODATA marker.
*/
GUInt32 nMinPoints;
/*! No data marker to fill empty points. */
double dfNoDataValue;
} GDALGridMovingAverageOptions;
/** Nearest neighbor method control options */
typedef struct
{
/*! The first radius (X axis if rotation angle is 0) of search ellipse. */
double dfRadius1;
/*! The second radius (Y axis if rotation angle is 0) of search ellipse. */
double dfRadius2;
/*! Angle of ellipse rotation in degrees.
*
* Ellipse rotated counter clockwise.
*/
double dfAngle;
/*! No data marker to fill empty points. */
double dfNoDataValue;
} GDALGridNearestNeighborOptions;
/** Data metrics method control options */
typedef struct
{
/*! The first radius (X axis if rotation angle is 0) of search ellipse. */
double dfRadius1;
/*! The second radius (Y axis if rotation angle is 0) of search ellipse. */
double dfRadius2;
/*! Angle of ellipse rotation in degrees.
*
* Ellipse rotated counter clockwise.
*/
double dfAngle;
/*! Minimum number of data points to average.
*
* If less amount of points found the grid node considered empty and will
* be filled with NODATA marker.
*/
GUInt32 nMinPoints;
/*! No data marker to fill empty points. */
double dfNoDataValue;
} GDALGridDataMetricsOptions;
/** Linear method control options */
typedef struct
{
/*! In case the point to be interpolated does not fit into a triangle of
* the Delaunay triangulation, use that maximum distance to search a nearest
* neighbour, or use nodata otherwise. If set to -1, the search distance is infinite.
* If set to 0, nodata value will be always used.
*/
double dfRadius;
/*! No data marker to fill empty points. */
double dfNoDataValue;
} GDALGridLinearOptions;
CPLErr CPL_DLL
GDALGridCreate( GDALGridAlgorithm, const void *, GUInt32,
const double *, const double *, const double *,
double, double, double, double,
GUInt32, GUInt32, GDALDataType, void *,
GDALProgressFunc, void *);
/** Grid context opaque type */
typedef struct GDALGridContext GDALGridContext;
GDALGridContext CPL_DLL*
GDALGridContextCreate( GDALGridAlgorithm eAlgorithm, const void *poOptions,
GUInt32 nPoints,
const double *padfX, const double *padfY, const double *padfZ,
int bCallerWillKeepPointArraysAlive );
void CPL_DLL GDALGridContextFree(GDALGridContext* psContext);
CPLErr CPL_DLL GDALGridContextProcess(GDALGridContext* psContext,
double dfXMin, double dfXMax, double dfYMin, double dfYMax,
GUInt32 nXSize, GUInt32 nYSize, GDALDataType eType, void *pData,
GDALProgressFunc pfnProgress, void *pProgressArg );
GDAL_GCP CPL_DLL *
GDALComputeMatchingPoints( GDALDatasetH hFirstImage,
GDALDatasetH hSecondImage,
char **papszOptions,
int *pnGCPCount );
/************************************************************************/
/* Delaunay triangulation interface. */
/************************************************************************/
/** Triangle fact */
typedef struct
{
int anVertexIdx[3]; /**< index to the padfX/padfY arrays */
int anNeighborIdx[3]; /**< index to GDALDelaunayTriangulation.pasFacets, or -1 */
/* anNeighborIdx[k] is the triangle to the opposite side */
/* of the opposite segment of anVertexIdx[k] */
} GDALTriFacet;
/** Triangle barycentric coefficients.
*
* Conversion from cartesian (x,y) to barycentric (l1,l2,l3) with :
* l1 = dfMul1X * (x - dfCxtX) + dfMul1Y * (y - dfCstY)
* l2 = dfMul2X * (x - dfCxtX) + dfMul2Y * (y - dfCstY)
* l3 = 1 - l1 - l2
*/
typedef struct
{
double dfMul1X; /**< dfMul1X */
double dfMul1Y; /**< dfMul1Y */
double dfMul2X; /**< dfMul2X */
double dfMul2Y; /**< dfMul2Y */
double dfCstX; /**< dfCstX */
double dfCstY; /**< dfCstY */
} GDALTriBarycentricCoefficients;
/** Triangulation structure */
typedef struct
{
int nFacets; /**< number of facets */
GDALTriFacet *pasFacets; /**< array of nFacets facets */
GDALTriBarycentricCoefficients *pasFacetCoefficients; /**< arra of nFacets barycentric coefficients */
} GDALTriangulation;
int CPL_DLL GDALHasTriangulation(void);
GDALTriangulation CPL_DLL *GDALTriangulationCreateDelaunay(int nPoints,
const double* padfX,
const double* padfY);
int CPL_DLL GDALTriangulationComputeBarycentricCoefficients(
GDALTriangulation* psDT,
const double* padfX,
const double* padfY);
int CPL_DLL GDALTriangulationComputeBarycentricCoordinates(
const GDALTriangulation* psDT,
int nFacetIdx,
double dfX,
double dfY,
double* pdfL1,
double* pdfL2,
double* pdfL3);
int CPL_DLL GDALTriangulationFindFacetBruteForce( const GDALTriangulation* psDT,
double dfX,
double dfY,
int* panOutputFacetIdx );
int CPL_DLL GDALTriangulationFindFacetDirected( const GDALTriangulation* psDT,
int nFacetIdx,
double dfX,
double dfY,
int* panOutputFacetIdx );
void CPL_DLL GDALTriangulationFree(GDALTriangulation* psDT);
/*! @cond Doxygen_Suppress */
// GDAL internal use only
void GDALTriangulationTerminate(void);
/*! @endcond */
GDALDatasetH CPL_DLL GDALOpenVerticalShiftGrid(
const char* pszProj4Geoidgrids,
int* pbError );
GDALDatasetH CPL_DLL GDALApplyVerticalShiftGrid( GDALDatasetH hSrcDataset,
GDALDatasetH hGridDataset,
int bInverse,
double dfSrcUnitToMeter,
double dfDstUnitToMeter,
const char* const* papszOptions );
CPL_C_END
#endif /* ndef GDAL_ALG_H_INCLUDED */

View File

@@ -0,0 +1,222 @@
/******************************************************************************
* $Id: gdal_alg_priv.h fe2d81c8819bf9794bce0210098e637565728350 2018-05-06 00:49:51 +0200 Even Rouault $
*
* Project: GDAL Image Processing Algorithms
* Purpose: Prototypes and definitions for various GDAL based algorithms:
* private declarations.
* Author: Andrey Kiselev, dron@ak4719.spb.edu
*
******************************************************************************
* Copyright (c) 2008, Andrey Kiselev <dron@ak4719.spb.edu>
* Copyright (c) 2010-2013, Even Rouault <even dot rouault at mines-paris dot org>
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included
* in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
****************************************************************************/
#ifndef GDAL_ALG_PRIV_H_INCLUDED
#define GDAL_ALG_PRIV_H_INCLUDED
#ifndef DOXYGEN_SKIP
#include "gdal_alg.h"
CPL_C_START
/** Source of the burn value */
typedef enum {
/*! Use value from padfBurnValue */ GBV_UserBurnValue = 0,
/*! Use value from the Z coordinate */ GBV_Z = 1,
/*! Use value form the M value */ GBV_M = 2
} GDALBurnValueSrc;
typedef enum {
GRMA_Replace = 0,
GRMA_Add = 1,
} GDALRasterMergeAlg;
typedef struct {
unsigned char * pabyChunkBuf;
int nXSize;
int nYSize;
int nBands;
GDALDataType eType;
double *padfBurnValue;
GDALBurnValueSrc eBurnValueSource;
GDALRasterMergeAlg eMergeAlg;
} GDALRasterizeInfo;
typedef enum {
GRO_Raster = 0,
GRO_Vector = 1,
GRO_Auto = 2,
} GDALRasterizeOptim;
/************************************************************************/
/* Low level rasterizer API. */
/************************************************************************/
typedef void (*llScanlineFunc)( void *, int, int, int, double );
typedef void (*llPointFunc)( void *, int, int, double );
void GDALdllImagePoint( int nRasterXSize, int nRasterYSize,
int nPartCount, int *panPartSize,
double *padfX, double *padfY, double *padfVariant,
llPointFunc pfnPointFunc, void *pCBData );
void GDALdllImageLine( int nRasterXSize, int nRasterYSize,
int nPartCount, int *panPartSize,
double *padfX, double *padfY, double *padfVariant,
llPointFunc pfnPointFunc, void *pCBData );
void GDALdllImageLineAllTouched( int nRasterXSize, int nRasterYSize,
int nPartCount, int *panPartSize,
double *padfX, double *padfY,
double *padfVariant,
llPointFunc pfnPointFunc, void *pCBData );
void GDALdllImageFilledPolygon( int nRasterXSize, int nRasterYSize,
int nPartCount, int *panPartSize,
double *padfX, double *padfY,
double *padfVariant,
llScanlineFunc pfnScanlineFunc, void *pCBData );
CPL_C_END
/************************************************************************/
/* Polygon Enumerator */
/************************************************************************/
#define GP_NODATA_MARKER -51502112
template<class DataType, class EqualityTest> class GDALRasterPolygonEnumeratorT
{
private:
void MergePolygon( int nSrcId, int nDstId );
int NewPolygon( DataType nValue );
CPL_DISALLOW_COPY_ASSIGN(GDALRasterPolygonEnumeratorT)
public: // these are intended to be readonly.
GInt32 *panPolyIdMap = nullptr;
DataType *panPolyValue = nullptr;
int nNextPolygonId = 0;
int nPolyAlloc = 0;
int nConnectedness = 0;
public:
explicit GDALRasterPolygonEnumeratorT( int nConnectedness=4 );
~GDALRasterPolygonEnumeratorT();
void ProcessLine( DataType *panLastLineVal, DataType *panThisLineVal,
GInt32 *panLastLineId, GInt32 *panThisLineId,
int nXSize );
void CompleteMerges();
void Clear();
};
struct IntEqualityTest
{
bool operator()(GInt32 a, GInt32 b) const { return a == b; }
};
typedef GDALRasterPolygonEnumeratorT<GInt32, IntEqualityTest> GDALRasterPolygonEnumerator;
typedef void* (*GDALTransformDeserializeFunc)( CPLXMLNode *psTree );
void CPL_DLL *GDALRegisterTransformDeserializer(const char* pszTransformName,
GDALTransformerFunc pfnTransformerFunc,
GDALTransformDeserializeFunc pfnDeserializeFunc);
void CPL_DLL GDALUnregisterTransformDeserializer(void* pData);
void GDALCleanupTransformDeserializerMutex();
/* Transformer cloning */
void* GDALCreateTPSTransformerInt( int nGCPCount, const GDAL_GCP *pasGCPList,
int bReversed, char** papszOptions );
void CPL_DLL * GDALCloneTransformer( void *pTransformerArg );
/************************************************************************/
/* Color table related */
/************************************************************************/
// Definitions exists for T = GUInt32 and T = GUIntBig.
template<class T> int
GDALComputeMedianCutPCTInternal( GDALRasterBandH hRed,
GDALRasterBandH hGreen,
GDALRasterBandH hBlue,
GByte* pabyRedBand,
GByte* pabyGreenBand,
GByte* pabyBlueBand,
int (*pfnIncludePixel)(int,int,void*),
int nColors,
int nBits,
T* panHistogram,
GDALColorTableH hColorTable,
GDALProgressFunc pfnProgress,
void * pProgressArg );
int GDALDitherRGB2PCTInternal( GDALRasterBandH hRed,
GDALRasterBandH hGreen,
GDALRasterBandH hBlue,
GDALRasterBandH hTarget,
GDALColorTableH hColorTable,
int nBits,
GInt16* pasDynamicColorMap,
int bDither,
GDALProgressFunc pfnProgress,
void * pProgressArg );
#define PRIME_FOR_65536 98317
// See HashHistogram structure in gdalmediancut.cpp and ColorIndex structure in
// gdaldither.cpp 6 * sizeof(int) should be the size of the largest of both
// structures.
#define MEDIAN_CUT_AND_DITHER_BUFFER_SIZE_65536 (6 * sizeof(int) * PRIME_FOR_65536)
/************************************************************************/
/* Float comparison function. */
/************************************************************************/
/**
* Units in the Last Place. This specifies how big an error we are willing to
* accept in terms of the value of the least significant digit of the floating
* point numbers representation. MAX_ULPS can also be interpreted in terms of
* how many representable floats we are willing to accept between A and B.
*/
#define MAX_ULPS 10
GBool GDALFloatEquals(float A, float B);
struct FloatEqualityTest
{
bool operator()(float a, float b) { return GDALFloatEquals(a,b) == TRUE; }
};
#endif /* #ifndef DOXYGEN_SKIP */
#endif /* ndef GDAL_ALG_PRIV_H_INCLUDED */

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,310 @@
/******************************************************************************
* Project: GDAL
* Purpose: Correlator
* Author: Andrew Migal, migal.drew@gmail.com
*
******************************************************************************
* Copyright (c) 2012, Andrew Migal
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included
* in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
****************************************************************************/
#include "gdal_simplesurf.h"
CPL_CVSID("$Id: gdal_octave.cpp fe2d81c8819bf9794bce0210098e637565728350 2018-05-06 00:49:51 +0200 Even Rouault $")
/************************************************************************/
/* ==================================================================== */
/* GDALIntegralImage */
/* ==================================================================== */
/************************************************************************/
GDALIntegralImage::GDALIntegralImage() = default;
int GDALIntegralImage::GetHeight() { return nHeight; }
int GDALIntegralImage::GetWidth() { return nWidth; }
void GDALIntegralImage::Initialize( const double **padfImg,
int nHeightIn, int nWidthIn )
{
if( pMatrix )
{
for( int i = 0; i < nHeight; i++ )
delete[] pMatrix[i];
delete[] pMatrix;
}
// Memory allocation.
pMatrix = new double*[nHeightIn];
for( int i = 0; i < nHeightIn; i++ )
pMatrix[i] = new double[nWidthIn];
nHeight = nHeightIn;
nWidth = nWidthIn;
// Integral image calculation.
for( int i = 0; i < nHeight; i++ )
for( int j = 0; j < nWidth; j++ )
{
const double val = padfImg[i][j];
double a = 0.0;
double b = 0.0;
double c = 0.0;
if( i - 1 >= 0 && j - 1 >= 0 )
a = pMatrix[i - 1][j - 1];
if( j - 1 >= 0 )
b = pMatrix[i][j - 1];
if( i - 1 >= 0 )
c = pMatrix[i - 1][j];
// New value based on previous calculations.
pMatrix[i][j] = val - a + b + c;
}
}
/*
* Returns value of specified cell.
*/
double GDALIntegralImage::GetValue( int nRow, int nCol )
{
if( !((nRow >= 0 && nRow < nHeight) && (nCol >= 0 && nCol < nWidth)) )
return 0;
return pMatrix[nRow][nCol];
}
double GDALIntegralImage::GetRectangleSum( int nRow, int nCol,
int nWidthIn, int nHeightIn )
{
// Left top point of rectangle is first.
const int w = nWidthIn - 1;
const int h = nHeightIn - 1;
const int row = nRow;
const int col = nCol;
// Left top point.
const int lt_row = (row <= nHeight) ? (row - 1) : -1;
const int lt_col = (col <= nWidth) ? (col - 1) : -1;
// Right bottom point of the rectangle.
const int rb_row = (row + h < nHeight) ? (row + h) : (nHeight - 1);
const int rb_col = (col + w < nWidth) ? (col + w) : (nWidth - 1);
double a = 0.0;
double b = 0.0;
double c = 0.0;
double d = 0.0;
if( lt_row >= 0 && lt_col >= 0 )
a = GetValue(lt_row, lt_col);
if( lt_row >= 0 && rb_col >= 0 )
b = GetValue(lt_row, rb_col);
if( rb_row >= 0 && rb_col >= 0 )
c = GetValue(rb_row, rb_col);
if( rb_row >= 0 && lt_col >= 0 )
d = GetValue(rb_row, lt_col);
const double res = a + c - b - d;
return res > 0 ? res : 0;
}
double GDALIntegralImage::HaarWavelet_X( int nRow, int nCol, int nSize )
{
return GetRectangleSum(nRow, nCol + nSize / 2, nSize / 2, nSize)
- GetRectangleSum(nRow, nCol, nSize / 2, nSize);
}
double GDALIntegralImage::HaarWavelet_Y( int nRow, int nCol, int nSize )
{
return GetRectangleSum(nRow + nSize / 2, nCol, nSize, nSize / 2)
- GetRectangleSum(nRow, nCol, nSize, nSize / 2);
}
GDALIntegralImage::~GDALIntegralImage()
{
// Clean up memory.
for( int i = 0; i < nHeight; i++ )
delete[] pMatrix[i];
delete[] pMatrix;
}
/************************************************************************/
/* ==================================================================== */
/* GDALOctaveLayer */
/* ==================================================================== */
/************************************************************************/
GDALOctaveLayer::GDALOctaveLayer( int nOctave, int nInterval ) :
octaveNum(nOctave),
filterSize(3 * static_cast<int>(pow(2.0, nOctave)) * nInterval + 1),
radius((filterSize - 1) / 2),
scale(static_cast<int>(pow(2.0, nOctave))),
width(0),
height(0),
detHessians(nullptr),
signs(nullptr)
{}
void GDALOctaveLayer::ComputeLayer( GDALIntegralImage *poImg )
{
width = poImg->GetWidth();
height = poImg->GetHeight();
// Allocate memory for arrays.
detHessians = new double *[height];
signs = new int *[height];
for( int i = 0; i < height; i++ )
{
detHessians[i] = new double[width];
signs[i] = new int[width];
}
// Values of Fast Hessian filters.
double dxx = 0.0;
double dyy = 0.0;
double dxy = 0.0;
// 1/3 of filter side.
const int lobe = filterSize / 3;
// Length of the longer side of the lobe in dxx and dyy filters.
const int longPart = 2 * lobe - 1;
const int normalization = filterSize * filterSize;
// Loop over image pixels.
// Filter should remain into image borders.
for( int r = radius; r <= height - radius; r++ )
for( int c = radius; c <= width - radius; c++ )
{
dxx = poImg->GetRectangleSum(r - lobe + 1, c - radius,
filterSize, longPart)
- 3 * poImg->GetRectangleSum(r - lobe + 1, c - (lobe - 1) / 2,
lobe, longPart);
dyy = poImg->GetRectangleSum(r - radius, c - lobe - 1,
longPart, filterSize)
- 3 * poImg->GetRectangleSum(r - lobe + 1, c - lobe + 1,
longPart, lobe);
dxy = poImg->GetRectangleSum(r - lobe, c - lobe, lobe, lobe)
+ poImg->GetRectangleSum(r + 1, c + 1, lobe, lobe)
- poImg->GetRectangleSum(r - lobe, c + 1, lobe, lobe)
- poImg->GetRectangleSum(r + 1, c - lobe, lobe, lobe);
dxx /= normalization;
dyy /= normalization;
dxy /= normalization;
// Memorize Hessian values and their signs.
detHessians[r][c] = dxx * dyy - 0.9 * 0.9 * dxy * dxy;
signs[r][c] = (dxx + dyy >= 0) ? 1 : -1;
}
}
GDALOctaveLayer::~GDALOctaveLayer()
{
for( int i = 0; i < height; i++ )
{
delete[] detHessians[i];
delete[] signs[i];
}
delete[] detHessians;
delete[] signs;
}
/************************************************************************/
/* ==================================================================== */
/* GDALOctaveMap */
/* ==================================================================== */
/************************************************************************/
GDALOctaveMap::GDALOctaveMap( int nOctaveStartIn, int nOctaveEndIn ) :
pMap(new GDALOctaveLayer**[nOctaveEndIn]),
octaveStart(nOctaveStartIn),
octaveEnd(nOctaveEndIn)
{
for( int i = 0; i < octaveEnd; i++ )
pMap[i] = new GDALOctaveLayer *[INTERVALS];
for( int oct = octaveStart; oct <= octaveEnd; oct++ )
for( int i = 1; i <= INTERVALS; i++ )
pMap[oct - 1][i - 1] = new GDALOctaveLayer(oct, i);
}
void GDALOctaveMap::ComputeMap( GDALIntegralImage *poImg )
{
for( int oct = octaveStart; oct <= octaveEnd; oct++ )
for( int i = 1; i <= INTERVALS; i++ )
pMap[oct - 1][i - 1]->ComputeLayer(poImg);
}
bool GDALOctaveMap::PointIsExtremum( int row, int col, GDALOctaveLayer *bot,
GDALOctaveLayer *mid, GDALOctaveLayer *top,
double threshold )
{
// Check that point in middle layer has all neighbors.
if( row <= top->radius || col <= top->radius ||
row + top->radius >= top->height || col + top->radius >= top->width )
return false;
const double curPoint = mid->detHessians[row][col];
// Hessian should be higher than threshold.
if( curPoint < threshold )
return false;
// Hessian should be higher than Hessians of all neighbors.
for( int i = -1; i <= 1; i++ )
for( int j = -1; j <= 1; j++ )
{
const double topPoint = top->detHessians[row + i][col + j];
const double midPoint = mid->detHessians[row + i][col + j];
const double botPoint = bot->detHessians[row + i][col + j];
if( topPoint >= curPoint || botPoint >= curPoint )
return false;
if( i != 0 || j != 0 )
if( midPoint >= curPoint )
return false;
}
return true;
}
GDALOctaveMap::~GDALOctaveMap()
{
// Clean up Octave layers.
for( int oct = octaveStart; oct <= octaveEnd; oct++ )
for( int i = 0; i < INTERVALS; i++ )
delete pMap[oct - 1][i];
// Clean up allocated memory.
for( int oct = 0; oct < octaveEnd; oct++ )
delete[] pMap[oct];
delete[] pMap;
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,524 @@
/******************************************************************************
* Project: GDAL
* Purpose: Correlator - GDALSimpleSURF and GDALFeaturePoint classes.
* Author: Andrew Migal, migal.drew@gmail.com
*
******************************************************************************
* Copyright (c) 2012, Andrew Migal
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included
* in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
****************************************************************************/
#include "gdal_simplesurf.h"
#include <algorithm>
CPL_CVSID("$Id: gdal_simplesurf.cpp 7e07230bbff24eb333608de4dbd460b7312839d0 2017-12-11 19:08:47Z Even Rouault $")
/************************************************************************/
/* ==================================================================== */
/* GDALFeaturePoint */
/* ==================================================================== */
/************************************************************************/
GDALFeaturePoint::GDALFeaturePoint() :
nX(-1),
nY(-1),
nScale(-1),
nRadius(-1),
nSign(-1),
padfDescriptor(new double[DESC_SIZE])
{}
GDALFeaturePoint::GDALFeaturePoint( const GDALFeaturePoint& fp ) :
nX(fp.nX),
nY(fp.nY),
nScale(fp.nScale),
nRadius(fp.nRadius),
nSign(fp.nSign),
padfDescriptor(new double[DESC_SIZE])
{
for( int i = 0; i < DESC_SIZE; i++ )
padfDescriptor[i] = fp.padfDescriptor[i];
}
GDALFeaturePoint::GDALFeaturePoint( int nXIn, int nYIn,
int nScaleIn, int nRadiusIn, int nSignIn ) :
nX(nXIn),
nY(nYIn),
nScale(nScaleIn),
nRadius(nRadiusIn),
nSign(nSignIn),
padfDescriptor(new double[DESC_SIZE])
{}
GDALFeaturePoint& GDALFeaturePoint::operator=( const GDALFeaturePoint& point )
{
if( this == &point )
return *this;
nX = point.nX;
nY = point.nY;
nScale = point.nScale;
nRadius = point.nRadius;
nSign = point.nSign;
// Free memory.
delete[] padfDescriptor;
// Copy descriptor values.
padfDescriptor = new double[DESC_SIZE];
for( int i = 0; i < DESC_SIZE; i++ )
padfDescriptor[i] = point.padfDescriptor[i];
return *this;
}
int GDALFeaturePoint::GetX() const { return nX; }
void GDALFeaturePoint::SetX( int nXIn ) { nX = nXIn; }
int GDALFeaturePoint::GetY() const { return nY; }
void GDALFeaturePoint::SetY( int nYIn ) { nY = nYIn; }
int GDALFeaturePoint::GetScale() const { return nScale; }
void GDALFeaturePoint::SetScale( int nScaleIn ) { nScale = nScaleIn; }
int GDALFeaturePoint::GetRadius() const { return nRadius; }
void GDALFeaturePoint::SetRadius( int nRadiusIn ) { nRadius = nRadiusIn; }
int GDALFeaturePoint::GetSign() const { return nSign; }
void GDALFeaturePoint::SetSign( int nSignIn ) { nSign = nSignIn; }
double& GDALFeaturePoint::operator [] (int nIndex)
{
if( nIndex < 0 || nIndex >= DESC_SIZE )
{
CPLError(CE_Failure, CPLE_AppDefined,
"Descriptor index is out of range");
}
return padfDescriptor[nIndex];
}
GDALFeaturePoint::~GDALFeaturePoint() {
delete[] padfDescriptor;
}
/************************************************************************/
/* ==================================================================== */
/* GDALSimpleSurf */
/* ==================================================================== */
/************************************************************************/
GDALSimpleSURF::GDALSimpleSURF( int nOctaveStartIn, int nOctaveEndIn ) :
octaveStart(nOctaveStartIn),
octaveEnd(nOctaveEndIn),
// Initialize Octave map with custom range.
poOctMap(new GDALOctaveMap(nOctaveStartIn, nOctaveEndIn))
{}
CPLErr GDALSimpleSURF::ConvertRGBToLuminosity(
GDALRasterBand *red, GDALRasterBand *green, GDALRasterBand *blue,
int nXSize, int nYSize, double **padfImg, int nHeight, int nWidth )
{
if( red == nullptr || green == nullptr || blue == nullptr )
{
CPLError(CE_Failure, CPLE_AppDefined,
"Raster bands are not specified");
return CE_Failure;
}
if( nXSize > red->GetXSize() || nYSize > red->GetYSize() )
{
CPLError(CE_Failure, CPLE_AppDefined,
"Red band has less size than has been requested");
return CE_Failure;
}
if( padfImg == nullptr )
{
CPLError(CE_Failure, CPLE_AppDefined, "Buffer isn't specified");
return CE_Failure;
}
const double forRed = 0.21;
const double forGreen = 0.72;
const double forBlue = 0.07;
const GDALDataType eRedType = red->GetRasterDataType();
const GDALDataType eGreenType = green->GetRasterDataType();
const GDALDataType eBlueType = blue->GetRasterDataType();
const int dataRedSize = GDALGetDataTypeSizeBytes(eRedType);
const int dataGreenSize = GDALGetDataTypeSizeBytes(eGreenType);
const int dataBlueSize = GDALGetDataTypeSizeBytes(eBlueType);
void *paRedLayer = CPLMalloc(dataRedSize * nWidth * nHeight);
void *paGreenLayer = CPLMalloc(dataGreenSize * nWidth * nHeight);
void *paBlueLayer = CPLMalloc(dataBlueSize * nWidth * nHeight);
CPLErr eErr = red->RasterIO(GF_Read, 0, 0, nXSize, nYSize, paRedLayer,
nWidth, nHeight, eRedType, 0, 0, nullptr);
if( eErr == CE_None )
eErr = green->RasterIO(GF_Read, 0, 0, nXSize, nYSize, paGreenLayer,
nWidth, nHeight, eGreenType, 0, 0, nullptr);
if( eErr == CE_None )
eErr = blue->RasterIO(GF_Read, 0, 0, nXSize, nYSize, paBlueLayer,
nWidth, nHeight, eBlueType, 0, 0, nullptr);
double maxValue = 255.0;
for( int row = 0; row < nHeight && eErr == CE_None; row++ )
for( int col = 0; col < nWidth; col++ )
{
// Get RGB values.
const double dfRedVal = SRCVAL(paRedLayer, eRedType,
nWidth * row + col * dataRedSize);
const double dfGreenVal =
SRCVAL(paGreenLayer, eGreenType,
nWidth * row + col * dataGreenSize);
const double dfBlueVal = SRCVAL(paBlueLayer, eBlueType,
nWidth * row + col * dataBlueSize);
// Compute luminosity value.
padfImg[row][col] = (
dfRedVal * forRed +
dfGreenVal * forGreen +
dfBlueVal * forBlue) / maxValue;
}
CPLFree(paRedLayer);
CPLFree(paGreenLayer);
CPLFree(paBlueLayer);
return eErr;
}
std::vector<GDALFeaturePoint>*
GDALSimpleSURF::ExtractFeaturePoints( GDALIntegralImage *poImg,
double dfThreshold )
{
std::vector<GDALFeaturePoint>* poCollection =
new std::vector<GDALFeaturePoint>();
// Calc Hessian values for layers.
poOctMap->ComputeMap(poImg);
// Search for extremum points.
for( int oct = octaveStart; oct <= octaveEnd; oct++ )
{
for( int k = 0; k < GDALOctaveMap::INTERVALS - 2; k++ )
{
GDALOctaveLayer *bot = poOctMap->pMap[oct - 1][k];
GDALOctaveLayer *mid = poOctMap->pMap[oct - 1][k + 1];
GDALOctaveLayer *top = poOctMap->pMap[oct - 1][k + 2];
for( int i = 0; i < mid->height; i++ )
{
for( int j = 0; j < mid->width; j++ )
{
if( poOctMap->PointIsExtremum(i, j, bot, mid, top,
dfThreshold) )
{
GDALFeaturePoint oFP(j, i, mid->scale,
mid->radius, mid->signs[i][j]);
SetDescriptor(&oFP, poImg);
poCollection->push_back(oFP);
}
}
}
}
}
return poCollection;
}
double GDALSimpleSURF::GetEuclideanDistance(
GDALFeaturePoint &firstPoint, GDALFeaturePoint &secondPoint)
{
double sum = 0.0;
for( int i = 0; i < GDALFeaturePoint::DESC_SIZE; i++ )
sum += (firstPoint[i] - secondPoint[i]) *
(firstPoint[i] - secondPoint[i]);
return sqrt(sum);
}
void GDALSimpleSURF::NormalizeDistances(std::list<MatchedPointPairInfo> *poList)
{
double max = 0.0;
std::list<MatchedPointPairInfo>::iterator i;
for( i = poList->begin(); i != poList->end(); ++i )
if( (*i).euclideanDist > max )
max = (*i).euclideanDist;
if( max != 0.0 )
{
for( i = poList->begin(); i != poList->end(); ++i )
(*i).euclideanDist /= max;
}
}
void GDALSimpleSURF::SetDescriptor(
GDALFeaturePoint *poPoint, GDALIntegralImage *poImg )
{
// Affects to the descriptor area.
const int haarScale = 20;
// Side of the Haar wavelet.
const int haarFilterSize = 2 * poPoint->GetScale();
// Length of the side of the descriptor area.
const int descSide = haarScale * poPoint->GetScale();
// Side of the quadrant in 4x4 grid.
const int quadStep = descSide / 4;
// Side of the sub-quadrant in 5x5 regular grid of quadrant.
const int subQuadStep = quadStep / 5;
const int leftTop_row = poPoint->GetY() - (descSide / 2);
const int leftTop_col = poPoint->GetX() - (descSide / 2);
int count = 0;
for( int r = leftTop_row; r < leftTop_row + descSide; r += quadStep )
for( int c = leftTop_col; c < leftTop_col + descSide; c += quadStep )
{
double dx = 0;
double dy = 0;
double abs_dx = 0;
double abs_dy = 0;
for( int sub_r = r; sub_r < r + quadStep; sub_r += subQuadStep )
for( int sub_c = c; sub_c < c + quadStep; sub_c += subQuadStep )
{
// Approximate center of sub quadrant.
const int cntr_r = sub_r + subQuadStep / 2;
const int cntr_c = sub_c + subQuadStep / 2;
// Left top point for Haar wavelet computation.
const int cur_r = cntr_r - haarFilterSize / 2;
const int cur_c = cntr_c - haarFilterSize / 2;
// Gradients.
const double cur_dx =
poImg->HaarWavelet_X(cur_r, cur_c, haarFilterSize);
const double cur_dy =
poImg->HaarWavelet_Y(cur_r, cur_c, haarFilterSize);
dx += cur_dx;
dy += cur_dy;
abs_dx += fabs(cur_dx);
abs_dy += fabs(cur_dy);
}
// Fills point's descriptor.
(*poPoint)[count++] = dx;
(*poPoint)[count++] = dy;
(*poPoint)[count++] = abs_dx;
(*poPoint)[count++] = abs_dy;
}
}
// TODO(schwehr): What does "value is 0,1." mean? Is that 0 to 1 or 0.1?
// TODO(schwehr): 0,001?
/**
* Find corresponding points (equal points in two collections).
*
* @param poMatchPairs Resulting collection for matched points
* @param poFirstCollect Points on the first image
* @param poSecondCollect Points on the second image
* @param dfThreshold Value from 0 to 1. Threshold affects to number of
* matched points. If threshold is higher, amount of corresponding
* points is larger, and vice versa
*
* @note Typical threshold's value is 0,1. BUT it's a very approximate guide.
* It can be 0,001 or even 1. This threshold provides direct adjustment
* of point matching.
* NOTICE that if threshold is lower, matches are more robust and correct, but
* number of matched points is smaller. Therefore if algorithm performs many
* false detections and produces bad results, reduce threshold. Otherwise, if
* algorithm finds nothing, increase threshold.
*
* @return CE_None or CE_Failure if error occurs.
*/
CPLErr GDALSimpleSURF::MatchFeaturePoints(
std::vector<GDALFeaturePoint*> *poMatchPairs,
std::vector<GDALFeaturePoint> *poFirstCollect,
std::vector<GDALFeaturePoint> *poSecondCollect,
double dfThreshold )
{
/* -------------------------------------------------------------------- */
/* Validate parameters. */
/* -------------------------------------------------------------------- */
if( poMatchPairs == nullptr )
{
CPLError( CE_Failure, CPLE_AppDefined,
"Matched points collection isn't specified" );
return CE_Failure;
}
if( poFirstCollect == nullptr || poSecondCollect == nullptr )
{
CPLError(CE_Failure, CPLE_AppDefined,
"Feature point collections are not specified");
return CE_Failure;
}
/* ==================================================================== */
/* Matching algorithm. */
/* ==================================================================== */
// Affects to false matching pruning.
const double ratioThreshold = 0.8;
int len_1 = static_cast<int>(poFirstCollect->size());
int len_2 = static_cast<int>(poSecondCollect->size());
const int minLength = std::min(len_1, len_2);
// Temporary pointers. Used to swap collections.
std::vector<GDALFeaturePoint> *p_1;
std::vector<GDALFeaturePoint> *p_2;
bool isSwap = false;
// Assign p_1 - collection with minimal number of points.
if( minLength == len_2 )
{
p_1 = poSecondCollect;
p_2 = poFirstCollect;
std::swap(len_1, len_2);
isSwap = true;
}
else
{
// Assignment 'as is'.
p_1 = poFirstCollect;
p_2 = poSecondCollect;
isSwap = false;
}
// Stores matched point indexes and their euclidean distances.
std::list<MatchedPointPairInfo> *poPairInfoList =
new std::list<MatchedPointPairInfo>();
// Flags that points in the 2nd collection are matched or not.
bool *alreadyMatched = new bool[len_2];
for( int i = 0; i < len_2; i++ )
alreadyMatched[i] = false;
for( int i = 0; i < len_1; i++ )
{
// Distance to the nearest point.
double bestDist = -1;
// Index of the nearest point in p_2 collection.
int bestIndex = -1;
// Distance to the 2nd nearest point.
double bestDist_2 = -1;
// Find the nearest and 2nd nearest points.
for( int j = 0; j < len_2; j++ )
if( !alreadyMatched[j] )
if( p_1->at(i).GetSign() == p_2->at(j).GetSign() )
{
// Get distance between two feature points.
double curDist = GetEuclideanDistance(
p_1->at(i), p_2->at(j));
if( bestDist == -1 )
{
bestDist = curDist;
bestIndex = j;
}
else
{
if( curDist < bestDist )
{
bestDist = curDist;
bestIndex = j;
}
}
// Findes the 2nd nearest point.
if( bestDist_2 < 0 )
bestDist_2 = curDist;
else
if( curDist > bestDist && curDist < bestDist_2 )
bestDist_2 = curDist;
}
/* -------------------------------------------------------------------- */
/* False matching pruning. */
/* If ratio bestDist to bestDist_2 greater than 0.8 => */
/* consider as false detection. */
/* Otherwise, add points as matched pair. */
/*----------------------------------------------------------------------*/
if( bestDist_2 > 0 && bestDist >= 0 )
if( bestDist / bestDist_2 < ratioThreshold )
{
MatchedPointPairInfo info(i, bestIndex, bestDist);
poPairInfoList->push_back(info);
alreadyMatched[bestIndex] = true;
}
}
/* -------------------------------------------------------------------- */
/* Pruning based on the provided threshold */
/* -------------------------------------------------------------------- */
NormalizeDistances(poPairInfoList);
std::list<MatchedPointPairInfo>::const_iterator iter;
for( iter = poPairInfoList->begin(); iter != poPairInfoList->end(); ++iter )
{
if( (*iter).euclideanDist <= dfThreshold )
{
const int i_1 = (*iter).ind_1;
const int i_2 = (*iter).ind_2;
// Add copies into MatchedCollection.
if( !isSwap )
{
poMatchPairs->push_back( &(p_1->at(i_1)) );
poMatchPairs->push_back( &(p_2->at(i_2)) );
}
else
{
poMatchPairs->push_back( &(p_2->at(i_2)) );
poMatchPairs->push_back( &(p_1->at(i_1)) );
}
}
}
// Clean up.
delete[] alreadyMatched;
delete poPairInfoList;
return CE_None;
}
GDALSimpleSURF::~GDALSimpleSURF()
{
delete poOctMap;
}

View File

@@ -0,0 +1,558 @@
/******************************************************************************
* $Id: gdal_simplesurf.h fe2d81c8819bf9794bce0210098e637565728350 2018-05-06 00:49:51 +0200 Even Rouault $
* Project: GDAL
* Purpose: Correlator
* Author: Andrew Migal, migal.drew@gmail.com
*
******************************************************************************
* Copyright (c) 2012, Andrew Migal
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included
* in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
****************************************************************************/
/**
* @file
* @author Andrew Migal migal.drew@gmail.com
* @brief Class for searching corresponding points on images.
*/
#ifndef GDALSIMPLESURF_H_
#define GDALSIMPLESURF_H_
#include "gdal_priv.h"
#include "cpl_conv.h"
#include <list>
/**
* @brief Class of "feature point" in raster. Used by SURF-based algorithm.
*
* @details This point presents coordinates of distinctive pixel in image.
* In computer vision, feature points - the most "strong" and "unique"
* pixels (or areas) in picture, which can be distinguished from others.
* For more details, see FAST corner detector, SIFT, SURF and similar algorithms.
*/
class GDALFeaturePoint
{
public:
/**
* Standard constructor. Initializes all parameters with negative numbers
* and allocates memory for descriptor.
*/
GDALFeaturePoint();
/**
* Copy constructor
* @param fp Copied instance of GDALFeaturePoint class
*/
GDALFeaturePoint(const GDALFeaturePoint& fp);
/**
* Create instance of GDALFeaturePoint class
*
* @param nX X-coordinate (pixel)
* @param nY Y-coordinate (line)
* @param nScale Scale which contains this point (2, 4, 8, 16 and so on)
* @param nRadius Half of the side of descriptor area
* @param nSign Sign of Hessian determinant for this point
*
* @note This constructor normally is invoked by SURF-based algorithm,
* which provides all necessary parameters.
*/
GDALFeaturePoint(int nX, int nY, int nScale, int nRadius, int nSign);
virtual ~GDALFeaturePoint();
/** Assignment operator */
GDALFeaturePoint& operator=(const GDALFeaturePoint& point);
/**
* Provide access to point's descriptor.
*
* @param nIndex Position of descriptor's value.
* nIndex should be within range from 0 to DESC_SIZE (in current version - 64)
*
* @return Reference to value of descriptor in 'nIndex' position.
* If index is out of range then behaviour is undefined.
*/
double& operator[](int nIndex);
/** Descriptor length */
static const int DESC_SIZE = 64;
/**
* Fetch X-coordinate (pixel) of point
*
* @return X-coordinate in pixels
*/
int GetX() const;
/**
* Set X coordinate of point
*
* @param nX X coordinate in pixels
*/
void SetX(int nX);
/**
* Fetch Y-coordinate (line) of point.
*
* @return Y-coordinate in pixels.
*/
int GetY() const;
/**
* Set Y coordinate of point.
*
* @param nY Y coordinate in pixels.
*/
void SetY(int nY);
/**
* Fetch scale of point.
*
* @return Scale for this point.
*/
int GetScale() const ;
/**
* Set scale of point.
*
* @param nScale Scale for this point.
*/
void SetScale(int nScale);
/**
* Fetch radius of point.
*
* @return Radius for this point.
*/
int GetRadius() const;
/**
* Set radius of point.
*
* @param nRadius Radius for this point.
*/
void SetRadius(int nRadius);
/**
* Fetch sign of Hessian determinant of point.
*
* @return Sign for this point.
*/
int GetSign() const;
/**
* Set sign of point.
*
* @param nSign Sign of Hessian determinant for this point.
*/
void SetSign(int nSign);
private:
// Coordinates of point in image
int nX;
int nY;
// --------------------
int nScale;
int nRadius;
int nSign;
// Descriptor array
double *padfDescriptor;
};
/**
* @author Andrew Migal migal.drew@gmail.com
* @brief Integral image class (summed area table).
* @details Integral image is a table for fast computing the sum of
* values in rectangular subarea. In more detail, for 2-dimensional array
* of numbers this class provides capability to get sum of values in
* rectangular arbitrary area with any size in constant time.
* Integral image is constructed from grayscale picture.
*/
class GDALIntegralImage
{
CPL_DISALLOW_COPY_ASSIGN(GDALIntegralImage)
public:
GDALIntegralImage();
virtual ~GDALIntegralImage();
/**
* Compute integral image for specified array. Result is stored internally.
*
* @param padfImg Pointer to 2-dimensional array of values
* @param nHeight Number of rows in array
* @param nWidth Number of columns in array
*/
void Initialize(const double **padfImg, int nHeight, int nWidth);
/**
* Fetch value of specified position in integral image.
*
* @param nRow Row of this position
* @param nCol Column of this position
*
* @return Value in specified position or zero if parameters are out of range.
*/
double GetValue(int nRow, int nCol);
/**
* Get sum of values in specified rectangular grid. Rectangle is constructed
* from left top point.
*
* @param nRow Row of left top point of rectangle
* @param nCol Column of left top point of rectangle
* @param nWidth Width of rectangular area (number of columns)
* @param nHeight Height of rectangular area (number of rows)
*
* @return Sum of values in specified grid.
*/
double GetRectangleSum(int nRow, int nCol, int nWidth, int nHeight);
/**
* Get value of horizontal Haar wavelet in specified square grid.
*
* @param nRow Row of left top point of square
* @param nCol Column of left top point of square
* @param nSize Side of the square
*
* @return Value of horizontal Haar wavelet in specified square grid.
*/
double HaarWavelet_X(int nRow, int nCol, int nSize);
/**
* Get value of vertical Haar wavelet in specified square grid.
*
* @param nRow Row of left top point of square
* @param nCol Column of left top point of square
* @param nSize Side of the square
*
* @return Value of vertical Haar wavelet in specified square grid.
*/
double HaarWavelet_Y(int nRow, int nCol, int nSize);
/**
* Fetch height of integral image.
*
* @return Height of integral image (number of rows).
*/
int GetHeight();
/**
* Fetch width of integral image.
*
* @return Width of integral image (number of columns).
*/
int GetWidth();
private:
double **pMatrix = nullptr;
int nWidth = 0;
int nHeight = 0;
};
/**
* @author Andrew Migal migal.drew@gmail.com
* @brief Class for computation and storage of Hessian values in SURF-based algorithm.
*
* @details SURF-based algorithm normally uses this class for searching
* feature points on raster images. Class also contains traces of Hessian matrices
* to provide fast computations.
*/
class GDALOctaveLayer
{
CPL_DISALLOW_COPY_ASSIGN(GDALOctaveLayer)
public:
GDALOctaveLayer();
/**
* Create instance with provided parameters.
*
* @param nOctave Number of octave which contains this layer
* @param nInterval Number of position in octave
*
* @note Normally constructor is invoked only by SURF-based algorithm.
*/
GDALOctaveLayer(int nOctave, int nInterval);
virtual ~GDALOctaveLayer();
/**
* Perform calculation of Hessian determinants and their signs
* for specified integral image. Result is stored internally.
*
* @param poImg Integral image object, which provides all necessary
* data for computation
*
* @note Normally method is invoked only by SURF-based algorithm.
*/
void ComputeLayer(GDALIntegralImage *poImg);
/**
* Octave which contains this layer (1,2,3...)
*/
int octaveNum;
/**
* Length of the side of filter
*/
int filterSize;
/**
* Length of the border
*/
int radius;
/**
* Scale for this layer
*/
int scale;
/**
* Image width in pixels
*/
int width;
/**
* Image height in pixels
*/
int height;
/**
* Hessian values for image pixels
*/
double **detHessians;
/**
* Hessian signs for speeded matching
*/
int **signs;
};
/**
* @author Andrew Migal migal.drew@gmail.com
* @brief Class for handling octave layers in SURF-based algorithm.
* @details Class contains OctaveLayers and provides capability to construct octave space and distinguish
* feature points. Normally this class is used only by SURF-based algorithm.
*/
class GDALOctaveMap
{
CPL_DISALLOW_COPY_ASSIGN( GDALOctaveMap )
public:
/**
* Create octave space. Octave numbers are start with one. (1, 2, 3, 4, ... )
*
* @param nOctaveStart Number of bottom octave
* @param nOctaveEnd Number of top octave. Should be equal or greater than OctaveStart
*/
GDALOctaveMap(int nOctaveStart, int nOctaveEnd);
virtual ~GDALOctaveMap();
/**
* Calculate Hessian values for octave space
* (for all stored octave layers) using specified integral image
* @param poImg Integral image instance which provides necessary data
* @see GDALOctaveLayer
*/
void ComputeMap(GDALIntegralImage *poImg);
/**
* Method makes decision that specified point
* in middle octave layer is maximum among all points
* from 3x3x3 neighbourhood (surrounding points in
* bottom, middle and top layers). Provided layers should be from the same octave's interval.
* Detects feature points.
*
* @param row Row of point, which is candidate to be feature point
* @param col Column of point, which is candidate to be feature point
* @param bot Bottom octave layer
* @param mid Middle octave layer
* @param top Top octave layer
* @param threshold Threshold for feature point recognition. Detected feature point
* will have Hessian value greater than this provided threshold.
*
* @return TRUE if candidate was evaluated as feature point or FALSE otherwise.
*/
static bool PointIsExtremum(int row, int col, GDALOctaveLayer *bot,
GDALOctaveLayer *mid, GDALOctaveLayer *top, double threshold);
/**
* 2-dimensional array of octave layers
*/
GDALOctaveLayer ***pMap;
/**
* Value for constructing internal octave space
*/
static const int INTERVALS = 4;
/**
* Number of bottom octave
*/
int octaveStart;
/**
* Number of top octave. Should be equal or greater than OctaveStart
*/
int octaveEnd;
};
/**
* @author Andrew Migal migal.drew@gmail.com
* @brief Class for searching corresponding points on images.
* @details Provides capability for detection feature points
* and finding equal points on different images.
* Class implements simplified version of SURF algorithm (Speeded Up Robust Features).
* As original, this realization is scale invariant, but sensitive to rotation.
* Images should have similar rotation angles (maximum difference is up to 10-15 degrees),
* otherwise algorithm produces incorrect and very unstable results.
*/
class GDALSimpleSURF
{
private:
/**
* Class stores indexes of pair of point
* and distance between them.
*/
class MatchedPointPairInfo
{
public:
MatchedPointPairInfo(int nInd_1, int nInd_2, double dfDist):
ind_1(nInd_1), ind_2(nInd_2), euclideanDist(dfDist) {}
int ind_1;
int ind_2;
double euclideanDist;
};
CPL_DISALLOW_COPY_ASSIGN( GDALSimpleSURF )
public:
/**
* Prepare class according to specified parameters. Octave numbers affects
* to amount of detected points and their robustness.
* Range between bottom and top octaves also affects to required time of detection points
* (if range is large, algorithm should perform more operations).
* @param nOctaveStart Number of bottom octave. Octave numbers starts with one
* @param nOctaveEnd Number of top octave. Should be equal or greater than OctaveStart
*
* @note
* Every octave finds points with specific size. For small images
* use small octave numbers, for high resolution - large.
* For 1024x1024 images it's normal to use any octave numbers from range 1-6.
* (for example, octave start - 1, octave end - 3, or octave start - 2, octave end - 2.)
* For larger images, try 1-10 range or even higher.
* Pay attention that number of detected point decreases quickly per octave
* for particular image. Algorithm finds more points in case of small octave numbers.
* If method detects nothing, reduce bottom bound of octave range.
*
* NOTICE that every octave requires time to compute. Use a little range
* or only one octave if execution time is significant.
*/
GDALSimpleSURF(int nOctaveStart, int nOctaveEnd);
virtual ~GDALSimpleSURF();
/**
* Convert image with RGB channels to grayscale using "luminosity" method.
* Result is used in SURF-based algorithm, but may be used anywhere where
* grayscale images with nice contrast are required.
*
* @param red Image's red channel
* @param green Image's green channel
* @param blue Image's blue channel
* @param nXSize Width of initial image
* @param nYSize Height of initial image
* @param padfImg Array for resulting grayscale image
* @param nHeight Height of resulting image
* @param nWidth Width of resulting image
*
* @return CE_None or CE_Failure if error occurs.
*/
static CPLErr ConvertRGBToLuminosity(
GDALRasterBand *red,
GDALRasterBand *green,
GDALRasterBand *blue,
int nXSize, int nYSize,
double **padfImg, int nHeight, int nWidth);
/**
* Find feature points using specified integral image.
*
* @param poImg Integral image to be used
* @param dfThreshold Threshold for feature point recognition. Detected feature point
* will have Hessian value greater than this provided threshold.
*
* @note Typical threshold's value is 0,001. But this value
* can be various in each case and depends on image's nature.
* For example, value can be 0.002 or 0.005.
* Fill free to experiment with it.
* If threshold is high, than number of detected feature points is small,
* and vice versa.
*/
std::vector<GDALFeaturePoint>*
ExtractFeaturePoints(GDALIntegralImage *poImg, double dfThreshold);
/**
* Find corresponding points (equal points in two collections).
*
* @param poMatchPairs Resulting collection for matched points
* @param poFirstCollect Points on the first image
* @param poSecondCollect Points on the second image
* @param dfThreshold Value from 0 to 1. Threshold affects to number of
* matched points. If threshold is lower, amount of corresponding
* points is larger, and vice versa
*
* @return CE_None or CE_Failure if error occurs.
*/
static CPLErr MatchFeaturePoints(
std::vector<GDALFeaturePoint*> *poMatchPairs,
std::vector<GDALFeaturePoint> *poFirstCollect,
std::vector<GDALFeaturePoint> *poSecondCollect,
double dfThreshold);
private:
/**
* Compute euclidean distance between descriptors of two feature points.
* It's used in comparison and matching of points.
*
* @param firstPoint First feature point to be compared
* @param secondPoint Second feature point to be compared
*
* @return Euclidean distance between descriptors.
*/
static double GetEuclideanDistance(
GDALFeaturePoint &firstPoint, GDALFeaturePoint &secondPoint);
/**
* Set provided distance values to range from 0 to 1.
*
* @param poList List of distances to be normalized
*/
static void NormalizeDistances(std::list<MatchedPointPairInfo> *poList);
/**
* Compute descriptor for specified feature point.
*
* @param poPoint Feature point instance
* @param poImg image where feature point was found
*/
static void SetDescriptor(GDALFeaturePoint *poPoint, GDALIntegralImage *poImg);
private:
int octaveStart;
int octaveEnd;
GDALOctaveMap *poOctMap;
};
#endif /* GDALSIMPLESURF_H_ */

View File

@@ -0,0 +1,464 @@
/******************************************************************************
*
* Project: High Performance Image Reprojector
* Purpose: Thin Plate Spline transformer (GDAL wrapper portion)
* Author: Frank Warmerdam, warmerdam@pobox.com
*
******************************************************************************
* Copyright (c) 2004, Frank Warmerdam <warmerdam@pobox.com>
* Copyright (c) 2011-2013, Even Rouault <even dot rouault at mines-paris dot org>
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included
* in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
****************************************************************************/
#include "cpl_port.h"
#include "thinplatespline.h"
#include <stdlib.h>
#include <string.h>
#include <map>
#include <utility>
#include "cpl_atomic_ops.h"
#include "cpl_conv.h"
#include "cpl_error.h"
#include "cpl_minixml.h"
#include "cpl_multiproc.h"
#include "cpl_string.h"
#include "gdal.h"
#include "gdal_alg.h"
#include "gdal_alg_priv.h"
#include "gdal_priv.h"
CPL_CVSID("$Id: gdal_tps.cpp 7e07230bbff24eb333608de4dbd460b7312839d0 2017-12-11 19:08:47Z Even Rouault $")
CPL_C_START
CPLXMLNode *GDALSerializeTPSTransformer( void *pTransformArg );
void *GDALDeserializeTPSTransformer( CPLXMLNode *psTree );
CPL_C_END
typedef struct
{
GDALTransformerInfo sTI;
VizGeorefSpline2D *poForward;
VizGeorefSpline2D *poReverse;
bool bForwardSolved;
bool bReverseSolved;
bool bReversed;
int nGCPCount;
GDAL_GCP *pasGCPList;
volatile int nRefCount;
} TPSTransformInfo;
/************************************************************************/
/* GDALCreateSimilarTPSTransformer() */
/************************************************************************/
static
void* GDALCreateSimilarTPSTransformer( void *hTransformArg,
double dfRatioX, double dfRatioY )
{
VALIDATE_POINTER1( hTransformArg, "GDALCreateSimilarTPSTransformer", nullptr );
TPSTransformInfo *psInfo = static_cast<TPSTransformInfo *>(hTransformArg);
if( dfRatioX == 1.0 && dfRatioY == 1.0 )
{
// We can just use a ref count, since using the source transformation
// is thread-safe.
CPLAtomicInc(&(psInfo->nRefCount));
}
else
{
GDAL_GCP *pasGCPList = GDALDuplicateGCPs( psInfo->nGCPCount,
psInfo->pasGCPList );
for( int i = 0; i < psInfo->nGCPCount; i++ )
{
pasGCPList[i].dfGCPPixel /= dfRatioX;
pasGCPList[i].dfGCPLine /= dfRatioY;
}
psInfo = static_cast<TPSTransformInfo *>(
GDALCreateTPSTransformer( psInfo->nGCPCount, pasGCPList,
psInfo->bReversed ));
GDALDeinitGCPs( psInfo->nGCPCount, pasGCPList );
CPLFree( pasGCPList );
}
return psInfo;
}
/************************************************************************/
/* GDALCreateTPSTransformer() */
/************************************************************************/
/**
* Create Thin Plate Spline transformer from GCPs.
*
* The thin plate spline transformer produces exact transformation
* at all control points and smoothly varying transformations between
* control points with greatest influence from local control points.
* It is suitable for for many applications not well modeled by polynomial
* transformations.
*
* Creating the TPS transformer involves solving systems of linear equations
* related to the number of control points involved. This solution is
* computed within this function call. It can be quite an expensive operation
* for large numbers of GCPs. For instance, for reference, it takes on the
* order of 10s for 400 GCPs on a 2GHz Athlon processor.
*
* TPS Transformers are serializable.
*
* The GDAL Thin Plate Spline transformer is based on code provided by
* Gilad Ronnen on behalf of VIZRT Inc (http://www.visrt.com). Incorporation
* of the algorithm into GDAL was supported by the Centro di Ecologia Alpina
* (http://www.cealp.it).
*
* @param nGCPCount the number of GCPs in pasGCPList.
* @param pasGCPList an array of GCPs to be used as input.
* @param bReversed set it to TRUE to compute the reversed transformation.
*
* @return the transform argument or NULL if creation fails.
*/
void *GDALCreateTPSTransformer( int nGCPCount, const GDAL_GCP *pasGCPList,
int bReversed )
{
return GDALCreateTPSTransformerInt(nGCPCount, pasGCPList, bReversed, nullptr);
}
static void GDALTPSComputeForwardInThread( void *pData )
{
TPSTransformInfo *psInfo = static_cast<TPSTransformInfo *>(pData);
psInfo->bForwardSolved = psInfo->poForward->solve() != 0;
}
void *GDALCreateTPSTransformerInt( int nGCPCount, const GDAL_GCP *pasGCPList,
int bReversed, char** papszOptions )
{
/* -------------------------------------------------------------------- */
/* Allocate transform info. */
/* -------------------------------------------------------------------- */
TPSTransformInfo *psInfo = static_cast<TPSTransformInfo *>(
CPLCalloc(sizeof(TPSTransformInfo), 1));
psInfo->pasGCPList = GDALDuplicateGCPs( nGCPCount, pasGCPList );
psInfo->nGCPCount = nGCPCount;
psInfo->bReversed = CPL_TO_BOOL(bReversed);
psInfo->poForward = new VizGeorefSpline2D( 2 );
psInfo->poReverse = new VizGeorefSpline2D( 2 );
memcpy( psInfo->sTI.abySignature,
GDAL_GTI2_SIGNATURE,
strlen(GDAL_GTI2_SIGNATURE) );
psInfo->sTI.pszClassName = "GDALTPSTransformer";
psInfo->sTI.pfnTransform = GDALTPSTransform;
psInfo->sTI.pfnCleanup = GDALDestroyTPSTransformer;
psInfo->sTI.pfnSerialize = GDALSerializeTPSTransformer;
psInfo->sTI.pfnCreateSimilar = GDALCreateSimilarTPSTransformer;
/* -------------------------------------------------------------------- */
/* Attach all the points to the transformation. */
/* -------------------------------------------------------------------- */
std::map< std::pair<double, double>, int > oMapPixelLineToIdx;
std::map< std::pair<double, double>, int > oMapXYToIdx;
for( int iGCP = 0; iGCP < nGCPCount; iGCP++ )
{
const double afPL[2] = {
pasGCPList[iGCP].dfGCPPixel,
pasGCPList[iGCP].dfGCPLine };
const double afXY[2] =
{ pasGCPList[iGCP].dfGCPX, pasGCPList[iGCP].dfGCPY };
std::map< std::pair<double, double>, int >::iterator oIter(
oMapPixelLineToIdx.find(std::pair<double, double>(afPL[0],
afPL[1])));
if( oIter != oMapPixelLineToIdx.end() )
{
if( afXY[0] == pasGCPList[oIter->second].dfGCPX &&
afXY[1] == pasGCPList[oIter->second].dfGCPY )
{
continue;
}
else
{
CPLError(CE_Warning, CPLE_AppDefined,
"GCP %d and %d have same (pixel,line)=(%f,%f), "
"but different (X,Y): (%f,%f) vs (%f,%f)",
iGCP + 1, oIter->second,
afPL[0], afPL[1],
afXY[0], afXY[1],
pasGCPList[oIter->second].dfGCPX,
pasGCPList[oIter->second].dfGCPY);
}
}
else
{
oMapPixelLineToIdx[std::pair<double, double>(afPL[0], afPL[1])] =
iGCP;
}
oIter = oMapXYToIdx.find(std::pair<double, double>(afXY[0], afXY[1]));
if( oIter != oMapXYToIdx.end() )
{
CPLError(CE_Warning, CPLE_AppDefined,
"GCP %d and %d have same (x,y)=(%f,%f), "
"but different (pixel,line): (%f,%f) vs (%f,%f)",
iGCP + 1, oIter->second,
afXY[0], afXY[1],
afPL[0], afPL[1],
pasGCPList[oIter->second].dfGCPPixel,
pasGCPList[oIter->second].dfGCPLine);
}
else
{
oMapXYToIdx[std::pair<double, double>(afXY[0], afXY[1])] = iGCP;
}
bool bOK = true;
if( bReversed )
{
bOK &= psInfo->poReverse->add_point( afPL[0], afPL[1], afXY );
bOK &= psInfo->poForward->add_point( afXY[0], afXY[1], afPL );
}
else
{
bOK &= psInfo->poForward->add_point( afPL[0], afPL[1], afXY );
bOK &= psInfo->poReverse->add_point( afXY[0], afXY[1], afPL );
}
if( !bOK )
{
GDALDestroyTPSTransformer(psInfo);
return nullptr;
}
}
psInfo->nRefCount = 1;
int nThreads = 1;
if( nGCPCount > 100 )
{
const char* pszWarpThreads =
CSLFetchNameValue(papszOptions, "NUM_THREADS");
if( pszWarpThreads == nullptr )
pszWarpThreads = CPLGetConfigOption("GDAL_NUM_THREADS", "1");
if( EQUAL(pszWarpThreads, "ALL_CPUS") )
nThreads = CPLGetNumCPUs();
else
nThreads = atoi(pszWarpThreads);
}
if( nThreads > 1 )
{
// Compute direct and reverse transforms in parallel.
CPLJoinableThread* hThread =
CPLCreateJoinableThread(GDALTPSComputeForwardInThread, psInfo);
psInfo->bReverseSolved = psInfo->poReverse->solve() != 0;
if( hThread != nullptr )
CPLJoinThread(hThread);
else
psInfo->bForwardSolved = psInfo->poForward->solve() != 0;
}
else
{
psInfo->bForwardSolved = psInfo->poForward->solve() != 0;
psInfo->bReverseSolved = psInfo->poReverse->solve() != 0;
}
if( !psInfo->bForwardSolved || !psInfo->bReverseSolved )
{
GDALDestroyTPSTransformer(psInfo);
return nullptr;
}
return psInfo;
}
/************************************************************************/
/* GDALDestroyTPSTransformer() */
/************************************************************************/
/**
* Destroy TPS transformer.
*
* This function is used to destroy information about a GCP based
* polynomial transformation created with GDALCreateTPSTransformer().
*
* @param pTransformArg the transform arg previously returned by
* GDALCreateTPSTransformer().
*/
void GDALDestroyTPSTransformer( void *pTransformArg )
{
if( pTransformArg == nullptr )
return;
TPSTransformInfo *psInfo = static_cast<TPSTransformInfo *>(pTransformArg);
if( CPLAtomicDec(&(psInfo->nRefCount)) == 0 )
{
delete psInfo->poForward;
delete psInfo->poReverse;
GDALDeinitGCPs( psInfo->nGCPCount, psInfo->pasGCPList );
CPLFree( psInfo->pasGCPList );
CPLFree( pTransformArg );
}
}
/************************************************************************/
/* GDALTPSTransform() */
/************************************************************************/
/**
* Transforms point based on GCP derived polynomial model.
*
* This function matches the GDALTransformerFunc signature, and can be
* used to transform one or more points from pixel/line coordinates to
* georeferenced coordinates (SrcToDst) or vice versa (DstToSrc).
*
* @param pTransformArg return value from GDALCreateTPSTransformer().
* @param bDstToSrc TRUE if transformation is from the destination
* (georeferenced) coordinates to pixel/line or FALSE when transforming
* from pixel/line to georeferenced coordinates.
* @param nPointCount the number of values in the x, y and z arrays.
* @param x array containing the X values to be transformed.
* @param y array containing the Y values to be transformed.
* @param z array containing the Z values to be transformed.
* @param panSuccess array in which a flag indicating success (TRUE) or
* failure (FALSE) of the transformation are placed.
*
* @return TRUE.
*/
int GDALTPSTransform( void *pTransformArg, int bDstToSrc,
int nPointCount,
double *x, double *y,
CPL_UNUSED double *z,
int *panSuccess )
{
VALIDATE_POINTER1( pTransformArg, "GDALTPSTransform", 0 );
TPSTransformInfo *psInfo = static_cast<TPSTransformInfo *>(pTransformArg);
for( int i = 0; i < nPointCount; i++ )
{
double xy_out[2] = { 0.0, 0.0 };
if( bDstToSrc )
{
psInfo->poReverse->get_point( x[i], y[i], xy_out );
x[i] = xy_out[0];
y[i] = xy_out[1];
}
else
{
psInfo->poForward->get_point( x[i], y[i], xy_out );
x[i] = xy_out[0];
y[i] = xy_out[1];
}
panSuccess[i] = TRUE;
}
return TRUE;
}
/************************************************************************/
/* GDALSerializeTPSTransformer() */
/************************************************************************/
CPLXMLNode *GDALSerializeTPSTransformer( void *pTransformArg )
{
VALIDATE_POINTER1( pTransformArg, "GDALSerializeTPSTransformer", nullptr );
TPSTransformInfo *psInfo = static_cast<TPSTransformInfo *>(pTransformArg);
CPLXMLNode *psTree = CPLCreateXMLNode(nullptr, CXT_Element, "TPSTransformer");
/* -------------------------------------------------------------------- */
/* Serialize bReversed. */
/* -------------------------------------------------------------------- */
CPLCreateXMLElementAndValue(
psTree, "Reversed",
CPLString().Printf( "%d", static_cast<int>(psInfo->bReversed) ) );
/* -------------------------------------------------------------------- */
/* Attach GCP List. */
/* -------------------------------------------------------------------- */
if( psInfo->nGCPCount > 0 )
{
GDALSerializeGCPListToXML( psTree,
psInfo->pasGCPList,
psInfo->nGCPCount,
nullptr );
}
return psTree;
}
/************************************************************************/
/* GDALDeserializeTPSTransformer() */
/************************************************************************/
void *GDALDeserializeTPSTransformer( CPLXMLNode *psTree )
{
/* -------------------------------------------------------------------- */
/* Check for GCPs. */
/* -------------------------------------------------------------------- */
CPLXMLNode *psGCPList = CPLGetXMLNode( psTree, "GCPList" );
GDAL_GCP *pasGCPList = nullptr;
int nGCPCount = 0;
if( psGCPList != nullptr )
{
GDALDeserializeGCPListFromXML( psGCPList,
&pasGCPList,
&nGCPCount,
nullptr );
}
/* -------------------------------------------------------------------- */
/* Get other flags. */
/* -------------------------------------------------------------------- */
const int bReversed = atoi(CPLGetXMLValue(psTree, "Reversed", "0"));
/* -------------------------------------------------------------------- */
/* Generate transformation. */
/* -------------------------------------------------------------------- */
void *pResult =
GDALCreateTPSTransformer( nGCPCount, pasGCPList, bReversed );
/* -------------------------------------------------------------------- */
/* Cleanup GCP copy. */
/* -------------------------------------------------------------------- */
GDALDeinitGCPs( nGCPCount, pasGCPList );
CPLFree( pasGCPList );
return pResult;
}

View File

@@ -0,0 +1,753 @@
/******************************************************************************
*
* Project: GDAL algorithms
* Purpose: Apply vertical shift grid
* Author: Even Rouault, even.rouault at spatialys.com
*
******************************************************************************
* Copyright (c) 2017, Even Rouault <even.rouault at spatialys.com>
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included
* in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
****************************************************************************/
#include "cpl_string.h"
#include "gdal.h"
#include "gdal_alg.h"
#include "gdal_priv.h"
#include "gdal_utils.h"
#include "gdalwarper.h"
#include "vrtdataset.h"
#include "ogr_spatialref.h"
#ifdef PROJ_STATIC
#if defined(PROJ_VERSION) && PROJ_VERSION >= 5
#include "proj.h"
#else
#include "proj_api.h"
#endif
#endif
#include <limits>
CPL_CVSID("$Id: gdalapplyverticalshiftgrid.cpp fe2d81c8819bf9794bce0210098e637565728350 2018-05-06 00:49:51 +0200 Even Rouault $")
/************************************************************************/
/* GDALApplyVSGDataset */
/************************************************************************/
class GDALApplyVSGDataset final: public GDALDataset
{
friend class GDALApplyVSGRasterBand;
GDALDataset* m_poSrcDataset = nullptr;
GDALDataset* m_poReprojectedGrid = nullptr;
bool m_bInverse = false;
double m_dfSrcUnitToMeter = 0.0;
double m_dfDstUnitToMeter = 0.0;
CPL_DISALLOW_COPY_ASSIGN(GDALApplyVSGDataset)
public:
GDALApplyVSGDataset( GDALDataset* poSrcDataset,
GDALDataset* poReprojectedGrid,
GDALDataType eDT,
bool bInverse,
double dfSrcUnitToMeter,
double dfDstUnitToMeter,
int nBlockSize );
virtual ~GDALApplyVSGDataset();
virtual int CloseDependentDatasets() override;
virtual CPLErr GetGeoTransform(double* padfGeoTransform) override;
virtual const char* GetProjectionRef() override;
bool IsInitOK();
};
/************************************************************************/
/* GDALApplyVSGRasterBand */
/************************************************************************/
class GDALApplyVSGRasterBand final: public GDALRasterBand
{
friend class GDALApplyVSGDataset;
float *m_pafSrcData = nullptr;
float *m_pafGridData = nullptr;
CPL_DISALLOW_COPY_ASSIGN(GDALApplyVSGRasterBand)
public:
GDALApplyVSGRasterBand( GDALDataType eDT,
int nBlockSize );
virtual ~GDALApplyVSGRasterBand();
virtual CPLErr IReadBlock( int nBlockXOff, int nBlockYOff,
void * pData ) override;
virtual double GetNoDataValue( int* pbSuccess ) override;
};
/************************************************************************/
/* GDALApplyVSGDataset() */
/************************************************************************/
GDALApplyVSGDataset::GDALApplyVSGDataset( GDALDataset* poSrcDataset,
GDALDataset* poReprojectedGrid,
GDALDataType eDT,
bool bInverse,
double dfSrcUnitToMeter,
double dfDstUnitToMeter,
int nBlockSize ) :
m_poSrcDataset(poSrcDataset),
m_poReprojectedGrid(poReprojectedGrid),
m_bInverse(bInverse),
m_dfSrcUnitToMeter(dfSrcUnitToMeter),
m_dfDstUnitToMeter(dfDstUnitToMeter)
{
m_poSrcDataset->Reference();
m_poReprojectedGrid->Reference();
nRasterXSize = poSrcDataset->GetRasterXSize();
nRasterYSize = poSrcDataset->GetRasterYSize();
SetBand( 1, new GDALApplyVSGRasterBand( eDT, nBlockSize ) );
}
/************************************************************************/
/* ~GDALApplyVSGDataset() */
/************************************************************************/
GDALApplyVSGDataset::~GDALApplyVSGDataset()
{
GDALApplyVSGDataset::CloseDependentDatasets();
}
/************************************************************************/
/* CloseDependentDatasets() */
/************************************************************************/
int GDALApplyVSGDataset::CloseDependentDatasets()
{
bool bRet = false;
if( m_poSrcDataset != nullptr )
{
if( m_poSrcDataset->ReleaseRef() )
{
bRet = true;
}
m_poSrcDataset = nullptr;
}
if( m_poReprojectedGrid != nullptr )
{
if( m_poReprojectedGrid->ReleaseRef() )
{
bRet = true;
}
m_poReprojectedGrid = nullptr;
}
return bRet;
}
/************************************************************************/
/* GetGeoTransform() */
/************************************************************************/
CPLErr GDALApplyVSGDataset::GetGeoTransform(double* padfGeoTransform)
{
return m_poSrcDataset->GetGeoTransform(padfGeoTransform);
}
/************************************************************************/
/* GetProjectionRef() */
/************************************************************************/
const char* GDALApplyVSGDataset::GetProjectionRef()
{
return m_poSrcDataset->GetProjectionRef();
}
/************************************************************************/
/* IsInitOK() */
/************************************************************************/
bool GDALApplyVSGDataset::IsInitOK()
{
GDALApplyVSGRasterBand* poBand =
reinterpret_cast<GDALApplyVSGRasterBand*>(GetRasterBand(1));
return poBand->m_pafSrcData != nullptr && poBand->m_pafGridData != nullptr;
}
/************************************************************************/
/* GDALApplyVSGRasterBand() */
/************************************************************************/
GDALApplyVSGRasterBand::GDALApplyVSGRasterBand( GDALDataType eDT,
int nBlockSize )
{
eDataType = eDT;
nBlockXSize = nBlockSize;
nBlockYSize = nBlockSize;
m_pafSrcData = static_cast<float*>(
VSI_MALLOC3_VERBOSE(nBlockXSize, nBlockYSize, sizeof(float)));
m_pafGridData = static_cast<float*>(
VSI_MALLOC3_VERBOSE(nBlockXSize, nBlockYSize, sizeof(float)));
}
/************************************************************************/
/* ~GDALApplyVSGRasterBand() */
/************************************************************************/
GDALApplyVSGRasterBand::~GDALApplyVSGRasterBand()
{
VSIFree(m_pafSrcData);
VSIFree(m_pafGridData);
}
/************************************************************************/
/* GetNoDataValue() */
/************************************************************************/
double GDALApplyVSGRasterBand::GetNoDataValue( int* pbSuccess )
{
GDALApplyVSGDataset* poGDS = reinterpret_cast<GDALApplyVSGDataset*>(poDS);
return poGDS->m_poSrcDataset->GetRasterBand(1)->GetNoDataValue(pbSuccess);
}
/************************************************************************/
/* IReadBlock() */
/************************************************************************/
CPLErr GDALApplyVSGRasterBand::IReadBlock( int nBlockXOff, int nBlockYOff,
void * pData )
{
GDALApplyVSGDataset* poGDS = reinterpret_cast<GDALApplyVSGDataset*>(poDS);
const int nXOff = nBlockXOff * nBlockXSize;
const int nReqXSize = ( nXOff > nRasterXSize - nBlockXSize ) ?
nRasterXSize - nXOff : nBlockXSize;
const int nYOff = nBlockYOff * nBlockYSize;
const int nReqYSize = ( nYOff > nRasterYSize - nBlockYSize ) ?
nRasterYSize - nYOff : nBlockYSize;
CPLErr eErr =
poGDS->m_poSrcDataset->GetRasterBand(1)->RasterIO(GF_Read,
nXOff, nYOff,
nReqXSize, nReqYSize,
m_pafSrcData,
nReqXSize, nReqYSize,
GDT_Float32,
sizeof(float),
nBlockXSize * sizeof(float),
nullptr);
if( eErr == CE_None )
eErr = poGDS->m_poReprojectedGrid->GetRasterBand(1)->RasterIO(GF_Read,
nXOff, nYOff,
nReqXSize, nReqYSize,
m_pafGridData,
nReqXSize, nReqYSize,
GDT_Float32,
sizeof(float),
nBlockXSize * sizeof(float),
nullptr);
if( eErr == CE_None )
{
const int nDTSize = GDALGetDataTypeSizeBytes(eDataType);
int bHasNoData = FALSE;
float fNoDataValue = static_cast<float>(GetNoDataValue(&bHasNoData));
for( int iY = 0; iY < nReqYSize; iY++ )
{
for( int iX = 0; iX < nReqXSize; iX ++ )
{
const float fSrcVal = m_pafSrcData[iY * nBlockXSize + iX];
const float fGridVal = m_pafGridData[iY * nBlockXSize + iX];
if( bHasNoData && fSrcVal == fNoDataValue )
{
}
else if( CPLIsInf(fGridVal) )
{
CPLError(CE_Failure, CPLE_AppDefined,
"Missing vertical grid value at source (%d,%d)",
nXOff + iX, nYOff + iY);
return CE_Failure;
}
else if( poGDS->m_bInverse )
{
m_pafSrcData[iY * nBlockXSize + iX] = static_cast<float>(
(fSrcVal * poGDS->m_dfSrcUnitToMeter - fGridVal) /
poGDS->m_dfDstUnitToMeter);
}
else
{
m_pafSrcData[iY * nBlockXSize + iX] = static_cast<float>(
(fSrcVal * poGDS->m_dfSrcUnitToMeter + fGridVal) /
poGDS->m_dfDstUnitToMeter);
}
}
GDALCopyWords( m_pafSrcData + iY * nBlockXSize,
GDT_Float32, sizeof(float),
static_cast<GByte*>(pData) + iY * nBlockXSize *
nDTSize, eDataType, nDTSize,
nReqXSize );
}
}
return eErr;
}
/************************************************************************/
/* GDALApplyVerticalShiftGrid() */
/************************************************************************/
/** Apply a vertical shift grid to a source (DEM typically) dataset.
*
* hGridDataset will typically use WGS84 as horizontal datum (but this is
* not a requirement) and its values are the values to add to go from geoid
* elevations to WGS84 ellipsoidal heights.
*
* hGridDataset will be on-the-fly reprojected and resampled to the projection
* and resolution of hSrcDataset, using bilinear resampling by default.
*
* Both hSrcDataset and hGridDataset must be single band datasets, and have
* a valid geotransform and projection.
*
* On success, a reference will be taken on hSrcDataset and hGridDataset.
* Reference counting semantics on the source and grid datasets should be
* honoured. That is, don't just GDALClose() it, unless it was opened with
* GDALOpenShared(), but rather use GDALReleaseDataset() if wanting to
* immediately release the reference(s) and make the returned dataset the
* owner of them.
*
* Valid use cases:
*
* \code
* hSrcDataset = GDALOpen(...)
* hGridDataset = GDALOpen(...)
* hDstDataset = GDALApplyVerticalShiftGrid(hSrcDataset, hGridDataset, ...)
* GDALReleaseDataset(hSrcDataset);
* GDALReleaseDataset(hGridDataset);
* if( hDstDataset )
* {
* // Do things with hDstDataset
* GDALClose(hDstDataset) // will close hSrcDataset and hGridDataset
* }
* \endcode
*
* @param hSrcDataset source (DEM) dataset. Must not be NULL.
* @param hGridDataset vertical grid shift dataset. Must not be NULL.
* @param bInverse if set to FALSE, hGridDataset values will be added to
* hSrcDataset. If set to TRUE, they will be subtracted.
* @param dfSrcUnitToMeter the factor to convert values from hSrcDataset to
* meters (1.0 if source values are in meter).
* @param dfDstUnitToMeter the factor to convert shifted values from meter
* (1.0 if output values must be in meter).
* @param papszOptions list of options, or NULL. Supported options are:
* <ul>
* <li>RESAMPLING=NEAREST/BILINEAR/CUBIC. Defaults to BILINEAR.</li>
* <li>MAX_ERROR=val. Maximum error measured in input pixels that is allowed in
* approximating the transformation (0.0 for exact calculations). Defaults
* to 0.125</li>
* <li>DATATYPE=Byte/UInt16/Int16/Float32/Float64. Output data type. If not
* specified will be the same as the one of hSrcDataset.
* <li>ERROR_ON_MISSING_VERT_SHIFT=YES/NO. Whether a missing/nodata value in
* hGridDataset should cause I/O requests to fail. Default is NO (in which case
* 0 will be used)
* <li>SRC_SRS=srs_def. Override projection on hSrcDataset;
* </ul>
*
* @return a new dataset corresponding to hSrcDataset adjusted with
* hGridDataset, or NULL. If not NULL, it must be closed with GDALClose().
*
* @since GDAL 2.2
*/
GDALDatasetH GDALApplyVerticalShiftGrid( GDALDatasetH hSrcDataset,
GDALDatasetH hGridDataset,
int bInverse,
double dfSrcUnitToMeter,
double dfDstUnitToMeter,
const char* const* papszOptions )
{
VALIDATE_POINTER1( hSrcDataset, "GDALApplyVerticalShiftGrid", nullptr );
VALIDATE_POINTER1( hGridDataset, "GDALApplyVerticalShiftGrid", nullptr );
double adfSrcGT[6];
if( GDALGetGeoTransform(hSrcDataset, adfSrcGT) != CE_None )
{
CPLError(CE_Failure, CPLE_NotSupported,
"Source dataset has no geotransform.");
return nullptr;
}
const char* pszSrcProjection = CSLFetchNameValueDef(papszOptions,
"SRC_SRS",
GDALGetProjectionRef(hSrcDataset));
if( pszSrcProjection == nullptr || pszSrcProjection[0] == '\0' )
{
CPLError(CE_Failure, CPLE_NotSupported,
"Source dataset has no projection.");
return nullptr;
}
if( GDALGetRasterCount(hSrcDataset) != 1 )
{
CPLError(CE_Failure, CPLE_NotSupported,
"Only single band source dataset is supported.");
return nullptr;
}
double adfGridGT[6];
if( GDALGetGeoTransform(hGridDataset, adfGridGT) != CE_None )
{
CPLError(CE_Failure, CPLE_NotSupported,
"Grid dataset has no geotransform.");
return nullptr;
}
const char* pszGridProjection = GDALGetProjectionRef(hGridDataset);
if( pszGridProjection == nullptr || pszGridProjection[0] == '\0' )
{
CPLError(CE_Failure, CPLE_NotSupported,
"Grid dataset has no projection.");
return nullptr;
}
if( GDALGetRasterCount(hGridDataset) != 1 )
{
CPLError(CE_Failure, CPLE_NotSupported,
"Only single band grid dataset is supported.");
return nullptr;
}
GDALDataType eDT = GDALGetRasterDataType(GDALGetRasterBand(hSrcDataset,1));
const char* pszDataType = CSLFetchNameValue(papszOptions, "DATATYPE");
if( pszDataType )
eDT = GDALGetDataTypeByName(pszDataType);
if( eDT == GDT_Unknown )
{
CPLError(CE_Failure, CPLE_NotSupported,
"Invalid DATATYPE=%s", pszDataType);
return nullptr;
}
const int nSrcXSize = GDALGetRasterXSize(hSrcDataset);
const int nSrcYSize = GDALGetRasterYSize(hSrcDataset);
OGRSpatialReference oSRS;
CPLString osSrcProjection(pszSrcProjection);
oSRS.SetFromUserInput(osSrcProjection);
if( oSRS.IsCompound() )
{
OGR_SRSNode* poNode = oSRS.GetRoot()->GetChild(1);
if( poNode != nullptr )
{
char* pszWKT = nullptr;
poNode->exportToWkt(&pszWKT);
osSrcProjection = pszWKT;
CPLFree(pszWKT);
}
}
void* hTransform = GDALCreateGenImgProjTransformer3( pszGridProjection,
adfGridGT,
osSrcProjection,
adfSrcGT );
if( hTransform == nullptr )
return nullptr;
GDALWarpOptions* psWO = GDALCreateWarpOptions();
psWO->hSrcDS = hGridDataset;
psWO->eResampleAlg = GRA_Bilinear;
const char* pszResampling = CSLFetchNameValue(papszOptions, "RESAMPLING");
if( pszResampling )
{
if( EQUAL(pszResampling, "NEAREST") )
psWO->eResampleAlg = GRA_NearestNeighbour;
else if( EQUAL(pszResampling, "BILINEAR") )
psWO->eResampleAlg = GRA_Bilinear;
else if( EQUAL(pszResampling, "CUBIC") )
psWO->eResampleAlg = GRA_Cubic;
}
psWO->eWorkingDataType = GDT_Float32;
int bHasNoData = FALSE;
const double dfSrcNoData = GDALGetRasterNoDataValue(
GDALGetRasterBand(hGridDataset, 1), &bHasNoData );
if( bHasNoData )
{
psWO->padfSrcNoDataReal =
static_cast<double*>(CPLMalloc(sizeof(double)));
psWO->padfSrcNoDataReal[0] = dfSrcNoData;
}
psWO->padfDstNoDataReal = static_cast<double*>(CPLMalloc(sizeof(double)));
const bool bErrorOnMissingShift = CPLFetchBool( papszOptions,
"ERROR_ON_MISSING_VERT_SHIFT",
false );
psWO->padfDstNoDataReal[0] =
(bErrorOnMissingShift) ? -std::numeric_limits<float>::infinity() : 0.0;
psWO->papszWarpOptions = CSLSetNameValue(psWO->papszWarpOptions,
"INIT_DEST",
"NO_DATA");
psWO->pfnTransformer = GDALGenImgProjTransform;
psWO->pTransformerArg = hTransform;
const double dfMaxError = CPLAtof(CSLFetchNameValueDef(papszOptions,
"MAX_ERROR",
"0.125"));
if( dfMaxError > 0.0 )
{
psWO->pTransformerArg =
GDALCreateApproxTransformer( psWO->pfnTransformer,
psWO->pTransformerArg,
dfMaxError );
psWO->pfnTransformer = GDALApproxTransform;
GDALApproxTransformerOwnsSubtransformer(psWO->pTransformerArg, TRUE);
}
psWO->nBandCount = 1;
psWO->panSrcBands = static_cast<int *>(CPLMalloc(sizeof(int)));
psWO->panSrcBands[0] = 1;
psWO->panDstBands = static_cast<int *>(CPLMalloc(sizeof(int)));
psWO->panDstBands[0] = 1;
VRTWarpedDataset* poReprojectedGrid =
new VRTWarpedDataset(nSrcXSize, nSrcYSize);
// This takes a reference on hGridDataset
CPLErr eErr = poReprojectedGrid->Initialize(psWO);
CPLAssert(eErr == CE_None);
CPL_IGNORE_RET_VAL(eErr);
GDALDestroyWarpOptions(psWO);
poReprojectedGrid->SetGeoTransform(adfSrcGT);
poReprojectedGrid->AddBand(GDT_Float32, nullptr);
GDALApplyVSGDataset* poOutDS = new GDALApplyVSGDataset(
reinterpret_cast<GDALDataset*>(hSrcDataset),
poReprojectedGrid,
eDT,
CPL_TO_BOOL(bInverse),
dfSrcUnitToMeter,
dfDstUnitToMeter,
// Undocumented option. For testing only
atoi(CSLFetchNameValueDef(papszOptions, "BLOCKSIZE", "256")) );
poReprojectedGrid->ReleaseRef();
if( !poOutDS->IsInitOK() )
{
delete poOutDS;
return nullptr;
}
poOutDS->SetDescription( GDALGetDescription( hSrcDataset ) );
return reinterpret_cast<GDALDatasetH>(poOutDS);
}
/************************************************************************/
/* my_proj4_logger() */
/************************************************************************/
#if defined(PROJ_STATIC) && PJ_VERSION >= 490 && PJ_VERSION <= 493
static void my_proj4_logger(void * user_data, int /*level*/, const char * msg)
{
CPLString* posMsg = static_cast<CPLString*>(user_data);
*posMsg += msg;
}
#endif
/************************************************************************/
/* GetProj4Filename() */
/************************************************************************/
static CPLString GetProj4Filename(const char* pszFilename)
{
CPLString osFilename;
/* or fixed path: /name, ./name or ../name */
if ( !CPLIsFilenameRelative(pszFilename) || *pszFilename == '.' )
{
return pszFilename;
}
#if defined(PROJ_STATIC) && PROJ_VERSION >= 5
PJ_GRID_INFO info = proj_grid_info(pszFilename);
if( info.filename[0] )
{
osFilename = info.filename;
}
#elif defined(PROJ_STATIC) && PJ_VERSION > 493
osFilename.resize(2048);
projCtx ctx = pj_ctx_alloc();
if( pj_find_file(ctx, pszFilename, &osFilename[0], osFilename.size()) )
{
osFilename.resize( strlen(osFilename) );
}
else
{
osFilename.clear();
}
pj_ctx_free(ctx);
#else
// Transpose some of the proj.4 pj_open_lib() logic...
/* check if ~/name */
char* pszSysname;
if (*pszFilename == '~' &&
(pszFilename[1] == '/' || pszFilename[1] == '\\') )
{
if ((pszSysname = getenv("HOME")) != nullptr)
{
osFilename = CPLFormFilename(pszSysname, pszFilename + 1, nullptr);
}
return osFilename;
}
/* or is environment PROJ_LIB defined */
else if ((pszSysname = getenv("PROJ_LIB")) != nullptr)
{
osFilename = CPLFormFilename(pszSysname, pszFilename, nullptr);
VSIStatBufL sStat;
if( VSIStatL(osFilename, &sStat) == 0 )
return osFilename;
osFilename.clear();
}
#if defined(PROJ_STATIC) && PJ_VERSION >= 490
// Super messy. proj.4 up to 4.9.3 had no public API to return the full
// path to a resource file, so we rely on the fact that it emits a log
// message with it...
// Basically this is needed in the case where the file is in the
// resource installation directory of proj.4, which we have no way to
// know otherwise.
CPLString osMsg;
projCtx ctx = pj_ctx_alloc();
pj_ctx_set_app_data(ctx, &osMsg);
pj_ctx_set_debug(ctx, PJ_LOG_DEBUG_MAJOR);
pj_ctx_set_logger(ctx, my_proj4_logger);
PAFile f = pj_open_lib(ctx, pszFilename, "rb");
if( f )
{
pj_ctx_fclose(ctx, f);
size_t nPos = osMsg.find("fopen(");
if( nPos != std::string::npos )
{
osFilename = osMsg.substr(nPos + strlen("fopen("));
nPos = osFilename.find(")");
if( nPos != std::string::npos )
osFilename = osFilename.substr(0, nPos);
}
}
pj_ctx_free(ctx);
#endif
#endif
return osFilename;
}
/************************************************************************/
/* GDALOpenVerticalShiftGrid() */
/************************************************************************/
/** Load proj.4 geoidgrids as GDAL dataset
*
* @param pszProj4Geoidgrids Value of proj.4 geoidgrids parameter.
* @param pbError If not NULL, the pointed value will be set to TRUE if an
* error occurred.
*
* @return a dataset. If not NULL, it must be closed with GDALClose().
*
* @since GDAL 2.2
*/
GDALDatasetH GDALOpenVerticalShiftGrid( const char* pszProj4Geoidgrids,
int* pbError )
{
char** papszGrids = CSLTokenizeString2( pszProj4Geoidgrids, ",", 0);
const int nGridCount = CSLCount(papszGrids);
if( nGridCount == 1 )
{
CSLDestroy(papszGrids);
bool bMissingOk = false;
if( *pszProj4Geoidgrids == '@' )
{
pszProj4Geoidgrids ++;
bMissingOk = true;
}
const CPLString osFilename(GetProj4Filename(pszProj4Geoidgrids));
const char* const papszOpenOptions[] =
{ "@SHIFT_ORIGIN_IN_MINUS_180_PLUS_180=YES", nullptr };
GDALDatasetH hDS = GDALOpenEx(osFilename, 0, nullptr, papszOpenOptions, nullptr);
if( hDS == nullptr )
{
CPLDebug("GDAL", "Cannot find file corresponding to %s",
pszProj4Geoidgrids);
}
if( pbError )
*pbError = (!bMissingOk && hDS == nullptr);
return hDS;
}
CPLStringList aosFilenames;
for( int i = nGridCount - 1; i >= 0; i-- )
{
const char* pszName = papszGrids[i];
bool bMissingOk = false;
if( *pszName == '@' )
{
pszName ++;
bMissingOk = true;
}
const CPLString osFilename(GetProj4Filename(pszName));
VSIStatBufL sStat;
if( osFilename.empty() || VSIStatL(osFilename, &sStat) != 0 )
{
CPLDebug("GDAL", "Cannot find file corresponding to %s",
pszName);
if( !bMissingOk )
{
if( pbError )
*pbError = true;
CSLDestroy(papszGrids);
return nullptr;
}
}
else
{
aosFilenames.AddString(osFilename);
}
}
CSLDestroy(papszGrids);
if( aosFilenames.empty() )
{
if( pbError )
*pbError = false;
return nullptr;
}
char** papszArgv = nullptr;
papszArgv = CSLAddString(papszArgv, "-resolution");
papszArgv = CSLAddString(papszArgv, "highest");
papszArgv = CSLAddString(papszArgv, "-vrtnodata");
papszArgv = CSLAddString(papszArgv, "-inf");
papszArgv = CSLAddString(papszArgv, "-oo");
papszArgv = CSLAddString(papszArgv, "@SHIFT_ORIGIN_IN_MINUS_180_PLUS_180=YES");
GDALBuildVRTOptions* psOptions = GDALBuildVRTOptionsNew(papszArgv, nullptr);
CSLDestroy(papszArgv);
GDALDatasetH hDS =
GDALBuildVRT( "", aosFilenames.size(), nullptr, aosFilenames.List(),
psOptions, nullptr );
GDALBuildVRTOptionsFree( psOptions );
if( pbError )
*pbError = hDS != nullptr;
return hDS;
}

View File

@@ -0,0 +1,180 @@
/******************************************************************************
*
* Project: GDAL
* Purpose: Compute simple checksum for a region of image data.
* Author: Frank Warmerdam, warmerdam@pobox.com
*
******************************************************************************
* Copyright (c) 2003, Frank Warmerdam
* Copyright (c) 2007-2008, Even Rouault <even dot rouault at mines-paris dot org>
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included
* in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
****************************************************************************/
#include "cpl_port.h"
#include "gdal_alg.h"
#include <cmath>
#include <cstddef>
#include "cpl_conv.h"
#include "cpl_error.h"
#include "cpl_vsi.h"
#include "gdal.h"
CPL_CVSID("$Id: gdalchecksum.cpp 7e07230bbff24eb333608de4dbd460b7312839d0 2017-12-11 19:08:47Z Even Rouault $")
/************************************************************************/
/* GDALChecksumImage() */
/************************************************************************/
/**
* Compute checksum for image region.
*
* Computes a 16bit (0-65535) checksum from a region of raster data on a GDAL
* supported band. Floating point data is converted to 32bit integer
* so decimal portions of such raster data will not affect the checksum.
* Real and Imaginary components of complex bands influence the result.
*
* @param hBand the raster band to read from.
* @param nXOff pixel offset of window to read.
* @param nYOff line offset of window to read.
* @param nXSize pixel size of window to read.
* @param nYSize line size of window to read.
*
* @return Checksum value.
*/
int CPL_STDCALL
GDALChecksumImage( GDALRasterBandH hBand,
int nXOff, int nYOff, int nXSize, int nYSize )
{
VALIDATE_POINTER1( hBand, "GDALChecksumImage", 0 );
const static int anPrimes[11] =
{ 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43 };
int nChecksum = 0;
int iPrime = 0;
const GDALDataType eDataType = GDALGetRasterDataType(hBand);
const bool bComplex = CPL_TO_BOOL(GDALDataTypeIsComplex(eDataType));
if( eDataType == GDT_Float32 || eDataType == GDT_Float64 ||
eDataType == GDT_CFloat32 || eDataType == GDT_CFloat64 )
{
const GDALDataType eDstDataType = bComplex ? GDT_CFloat64 : GDT_Float64;
double* padfLineData = static_cast<double *>(
VSI_MALLOC2_VERBOSE(nXSize,
GDALGetDataTypeSizeBytes(eDstDataType)));
if( padfLineData == nullptr )
{
return 0;
}
for( int iLine = nYOff; iLine < nYOff + nYSize; iLine++ )
{
if( GDALRasterIO( hBand, GF_Read, nXOff, iLine, nXSize, 1,
padfLineData, nXSize, 1,
eDstDataType, 0, 0 ) != CE_None )
{
CPLError(CE_Failure, CPLE_FileIO,
"Checksum value couldn't be computed due to "
"I/O read error.");
break;
}
const int nCount = bComplex ? nXSize * 2 : nXSize;
for( int i = 0; i < nCount; i++ )
{
double dfVal = padfLineData[i];
int nVal;
if( CPLIsNan(dfVal) || CPLIsInf(dfVal) )
{
// Most compilers seem to cast NaN or Inf to 0x80000000.
// but VC7 is an exception. So we force the result
// of such a cast.
nVal = 0x80000000;
}
else
{
// Standard behaviour of GDALCopyWords when converting
// from floating point to Int32.
dfVal += 0.5;
if( dfVal < -2147483647.0 )
nVal = -2147483647;
else if( dfVal > 2147483647 )
nVal = 2147483647;
else
nVal = static_cast<GInt32>(floor(dfVal));
}
nChecksum += nVal % anPrimes[iPrime++];
if( iPrime > 10 )
iPrime = 0;
nChecksum &= 0xffff;
}
}
CPLFree(padfLineData);
}
else
{
const GDALDataType eDstDataType = bComplex ? GDT_CInt32 : GDT_Int32;
int *panLineData = static_cast<GInt32 *>(
VSI_MALLOC2_VERBOSE(nXSize,
GDALGetDataTypeSizeBytes(eDstDataType)));
if( panLineData == nullptr )
{
return 0;
}
for( int iLine = nYOff; iLine < nYOff + nYSize; iLine++ )
{
if( GDALRasterIO( hBand, GF_Read, nXOff, iLine, nXSize, 1,
panLineData, nXSize, 1, eDstDataType,
0, 0 ) != CE_None )
{
CPLError(CE_Failure, CPLE_FileIO,
"Checksum value could not be computed due to I/O "
"read error.");
break;
}
const int nCount = bComplex ? nXSize * 2 : nXSize;
for( int i = 0; i < nCount; i++ )
{
nChecksum += panLineData[i] % anPrimes[iPrime++];
if( iPrime > 10 )
iPrime = 0;
nChecksum &= 0xffff;
}
}
CPLFree( panLineData );
}
return nChecksum;
}

View File

@@ -0,0 +1,407 @@
/******************************************************************************
*
* Project: High Performance Image Reprojector
* Purpose: Implement cutline/blend mask generator.
* Author: Frank Warmerdam, warmerdam@pobox.com
*
******************************************************************************
* Copyright (c) 2008, Frank Warmerdam <warmerdam@pobox.com>
* Copyright (c) 2008-2013, Even Rouault <even dot rouault at mines-paris dot org>
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included
* in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
****************************************************************************/
#include "cpl_port.h"
#include "gdalwarper.h"
#include <cmath>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include "cpl_conv.h"
#include "cpl_error.h"
#include "cpl_string.h"
#include "gdal.h"
#include "gdal_alg.h"
#include "ogr_api.h"
#include "ogr_core.h"
#include "ogr_geometry.h"
#include "ogr_geos.h"
CPL_CVSID("$Id: gdalcutline.cpp 7d078e0357d2998edfa713422e607cbadf77f9ff 2018-04-08 22:11:28 +0200 Even Rouault $")
/************************************************************************/
/* BlendMaskGenerator() */
/************************************************************************/
#ifndef HAVE_GEOS
static CPLErr
BlendMaskGenerator( int /* nXOff */, int /* nYOff */,
int /* nXSize */, int /* nYSize */,
GByte * /* pabyPolyMask */,
float * /* pafValidityMask */,
OGRGeometryH /* hPolygon */,
double /* dfBlendDist */ )
{
CPLError(CE_Failure, CPLE_AppDefined,
"Blend distance support not available without the GEOS library.");
return CE_Failure;
}
#else
static CPLErr
BlendMaskGenerator( int nXOff, int nYOff, int nXSize, int nYSize,
GByte *pabyPolyMask, float *pafValidityMask,
OGRGeometryH hPolygon, double dfBlendDist )
{
/* -------------------------------------------------------------------- */
/* Convert the polygon into a collection of lines so that we */
/* measure distance from the edge even on the inside. */
/* -------------------------------------------------------------------- */
OGRGeometry *poLines =
OGRGeometryFactory::forceToMultiLineString(
reinterpret_cast<OGRGeometry *>(hPolygon)->clone() );
/* -------------------------------------------------------------------- */
/* Prepare a clipping polygon a bit bigger than the area of */
/* interest in the hopes of simplifying the cutline down to */
/* stuff that will be relevant for this area of interest. */
/* -------------------------------------------------------------------- */
CPLString osClipRectWKT;
osClipRectWKT.Printf( "POLYGON((%g %g,%g %g,%g %g,%g %g,%g %g))",
nXOff - (dfBlendDist + 1),
nYOff - (dfBlendDist + 1),
nXOff + nXSize + (dfBlendDist + 1),
nYOff - (dfBlendDist + 1),
nXOff + nXSize + (dfBlendDist + 1),
nYOff + nYSize + (dfBlendDist + 1),
nXOff - (dfBlendDist + 1),
nYOff + nYSize + (dfBlendDist + 1),
nXOff - (dfBlendDist + 1),
nYOff - (dfBlendDist + 1) );
OGRPolygon *poClipRect = nullptr;
OGRGeometryFactory::createFromWkt( osClipRectWKT.c_str(), nullptr,
reinterpret_cast<OGRGeometry**>(&poClipRect) );
if( poClipRect )
{
// If it does not intersect the polym, zero the mask and return.
if( !reinterpret_cast<OGRGeometry *>(hPolygon)->Intersects(poClipRect) )
{
memset( pafValidityMask, 0, sizeof(float) * nXSize * nYSize );
delete poLines;
delete poClipRect;
return CE_None;
}
// If it does not intersect the line at all, just return.
else if( !static_cast<OGRGeometry *>(poLines)->Intersects(poClipRect) )
{
delete poLines;
delete poClipRect;
return CE_None;
}
OGRGeometry *poClippedLines = poLines->Intersection(poClipRect);
delete poLines;
poLines = poClippedLines;
delete poClipRect;
}
/* -------------------------------------------------------------------- */
/* Convert our polygon into GEOS format, and compute an */
/* envelope to accelerate later distance operations. */
/* -------------------------------------------------------------------- */
OGREnvelope sEnvelope;
GEOSContextHandle_t hGEOSCtxt = OGRGeometry::createGEOSContext();
GEOSGeom poGEOSPoly = poLines->exportToGEOS(hGEOSCtxt);
OGR_G_GetEnvelope( hPolygon, &sEnvelope );
delete poLines;
// This check was already done in the calling
// function and should never be true.
// if( sEnvelope.MinY - dfBlendDist > nYOff+nYSize
// || sEnvelope.MaxY + dfBlendDist < nYOff
// || sEnvelope.MinX - dfBlendDist > nXOff+nXSize
// || sEnvelope.MaxX + dfBlendDist < nXOff )
// return CE_None;
const int iXMin =
std::max(0,
static_cast<int>(floor(sEnvelope.MinX - dfBlendDist - nXOff)));
const int iXMax =
std::min(nXSize,
static_cast<int>(ceil(sEnvelope.MaxX + dfBlendDist - nXOff)));
const int iYMin =
std::max(0,
static_cast<int>(floor(sEnvelope.MinY - dfBlendDist - nYOff)));
const int iYMax =
std::min(nYSize,
static_cast<int>(ceil(sEnvelope.MaxY + dfBlendDist - nYOff)));
/* -------------------------------------------------------------------- */
/* Loop over potential area within blend line distance, */
/* processing each pixel. */
/* -------------------------------------------------------------------- */
for( int iY = 0; iY < nYSize; iY++ )
{
double dfLastDist = 0.0;
for( int iX = 0; iX < nXSize; iX++ )
{
if( iX < iXMin || iX >= iXMax
|| iY < iYMin || iY > iYMax
|| dfLastDist > dfBlendDist + 1.5 )
{
if( pabyPolyMask[iX + iY * nXSize] == 0 )
pafValidityMask[iX + iY * nXSize] = 0.0;
dfLastDist -= 1.0;
continue;
}
CPLString osPointWKT;
osPointWKT.Printf( "POINT(%d.5 %d.5)", iX + nXOff, iY + nYOff );
GEOSGeom poGEOSPoint = GEOSGeomFromWKT_r( hGEOSCtxt, osPointWKT );
double dfDist = 0.0;
GEOSDistance_r( hGEOSCtxt, poGEOSPoly, poGEOSPoint, &dfDist );
GEOSGeom_destroy_r( hGEOSCtxt, poGEOSPoint );
dfLastDist = dfDist;
if( dfDist > dfBlendDist )
{
if( pabyPolyMask[iX + iY * nXSize] == 0 )
pafValidityMask[iX + iY * nXSize] = 0.0;
continue;
}
const double dfRatio =
pabyPolyMask[iX + iY * nXSize] == 0
? 0.5 - (dfDist / dfBlendDist) * 0.5 // Outside.
: 0.5 + (dfDist / dfBlendDist) * 0.5; // Inside.
pafValidityMask[iX + iY * nXSize] *= static_cast<float>(dfRatio);
}
}
/* -------------------------------------------------------------------- */
/* Cleanup */
/* -------------------------------------------------------------------- */
GEOSGeom_destroy_r( hGEOSCtxt, poGEOSPoly );
OGRGeometry::freeGEOSContext( hGEOSCtxt );
return CE_None;
}
#endif // HAVE_GEOS
/************************************************************************/
/* CutlineTransformer() */
/* */
/* A simple transformer for the cutline that just offsets */
/* relative to the current chunk. */
/************************************************************************/
static int CutlineTransformer( void *pTransformArg,
int bDstToSrc,
int nPointCount,
double *x,
double *y,
double * /* z */,
int * /* panSuccess */ )
{
int nXOff = static_cast<int *>(pTransformArg)[0];
int nYOff = static_cast<int *>(pTransformArg)[1];
if( bDstToSrc )
{
nXOff *= -1;
nYOff *= -1;
}
for( int i = 0; i < nPointCount; i++ )
{
x[i] -= nXOff;
y[i] -= nYOff;
}
return TRUE;
}
/************************************************************************/
/* GDALWarpCutlineMasker() */
/* */
/* This function will generate a source mask based on a */
/* provided cutline, and optional blend distance. */
/************************************************************************/
CPLErr
GDALWarpCutlineMasker( void *pMaskFuncArg,
int /* nBandCount */,
GDALDataType /* eType */,
int nXOff, int nYOff, int nXSize, int nYSize,
GByte ** /*ppImageData */,
int bMaskIsFloat, void *pValidityMask )
{
if( nXSize < 1 || nYSize < 1 )
return CE_None;
/* -------------------------------------------------------------------- */
/* Do some minimal checking. */
/* -------------------------------------------------------------------- */
if( !bMaskIsFloat )
{
CPLAssert( false );
return CE_Failure;
}
GDALWarpOptions *psWO = static_cast<GDALWarpOptions *>(pMaskFuncArg);
if( psWO == nullptr || psWO->hCutline == nullptr )
{
CPLAssert( false );
return CE_Failure;
}
GDALDriverH hMemDriver = GDALGetDriverByName("MEM");
if( hMemDriver == nullptr )
{
CPLError(CE_Failure, CPLE_AppDefined,
"GDALWarpCutlineMasker needs MEM driver");
return CE_Failure;
}
/* -------------------------------------------------------------------- */
/* Check the polygon. */
/* -------------------------------------------------------------------- */
OGRGeometryH hPolygon = static_cast<OGRGeometryH>(psWO->hCutline);
if( wkbFlatten(OGR_G_GetGeometryType(hPolygon)) != wkbPolygon
&& wkbFlatten(OGR_G_GetGeometryType(hPolygon)) != wkbMultiPolygon )
{
CPLAssert( false );
return CE_Failure;
}
OGREnvelope sEnvelope;
OGR_G_GetEnvelope( hPolygon, &sEnvelope );
float *pafMask = static_cast<float *>(pValidityMask);
if( sEnvelope.MaxX + psWO->dfCutlineBlendDist < nXOff
|| sEnvelope.MinX - psWO->dfCutlineBlendDist > nXOff + nXSize
|| sEnvelope.MaxY + psWO->dfCutlineBlendDist < nYOff
|| sEnvelope.MinY - psWO->dfCutlineBlendDist > nYOff + nYSize )
{
// We are far from the blend line - everything is masked to zero.
// It would be nice to realize no work is required for this whole
// chunk!
memset( pafMask, 0, sizeof(float) * nXSize * nYSize );
return CE_None;
}
/* -------------------------------------------------------------------- */
/* Create a byte buffer into which we can burn the */
/* mask polygon and wrap it up as a memory dataset. */
/* -------------------------------------------------------------------- */
GByte *pabyPolyMask = static_cast<GByte *>(CPLCalloc(nXSize, nYSize));
char szDataPointer[100] = {};
// cppcheck-suppress redundantCopy
snprintf( szDataPointer, sizeof(szDataPointer), "DATAPOINTER=" );
CPLPrintPointer(
szDataPointer+strlen(szDataPointer),
pabyPolyMask,
static_cast<int>(sizeof(szDataPointer) - strlen(szDataPointer)) );
GDALDatasetH hMemDS = GDALCreate( hMemDriver, "warp_temp",
nXSize, nYSize, 0, GDT_Byte, nullptr );
char *apszOptions[] = { szDataPointer, nullptr };
GDALAddBand( hMemDS, GDT_Byte, apszOptions );
double adfGeoTransform[6] = { 0.0, 1.0, 0.0, 0.0, 0.0, 1.0 };
GDALSetGeoTransform( hMemDS, adfGeoTransform );
/* -------------------------------------------------------------------- */
/* Burn the polygon into the mask with 1.0 values. */
/* -------------------------------------------------------------------- */
int nTargetBand = 1;
double dfBurnValue = 255.0;
char **papszRasterizeOptions = nullptr;
if( CPLFetchBool( psWO->papszWarpOptions, "CUTLINE_ALL_TOUCHED", false ))
papszRasterizeOptions =
CSLSetNameValue( papszRasterizeOptions, "ALL_TOUCHED", "TRUE" );
int anXYOff[2] = { nXOff, nYOff };
CPLErr eErr =
GDALRasterizeGeometries( hMemDS, 1, &nTargetBand,
1, &hPolygon,
CutlineTransformer, anXYOff,
&dfBurnValue, papszRasterizeOptions,
nullptr, nullptr );
CSLDestroy( papszRasterizeOptions );
// Close and ensure data flushed to underlying array.
GDALClose( hMemDS );
/* -------------------------------------------------------------------- */
/* In the case with no blend distance, we just apply this as a */
/* mask, zeroing out everything outside the polygon. */
/* -------------------------------------------------------------------- */
if( psWO->dfCutlineBlendDist == 0.0 )
{
for( int i = nXSize * nYSize - 1; i >= 0; i-- )
{
if( pabyPolyMask[i] == 0 )
static_cast<float *>(pValidityMask)[i] = 0.0;
}
}
else
{
eErr = BlendMaskGenerator( nXOff, nYOff, nXSize, nYSize,
pabyPolyMask,
static_cast<float *>(pValidityMask),
hPolygon, psWO->dfCutlineBlendDist );
}
/* -------------------------------------------------------------------- */
/* Clean up. */
/* -------------------------------------------------------------------- */
CPLFree( pabyPolyMask );
return eErr;
}

View File

@@ -0,0 +1,716 @@
/******************************************************************************
*
* Project: CIETMap Phase 2
* Purpose: Convert RGB (24bit) to a pseudo-colored approximation using
* Floyd-Steinberg dithering (error diffusion).
* Author: Frank Warmerdam, warmerdam@pobox.com
*
******************************************************************************
* Copyright (c) 2001, Frank Warmerdam
* Copyright (c) 2007, Even Rouault <even dot rouault at mines-paris dot org>
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included
* in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
******************************************************************************
*
* Notes:
*
* [1] Floyd-Steinberg dither:
* I should point out that the actual fractions we used were, assuming
* you are at X, moving left to right:
*
* X 7/16
* 3/16 5/16 1/16
*
* Note that the error goes to four neighbors, not three. I think this
* will probably do better (at least for black and white) than the
* 3/8-3/8-1/4 distribution, at the cost of greater processing. I have
* seen the 3/8-3/8-1/4 distribution described as "our" algorithm before,
* but I have no idea who the credit really belongs to.
* --
* Lou Steinberg
*/
#include "cpl_port.h"
#include "gdal_alg.h"
#include "gdal_alg_priv.h"
#include <cstdlib>
#include <cstring>
#include <algorithm>
#include "cpl_conv.h"
#include "cpl_error.h"
#include "cpl_progress.h"
#include "cpl_vsi.h"
#include "gdal.h"
#include "gdal_priv.h"
#if defined(__x86_64) || defined(_M_X64)
#define USE_SSE2
#endif
#ifdef USE_SSE2
#include <emmintrin.h>
#define CAST_PCT(x) reinterpret_cast<GByte*>(x)
#define ALIGN_INT_ARRAY_ON_16_BYTE(x) \
( ((reinterpret_cast<GUIntptr_t>(x) % 16) != 0 ) \
? reinterpret_cast<int*>(reinterpret_cast<GByte*>(x) + 16 - (reinterpret_cast<GUIntptr_t>(x) % 16)) \
: (x) )
#else
#define CAST_PCT(x) x
#endif
CPL_CVSID("$Id: gdaldither.cpp 7c397f8aee59df906fb51153f5a7980a8cc86d43 2018-04-05 22:42:08 +0200 Even Rouault $")
static int MAKE_COLOR_CODE( int r, int g, int b )
{
return r | (g << 8) | (b << 16);
}
static void FindNearestColor( int nColors, int *panPCT, GByte *pabyColorMap,
int nCLevels );
static int FindNearestColor( int nColors, int *panPCT,
int nRedValue, int nGreenValue, int nBlueValue );
// Structure for a hashmap from a color code to a color index of the
// color table.
// NOTE: if changing the size of this structure, edit
// MEDIAN_CUT_AND_DITHER_BUFFER_SIZE_65536 in gdal_alg_priv.h and take
// into account HashHistogram in gdalmediancut.cpp.
typedef struct
{
GUInt32 nColorCode;
GUInt32 nColorCode2;
GUInt32 nColorCode3;
GByte nIndex;
GByte nIndex2;
GByte nIndex3;
GByte nPadding;
} ColorIndex;
/************************************************************************/
/* GDALDitherRGB2PCT() */
/************************************************************************/
/**
* 24bit to 8bit conversion with dithering.
*
* This functions utilizes Floyd-Steinberg dithering in the process of
* converting a 24bit RGB image into a pseudocolored 8bit image using a
* provided color table.
*
* The red, green and blue input bands do not necessarily need to come
* from the same file, but they must be the same width and height. They will
* be clipped to 8bit during reading, so non-eight bit bands are generally
* inappropriate. Likewise the hTarget band will be written with 8bit values
* and must match the width and height of the source bands.
*
* The color table cannot have more than 256 entries.
*
* @param hRed Red input band.
* @param hGreen Green input band.
* @param hBlue Blue input band.
* @param hTarget Output band.
* @param hColorTable the color table to use with the output band.
* @param pfnProgress callback for reporting algorithm progress matching the
* GDALProgressFunc() semantics. May be NULL.
* @param pProgressArg callback argument passed to pfnProgress.
*
* @return CE_None on success or CE_Failure if an error occurs.
*/
int CPL_STDCALL
GDALDitherRGB2PCT( GDALRasterBandH hRed,
GDALRasterBandH hGreen,
GDALRasterBandH hBlue,
GDALRasterBandH hTarget,
GDALColorTableH hColorTable,
GDALProgressFunc pfnProgress,
void * pProgressArg )
{
return GDALDitherRGB2PCTInternal( hRed, hGreen, hBlue, hTarget,
hColorTable, 5, nullptr, TRUE,
pfnProgress, pProgressArg );
}
int GDALDitherRGB2PCTInternal(
GDALRasterBandH hRed,
GDALRasterBandH hGreen,
GDALRasterBandH hBlue,
GDALRasterBandH hTarget,
GDALColorTableH hColorTable,
int nBits,
// NULL or at least 256 * 256 * 256 * sizeof(GInt16) bytes.
GInt16* pasDynamicColorMap,
int bDither,
GDALProgressFunc pfnProgress,
void* pProgressArg )
{
VALIDATE_POINTER1( hRed, "GDALDitherRGB2PCT", CE_Failure );
VALIDATE_POINTER1( hGreen, "GDALDitherRGB2PCT", CE_Failure );
VALIDATE_POINTER1( hBlue, "GDALDitherRGB2PCT", CE_Failure );
VALIDATE_POINTER1( hTarget, "GDALDitherRGB2PCT", CE_Failure );
VALIDATE_POINTER1( hColorTable, "GDALDitherRGB2PCT", CE_Failure );
/* -------------------------------------------------------------------- */
/* Validate parameters. */
/* -------------------------------------------------------------------- */
const int nXSize = GDALGetRasterBandXSize( hRed );
const int nYSize = GDALGetRasterBandYSize( hRed );
if( GDALGetRasterBandXSize( hGreen ) != nXSize
|| GDALGetRasterBandYSize( hGreen ) != nYSize
|| GDALGetRasterBandXSize( hBlue ) != nXSize
|| GDALGetRasterBandYSize( hBlue ) != nYSize )
{
CPLError( CE_Failure, CPLE_IllegalArg,
"Green or blue band doesn't match size of red band." );
return CE_Failure;
}
if( GDALGetRasterBandXSize( hTarget ) != nXSize
|| GDALGetRasterBandYSize( hTarget ) != nYSize )
{
CPLError( CE_Failure, CPLE_IllegalArg,
"GDALDitherRGB2PCT(): "
"Target band doesn't match size of source bands." );
return CE_Failure;
}
if( pfnProgress == nullptr )
pfnProgress = GDALDummyProgress;
/* -------------------------------------------------------------------- */
/* Setup more direct colormap. */
/* -------------------------------------------------------------------- */
int iColor;
#ifdef USE_SSE2
int anPCTUnaligned[256+4]; // 4 for alignment on 16-byte boundary.
int* anPCT = ALIGN_INT_ARRAY_ON_16_BYTE(anPCTUnaligned);
#else
int anPCT[256*4] = {};
#endif
const int nColors = GDALGetColorEntryCount( hColorTable );
if( nColors == 0 )
{
CPLError( CE_Failure, CPLE_IllegalArg,
"GDALDitherRGB2PCT(): "
"Color table must not be empty." );
return CE_Failure;
}
else if( nColors > 256 )
{
CPLError( CE_Failure, CPLE_IllegalArg,
"GDALDitherRGB2PCT(): "
"Color table cannot have more than 256 entries." );
return CE_Failure;
}
iColor = 0;
do
{
GDALColorEntry sEntry;
GDALGetColorEntryAsRGB( hColorTable, iColor, &sEntry );
CAST_PCT(anPCT)[4*iColor+0] = static_cast<GByte>(sEntry.c1);
CAST_PCT(anPCT)[4*iColor+1] = static_cast<GByte>(sEntry.c2);
CAST_PCT(anPCT)[4*iColor+2] = static_cast<GByte>(sEntry.c3);
CAST_PCT(anPCT)[4*iColor+3] = 0;
iColor++;
} while( iColor < nColors );
#ifdef USE_SSE2
// Pad to multiple of 8 colors.
const int nColorsMod8 = nColors % 8;
if( nColorsMod8 )
{
int iDest = nColors;
for( iColor = 0; iColor < 8 - nColorsMod8 &&
iDest < 256; iColor ++, iDest++)
{
anPCT[iDest] = anPCT[nColors-1];
}
}
#endif
/* -------------------------------------------------------------------- */
/* Setup various variables. */
/* -------------------------------------------------------------------- */
int nCLevels = 1 << nBits;
ColorIndex* psColorIndexMap = nullptr;
GByte *pabyRed = static_cast<GByte *>(VSI_MALLOC_VERBOSE(nXSize));
GByte *pabyGreen = static_cast<GByte *>(VSI_MALLOC_VERBOSE(nXSize));
GByte *pabyBlue = static_cast<GByte *>(VSI_MALLOC_VERBOSE(nXSize));
GByte *pabyIndex = static_cast<GByte *>(VSI_MALLOC_VERBOSE(nXSize));
int *panError = static_cast<int *>(
VSI_CALLOC_VERBOSE(sizeof(int), (nXSize + 2) * 3));
if( pabyRed == nullptr ||
pabyGreen == nullptr ||
pabyBlue == nullptr ||
pabyIndex == nullptr ||
panError == nullptr )
{
CPLFree( pabyRed );
CPLFree( pabyGreen );
CPLFree( pabyBlue );
CPLFree( pabyIndex );
CPLFree( panError );
return CE_Failure;
}
GByte *pabyColorMap = nullptr;
if( pasDynamicColorMap == nullptr )
{
/* -------------------------------------------------------------------- */
/* Build a 24bit to 8 bit color mapping. */
/* -------------------------------------------------------------------- */
pabyColorMap = static_cast<GByte *>(
VSI_MALLOC_VERBOSE(nCLevels * nCLevels * nCLevels * sizeof(GByte)));
if( pabyColorMap == nullptr )
{
CPLFree( pabyRed );
CPLFree( pabyGreen );
CPLFree( pabyBlue );
CPLFree( pabyIndex );
CPLFree( panError );
CPLFree( pabyColorMap );
return CE_Failure;
}
FindNearestColor( nColors, anPCT, pabyColorMap, nCLevels);
}
else
{
pabyColorMap = nullptr;
if( nBits == 8 && static_cast<GIntBig>(nXSize) * nYSize <= 65536 )
{
// If the image is small enough, then the number of colors
// will be limited and using a hashmap, rather than a full table
// will be more efficient.
psColorIndexMap = reinterpret_cast<ColorIndex*>(pasDynamicColorMap);
memset(psColorIndexMap, 0xFF, sizeof(ColorIndex) * PRIME_FOR_65536);
}
else
{
memset(pasDynamicColorMap, 0xFF, 256 * 256 * 256 * sizeof(GInt16));
}
}
/* ==================================================================== */
/* Loop over all scanlines of data to process. */
/* ==================================================================== */
CPLErr err = CE_None;
for( int iScanline = 0; iScanline < nYSize; iScanline++ )
{
/* -------------------------------------------------------------------- */
/* Report progress */
/* -------------------------------------------------------------------- */
if( !pfnProgress( iScanline / static_cast<double>(nYSize),
nullptr, pProgressArg ) )
{
CPLError( CE_Failure, CPLE_UserInterrupt, "User Terminated" );
CPLFree( pabyRed );
CPLFree( pabyGreen );
CPLFree( pabyBlue );
CPLFree( pabyIndex );
CPLFree( panError );
CPLFree( pabyColorMap );
return CE_Failure;
}
/* -------------------------------------------------------------------- */
/* Read source data. */
/* -------------------------------------------------------------------- */
CPLErr err1 =
GDALRasterIO( hRed, GF_Read, 0, iScanline, nXSize, 1,
pabyRed, nXSize, 1, GDT_Byte, 0, 0 );
if( err1 == CE_None )
err1 = GDALRasterIO( hGreen, GF_Read, 0, iScanline, nXSize, 1,
pabyGreen, nXSize, 1, GDT_Byte, 0, 0 );
if( err1 == CE_None )
err1 = GDALRasterIO( hBlue, GF_Read, 0, iScanline, nXSize, 1,
pabyBlue, nXSize, 1, GDT_Byte, 0, 0 );
if( err1 != CE_None )
{
CPLFree( pabyRed );
CPLFree( pabyGreen );
CPLFree( pabyBlue );
CPLFree( pabyIndex );
CPLFree( panError );
CPLFree( pabyColorMap );
return err1;
}
/* -------------------------------------------------------------------- */
/* Apply the error from the previous line to this one. */
/* -------------------------------------------------------------------- */
if( bDither )
{
for( int i = 0; i < nXSize; i++ )
{
pabyRed[i] = static_cast<GByte>(
std::max(0, std::min(255, (pabyRed[i] + panError[i*3+0+3]))));
pabyGreen[i] = static_cast<GByte>(
std::max(0,
std::min(255, (pabyGreen[i] + panError[i*3+1+3]))));
pabyBlue[i] = static_cast<GByte>(
std::max(0, std::min(255,
(pabyBlue[i] + panError[i*3+2+3]))));
}
memset( panError, 0, sizeof(int) * (nXSize+2) * 3 );
}
/* -------------------------------------------------------------------- */
/* Figure out the nearest color to the RGB value. */
/* -------------------------------------------------------------------- */
int nLastRedError = 0;
int nLastGreenError = 0;
int nLastBlueError = 0;
for( int i = 0; i < nXSize; i++ )
{
const int nRedValue =
std::max(0, std::min(255, pabyRed[i] + nLastRedError));
const int nGreenValue =
std::max(0, std::min(255, pabyGreen[i] + nLastGreenError));
const int nBlueValue =
std::max(0, std::min(255, pabyBlue[i] + nLastBlueError));
int iIndex = 0;
int nError = 0;
int nSixth = 0;
if( psColorIndexMap )
{
const GUInt32 nColorCode =
MAKE_COLOR_CODE(nRedValue, nGreenValue, nBlueValue);
GUInt32 nIdx = nColorCode % PRIME_FOR_65536;
while( true )
{
if( psColorIndexMap[nIdx].nColorCode == nColorCode )
{
iIndex = psColorIndexMap[nIdx].nIndex;
break;
}
if( static_cast<int>(psColorIndexMap[nIdx].nColorCode) < 0 )
{
psColorIndexMap[nIdx].nColorCode = nColorCode;
iIndex = FindNearestColor(
nColors, anPCT, nRedValue, nGreenValue, nBlueValue);
psColorIndexMap[nIdx].nIndex =
static_cast<GByte>(iIndex);
break;
}
if( psColorIndexMap[nIdx].nColorCode2 == nColorCode )
{
iIndex = psColorIndexMap[nIdx].nIndex2;
break;
}
if( static_cast<int>(psColorIndexMap[nIdx].nColorCode2) <
0 )
{
psColorIndexMap[nIdx].nColorCode2 = nColorCode;
iIndex = FindNearestColor(
nColors, anPCT, nRedValue, nGreenValue, nBlueValue);
psColorIndexMap[nIdx].nIndex2 =
static_cast<GByte>(iIndex);
break;
}
if( psColorIndexMap[nIdx].nColorCode3 == nColorCode )
{
iIndex = psColorIndexMap[nIdx].nIndex3;
break;
}
if( static_cast<int>(psColorIndexMap[nIdx].nColorCode3) <
0 )
{
psColorIndexMap[nIdx].nColorCode3 = nColorCode;
iIndex = FindNearestColor( nColors, anPCT,
nRedValue, nGreenValue,
nBlueValue );
psColorIndexMap[nIdx].nIndex3 =
static_cast<GByte>(iIndex);
break;
}
do
{
nIdx+=257;
if( nIdx >= PRIME_FOR_65536 )
nIdx -= PRIME_FOR_65536;
}
while( static_cast<int>(psColorIndexMap[nIdx].nColorCode)
>= 0 &&
psColorIndexMap[nIdx].nColorCode != nColorCode &&
static_cast<int>(psColorIndexMap[nIdx].nColorCode2)
>= 0 &&
psColorIndexMap[nIdx].nColorCode2 != nColorCode&&
static_cast<int>(psColorIndexMap[nIdx].nColorCode3)
>= 0 &&
psColorIndexMap[nIdx].nColorCode3 != nColorCode );
}
}
else if( pasDynamicColorMap == nullptr )
{
const int iRed = nRedValue * nCLevels / 256;
const int iGreen = nGreenValue * nCLevels / 256;
const int iBlue = nBlueValue * nCLevels / 256;
iIndex = pabyColorMap[iRed + iGreen * nCLevels
+ iBlue * nCLevels * nCLevels];
}
else
{
const GUInt32 nColorCode =
MAKE_COLOR_CODE(nRedValue, nGreenValue, nBlueValue);
GInt16* psIndex = &pasDynamicColorMap[nColorCode];
if( *psIndex < 0 )
{
*psIndex = static_cast<GInt16>(
FindNearestColor( nColors, anPCT,
nRedValue,
nGreenValue,
nBlueValue ));
iIndex = *psIndex;
}
else
{
iIndex = *psIndex;
}
}
pabyIndex[i] = static_cast<GByte>(iIndex);
if( !bDither )
continue;
/* -------------------------------------------------------------------- */
/* Compute Red error, and carry it on to the next error line. */
/* -------------------------------------------------------------------- */
nError = nRedValue - CAST_PCT(anPCT)[4 * iIndex + 0];
nSixth = nError / 6;
panError[i * 3 ] += nSixth;
panError[i * 3 + 6] = nSixth;
panError[i * 3 + 3] += nError - 5 * nSixth;
nLastRedError = 2 * nSixth;
/* -------------------------------------------------------------------- */
/* Compute Green error, and carry it on to the next error line. */
/* -------------------------------------------------------------------- */
nError = nGreenValue - CAST_PCT(anPCT)[4*iIndex+1];
nSixth = nError / 6;
panError[i * 3 + 1] += nSixth;
panError[i * 3 + 6 + 1] = nSixth;
panError[i * 3 + 3 + 1] += nError - 5 * nSixth;
nLastGreenError = 2 * nSixth;
/* -------------------------------------------------------------------- */
/* Compute Blue error, and carry it on to the next error line. */
/* -------------------------------------------------------------------- */
nError = nBlueValue - CAST_PCT(anPCT)[4*iIndex+2];
nSixth = nError / 6;
panError[i * 3 + 2] += nSixth;
panError[i * 3 + 6 + 2] = nSixth;
panError[i * 3 + 3 + 2] += nError - 5 * nSixth;
nLastBlueError = 2 * nSixth;
}
/* -------------------------------------------------------------------- */
/* Write results. */
/* -------------------------------------------------------------------- */
err = GDALRasterIO( hTarget, GF_Write, 0, iScanline, nXSize, 1,
pabyIndex, nXSize, 1, GDT_Byte, 0, 0 );
if( err != CE_None )
break;
}
pfnProgress( 1.0, nullptr, pProgressArg );
/* -------------------------------------------------------------------- */
/* Cleanup */
/* -------------------------------------------------------------------- */
CPLFree( pabyRed );
CPLFree( pabyGreen );
CPLFree( pabyBlue );
CPLFree( pabyIndex );
CPLFree( panError );
CPLFree( pabyColorMap );
return err;
}
static int FindNearestColor( int nColors, int *panPCT,
int nRedValue, int nGreenValue, int nBlueValue )
{
#ifdef USE_SSE2
int nBestDist = 768;
int nBestIndex = 0;
int anDistanceUnaligned[16+4] = {}; // 4 for alignment on 16-byte boundary.
int* anDistance = ALIGN_INT_ARRAY_ON_16_BYTE(anDistanceUnaligned);
const __m128i ff = _mm_set1_epi32(0xFFFFFFFF);
const __m128i mask_low = _mm_srli_epi64(ff, 32);
const __m128i mask_high = _mm_slli_epi64(ff, 32);
const unsigned int nColorVal =
MAKE_COLOR_CODE(nRedValue, nGreenValue, nBlueValue);
const __m128i thisColor = _mm_set1_epi32(nColorVal);
const __m128i thisColor_low = _mm_srli_epi64(thisColor, 32);
const __m128i thisColor_high = _mm_slli_epi64(thisColor, 32);
for( int iColor = 0; iColor < nColors; iColor+=8 )
{
const __m128i pctColor = _mm_load_si128(reinterpret_cast<__m128i*>(&panPCT[iColor]));
const __m128i pctColor2 = _mm_load_si128(reinterpret_cast<__m128i*>(&panPCT[iColor+4]));
_mm_store_si128(
reinterpret_cast<__m128i*>(anDistance),
_mm_sad_epu8(_mm_and_si128(pctColor, mask_low), thisColor_low));
_mm_store_si128(
reinterpret_cast<__m128i*>(anDistance+4),
_mm_sad_epu8(_mm_and_si128(pctColor, mask_high), thisColor_high));
_mm_store_si128(
reinterpret_cast<__m128i*>(anDistance+8),
_mm_sad_epu8(_mm_and_si128(pctColor2, mask_low), thisColor_low));
_mm_store_si128(
reinterpret_cast<__m128i*>(anDistance+12),
_mm_sad_epu8(_mm_and_si128(pctColor2, mask_high), thisColor_high));
if( anDistance[0] < nBestDist )
{
nBestIndex = iColor;
nBestDist = anDistance[0];
}
if( anDistance[4] < nBestDist )
{
nBestIndex = iColor + 1;
nBestDist = anDistance[4];
}
if( anDistance[2] < nBestDist )
{
nBestIndex = iColor + 2;
nBestDist = anDistance[2];
}
if( anDistance[6] < nBestDist )
{
nBestIndex = iColor + 3;
nBestDist = anDistance[6];
}
if( anDistance[8 + 0] < nBestDist )
{
nBestIndex = iColor + 4;
nBestDist = anDistance[8 + 0];
}
if( anDistance[8 + 4] < nBestDist )
{
nBestIndex = iColor + 4 + 1;
nBestDist = anDistance[8 + 4];
}
if( anDistance[8 + 2] < nBestDist )
{
nBestIndex = iColor + 4 + 2;
nBestDist = anDistance[8 + 2];
}
if( anDistance[8 + 6] < nBestDist )
{
nBestIndex = iColor + 4 + 3;
nBestDist = anDistance[8 + 6];
}
}
return nBestIndex;
#else
int nBestDist = 768;
int nBestIndex = 0;
for( int iColor = 0; iColor < nColors; iColor++ )
{
const int nThisDist =
std::abs(nRedValue - panPCT[4*iColor + 0]) +
std::abs(nGreenValue - panPCT[4*iColor + 1]) +
std::abs(nBlueValue - panPCT[4*iColor + 2]);
if( nThisDist < nBestDist )
{
nBestIndex = iColor;
nBestDist = nThisDist;
}
}
return nBestIndex;
#endif
}
/************************************************************************/
/* FindNearestColor() */
/* */
/* Finear near PCT color for any RGB color. */
/************************************************************************/
static void FindNearestColor( int nColors, int *panPCT, GByte *pabyColorMap,
int nCLevels )
{
/* -------------------------------------------------------------------- */
/* Loop over all the cells in the high density cube. */
/* -------------------------------------------------------------------- */
for( int iBlue = 0; iBlue < nCLevels; iBlue++ )
{
for( int iGreen = 0; iGreen < nCLevels; iGreen++ )
{
for( int iRed = 0; iRed < nCLevels; iRed++ )
{
const int nRedValue = (iRed * 255) / (nCLevels - 1);
const int nGreenValue = (iGreen * 255) / (nCLevels - 1);
const int nBlueValue = (iBlue * 255) / (nCLevels - 1);
const int nBestIndex =
FindNearestColor( nColors, panPCT,
nRedValue, nGreenValue, nBlueValue );
pabyColorMap[iRed + iGreen*nCLevels
+ iBlue*nCLevels*nCLevels] =
static_cast<GByte>(nBestIndex);
}
}
}
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,140 @@
/******************************************************************************
* $Id: gdalgrid.h fcf615cbf6b2e03db17171af0ebba6da4b4a562d 2016-08-05 17:13:05Z Even Rouault $
*
* Project: GDAL Gridding API.
* Purpose: Prototypes, and definitions for of GDAL scattered data gridder.
* Author: Andrey Kiselev, dron@ak4719.spb.edu
*
******************************************************************************
* Copyright (c) 2007, Andrey Kiselev <dron@ak4719.spb.edu>
* Copyright (c) 2012, Even Rouault <even dot rouault at mines-paris dot org>
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included
* in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
****************************************************************************/
#ifndef GDALGRID_H_INCLUDED
#define GDALGRID_H_INCLUDED
/**
* \file gdalgrid.h
*
* GDAL gridder related entry points and definitions.
*/
#include "gdal_alg.h"
/*
* GridCreate Algorithm names
*/
static const char szAlgNameInvDist[] = "invdist";
static const char szAlgNameInvDistNearestNeighbor[] = "invdistnn";
static const char szAlgNameAverage[] = "average";
static const char szAlgNameNearest[] = "nearest";
static const char szAlgNameMinimum[] = "minimum";
static const char szAlgNameMaximum[] = "maximum";
static const char szAlgNameRange[] = "range";
static const char szAlgNameCount[] = "count";
static const char szAlgNameAverageDistance[] = "average_distance";
static const char szAlgNameAverageDistancePts[] = "average_distance_pts";
static const char szAlgNameLinear[] = "linear";
CPL_C_START
/*! @cond Doxygen_Suppress */
typedef CPLErr (*GDALGridFunction)( const void *, GUInt32,
const double *, const double *,
const double *,
double, double, double *,
void* );
/*! @endcond */
CPLErr
GDALGridInverseDistanceToAPower( const void *, GUInt32,
const double *, const double *,
const double *,
double, double, double *,
void* );
CPLErr
GDALGridInverseDistanceToAPowerNearestNeighbor( const void *, GUInt32,
const double *, const double *,
const double *,
double, double, double *,
void* );
CPLErr
GDALGridInverseDistanceToAPowerNoSearch( const void *, GUInt32,
const double *, const double *,
const double *,
double, double, double *,
void* );
CPLErr
GDALGridMovingAverage( const void *, GUInt32,
const double *, const double *, const double *,
double, double, double *,
void* );
CPLErr
GDALGridNearestNeighbor( const void *, GUInt32,
const double *, const double *, const double *,
double, double, double *,
void* );
CPLErr
GDALGridDataMetricMinimum( const void *, GUInt32,
const double *, const double *, const double *,
double, double, double *,
void* );
CPLErr
GDALGridDataMetricMaximum( const void *, GUInt32,
const double *, const double *, const double *,
double, double, double *,
void* );
CPLErr
GDALGridDataMetricRange( const void *, GUInt32,
const double *, const double *, const double *,
double, double, double *,
void* );
CPLErr
GDALGridDataMetricCount( const void *, GUInt32,
const double *, const double *, const double *,
double, double, double *,
void* );
CPLErr
GDALGridDataMetricAverageDistance( const void *, GUInt32,
const double *, const double *,
const double *, double, double, double *,
void* );
CPLErr
GDALGridDataMetricAverageDistancePts( const void *, GUInt32,
const double *, const double *,
const double *, double, double,
double *,
void* );
CPLErr
GDALGridLinear( const void *, GUInt32,
const double *, const double *,
const double *,
double, double, double *,
void* );
CPLErr CPL_DLL
ParseAlgorithmAndOptions( const char *,
GDALGridAlgorithm *,
void ** );
CPL_C_END
#endif /* GDALGRID_H_INCLUDED */

View File

@@ -0,0 +1,94 @@
/******************************************************************************
* $Id: gdalgrid_priv.h 538551c247adf9f139ab49ffd68629bf93bb4404 2016-08-13 21:20:46Z Even Rouault $
*
* Project: GDAL Gridding API.
* Purpose: Prototypes, and definitions for of GDAL scattered data gridder.
* Author: Even Rouault, <even dot rouault at mines dash paris dot org>
*
******************************************************************************
* Copyright (c) 2013, Even Rouault <even dot rouault at mines-paris dot org>
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included
* in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
****************************************************************************/
#ifndef GDALGRID_PRIV_H
#define GDALGRID_PRIV_H
#include "cpl_error.h"
#include "cpl_quad_tree.h"
//! @cond Doxygen_Suppress
typedef struct
{
const double* padfX;
const double* padfY;
} GDALGridXYArrays;
typedef struct
{
GDALGridXYArrays* psXYArrays;
int i;
} GDALGridPoint;
typedef struct
{
CPLQuadTree* hQuadTree;
double dfInitialSearchRadius;
float *pafX; // Aligned to be usable with AVX
float *pafY;
float *pafZ;
GDALTriangulation* psTriangulation;
int nInitialFacetIdx;
/*! Weighting power divided by 2 (pre-computation). */
double dfPowerDiv2PreComp;
/*! The radius of search circle squared (pre-computation). */
double dfRadiusPower2PreComp;
/*! The radius of search circle to power 4 (pre-computation). */
double dfRadiusPower4PreComp;
} GDALGridExtraParameters;
#ifdef HAVE_SSE_AT_COMPILE_TIME
CPLErr
GDALGridInverseDistanceToAPower2NoSmoothingNoSearchSSE(
const void *poOptions,
GUInt32 nPoints,
const double *unused_padfX,
const double *unused_padfY,
const double *unused_padfZ,
double dfXPoint, double dfYPoint,
double *pdfValue,
void* hExtraParamsIn );
#endif
#ifdef HAVE_AVX_AT_COMPILE_TIME
CPLErr GDALGridInverseDistanceToAPower2NoSmoothingNoSearchAVX(
const void *poOptions,
GUInt32 nPoints,
const double *unused_padfX,
const double *unused_padfY,
const double *unused_padfZ,
double dfXPoint, double dfYPoint,
double *pdfValue,
void* hExtraParamsIn );
#endif
//! @endcond
#endif // GDALGRID_PRIV_H

View File

@@ -0,0 +1,202 @@
/******************************************************************************
*
* Project: GDAL Gridding API.
* Purpose: Implementation of GDAL scattered data gridder.
* Author: Even Rouault, <even dot rouault at mines dash paris dot org>
*
******************************************************************************
* Copyright (c) 2013, Even Rouault <even dot rouault at mines-paris dot org>
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included
* in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
****************************************************************************/
#include "gdalgrid.h"
#include "gdalgrid_priv.h"
#ifdef HAVE_AVX_AT_COMPILE_TIME
#include <immintrin.h>
CPL_CVSID("$Id: gdalgridavx.cpp 9ff327806cd64df6d73a6c91f92d12ca0c5e07df 2018-04-07 20:25:06 +0200 Even Rouault $")
/************************************************************************/
/* GDALGridInverseDistanceToAPower2NoSmoothingNoSearchAVX() */
/************************************************************************/
#define GDAL_mm256_load1_ps(x) _mm256_set_ps(x, x, x, x, x, x, x, x)
CPLErr
GDALGridInverseDistanceToAPower2NoSmoothingNoSearchAVX(
const void *poOptions,
GUInt32 nPoints,
CPL_UNUSED const double *unused_padfX,
CPL_UNUSED const double *unused_padfY,
CPL_UNUSED const double *unused_padfZ,
double dfXPoint, double dfYPoint,
double *pdfValue,
void* hExtraParamsIn )
{
size_t i = 0;
GDALGridExtraParameters* psExtraParams = static_cast<GDALGridExtraParameters*>(hExtraParamsIn);
const float* pafX = psExtraParams->pafX;
const float* pafY = psExtraParams->pafY;
const float* pafZ = psExtraParams->pafZ;
const float fEpsilon = 0.0000000000001f;
const float fXPoint = static_cast<float>(dfXPoint);
const float fYPoint = static_cast<float>(dfYPoint);
const __m256 ymm_small = GDAL_mm256_load1_ps(fEpsilon);
const __m256 ymm_x = GDAL_mm256_load1_ps(fXPoint);
const __m256 ymm_y = GDAL_mm256_load1_ps(fYPoint);
__m256 ymm_nominator = _mm256_setzero_ps();
__m256 ymm_denominator = _mm256_setzero_ps();
int mask = 0;
#undef LOOP_SIZE
#if defined(__x86_64) || defined(_M_X64)
/* This would also work in 32bit mode, but there are only 8 XMM registers */
/* whereas we have 16 for 64bit */
#define LOOP_SIZE 16
size_t nPointsRound = (nPoints / LOOP_SIZE) * LOOP_SIZE;
for( i = 0; i < nPointsRound; i += LOOP_SIZE )
{
__m256 ymm_rx = _mm256_sub_ps(_mm256_load_ps(pafX + i), ymm_x); /* rx = pafX[i] - fXPoint */
__m256 ymm_rx_8 = _mm256_sub_ps(_mm256_load_ps(pafX + i + 8), ymm_x);
__m256 ymm_ry = _mm256_sub_ps(_mm256_load_ps(pafY + i), ymm_y); /* ry = pafY[i] - fYPoint */
__m256 ymm_ry_8 = _mm256_sub_ps(_mm256_load_ps(pafY + i + 8), ymm_y);
__m256 ymm_r2 = _mm256_add_ps(_mm256_mul_ps(ymm_rx, ymm_rx), /* r2 = rx * rx + ry * ry */
_mm256_mul_ps(ymm_ry, ymm_ry));
__m256 ymm_r2_8 = _mm256_add_ps(_mm256_mul_ps(ymm_rx_8, ymm_rx_8),
_mm256_mul_ps(ymm_ry_8, ymm_ry_8));
__m256 ymm_invr2 = _mm256_rcp_ps(ymm_r2); /* invr2 = 1.0f / r2 */
__m256 ymm_invr2_8 = _mm256_rcp_ps(ymm_r2_8);
ymm_nominator = _mm256_add_ps(ymm_nominator, /* nominator += invr2 * pafZ[i] */
_mm256_mul_ps(ymm_invr2, _mm256_load_ps(pafZ + i)));
ymm_nominator = _mm256_add_ps(ymm_nominator,
_mm256_mul_ps(ymm_invr2_8, _mm256_load_ps(pafZ + i + 8)));
ymm_denominator = _mm256_add_ps(ymm_denominator, ymm_invr2); /* denominator += invr2 */
ymm_denominator = _mm256_add_ps(ymm_denominator, ymm_invr2_8);
mask = _mm256_movemask_ps(_mm256_cmp_ps(ymm_r2, ymm_small, _CMP_LT_OS)) | /* if( r2 < fEpsilon) */
(_mm256_movemask_ps(_mm256_cmp_ps(ymm_r2_8, ymm_small, _CMP_LT_OS)) << 8);
if( mask )
break;
}
#else
#define LOOP_SIZE 8
size_t nPointsRound = (nPoints / LOOP_SIZE) * LOOP_SIZE;
for( i = 0; i < nPointsRound; i += LOOP_SIZE )
{
__m256 ymm_rx = _mm256_sub_ps(_mm256_load_ps(const_cast<float*>(pafX) + i), ymm_x); /* rx = pafX[i] - fXPoint */
__m256 ymm_ry = _mm256_sub_ps(_mm256_load_ps(const_cast<float*>(pafY) + i), ymm_y); /* ry = pafY[i] - fYPoint */
__m256 ymm_r2 = _mm256_add_ps(_mm256_mul_ps(ymm_rx, ymm_rx), /* r2 = rx * rx + ry * ry */
_mm256_mul_ps(ymm_ry, ymm_ry));
__m256 ymm_invr2 = _mm256_rcp_ps(ymm_r2); /* invr2 = 1.0f / r2 */
ymm_nominator = _mm256_add_ps(ymm_nominator, /* nominator += invr2 * pafZ[i] */
_mm256_mul_ps(ymm_invr2, _mm256_load_ps(const_cast<float*>(pafZ) + i)));
ymm_denominator = _mm256_add_ps(ymm_denominator, ymm_invr2); /* denominator += invr2 */
mask = _mm256_movemask_ps(_mm256_cmp_ps(ymm_r2, ymm_small, _CMP_LT_OS)); /* if( r2 < fEpsilon) */
if( mask )
break;
}
#endif
// Find which i triggered r2 < fEpsilon.
if( mask )
{
for( int j = 0; j < LOOP_SIZE; j++ )
{
if( mask & (1 << j) )
{
(*pdfValue) = (pafZ)[i + j];
// GCC and MSVC need explicit zeroing.
#if !defined(__clang__)
_mm256_zeroupper();
#endif
return CE_None;
}
}
}
#undef LOOP_SIZE
// Get back nominator and denominator values for YMM registers.
float afNominator[8];
float afDenominator[8];
_mm256_storeu_ps(afNominator, ymm_nominator);
_mm256_storeu_ps(afDenominator, ymm_denominator);
// MSVC doesn't emit AVX afterwards but may use SSE, so clear
// upper bits. Other compilers will continue using AVX for the
// below floating points operations.
#if defined(_MSC_FULL_VER)
_mm256_zeroupper();
#endif
float fNominator = afNominator[0] + afNominator[1] +
afNominator[2] + afNominator[3] +
afNominator[4] + afNominator[5] +
afNominator[6] + afNominator[7];
float fDenominator = afDenominator[0] + afDenominator[1] +
afDenominator[2] + afDenominator[3] +
afDenominator[4] + afDenominator[5] +
afDenominator[6] + afDenominator[7];
// Do the few remaining loop iterations.
for( ; i < nPoints; i++ )
{
const float fRX = pafX[i] - fXPoint;
const float fRY = pafY[i] - fYPoint;
const float fR2 =
fRX * fRX + fRY * fRY;
// If the test point is close to the grid node, use the point
// value directly as a node value to avoid singularity.
if( fR2 < 0.0000000000001 )
{
break;
}
else
{
const float fInvR2 = 1.0f / fR2;
fNominator += fInvR2 * pafZ[i];
fDenominator += fInvR2;
}
}
if( i != nPoints )
{
(*pdfValue) = pafZ[i];
}
else
if( fDenominator == 0.0 )
{
(*pdfValue) =
static_cast<const GDALGridInverseDistanceToAPowerOptions*>(poOptions)->dfNoDataValue;
}
else
(*pdfValue) = fNominator / fDenominator;
// GCC needs explicit zeroing.
#if defined(__GNUC__) && !defined(__clang__)
_mm256_zeroupper();
#endif
return CE_None;
}
#endif /* HAVE_AVX_AT_COMPILE_TIME */

View File

@@ -0,0 +1,187 @@
/******************************************************************************
*
* Project: GDAL Gridding API.
* Purpose: Implementation of GDAL scattered data gridder.
* Author: Even Rouault, <even dot rouault at mines dash paris dot org>
*
******************************************************************************
* Copyright (c) 2013, Even Rouault <even dot rouault at mines-paris dot org>
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included
* in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
****************************************************************************/
#include "gdalgrid.h"
#include "gdalgrid_priv.h"
#ifdef HAVE_SSE_AT_COMPILE_TIME
#include <xmmintrin.h>
CPL_CVSID("$Id: gdalgridsse.cpp 9ff327806cd64df6d73a6c91f92d12ca0c5e07df 2018-04-07 20:25:06 +0200 Even Rouault $")
/************************************************************************/
/* GDALGridInverseDistanceToAPower2NoSmoothingNoSearchSSE() */
/************************************************************************/
CPLErr
GDALGridInverseDistanceToAPower2NoSmoothingNoSearchSSE(
const void *poOptions,
GUInt32 nPoints,
CPL_UNUSED const double *unused_padfX,
CPL_UNUSED const double *unused_padfY,
CPL_UNUSED const double *unused_padfZ,
double dfXPoint, double dfYPoint,
double *pdfValue,
void* hExtraParamsIn )
{
size_t i = 0;
GDALGridExtraParameters* psExtraParams =
static_cast<GDALGridExtraParameters *>(hExtraParamsIn);
const float* pafX = psExtraParams->pafX;
const float* pafY = psExtraParams->pafY;
const float* pafZ = psExtraParams->pafZ;
const float fEpsilon = 0.0000000000001f;
const float fXPoint = static_cast<float>(dfXPoint);
const float fYPoint = static_cast<float>(dfYPoint);
const __m128 xmm_small = _mm_load1_ps(const_cast<float *>(&fEpsilon));
const __m128 xmm_x = _mm_load1_ps(const_cast<float*>(&fXPoint));
const __m128 xmm_y = _mm_load1_ps(const_cast<float*>(&fYPoint));
__m128 xmm_nominator = _mm_setzero_ps();
__m128 xmm_denominator = _mm_setzero_ps();
int mask = 0;
#if defined(__x86_64) || defined(_M_X64)
// This would also work in 32bit mode, but there are only 8 XMM registers
// whereas we have 16 for 64bit.
const size_t LOOP_SIZE = 8;
size_t nPointsRound = (nPoints / LOOP_SIZE) * LOOP_SIZE;
for( i = 0; i < nPointsRound; i += LOOP_SIZE )
{
// rx = pafX[i] - fXPoint
__m128 xmm_rx = _mm_sub_ps(_mm_load_ps(pafX + i), xmm_x);
__m128 xmm_rx_4 = _mm_sub_ps(_mm_load_ps(pafX + i + 4), xmm_x);
// ry = pafY[i] - fYPoint
__m128 xmm_ry = _mm_sub_ps(_mm_load_ps(pafY + i), xmm_y);
__m128 xmm_ry_4 = _mm_sub_ps(_mm_load_ps(pafY + i + 4), xmm_y);
// r2 = rx * rx + ry * ry
__m128 xmm_r2 = _mm_add_ps(_mm_mul_ps(xmm_rx, xmm_rx),
_mm_mul_ps(xmm_ry, xmm_ry));
__m128 xmm_r2_4 = _mm_add_ps(_mm_mul_ps(xmm_rx_4, xmm_rx_4),
_mm_mul_ps(xmm_ry_4, xmm_ry_4));
// invr2 = 1.0f / r2
__m128 xmm_invr2 = _mm_rcp_ps(xmm_r2);
__m128 xmm_invr2_4 = _mm_rcp_ps(xmm_r2_4);
// nominator += invr2 * pafZ[i]
xmm_nominator = _mm_add_ps(xmm_nominator,
_mm_mul_ps(xmm_invr2, _mm_load_ps(pafZ + i)));
xmm_nominator = _mm_add_ps(xmm_nominator,
_mm_mul_ps(xmm_invr2_4, _mm_load_ps(pafZ + i + 4)));
// denominator += invr2
xmm_denominator = _mm_add_ps(xmm_denominator, xmm_invr2);
xmm_denominator = _mm_add_ps(xmm_denominator, xmm_invr2_4);
// if( r2 < fEpsilon)
mask = _mm_movemask_ps(_mm_cmplt_ps(xmm_r2, xmm_small)) |
(_mm_movemask_ps(_mm_cmplt_ps(xmm_r2_4, xmm_small)) << 4);
if( mask )
break;
}
#else
#define LOOP_SIZE 4
size_t nPointsRound = (nPoints / LOOP_SIZE) * LOOP_SIZE;
for( i = 0; i < nPointsRound; i += LOOP_SIZE )
{
__m128 xmm_rx = _mm_sub_ps(_mm_load_ps((float*)pafX + i), xmm_x); /* rx = pafX[i] - fXPoint */
__m128 xmm_ry = _mm_sub_ps(_mm_load_ps((float*)pafY + i), xmm_y); /* ry = pafY[i] - fYPoint */
__m128 xmm_r2 = _mm_add_ps(_mm_mul_ps(xmm_rx, xmm_rx), /* r2 = rx * rx + ry * ry */
_mm_mul_ps(xmm_ry, xmm_ry));
__m128 xmm_invr2 = _mm_rcp_ps(xmm_r2); /* invr2 = 1.0f / r2 */
xmm_nominator = _mm_add_ps(xmm_nominator, /* nominator += invr2 * pafZ[i] */
_mm_mul_ps(xmm_invr2, _mm_load_ps((float*)pafZ + i)));
xmm_denominator = _mm_add_ps(xmm_denominator, xmm_invr2); /* denominator += invr2 */
mask = _mm_movemask_ps(_mm_cmplt_ps(xmm_r2, xmm_small)); /* if( r2 < fEpsilon) */
if( mask )
break;
}
#endif
// Find which i triggered r2 < fEpsilon.
if( mask )
{
for( size_t j = 0; j < LOOP_SIZE; j++ )
{
if( mask & (1 << j) )
{
(*pdfValue) = (pafZ)[i + j];
return CE_None;
}
}
}
// Get back nominator and denominator values for XMM registers.
float afNominator[4];
float afDenominator[4];
_mm_storeu_ps(afNominator, xmm_nominator);
_mm_storeu_ps(afDenominator, xmm_denominator);
float fNominator = afNominator[0] + afNominator[1] +
afNominator[2] + afNominator[3];
float fDenominator = afDenominator[0] + afDenominator[1] +
afDenominator[2] + afDenominator[3];
/* Do the few remaining loop iterations */
for( ; i < nPoints; i++ )
{
const float fRX = pafX[i] - fXPoint;
const float fRY = pafY[i] - fYPoint;
const float fR2 =
fRX * fRX + fRY * fRY;
// If the test point is close to the grid node, use the point
// value directly as a node value to avoid singularity.
if( fR2 < 0.0000000000001 )
{
break;
}
else
{
const float fInvR2 = 1.0f / fR2;
fNominator += fInvR2 * pafZ[i];
fDenominator += fInvR2;
}
}
if( i != nPoints )
{
(*pdfValue) = pafZ[i];
}
else
if( fDenominator == 0.0 )
{
(*pdfValue) =
static_cast<const GDALGridInverseDistanceToAPowerOptions*>(poOptions)->dfNoDataValue;
}
else
{
(*pdfValue) = fNominator / fDenominator;
}
return CE_None;
}
#endif /* HAVE_SSE_AT_COMPILE_TIME */

View File

@@ -0,0 +1,264 @@
/******************************************************************************
*
* Project: GDAL
* Purpose: Linear system solver
* Author: VIZRT Development Team.
*
* This code was provided by Gilad Ronnen (gro at visrt dot com) with
* permission to reuse under the following license.
*
******************************************************************************
* Copyright (c) 2004, VIZRT Inc.
* Copyright (c) 2008-2014, Even Rouault <even dot rouault at mines-paris dot org>
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included
* in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
****************************************************************************/
/*! @cond Doxygen_Suppress */
#if defined(HAVE_ARMADILLO) && !defined(DO_NOT_USE_DEBUG_BOOL)
#define DO_NOT_USE_DEBUG_BOOL
#endif
#include "cpl_port.h"
#include "cpl_conv.h"
#include "gdallinearsystem.h"
#ifdef HAVE_ARMADILLO
#include "armadillo"
#endif
#include <cstdio>
#include <vector>
#include <algorithm>
CPL_CVSID("$Id: gdallinearsystem.cpp d6c9bd707d4c2c4ba4390e4d1352d277772ffe8c 2017-12-19 23:54:42Z Alan Thomas $")
static int matrixInvert( int N, const double input[], double output[] );
/************************************************************************/
/* GDALLinearSystemSolve() */
/* */
/* Solves the linear system adfA*adfOut = adfRHS for adfOut, where */
/* adfA is a square matrix. The matrices are given as flat 1D */
/* arrays with the entries in row-major order. */
/* nDim is the number of rows and columns in adfA, and nRHS is the */
/* number of right-hand sides (columns) in adfRHS. */
/************************************************************************/
bool GDALLinearSystemSolve( const int nDim, const int nRHS,
const double adfA[], const double adfRHS[], double adfOut[] )
{
#ifdef HAVE_ARMADILLO
try
{
arma::mat matA( const_cast<double*>( adfA ), nDim, nDim, false );
arma::inplace_trans( matA );
arma::mat matRHS( const_cast<double*>( adfRHS ), nRHS, nDim, false );
arma::inplace_trans( matRHS );
arma::mat matOut;
#if defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 8))
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wzero-as-null-pointer-constant"
#endif
#if ARMA_VERSION_MAJOR > 6 || (ARMA_VERSION_MAJOR == 6 && ARMA_VERSION_MINOR >= 500 )
// Perhaps available in earlier versions, but didn't check
if( arma::solve( matOut, matA, matRHS, arma::solve_opts::equilibrate +
arma::solve_opts::no_approx ) )
#else
if( arma::solve( matOut, matA, matRHS ) )
#endif
#if defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 8))
#pragma GCC diagnostic pop
#endif
{
for( int iEq = 0; iEq < nDim; iEq++ )
for( int iRHS = 0; iRHS < nRHS; iRHS++ )
adfOut[iEq * nRHS + iRHS] = matOut.at(iEq, iRHS);
return true;
}
}
catch(...) {}
#endif
double* adfAInverse = new double[nDim * nDim];
if( !matrixInvert( nDim, adfA, adfAInverse ) )
{
// I guess adfA is singular
delete[] adfAInverse;
return false;
}
// calculate the coefficients
for( int iRHS = 0; iRHS < nRHS; iRHS++ )
{
for( int iEq = 0; iEq < nDim; iEq++ )
{
adfOut[iEq * nRHS + iRHS] = 0.0;
for( int iVar = 0; iVar < nDim; iVar++ )
{
adfOut[iEq * nRHS + iRHS] +=
adfAInverse[iEq * nDim + iVar] *
adfRHS[iVar * nRHS + iRHS];
}
}
}
delete[] adfAInverse;
return true;
}
static int matrixInvert( int N, const double input[], double output[] )
{
// Receives an array of dimension NxN as input. This is passed as a one-
// dimensional array of N-squared size. It produces the inverse of the
// input matrix, returned as output, also of size N-squared. The Gauss-
// Jordan Elimination method is used. (Adapted from a BASIC routine in
// "Basic Scientific Subroutines Vol. 1", courtesy of Scott Edwards.)
// Array elements 0...N-1 are for the first row, N...2N-1 are for the
// second row, etc.
// We need to have a temporary array of size N x 2N. We'll refer to the
// "left" and "right" halves of this array.
#if DEBUG_VERBOSE
fprintf(stderr, "Matrix Inversion input matrix (N=%d)\n", N);/*ok*/
for( int row = 0; row < N; row++ )
{
for( int col = 0; col < N; col++ )
{
fprintf(stderr, "%5.2f ", input[row*N + col]);/*ok*/
}
fprintf(stderr, "\n");/*ok*/
}
#endif
const int tempSize = 2 * N * N;
double* temp = new double[tempSize];
if( temp == nullptr )
{
CPLError(CE_Failure, CPLE_AppDefined,
"matrixInvert(): ERROR - memory allocation failed.");
return false;
}
// First create a double-width matrix with the input array on the left
// and the identity matrix on the right.
for( int row = 0; row < N; row++ )
{
for( int col = 0; col<N; col++ )
{
// Our index into the temp array is X2 because it's twice as wide
// as the input matrix.
temp[ 2*row*N + col ] = input[ row*N+col ]; // left = input matrix
temp[ 2*row*N + col + N ] = 0.0; // right = 0
}
temp[ 2*row*N + row + N ] = 1.0; // 1 on the diagonal of RHS
}
// Now perform row-oriented operations to convert the left hand side
// of temp to the identity matrix. The inverse of input will then be
// on the right.
int max = 0;
int k = 0;
for( k = 0; k < N; k++ )
{
if( k + 1 < N ) // If not on the last row.
{
max = k;
for( int row = k + 1; row < N; row++ ) // Find the maximum element.
{
if( fabs( temp[row*2*N + k] ) > fabs( temp[max*2*N + k] ) )
{
max = row;
}
}
if( max != k ) // Swap all the elements in the two rows.
{
for( int col = k; col < 2 * N; col++ )
{
std::swap(temp[k*2*N + col], temp[max*2*N + col]);
}
}
}
const double ftemp = temp[k*2*N + k];
if( ftemp == 0.0 ) // Matrix cannot be inverted.
{
delete[] temp;
return false;
}
for( int col = k; col < 2 * N; col++ )
{
temp[k*2*N + col] /= ftemp;
}
const int i2 = k * 2 * N;
for( int row = 0; row < N; row++ )
{
if( row != k )
{
const int i1 = row * 2 * N;
const double ftemp2 = temp[ i1 + k ];
for( int col = k; col < 2*N; col++ )
{
temp[i1 + col] -= ftemp2 * temp[i2 + col];
}
}
}
}
// Retrieve inverse from the right side of temp.
for( int row = 0; row < N; row++ )
{
for( int col = 0; col < N; col++ )
{
output[row*N + col] = temp[row*2*N + col + N ];
}
}
delete [] temp;
#if DEBUG_VERBOSE
fprintf(stderr, "Matrix Inversion result matrix:\n");/*ok*/
for( int row = 0; row < N; row++ )
{
for( int col = 0; col < N; col++ )
{
fprintf(stderr, "%5.2f ", output[row*N + col]);/*ok*/
}
fprintf(stderr, "\n");/*ok*/
}
#endif
return true;
}
/*! @endcond */

View File

@@ -0,0 +1,39 @@
/******************************************************************************
*
* Project: GDAL
* Purpose: Linear system solver
* Author: VIZRT Development Team.
*
******************************************************************************
* Copyright (c) 2017 Alan Thomas <alant@outlook.com.au>
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included
* in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
****************************************************************************/
/*! @cond Doxygen_Suppress */
#ifndef GDALLINEARSYSTEM_H_INCLUDED
#define GDALLINEARSYSTEM_H_INCLUDED
bool GDALLinearSystemSolve( const int nDim, const int nRHS,
const double adfA[], const double adfRHS[], double adfOut[] );
#endif /* #ifndef GDALLINEARSYSTEM_H_INCLUDED */
/*! @endcond */

View File

@@ -0,0 +1,316 @@
/******************************************************************************
*
* Project: GDAL
* Purpose: GDAL Wrapper for image matching via correlation algorithm.
* Author: Frank Warmerdam, warmerdam@pobox.com
* Author: Andrew Migal, migal.drew@gmail.com
*
******************************************************************************
* Copyright (c) 2012, Frank Warmerdam
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included
* in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
****************************************************************************/
#include "gdal_alg.h"
#include "gdal_simplesurf.h"
//! @cond Doxygen_Suppress
CPL_CVSID("$Id: gdalmatching.cpp 9ff327806cd64df6d73a6c91f92d12ca0c5e07df 2018-04-07 20:25:06 +0200 Even Rouault $")
//! @endcond
// TODO(schwehr): What? This below: "0,001"
/**
* @file
* @author Andrew Migal migal.drew@gmail.com
* @brief Algorithms for searching corresponding points on images.
* @details This implementation is based on an simplified version
* of SURF algorithm (Speeded Up Robust Features).
* Provides capability for detection feature points
* and finding equal points on different images.
* As original, this realization is scale invariant, but sensitive to rotation.
* Images should have similar rotation angles (maximum difference is up to 10-15
* degrees), otherwise algorithm produces incorrect and very unstable results.
*/
/**
* Detect feature points on provided image. Please carefully read documentation
* below.
*
* @param poDataset Image on which feature points will be detected
* @param panBands Array of 3 raster bands numbers, for Red, Green, Blue bands
* (in that order)
* @param nOctaveStart Number of bottom octave. Octave numbers starts from one.
* This value directly and strongly affects to amount of recognized points
* @param nOctaveEnd Number of top octave. Should be equal or greater than
* octaveStart
* @param dfThreshold Value from 0 to 1. Threshold for feature point
* recognition. Number of detected points is larger if threshold is lower
*
* @see GDALFeaturePoint, GDALSimpleSURF class for details.
*
* @note Every octave finds points in specific size. For small images
* use small octave numbers, for high resolution - large.
* For 1024x1024 images it's normal to use any octave numbers from range 1-6.
* (for example, octave start - 1, octave end - 3, or octave start - 2, octave
* end - 2.)
* For larger images, try 1-10 range or even higher.
* Pay attention that number of detected point decreases quickly per octave for
* particular image. Algorithm finds more points in case of small octave number.
* If method detects nothing, reduce octave start value.
* In addition, if many feature points are required (the largest possible
* amount), use the lowest octave start value (1) and wide octave range.
*
* @note Typical threshold's value is 0,001. It's pretty good for all images.
* But this value depends on image's nature and may be various in each
* particular case.
* For example, value can be 0,002 or 0,005.
* Notice that number of detected points is larger if threshold is lower.
* But with high threshold feature points will be better - "stronger", more
* "unique" and distinctive.
*
* Feel free to experiment with parameters, because character, robustness and
* number of points entirely depend on provided range of octaves and threshold.
*
* NOTICE that every octave requires time to compute. Use a little range
* or only one octave, if execution time is significant.
*
* @return CE_None or CE_Failure if error occurs.
*/
static std::vector<GDALFeaturePoint> *
GatherFeaturePoints( GDALDataset* poDataset, int* panBands,
int nOctaveStart, int nOctaveEnd, double dfThreshold )
{
if( poDataset == nullptr )
{
CPLError(CE_Failure, CPLE_AppDefined, "GDALDataset isn't specified");
return nullptr;
}
if( panBands == nullptr )
{
CPLError(CE_Failure, CPLE_AppDefined,
"Raster bands are not specified");
return nullptr;
}
if( nOctaveStart <= 0 || nOctaveEnd < 0 ||
nOctaveStart > nOctaveEnd )
{
CPLError(CE_Failure, CPLE_AppDefined,
"Octave numbers are invalid");
return nullptr;
}
if( dfThreshold < 0 )
{
CPLError(CE_Failure, CPLE_AppDefined,
"Threshold have to be greater than zero");
return nullptr;
}
GDALRasterBand *poRstRedBand = poDataset->GetRasterBand(panBands[0]);
GDALRasterBand *poRstGreenBand = poDataset->GetRasterBand(panBands[1]);
GDALRasterBand *poRstBlueBand = poDataset->GetRasterBand(panBands[2]);
const int nWidth = poRstRedBand->GetXSize();
const int nHeight = poRstRedBand->GetYSize();
if( nWidth == 0 || nHeight == 0 )
{
CPLError(CE_Failure, CPLE_AppDefined,
"Must have non-zero width and height.");
return nullptr;
}
// Allocate memory for grayscale image.
double **padfImg = new double*[nHeight];
for( int i = 0; ; )
{
padfImg[i] = new double[nWidth];
for( int j = 0; j < nWidth; ++j )
padfImg[i][j] = 0.0;
++i;
if( i == nHeight )
break;
}
// Create grayscale image.
GDALSimpleSURF::ConvertRGBToLuminosity(
poRstRedBand, poRstGreenBand, poRstBlueBand, nWidth, nHeight,
padfImg, nHeight, nWidth);
// Prepare integral image.
GDALIntegralImage *poImg = new GDALIntegralImage();
poImg->Initialize(const_cast<const double**>(padfImg), nHeight, nWidth);
// Get feature points.
GDALSimpleSURF *poSurf = new GDALSimpleSURF(nOctaveStart, nOctaveEnd);
std::vector<GDALFeaturePoint> *poCollection =
poSurf->ExtractFeaturePoints(poImg, dfThreshold);
// Clean up.
delete poImg;
delete poSurf;
for( int i = 0; i < nHeight; ++i )
delete[] padfImg[i];
delete[] padfImg;
return poCollection;
}
/************************************************************************/
/* GDALComputeMatchingPoints() */
/************************************************************************/
/** GDALComputeMatchingPoints. TODO document */
GDAL_GCP CPL_DLL *
GDALComputeMatchingPoints( GDALDatasetH hFirstImage,
GDALDatasetH hSecondImage,
char **papszOptions,
int *pnGCPCount )
{
*pnGCPCount = 0;
/* -------------------------------------------------------------------- */
/* Override default algorithm parameters. */
/* -------------------------------------------------------------------- */
int nOctaveStart, nOctaveEnd;
double dfSURFThreshold;
nOctaveStart =atoi(CSLFetchNameValueDef(papszOptions, "OCTAVE_START", "2"));
nOctaveEnd = atoi(CSLFetchNameValueDef(papszOptions, "OCTAVE_END", "2"));
dfSURFThreshold = CPLAtof(
CSLFetchNameValueDef(papszOptions, "SURF_THRESHOLD", "0.001"));
const double dfMatchingThreshold = CPLAtof(
CSLFetchNameValueDef(papszOptions, "MATCHING_THRESHOLD", "0.015"));
/* -------------------------------------------------------------------- */
/* Identify the bands to use. For now we are effectively */
/* limited to using RGB input so if we have one band only treat */
/* it as red=green=blue=band 1. Disallow non eightbit imagery. */
/* -------------------------------------------------------------------- */
int anBandMap1[3] = { 1, 1, 1 };
if( GDALGetRasterCount(hFirstImage) >= 3 )
{
anBandMap1[1] = 2;
anBandMap1[2] = 3;
}
int anBandMap2[3] = { 1, 1, 1 };
if( GDALGetRasterCount(hSecondImage) >= 3 )
{
anBandMap2[1] = 2;
anBandMap2[2] = 3;
}
/* -------------------------------------------------------------------- */
/* Collect reference points on each image. */
/* -------------------------------------------------------------------- */
std::vector<GDALFeaturePoint> *poFPCollection1 =
GatherFeaturePoints(reinterpret_cast<GDALDataset *>(hFirstImage),
anBandMap1,
nOctaveStart, nOctaveEnd, dfSURFThreshold);
if( poFPCollection1 == nullptr )
return nullptr;
std::vector<GDALFeaturePoint> *poFPCollection2 =
GatherFeaturePoints(reinterpret_cast<GDALDataset *>(hSecondImage),
anBandMap2,
nOctaveStart, nOctaveEnd,
dfSURFThreshold);
if( poFPCollection2 == nullptr )
{
delete poFPCollection1;
return nullptr;
}
/* -------------------------------------------------------------------- */
/* Try to find corresponding locations. */
/* -------------------------------------------------------------------- */
std::vector<GDALFeaturePoint *> oMatchPairs;
if( CE_None != GDALSimpleSURF::MatchFeaturePoints(
&oMatchPairs, poFPCollection1, poFPCollection2,
dfMatchingThreshold ))
{
delete poFPCollection1;
delete poFPCollection2;
return nullptr;
}
*pnGCPCount = static_cast<int>(oMatchPairs.size()) / 2;
/* -------------------------------------------------------------------- */
/* Translate these into GCPs - but with the output coordinate */
/* system being pixel/line on the second image. */
/* -------------------------------------------------------------------- */
GDAL_GCP *pasGCPList =
static_cast<GDAL_GCP*>(CPLCalloc(*pnGCPCount, sizeof(GDAL_GCP)));
GDALInitGCPs(*pnGCPCount, pasGCPList);
for( int i=0; i < *pnGCPCount; i++ )
{
GDALFeaturePoint *poPoint1 = oMatchPairs[i*2 ];
GDALFeaturePoint *poPoint2 = oMatchPairs[i*2+1];
pasGCPList[i].dfGCPPixel = poPoint1->GetX() + 0.5;
pasGCPList[i].dfGCPLine = poPoint1->GetY() + 0.5;
pasGCPList[i].dfGCPX = poPoint2->GetX() + 0.5;
pasGCPList[i].dfGCPY = poPoint2->GetY() + 0.5;
pasGCPList[i].dfGCPZ = 0.0;
}
// Cleanup the feature point lists.
delete poFPCollection1;
delete poFPCollection2;
/* -------------------------------------------------------------------- */
/* Optionally transform into the georef coordinates of the */
/* output image. */
/* -------------------------------------------------------------------- */
const bool bGeorefOutput =
CPLTestBool(CSLFetchNameValueDef(papszOptions, "OUTPUT_GEOREF", "NO"));
if( bGeorefOutput )
{
double adfGeoTransform[6] = {};
GDALGetGeoTransform( hSecondImage, adfGeoTransform );
for( int i=0; i < *pnGCPCount; i++ )
{
GDALApplyGeoTransform(adfGeoTransform,
pasGCPList[i].dfGCPX,
pasGCPList[i].dfGCPY,
&(pasGCPList[i].dfGCPX),
&(pasGCPList[i].dfGCPY));
}
}
return pasGCPList;
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,289 @@
/******************************************************************************
* $Id: gdalpansharpen.h fe2d81c8819bf9794bce0210098e637565728350 2018-05-06 00:49:51 +0200 Even Rouault $
*
* Project: GDAL Pansharpening module
* Purpose: Prototypes, and definitions for pansharpening related work.
* Author: Even Rouault <even.rouault at spatialys.com>
*
******************************************************************************
* Copyright (c) 2015, Even Rouault <even.rouault at spatialys.com>
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included
* in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
****************************************************************************/
#ifndef GDALPANSHARPEN_H_INCLUDED
#define GDALPANSHARPEN_H_INCLUDED
#include "gdal.h"
CPL_C_START
/**
* \file gdalpansharpen.h
*
* GDAL pansharpening related entry points and definitions.
*
* @since GDAL 2.1
*/
/** Pansharpening algorithms.
*/
typedef enum
{
/*! Weighted Brovery. */
GDAL_PSH_WEIGHTED_BROVEY
} GDALPansharpenAlg;
/** Pansharpening options.
*/
typedef struct
{
/*! Pan sharpening algorithm/method. Only weighed Brovey for now. */
GDALPansharpenAlg ePansharpenAlg;
/*! Resampling algorithm to upsample spectral bands to pan band resolution. */
GDALRIOResampleAlg eResampleAlg;
/*! Bit depth of the spectral bands. Can be let to 0 for default behaviour. */
int nBitDepth;
/*! Number of weight coefficients in padfWeights. */
int nWeightCount;
/*! Array of nWeightCount weights used by weighted Brovey. */
double *padfWeights;
/*! Panchromatic band. */
GDALRasterBandH hPanchroBand;
/*! Number of input spectral bands. */
int nInputSpectralBands;
/** Array of nInputSpectralBands input spectral bands. The spectral band have
* generally a coarser resolution than the panchromatic band, but they
* are assumed to have the same spatial extent (and projection) at that point.
* Necessary spatial adjustments must be done beforehand, for example by wrapping
* inside a VRT dataset.
*/
GDALRasterBandH *pahInputSpectralBands;
/*! Number of output pansharpened spectral bands. */
int nOutPansharpenedBands;
/*! Array of nOutPansharpendBands values such as panOutPansharpenedBands[k] is a value in the range [0,nInputSpectralBands-1] . */
int *panOutPansharpenedBands;
/*! Whether the panchromatic and spectral bands have a noData value. */
int bHasNoData;
/** NoData value of the panchromatic and spectral bands (only taken into account if bHasNoData = TRUE).
This will also be use has the output nodata value. */
double dfNoData;
/** Number of threads or -1 to mean ALL_CPUS. By default (0), single threaded mode is enabled
* unless the GDAL_NUM_THREADS configuration option is set to an integer or ALL_CPUS. */
int nThreads;
/** Shift in pixels of multispectral bands w.r.t panchromatic band, in X direction */
double dfMSShiftX;
/** Shift in pixels of multispectral bands w.r.t panchromatic band, in Y direction */
double dfMSShiftY;
} GDALPansharpenOptions;
GDALPansharpenOptions CPL_DLL * GDALCreatePansharpenOptions(void);
void CPL_DLL GDALDestroyPansharpenOptions( GDALPansharpenOptions * );
GDALPansharpenOptions CPL_DLL * GDALClonePansharpenOptions(
const GDALPansharpenOptions* psOptions);
/*! Pansharpening operation handle. */
typedef void* GDALPansharpenOperationH;
GDALPansharpenOperationH CPL_DLL GDALCreatePansharpenOperation(const GDALPansharpenOptions* );
void CPL_DLL GDALDestroyPansharpenOperation( GDALPansharpenOperationH );
CPLErr CPL_DLL GDALPansharpenProcessRegion( GDALPansharpenOperationH hOperation,
int nXOff, int nYOff,
int nXSize, int nYSize,
void *pDataBuf,
GDALDataType eBufDataType);
CPL_C_END
#ifdef __cplusplus
#include <vector>
#include "gdal_priv.h"
#include "cpl_worker_thread_pool.h"
#ifdef DEBUG_TIMING
#include <sys/time.h>
#endif
class GDALPansharpenOperation;
//! @cond Doxygen_Suppress
typedef struct
{
GDALPansharpenOperation* poPansharpenOperation;
GDALDataType eWorkDataType;
GDALDataType eBufDataType;
const void* pPanBuffer;
const void* pUpsampledSpectralBuffer;
void* pDataBuf;
int nValues;
int nBandValues;
GUInt32 nMaxValue;
#ifdef DEBUG_TIMING
struct timeval* ptv;
#endif
CPLErr eErr;
} GDALPansharpenJob;
typedef struct
{
GDALDataset* poMEMDS;
int nXOff;
int nYOff;
int nXSize;
int nYSize;
double dfXOff;
double dfYOff;
double dfXSize;
double dfYSize;
void *pBuffer;
GDALDataType eDT;
int nBufXSize;
int nBufYSize;
int nBandCount;
GDALRIOResampleAlg eResampleAlg;
GSpacing nBandSpace;
#ifdef DEBUG_TIMING
struct timeval* ptv;
#endif
} GDALPansharpenResampleJob;
//! @endcond
/** Pansharpening operation class.
*/
class GDALPansharpenOperation
{
CPL_DISALLOW_COPY_ASSIGN(GDALPansharpenOperation)
GDALPansharpenOptions* psOptions = nullptr;
std::vector<int> anInputBands{};
std::vector<GDALDataset*> aVDS{}; // to destroy
std::vector<GDALRasterBand*> aMSBands{}; // original multispectral bands potentially warped into a VRT
int bPositiveWeights = TRUE;
CPLWorkerThreadPool* poThreadPool = nullptr;
int nKernelRadius = 0;
static void PansharpenJobThreadFunc(void* pUserData);
static void PansharpenResampleJobThreadFunc(void* pUserData);
template<class WorkDataType, class OutDataType> void WeightedBroveyWithNoData(
const WorkDataType* pPanBuffer,
const WorkDataType* pUpsampledSpectralBuffer,
OutDataType* pDataBuf,
int nValues,
int nBandValues,
WorkDataType nMaxValue) const;
template<class WorkDataType, class OutDataType, int bHasBitDepth> void WeightedBrovey3(
const WorkDataType* pPanBuffer,
const WorkDataType* pUpsampledSpectralBuffer,
OutDataType* pDataBuf,
int nValues,
int nBandValues,
WorkDataType nMaxValue) const;
// cppcheck-suppress functionStatic
template<class WorkDataType, class OutDataType> void WeightedBrovey(
const WorkDataType* pPanBuffer,
const WorkDataType* pUpsampledSpectralBuffer,
OutDataType* pDataBuf,
int nValues,
int nBandValues,
WorkDataType nMaxValue) const;
template<class WorkDataType> CPLErr WeightedBrovey(
const WorkDataType* pPanBuffer,
const WorkDataType* pUpsampledSpectralBuffer,
void *pDataBuf,
GDALDataType eBufDataType,
int nValues,
int nBandValues,
WorkDataType nMaxValue) const;
// cppcheck-suppress functionStatic
template<class WorkDataType> CPLErr WeightedBrovey(
const WorkDataType* pPanBuffer,
const WorkDataType* pUpsampledSpectralBuffer,
void *pDataBuf,
GDALDataType eBufDataType,
int nValues,
int nBandValues) const;
template<class T> void WeightedBroveyPositiveWeights(
const T* pPanBuffer,
const T* pUpsampledSpectralBuffer,
T* pDataBuf,
int nValues,
int nBandValues,
T nMaxValue) const;
template<class T, int NINPUT, int NOUTPUT> int WeightedBroveyPositiveWeightsInternal(
const T* pPanBuffer,
const T* pUpsampledSpectralBuffer,
T* pDataBuf,
int nValues,
int nBandValues,
T nMaxValue) const;
// cppcheck-suppress unusedPrivateFunction
template<class T> void WeightedBroveyGByteOrUInt16(
const T* pPanBuffer,
const T* pUpsampledSpectralBuffer,
T* pDataBuf,
int nValues,
int nBandValues,
T nMaxValue ) const;
CPLErr PansharpenChunk( GDALDataType eWorkDataType, GDALDataType eBufDataType,
const void* pPanBuffer,
const void* pUpsampledSpectralBuffer,
void* pDataBuf,
int nValues,
int nBandValues,
GUInt32 nMaxValue) const;
public:
GDALPansharpenOperation();
~GDALPansharpenOperation();
CPLErr Initialize(const GDALPansharpenOptions* psOptions);
CPLErr ProcessRegion(int nXOff, int nYOff,
int nXSize, int nYSize,
void *pDataBuf,
GDALDataType eBufDataType);
GDALPansharpenOptions* GetOptions();
};
#endif /* __cplusplus */
#endif /* GDALPANSHARPEN_H_INCLUDED */

View File

@@ -0,0 +1,594 @@
/******************************************************************************
*
* Project: GDAL
* Purpose: Compute each pixel's proximity to a set of target pixels.
* Author: Frank Warmerdam, warmerdam@pobox.com
*
******************************************************************************
* Copyright (c) 2008, Frank Warmerdam
* Copyright (c) 2009-2010, Even Rouault <even dot rouault at mines-paris dot org>
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included
* in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
****************************************************************************/
#include "cpl_port.h"
#include "gdal_alg.h"
#include <cmath>
#include <cstdlib>
#include <algorithm>
#include "cpl_conv.h"
#include "cpl_error.h"
#include "cpl_progress.h"
#include "cpl_string.h"
#include "cpl_vsi.h"
#include "gdal.h"
CPL_CVSID("$Id: gdalproximity.cpp 7e07230bbff24eb333608de4dbd460b7312839d0 2017-12-11 19:08:47Z Even Rouault $")
static CPLErr
ProcessProximityLine( GInt32 *panSrcScanline, int *panNearX, int *panNearY,
int bForward, int iLine, int nXSize, double nMaxDist,
float *pafProximity, double *pdfSrcNoDataValue,
int nTargetValues, int *panTargetValues );
/************************************************************************/
/* GDALComputeProximity() */
/************************************************************************/
/**
Compute the proximity of all pixels in the image to a set of pixels in
the source image.
This function attempts to compute the proximity of all pixels in
the image to a set of pixels in the source image. The following
options are used to define the behavior of the function. By
default all non-zero pixels in hSrcBand will be considered the
"target", and all proximities will be computed in pixels. Note
that target pixels are set to the value corresponding to a distance
of zero.
The progress function args may be NULL or a valid progress reporting function
such as GDALTermProgress/NULL.
Options:
VALUES=n[,n]*
A list of target pixel values to measure the distance from. If this
option is not provided proximity will be computed from non-zero
pixel values. Currently pixel values are internally processed as
integers.
DISTUNITS=[PIXEL]/GEO
Indicates whether distances will be computed in pixel units or
in georeferenced units. The default is pixel units. This also
determines the interpretation of MAXDIST.
MAXDIST=n
The maximum distance to search. Proximity distances greater than
this value will not be computed. Instead output pixels will be
set to a nodata value.
NODATA=n
The NODATA value to use on the output band for pixels that are
beyond MAXDIST. If not provided, the hProximityBand will be
queried for a nodata value. If one is not found, 65535 will be used.
USE_INPUT_NODATA=YES/NO
If this option is set, the input data set no-data value will be
respected. Leaving no data pixels in the input as no data pixels in
the proximity output.
FIXED_BUF_VAL=n
If this option is set, all pixels within the MAXDIST threadhold are
set to this fixed value instead of to a proximity distance.
*/
CPLErr CPL_STDCALL
GDALComputeProximity( GDALRasterBandH hSrcBand,
GDALRasterBandH hProximityBand,
char **papszOptions,
GDALProgressFunc pfnProgress,
void * pProgressArg )
{
VALIDATE_POINTER1( hSrcBand, "GDALComputeProximity", CE_Failure );
VALIDATE_POINTER1( hProximityBand, "GDALComputeProximity", CE_Failure );
if( pfnProgress == nullptr )
pfnProgress = GDALDummyProgress;
/* -------------------------------------------------------------------- */
/* Are we using pixels or georeferenced coordinates for distances? */
/* -------------------------------------------------------------------- */
double dfDistMult = 1.0;
const char *pszOpt = CSLFetchNameValue( papszOptions, "DISTUNITS" );
if( pszOpt )
{
if( EQUAL(pszOpt, "GEO") )
{
GDALDatasetH hSrcDS = GDALGetBandDataset( hSrcBand );
if( hSrcDS )
{
double adfGeoTransform[6] = { 0.0, 0.0, 0.0, 0.0, 0.0, 0.0 };
GDALGetGeoTransform( hSrcDS, adfGeoTransform );
if( std::abs(adfGeoTransform[1]) !=
std::abs(adfGeoTransform[5]) )
CPLError(
CE_Warning, CPLE_AppDefined,
"Pixels not square, distances will be inaccurate." );
dfDistMult = std::abs(adfGeoTransform[1]);
}
}
else if( !EQUAL(pszOpt, "PIXEL") )
{
CPLError(
CE_Failure, CPLE_AppDefined,
"Unrecognized DISTUNITS value '%s', should be GEO or PIXEL.",
pszOpt );
return CE_Failure;
}
}
/* -------------------------------------------------------------------- */
/* What is our maxdist value? */
/* -------------------------------------------------------------------- */
pszOpt = CSLFetchNameValue( papszOptions, "MAXDIST" );
const double dfMaxDist = pszOpt ?
CPLAtof(pszOpt) / dfDistMult :
GDALGetRasterBandXSize(hSrcBand) + GDALGetRasterBandYSize(hSrcBand);
CPLDebug( "GDAL", "MAXDIST=%g, DISTMULT=%g", dfMaxDist, dfDistMult );
/* -------------------------------------------------------------------- */
/* Verify the source and destination are compatible. */
/* -------------------------------------------------------------------- */
const int nXSize = GDALGetRasterBandXSize( hSrcBand );
const int nYSize = GDALGetRasterBandYSize( hSrcBand );
if( nXSize != GDALGetRasterBandXSize( hProximityBand )
|| nYSize != GDALGetRasterBandYSize( hProximityBand ))
{
CPLError( CE_Failure, CPLE_AppDefined,
"Source and proximity bands are not the same size." );
return CE_Failure;
}
/* -------------------------------------------------------------------- */
/* Get input NODATA value. */
/* -------------------------------------------------------------------- */
double dfSrcNoDataValue = 0.0;
double *pdfSrcNoData = nullptr;
if( CPLFetchBool( papszOptions, "USE_INPUT_NODATA", false ) )
{
int bSrcHasNoData = 0;
dfSrcNoDataValue = GDALGetRasterNoDataValue( hSrcBand, &bSrcHasNoData );
if( bSrcHasNoData )
pdfSrcNoData = &dfSrcNoDataValue;
}
/* -------------------------------------------------------------------- */
/* Get output NODATA value. */
/* -------------------------------------------------------------------- */
float fNoDataValue = 0.0f;
pszOpt = CSLFetchNameValue( papszOptions, "NODATA" );
if( pszOpt != nullptr )
{
fNoDataValue = static_cast<float>(CPLAtof(pszOpt));
}
else
{
int bSuccess = FALSE;
fNoDataValue = static_cast<float>(
GDALGetRasterNoDataValue( hProximityBand, &bSuccess ) );
if( !bSuccess )
fNoDataValue = 65535.0;
}
/* -------------------------------------------------------------------- */
/* Is there a fixed value we wish to force the buffer area to? */
/* -------------------------------------------------------------------- */
double dfFixedBufVal = 0.0;
bool bFixedBufVal = false;
pszOpt = CSLFetchNameValue( papszOptions, "FIXED_BUF_VAL" );
if( pszOpt )
{
dfFixedBufVal = CPLAtof(pszOpt);
bFixedBufVal = true;
}
/* -------------------------------------------------------------------- */
/* Get the target value(s). */
/* -------------------------------------------------------------------- */
int *panTargetValues = nullptr;
int nTargetValues = 0;
pszOpt = CSLFetchNameValue( papszOptions, "VALUES" );
if( pszOpt != nullptr )
{
char **papszValuesTokens =
CSLTokenizeStringComplex( pszOpt, ",", FALSE, FALSE);
nTargetValues = CSLCount(papszValuesTokens);
panTargetValues = static_cast<int *>(
CPLCalloc(sizeof(int), nTargetValues) );
for( int i = 0; i < nTargetValues; i++ )
panTargetValues[i] = atoi(papszValuesTokens[i]);
CSLDestroy( papszValuesTokens );
}
/* -------------------------------------------------------------------- */
/* Initialize progress counter. */
/* -------------------------------------------------------------------- */
if( !pfnProgress( 0.0, "", pProgressArg ) )
{
CPLError( CE_Failure, CPLE_UserInterrupt, "User terminated" );
CPLFree(panTargetValues);
return CE_Failure;
}
/* -------------------------------------------------------------------- */
/* We need a signed type for the working proximity values kept */
/* on disk. If our proximity band is not signed, then create a */
/* temporary file for this purpose. */
/* -------------------------------------------------------------------- */
GDALRasterBandH hWorkProximityBand = hProximityBand;
GDALDatasetH hWorkProximityDS = nullptr;
const GDALDataType eProxType = GDALGetRasterDataType(hProximityBand);
CPLErr eErr = CE_None;
// TODO(schwehr): Localize after removing gotos.
float *pafProximity = nullptr;
int *panNearX = nullptr;
int *panNearY = nullptr;
GInt32 *panSrcScanline = nullptr;
bool bTempFileAlreadyDeleted = false;
if( eProxType == GDT_Byte
|| eProxType == GDT_UInt16
|| eProxType == GDT_UInt32 )
{
GDALDriverH hDriver = GDALGetDriverByName("GTiff");
if( hDriver == nullptr )
{
CPLError( CE_Failure, CPLE_AppDefined,
"GDALComputeProximity needs GTiff driver" );
eErr = CE_Failure;
goto end;
}
CPLString osTmpFile = CPLGenerateTempFilename( "proximity" );
hWorkProximityDS =
GDALCreate( hDriver, osTmpFile,
nXSize, nYSize, 1, GDT_Float32, nullptr );
if( hWorkProximityDS == nullptr )
{
eErr = CE_Failure;
goto end;
}
// On Unix, attempt at deleting the temporary file now, so that
// if the process gets interrupted, it is automatically destroyed
// by the operating system.
bTempFileAlreadyDeleted = VSIUnlink( osTmpFile ) == 0;
hWorkProximityBand = GDALGetRasterBand( hWorkProximityDS, 1 );
}
/* -------------------------------------------------------------------- */
/* Allocate buffer for two scanlines of distances as floats */
/* (the current and last line). */
/* -------------------------------------------------------------------- */
pafProximity =
static_cast<float *>(VSI_MALLOC2_VERBOSE(sizeof(float), nXSize));
panNearX =
static_cast<int *>(VSI_MALLOC2_VERBOSE(sizeof(int), nXSize));
panNearY =
static_cast<int *>(VSI_MALLOC2_VERBOSE(sizeof(int), nXSize));
panSrcScanline =
static_cast<GInt32 *>(VSI_MALLOC2_VERBOSE(sizeof(GInt32), nXSize));
if( pafProximity == nullptr
|| panNearX == nullptr
|| panNearY == nullptr
|| panSrcScanline == nullptr)
{
eErr = CE_Failure;
goto end;
}
/* -------------------------------------------------------------------- */
/* Loop from top to bottom of the image. */
/* -------------------------------------------------------------------- */
for( int i = 0; i < nXSize; i++ )
{
panNearX[i] = -1;
panNearY[i] = -1;
}
for( int iLine = 0; eErr == CE_None && iLine < nYSize; iLine++ )
{
// Read for target values.
eErr = GDALRasterIO( hSrcBand, GF_Read, 0, iLine, nXSize, 1,
panSrcScanline, nXSize, 1, GDT_Int32, 0, 0 );
if( eErr != CE_None )
break;
for( int i = 0; i < nXSize; i++ )
pafProximity[i] = -1.0;
// Left to right.
ProcessProximityLine( panSrcScanline, panNearX, panNearY,
TRUE, iLine, nXSize, dfMaxDist, pafProximity,
pdfSrcNoData, nTargetValues, panTargetValues );
// Right to Left.
ProcessProximityLine( panSrcScanline, panNearX, panNearY,
FALSE, iLine, nXSize, dfMaxDist, pafProximity,
pdfSrcNoData, nTargetValues, panTargetValues );
// Write out results.
eErr =
GDALRasterIO( hWorkProximityBand, GF_Write, 0, iLine, nXSize, 1,
pafProximity, nXSize, 1, GDT_Float32, 0, 0 );
if( eErr != CE_None )
break;
if( !pfnProgress( 0.5 * (iLine+1) / static_cast<double>(nYSize),
"", pProgressArg ) )
{
CPLError( CE_Failure, CPLE_UserInterrupt, "User terminated" );
eErr = CE_Failure;
}
}
/* -------------------------------------------------------------------- */
/* Loop from bottom to top of the image. */
/* -------------------------------------------------------------------- */
for( int i = 0; i < nXSize; i++ )
{
panNearX[i] = -1;
panNearY[i] = -1;
}
for( int iLine = nYSize-1; eErr == CE_None && iLine >= 0; iLine-- )
{
// Read first pass proximity.
eErr =
GDALRasterIO( hWorkProximityBand, GF_Read, 0, iLine, nXSize, 1,
pafProximity, nXSize, 1, GDT_Float32, 0, 0 );
if( eErr != CE_None )
break;
// Read pixel values.
eErr = GDALRasterIO( hSrcBand, GF_Read, 0, iLine, nXSize, 1,
panSrcScanline, nXSize, 1, GDT_Int32, 0, 0 );
if( eErr != CE_None )
break;
// Right to left.
ProcessProximityLine( panSrcScanline, panNearX, panNearY,
FALSE, iLine, nXSize, dfMaxDist, pafProximity,
pdfSrcNoData, nTargetValues, panTargetValues );
// Left to right.
ProcessProximityLine( panSrcScanline, panNearX, panNearY,
TRUE, iLine, nXSize, dfMaxDist, pafProximity,
pdfSrcNoData, nTargetValues, panTargetValues );
// Final post processing of distances.
for( int i = 0; i < nXSize; i++ )
{
if( pafProximity[i] < 0.0 )
pafProximity[i] = fNoDataValue;
else if( pafProximity[i] > 0.0 )
{
if( bFixedBufVal )
pafProximity[i] = static_cast<float>( dfFixedBufVal );
else
pafProximity[i] =
static_cast<float>(pafProximity[i] * dfDistMult);
}
}
// Write out results.
eErr =
GDALRasterIO( hProximityBand, GF_Write, 0, iLine, nXSize, 1,
pafProximity, nXSize, 1, GDT_Float32, 0, 0 );
if( eErr != CE_None )
break;
if( !pfnProgress( 0.5 +
0.5 * (nYSize-iLine) / static_cast<double>( nYSize ),
"", pProgressArg ) )
{
CPLError( CE_Failure, CPLE_UserInterrupt, "User terminated" );
eErr = CE_Failure;
}
}
/* -------------------------------------------------------------------- */
/* Cleanup */
/* -------------------------------------------------------------------- */
end:
CPLFree( panNearX );
CPLFree( panNearY );
CPLFree( panSrcScanline );
CPLFree( pafProximity );
CPLFree( panTargetValues );
if( hWorkProximityDS != nullptr )
{
CPLString osProxFile = GDALGetDescription( hWorkProximityDS );
GDALClose( hWorkProximityDS );
if( !bTempFileAlreadyDeleted )
{
GDALDeleteDataset( GDALGetDriverByName( "GTiff" ), osProxFile );
}
}
return eErr;
}
/************************************************************************/
/* SquareDistance() */
/************************************************************************/
static double SquareDistance(double dfX1, double dfX2,
double dfY1, double dfY2)
{
const double dfDX = dfX1 - dfX2;
const double dfDY = dfY1 - dfY2;
return dfDX * dfDX + dfDY * dfDY;
}
/************************************************************************/
/* ProcessProximityLine() */
/************************************************************************/
static CPLErr
ProcessProximityLine( GInt32 *panSrcScanline, int *panNearX, int *panNearY,
int bForward, int iLine, int nXSize, double dfMaxDist,
float *pafProximity, double *pdfSrcNoDataValue,
int nTargetValues, int *panTargetValues )
{
const int iStart = bForward ? 0 : nXSize - 1;
const int iEnd = bForward ? nXSize : -1;
const int iStep = bForward ? 1 : -1;
for( int iPixel = iStart; iPixel != iEnd; iPixel += iStep )
{
bool bIsTarget = false;
/* -------------------------------------------------------------------- */
/* Is the current pixel a target pixel? */
/* -------------------------------------------------------------------- */
if( nTargetValues == 0 )
{
bIsTarget = panSrcScanline[iPixel] != 0;
}
else
{
for( int i = 0; i < nTargetValues; i++ )
{
if( panSrcScanline[iPixel] == panTargetValues[i] )
bIsTarget = TRUE;
}
}
if( bIsTarget )
{
pafProximity[iPixel] = 0.0;
panNearX[iPixel] = iPixel;
panNearY[iPixel] = iLine;
continue;
}
/* -------------------------------------------------------------------- */
/* Are we near(er) to the closest target to the above (below) */
/* pixel? */
/* -------------------------------------------------------------------- */
double dfNearDistSq =
std::max(dfMaxDist, static_cast<double>(nXSize)) *
std::max(dfMaxDist, static_cast<double>(nXSize)) * 2.0;
if( panNearX[iPixel] != -1 )
{
const double dfDistSq =
SquareDistance(panNearX[iPixel], iPixel,
panNearY[iPixel], iLine);
if( dfDistSq < dfNearDistSq )
{
dfNearDistSq = dfDistSq;
}
else
{
panNearX[iPixel] = -1;
panNearY[iPixel] = -1;
}
}
/* -------------------------------------------------------------------- */
/* Are we near(er) to the closest target to the left (right) */
/* pixel? */
/* -------------------------------------------------------------------- */
const int iLast = iPixel - iStep;
if( iPixel != iStart && panNearX[iLast] != -1 )
{
const double dfDistSq =
SquareDistance(panNearX[iLast], iPixel,
panNearY[iLast], iLine);
if( dfDistSq < dfNearDistSq )
{
dfNearDistSq = dfDistSq;
panNearX[iPixel] = panNearX[iLast];
panNearY[iPixel] = panNearY[iLast];
}
}
/* -------------------------------------------------------------------- */
/* Are we near(er) to the closest target to the topright */
/* (bottom left) pixel? */
/* -------------------------------------------------------------------- */
const int iTR = iPixel + iStep;
if( iTR != iEnd && panNearX[iTR] != -1 )
{
const double dfDistSq =
SquareDistance(panNearX[iTR], iPixel,
panNearY[iTR], iLine);
if( dfDistSq < dfNearDistSq )
{
dfNearDistSq = dfDistSq;
panNearX[iPixel] = panNearX[iTR];
panNearY[iPixel] = panNearY[iTR];
}
}
/* -------------------------------------------------------------------- */
/* Update our proximity value. */
/* -------------------------------------------------------------------- */
if( panNearX[iPixel] != -1
&& (pdfSrcNoDataValue == nullptr
|| panSrcScanline[iPixel] != *pdfSrcNoDataValue)
&& dfNearDistSq <= dfMaxDist * dfMaxDist
&& (pafProximity[iPixel] < 0
|| dfNearDistSq < pafProximity[iPixel] * pafProximity[iPixel]) )
pafProximity[iPixel] = static_cast<float>(sqrt(dfNearDistSq));
}
return CE_None;
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,306 @@
/******************************************************************************
*
* Project: GDAL
* Purpose: Raster Polygon Enumerator
* Author: Frank Warmerdam, warmerdam@pobox.com
*
******************************************************************************
* Copyright (c) 2008, Frank Warmerdam
* Copyright (c) 2015, Even Rouault <even.rouault at spatialys.com>
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included
* in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
****************************************************************************/
#include "cpl_port.h"
#include "gdal_alg_priv.h"
#include <cstddef>
#include "cpl_conv.h"
#include "cpl_error.h"
CPL_CVSID("$Id: gdalrasterpolygonenumerator.cpp fe2d81c8819bf9794bce0210098e637565728350 2018-05-06 00:49:51 +0200 Even Rouault $")
/*! @cond Doxygen_Suppress */
/************************************************************************/
/* GDALRasterPolygonEnumeratorT() */
/************************************************************************/
template<class DataType, class EqualityTest>
GDALRasterPolygonEnumeratorT<DataType,
EqualityTest>::GDALRasterPolygonEnumeratorT(
int nConnectednessIn ) :
nConnectedness( nConnectednessIn )
{
CPLAssert( nConnectedness == 4 || nConnectedness == 8 );
}
/************************************************************************/
/* ~GDALRasterPolygonEnumeratorT() */
/************************************************************************/
template<class DataType, class EqualityTest>
GDALRasterPolygonEnumeratorT<DataType,
EqualityTest>::~GDALRasterPolygonEnumeratorT()
{
Clear();
}
/************************************************************************/
/* Clear() */
/************************************************************************/
template<class DataType, class EqualityTest>
void GDALRasterPolygonEnumeratorT<DataType, EqualityTest>::Clear()
{
CPLFree( panPolyIdMap );
CPLFree( panPolyValue );
panPolyIdMap = nullptr;
panPolyValue = nullptr;
nNextPolygonId = 0;
nPolyAlloc = 0;
}
/************************************************************************/
/* MergePolygon() */
/* */
/* Update the polygon map to indicate the merger of two polygons. */
/************************************************************************/
template<class DataType, class EqualityTest>
void GDALRasterPolygonEnumeratorT<DataType,
EqualityTest>::MergePolygon( int nSrcId,
int nDstIdInit )
{
// Figure out the final dest id.
int nDstIdFinal = nDstIdInit;
while( panPolyIdMap[nDstIdFinal] != nDstIdFinal )
nDstIdFinal = panPolyIdMap[nDstIdFinal];
// Map the whole intermediate chain to it.
int nDstIdCur = nDstIdInit;
while( panPolyIdMap[nDstIdCur] != nDstIdCur )
{
int nNextDstId = panPolyIdMap[nDstIdCur];
panPolyIdMap[nDstIdCur] = nDstIdFinal;
nDstIdCur = nNextDstId;
}
// And map the whole source chain to it too (can be done in one pass).
while( panPolyIdMap[nSrcId] != nSrcId )
{
int nNextSrcId = panPolyIdMap[nSrcId];
panPolyIdMap[nSrcId] = nDstIdFinal;
nSrcId = nNextSrcId;
}
panPolyIdMap[nSrcId] = nDstIdFinal;
}
/************************************************************************/
/* NewPolygon() */
/* */
/* Allocate a new polygon id, and reallocate the polygon maps */
/* if needed. */
/************************************************************************/
template<class DataType, class EqualityTest>
int GDALRasterPolygonEnumeratorT<DataType, EqualityTest>::NewPolygon(
DataType nValue )
{
const int nPolyId = nNextPolygonId;
if( nNextPolygonId >= nPolyAlloc )
{
nPolyAlloc = nPolyAlloc * 2 + 20;
panPolyIdMap = static_cast<GInt32 *>(
CPLRealloc(panPolyIdMap, nPolyAlloc*sizeof(GInt32)));
panPolyValue = static_cast<DataType *>(
CPLRealloc(panPolyValue, nPolyAlloc*sizeof(DataType)));
}
nNextPolygonId++;
panPolyIdMap[nPolyId] = nPolyId;
panPolyValue[nPolyId] = nValue;
return nPolyId;
}
/************************************************************************/
/* CompleteMerges() */
/* */
/* Make a pass through the maps, ensuring every polygon id */
/* points to the final id it should use, not an intermediate */
/* value. */
/************************************************************************/
template<class DataType, class EqualityTest>
void GDALRasterPolygonEnumeratorT<DataType, EqualityTest>::CompleteMerges()
{
int nFinalPolyCount = 0;
for( int iPoly = 0; iPoly < nNextPolygonId; iPoly++ )
{
// Figure out the final id.
int nId = panPolyIdMap[iPoly];
while( nId != panPolyIdMap[nId] )
{
nId = panPolyIdMap[nId];
}
// Then map the whole intermediate chain to it.
int nIdCur = panPolyIdMap[iPoly];
panPolyIdMap[iPoly] = nId;
while( nIdCur != panPolyIdMap[nIdCur] )
{
int nNextId = panPolyIdMap[nIdCur];
panPolyIdMap[nIdCur] = nId;
nIdCur = nNextId;
}
if( panPolyIdMap[iPoly] == iPoly )
nFinalPolyCount++;
}
CPLDebug( "GDALRasterPolygonEnumerator",
"Counted %d polygon fragments forming %d final polygons.",
nNextPolygonId, nFinalPolyCount );
}
/************************************************************************/
/* ProcessLine() */
/* */
/* Assign ids to polygons, one line at a time. */
/************************************************************************/
template<class DataType, class EqualityTest>
void GDALRasterPolygonEnumeratorT<DataType, EqualityTest>::ProcessLine(
DataType *panLastLineVal, DataType *panThisLineVal,
GInt32 *panLastLineId, GInt32 *panThisLineId,
int nXSize )
{
EqualityTest eq;
/* -------------------------------------------------------------------- */
/* Special case for the first line. */
/* -------------------------------------------------------------------- */
if( panLastLineVal == nullptr )
{
for( int i = 0; i < nXSize; i++ )
{
if( panThisLineVal[i] == GP_NODATA_MARKER )
{
panThisLineId[i] = -1;
}
else if( i == 0 ||
!(eq.operator()(panThisLineVal[i], panThisLineVal[i-1])) )
{
panThisLineId[i] = NewPolygon( panThisLineVal[i] );
}
else
{
panThisLineId[i] = panThisLineId[i-1];
}
}
return;
}
/* -------------------------------------------------------------------- */
/* Process each pixel comparing to the previous pixel, and to */
/* the last line. */
/* -------------------------------------------------------------------- */
for( int i = 0; i < nXSize; i++ )
{
if( panThisLineVal[i] == GP_NODATA_MARKER )
{
panThisLineId[i] = -1;
}
else if( i > 0 &&
eq.operator()(panThisLineVal[i], panThisLineVal[i-1]) )
{
panThisLineId[i] = panThisLineId[i-1];
if( eq.operator()(panLastLineVal[i], panThisLineVal[i])
&& (panPolyIdMap[panLastLineId[i]]
!= panPolyIdMap[panThisLineId[i]]) )
{
MergePolygon( panLastLineId[i], panThisLineId[i] );
}
if( nConnectedness == 8
&& eq.operator()(panLastLineVal[i-1], panThisLineVal[i])
&& (panPolyIdMap[panLastLineId[i-1]]
!= panPolyIdMap[panThisLineId[i]]) )
{
MergePolygon( panLastLineId[i-1], panThisLineId[i] );
}
if( nConnectedness == 8 && i < nXSize-1
&& eq.operator()(panLastLineVal[i+1], panThisLineVal[i])
&& (panPolyIdMap[panLastLineId[i+1]]
!= panPolyIdMap[panThisLineId[i]]) )
{
MergePolygon( panLastLineId[i+1], panThisLineId[i] );
}
}
else if( eq.operator()(panLastLineVal[i], panThisLineVal[i]) )
{
panThisLineId[i] = panLastLineId[i];
}
else if( i > 0 && nConnectedness == 8
&& eq.operator()(panLastLineVal[i-1], panThisLineVal[i]) )
{
panThisLineId[i] = panLastLineId[i-1];
if( i < nXSize-1 &&
eq.operator()(panLastLineVal[i+1], panThisLineVal[i]) &&
(panPolyIdMap[panLastLineId[i+1]]
!= panPolyIdMap[panThisLineId[i]]) )
{
MergePolygon( panLastLineId[i+1], panThisLineId[i] );
}
}
else if( i < nXSize-1 && nConnectedness == 8
&& eq.operator()(panLastLineVal[i+1], panThisLineVal[i]) )
{
panThisLineId[i] = panLastLineId[i+1];
}
else
{
panThisLineId[i] = NewPolygon(panThisLineVal[i]);
}
}
}
template class GDALRasterPolygonEnumeratorT<GInt32, IntEqualityTest>;
template class GDALRasterPolygonEnumeratorT<float, FloatEqualityTest>;
/*! @endcond */

View File

@@ -0,0 +1,616 @@
/******************************************************************************
*
* Project: GDAL
* Purpose: Raster to Polygon Converter
* Author: Frank Warmerdam, warmerdam@pobox.com
*
******************************************************************************
* Copyright (c) 2008, Frank Warmerdam
* Copyright (c) 2009-2011, Even Rouault <even dot rouault at mines-paris dot org>
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included
* in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
****************************************************************************/
#include "cpl_port.h"
#include "gdal_alg.h"
#include <cstring>
#include <algorithm>
#include <set>
#include <vector>
#include <utility>
#include "cpl_conv.h"
#include "cpl_error.h"
#include "cpl_progress.h"
#include "cpl_vsi.h"
#include "gdal.h"
#include "gdal_alg_priv.h"
CPL_CVSID("$Id: gdalsievefilter.cpp 7e07230bbff24eb333608de4dbd460b7312839d0 2017-12-11 19:08:47Z Even Rouault $")
#define MY_MAX_INT 2147483647
/*
* General Plan
*
* 1) make a pass with the polygon enumerator to build up the
* polygon map array. Also accumulate polygon size information.
*
* 2) Identify the polygons that need to be merged.
*
* 3) Make a pass with the polygon enumerator. For each "to be merged"
* polygon keep track of its largest neighbour.
*
* 4) Fix up remappings that would go to polygons smaller than the seive
* size. Ensure these in term map to the largest neighbour of the
* "to be sieved" polygons.
*
* 5) Make another pass with the polygon enumerator. This time we remap
* the actual pixel values of all polygons to be merged.
*/
/************************************************************************/
/* GPMaskImageData() */
/* */
/* Mask out image pixels to a special nodata value if the mask */
/* band is zero. */
/************************************************************************/
static CPLErr
GPMaskImageData( GDALRasterBandH hMaskBand, GByte *pabyMaskLine,
int iY, int nXSize,
GInt32 *panImageLine )
{
const CPLErr eErr =
GDALRasterIO( hMaskBand, GF_Read, 0, iY, nXSize, 1,
pabyMaskLine, nXSize, 1, GDT_Byte, 0, 0 );
if( eErr == CE_None )
{
for( int i = 0; i < nXSize; i++ )
{
if( pabyMaskLine[i] == 0 )
panImageLine[i] = GP_NODATA_MARKER;
}
}
return eErr;
}
// TODO: What is "eaches" supposed to be?
/************************************************************************/
/* CompareNeighbour() */
/* */
/* Compare two neighbouring polygons, and update eaches */
/* "biggest neighbour" if the other is larger than its current */
/* largest neighbour. */
/* */
/* Note that this should end up with each polygon knowing the */
/* id of its largest neighbour. No attempt is made to */
/* restrict things to small polygons that we will be merging, */
/* nor to exclude assigning "biggest neighbours" that are still */
/* smaller than our sieve threshold. */
/************************************************************************/
static inline void CompareNeighbour( int nPolyId1, int nPolyId2,
int *panPolyIdMap,
int * /* panPolyValue */,
std::vector<int> &anPolySizes,
std::vector<int> &anBigNeighbour )
{
// Nodata polygon do not need neighbours, and cannot be neighbours
// to valid polygons.
if( nPolyId1 < 0 || nPolyId2 < 0 )
return;
// Make sure we are working with the final merged polygon ids.
nPolyId1 = panPolyIdMap[nPolyId1];
nPolyId2 = panPolyIdMap[nPolyId2];
if( nPolyId1 == nPolyId2 )
return;
// Nodata polygon do not need neighbours, and cannot be neighbours
// to valid polygons.
// Should no longer happen with r28826 optimization.
// if( panPolyValue[nPolyId1] == GP_NODATA_MARKER
// || panPolyValue[nPolyId2] == GP_NODATA_MARKER )
// return;
if( anBigNeighbour[nPolyId1] == -1
|| anPolySizes[anBigNeighbour[nPolyId1]] < anPolySizes[nPolyId2] )
anBigNeighbour[nPolyId1] = nPolyId2;
if( anBigNeighbour[nPolyId2] == -1
|| anPolySizes[anBigNeighbour[nPolyId2]] < anPolySizes[nPolyId1] )
anBigNeighbour[nPolyId2] = nPolyId1;
}
/************************************************************************/
/* GDALSieveFilter() */
/************************************************************************/
/**
* Removes small raster polygons.
*
* The function removes raster polygons smaller than a provided
* threshold size (in pixels) and replaces replaces them with the pixel value
* of the largest neighbour polygon.
*
* Polygon are determined (per GDALRasterPolygonEnumerator) as regions of
* the raster where the pixels all have the same value, and that are contiguous
* (connected).
*
* Pixels determined to be "nodata" per hMaskBand will not be treated as part
* of a polygon regardless of their pixel values. Nodata areas will never be
* changed nor affect polygon sizes.
*
* Polygons smaller than the threshold with no neighbours that are as large
* as the threshold will not be altered. Polygons surrounded by nodata areas
* will therefore not be altered.
*
* The algorithm makes three passes over the input file to enumerate the
* polygons and collect limited information about them. Memory use is
* proportional to the number of polygons (roughly 24 bytes per polygon), but
* is not directly related to the size of the raster. So very large raster
* files can be processed effectively if there aren't too many polygons. But
* extremely noisy rasters with many one pixel polygons will end up being
* expensive (in memory) to process.
*
* @param hSrcBand the source raster band to be processed.
* @param hMaskBand an optional mask band. All pixels in the mask band with a
* value other than zero will be considered suitable for inclusion in polygons.
* @param hDstBand the output raster band. It may be the same as hSrcBand
* to update the source in place.
* @param nSizeThreshold raster polygons with sizes smaller than this will
* be merged into their largest neighbour.
* @param nConnectedness either 4 indicating that diagonal pixels are not
* considered directly adjacent for polygon membership purposes or 8
* indicating they are.
* @param papszOptions algorithm options in name=value list form. None
* currently supported.
* @param pfnProgress callback for reporting algorithm progress matching the
* GDALProgressFunc() semantics. May be NULL.
* @param pProgressArg callback argument passed to pfnProgress.
*
* @return CE_None on success or CE_Failure if an error occurs.
*/
CPLErr CPL_STDCALL
GDALSieveFilter( GDALRasterBandH hSrcBand, GDALRasterBandH hMaskBand,
GDALRasterBandH hDstBand,
int nSizeThreshold, int nConnectedness,
CPL_UNUSED char **papszOptions,
GDALProgressFunc pfnProgress,
void * pProgressArg )
{
VALIDATE_POINTER1( hSrcBand, "GDALSieveFilter", CE_Failure );
VALIDATE_POINTER1( hDstBand, "GDALSieveFilter", CE_Failure );
if( pfnProgress == nullptr )
pfnProgress = GDALDummyProgress;
/* -------------------------------------------------------------------- */
/* Allocate working buffers. */
/* -------------------------------------------------------------------- */
int nXSize = GDALGetRasterBandXSize( hSrcBand );
int nYSize = GDALGetRasterBandYSize( hSrcBand );
GInt32 *panLastLineVal = static_cast<GInt32 *>(
VSI_MALLOC2_VERBOSE(sizeof(GInt32), nXSize));
GInt32 *panThisLineVal = static_cast<GInt32 *>(
VSI_MALLOC2_VERBOSE(sizeof(GInt32), nXSize));
GInt32 *panLastLineId = static_cast<GInt32 *>(
VSI_MALLOC2_VERBOSE(sizeof(GInt32), nXSize));
GInt32 *panThisLineId = static_cast<GInt32 *>(
VSI_MALLOC2_VERBOSE(sizeof(GInt32), nXSize));
GInt32 *panThisLineWriteVal = static_cast<GInt32 *>(
VSI_MALLOC2_VERBOSE(sizeof(GInt32), nXSize));
GByte *pabyMaskLine =
hMaskBand != nullptr
? static_cast<GByte *>(VSI_MALLOC_VERBOSE(nXSize))
: nullptr;
if( panLastLineVal == nullptr || panThisLineVal == nullptr ||
panLastLineId == nullptr || panThisLineId == nullptr ||
panThisLineWriteVal == nullptr ||
(hMaskBand != nullptr && pabyMaskLine == nullptr) )
{
CPLFree( panThisLineId );
CPLFree( panLastLineId );
CPLFree( panThisLineVal );
CPLFree( panLastLineVal );
CPLFree( panThisLineWriteVal );
CPLFree( pabyMaskLine );
return CE_Failure;
}
/* -------------------------------------------------------------------- */
/* The first pass over the raster is only used to build up the */
/* polygon id map so we will know in advance what polygons are */
/* what on the second pass. */
/* -------------------------------------------------------------------- */
GDALRasterPolygonEnumerator oFirstEnum( nConnectedness );
std::vector<int> anPolySizes;
CPLErr eErr = CE_None;
for( int iY = 0; eErr == CE_None && iY < nYSize; iY++ )
{
eErr = GDALRasterIO(
hSrcBand,
GF_Read, 0, iY, nXSize, 1,
panThisLineVal, nXSize, 1, GDT_Int32, 0, 0 );
if( eErr == CE_None && hMaskBand != nullptr )
eErr = GPMaskImageData(hMaskBand, pabyMaskLine, iY, nXSize,
panThisLineVal);
if( iY == 0 )
oFirstEnum.ProcessLine(
nullptr, panThisLineVal, nullptr, panThisLineId, nXSize );
else
oFirstEnum.ProcessLine(
panLastLineVal, panThisLineVal,
panLastLineId, panThisLineId,
nXSize );
/* -------------------------------------------------------------------- */
/* Accumulate polygon sizes. */
/* -------------------------------------------------------------------- */
if( oFirstEnum.nNextPolygonId > static_cast<int>(anPolySizes.size()) )
anPolySizes.resize( oFirstEnum.nNextPolygonId );
for( int iX = 0; iX < nXSize; iX++ )
{
const int iPoly = panThisLineId[iX];
if( iPoly >= 0 && anPolySizes[iPoly] < MY_MAX_INT )
anPolySizes[iPoly] += 1;
}
/* -------------------------------------------------------------------- */
/* swap this/last lines. */
/* -------------------------------------------------------------------- */
std::swap(panLastLineVal, panThisLineVal);
std::swap(panLastLineId, panThisLineId);
/* -------------------------------------------------------------------- */
/* Report progress, and support interrupts. */
/* -------------------------------------------------------------------- */
if( eErr == CE_None
&& !pfnProgress( 0.25 * ((iY+1) / static_cast<double>(nYSize)),
"", pProgressArg ) )
{
CPLError( CE_Failure, CPLE_UserInterrupt, "User terminated" );
eErr = CE_Failure;
}
}
/* -------------------------------------------------------------------- */
/* Make a pass through the maps, ensuring every polygon id */
/* points to the final id it should use, not an intermediate */
/* value. */
/* -------------------------------------------------------------------- */
oFirstEnum.CompleteMerges();
/* -------------------------------------------------------------------- */
/* Push the sizes of merged polygon fragments into the */
/* merged polygon id's count. */
/* -------------------------------------------------------------------- */
for( int iPoly = 0; oFirstEnum.panPolyIdMap != nullptr && // for Coverity
iPoly < oFirstEnum.nNextPolygonId; iPoly++ )
{
if( oFirstEnum.panPolyIdMap[iPoly] != iPoly )
{
GIntBig nSize = anPolySizes[oFirstEnum.panPolyIdMap[iPoly]];
nSize += anPolySizes[iPoly];
if( nSize > MY_MAX_INT )
nSize = MY_MAX_INT;
anPolySizes[oFirstEnum.panPolyIdMap[iPoly]] =
static_cast<int>(nSize);
anPolySizes[iPoly] = 0;
}
}
/* -------------------------------------------------------------------- */
/* We will use a new enumerator for the second pass primarily */
/* so we can preserve the first pass map. */
/* -------------------------------------------------------------------- */
GDALRasterPolygonEnumerator oSecondEnum( nConnectedness );
std::vector<int> anBigNeighbour;
anBigNeighbour.resize( anPolySizes.size() );
for( int iPoly = 0; iPoly < static_cast<int>(anPolySizes.size()); iPoly++ )
anBigNeighbour[iPoly] = -1;
/* ==================================================================== */
/* Second pass ... identify the largest neighbour for each */
/* polygon. */
/* ==================================================================== */
for( int iY = 0; eErr == CE_None && iY < nYSize; iY++ )
{
/* -------------------------------------------------------------------- */
/* Read the image data. */
/* -------------------------------------------------------------------- */
eErr = GDALRasterIO( hSrcBand, GF_Read, 0, iY, nXSize, 1,
panThisLineVal, nXSize, 1, GDT_Int32, 0, 0 );
if( eErr == CE_None && hMaskBand != nullptr )
eErr = GPMaskImageData( hMaskBand, pabyMaskLine, iY, nXSize,
panThisLineVal );
if( eErr != CE_None )
continue;
/* -------------------------------------------------------------------- */
/* Determine what polygon the various pixels belong to (redoing */
/* the same thing done in the first pass above). */
/* -------------------------------------------------------------------- */
if( iY == 0 )
oSecondEnum.ProcessLine(
nullptr, panThisLineVal, nullptr, panThisLineId, nXSize );
else
oSecondEnum.ProcessLine(
panLastLineVal, panThisLineVal,
panLastLineId, panThisLineId,
nXSize );
/* -------------------------------------------------------------------- */
/* Check our neighbours, and update our biggest neighbour map */
/* as appropriate. */
/* -------------------------------------------------------------------- */
for( int iX = 0; iX < nXSize; iX++ )
{
if( iY > 0 )
{
CompareNeighbour( panThisLineId[iX],
panLastLineId[iX],
oFirstEnum.panPolyIdMap,
oFirstEnum.panPolyValue,
anPolySizes, anBigNeighbour );
if( iX > 0 && nConnectedness == 8 )
CompareNeighbour( panThisLineId[iX],
panLastLineId[iX-1],
oFirstEnum.panPolyIdMap,
oFirstEnum.panPolyValue,
anPolySizes, anBigNeighbour );
if( iX < nXSize-1 && nConnectedness == 8 )
CompareNeighbour( panThisLineId[iX],
panLastLineId[iX+1],
oFirstEnum.panPolyIdMap,
oFirstEnum.panPolyValue,
anPolySizes, anBigNeighbour );
}
if( iX > 0 )
CompareNeighbour( panThisLineId[iX],
panThisLineId[iX-1],
oFirstEnum.panPolyIdMap,
oFirstEnum.panPolyValue,
anPolySizes, anBigNeighbour );
// We don't need to compare to next pixel or next line
// since they will be compared to us.
}
/* -------------------------------------------------------------------- */
/* Swap pixel value, and polygon id lines to be ready for the */
/* next line. */
/* -------------------------------------------------------------------- */
std::swap(panLastLineVal, panThisLineVal);
std::swap(panLastLineId, panThisLineId);
/* -------------------------------------------------------------------- */
/* Report progress, and support interrupts. */
/* -------------------------------------------------------------------- */
if( eErr == CE_None &&
!pfnProgress(0.25 + 0.25 * ((iY + 1) / static_cast<double>(nYSize)),
"", pProgressArg) )
{
CPLError( CE_Failure, CPLE_UserInterrupt, "User terminated" );
eErr = CE_Failure;
}
}
/* -------------------------------------------------------------------- */
/* If our biggest neighbour is still smaller than the */
/* threshold, then try tracking to that polygons biggest */
/* neighbour, and so forth. */
/* -------------------------------------------------------------------- */
int nFailedMerges = 0;
int nIsolatedSmall = 0;
int nSieveTargets = 0;
for( int iPoly = 0; oFirstEnum.panPolyIdMap != nullptr && // for Coverity
oFirstEnum.panPolyValue != nullptr && // for Coverity
iPoly < static_cast<int>(anPolySizes.size()); iPoly++ )
{
if( oFirstEnum.panPolyIdMap[iPoly] != iPoly )
continue;
// Ignore nodata polygons.
if( oFirstEnum.panPolyValue[iPoly] == GP_NODATA_MARKER )
continue;
// Don't try to merge polygons larger than the threshold.
if( anPolySizes[iPoly] >= nSizeThreshold )
{
anBigNeighbour[iPoly] = -1;
continue;
}
nSieveTargets++;
// if we have no neighbours but we are small, what shall we do?
if( anBigNeighbour[iPoly] == -1 )
{
nIsolatedSmall++;
continue;
}
std::set<int> oSetVisitedPoly;
oSetVisitedPoly.insert(iPoly);
// Walk through our neighbours until we find a polygon large enough.
int iFinalId = iPoly;
bool bFoundBigEnoughPoly = false;
while( true )
{
iFinalId = anBigNeighbour[iFinalId];
if( iFinalId < 0 )
{
break;
}
// If the biggest neighbour is larger than the threshold
// then we are golden.
if( anPolySizes[iFinalId] >= nSizeThreshold )
{
bFoundBigEnoughPoly = true;
break;
}
// Check that we don't cycle on an already visited polygon.
if( oSetVisitedPoly.find(iFinalId) != oSetVisitedPoly.end() )
break;
oSetVisitedPoly.insert(iFinalId);
}
if( !bFoundBigEnoughPoly )
{
nFailedMerges++;
anBigNeighbour[iPoly] = -1;
continue;
}
// Map the whole intermediate chain to it.
int iPolyCur = iPoly;
while( anBigNeighbour[iPolyCur] != iFinalId )
{
int iNextPoly = anBigNeighbour[iPolyCur];
anBigNeighbour[iPolyCur] = iFinalId;
iPolyCur = iNextPoly;
}
}
CPLDebug( "GDALSieveFilter",
"Small Polygons: %d, Isolated: %d, Unmergable: %d",
nSieveTargets, nIsolatedSmall, nFailedMerges );
/* ==================================================================== */
/* Make a third pass over the image, actually applying the */
/* merges. We reuse the second enumerator but preserve the */
/* "final maps" from the first. */
/* ==================================================================== */
oSecondEnum.Clear();
for( int iY = 0; oFirstEnum.panPolyIdMap != nullptr && // for Coverity
eErr == CE_None && iY < nYSize; iY++ )
{
/* -------------------------------------------------------------------- */
/* Read the image data. */
/* -------------------------------------------------------------------- */
eErr = GDALRasterIO( hSrcBand, GF_Read, 0, iY, nXSize, 1,
panThisLineVal, nXSize, 1, GDT_Int32, 0, 0 );
memcpy( panThisLineWriteVal, panThisLineVal, 4 * nXSize );
if( eErr == CE_None && hMaskBand != nullptr )
eErr = GPMaskImageData( hMaskBand, pabyMaskLine, iY, nXSize,
panThisLineVal );
if( eErr != CE_None )
continue;
/* -------------------------------------------------------------------- */
/* Determine what polygon the various pixels belong to (redoing */
/* the same thing done in the first pass above). */
/* -------------------------------------------------------------------- */
if( iY == 0 )
oSecondEnum.ProcessLine(
nullptr, panThisLineVal, nullptr, panThisLineId, nXSize );
else
oSecondEnum.ProcessLine(
panLastLineVal, panThisLineVal,
panLastLineId, panThisLineId,
nXSize );
/* -------------------------------------------------------------------- */
/* Reprocess the actual pixel values according to the polygon */
/* merging, and write out this line of image data. */
/* -------------------------------------------------------------------- */
for( int iX = 0; iX < nXSize; iX++ )
{
int iThisPoly = panThisLineId[iX];
if( iThisPoly >= 0 )
{
iThisPoly = oFirstEnum.panPolyIdMap[iThisPoly];
if( anBigNeighbour[iThisPoly] != -1 )
{
panThisLineWriteVal[iX] =
oFirstEnum.panPolyValue[
anBigNeighbour[iThisPoly]];
}
}
}
/* -------------------------------------------------------------------- */
/* Write the update data out. */
/* -------------------------------------------------------------------- */
eErr = GDALRasterIO( hDstBand, GF_Write, 0, iY, nXSize, 1,
panThisLineWriteVal, nXSize, 1, GDT_Int32, 0, 0 );
/* -------------------------------------------------------------------- */
/* Swap pixel value, and polygon id lines to be ready for the */
/* next line. */
/* -------------------------------------------------------------------- */
std::swap(panLastLineVal, panThisLineVal);
std::swap(panLastLineId, panThisLineId);
/* -------------------------------------------------------------------- */
/* Report progress, and support interrupts. */
/* -------------------------------------------------------------------- */
if( eErr == CE_None
&& !pfnProgress(0.5 + 0.5 * ((iY+1) / static_cast<double>(nYSize)),
"", pProgressArg) )
{
CPLError( CE_Failure, CPLE_UserInterrupt, "User terminated" );
eErr = CE_Failure;
}
}
/* -------------------------------------------------------------------- */
/* Cleanup */
/* -------------------------------------------------------------------- */
CPLFree( panThisLineId );
CPLFree( panLastLineId );
CPLFree( panThisLineVal );
CPLFree( panLastLineVal );
CPLFree( panThisLineWriteVal );
CPLFree( pabyMaskLine );
return eErr;
}

View File

@@ -0,0 +1,489 @@
/******************************************************************************
*
* Project: Mapinfo Image Warper
* Purpose: Simple (source in memory) warp algorithm.
* Author: Frank Warmerdam, warmerdam@pobox.com
*
******************************************************************************
* Copyright (c) 2002, i3 - information integration and imaging, Fort Collin, CO
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included
* in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
****************************************************************************/
#include "cpl_port.h"
#include "gdal_alg.h"
#include <cstdlib>
#include <cstring>
#include <algorithm>
#include "cpl_conv.h"
#include "cpl_error.h"
#include "cpl_progress.h"
#include "cpl_string.h"
#include "cpl_vsi.h"
#include "gdal.h"
#include "gdal_priv.h"
CPL_CVSID("$Id: gdalsimplewarp.cpp 9ef400e8849f3477878b34c0851382dc05969f12 2018-01-14 15:42:42Z Kurt Schwehr $")
/************************************************************************/
/* GDALSimpleWarpRemapping() */
/* */
/* This function implements any raster remapping requested in */
/* the options list. The remappings are applied to the source */
/* data before warping. Two kinds are support ... REMAP */
/* commands which remap selected pixel values for any band and */
/* REMAP_MULTI which only remap pixels matching the input in */
/* all bands at once (i.e. to remap an RGB value to another). */
/************************************************************************/
static void
GDALSimpleWarpRemapping( int nBandCount, GByte **papabySrcData,
int nSrcXSize, int nSrcYSize,
char **papszWarpOptions )
{
/* ==================================================================== */
/* Process any and all single value REMAP commands. */
/* ==================================================================== */
char **papszRemaps = CSLFetchNameValueMultiple( papszWarpOptions,
"REMAP" );
const int nRemaps = CSLCount(papszRemaps);
for( int iRemap = 0; iRemap < nRemaps; iRemap++ )
{
/* -------------------------------------------------------------------- */
/* What are the pixel values to map from and to? */
/* -------------------------------------------------------------------- */
char **papszTokens = CSLTokenizeString( papszRemaps[iRemap] );
if( CSLCount(papszTokens) != 2 )
{
CPLError(CE_Warning, CPLE_AppDefined,
"Ill formed REMAP `%s' ignored in "
"GDALSimpleWarpRemapping()",
papszRemaps[iRemap] );
CSLDestroy( papszTokens );
continue;
}
const int nFromValue = atoi(papszTokens[0]);
const int nToValue = atoi(papszTokens[1]);
// TODO(schwehr): Why is it ok to narrow ints to byte without checking?
const GByte byToValue = static_cast<GByte>(nToValue);
CSLDestroy( papszTokens );
/* -------------------------------------------------------------------- */
/* Pass over each band searching for matches. */
/* -------------------------------------------------------------------- */
for( int iBand = 0; iBand < nBandCount; iBand++ )
{
GByte *pabyData = papabySrcData[iBand];
int nPixelCount = nSrcXSize * nSrcYSize;
while( nPixelCount != 0 )
{
if( *pabyData == nFromValue )
*pabyData = byToValue;
pabyData++;
nPixelCount--;
}
}
}
CSLDestroy( papszRemaps );
/* ==================================================================== */
/* Process any and all REMAP_MULTI commands. */
/* ==================================================================== */
papszRemaps = CSLFetchNameValueMultiple( papszWarpOptions,
"REMAP_MULTI" );
const int nRemapsMulti = CSLCount(papszRemaps);
for( int iRemap = 0; iRemap < nRemapsMulti; iRemap++ )
{
/* -------------------------------------------------------------------- */
/* What are the pixel values to map from and to? */
/* -------------------------------------------------------------------- */
char **papszTokens = CSLTokenizeString( papszRemaps[iRemap] );
const int nTokens = CSLCount(papszTokens);
if( nTokens % 2 == 1 ||
nTokens == 0 ||
nTokens > nBandCount * 2 )
{
CPLError(CE_Warning, CPLE_AppDefined,
"Ill formed REMAP_MULTI `%s' ignored in "
"GDALSimpleWarpRemapping()",
papszRemaps[iRemap]);
CSLDestroy( papszTokens );
continue;
}
const int nMapBandCount = nTokens / 2;
int *panFromValue = static_cast<int *>(
CPLMalloc(sizeof(int) * nMapBandCount ) );
int *panToValue = static_cast<int *>(
CPLMalloc(sizeof(int) * nMapBandCount ) );
for( int iBand = 0; iBand < nMapBandCount; iBand++ )
{
panFromValue[iBand] = atoi(papszTokens[iBand]);
panToValue[iBand] = atoi(papszTokens[iBand+nMapBandCount]);
}
CSLDestroy( papszTokens );
/* -------------------------------------------------------------------- */
/* Search for matching values to replace. */
/* -------------------------------------------------------------------- */
const int nPixelCount = nSrcXSize * nSrcYSize;
for( int iPixel = 0; iPixel < nPixelCount; iPixel++ )
{
bool bMatch = true;
// Always check band 0.
for( int iBand = 0; bMatch && iBand < std::max(1, nMapBandCount);
iBand++ )
{
if( papabySrcData[iBand][iPixel] != panFromValue[iBand] )
bMatch = false;
}
if( !bMatch )
continue;
for( int iBand = 0; iBand < nMapBandCount; iBand++ )
papabySrcData[iBand][iPixel] =
static_cast<GByte>( panToValue[iBand] );
}
CPLFree( panFromValue );
CPLFree( panToValue );
}
CSLDestroy( papszRemaps );
}
/************************************************************************/
/* GDALSimpleImageWarp() */
/************************************************************************/
/**
* Perform simple image warp.
*
* Copies an image from a source dataset to a destination dataset applying
* an application defined transformation. This algorithm is called simple
* because it lacks many options such as resampling kernels (other than
* nearest neighbour), support for data types other than 8bit, and the
* ability to warp images without holding the entire source and destination
* image in memory.
*
* The following option(s) may be passed in papszWarpOptions.
* <ul>
* <li> "INIT=v[,v...]": This option indicates that the output dataset should
* be initialized to the indicated value in any area valid data is not written.
* Distinct values may be listed for each band separated by columns.
* </ul>
*
* @param hSrcDS the source image dataset.
* @param hDstDS the destination image dataset.
* @param nBandCount the number of bands to be warped. If zero, all bands
* will be processed.
* @param panBandList the list of bands to translate.
* @param pfnTransform the transformation function to call. See
* GDALTransformerFunc().
* @param pTransformArg the callback handle to pass to pfnTransform.
* @param pfnProgress the function used to report progress. See
* GDALProgressFunc().
* @param pProgressArg the callback handle to pass to pfnProgress.
* @param papszWarpOptions additional options controlling the warp.
*
* @return TRUE if the operation completes, or FALSE if an error occurs.
*/
int CPL_STDCALL
GDALSimpleImageWarp( GDALDatasetH hSrcDS, GDALDatasetH hDstDS,
int nBandCount, int *panBandList,
GDALTransformerFunc pfnTransform, void *pTransformArg,
GDALProgressFunc pfnProgress, void *pProgressArg,
char **papszWarpOptions )
{
VALIDATE_POINTER1( hSrcDS, "GDALSimpleImageWarp", 0 );
VALIDATE_POINTER1( hDstDS, "GDALSimpleImageWarp", 0 );
bool bError = false;
/* -------------------------------------------------------------------- */
/* If no bands provided assume we should process all bands. */
/* -------------------------------------------------------------------- */
if( nBandCount == 0 )
{
nBandCount = GDALGetRasterCount( hSrcDS );
if( nBandCount == 0 )
{
CPLError(CE_Failure, CPLE_AppDefined,
"No raster band in source dataset");
return FALSE;
}
panBandList = static_cast<int *>(CPLCalloc(sizeof(int), nBandCount));
for( int iBand = 0; iBand < nBandCount; iBand++ )
panBandList[iBand] = iBand + 1;
const int nResult =
GDALSimpleImageWarp( hSrcDS, hDstDS, nBandCount, panBandList,
pfnTransform, pTransformArg,
pfnProgress, pProgressArg,
papszWarpOptions );
CPLFree( panBandList );
return nResult;
}
/* -------------------------------------------------------------------- */
/* Post initial progress. */
/* -------------------------------------------------------------------- */
if( pfnProgress )
{
if( !pfnProgress( 0.0, "", pProgressArg ) )
return FALSE;
}
/* -------------------------------------------------------------------- */
/* Load the source image band(s). */
/* -------------------------------------------------------------------- */
const int nSrcXSize = GDALGetRasterXSize(hSrcDS);
const int nSrcYSize = GDALGetRasterYSize(hSrcDS);
GByte **papabySrcData = static_cast<GByte **>(
CPLCalloc(nBandCount, sizeof(GByte*)) );
bool ok = true;
for( int iBand = 0; iBand < nBandCount; iBand++ )
{
papabySrcData[iBand] = static_cast<GByte *>(
VSI_MALLOC2_VERBOSE(nSrcXSize, nSrcYSize) );
if( papabySrcData[iBand] == nullptr )
{
CPLError( CE_Failure, CPLE_OutOfMemory,
"GDALSimpleImageWarp out of memory." );
ok = false;
break;
}
if( GDALRasterIO(
GDALGetRasterBand(hSrcDS,panBandList[iBand]), GF_Read,
0, 0, nSrcXSize, nSrcYSize,
papabySrcData[iBand], nSrcXSize, nSrcYSize, GDT_Byte,
0, 0 ) != CE_None )
{
CPLError( CE_Failure, CPLE_FileIO,
"GDALSimpleImageWarp GDALRasterIO failure %s",
CPLGetLastErrorMsg() );
ok = false;
break;
}
}
if( !ok )
{
for( int i=0; i <= nBandCount; i++ )
{
VSIFree(papabySrcData[i]);
}
CPLFree(papabySrcData);
return FALSE;
}
/* -------------------------------------------------------------------- */
/* Check for remap request(s). */
/* -------------------------------------------------------------------- */
GDALSimpleWarpRemapping( nBandCount, papabySrcData, nSrcXSize, nSrcYSize,
papszWarpOptions );
/* -------------------------------------------------------------------- */
/* Allocate scanline buffers for output image. */
/* -------------------------------------------------------------------- */
const int nDstXSize = GDALGetRasterXSize( hDstDS );
const int nDstYSize = GDALGetRasterYSize( hDstDS );
GByte **papabyDstLine = static_cast<GByte **>(
CPLCalloc(nBandCount, sizeof(GByte*)) );
for( int iBand = 0; iBand < nBandCount; iBand++ )
papabyDstLine[iBand] = static_cast<GByte *>(CPLMalloc( nDstXSize ));
/* -------------------------------------------------------------------- */
/* Allocate x,y,z coordinate arrays for transformation ... one */
/* scanlines worth of positions. */
/* -------------------------------------------------------------------- */
double *padfX = static_cast<double *>(
CPLMalloc(sizeof(double) * nDstXSize) );
double *padfY = static_cast<double *>(
CPLMalloc(sizeof(double) * nDstXSize) );
double *padfZ = static_cast<double *>(
CPLMalloc(sizeof(double) * nDstXSize) );
int *pabSuccess = static_cast<int *>( CPLMalloc(sizeof(int) * nDstXSize) );
/* -------------------------------------------------------------------- */
/* Establish the value we will use to initialize the bands. We */
/* default to -1 indicating the initial value should be read */
/* and preserved from the source file, but allow this to be */
/* overridden by passed */
/* option(s). */
/* -------------------------------------------------------------------- */
int * const panBandInit =
static_cast<int *>( CPLCalloc(sizeof(int), nBandCount) );
if( CSLFetchNameValue( papszWarpOptions, "INIT" ) )
{
char **papszTokens =
CSLTokenizeStringComplex( CSLFetchNameValue( papszWarpOptions,
"INIT" ),
" ,", FALSE, FALSE );
const int nTokenCount = CSLCount(papszTokens);
for( int iBand = 0; iBand < nBandCount; iBand++ )
{
if( nTokenCount == 0 )
panBandInit[iBand] = 0;
else
panBandInit[iBand] =
atoi(papszTokens[std::min(iBand, nTokenCount- 1)]);
}
CSLDestroy(papszTokens);
}
/* -------------------------------------------------------------------- */
/* Loop over all the scanlines in the output image. */
/* -------------------------------------------------------------------- */
for( int iDstY = 0; iDstY < nDstYSize; iDstY++ )
{
// Clear output buffer to "transparent" value. Should not we
// really be reading from the destination file to support overlay?
for( int iBand = 0; iBand < nBandCount; iBand++ )
{
if( panBandInit[iBand] == -1 )
{
if( GDALRasterIO(
GDALGetRasterBand(hDstDS,iBand + 1), GF_Read,
0, iDstY, nDstXSize, 1,
papabyDstLine[iBand], nDstXSize, 1, GDT_Byte,
0, 0 ) != CE_None )
{
bError = TRUE;
break;
}
}
else
{
memset( papabyDstLine[iBand], panBandInit[iBand], nDstXSize );
}
}
// Set point to transform.
for( int iDstX = 0; iDstX < nDstXSize; iDstX++ )
{
padfX[iDstX] = iDstX + 0.5;
padfY[iDstX] = iDstY + 0.5;
padfZ[iDstX] = 0.0;
}
// Transform the points from destination pixel/line coordinates
// to source pixel/line coordinates.
pfnTransform( pTransformArg, TRUE, nDstXSize,
padfX, padfY, padfZ, pabSuccess );
// Loop over the output scanline.
for( int iDstX = 0; iDstX < nDstXSize; iDstX++ )
{
if( !pabSuccess[iDstX] )
continue;
// We test against the value before casting to avoid the
// problem of asymmetric truncation effects around zero. That is
// -0.5 will be 0 when cast to an int.
if( padfX[iDstX] < 0.0 || padfY[iDstX] < 0.0 )
continue;
const int iSrcX = static_cast<int>( padfX[iDstX] );
const int iSrcY = static_cast<int>( padfY[iDstX] );
if( iSrcX >= nSrcXSize || iSrcY >= nSrcYSize )
continue;
const int iSrcOffset = iSrcX + iSrcY * nSrcXSize;
for( int iBand = 0; iBand < nBandCount; iBand++ )
papabyDstLine[iBand][iDstX] = papabySrcData[iBand][iSrcOffset];
}
// Write scanline to disk.
for( int iBand = 0; iBand < nBandCount; iBand++ )
{
if( GDALRasterIO(
GDALGetRasterBand(hDstDS,iBand+1), GF_Write,
0, iDstY, nDstXSize, 1,
papabyDstLine[iBand], nDstXSize,
1, GDT_Byte, 0, 0 ) != CE_None )
{
bError = TRUE;
break;
}
}
if( pfnProgress != nullptr )
{
if( !pfnProgress( (iDstY + 1) / static_cast<double>(nDstYSize),
"", pProgressArg ) )
{
CPLError( CE_Failure, CPLE_UserInterrupt, "User terminated" );
bError = TRUE;
break;
}
}
}
/* -------------------------------------------------------------------- */
/* Cleanup working buffers. */
/* -------------------------------------------------------------------- */
for( int iBand = 0; iBand < nBandCount; iBand++ )
{
CPLFree( papabyDstLine[iBand] );
CPLFree( papabySrcData[iBand] );
}
CPLFree( panBandInit );
CPLFree( papabyDstLine );
CPLFree( papabySrcData );
CPLFree( padfX );
CPLFree( padfY );
CPLFree( padfZ );
CPLFree( pabSuccess );
return !bError;
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,161 @@
/******************************************************************************
*
* Project: GDAL
* Purpose: Algorithm to apply a transformer to geolocation style bands.
* Author: Frank Warmerdam, warmerdam@pobox.com
*
******************************************************************************
* Copyright (c) 2012, Frank Warmerdam
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included
* in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
****************************************************************************/
#include "cpl_port.h"
#include "gdal_alg.h"
#include <cstring>
#include "cpl_conv.h"
#include "cpl_error.h"
#include "cpl_progress.h"
#include "gdal.h"
#include "gdal_alg_priv.h"
#include "gdal_priv.h"
CPL_CVSID("$Id: gdaltransformgeolocs.cpp 7e07230bbff24eb333608de4dbd460b7312839d0 2017-12-11 19:08:47Z Even Rouault $")
/************************************************************************/
/* GDALTransformGeolocations() */
/************************************************************************/
/**
* Transform locations held in bands.
*
* The X/Y and possibly Z values in the identified bands are transformed
* using a spatial transformer. The changes values are written back to the
* source bands so they need to updatable.
*
* @param hXBand the band containing the X locations (usually long/easting).
* @param hYBand the band containing the Y locations (usually lat/northing).
* @param hZBand the band containing the Z locations (may be NULL).
* @param pfnTransformer the transformer function.
* @param pTransformArg the callback data for the transformer function.
* @param pfnProgress callback for reporting algorithm progress matching the
* GDALProgressFunc() semantics. May be NULL.
* @param pProgressArg callback argument passed to pfnProgress.
* @param papszOptions list of name/value options - none currently supported.
*
* @return CE_None on success or CE_Failure if an error occurs.
*/
CPLErr
GDALTransformGeolocations( GDALRasterBandH hXBand,
GDALRasterBandH hYBand,
GDALRasterBandH hZBand,
GDALTransformerFunc pfnTransformer,
void *pTransformArg,
GDALProgressFunc pfnProgress,
void *pProgressArg,
CPL_UNUSED char **papszOptions )
{
VALIDATE_POINTER1( hXBand, "GDALTransformGeolocations", CE_Failure );
VALIDATE_POINTER1( hYBand, "GDALTransformGeolocations", CE_Failure );
if( pfnProgress == nullptr )
pfnProgress = GDALDummyProgress;
/* -------------------------------------------------------------------- */
/* Ensure the bands are matching in size. */
/* -------------------------------------------------------------------- */
GDALRasterBand *poXBand = reinterpret_cast<GDALRasterBand *>(hXBand);
GDALRasterBand *poYBand = reinterpret_cast<GDALRasterBand *>(hYBand);
GDALRasterBand *poZBand = reinterpret_cast<GDALRasterBand *>(hZBand);
const int nXSize = poXBand->GetXSize();
const int nYSize = poXBand->GetYSize();
if( nXSize != poYBand->GetXSize()
|| nYSize != poYBand->GetYSize()
|| (poZBand != nullptr && nXSize != poZBand->GetXSize())
|| (poZBand != nullptr && nYSize != poZBand->GetYSize()) )
{
CPLError( CE_Failure, CPLE_AppDefined,
"Size of X, Y and/or Z bands do not match." );
return CE_Failure;
}
/* -------------------------------------------------------------------- */
/* Allocate a buffer large enough to hold one whole row. */
/* -------------------------------------------------------------------- */
double *padfX = static_cast<double *>(CPLMalloc(sizeof(double) * nXSize));
double *padfY = static_cast<double *>(CPLMalloc(sizeof(double) * nXSize));
double *padfZ = static_cast<double *>(CPLMalloc(sizeof(double) * nXSize));
int *panSuccess = static_cast<int *>(CPLMalloc(sizeof(int) * nXSize));
CPLErr eErr = CE_None;
pfnProgress( 0.0, "", pProgressArg );
for( int iLine = 0; eErr == CE_None && iLine < nYSize; iLine++ )
{
eErr = poXBand->RasterIO( GF_Read, 0, iLine, nXSize, 1,
padfX, nXSize, 1, GDT_Float64, 0, 0, nullptr );
if( eErr == CE_None )
eErr = poYBand->RasterIO( GF_Read, 0, iLine, nXSize, 1,
padfY, nXSize, 1, GDT_Float64,
0, 0, nullptr );
if( eErr == CE_None && poZBand != nullptr )
eErr = poZBand->RasterIO( GF_Read, 0, iLine, nXSize, 1,
padfZ, nXSize, 1, GDT_Float64,
0, 0, nullptr );
else
memset( padfZ, 0, sizeof(double) * nXSize);
if( eErr == CE_None )
{
pfnTransformer( pTransformArg, FALSE, nXSize,
padfX, padfY, padfZ, panSuccess );
}
if( eErr == CE_None )
eErr = poXBand->RasterIO( GF_Write, 0, iLine, nXSize, 1,
padfX, nXSize, 1, GDT_Float64,
0, 0, nullptr );
if( eErr == CE_None )
eErr = poYBand->RasterIO( GF_Write, 0, iLine, nXSize, 1,
padfY, nXSize, 1, GDT_Float64,
0, 0, nullptr );
if( eErr == CE_None && poZBand != nullptr )
eErr = poZBand->RasterIO( GF_Write, 0, iLine, nXSize, 1,
padfZ, nXSize, 1, GDT_Float64,
0, 0, nullptr );
if( eErr == CE_None )
pfnProgress( (iLine+1) /
static_cast<double>(nYSize), "", pProgressArg );
}
/* -------------------------------------------------------------------- */
/* Cleanup */
/* -------------------------------------------------------------------- */
CPLFree( padfX );
CPLFree( padfY );
CPLFree( padfZ );
CPLFree( panSuccess );
return eErr;
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,564 @@
/******************************************************************************
* $Id: gdalwarper.h d16ecc80707f9c7097a11bfe47c8403bb9df310f 2018-07-27 20:14:48 -0700 piyush.agram@jpl.nasa.gov $
*
* Project: GDAL High Performance Warper
* Purpose: Prototypes, and definitions for warping related work.
* Author: Frank Warmerdam, warmerdam@pobox.com
*
******************************************************************************
* Copyright (c) 2003, Frank Warmerdam
* Copyright (c) 2009-2012, Even Rouault <even dot rouault at mines-paris dot org>
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included
* in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
****************************************************************************/
#ifndef GDALWARPER_H_INCLUDED
#define GDALWARPER_H_INCLUDED
/**
* \file gdalwarper.h
*
* GDAL warper related entry points and definitions. Eventually it is
* expected that this file will be mostly private to the implementation,
* and the public C entry points will be available in gdal_alg.h.
*/
#include "gdal_alg.h"
#include "cpl_minixml.h"
#include "cpl_multiproc.h"
CPL_C_START
/* Note: values are selected to be consistent with GDALRIOResampleAlg of gcore/gdal.h */
/*! Warp Resampling Algorithm */
typedef enum {
/*! Nearest neighbour (select on one input pixel) */ GRA_NearestNeighbour=0,
/*! Bilinear (2x2 kernel) */ GRA_Bilinear=1,
/*! Cubic Convolution Approximation (4x4 kernel) */ GRA_Cubic=2,
/*! Cubic B-Spline Approximation (4x4 kernel) */ GRA_CubicSpline=3,
/*! Lanczos windowed sinc interpolation (6x6 kernel) */ GRA_Lanczos=4,
/*! Average (computes the average of all non-NODATA contributing pixels) */ GRA_Average=5,
/*! Mode (selects the value which appears most often of all the sampled points) */ GRA_Mode=6,
/* GRA_Gauss=7 reserved. */
/*! Max (selects maximum of all non-NODATA contributing pixels) */ GRA_Max=8,
/*! Min (selects minimum of all non-NODATA contributing pixels) */ GRA_Min=9,
/*! Med (selects median of all non-NODATA contributing pixels) */ GRA_Med=10,
/*! Q1 (selects first quartile of all non-NODATA contributing pixels) */ GRA_Q1=11,
/*! Q3 (selects third quartile of all non-NODATA contributing pixels) */ GRA_Q3=12
} GDALResampleAlg;
/*! GWKAverageOrMode Algorithm */
typedef enum {
/*! Average */ GWKAOM_Average=1,
/*! Mode */ GWKAOM_Fmode=2,
/*! Mode of GDT_Byte, GDT_UInt16, or GDT_Int16 */ GWKAOM_Imode=3,
/*! Maximum */ GWKAOM_Max=4,
/*! Minimum */ GWKAOM_Min=5,
/*! Quantile */ GWKAOM_Quant=6
} GWKAverageOrModeAlg;
/*! @cond Doxygen_Suppress */
typedef int
(*GDALMaskFunc)( void *pMaskFuncArg,
int nBandCount, GDALDataType eType,
int nXOff, int nYOff,
int nXSize, int nYSize,
GByte **papabyImageData,
int bMaskIsFloat, void *pMask );
CPLErr CPL_DLL
GDALWarpNoDataMasker( void *pMaskFuncArg, int nBandCount, GDALDataType eType,
int nXOff, int nYOff, int nXSize, int nYSize,
GByte **papabyImageData, int bMaskIsFloat,
void *pValidityMask, int* pbOutAllValid );
CPLErr CPL_DLL
GDALWarpDstAlphaMasker( void *pMaskFuncArg, int nBandCount, GDALDataType eType,
int nXOff, int nYOff, int nXSize, int nYSize,
GByte ** /*ppImageData */,
int bMaskIsFloat, void *pValidityMask );
CPLErr CPL_DLL
GDALWarpSrcAlphaMasker( void *pMaskFuncArg, int nBandCount, GDALDataType eType,
int nXOff, int nYOff, int nXSize, int nYSize,
GByte ** /*ppImageData */,
int bMaskIsFloat, void *pValidityMask, int* pbOutAllOpaque );
CPLErr CPL_DLL
GDALWarpSrcMaskMasker( void *pMaskFuncArg, int nBandCount, GDALDataType eType,
int nXOff, int nYOff, int nXSize, int nYSize,
GByte ** /*ppImageData */,
int bMaskIsFloat, void *pValidityMask );
CPLErr CPL_DLL
GDALWarpCutlineMasker( void *pMaskFuncArg, int nBandCount, GDALDataType eType,
int nXOff, int nYOff, int nXSize, int nYSize,
GByte ** /* ppImageData */,
int bMaskIsFloat, void *pValidityMask );
/*! @endcond */
/************************************************************************/
/* GDALWarpOptions */
/************************************************************************/
/** Warp control options for use with GDALWarpOperation::Initialize() */
typedef struct {
char **papszWarpOptions;
/*! In bytes, 0.0 for internal default */
double dfWarpMemoryLimit;
/*! Resampling algorithm to use */
GDALResampleAlg eResampleAlg;
/*! data type to use during warp operation, GDT_Unknown lets the algorithm
select the type */
GDALDataType eWorkingDataType;
/*! Source image dataset. */
GDALDatasetH hSrcDS;
/*! Destination image dataset - may be NULL if only using GDALWarpOperation::WarpRegionToBuffer(). */
GDALDatasetH hDstDS;
/*! Number of bands to process, may be 0 to select all bands. */
int nBandCount;
/*! The band numbers for the source bands to process (1 based) */
int *panSrcBands;
/*! The band numbers for the destination bands to process (1 based) */
int *panDstBands;
/*! The source band so use as an alpha (transparency) value, 0=disabled */
int nSrcAlphaBand;
/*! The dest. band so use as an alpha (transparency) value, 0=disabled */
int nDstAlphaBand;
/*! The "nodata" value real component for each input band, if NULL there isn't one */
double *padfSrcNoDataReal;
/*! The "nodata" value imaginary component - may be NULL even if real
component is provided. This value is not used to flag invalid values.
Only the real component is used. */
double *padfSrcNoDataImag;
/*! The "nodata" value real component for each output band, if NULL there isn't one */
double *padfDstNoDataReal;
/*! The "nodata" value imaginary component - may be NULL even if real
component is provided. Note that warp operations only use real component
for flagging invalid data.*/
double *padfDstNoDataImag;
/*! GDALProgressFunc() compatible progress reporting function, or NULL
if there isn't one. */
GDALProgressFunc pfnProgress;
/*! Callback argument to be passed to pfnProgress. */
void *pProgressArg;
/*! Type of spatial point transformer function */
GDALTransformerFunc pfnTransformer;
/*! Handle to image transformer setup structure */
void *pTransformerArg;
/** Unused. Must be NULL */
GDALMaskFunc *papfnSrcPerBandValidityMaskFunc;
/** Unused. Must be NULL */
void **papSrcPerBandValidityMaskFuncArg;
/** Unused. Must be NULL */
GDALMaskFunc pfnSrcValidityMaskFunc;
/** Unused. Must be NULL */
void *pSrcValidityMaskFuncArg;
/** Unused. Must be NULL */
GDALMaskFunc pfnSrcDensityMaskFunc;
/** Unused. Must be NULL */
void *pSrcDensityMaskFuncArg;
/** Unused. Must be NULL */
GDALMaskFunc pfnDstDensityMaskFunc;
/** Unused. Must be NULL */
void *pDstDensityMaskFuncArg;
/** Unused. Must be NULL */
GDALMaskFunc pfnDstValidityMaskFunc;
/** Unused. Must be NULL */
void *pDstValidityMaskFuncArg;
/** Unused. Must be NULL */
CPLErr (*pfnPreWarpChunkProcessor)( void *pKern, void *pArg );
/** Unused. Must be NULL */
void *pPreWarpProcessorArg;
/** Unused. Must be NULL */
CPLErr (*pfnPostWarpChunkProcessor)( void *pKern, void *pArg);
/** Unused. Must be NULL */
void *pPostWarpProcessorArg;
/*! Optional OGRPolygonH for a masking cutline. */
void *hCutline;
/*! Optional blending distance to apply across cutline in pixels, default is zero. */
double dfCutlineBlendDist;
} GDALWarpOptions;
GDALWarpOptions CPL_DLL * CPL_STDCALL GDALCreateWarpOptions(void);
void CPL_DLL CPL_STDCALL GDALDestroyWarpOptions( GDALWarpOptions * );
GDALWarpOptions CPL_DLL * CPL_STDCALL
GDALCloneWarpOptions( const GDALWarpOptions * );
void CPL_DLL CPL_STDCALL
GDALWarpInitDstNoDataReal( GDALWarpOptions *, double dNoDataReal );
void CPL_DLL CPL_STDCALL
GDALWarpInitSrcNoDataReal( GDALWarpOptions *, double dNoDataReal );
void CPL_DLL CPL_STDCALL
GDALWarpInitNoDataReal( GDALWarpOptions *, double dNoDataReal );
void CPL_DLL CPL_STDCALL
GDALWarpInitDstNoDataImag( GDALWarpOptions *, double dNoDataImag );
void CPL_DLL CPL_STDCALL
GDALWarpInitSrcNoDataImag( GDALWarpOptions *, double dNoDataImag );
void CPL_DLL CPL_STDCALL
GDALWarpResolveWorkingDataType( GDALWarpOptions * );
void CPL_DLL CPL_STDCALL
GDALWarpInitDefaultBandMapping( GDALWarpOptions *, int nBandCount );
/*! @cond Doxygen_Suppress */
CPLXMLNode CPL_DLL * CPL_STDCALL
GDALSerializeWarpOptions( const GDALWarpOptions * );
GDALWarpOptions CPL_DLL * CPL_STDCALL
GDALDeserializeWarpOptions( CPLXMLNode * );
/*! @endcond */
/************************************************************************/
/* GDALReprojectImage() */
/************************************************************************/
CPLErr CPL_DLL CPL_STDCALL
GDALReprojectImage( GDALDatasetH hSrcDS, const char *pszSrcWKT,
GDALDatasetH hDstDS, const char *pszDstWKT,
GDALResampleAlg eResampleAlg, double dfWarpMemoryLimit,
double dfMaxError,
GDALProgressFunc pfnProgress, void *pProgressArg,
GDALWarpOptions *psOptions );
CPLErr CPL_DLL CPL_STDCALL
GDALCreateAndReprojectImage( GDALDatasetH hSrcDS, const char *pszSrcWKT,
const char *pszDstFilename, const char *pszDstWKT,
GDALDriverH hDstDriver, char **papszCreateOptions,
GDALResampleAlg eResampleAlg, double dfWarpMemoryLimit,
double dfMaxError,
GDALProgressFunc pfnProgress, void *pProgressArg,
GDALWarpOptions *psOptions );
/************************************************************************/
/* VRTWarpedDataset */
/************************************************************************/
GDALDatasetH CPL_DLL CPL_STDCALL
GDALAutoCreateWarpedVRT( GDALDatasetH hSrcDS,
const char *pszSrcWKT, const char *pszDstWKT,
GDALResampleAlg eResampleAlg,
double dfMaxError, const GDALWarpOptions *psOptions );
GDALDatasetH CPL_DLL CPL_STDCALL
GDALCreateWarpedVRT( GDALDatasetH hSrcDS,
int nPixels, int nLines, double *padfGeoTransform,
GDALWarpOptions *psOptions );
CPLErr CPL_DLL CPL_STDCALL
GDALInitializeWarpedVRT( GDALDatasetH hDS,
GDALWarpOptions *psWO );
CPL_C_END
#if defined(__cplusplus) && !defined(CPL_SUPRESS_CPLUSPLUS)
/************************************************************************/
/* GDALWarpKernel */
/* */
/** This is the number of dummy pixels that must be reserved in source arrays
* in order to satisfy assumptions made in GWKResample(), and more specifically
* by GWKGetPixelRow() that always read a even number of pixels. So if we are
* in the situation to read the last pixel of the source array, we need 1 extra
* dummy pixel to avoid reading out of bounds. */
#define WARP_EXTRA_ELTS 1
/** This class represents the lowest level of abstraction of warping.
*
* It holds the imagery for one "chunk" of a warp, and the
* pre-prepared masks. All IO is done before and after its
* operation. This class is not normally used by the
* application.
*/
class CPL_DLL GDALWarpKernel
{
CPL_DISALLOW_COPY_ASSIGN(GDALWarpKernel)
public:
/** Warp options */
char **papszWarpOptions;
/** Resample algorithm */
GDALResampleAlg eResample;
/** Working data type */
GDALDataType eWorkingDataType;
/** Number of input and output bands (excluding alpha bands) */
int nBands;
/** Width of the source image */
int nSrcXSize;
/** Height of the source image */
int nSrcYSize;
/** Extra pixels (included in nSrcXSize) reserved for filter window. Should be ignored in scale computation */
double dfSrcXExtraSize;
/** Extra pixels (included in nSrcYSize) reserved for filter window. Should be ignored in scale computation */
double dfSrcYExtraSize;
/** Array of nBands source images of size nSrcXSize * nSrcYSize. Each subarray must have WARP_EXTRA_ELTS at the end */
GByte **papabySrcImage;
/** Array of nBands validity mask of size (nSrcXSize * nSrcYSize + WARP_EXTRA_ELTS) / 8 */
GUInt32 **papanBandSrcValid;
/** Unified validity mask of size (nSrcXSize * nSrcYSize + WARP_EXTRA_ELTS) / 8 */
GUInt32 *panUnifiedSrcValid;
/** Unified source density of size nSrcXSize * nSrcYSize + WARP_EXTRA_ELTS */
float *pafUnifiedSrcDensity;
/** Width of the destination image */
int nDstXSize;
/** Height of the destination image */
int nDstYSize;
/** Array of nBands destination images of size nDstXSize * nDstYSize */
GByte **papabyDstImage;
/** Validify mask of size (nDstXSize * nDstYSize) / 8 */
GUInt32 *panDstValid;
/** Destination density of size nDstXSize * nDstYSize */
float *pafDstDensity;
/** X resampling scale, i.e. nDstXSize / nSrcXSize */
double dfXScale;
/** Y resampling scale, i.e. nDstYSize / nSrcYSize */
double dfYScale;
/** X size of filter kernel */
double dfXFilter;
/** Y size of filter kernel */
double dfYFilter;
/** X size of window to filter */
int nXRadius;
/** Y size of window to filter */
int nYRadius;
/** X filtering offset */
int nFiltInitX;
/** Y filtering offset */
int nFiltInitY;
/** X offset of the source buffer regarding the top-left corner of the image */
int nSrcXOff;
/** Y offset of the source buffer regarding the top-left corner of the image */
int nSrcYOff;
/** X offset of the destination buffer regarding the top-left corner of the image */
int nDstXOff;
/** Y offset of the destination buffer regarding the top-left corner of the image */
int nDstYOff;
/** Pixel transformation function */
GDALTransformerFunc pfnTransformer;
/** User data provided to pfnTransformer */
void *pTransformerArg;
/** Progress function */
GDALProgressFunc pfnProgress;
/** User data provided to pfnProgress */
void *pProgress;
/** Base/offset value for progress computation */
double dfProgressBase;
/** Scale value for progress computation */
double dfProgressScale;
/** Array of nBands value for destination nodata */
double *padfDstNoDataReal;
/*! @cond Doxygen_Suppress */
/** Per-thread data. Internally set */
void *psThreadData;
/*! @endcond */
GDALWarpKernel();
virtual ~GDALWarpKernel();
CPLErr Validate();
CPLErr PerformWarp();
};
/*! @cond Doxygen_Suppress */
void* GWKThreadsCreate(char** papszWarpOptions,
GDALTransformerFunc pfnTransformer,
void* pTransformerArg);
void GWKThreadsEnd(void* psThreadDataIn);
/*! @endcond */
/************************************************************************/
/* GDALWarpOperation() */
/* */
/* This object is application created, or created by a higher */
/* level convenience function. It is responsible for */
/* subdividing the operation into chunks, loading and saving */
/* imagery, and establishing the varios validity and density */
/* masks. Actual resampling is done by the GDALWarpKernel. */
/************************************************************************/
/*! @cond Doxygen_Suppress */
typedef struct _GDALWarpChunk GDALWarpChunk;
/*! @endcond */
class CPL_DLL GDALWarpOperation {
CPL_DISALLOW_COPY_ASSIGN(GDALWarpOperation)
private:
GDALWarpOptions *psOptions;
void WipeOptions();
int ValidateOptions();
CPLErr ComputeSourceWindow( int nDstXOff, int nDstYOff,
int nDstXSize, int nDstYSize,
int *pnSrcXOff, int *pnSrcYOff,
int *pnSrcXSize, int *pnSrcYSize,
double *pdfSrcXExtraSize, double *pdfSrcYExtraSize,
double* pdfSrcFillRatio );
void ComputeSourceWindowStartingFromSource(
int nDstXOff, int nDstYOff,
int nDstXSize, int nDstYSize,
double* padfSrcMinX, double* padfSrcMinY,
double* padfSrcMaxX, double* padfSrcMaxY);
static CPLErr CreateKernelMask( GDALWarpKernel *, int iBand,
const char *pszType );
CPLMutex *hIOMutex;
CPLMutex *hWarpMutex;
int nChunkListCount;
int nChunkListMax;
GDALWarpChunk *pasChunkList;
int bReportTimings;
unsigned long nLastTimeReported;
void *psThreadData;
void WipeChunkList();
CPLErr CollectChunkListInternal( int nDstXOff, int nDstYOff,
int nDstXSize, int nDstYSize );
void CollectChunkList( int nDstXOff, int nDstYOff,
int nDstXSize, int nDstYSize );
void ReportTiming( const char * );
public:
GDALWarpOperation();
virtual ~GDALWarpOperation();
CPLErr Initialize( const GDALWarpOptions *psNewOptions );
void* CreateDestinationBuffer( int nDstXSize, int nDstYSize,
int *pbWasInitialized = nullptr );
static void DestroyDestinationBuffer(void* pDstBuffer);
const GDALWarpOptions *GetOptions();
CPLErr ChunkAndWarpImage( int nDstXOff, int nDstYOff,
int nDstXSize, int nDstYSize );
CPLErr ChunkAndWarpMulti( int nDstXOff, int nDstYOff,
int nDstXSize, int nDstYSize );
CPLErr WarpRegion( int nDstXOff, int nDstYOff,
int nDstXSize, int nDstYSize,
int nSrcXOff=0, int nSrcYOff=0,
int nSrcXSize=0, int nSrcYSize=0,
double dfProgressBase=0.0, double dfProgressScale=1.0);
CPLErr WarpRegion( int nDstXOff, int nDstYOff,
int nDstXSize, int nDstYSize,
int nSrcXOff, int nSrcYOff,
int nSrcXSize, int nSrcYSize,
double dfSrcXExtraSize, double dfSrcYExtraSize,
double dfProgressBase, double dfProgressScale);
CPLErr WarpRegionToBuffer( int nDstXOff, int nDstYOff,
int nDstXSize, int nDstYSize,
void *pDataBuf,
GDALDataType eBufDataType,
int nSrcXOff=0, int nSrcYOff=0,
int nSrcXSize=0, int nSrcYSize=0,
double dfProgressBase=0.0, double dfProgressScale=1.0);
CPLErr WarpRegionToBuffer( int nDstXOff, int nDstYOff,
int nDstXSize, int nDstYSize,
void *pDataBuf,
GDALDataType eBufDataType,
int nSrcXOff, int nSrcYOff,
int nSrcXSize, int nSrcYSize,
double dfSrcXExtraSize, double dfSrcYExtraSize,
double dfProgressBase, double dfProgressScale);
};
#endif /* def __cplusplus */
CPL_C_START
/** Opaque type representing a GDALWarpOperation object */
typedef void * GDALWarpOperationH;
GDALWarpOperationH CPL_DLL GDALCreateWarpOperation(const GDALWarpOptions* );
void CPL_DLL GDALDestroyWarpOperation( GDALWarpOperationH );
CPLErr CPL_DLL GDALChunkAndWarpImage( GDALWarpOperationH, int, int, int, int );
CPLErr CPL_DLL GDALChunkAndWarpMulti( GDALWarpOperationH, int, int, int, int );
CPLErr CPL_DLL GDALWarpRegion( GDALWarpOperationH,
int, int, int, int, int, int, int, int );
CPLErr CPL_DLL GDALWarpRegionToBuffer( GDALWarpOperationH, int, int, int, int,
void *, GDALDataType,
int, int, int, int );
/************************************************************************/
/* Warping kernel functions */
/************************************************************************/
/*! @cond Doxygen_Suppress */
int GWKGetFilterRadius(GDALResampleAlg eResampleAlg);
typedef double (*FilterFuncType)(double dfX);
FilterFuncType GWKGetFilterFunc(GDALResampleAlg eResampleAlg);
// TODO(schwehr): Can padfVals be a const pointer?
typedef double (*FilterFunc4ValuesType)(double* padfVals);
FilterFunc4ValuesType GWKGetFilterFunc4Values(GDALResampleAlg eResampleAlg);
/*! @endcond */
CPL_C_END
#endif /* ndef GDAL_ALG_H_INCLUDED */

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,197 @@
/******************************************************************************
* $Id: gdalwarpkernel_opencl.h 678d89afcc4ec43e300b2f337b51349139543d01 2016-06-30 22:42:39Z Kurt Schwehr $
*
* Project: OpenCL Image Reprojector
* Purpose: Implementation of the GDALWarpKernel reprojector in OpenCL.
* Author: Seth Price, seth@pricepages.org
*
******************************************************************************
* Copyright (c) 2010, Seth Price <seth@pricepages.org>
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included
* in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
****************************************************************************/
#if defined(HAVE_OPENCL)
/* The following relates to the profiling calls to
clSetCommandQueueProperty() which are not available by default
with some OpenCL implementation (i.e. ATI) */
#if defined(DEBUG_OPENCL) && DEBUG_OPENCL == 1
#define CL_USE_DEPRECATED_OPENCL_1_0_APIS
#endif
#ifdef __APPLE__
#include <OpenCL/OpenCL.h>
#else
#include <CL/opencl.h>
#endif
#ifdef __cplusplus /* If this is a C++ compiler, use C linkage */
extern "C" {
#endif
typedef enum {
OCL_Bilinear=10,
OCL_Cubic=11,
OCL_CubicSpline=12,
OCL_Lanczos=13
} OCLResampAlg;
typedef enum
{
VENDOR_OTHER,
VENDOR_AMD,
VENDOR_INTEL
} OCLVendor;
struct oclWarper {
cl_command_queue queue;
cl_context context;
cl_device_id dev;
cl_kernel kern1;
cl_kernel kern4;
int srcWidth;
int srcHeight;
int dstWidth;
int dstHeight;
int useUnifiedSrcDensity;
int useUnifiedSrcValid;
int useDstDensity;
int useDstValid;
int numBands;
int numImages;
OCLResampAlg resampAlg;
cl_channel_type imageFormat;
cl_mem *realWorkCL;
union {
void **v;
char **c;
unsigned char **uc;
short **s;
unsigned short **us;
float **f;
} realWork;
cl_mem *imagWorkCL;
union {
void **v;
char **c;
unsigned char **uc;
short **s;
unsigned short **us;
float **f;
} imagWork;
cl_mem *dstRealWorkCL;
union {
void **v;
char **c;
unsigned char **uc;
short **s;
unsigned short **us;
float **f;
} dstRealWork;
cl_mem *dstImagWorkCL;
union {
void **v;
char **c;
unsigned char **uc;
short **s;
unsigned short **us;
float **f;
} dstImagWork;
unsigned int imgChSize1;
cl_channel_order imgChOrder1;
unsigned int imgChSize4;
cl_channel_order imgChOrder4;
char useVec;
cl_mem useBandSrcValidCL;
char *useBandSrcValid;
cl_mem nBandSrcValidCL;
float *nBandSrcValid;
cl_mem xyWorkCL;
float *xyWork;
int xyWidth;
int xyHeight;
int coordMult;
unsigned int xyChSize;
cl_channel_order xyChOrder;
cl_mem fDstNoDataRealCL;
float *fDstNoDataReal;
OCLVendor eCLVendor;
};
struct oclWarper* GDALWarpKernelOpenCL_createEnv(int srcWidth, int srcHeight,
int dstWidth, int dstHeight,
cl_channel_type imageFormat,
int numBands, int coordMult,
int useImag, int useBandSrcValid,
float *fDstDensity,
double *dfDstNoDataReal,
OCLResampAlg resampAlg, cl_int *envErr);
cl_int GDALWarpKernelOpenCL_setSrcValid(struct oclWarper *warper,
int *bandSrcValid, int bandNum);
cl_int GDALWarpKernelOpenCL_setSrcImg(struct oclWarper *warper, void *imgData,
int bandNum);
cl_int GDALWarpKernelOpenCL_setDstImg(struct oclWarper *warper, void *imgData,
int bandNum);
cl_int GDALWarpKernelOpenCL_setCoordRow(struct oclWarper *warper,
double *rowSrcX, double *rowSrcY,
double srcXOff, double srcYOff,
int *success, int rowNum);
cl_int GDALWarpKernelOpenCL_runResamp(struct oclWarper *warper,
float *unifiedSrcDensity,
unsigned int *unifiedSrcValid,
float *dstDensity,
unsigned int *dstValid,
double dfXScale, double dfYScale,
double dfXFilter, double dfYFilter,
int nXRadius, int nYRadius,
int nFiltInitX, int nFiltInitY);
cl_int GDALWarpKernelOpenCL_getRow(struct oclWarper *warper,
void **rowReal, void **rowImag,
int rowNum, int bandNum);
cl_int GDALWarpKernelOpenCL_deleteEnv(struct oclWarper *warper);
#ifdef __cplusplus /* If this is a C++ compiler, end C linkage */
}
#endif
#endif /* defined(HAVE_OPENCL) */

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,86 @@
/* $Id: gvgcpfit.h de59b35db67113437ccb089ebab8dc4b9628d5f0 2016-10-24 04:10:14Z Kurt Schwehr $ */
#ifndef GVGCPFIT_H_INCLUDED
#define GVGCPFIT_H_INCLUDED
#include "cpl_port.h"
#include "cpl_conv.h"
#include "cpl_error.h"
#define EXTERNAL
#define LOCAL static
#define SUCCESS 0
#define ABORT -1
/*------------------------ Start of file CURVEFIT.H -----------------------*/
/*
******************************************************************************
* *
* CURVEFIT.H *
* ========= *
* *
* This file contains the function prototype for CURVEFIT.C. *
******************************************************************************
*/
#ifndef CURVEFIT_H
#define CURVEFIT_H
/*- Function prototypes in CURVEFIT.C. -*/
EXTERNAL int svdfit(float x[], float y[], int ndata,
double a[], int ma, double **u, double **v, double w[],
double *chisq, void (*funcs)(double, double *, int));
EXTERNAL void svbksb(double **u, double w[], double **v, int m,int n,
double b[], double x[]);
EXTERNAL void svdvar(double **v, int ma, double w[], double **cvm);
EXTERNAL int svdcmp(double **a, int m, int n, double *w, double **v);
#endif
/*-------------------------- End of file CURVEFIT.H -----------------------*/
/*----------------------------- FILE polyfit.h ----------------------------*/
#ifndef POLYFIT_H
#define POLYFIT_H
EXTERNAL int OneDPolyFit( double *rms_err, double *coeffs_array,
int fit_order, int no_samples, double *f_array, double *x_array );
EXTERNAL double OneDPolyEval( double *coeff, int order, double x );
EXTERNAL int TwoDPolyFit( double *rms_err, double *coeffs_array,
int fit_order, int no_samples, double *f_array, double *x_array,
double *y_array );
EXTERNAL double TwoDPolyEval( double *coeff, int order, double x, double y );
EXTERNAL int TwoDPolyGradFit( double *rms_err, double *coeffs_array,
int fit_order, int no_samples, double *gradxy_array,
double *x_array, double *y_array );
EXTERNAL void TwoDPolyGradEval(double *fgradx, double *fgrady,
double *coeff, int order, double x, double y);
EXTERNAL void GetPolyInX (double *xcoeffs, double *xycoeffs, int order,
double y);
EXTERNAL void GetPolyInY(double *ycoeffs, double *xycoeffs, int order,
double x);
EXTERNAL int ThreeDPolyFit( double *rms_err, double *coeffs_array,
int fit_order, int no_samples, double *f_array, double *x_array,
double *y_array, double *z_array );
EXTERNAL double ThreeDPolyEval( double *coeff, int order, double x, double y, double z );
#endif /* POLYFIT_H */
/*---------------------- End of FILE polyfit.h ----------------------------*/
#endif /* ndef _GVGCPFIT_INCLUDED */

View File

@@ -0,0 +1,38 @@
Qhull, Copyright (c) 1993-2012
C.B. Barber
Arlington, MA
and
The National Science and Technology Research Center for
Computation and Visualization of Geometric Structures
(The Geometry Center)
University of Minnesota
email: qhull@qhull.org
This software includes Qhull from C.B. Barber and The Geometry Center.
Qhull is copyrighted as noted above. Qhull is free software and may
be obtained via http from www.qhull.org. It may be freely copied, modified,
and redistributed under the following conditions:
1. All copyright notices must remain intact in all files.
2. A copy of this text file must be distributed along with any copies
of Qhull that you redistribute; this includes copies that you have
modified, or copies of programs or other software products that
include Qhull.
3. If you modify Qhull, you must include a notice giving the
name of the person performing the modification, the date of
modification, and the reason for such modification.
4. When distributing modified versions of Qhull, or other software
products that include Qhull, you must provide notice that the original
source code may be obtained as noted above.
5. There is no warranty or other guarantee of fitness for Qhull, it is
provided solely "as is". Bug reports or fixes may be sent to
qhull_bug@qhull.org; the authors may or may not act on them as
they desire.

View File

@@ -0,0 +1,523 @@
Name
qhull, rbox 2012.1 2012/02/18
Convex hull, Delaunay triangulation, Voronoi diagrams, Halfspace intersection
Documentation:
html/index.htm
http://www.qhull.org/html
Available from:
<http://www.qhull.org>
<git@gitorious.org:qhull/qhull.git>
<http://packages.debian.org/sid/libqhull5> [out-of-date]
News and a paper:
<http://www.qhull.org/news>
<http://citeseerx.ist.psu.edu/viewdoc/summary?doi=10.1.1.117.405>
Version 1 (simplicial only):
<http://www.qhull.org/download/qhull-1.0.tar.gz>
Purpose
Qhull is a general dimension convex hull program that reads a set
of points from stdin, and outputs the smallest convex set that contains
the points to stdout. It also generates Delaunay triangulations, Voronoi
diagrams, furthest-site Voronoi diagrams, and halfspace intersections
about a point.
Rbox is a useful tool in generating input for Qhull; it generates
hypercubes, diamonds, cones, circles, simplices, spirals,
lattices, and random points.
Qhull produces graphical output for Geomview. This helps with
understanding the output. <http://www.geomview.org>
Environment requirements
Qhull and rbox should run on all 32-bit and 64-bit computers. Use
an ANSI C or C++ compiler to compile the program. The software is
self-contained. It comes with examples and test scripts.
Qhull's C++ interface uses the STL. The C++ test program uses QTestLib
from Nokia's Qt Framework. Qhull's C++ interface may change without
notice. Eventually, it will move into the qhull shared library.
Qhull is copyrighted software. Please read COPYING.txt and REGISTER.txt
before using or distributing Qhull.
To cite Qhull, please use
Barber, C.B., Dobkin, D.P., and Huhdanpaa, H.T., "The Quickhull
algorithm for convex hulls," ACM Trans. on Mathematical Software,
22(4):469-483, Dec 1996, http://www.qhull.org.
To contribute to Qhull
Qhull is on Gitorious (http://gitorious.org:qhull, git@gitorious.org:qhull/qhull.git)
For internal documentation, see html/qh-code.htm
To install Qhull
Qhull is precompiled for Windows, otherwise it needs compilation.
Besides makefiles for gcc, qhull includes CMakeLists.txt for CMake,
vcproj/sln files for Microsoft Visual Studio, and .pro files for Qt Creator.
It compiles with mingw.
Install and build instructions follow.
See the end of this document for a list of distributed files.
-----------------
Installing Qhull on Windows
The zip file contains rbox.exe, qhull.exe, qconvex.exe, qdelaunay.exe,
qhalf.exe, qvoronoi.exe, testqset.exe, user_eg*.exe, documentation files,
and source files.
To install Qhull:
- Unzip the files into a directory. You may use WinZip32 <www.hotfiles.com>
- Click on QHULL-GO or open a command window into Qhull's bin directory.
To uninstall Qhull
- Delete the qhull directory
To learn about Qhull:
- Execute 'qconvex' for a synopsis and examples.
- Execute 'rbox 10 | qconvex' to compute the convex hull of 10 random points.
- Execute 'rbox 10 | qconvex i TO file' to write results to 'file'.
- Browse the documentation: qhull\html\index.htm
- If an error occurs, Windows sends the error to stdout instead of stderr.
Use 'TO xxx' to send normal output to xxx and error output to stdout
To improve the command window
- Double-click the window bar to increase the size of the window
- Right-click the window bar
- Select Properties
- Check QuickEdit Mode
Select text with right-click or Enter
Paste text with right-click
- Change Font to Lucinda Console
- Change Layout to Screen Buffer Height 999, Window Size Height 55
- Change Colors to Screen Background White, Screen Text Black
- Click OK
- Select 'Modify shortcut that started this window', then OK
If you use qhull a lot, install MSYS (www.mingw.org),
Road Bash (www.qhull.org/bash), or Cygwin (www.cygwin.com).
-----------------
Installing Qhull on Unix with gcc
To build Qhull, static libraries, shared library, and C++ interface
- Extract Qhull from qhull...tgz or qhull...zip
- make
- export LD_LIBRARY_PATH=$PWD/lib:$LD_LIBRARY_PATH
Or, to build Qhull and libqhullstatic.a
- Extract Qhull from qhull...tgz or qhull...zip
- cd src/libqhull
- make
The Makefiles may be edited for other compilers.
If 'testqset' exits with an error, qhull is broken
-----------------
Installing Qhull with CMake 2.6 or later
To build Qhull, static libraries, shared library, and C++ interface
- Extract Qhull from qhull...tgz or qhull...zip
- cd build
- cmake ..
- make
- make install
On Windows, CMake installs to C:/Program Files/qhull
See CMakeLists.txt for further build instructions
-----------------
Installing Qhull with Qt
To build Qhull, static libraries, shared library, C++ interface, and C++ test
- Extract Qhull from qhull...tgz or qhull...zip
- cd src
- qmake
- make
-----------------
Installing Qhull with Autoconf [WARNING out-of-date]
The tar.gz tarball contains documentation, source files,
and a config directory [R. Laboissiere].
[Nov 2011] Qhull 2009.1.2 does not include the C++ interface
To install Qhull
- Extract the files
- ./configure
- make
- make install
-------------------
Working with Qhull's C++ interface
Qhull's C++ interface is likely to change. Stay current with Gitorious.
To clone Qhull's next branch from http://gitorious.org/qhull
git init
git clone git://gitorious.org/qhull/qhull.git
cd qhull
git checkout next
...
git pull origin next
------------------
Compiling Qhull with Microsoft Visual C++ 2005 or later
To compile Qhull with Microsoft Visual C++
- Extract Qhull from Gitorious, qhull...tgz, or qhull...zip
- Load solution build/qhull.sln
- Build
- Project qhulltest requires Qt for DevStudio (http://qt.nokia.com/downloads)
Set the QTDIR environment variable to your Qt directory (e.g., c:/qt/4.7.4)
If incorrect, precompile will fail with 'Can not locate the file specified'
-----------------
Compiling Qhull with Qt Creator
Qt (http://qt.nokia.com) is a C++ framework for Windows, Linux, and Macintosh
Qhull uses QTestLib to test qhull's C++ interface (qhulltest)
To compile Qhull with Qt Creator
- Extract Qhull from Gitorious, qhull...tgz, or qhull...zip
- Download the Qt SDK from Nokia (http://qt.nokia.com/downloads)
- Start Qt Creator
- Load src/qhull-all.pro
- Build
-----------------
Compiling Qhull with mingw on Windows
To compile Qhull with MINGW
- Extract Qhull from Gitorious, qhull...tgz, or qhull...zip
- Install Road Bash (http://www.qhull.org/bash)
or install MSYS (http://www.mingw.org/wiki/msys)
- Install MINGW (http://www.mingw.org/). Mingw is included with Qt SDK.
- make
-----------------
Compiling Qhull with cygwin on Windows
To compile Qhull with cygwin
- Extract Qhull from Gitorious, qhull...tgz, or qhull...zip
- Install cygwin (http://www.cygwin.com)
- Include packages for gcc, make, ar, and ln
- make
-----------------
Compiling from Makfile without gcc
The file, qhull-src.tgz, contains documentation and source files for
qhull and rbox.
To unpack the gzip file
- tar zxf qhull-src.tgz
- cd qhull
Compiling qhull and rbox with Makefile
- in Makefile, check the CC, CCOPTS1, PRINTMAN, and PRINTC defines
- the defaults are gcc and enscript
- CCOPTS1 should include the ANSI flag. It defines __STDC__
- in user.h, check the definitions of qh_SECticks and qh_CPUclock.
- use '#define qh_CLOCKtype 2' for timing runs longer than 1 hour
- type: make
- this builds: qhull qconvex qdelaunay qhalf qvoronoi rbox libqhull.a
- type: make doc
- this prints the man page
- See also qhull/html/index.htm
- if your compiler reports many errors, it is probably not a ANSI C compiler
- you will need to set the -ansi switch or find another compiler
- if your compiler warns about missing prototypes for fprintf() etc.
- this is ok, your compiler should have these in stdio.h
- if your compiler warns about missing prototypes for memset() etc.
- include memory.h in qhull_a.h
- if your compiler reports "global.c: storage size of 'qh_qh' isn't known"
- delete the initializer "={0}" in global.c, stat.c and mem.c
- if your compiler warns about "stat.c: improper initializer"
- this is ok, the initializer is not used
- if you have trouble building libqhull.a with 'ar'
- try 'make -f Makefile.txt qhullx'
- if the code compiles, the qhull test case will automatically execute
- if an error occurs, there's an incompatibility between machines
- If you can, try a different compiler
- You can turn off the Qhull memory manager with qh_NOmem in mem.h
- You can turn off compiler optimization (-O2 in Makefile)
- If you find the source of the problem, please let us know
- to install the programs and their man pages:
- define MANDIR and BINDIR
- type 'make install'
- if you have Geomview (www.geomview.org)
- try 'rbox 100 | qconvex G >a' and load 'a' into Geomview
- run 'q_eg' for Geomview examples of Qhull output (see qh-eg.htm)
------------------
Compiling on other machines and compilers
Qhull compiles with Borland C++ 5.0 bcc32. A Makefile is included.
Execute 'make -f Mborland'. If you use the Borland IDE, set the ANSI
option in Options:Project:Compiler:Source:Language-compliance.
Qhull compiles with Borland C++ 4.02 for Win32 and DOS Power Pack.
Use 'make -f Mborland -D_DPMI'. Qhull 1.0 compiles with Borland
C++ 4.02. For rbox 1.0, use "bcc32 -WX -w- -O2-e -erbox -lc rbox.c".
Use the same options for Qhull 1.0. [D. Zwick]
Qhull compiles with Metrowerks C++ 1.7 with the ANSI option.
If you turn on full warnings, the compiler will report a number of
unused variables, variables set but not used, and dead code. These are
intentional. For example, variables may be initialized (unnecessarily)
to prevent warnings about possible use of uninitialized variables.
Qhull compiles on the Power Macintosh with Metrowerk's C compiler.
It uses the SIOUX interface to read point coordinates and return output.
There is no graphical output. For project files, see 'Compiling a
custom build'. Instead of using SIOUX, Qhull may be embedded within an
application.
Some users have reported problems with compiling Qhull under Irix 5.1. It
compiles under other versions of Irix.
If you have troubles with the memory manager, you can turn it off by
defining qh_NOmem in mem.h.
-----------------
Distributed files
README.txt // Instructions for installing Qhull
REGISTER.txt // Qhull registration
COPYING.txt // Copyright notice
QHULL-GO.lnk // Windows icon for eg/qhull-go.bat
Announce.txt // Announcement
CMakeLists.txt // CMake build file (2.6 or later)
File_id.diz // Package descriptor
index.htm // Home page
Makefile // Makefile for gcc and other compilers
qhull*.md5sum // md5sum for all files
bin/* // Qhull executables and dll (.zip only)
build/qhull.sln // DevStudio solution and project files (2005 or later)
build/*.vcproj
config/* // Autoconf files for creating configure (Unix only)
eg/* // Test scripts and geomview files from q_eg
html/index.htm // Manual
html/qh-faq.htm // Frequently asked questions
html/qh-get.htm // Download page
html/qhull-cpp.xml // C++ style notes as a Road FAQ (www.qhull.org/road)
src/Changes.txt // Change history for Qhull and rbox
src/qhull-all.pro // Qt project
eg/
q_eg // shell script for Geomview examples (eg.01.cube)
q_egtest // shell script for Geomview test examples
q_test // shell script to test qhull
q_test-ok.txt // output from q_test
qhulltest-ok.txt // output from qhulltest (Qt only)
rbox consists of (bin, html):
rbox.exe // Win32 executable (.zip only)
rbox.htm // html manual
rbox.man // Unix man page
rbox.txt
qhull consists of (bin, html):
qhull.exe // Win32 executables and dlls (.zip only)
qconvex.exe
qdelaunay.exe
qhalf.exe
qvoronoi.exe
qhull.dll
qhull_p.dll
qhull-go.bat // command window
qconvex.htm // html manual
qdelaun.htm
qdelau_f.htm
qhalf.htm
qvoronoi.htm
qvoron_f.htm
qh-eg.htm
qh-code.htm
qh-impre.htm
index.htm
qh-opt*.htm
qh-quick.htm
qh--*.gif // images for manual
normal_voronoi_knauss_oesterle.jpg
qhull.man // Unix man page
qhull.txt
bin/
msvcr80.dll // Visual C++ redistributable file (.zip only)
src/
qhull/unix.c // Qhull and rbox applications
qconvex/qconvex.c
qhalf/qhalf.c
qdelaunay/qdelaunay.c
qvoronoi/qvoronoi.c
rbox/rbox.c
user_eg/user_eg.c // example of using qhull_p.dll (requires -Dqh_QHpointer)
user_eg2/user_eg2.c // example of using qhull.dll from a user program
user_eg3/user_eg3.cpp // example of Qhull's C++ interface with libqhullstatic_p.a
qhulltest/qhulltest.cpp // Test of Qhull's C++ interface using Qt's QTestLib
qhull-*.pri // Include files for Qt projects
src/libqhull
libqhull.pro // Qt project for shared library (qhull.dll)
index.htm // design documentation for libqhull
qh-*.htm
qhull-exports.def // Export Definition file for Visual C++
Makefile // Simple gcc Makefile for qhull and libqhullstatic.a
Mborland // Makefile for Borland C++ 5.0
libqhull.h // header file for qhull
user.h // header file of user definable constants
libqhull.c // Quickhull algorithm with partitioning
user.c // user re-definable functions
usermem.c
userprintf.c
userprintf_rbox.c
qhull_a.h // include files for libqhull/*.c
geom.c // geometric routines
geom2.c
geom.h
global.c // global variables
io.c // input-output routines
io.h
mem.c // memory routines, this is stand-alone code
mem.h
merge.c // merging of non-convex facets
merge.h
poly.c // polyhedron routines
poly2.c
poly.h
qset.c // set routines, this only depends on mem.c
qset.h
random.c // utilities w/ Park & Miller's random number generator
random.h
rboxlib.c // point set generator for rbox
stat.c // statistics
stat.h
src/libqhullp
libqhullp.pro // Qt project for shared library (qhull_p.dll)
qhull_p-exports.def // Export Definition file for Visual C++
src/libqhullstatic/
libqhullstatic.pro // Qt project for static library
src/libqhullstaticp/
libqhullstaticp.pro // Qt project for static library with qh_QHpointer
src/libqhullcpp/
libqhullcpp.pro // Qt project for static C++ library
Qhull.cpp // Call libqhull.c from C++
Qhull.h
qt-qhull.cpp // Supporting methods for Qt
qhull_interface.cpp // Another approach to C++
Coordinates.cpp // input classes
Coordinates.h
PointCoordinates.cpp
PointCoordinates.h
RboxPoints.cpp // call rboxlib.c from C++
RboxPoints.h
QhullFacet.cpp // data structure classes
QhullFacet.h
QhullHyperplane.cpp
QhullHyperplane.h
QhullPoint.cpp
QhullPoint.h
QhullQh.cpp
QhullStat.cpp
QhullStat.h
QhullVertex.cpp
QhullVertex.h
QhullFacetList.cpp // collection classes
QhullFacetList.h
QhullFacetSet.cpp
QhullFacetSet.h
QhullIterator.h
QhullLinkedList.h
QhullPoints.cpp
QhullPoints.h
QhullPointSet.cpp
QhullPointSet.h
QhullRidge.cpp
QhullRidge.h
QhullSet.cpp
QhullSet.h
QhullSets.h
QhullVertexSet.cpp
QhullVertexSet.h
functionObjects.h // supporting classes
QhullError.cpp
QhullError.h
QhullQh.cpp
QhullQh.h
UsingLibQhull.cpp
UsingLibQhull.h
src/qhulltest/
qhulltest.pro // Qt project for test of C++ interface
Coordinates_test.cpp // Test of each class
PointCoordinates_test.cpp
Point_test.cpp
QhullFacetList_test.cpp
QhullFacetSet_test.cpp
QhullFacet_test.cpp
QhullHyperplane_test.cpp
QhullLinkedList_test.cpp
QhullPointSet_test.cpp
QhullPoints_test.cpp
QhullPoint_test.cpp
QhullRidge_test.cpp
QhullSet_test.cpp
QhullVertexSet_test.cpp
QhullVertex_test.cpp
Qhull_test.cpp
RboxPoints_test.cpp
UsingLibQhull_test.cpp
src/road/
RoadError.cpp // Supporting base classes
RoadError.h
RoadLogEvent.cpp
RoadLogEvent.h
RoadTest.cpp // Run multiple test files with QTestLib
RoadTest.h
src/testqset/
testqset.pro // Qt project for test qset.c with mem.c
testqset.c
-----------------
Authors:
C. Bradford Barber Hannu Huhdanpaa (Version 1.0)
bradb@shore.net hannu@qhull.org
Qhull 1.0 and 2.0 were developed under NSF grants NSF/DMS-8920161
and NSF-CCR-91-15793 750-7504 at the Geometry Center and Harvard
University. If you find Qhull useful, please let us know.

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,176 @@
/*<html><pre> -<a href="qh-geom.htm"
>-------------------------------</a><a name="TOP">-</a>
geom.h
header file for geometric routines
see qh-geom.htm and geom.c
Copyright (c) 1993-2012 The Geometry Center.
$Id: //main/2011/qhull/src/libqhull/geom.h#3 $$Change: 1464 $
$DateTime: 2012/01/25 22:58:41 $$Author: bbarber $
*/
#ifndef qhDEFgeom
#define qhDEFgeom 1
#include "libqhull.h"
/* ============ -macros- ======================== */
/*-<a href="qh-geom.htm#TOC"
>--------------------------------</a><a name="fabs_">-</a>
fabs_(a)
returns the absolute value of a
*/
#define fabs_( a ) ((( a ) < 0 ) ? -( a ):( a ))
/*-<a href="qh-geom.htm#TOC"
>--------------------------------</a><a name="fmax_">-</a>
fmax_(a,b)
returns the maximum value of a and b
*/
#define fmax_( a,b ) ( ( a ) < ( b ) ? ( b ) : ( a ) )
/*-<a href="qh-geom.htm#TOC"
>--------------------------------</a><a name="fmin_">-</a>
fmin_(a,b)
returns the minimum value of a and b
*/
#define fmin_( a,b ) ( ( a ) > ( b ) ? ( b ) : ( a ) )
/*-<a href="qh-geom.htm#TOC"
>--------------------------------</a><a name="maximize_">-</a>
maximize_(maxval, val)
set maxval to val if val is greater than maxval
*/
#define maximize_( maxval, val ) { if (( maxval ) < ( val )) ( maxval )= ( val ); }
/*-<a href="qh-geom.htm#TOC"
>--------------------------------</a><a name="minimize_">-</a>
minimize_(minval, val)
set minval to val if val is less than minval
*/
#define minimize_( minval, val ) { if (( minval ) > ( val )) ( minval )= ( val ); }
/*-<a href="qh-geom.htm#TOC"
>--------------------------------</a><a name="det2_">-</a>
det2_(a1, a2,
b1, b2)
compute a 2-d determinate
*/
#define det2_( a1,a2,b1,b2 ) (( a1 )*( b2 ) - ( a2 )*( b1 ))
/*-<a href="qh-geom.htm#TOC"
>--------------------------------</a><a name="det3_">-</a>
det3_(a1, a2, a3,
b1, b2, b3,
c1, c2, c3)
compute a 3-d determinate
*/
#define det3_( a1,a2,a3,b1,b2,b3,c1,c2,c3 ) ( ( a1 )*det2_( b2,b3,c2,c3 ) \
- ( b1 )*det2_( a2,a3,c2,c3 ) + ( c1 )*det2_( a2,a3,b2,b3 ) )
/*-<a href="qh-geom.htm#TOC"
>--------------------------------</a><a name="dX">-</a>
dX( p1, p2 )
dY( p1, p2 )
dZ( p1, p2 )
given two indices into rows[],
compute the difference between X, Y, or Z coordinates
*/
#define dX( p1,p2 ) ( *( rows[p1] ) - *( rows[p2] ))
#define dY( p1,p2 ) ( *( rows[p1]+1 ) - *( rows[p2]+1 ))
#define dZ( p1,p2 ) ( *( rows[p1]+2 ) - *( rows[p2]+2 ))
#define dW( p1,p2 ) ( *( rows[p1]+3 ) - *( rows[p2]+3 ))
/*============= prototypes in alphabetical order, infrequent at end ======= */
void qh_backnormal(realT **rows, int numrow, int numcol, boolT sign, coordT *normal, boolT *nearzero);
void qh_distplane(pointT *point, facetT *facet, realT *dist);
facetT *qh_findbest(pointT *point, facetT *startfacet,
boolT bestoutside, boolT isnewfacets, boolT noupper,
realT *dist, boolT *isoutside, int *numpart);
facetT *qh_findbesthorizon(boolT ischeckmax, pointT *point,
facetT *startfacet, boolT noupper, realT *bestdist, int *numpart);
facetT *qh_findbestnew(pointT *point, facetT *startfacet, realT *dist,
boolT bestoutside, boolT *isoutside, int *numpart);
void qh_gausselim(realT **rows, int numrow, int numcol, boolT *sign, boolT *nearzero);
realT qh_getangle(pointT *vect1, pointT *vect2);
pointT *qh_getcenter(setT *vertices);
pointT *qh_getcentrum(facetT *facet);
realT qh_getdistance(facetT *facet, facetT *neighbor, realT *mindist, realT *maxdist);
void qh_normalize(coordT *normal, int dim, boolT toporient);
void qh_normalize2 (coordT *normal, int dim, boolT toporient,
realT *minnorm, boolT *ismin);
pointT *qh_projectpoint(pointT *point, facetT *facet, realT dist);
void qh_setfacetplane(facetT *newfacets);
void qh_sethyperplane_det(int dim, coordT **rows, coordT *point0,
boolT toporient, coordT *normal, realT *offset, boolT *nearzero);
void qh_sethyperplane_gauss(int dim, coordT **rows, pointT *point0,
boolT toporient, coordT *normal, coordT *offset, boolT *nearzero);
boolT qh_sharpnewfacets(void);
/*========= infrequently used code in geom2.c =============*/
coordT *qh_copypoints(coordT *points, int numpoints, int dimension);
void qh_crossproduct(int dim, realT vecA[3], realT vecB[3], realT vecC[3]);
realT qh_determinant(realT **rows, int dim, boolT *nearzero);
realT qh_detjoggle(pointT *points, int numpoints, int dimension);
void qh_detroundoff(void);
realT qh_detsimplex(pointT *apex, setT *points, int dim, boolT *nearzero);
realT qh_distnorm(int dim, pointT *point, pointT *normal, realT *offsetp);
realT qh_distround(int dimension, realT maxabs, realT maxsumabs);
realT qh_divzero(realT numer, realT denom, realT mindenom1, boolT *zerodiv);
realT qh_facetarea(facetT *facet);
realT qh_facetarea_simplex(int dim, coordT *apex, setT *vertices,
vertexT *notvertex, boolT toporient, coordT *normal, realT *offset);
pointT *qh_facetcenter(setT *vertices);
facetT *qh_findgooddist(pointT *point, facetT *facetA, realT *distp, facetT **facetlist);
void qh_getarea(facetT *facetlist);
boolT qh_gram_schmidt(int dim, realT **rows);
boolT qh_inthresholds(coordT *normal, realT *angle);
void qh_joggleinput(void);
realT *qh_maxabsval(realT *normal, int dim);
setT *qh_maxmin(pointT *points, int numpoints, int dimension);
realT qh_maxouter(void);
void qh_maxsimplex(int dim, setT *maxpoints, pointT *points, int numpoints, setT **simplex);
realT qh_minabsval(realT *normal, int dim);
int qh_mindiff(realT *vecA, realT *vecB, int dim);
boolT qh_orientoutside(facetT *facet);
void qh_outerinner(facetT *facet, realT *outerplane, realT *innerplane);
coordT qh_pointdist(pointT *point1, pointT *point2, int dim);
void qh_printmatrix(FILE *fp, const char *string, realT **rows, int numrow, int numcol);
void qh_printpoints(FILE *fp, const char *string, setT *points);
void qh_projectinput(void);
void qh_projectpoints(signed char *project, int n, realT *points,
int numpoints, int dim, realT *newpoints, int newdim);
void qh_rotateinput(realT **rows);
void qh_rotatepoints(realT *points, int numpoints, int dim, realT **rows);
void qh_scaleinput(void);
void qh_scalelast(coordT *points, int numpoints, int dim, coordT low,
coordT high, coordT newhigh);
void qh_scalepoints(pointT *points, int numpoints, int dim,
realT *newlows, realT *newhighs);
boolT qh_sethalfspace(int dim, coordT *coords, coordT **nextp,
coordT *normal, coordT *offset, coordT *feasible);
coordT *qh_sethalfspace_all(int dim, int count, coordT *halfspaces, pointT *feasible);
pointT *qh_voronoi_center(int dim, setT *points);
#endif /* qhDEFgeom */

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,159 @@
/*<html><pre> -<a href="qh-io.htm"
>-------------------------------</a><a name="TOP">-</a>
io.h
declarations of Input/Output functions
see README, libqhull.h and io.c
Copyright (c) 1993-2012 The Geometry Center.
$Id: //main/2011/qhull/src/libqhull/io.h#3 $$Change: 1464 $
$DateTime: 2012/01/25 22:58:41 $$Author: bbarber $
*/
#ifndef qhDEFio
#define qhDEFio 1
#include "libqhull.h"
/*============ constants and flags ==================*/
/*-<a href="qh-io.htm#TOC"
>--------------------------------</a><a name="qh_MAXfirst">-</a>
qh_MAXfirst
maximum length of first two lines of stdin
*/
#define qh_MAXfirst 200
/*-<a href="qh-io.htm#TOC"
>--------------------------------</a><a name="qh_MINradius">-</a>
qh_MINradius
min radius for Gp and Gv, fraction of maxcoord
*/
#define qh_MINradius 0.02
/*-<a href="qh-io.htm#TOC"
>--------------------------------</a><a name="qh_GEOMepsilon">-</a>
qh_GEOMepsilon
adjust outer planes for 'lines closer' and geomview roundoff.
This prevents bleed through.
*/
#define qh_GEOMepsilon 2e-3
/*-<a href="qh-io.htm#TOC"
>--------------------------------</a><a name="qh_WHITESPACE">-</a>
qh_WHITESPACE
possible values of white space
*/
#define qh_WHITESPACE " \n\t\v\r\f"
/*-<a href="qh-io.htm#TOC"
>--------------------------------</a><a name="RIDGE">-</a>
qh_RIDGE
to select which ridges to print in qh_eachvoronoi
*/
typedef enum
{
qh_RIDGEall = 0, qh_RIDGEinner, qh_RIDGEouter
}
qh_RIDGE;
/*-<a href="qh-io.htm#TOC"
>--------------------------------</a><a name="printvridgeT">-</a>
printvridgeT
prints results of qh_printvdiagram
see:
<a href="io.c#printvridge">qh_printvridge</a> for an example
*/
typedef void (*printvridgeT)(FILE *fp, vertexT *vertex, vertexT *vertexA, setT *centers, boolT unbounded);
/*============== -prototypes in alphabetical order =========*/
void dfacet(unsigned id);
void dvertex(unsigned id);
int qh_compare_facetarea(const void *p1, const void *p2);
int qh_compare_facetmerge(const void *p1, const void *p2);
int qh_compare_facetvisit(const void *p1, const void *p2);
int qh_compare_vertexpoint(const void *p1, const void *p2); /* not used */
void qh_copyfilename(char *filename, int size, const char* source, int length);
void qh_countfacets(facetT *facetlist, setT *facets, boolT printall,
int *numfacetsp, int *numsimplicialp, int *totneighborsp,
int *numridgesp, int *numcoplanarsp, int *numnumtricoplanarsp);
pointT *qh_detvnorm(vertexT *vertex, vertexT *vertexA, setT *centers, realT *offsetp);
setT *qh_detvridge(vertexT *vertex);
setT *qh_detvridge3 (vertexT *atvertex, vertexT *vertex);
int qh_eachvoronoi(FILE *fp, printvridgeT printvridge, vertexT *atvertex, boolT visitall, qh_RIDGE innerouter, boolT inorder);
int qh_eachvoronoi_all(FILE *fp, printvridgeT printvridge, boolT isUpper, qh_RIDGE innerouter, boolT inorder);
void qh_facet2point(facetT *facet, pointT **point0, pointT **point1, realT *mindist);
setT *qh_facetvertices(facetT *facetlist, setT *facets, boolT allfacets);
void qh_geomplanes(facetT *facet, realT *outerplane, realT *innerplane);
void qh_markkeep(facetT *facetlist);
setT *qh_markvoronoi(facetT *facetlist, setT *facets, boolT printall, boolT *isLowerp, int *numcentersp);
void qh_order_vertexneighbors(vertexT *vertex);
void qh_prepare_output(void);
void qh_printafacet(FILE *fp, qh_PRINT format, facetT *facet, boolT printall);
void qh_printbegin(FILE *fp, qh_PRINT format, facetT *facetlist, setT *facets, boolT printall);
void qh_printcenter(FILE *fp, qh_PRINT format, const char *string, facetT *facet);
void qh_printcentrum(FILE *fp, facetT *facet, realT radius);
void qh_printend(FILE *fp, qh_PRINT format, facetT *facetlist, setT *facets, boolT printall);
void qh_printend4geom(FILE *fp, facetT *facet, int *num, boolT printall);
void qh_printextremes(FILE *fp, facetT *facetlist, setT *facets, boolT printall);
void qh_printextremes_2d(FILE *fp, facetT *facetlist, setT *facets, boolT printall);
void qh_printextremes_d(FILE *fp, facetT *facetlist, setT *facets, boolT printall);
void qh_printfacet(FILE *fp, facetT *facet);
void qh_printfacet2math(FILE *fp, facetT *facet, qh_PRINT format, int notfirst);
void qh_printfacet2geom(FILE *fp, facetT *facet, realT color[3]);
void qh_printfacet2geom_points(FILE *fp, pointT *point1, pointT *point2,
facetT *facet, realT offset, realT color[3]);
void qh_printfacet3math(FILE *fp, facetT *facet, qh_PRINT format, int notfirst);
void qh_printfacet3geom_nonsimplicial(FILE *fp, facetT *facet, realT color[3]);
void qh_printfacet3geom_points(FILE *fp, setT *points, facetT *facet, realT offset, realT color[3]);
void qh_printfacet3geom_simplicial(FILE *fp, facetT *facet, realT color[3]);
void qh_printfacet3vertex(FILE *fp, facetT *facet, qh_PRINT format);
void qh_printfacet4geom_nonsimplicial(FILE *fp, facetT *facet, realT color[3]);
void qh_printfacet4geom_simplicial(FILE *fp, facetT *facet, realT color[3]);
void qh_printfacetNvertex_nonsimplicial(FILE *fp, facetT *facet, int id, qh_PRINT format);
void qh_printfacetNvertex_simplicial(FILE *fp, facetT *facet, qh_PRINT format);
void qh_printfacetheader(FILE *fp, facetT *facet);
void qh_printfacetridges(FILE *fp, facetT *facet);
void qh_printfacets(FILE *fp, qh_PRINT format, facetT *facetlist, setT *facets, boolT printall);
void qh_printhyperplaneintersection(FILE *fp, facetT *facet1, facetT *facet2,
setT *vertices, realT color[3]);
void qh_printneighborhood(FILE *fp, qh_PRINT format, facetT *facetA, facetT *facetB, boolT printall);
void qh_printline3geom(FILE *fp, pointT *pointA, pointT *pointB, realT color[3]);
void qh_printpoint(FILE *fp, const char *string, pointT *point);
void qh_printpointid(FILE *fp, const char *string, int dim, pointT *point, int id);
void qh_printpoint3 (FILE *fp, pointT *point);
void qh_printpoints_out(FILE *fp, facetT *facetlist, setT *facets, boolT printall);
void qh_printpointvect(FILE *fp, pointT *point, coordT *normal, pointT *center, realT radius, realT color[3]);
void qh_printpointvect2 (FILE *fp, pointT *point, coordT *normal, pointT *center, realT radius);
void qh_printridge(FILE *fp, ridgeT *ridge);
void qh_printspheres(FILE *fp, setT *vertices, realT radius);
void qh_printvdiagram(FILE *fp, qh_PRINT format, facetT *facetlist, setT *facets, boolT printall);
int qh_printvdiagram2 (FILE *fp, printvridgeT printvridge, setT *vertices, qh_RIDGE innerouter, boolT inorder);
void qh_printvertex(FILE *fp, vertexT *vertex);
void qh_printvertexlist(FILE *fp, const char* string, facetT *facetlist,
setT *facets, boolT printall);
void qh_printvertices(FILE *fp, const char* string, setT *vertices);
void qh_printvneighbors(FILE *fp, facetT* facetlist, setT *facets, boolT printall);
void qh_printvoronoi(FILE *fp, qh_PRINT format, facetT *facetlist, setT *facets, boolT printall);
void qh_printvnorm(FILE *fp, vertexT *vertex, vertexT *vertexA, setT *centers, boolT unbounded);
void qh_printvridge(FILE *fp, vertexT *vertex, vertexT *vertexA, setT *centers, boolT unbounded);
void qh_produce_output(void);
void qh_produce_output2(void);
void qh_projectdim3 (pointT *source, pointT *destination);
int qh_readfeasible(int dim, const char *curline);
coordT *qh_readpoints(int *numpoints, int *dimension, boolT *ismalloc);
void qh_setfeasible(int dim);
boolT qh_skipfacet(facetT *facet);
char *qh_skipfilename(char *filename);
#endif /* qhDEFio */

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,545 @@
/*<html><pre> -<a href="qh-mem.htm"
>-------------------------------</a><a name="TOP">-</a>
mem.c
memory management routines for qhull
This is a standalone program.
To initialize memory:
qh_meminit(stderr);
qh_meminitbuffers(qh IStracing, qh_MEMalign, 7, qh_MEMbufsize,qh_MEMinitbuf);
qh_memsize((int)sizeof(facetT));
qh_memsize((int)sizeof(facetT));
...
qh_memsetup();
To free up all memory buffers:
qh_memfreeshort(&curlong, &totlong);
if qh_NOmem,
malloc/free is used instead of mem.c
notes:
uses Quickfit algorithm (freelists for commonly allocated sizes)
assumes small sizes for freelists (it discards the tail of memory buffers)
see:
qh-mem.htm and mem.h
global.c (qh_initbuffers) for an example of using mem.c
Copyright (c) 1993-2012 The Geometry Center.
$Id: //main/2011/qhull/src/libqhull/mem.c#4 $$Change: 1464 $
$DateTime: 2012/01/25 22:58:41 $$Author: bbarber $
*/
#include "mem.h"
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#ifndef qhDEFlibqhull
typedef struct ridgeT ridgeT;
typedef struct facetT facetT;
#ifdef _MSC_VER /* Microsoft Visual C++ -- warning level 4 */
#pragma warning( disable : 4127) /* conditional expression is constant */
#pragma warning( disable : 4706) /* assignment within conditional function */
#endif
void qh_errexit(int exitcode, facetT *, ridgeT *);
void qh_exit(int exitcode);
void qh_fprintf(FILE *fp, int msgcode, const char *fmt, ... );
void qh_free(void *mem);
void *qh_malloc(size_t size);
#endif
/*============ -global data structure ==============
see mem.h for definition
*/
qhmemT qhmem= {0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0}; /* remove "= {0}" if this causes a compiler error */
#ifndef qh_NOmem
/*============= internal functions ==============*/
static int qh_intcompare(const void *i, const void *j);
/*========== functions in alphabetical order ======== */
/*-<a href="qh-mem.htm#TOC"
>-------------------------------</a><a name="intcompare">-</a>
qh_intcompare( i, j )
used by qsort and bsearch to compare two integers
*/
static int qh_intcompare(const void *i, const void *j) {
return(*((const int *)i) - *((const int *)j));
} /* intcompare */
/*-<a href="qh-mem.htm#TOC"
>--------------------------------</a><a name="memalloc">-</a>
qh_memalloc( insize )
returns object of insize bytes
qhmem is the global memory structure
returns:
pointer to allocated memory
errors if insufficient memory
notes:
use explicit type conversion to avoid type warnings on some compilers
actual object may be larger than insize
use qh_memalloc_() for inline code for quick allocations
logs allocations if 'T5'
design:
if size < qhmem.LASTsize
if qhmem.freelists[size] non-empty
return first object on freelist
else
round up request to size of qhmem.freelists[size]
allocate new allocation buffer if necessary
allocate object from allocation buffer
else
allocate object with qh_malloc() in user.c
*/
void *qh_memalloc(int insize) {
void **freelistp, *newbuffer;
int idx, size, n;
int outsize, bufsize;
void *object;
if (insize<0) {
qh_fprintf(qhmem.ferr, 6235, "qhull error (qh_memalloc): negative request size (%d). Did int overflow due to high-D?\n", insize); /* WARN64 */
qh_errexit(qhmem_ERRmem, NULL, NULL);
}
if (insize>=0 && insize <= qhmem.LASTsize) {
idx= qhmem.indextable[insize];
outsize= qhmem.sizetable[idx];
qhmem.totshort += outsize;
freelistp= qhmem.freelists+idx;
if ((object= *freelistp)) {
qhmem.cntquick++;
qhmem.totfree -= outsize;
*freelistp= *((void **)*freelistp); /* replace freelist with next object */
#ifdef qh_TRACEshort
n= qhmem.cntshort+qhmem.cntquick+qhmem.freeshort;
if (qhmem.IStracing >= 5)
qh_fprintf(qhmem.ferr, 8141, "qh_mem %p n %8d alloc quick: %d bytes (tot %d cnt %d)\n", object, n, outsize, qhmem.totshort, qhmem.cntshort+qhmem.cntquick-qhmem.freeshort);
#endif
return(object);
}else {
qhmem.cntshort++;
if (outsize > qhmem .freesize) {
qhmem .totdropped += qhmem .freesize;
if (!qhmem.curbuffer)
bufsize= qhmem.BUFinit;
else
bufsize= qhmem.BUFsize;
if (!(newbuffer= qh_malloc((size_t)bufsize))) {
qh_fprintf(qhmem.ferr, 6080, "qhull error (qh_memalloc): insufficient memory to allocate short memory buffer (%d bytes)\n", bufsize);
qh_errexit(qhmem_ERRmem, NULL, NULL);
}
/* newbuffer cannot be NULL since above qh_errexit didn't return */
/* coverity[var_deref_op] */
*((void **)newbuffer)= qhmem.curbuffer; /* prepend newbuffer to curbuffer
list */
qhmem.curbuffer= newbuffer;
size= (sizeof(void **) + qhmem.ALIGNmask) & ~qhmem.ALIGNmask;
qhmem.freemem= (void *)((char *)newbuffer+size);
qhmem.freesize= bufsize - size;
qhmem.totbuffer += bufsize - size; /* easier to check */
/* Periodically test totbuffer. It matches at beginning and exit of every call */
n = qhmem.totshort + qhmem.totfree + qhmem.totdropped + qhmem.freesize - outsize;
if (qhmem.totbuffer != n) {
qh_fprintf(qhmem.ferr, 6212, "qh_memalloc internal error: short totbuffer %d != totshort+totfree... %d\n", qhmem.totbuffer, n);
qh_errexit(qhmem_ERRmem, NULL, NULL);
}
}
object= qhmem.freemem;
qhmem.freemem= (void *)((char *)qhmem.freemem + outsize);
qhmem.freesize -= outsize;
qhmem.totunused += outsize - insize;
#ifdef qh_TRACEshort
n= qhmem.cntshort+qhmem.cntquick+qhmem.freeshort;
if (qhmem.IStracing >= 5)
qh_fprintf(qhmem.ferr, 8140, "qh_mem %p n %8d alloc short: %d bytes (tot %d cnt %d)\n", object, n, outsize, qhmem.totshort, qhmem.cntshort+qhmem.cntquick-qhmem.freeshort);
#endif
return object;
}
}else { /* long allocation */
if (!qhmem.indextable) {
qh_fprintf(qhmem.ferr, 6081, "qhull internal error (qh_memalloc): qhmem has not been initialized.\n");
qh_errexit(qhmem_ERRqhull, NULL, NULL);
}
outsize= insize;
qhmem .cntlong++;
qhmem .totlong += outsize;
if (qhmem.maxlong < qhmem.totlong)
qhmem.maxlong= qhmem.totlong;
if (!(object= qh_malloc((size_t)outsize))) {
qh_fprintf(qhmem.ferr, 6082, "qhull error (qh_memalloc): insufficient memory to allocate %d bytes\n", outsize);
qh_errexit(qhmem_ERRmem, NULL, NULL);
}
if (qhmem.IStracing >= 5)
qh_fprintf(qhmem.ferr, 8057, "qh_mem %p n %8d alloc long: %d bytes (tot %d cnt %d)\n", object, qhmem.cntlong+qhmem.freelong, outsize, qhmem.totlong, qhmem.cntlong-qhmem.freelong);
}
return(object);
} /* memalloc */
/*-<a href="qh-mem.htm#TOC"
>--------------------------------</a><a name="memfree">-</a>
qh_memfree( object, insize )
free up an object of size bytes
size is insize from qh_memalloc
notes:
object may be NULL
type checking warns if using (void **)object
use qh_memfree_() for quick free's of small objects
design:
if size <= qhmem.LASTsize
append object to corresponding freelist
else
call qh_free(object)
*/
void qh_memfree(void *object, int insize) {
void **freelistp;
int idx, outsize;
if (!object)
return;
if (insize <= qhmem.LASTsize) {
qhmem .freeshort++;
idx= qhmem.indextable[insize];
outsize= qhmem.sizetable[idx];
qhmem .totfree += outsize;
qhmem .totshort -= outsize;
freelistp= qhmem.freelists + idx;
*((void **)object)= *freelistp;
*freelistp= object;
#ifdef qh_TRACEshort
idx= qhmem.cntshort+qhmem.cntquick+qhmem.freeshort;
if (qhmem.IStracing >= 5)
qh_fprintf(qhmem.ferr, 8142, "qh_mem %p n %8d free short: %d bytes (tot %d cnt %d)\n", object, idx, outsize, qhmem.totshort, qhmem.cntshort+qhmem.cntquick-qhmem.freeshort);
#endif
}else {
qhmem .freelong++;
qhmem .totlong -= insize;
if (qhmem.IStracing >= 5)
qh_fprintf(qhmem.ferr, 8058, "qh_mem %p n %8d free long: %d bytes (tot %d cnt %d)\n", object, qhmem.cntlong+qhmem.freelong, insize, qhmem.totlong, qhmem.cntlong-qhmem.freelong);
qh_free(object);
}
} /* memfree */
/*-<a href="qh-mem.htm#TOC"
>-------------------------------</a><a name="memfreeshort">-</a>
qh_memfreeshort( curlong, totlong )
frees up all short and qhmem memory allocations
returns:
number and size of current long allocations
see:
qh_freeqhull(allMem)
qh_memtotal(curlong, totlong, curshort, totshort, maxlong, totbuffer);
*/
void qh_memfreeshort(int *curlong, int *totlong) {
void *buffer, *nextbuffer;
FILE *ferr;
*curlong= qhmem .cntlong - qhmem .freelong;
*totlong= qhmem .totlong;
for (buffer= qhmem.curbuffer; buffer; buffer= nextbuffer) {
nextbuffer= *((void **) buffer);
qh_free(buffer);
}
qhmem.curbuffer= NULL;
if (qhmem .LASTsize) {
qh_free(qhmem .indextable);
qh_free(qhmem .freelists);
qh_free(qhmem .sizetable);
}
ferr= qhmem.ferr;
memset((char *)&qhmem, 0, sizeof(qhmem)); /* every field is 0, FALSE, NULL */
qhmem.ferr= ferr;
} /* memfreeshort */
/*-<a href="qh-mem.htm#TOC"
>--------------------------------</a><a name="meminit">-</a>
qh_meminit( ferr )
initialize qhmem and test sizeof( void*)
*/
void qh_meminit(FILE *ferr) {
memset((char *)&qhmem, 0, sizeof(qhmem)); /* every field is 0, FALSE, NULL */
qhmem.ferr= ferr;
if (sizeof(void*) < sizeof(int)) {
qh_fprintf(ferr, 6083, "qhull internal error (qh_meminit): sizeof(void*) %d < sizeof(int) %d. qset.c will not work\n", (int)sizeof(void*), (int)sizeof(int));
qh_exit(qhmem_ERRqhull); /* can not use qh_errexit() */
}
if (sizeof(void*) > sizeof(ptr_intT)) {
qh_fprintf(ferr, 6084, "qhull internal error (qh_meminit): sizeof(void*) %d > sizeof(ptr_intT) %d. Change ptr_intT in mem.h to 'long long'\n", (int)sizeof(void*), (int)sizeof(ptr_intT));
qh_exit(qhmem_ERRqhull); /* can not use qh_errexit() */
}
} /* meminit */
/*-<a href="qh-mem.htm#TOC"
>-------------------------------</a><a name="meminitbuffers">-</a>
qh_meminitbuffers( tracelevel, alignment, numsizes, bufsize, bufinit )
initialize qhmem
if tracelevel >= 5, trace memory allocations
alignment= desired address alignment for memory allocations
numsizes= number of freelists
bufsize= size of additional memory buffers for short allocations
bufinit= size of initial memory buffer for short allocations
*/
void qh_meminitbuffers(int tracelevel, int alignment, int numsizes, int bufsize, int bufinit) {
qhmem.IStracing= tracelevel;
qhmem.NUMsizes= numsizes;
qhmem.BUFsize= bufsize;
qhmem.BUFinit= bufinit;
qhmem.ALIGNmask= alignment-1;
if (qhmem.ALIGNmask & ~qhmem.ALIGNmask) {
qh_fprintf(qhmem.ferr, 6085, "qhull internal error (qh_meminit): memory alignment %d is not a power of 2\n", alignment);
qh_errexit(qhmem_ERRqhull, NULL, NULL);
}
qhmem.sizetable= (int *) calloc((size_t)numsizes, sizeof(int));
qhmem.freelists= (void **) calloc((size_t)numsizes, sizeof(void *));
if (!qhmem.sizetable || !qhmem.freelists) {
qh_fprintf(qhmem.ferr, 6086, "qhull error (qh_meminit): insufficient memory\n");
qh_errexit(qhmem_ERRmem, NULL, NULL);
}
if (qhmem.IStracing >= 1)
qh_fprintf(qhmem.ferr, 8059, "qh_meminitbuffers: memory initialized with alignment %d\n", alignment);
} /* meminitbuffers */
/*-<a href="qh-mem.htm#TOC"
>-------------------------------</a><a name="memsetup">-</a>
qh_memsetup()
set up memory after running memsize()
*/
void qh_memsetup(void) {
int k,i;
qsort(qhmem.sizetable, (size_t)qhmem.TABLEsize, sizeof(int), qh_intcompare);
qhmem.LASTsize= qhmem.sizetable[qhmem.TABLEsize-1];
if (qhmem .LASTsize >= qhmem .BUFsize || qhmem.LASTsize >= qhmem .BUFinit) {
qh_fprintf(qhmem.ferr, 6087, "qhull error (qh_memsetup): largest mem size %d is >= buffer size %d or initial buffer size %d\n",
qhmem .LASTsize, qhmem .BUFsize, qhmem .BUFinit);
qh_errexit(qhmem_ERRmem, NULL, NULL);
}
if (!(qhmem.indextable= (int *)qh_malloc((qhmem.LASTsize+1) * sizeof(int)))) {
qh_fprintf(qhmem.ferr, 6088, "qhull error (qh_memsetup): insufficient memory\n");
qh_errexit(qhmem_ERRmem, NULL, NULL);
}
for (k=qhmem.LASTsize+1; k--; )
qhmem.indextable[k]= k;
i= 0;
for (k=0; k <= qhmem.LASTsize; k++) {
if (qhmem.indextable[k] <= qhmem.sizetable[i])
qhmem.indextable[k]= i;
else
qhmem.indextable[k]= ++i;
}
} /* memsetup */
/*-<a href="qh-mem.htm#TOC"
>-------------------------------</a><a name="memsize">-</a>
qh_memsize( size )
define a free list for this size
*/
void qh_memsize(int size) {
int k;
if (qhmem .LASTsize) {
qh_fprintf(qhmem.ferr, 6089, "qhull error (qh_memsize): called after qhmem_setup\n");
qh_errexit(qhmem_ERRqhull, NULL, NULL);
}
size= (size + qhmem.ALIGNmask) & ~qhmem.ALIGNmask;
for (k=qhmem.TABLEsize; k--; ) {
if (qhmem.sizetable[k] == size)
return;
}
if (qhmem.TABLEsize < qhmem.NUMsizes)
qhmem.sizetable[qhmem.TABLEsize++]= size;
else
qh_fprintf(qhmem.ferr, 7060, "qhull warning (memsize): free list table has room for only %d sizes\n", qhmem.NUMsizes);
} /* memsize */
/*-<a href="qh-mem.htm#TOC"
>-------------------------------</a><a name="memstatistics">-</a>
qh_memstatistics( fp )
print out memory statistics
Verifies that qhmem.totfree == sum of freelists
*/
void qh_memstatistics(FILE *fp) {
int i, count, totfree= 0;
void *object;
for (i=0; i < qhmem.TABLEsize; i++) {
count=0;
for (object= qhmem .freelists[i]; object; object= *((void **)object))
count++;
totfree += qhmem.sizetable[i] * count;
}
if (totfree != qhmem .totfree) {
qh_fprintf(qhmem.ferr, 6211, "qh_memstatistics internal error: totfree %d not equal to freelist total %d\n", qhmem.totfree, totfree);
qh_errexit(qhmem_ERRqhull, NULL, NULL);
}
qh_fprintf(fp, 9278, "\nmemory statistics:\n\
%7d quick allocations\n\
%7d short allocations\n\
%7d long allocations\n\
%7d short frees\n\
%7d long frees\n\
%7d bytes of short memory in use\n\
%7d bytes of short memory in freelists\n\
%7d bytes of dropped short memory\n\
%7d bytes of unused short memory (estimated)\n\
%7d bytes of long memory allocated (max, except for input)\n\
%7d bytes of long memory in use (in %d pieces)\n\
%7d bytes of short memory buffers (minus links)\n\
%7d bytes per short memory buffer (initially %d bytes)\n",
qhmem .cntquick, qhmem .cntshort, qhmem .cntlong,
qhmem .freeshort, qhmem .freelong,
qhmem .totshort, qhmem .totfree,
qhmem .totdropped + qhmem .freesize, qhmem .totunused,
qhmem .maxlong, qhmem .totlong, qhmem .cntlong - qhmem .freelong,
qhmem .totbuffer, qhmem .BUFsize, qhmem .BUFinit);
if (qhmem.cntlarger) {
qh_fprintf(fp, 9279, "%7d calls to qh_setlarger\n%7.2g average copy size\n",
qhmem.cntlarger, ((float)qhmem.totlarger)/(float)qhmem.cntlarger);
qh_fprintf(fp, 9280, " freelists(bytes->count):");
}
for (i=0; i < qhmem.TABLEsize; i++) {
count=0;
for (object= qhmem .freelists[i]; object; object= *((void **)object))
count++;
qh_fprintf(fp, 9281, " %d->%d", qhmem.sizetable[i], count);
}
qh_fprintf(fp, 9282, "\n\n");
} /* memstatistics */
/*-<a href="qh-mem.htm#TOC"
>-------------------------------</a><a name="NOmem">-</a>
qh_NOmem
turn off quick-fit memory allocation
notes:
uses qh_malloc() and qh_free() instead
*/
#else /* qh_NOmem */
void *qh_memalloc(int insize) {
void *object;
if (!(object= qh_malloc((size_t)insize))) {
qh_fprintf(qhmem.ferr, 6090, "qhull error (qh_memalloc): insufficient memory\n");
qh_errexit(qhmem_ERRmem, NULL, NULL);
}
qhmem .cntlong++;
qhmem .totlong += insize;
if (qhmem.maxlong < qhmem.totlong)
qhmem.maxlong= qhmem.totlong;
if (qhmem.IStracing >= 5)
qh_fprintf(qhmem.ferr, 8060, "qh_mem %p n %8d alloc long: %d bytes (tot %d cnt %d)\n", object, qhmem.cntlong+qhmem.freelong, insize, qhmem.totlong, qhmem.cntlong-qhmem.freelong);
return object;
}
void qh_memfree(void *object, int insize) {
if (!object)
return;
qh_free(object);
qhmem .freelong++;
qhmem .totlong -= insize;
if (qhmem.IStracing >= 5)
qh_fprintf(qhmem.ferr, 8061, "qh_mem %p n %8d free long: %d bytes (tot %d cnt %d)\n", object, qhmem.cntlong+qhmem.freelong, insize, qhmem.totlong, qhmem.cntlong-qhmem.freelong);
}
void qh_memfreeshort(int *curlong, int *totlong) {
*totlong= qhmem .totlong;
*curlong= qhmem .cntlong - qhmem .freelong;
memset((char *)&qhmem, 0, sizeof(qhmem)); /* every field is 0, FALSE, NULL */
}
void qh_meminit(FILE *ferr) {
memset((char *)&qhmem, 0, sizeof(qhmem)); /* every field is 0, FALSE, NULL */
qhmem.ferr= ferr;
if (sizeof(void*) < sizeof(int)) {
qh_fprintf(ferr, 6091, "qhull internal error (qh_meminit): sizeof(void*) %d < sizeof(int) %d. qset.c will not work\n", (int)sizeof(void*), (int)sizeof(int));
qh_errexit(qhmem_ERRqhull, NULL, NULL);
}
}
void qh_meminitbuffers(int tracelevel, int alignment, int numsizes, int bufsize, int bufinit) {
qhmem.IStracing= tracelevel;
}
void qh_memsetup(void) {
}
void qh_memsize(int size) {
}
void qh_memstatistics(FILE *fp) {
qh_fprintf(fp, 9409, "\nmemory statistics:\n\
%7d long allocations\n\
%7d long frees\n\
%7d bytes of long memory allocated (max, except for input)\n\
%7d bytes of long memory in use (in %d pieces)\n",
qhmem .cntlong,
qhmem .freelong,
qhmem .maxlong, qhmem .totlong, qhmem .cntlong - qhmem .freelong);
}
#endif /* qh_NOmem */
/*-<a href="qh-mem.htm#TOC"
>-------------------------------</a><a name="memtotlong">-</a>
qh_memtotal( totlong, curlong, totshort, curshort, maxlong, totbuffer )
Return the total, allocated long and short memory
returns:
Returns the total current bytes of long and short allocations
Returns the current count of long and short allocations
Returns the maximum long memory and total short buffer (minus one link per buffer)
Does not error (UsingLibQhull.cpp)
*/
void qh_memtotal(int *totlong, int *curlong, int *totshort, int *curshort, int *maxlong, int *totbuffer) {
*totlong= qhmem .totlong;
*curlong= qhmem .cntlong - qhmem .freelong;
*totshort= qhmem .totshort;
*curshort= qhmem .cntshort + qhmem .cntquick - qhmem .freeshort;
*maxlong= qhmem .maxlong;
*totbuffer= qhmem .totbuffer;
} /* memtotlong */

View File

@@ -0,0 +1,219 @@
/*<html><pre> -<a href="qh-mem.htm"
>-------------------------------</a><a name="TOP">-</a>
mem.h
prototypes for memory management functions
see qh-mem.htm, mem.c and qset.h
for error handling, writes message and calls
qh_errexit(qhmem_ERRmem, NULL, NULL) if insufficient memory
and
qh_errexit(qhmem_ERRqhull, NULL, NULL) otherwise
Copyright (c) 1993-2012 The Geometry Center.
$Id: //main/2011/qhull/src/libqhull/mem.h#4 $$Change: 1464 $
$DateTime: 2012/01/25 22:58:41 $$Author: bbarber $
*/
#ifndef qhDEFmem
#define qhDEFmem 1
#include <stdio.h>
/*-<a href="qh-mem.htm#TOC"
>-------------------------------</a><a name="NOmem">-</a>
qh_NOmem
turn off quick-fit memory allocation
notes:
mem.c implements Quickfit memory allocation for about 20% time
savings. If it fails on your machine, try to locate the
problem, and send the answer to qhull@qhull.org. If this can
not be done, define qh_NOmem to use malloc/free instead.
#define qh_NOmem
*/
/*-<a href="qh-mem.htm#TOC"
>-------------------------------</a><a name="TRACEshort">-</a>
qh_TRACEshort
Trace short and quick memory allocations at T5
*/
#define qh_TRACEshort
/*-------------------------------------------
to avoid bus errors, memory allocation must consider alignment requirements.
malloc() automatically takes care of alignment. Since mem.c manages
its own memory, we need to explicitly specify alignment in
qh_meminitbuffers().
A safe choice is sizeof(double). sizeof(float) may be used if doubles
do not occur in data structures and pointers are the same size. Be careful
of machines (e.g., DEC Alpha) with large pointers. If gcc is available,
use __alignof__(double) or fmax_(__alignof__(float), __alignof__(void *)).
see <a href="user.h#MEMalign">qh_MEMalign</a> in user.h for qhull's alignment
*/
#define qhmem_ERRmem 4 /* matches qh_ERRmem in libqhull.h */
#define qhmem_ERRqhull 5 /* matches qh_ERRqhull in libqhull.h */
/*-<a href="qh-mem.htm#TOC"
>--------------------------------</a><a name="ptr_intT">-</a>
ptr_intT
for casting a void * to an integer-type that holds a pointer
Used for integer expressions (e.g., computing qh_gethash() in poly.c)
notes:
WARN64 -- these notes indicate 64-bit issues
On 64-bit machines, a pointer may be larger than an 'int'.
qh_meminit()/mem.c checks that 'ptr_intT' holds a 'void*'
ptr_intT is typically a signed value, but not necessarily so
size_t is typically unsigned, but should match the parameter type
Qhull uses int instead of size_t except for system calls such as malloc, qsort, qh_malloc, etc.
This matches Qt convention and is easier to work with.
*/
#if _MSC_VER && defined(_WIN64)
typedef long long ptr_intT;
#else
typedef long ptr_intT;
#endif
/*-<a href="qh-mem.htm#TOC"
>--------------------------------</a><a name="qhmemT">-</a>
qhmemT
global memory structure for mem.c
notes:
users should ignore qhmem except for writing extensions
qhmem is allocated in mem.c
qhmem could be swapable like qh and qhstat, but then
multiple qh's and qhmem's would need to keep in sync.
A swapable qhmem would also waste memory buffers. As long
as memory operations are atomic, there is no problem with
multiple qh structures being active at the same time.
If you need separate address spaces, you can swap the
contents of qhmem.
*/
typedef struct qhmemT qhmemT;
extern qhmemT qhmem;
#ifndef DEFsetT
#define DEFsetT 1
typedef struct setT setT; /* defined in qset.h */
#endif
/* Update qhmem in mem.c if add or remove fields */
struct qhmemT { /* global memory management variables */
int BUFsize; /* size of memory allocation buffer */
int BUFinit; /* initial size of memory allocation buffer */
int TABLEsize; /* actual number of sizes in free list table */
int NUMsizes; /* maximum number of sizes in free list table */
int LASTsize; /* last size in free list table */
int ALIGNmask; /* worst-case alignment, must be 2^n-1 */
void **freelists; /* free list table, linked by offset 0 */
int *sizetable; /* size of each freelist */
int *indextable; /* size->index table */
void *curbuffer; /* current buffer, linked by offset 0 */
void *freemem; /* free memory in curbuffer */
int freesize; /* size of freemem in bytes */
setT *tempstack; /* stack of temporary memory, managed by users */
FILE *ferr; /* file for reporting errors, only user is qh_fprintf() */
int IStracing; /* =5 if tracing memory allocations */
int cntquick; /* count of quick allocations */
/* Note: removing statistics doesn't effect speed */
int cntshort; /* count of short allocations */
int cntlong; /* count of long allocations */
int freeshort; /* count of short memfrees */
int freelong; /* count of long memfrees */
int totbuffer; /* total short memory buffers minus buffer links */
int totdropped; /* total dropped memory at end of short memory buffers (e.g., freesize) */
int totfree; /* total size of free, short memory on freelists */
int totlong; /* total size of long memory in use */
int maxlong; /* maximum totlong */
int totshort; /* total size of short memory in use */
int totunused; /* total unused short memory (estimated, short size - request size of first allocations) */
int cntlarger; /* count of setlarger's */
int totlarger; /* total copied by setlarger */
};
/*==================== -macros ====================*/
/*-<a href="qh-mem.htm#TOC"
>--------------------------------</a><a name="memalloc_">-</a>
qh_memalloc_(insize, object, type)
returns object of size bytes
assumes size<=qhmem.LASTsize and void **freelistp is a temp
*/
#if defined qh_NOmem
#define qh_memalloc_(insize, freelistp, object, type) {\
object= (type*)qh_memalloc(insize); }
#elif defined qh_TRACEshort
#define qh_memalloc_(insize, freelistp, object, type) {\
freelistp= NULL; /* Avoid warnings */ \
object= (type*)qh_memalloc(insize); }
#else /* !qh_NOmem */
#define qh_memalloc_(insize, freelistp, object, type) {\
freelistp= qhmem.freelists + qhmem.indextable[insize];\
if ((object= (type*)*freelistp)) {\
qhmem.totshort += qhmem.sizetable[qhmem.indextable[insize]]; \
qhmem.totfree -= qhmem.sizetable[qhmem.indextable[insize]]; \
qhmem.cntquick++; \
*freelistp= *((void **)*freelistp);\
}else object= (type*)qh_memalloc(insize);}
#endif
/*-<a href="qh-mem.htm#TOC"
>--------------------------------</a><a name="memfree_">-</a>
qh_memfree_(object, insize)
free up an object
notes:
object may be NULL
assumes size<=qhmem.LASTsize and void **freelistp is a temp
*/
#if defined qh_NOmem
#define qh_memfree_(object, insize, freelistp) {\
qh_memfree(object, insize); }
#elif defined qh_TRACEshort
#define qh_memfree_(object, insize, freelistp) {\
freelistp= NULL; /* Avoid warnings */ \
qh_memfree(object, insize); }
#else /* !qh_NOmem */
#define qh_memfree_(object, insize, freelistp) {\
if (object) { \
qhmem .freeshort++;\
freelistp= qhmem.freelists + qhmem.indextable[insize];\
qhmem.totshort -= qhmem.sizetable[qhmem.indextable[insize]]; \
qhmem.totfree += qhmem.sizetable[qhmem.indextable[insize]]; \
*((void **)object)= *freelistp;\
*freelistp= object;}}
#endif
/*=============== prototypes in alphabetical order ============*/
void *qh_memalloc(int insize);
void qh_memfree(void *object, int insize);
void qh_memfreeshort(int *curlong, int *totlong);
void qh_meminit(FILE *ferr);
void qh_meminitbuffers(int tracelevel, int alignment, int numsizes,
int bufsize, int bufinit);
void qh_memsetup(void);
void qh_memsize(int size);
void qh_memstatistics(FILE *fp);
void qh_memtotal(int *totlong, int *curlong, int *totshort, int *curshort, int *maxlong, int *totbuffer);
#endif /* qhDEFmem */

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,178 @@
/*<html><pre> -<a href="qh-merge.htm"
>-------------------------------</a><a name="TOP">-</a>
merge.h
header file for merge.c
see qh-merge.htm and merge.c
Copyright (c) 1993-2012 C.B. Barber.
$Id: //main/2011/qhull/src/libqhull/merge.h#3 $$Change: 1464 $
$DateTime: 2012/01/25 22:58:41 $$Author: bbarber $
*/
#ifndef qhDEFmerge
#define qhDEFmerge 1
#include "libqhull.h"
/*============ -constants- ==============*/
/*-<a href="qh-merge.htm#TOC"
>--------------------------------</a><a name="qh_ANGLEredundant">-</a>
qh_ANGLEredundant
indicates redundant merge in mergeT->angle
*/
#define qh_ANGLEredundant 6.0
/*-<a href="qh-merge.htm#TOC"
>--------------------------------</a><a name="qh_ANGLEdegen">-</a>
qh_ANGLEdegen
indicates degenerate facet in mergeT->angle
*/
#define qh_ANGLEdegen 5.0
/*-<a href="qh-merge.htm#TOC"
>--------------------------------</a><a name="qh_ANGLEconcave">-</a>
qh_ANGLEconcave
offset to indicate concave facets in mergeT->angle
notes:
concave facets are assigned the range of [2,4] in mergeT->angle
roundoff error may make the angle less than 2
*/
#define qh_ANGLEconcave 1.5
/*-<a href="qh-merge.htm#TOC"
>--------------------------------</a><a name="MRG">-</a>
MRG... (mergeType)
indicates the type of a merge (mergeT->type)
*/
typedef enum { /* in sort order for facet_mergeset */
MRGnone= 0,
MRGcoplanar, /* centrum coplanar */
MRGanglecoplanar, /* angle coplanar */
/* could detect half concave ridges */
MRGconcave, /* concave ridge */
MRGflip, /* flipped facet. facet1 == facet2 */
MRGridge, /* duplicate ridge (qh_MERGEridge) */
/* degen and redundant go onto degen_mergeset */
MRGdegen, /* degenerate facet (!enough neighbors) facet1 == facet2 */
MRGredundant, /* redundant facet (vertex subset) */
/* merge_degenredundant assumes degen < redundant */
MRGmirror, /* mirror facet from qh_triangulate */
ENDmrg
} mergeType;
/*-<a href="qh-merge.htm#TOC"
>--------------------------------</a><a name="qh_MERGEapex">-</a>
qh_MERGEapex
flag for qh_mergefacet() to indicate an apex merge
*/
#define qh_MERGEapex True
/*============ -structures- ====================*/
/*-<a href="qh-merge.htm#TOC"
>--------------------------------</a><a name="mergeT">-</a>
mergeT
structure used to merge facets
*/
typedef struct mergeT mergeT;
struct mergeT { /* initialize in qh_appendmergeset */
realT angle; /* angle between normals of facet1 and facet2 */
facetT *facet1; /* will merge facet1 into facet2 */
facetT *facet2;
mergeType type;
};
/*=========== -macros- =========================*/
/*-<a href="qh-merge.htm#TOC"
>--------------------------------</a><a name="FOREACHmerge_">-</a>
FOREACHmerge_( merges ) {...}
assign 'merge' to each merge in merges
notes:
uses 'mergeT *merge, **mergep;'
if qh_mergefacet(),
restart since qh.facet_mergeset may change
see <a href="qset.h#FOREACHsetelement_">FOREACHsetelement_</a>
*/
#define FOREACHmerge_( merges ) FOREACHsetelement_(mergeT, merges, merge)
/*============ prototypes in alphabetical order after pre/postmerge =======*/
void qh_premerge(vertexT *apex, realT maxcentrum, realT maxangle);
void qh_postmerge(const char *reason, realT maxcentrum, realT maxangle,
boolT vneighbors);
void qh_all_merges(boolT othermerge, boolT vneighbors);
void qh_appendmergeset(facetT *facet, facetT *neighbor, mergeType mergetype, realT *angle);
setT *qh_basevertices( facetT *samecycle);
void qh_checkconnect(void /* qh new_facets */);
boolT qh_checkzero(boolT testall);
int qh_compareangle(const void *p1, const void *p2);
int qh_comparemerge(const void *p1, const void *p2);
int qh_comparevisit(const void *p1, const void *p2);
void qh_copynonconvex(ridgeT *atridge);
void qh_degen_redundant_facet(facetT *facet);
void qh_degen_redundant_neighbors(facetT *facet, facetT *delfacet);
vertexT *qh_find_newvertex(vertexT *oldvertex, setT *vertices, setT *ridges);
void qh_findbest_test(boolT testcentrum, facetT *facet, facetT *neighbor,
facetT **bestfacet, realT *distp, realT *mindistp, realT *maxdistp);
facetT *qh_findbestneighbor(facetT *facet, realT *distp, realT *mindistp, realT *maxdistp);
void qh_flippedmerges(facetT *facetlist, boolT *wasmerge);
void qh_forcedmerges( boolT *wasmerge);
void qh_getmergeset(facetT *facetlist);
void qh_getmergeset_initial(facetT *facetlist);
void qh_hashridge(setT *hashtable, int hashsize, ridgeT *ridge, vertexT *oldvertex);
ridgeT *qh_hashridge_find(setT *hashtable, int hashsize, ridgeT *ridge,
vertexT *vertex, vertexT *oldvertex, int *hashslot);
void qh_makeridges(facetT *facet);
void qh_mark_dupridges(facetT *facetlist);
void qh_maydropneighbor(facetT *facet);
int qh_merge_degenredundant(void);
void qh_merge_nonconvex( facetT *facet1, facetT *facet2, mergeType mergetype);
void qh_mergecycle(facetT *samecycle, facetT *newfacet);
void qh_mergecycle_all(facetT *facetlist, boolT *wasmerge);
void qh_mergecycle_facets( facetT *samecycle, facetT *newfacet);
void qh_mergecycle_neighbors(facetT *samecycle, facetT *newfacet);
void qh_mergecycle_ridges(facetT *samecycle, facetT *newfacet);
void qh_mergecycle_vneighbors( facetT *samecycle, facetT *newfacet);
void qh_mergefacet(facetT *facet1, facetT *facet2, realT *mindist, realT *maxdist, boolT mergeapex);
void qh_mergefacet2d(facetT *facet1, facetT *facet2);
void qh_mergeneighbors(facetT *facet1, facetT *facet2);
void qh_mergeridges(facetT *facet1, facetT *facet2);
void qh_mergesimplex(facetT *facet1, facetT *facet2, boolT mergeapex);
void qh_mergevertex_del(vertexT *vertex, facetT *facet1, facetT *facet2);
void qh_mergevertex_neighbors(facetT *facet1, facetT *facet2);
void qh_mergevertices(setT *vertices1, setT **vertices);
setT *qh_neighbor_intersections(vertexT *vertex);
void qh_newvertices(setT *vertices);
boolT qh_reducevertices(void);
vertexT *qh_redundant_vertex(vertexT *vertex);
boolT qh_remove_extravertices(facetT *facet);
vertexT *qh_rename_sharedvertex(vertexT *vertex, facetT *facet);
void qh_renameridgevertex(ridgeT *ridge, vertexT *oldvertex, vertexT *newvertex);
void qh_renamevertex(vertexT *oldvertex, vertexT *newvertex, setT *ridges,
facetT *oldfacet, facetT *neighborA);
boolT qh_test_appendmerge(facetT *facet, facetT *neighbor);
boolT qh_test_vneighbors(void /* qh newfacet_list */);
void qh_tracemerge(facetT *facet1, facetT *facet2);
void qh_tracemerging(void);
void qh_updatetested( facetT *facet1, facetT *facet2);
setT *qh_vertexridges(vertexT *vertex);
void qh_vertexridges_facet(vertexT *vertex, facetT *facet, setT **ridges);
void qh_willdelete(facetT *facet, facetT *replace);
#endif /* qhDEFmerge */

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,295 @@
/*<html><pre> -<a href="qh-poly.htm"
>-------------------------------</a><a name="TOP">-</a>
poly.h
header file for poly.c and poly2.c
see qh-poly.htm, libqhull.h and poly.c
Copyright (c) 1993-2012 The Geometry Center.
$Id: //main/2011/qhull/src/libqhull/poly.h#3 $$Change: 1464 $
$DateTime: 2012/01/25 22:58:41 $$Author: bbarber $
*/
#ifndef qhDEFpoly
#define qhDEFpoly 1
#include "libqhull.h"
/*=============== constants ========================== */
/*-<a href="qh-geom.htm#TOC"
>--------------------------------</a><a name="ALGORITHMfault">-</a>
ALGORITHMfault
use as argument to checkconvex() to report errors during buildhull
*/
#define qh_ALGORITHMfault 0
/*-<a href="qh-poly.htm#TOC"
>--------------------------------</a><a name="DATAfault">-</a>
DATAfault
use as argument to checkconvex() to report errors during initialhull
*/
#define qh_DATAfault 1
/*-<a href="qh-poly.htm#TOC"
>--------------------------------</a><a name="DUPLICATEridge">-</a>
DUPLICATEridge
special value for facet->neighbor to indicate a duplicate ridge
notes:
set by matchneighbor, used by matchmatch and mark_dupridge
*/
#define qh_DUPLICATEridge (facetT *)1L
/*-<a href="qh-poly.htm#TOC"
>--------------------------------</a><a name="MERGEridge">-</a>
MERGEridge flag in facet
special value for facet->neighbor to indicate a merged ridge
notes:
set by matchneighbor, used by matchmatch and mark_dupridge
*/
#define qh_MERGEridge (facetT *)2L
/*============ -structures- ====================*/
/*=========== -macros- =========================*/
/*-<a href="qh-poly.htm#TOC"
>--------------------------------</a><a name="FORALLfacet_">-</a>
FORALLfacet_( facetlist ) { ... }
assign 'facet' to each facet in facetlist
notes:
uses 'facetT *facet;'
assumes last facet is a sentinel
see:
FORALLfacets
*/
#define FORALLfacet_( facetlist ) if (facetlist ) for ( facet=( facetlist ); facet && facet->next; facet= facet->next )
/*-<a href="qh-poly.htm#TOC"
>--------------------------------</a><a name="FORALLnew_facets">-</a>
FORALLnew_facets { ... }
assign 'newfacet' to each facet in qh.newfacet_list
notes:
uses 'facetT *newfacet;'
at exit, newfacet==NULL
*/
#define FORALLnew_facets for ( newfacet=qh newfacet_list;newfacet && newfacet->next;newfacet=newfacet->next )
/*-<a href="qh-poly.htm#TOC"
>--------------------------------</a><a name="FORALLvertex_">-</a>
FORALLvertex_( vertexlist ) { ... }
assign 'vertex' to each vertex in vertexlist
notes:
uses 'vertexT *vertex;'
at exit, vertex==NULL
*/
#define FORALLvertex_( vertexlist ) for (vertex=( vertexlist );vertex && vertex->next;vertex= vertex->next )
/*-<a href="qh-poly.htm#TOC"
>--------------------------------</a><a name="FORALLvisible_facets">-</a>
FORALLvisible_facets { ... }
assign 'visible' to each visible facet in qh.visible_list
notes:
uses 'vacetT *visible;'
at exit, visible==NULL
*/
#define FORALLvisible_facets for (visible=qh visible_list; visible && visible->visible; visible= visible->next)
/*-<a href="qh-poly.htm#TOC"
>--------------------------------</a><a name="FORALLsame_">-</a>
FORALLsame_( newfacet ) { ... }
assign 'same' to each facet in newfacet->f.samecycle
notes:
uses 'facetT *same;'
stops when it returns to newfacet
*/
#define FORALLsame_(newfacet) for (same= newfacet->f.samecycle; same != newfacet; same= same->f.samecycle)
/*-<a href="qh-poly.htm#TOC"
>--------------------------------</a><a name="FORALLsame_cycle_">-</a>
FORALLsame_cycle_( newfacet ) { ... }
assign 'same' to each facet in newfacet->f.samecycle
notes:
uses 'facetT *same;'
at exit, same == NULL
*/
#define FORALLsame_cycle_(newfacet) \
for (same= newfacet->f.samecycle; \
same; same= (same == newfacet ? NULL : same->f.samecycle))
/*-<a href="qh-poly.htm#TOC"
>--------------------------------</a><a name="FOREACHneighborA_">-</a>
FOREACHneighborA_( facet ) { ... }
assign 'neighborA' to each neighbor in facet->neighbors
FOREACHneighborA_( vertex ) { ... }
assign 'neighborA' to each neighbor in vertex->neighbors
declare:
facetT *neighborA, **neighborAp;
see:
<a href="qset.h#FOREACHsetelement_">FOREACHsetelement_</a>
*/
#define FOREACHneighborA_(facet) FOREACHsetelement_(facetT, facet->neighbors, neighborA)
/*-<a href="qh-poly.htm#TOC"
>--------------------------------</a><a name="FOREACHvisible_">-</a>
FOREACHvisible_( facets ) { ... }
assign 'visible' to each facet in facets
notes:
uses 'facetT *facet, *facetp;'
see <a href="qset.h#FOREACHsetelement_">FOREACHsetelement_</a>
*/
#define FOREACHvisible_(facets) FOREACHsetelement_(facetT, facets, visible)
/*-<a href="qh-poly.htm#TOC"
>--------------------------------</a><a name="FOREACHnewfacet_">-</a>
FOREACHnewfacet_( facets ) { ... }
assign 'newfacet' to each facet in facets
notes:
uses 'facetT *newfacet, *newfacetp;'
see <a href="qset.h#FOREACHsetelement_">FOREACHsetelement_</a>
*/
#define FOREACHnewfacet_(facets) FOREACHsetelement_(facetT, facets, newfacet)
/*-<a href="qh-poly.htm#TOC"
>--------------------------------</a><a name="FOREACHvertexA_">-</a>
FOREACHvertexA_( vertices ) { ... }
assign 'vertexA' to each vertex in vertices
notes:
uses 'vertexT *vertexA, *vertexAp;'
see <a href="qset.h#FOREACHsetelement_">FOREACHsetelement_</a>
*/
#define FOREACHvertexA_(vertices) FOREACHsetelement_(vertexT, vertices, vertexA)
/*-<a href="qh-poly.htm#TOC"
>--------------------------------</a><a name="FOREACHvertexreverse12_">-</a>
FOREACHvertexreverse12_( vertices ) { ... }
assign 'vertex' to each vertex in vertices
reverse order of first two vertices
notes:
uses 'vertexT *vertex, *vertexp;'
see <a href="qset.h#FOREACHsetelement_">FOREACHsetelement_</a>
*/
#define FOREACHvertexreverse12_(vertices) FOREACHsetelementreverse12_(vertexT, vertices, vertex)
/*=============== prototypes poly.c in alphabetical order ================*/
void qh_appendfacet(facetT *facet);
void qh_appendvertex(vertexT *vertex);
void qh_attachnewfacets(void);
boolT qh_checkflipped(facetT *facet, realT *dist, boolT allerror);
void qh_delfacet(facetT *facet);
void qh_deletevisible(void /*qh visible_list, qh horizon_list*/);
setT *qh_facetintersect(facetT *facetA, facetT *facetB, int *skipAp,int *skipBp, int extra);
int qh_gethash(int hashsize, setT *set, int size, int firstindex, void *skipelem);
facetT *qh_makenewfacet(setT *vertices, boolT toporient, facetT *facet);
void qh_makenewplanes(void /* newfacet_list */);
facetT *qh_makenew_nonsimplicial(facetT *visible, vertexT *apex, int *numnew);
facetT *qh_makenew_simplicial(facetT *visible, vertexT *apex, int *numnew);
void qh_matchneighbor(facetT *newfacet, int newskip, int hashsize,
int *hashcount);
void qh_matchnewfacets(void);
boolT qh_matchvertices(int firstindex, setT *verticesA, int skipA,
setT *verticesB, int *skipB, boolT *same);
facetT *qh_newfacet(void);
ridgeT *qh_newridge(void);
int qh_pointid(pointT *point);
void qh_removefacet(facetT *facet);
void qh_removevertex(vertexT *vertex);
void qh_updatevertices(void);
/*========== -prototypes poly2.c in alphabetical order ===========*/
void qh_addhash(void* newelem, setT *hashtable, int hashsize, int hash);
void qh_check_bestdist(void);
void qh_check_maxout(void);
void qh_check_output(void);
void qh_check_point(pointT *point, facetT *facet, realT *maxoutside, realT *maxdist, facetT **errfacet1, facetT **errfacet2);
void qh_check_points(void);
void qh_checkconvex(facetT *facetlist, int fault);
void qh_checkfacet(facetT *facet, boolT newmerge, boolT *waserrorp);
void qh_checkflipped_all(facetT *facetlist);
void qh_checkpolygon(facetT *facetlist);
void qh_checkvertex(vertexT *vertex);
void qh_clearcenters(qh_CENTER type);
void qh_createsimplex(setT *vertices);
void qh_delridge(ridgeT *ridge);
void qh_delvertex(vertexT *vertex);
setT *qh_facet3vertex(facetT *facet);
facetT *qh_findbestfacet(pointT *point, boolT bestoutside,
realT *bestdist, boolT *isoutside);
facetT *qh_findbestlower(facetT *upperfacet, pointT *point, realT *bestdistp, int *numpart);
facetT *qh_findfacet_all(pointT *point, realT *bestdist, boolT *isoutside,
int *numpart);
int qh_findgood(facetT *facetlist, int goodhorizon);
void qh_findgood_all(facetT *facetlist);
void qh_furthestnext(void /* qh facet_list */);
void qh_furthestout(facetT *facet);
void qh_infiniteloop(facetT *facet);
void qh_initbuild(void);
void qh_initialhull(setT *vertices);
setT *qh_initialvertices(int dim, setT *maxpoints, pointT *points, int numpoints);
vertexT *qh_isvertex(pointT *point, setT *vertices);
vertexT *qh_makenewfacets(pointT *point /*horizon_list, visible_list*/);
void qh_matchduplicates(facetT *atfacet, int atskip, int hashsize, int *hashcount);
void qh_nearcoplanar(void /* qh.facet_list */);
vertexT *qh_nearvertex(facetT *facet, pointT *point, realT *bestdistp);
int qh_newhashtable(int newsize);
vertexT *qh_newvertex(pointT *point);
ridgeT *qh_nextridge3d(ridgeT *atridge, facetT *facet, vertexT **vertexp);
void qh_outcoplanar(void /* facet_list */);
pointT *qh_point(int id);
void qh_point_add(setT *set, pointT *point, void *elem);
setT *qh_pointfacet(void /*qh facet_list*/);
setT *qh_pointvertex(void /*qh facet_list*/);
void qh_prependfacet(facetT *facet, facetT **facetlist);
void qh_printhashtable(FILE *fp);
void qh_printlists(void);
void qh_resetlists(boolT stats, boolT resetVisible /*qh newvertex_list newfacet_list visible_list*/);
void qh_setvoronoi_all(void);
void qh_triangulate(void /*qh facet_list*/);
void qh_triangulate_facet(facetT *facetA, vertexT **first_vertex);
void qh_triangulate_link(facetT *oldfacetA, facetT *facetA, facetT *oldfacetB, facetT *facetB);
void qh_triangulate_mirror(facetT *facetA, facetT *facetB);
void qh_triangulate_null(facetT *facetA);
void qh_vertexintersect(setT **vertexsetA,setT *vertexsetB);
setT *qh_vertexintersect_new(setT *vertexsetA,setT *vertexsetB);
void qh_vertexneighbors(void /*qh facet_list*/);
boolT qh_vertexsubset(setT *vertexsetA, setT *vertexsetB);
#endif /* qhDEFpoly */

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,151 @@
/*<html><pre> -<a href="qh-qhull.htm"
>-------------------------------</a><a name="TOP">-</a>
qhull_a.h
all header files for compiling qhull
see qh-qhull.htm
see libqhull.h for user-level definitions
see user.h for user-definable constants
defines internal functions for libqhull.c global.c
Copyright (c) 1993-2012 The Geometry Center.
$Id: //main/2011/qhull/src/libqhull/qhull_a.h#3 $$Change: 1464 $
$DateTime: 2012/01/25 22:58:41 $$Author: bbarber $
Notes: grep for ((" and (" to catch fprintf("lkasdjf");
full parens around (x?y:z)
use '#include qhull/qhull_a.h' to avoid name clashes
*/
#ifndef qhDEFqhulla
#define qhDEFqhulla 1
#include "libqhull.h" /* Defines data types */
#include "stat.h"
#include "random.h"
#include "mem.h"
#include "qset.h"
#include "geom.h"
#include "merge.h"
#include "poly.h"
#include "io.h"
#include <setjmp.h>
#include <string.h>
#include <math.h>
#include <float.h> /* some compilers will not need float.h */
#include <limits.h>
#include <time.h>
#include <ctype.h>
#include <stdio.h>
#include <stdlib.h>
/*** uncomment here and qset.c
if string.h does not define memcpy()
#include <memory.h>
*/
#if qh_CLOCKtype == 2 /* defined in user.h from libqhull.h */
#include <sys/types.h>
#include <sys/times.h>
#include <unistd.h>
#endif
#ifdef _MSC_VER /* Microsoft Visual C++ -- warning level 4 */
#pragma warning( disable : 4100) /* unreferenced formal parameter */
#pragma warning( disable : 4127) /* conditional expression is constant */
#pragma warning( disable : 4706) /* assignment within conditional function */
#pragma warning( disable : 4996) /* function was declared deprecated(strcpy, localtime, etc.) */
#endif
/* ======= -macros- =========== */
/*-<a href="qh-qhull.htm#TOC"
>--------------------------------</a><a name="traceN">-</a>
traceN((qh ferr, 0Nnnn, "format\n", vars));
calls qh_fprintf if qh.IStracing >= N
Add debugging traps to the end of qh_fprintf
notes:
removing tracing reduces code size but doesn't change execution speed
*/
#ifndef qh_NOtrace
#define trace0(args) {if (qh IStracing) qh_fprintf args;}
#define trace1(args) {if (qh IStracing >= 1) qh_fprintf args;}
#define trace2(args) {if (qh IStracing >= 2) qh_fprintf args;}
#define trace3(args) {if (qh IStracing >= 3) qh_fprintf args;}
#define trace4(args) {if (qh IStracing >= 4) qh_fprintf args;}
#define trace5(args) {if (qh IStracing >= 5) qh_fprintf args;}
#else /* qh_NOtrace */
#define trace0(args) {}
#define trace1(args) {}
#define trace2(args) {}
#define trace3(args) {}
#define trace4(args) {}
#define trace5(args) {}
#endif /* qh_NOtrace */
/*-<a href="qh-qhull.htm#TOC"
>--------------------------------</a><a name="QHULL_UNUSED">-</a>
*/
/* See Qt's qglobal.h */
#if !defined(SAG_COM) && (defined(WIN64) || defined(_WIN64) || defined(__WIN64__) || defined(WIN32) || defined(_WIN32) || defined(__WIN32__) || defined(__NT__))
# define QHULL_OS_WIN
#elif defined(__MWERKS__) && defined(__INTEL__)
# define QHULL_OS_WIN
#endif
#if defined(__INTEL_COMPILER) && !defined(QHULL_OS_WIN)
template <typename T>
inline void qhullUnused(T &x) { (void)x; }
# define QHULL_UNUSED(x) qhullUnused(x);
#else
# define QHULL_UNUSED(x) (void)x;
#endif
/***** -libqhull.c prototypes (alphabetical after qhull) ********************/
void qh_qhull(void);
boolT qh_addpoint(pointT *furthest, facetT *facet, boolT checkdist);
void qh_buildhull(void);
void qh_buildtracing(pointT *furthest, facetT *facet);
void qh_build_withrestart(void);
void qh_errexit2(int exitcode, facetT *facet, facetT *otherfacet);
void qh_findhorizon(pointT *point, facetT *facet, int *goodvisible,int *goodhorizon);
pointT *qh_nextfurthest(facetT **visible);
void qh_partitionall(setT *vertices, pointT *points,int npoints);
void qh_partitioncoplanar(pointT *point, facetT *facet, realT *dist);
void qh_partitionpoint(pointT *point, facetT *facet);
void qh_partitionvisible(boolT allpoints, int *numpoints);
void qh_precision(const char *reason);
void qh_printsummary(FILE *fp);
/***** -global.c internal prototypes (alphabetical) ***********************/
void qh_appendprint(qh_PRINT format);
void qh_freebuild(boolT allmem);
void qh_freebuffers(void);
void qh_initbuffers(coordT *points, int numpoints, int dim, boolT ismalloc);
/***** -stat.c internal prototypes (alphabetical) ***********************/
void qh_allstatA(void);
void qh_allstatB(void);
void qh_allstatC(void);
void qh_allstatD(void);
void qh_allstatE(void);
void qh_allstatE2 (void);
void qh_allstatF(void);
void qh_allstatG(void);
void qh_allstatH(void);
void qh_freebuffers(void);
void qh_initbuffers(coordT *points, int numpoints, int dim, boolT ismalloc);
#endif /* qhDEFqhulla */

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,488 @@
/*<html><pre> -<a href="qh-set.htm"
>-------------------------------</a><a name="TOP">-</a>
qset.h
header file for qset.c that implements set
see qh-set.htm and qset.c
only uses mem.c, malloc/free
for error handling, writes message and calls
qh_errexit(qhmem_ERRqhull, NULL, NULL);
set operations satisfy the following properties:
- sets have a max size, the actual size (if different) is stored at the end
- every set is NULL terminated
- sets may be sorted or unsorted, the caller must distinguish this
Copyright (c) 1993-2012 The Geometry Center.
$Id: //main/2011/qhull/src/libqhull/qset.h#4 $$Change: 1464 $
$DateTime: 2012/01/25 22:58:41 $$Author: bbarber $
*/
#ifndef qhDEFset
#define qhDEFset 1
#include <stdio.h>
/*================= -structures- ===============*/
#ifndef DEFsetT
#define DEFsetT 1
typedef struct setT setT; /* a set is a sorted or unsorted array of pointers */
#endif
/*-<a href="qh-set.htm#TOC"
>----------------------------------------</a><a name="setT">-</a>
setT
a set or list of pointers with maximum size and actual size.
variations:
unsorted, unique -- a list of unique pointers with NULL terminator
user guarantees uniqueness
sorted -- a sorted list of unique pointers with NULL terminator
qset.c guarantees uniqueness
unsorted -- a list of pointers terminated with NULL
indexed -- an array of pointers with NULL elements
structure for set of n elements:
--------------
| maxsize
--------------
| e[0] - a pointer, may be NULL for indexed sets
--------------
| e[1]
--------------
| ...
--------------
| e[n-1]
--------------
| e[n] = NULL
--------------
| ...
--------------
| e[maxsize] - n+1 or NULL (determines actual size of set)
--------------
*/
/*-- setelemT -- internal type to allow both pointers and indices
*/
typedef union setelemT setelemT;
union setelemT {
void *p;
int i; /* integer used for e[maxSize] */
};
struct setT {
int maxsize; /* maximum number of elements (except NULL) */
setelemT e[1]; /* array of pointers, tail is NULL */
/* last slot (unless NULL) is actual size+1
e[maxsize]==NULL or e[e[maxsize]-1]==NULL */
/* this may generate a warning since e[] contains
maxsize elements */
};
/*=========== -constants- =========================*/
/*-<a href="qh-set.htm#TOC"
>-----------------------------------</a><a name="SETelemsize">-</a>
SETelemsize
size of a set element in bytes
*/
#define SETelemsize ((int)sizeof(setelemT))
/*=========== -macros- =========================*/
/*-<a href="qh-set.htm#TOC"
>-----------------------------------</a><a name="FOREACHsetelement_">-</a>
FOREACHsetelement_(type, set, variable)
define FOREACH iterator
declare:
assumes *variable and **variablep are declared
no space in "variable)" [DEC Alpha cc compiler]
each iteration:
variable is set element
variablep is one beyond variable.
to repeat an element:
variablep--; / *repeat* /
at exit:
variable is NULL at end of loop
example:
#define FOREACHfacet_( facets ) FOREACHsetelement_( facetT, facets, facet )
notes:
use FOREACHsetelement_i_() if need index or include NULLs
WARNING:
nested loops can't use the same variable (define another FOREACH)
needs braces if nested inside another FOREACH
this includes intervening blocks, e.g. FOREACH...{ if () FOREACH...} )
*/
#define FOREACHsetelement_(type, set, variable) \
if (((variable= NULL), set)) for (\
variable##p= (type **)&((set)->e[0].p); \
(variable= *variable##p++);)
/*-<a href="qh-set.htm#TOC"
>----------------------------------------</a><a name="FOREACHsetelement_i_">-</a>
FOREACHsetelement_i_(type, set, variable)
define indexed FOREACH iterator
declare:
type *variable, variable_n, variable_i;
each iteration:
variable is set element, may be NULL
variable_i is index, variable_n is qh_setsize()
to repeat an element:
variable_i--; variable_n-- repeats for deleted element
at exit:
variable==NULL and variable_i==variable_n
example:
#define FOREACHfacet_i_( facets ) FOREACHsetelement_i_( facetT, facets, facet )
WARNING:
nested loops can't use the same variable (define another FOREACH)
needs braces if nested inside another FOREACH
this includes intervening blocks, e.g. FOREACH...{ if () FOREACH...} )
*/
#define FOREACHsetelement_i_(type, set, variable) \
if (((variable= NULL), set)) for (\
variable##_i= 0, variable= (type *)((set)->e[0].p), \
variable##_n= qh_setsize(set);\
variable##_i < variable##_n;\
variable= (type *)((set)->e[++variable##_i].p) )
/*-<a href="qh-set.htm#TOC"
>--------------------------------------</a><a name="FOREACHsetelementreverse_">-</a>
FOREACHsetelementreverse_(type, set, variable)-
define FOREACH iterator in reverse order
declare:
assumes *variable and **variablep are declared
also declare 'int variabletemp'
each iteration:
variable is set element
to repeat an element:
variabletemp++; / *repeat* /
at exit:
variable is NULL
example:
#define FOREACHvertexreverse_( vertices ) FOREACHsetelementreverse_( vertexT, vertices, vertex )
notes:
use FOREACHsetelementreverse12_() to reverse first two elements
WARNING: needs braces if nested inside another FOREACH
*/
#define FOREACHsetelementreverse_(type, set, variable) \
if (((variable= NULL), set)) for (\
variable##temp= qh_setsize(set)-1, variable= qh_setlast(set);\
variable; variable= \
((--variable##temp >= 0) ? SETelemt_(set, variable##temp, type) : NULL))
/*-<a href="qh-set.htm#TOC"
>-----------------------------------</a><a name="FOREACHsetelementreverse12_">-</a>
FOREACHsetelementreverse12_(type, set, variable)-
define FOREACH iterator with e[1] and e[0] reversed
declare:
assumes *variable and **variablep are declared
each iteration:
variable is set element
variablep is one after variable.
to repeat an element:
variablep--; / *repeat* /
at exit:
variable is NULL at end of loop
example
#define FOREACHvertexreverse12_( vertices ) FOREACHsetelementreverse12_( vertexT, vertices, vertex )
notes:
WARNING: needs braces if nested inside another FOREACH
*/
#define FOREACHsetelementreverse12_(type, set, variable) \
if (((variable= NULL), set)) for (\
variable##p= (type **)&((set)->e[1].p); \
(variable= *variable##p); \
variable##p == ((type **)&((set)->e[0].p))?variable##p += 2: \
(variable##p == ((type **)&((set)->e[1].p))?variable##p--:variable##p++))
/*-<a href="qh-set.htm#TOC"
>-----------------------------------</a><a name="FOREACHelem_">-</a>
FOREACHelem_( set )-
iterate elements in a set
declare:
void *elem, *elemp;
each iteration:
elem is set element
elemp is one beyond
to repeat an element:
elemp--; / *repeat* /
at exit:
elem == NULL at end of loop
example:
FOREACHelem_(set) {
notes:
WARNING: needs braces if nested inside another FOREACH
*/
#define FOREACHelem_(set) FOREACHsetelement_(void, set, elem)
/*-<a href="qh-set.htm#TOC"
>-----------------------------------</a><a name="FOREACHset_">-</a>
FOREACHset_( set )-
iterate a set of sets
declare:
setT *set, **setp;
each iteration:
set is set element
setp is one beyond
to repeat an element:
setp--; / *repeat* /
at exit:
set == NULL at end of loop
example
FOREACHset_(sets) {
notes:
WARNING: needs braces if nested inside another FOREACH
*/
#define FOREACHset_(sets) FOREACHsetelement_(setT, sets, set)
/*-<a href="qh-set.htm#TOC"
>-----------------------------------------</a><a name="SETindex_">-</a>
SETindex_( set, elem )
return index of elem in set
notes:
for use with FOREACH iteration
WARN64 -- Maximum set size is 2G
example:
i= SETindex_(ridges, ridge)
*/
#define SETindex_(set, elem) ((int)((void **)elem##p - (void **)&(set)->e[1].p))
/*-<a href="qh-set.htm#TOC"
>---------------------------------------</a><a name="SETref_">-</a>
SETref_( elem )
l.h.s. for modifying the current element in a FOREACH iteration
example:
SETref_(ridge)= anotherridge;
*/
#define SETref_(elem) (elem##p[-1])
/*-<a href="qh-set.htm#TOC"
>---------------------------------------</a><a name="SETelem_">-</a>
SETelem_(set, n)
return the n'th element of set
notes:
assumes that n is valid [0..size] and that set is defined
use SETelemt_() for type cast
*/
#define SETelem_(set, n) ((set)->e[n].p)
/*-<a href="qh-set.htm#TOC"
>---------------------------------------</a><a name="SETelemt_">-</a>
SETelemt_(set, n, type)
return the n'th element of set as a type
notes:
assumes that n is valid [0..size] and that set is defined
*/
#define SETelemt_(set, n, type) ((type*)((set)->e[n].p))
/*-<a href="qh-set.htm#TOC"
>---------------------------------------</a><a name="SETelemaddr_">-</a>
SETelemaddr_(set, n, type)
return address of the n'th element of a set
notes:
assumes that n is valid [0..size] and set is defined
*/
#define SETelemaddr_(set, n, type) ((type **)(&((set)->e[n].p)))
/*-<a href="qh-set.htm#TOC"
>---------------------------------------</a><a name="SETfirst_">-</a>
SETfirst_(set)
return first element of set
*/
#define SETfirst_(set) ((set)->e[0].p)
/*-<a href="qh-set.htm#TOC"
>---------------------------------------</a><a name="SETfirstt_">-</a>
SETfirstt_(set, type)
return first element of set as a type
*/
#define SETfirstt_(set, type) ((type*)((set)->e[0].p))
/*-<a href="qh-set.htm#TOC"
>---------------------------------------</a><a name="SETsecond_">-</a>
SETsecond_(set)
return second element of set
*/
#define SETsecond_(set) ((set)->e[1].p)
/*-<a href="qh-set.htm#TOC"
>---------------------------------------</a><a name="SETsecondt_">-</a>
SETsecondt_(set, type)
return second element of set as a type
*/
#define SETsecondt_(set, type) ((type*)((set)->e[1].p))
/*-<a href="qh-set.htm#TOC"
>---------------------------------------</a><a name="SETaddr_">-</a>
SETaddr_(set, type)
return address of set's elements
*/
#define SETaddr_(set,type) ((type **)(&((set)->e[0].p)))
/*-<a href="qh-set.htm#TOC"
>---------------------------------------</a><a name="SETreturnsize_">-</a>
SETreturnsize_(set, size)
return size of a set
notes:
set must be defined
use qh_setsize(set) unless speed is critical
*/
#define SETreturnsize_(set, size) (((size)= ((set)->e[(set)->maxsize].i))?(--(size)):((size)= (set)->maxsize))
/*-<a href="qh-set.htm#TOC"
>---------------------------------------</a><a name="SETempty_">-</a>
SETempty_(set)
return true(1) if set is empty
notes:
set may be NULL
*/
#define SETempty_(set) (!set || (SETfirst_(set) ? 0 : 1))
/*-<a href="qh-set.htm#TOC"
>-------------------------------<a name="SETsizeaddr_">-</a>
SETsizeaddr_(set)
return pointer to 'actual size+1' of set (set CANNOT be NULL!!)
Its type is setelemT* for strict aliasing
All SETelemaddr_ must be cast to setelemT
notes:
*SETsizeaddr==NULL or e[*SETsizeaddr-1].p==NULL
*/
#define SETsizeaddr_(set) (&((set)->e[(set)->maxsize]))
/*-<a href="qh-set.htm#TOC"
>---------------------------------------</a><a name="SETtruncate_">-</a>
SETtruncate_(set, size)
truncate set to size
see:
qh_settruncate()
*/
#define SETtruncate_(set, size) {set->e[set->maxsize].i= size+1; /* maybe overwritten */ \
set->e[size].p= NULL;}
/*======= prototypes in alphabetical order ============*/
void qh_setaddsorted(setT **setp, void *elem);
void qh_setaddnth(setT **setp, int nth, void *newelem);
void qh_setappend(setT **setp, void *elem);
void qh_setappend_set(setT **setp, setT *setA);
void qh_setappend2ndlast(setT **setp, void *elem);
void qh_setcheck(setT *set, const char *tname, unsigned id);
void qh_setcompact(setT *set);
setT *qh_setcopy(setT *set, int extra);
void *qh_setdel(setT *set, void *elem);
void *qh_setdellast(setT *set);
void *qh_setdelnth(setT *set, int nth);
void *qh_setdelnthsorted(setT *set, int nth);
void *qh_setdelsorted(setT *set, void *newelem);
setT *qh_setduplicate( setT *set, int elemsize);
int qh_setequal(setT *setA, setT *setB);
int qh_setequal_except(setT *setA, void *skipelemA, setT *setB, void *skipelemB);
int qh_setequal_skip(setT *setA, int skipA, setT *setB, int skipB);
void **qh_setendpointer(setT *set);
void qh_setfree(setT **set);
void qh_setfree2( setT **setp, int elemsize);
void qh_setfreelong(setT **set);
int qh_setin(setT *set, void *setelem);
int qh_setindex(setT *set, void *setelem);
void qh_setlarger(setT **setp);
void *qh_setlast(setT *set);
setT *qh_setnew(int size);
setT *qh_setnew_delnthsorted(setT *set, int size, int nth, int prepend);
void qh_setprint(FILE *fp, const char* string, setT *set);
void qh_setreplace(setT *set, void *oldelem, void *newelem);
int qh_setsize(setT *set);
setT *qh_settemp(int setsize);
void qh_settempfree(setT **set);
void qh_settempfree_all(void);
setT *qh_settemppop(void);
void qh_settemppush(setT *set);
void qh_settruncate(setT *set, int size);
int qh_setunique(setT **set, void *elem);
void qh_setzero(setT *set, int idx, int size);
#endif /* qhDEFset */

View File

@@ -0,0 +1,243 @@
/*<html><pre> -<a href="index.htm#TOC"
>-------------------------------</a><a name="TOP">-</a>
random.c -- utilities
Park & Miller's minimal standard random number generator
argc/argv conversion
Used by rbox. Do not use 'qh'
*/
#include "libqhull.h"
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#ifdef _MSC_VER /* Microsoft Visual C++ -- warning level 4 */
#pragma warning( disable : 4706) /* assignment within conditional function */
#pragma warning( disable : 4996) /* function was declared deprecated(strcpy, localtime, etc.) */
#endif
/*-<a href="qh-globa.htm#TOC"
>-------------------------------</a><a name="argv_to_command">-</a>
qh_argv_to_command( argc, argv, command, max_size )
build command from argc/argv
max_size is at least
returns:
a space-delimited string of options (just as typed)
returns false if max_size is too short
notes:
silently removes
makes option string easy to input and output
matches qh_argv_to_command_size()
argc may be 0
*/
int qh_argv_to_command(int argc, char *argv[], char* command, int max_size) {
int i, remaining;
char *s;
*command= '\0'; /* max_size > 0 */
if (argc) {
if ((s= strrchr( argv[0], '\\')) /* get filename w/o .exe extension */
|| (s= strrchr( argv[0], '/')))
s++;
else
s= argv[0];
if ((int)strlen(s) < max_size) /* WARN64 */
strcpy(command, s);
else
goto error_argv;
if ((s= strstr(command, ".EXE"))
|| (s= strstr(command, ".exe")))
*s= '\0';
}
for (i=1; i < argc; i++) {
s= argv[i];
remaining= max_size - (int)strlen(command) - (int)strlen(s) - 2; /* WARN64 */
if (!*s || strchr(s, ' ')) {
char *t= command + strlen(command);
remaining -= 2;
if (remaining < 0) {
goto error_argv;
}
*t++= ' ';
*t++= '"';
while (*s) {
if (*s == '"') {
if (--remaining < 0)
goto error_argv;
*t++= '\\';
}
*t++= *s++;
}
*t++= '"';
*t= '\0';
}else if (remaining < 0) {
goto error_argv;
}else
strcat(command, " ");
strcat(command, s);
}
return 1;
error_argv:
return 0;
} /* argv_to_command */
/*-<a href="qh-globa.htm#TOC"
>-------------------------------</a><a name="argv_to_command_size">-</a>
qh_argv_to_command_size( argc, argv )
return size to allocate for qh_argv_to_command()
notes:
argc may be 0
actual size is usually shorter
*/
int qh_argv_to_command_size(int argc, char *argv[]) {
unsigned int count= 1; /* null-terminator if argc==0 */
int i;
char *s;
for (i=0; i<argc; i++){
count += (int)strlen(argv[i]) + 1; /* WARN64 */
if (i>0 && strchr(argv[i], ' ')) {
count += 2; /* quote delimiters */
for (s=argv[i]; *s; s++) {
if (*s == '"') {
count++;
}
}
}
}
return count;
} /* argv_to_command_size */
/*-<a href="qh-geom.htm#TOC"
>-------------------------------</a><a name="rand">-</a>
qh_rand()
qh_srand( seed )
generate pseudo-random number between 1 and 2^31 -2
notes:
For qhull and rbox, called from qh_RANDOMint(),etc. [user.h]
From Park & Miller's minimal standard random number generator
Communications of the ACM, 31:1192-1201, 1988.
Does not use 0 or 2^31 -1
this is silently enforced by qh_srand()
Can make 'Rn' much faster by moving qh_rand to qh_distplane
*/
/* Global variables and constants */
int qh_rand_seed= 1; /* define as global variable instead of using qh */
#define qh_rand_a 16807
#define qh_rand_m 2147483647
#define qh_rand_q 127773 /* m div a */
#define qh_rand_r 2836 /* m mod a */
int qh_rand( void) {
int lo, hi, test;
int seed = qh_rand_seed;
hi = seed / qh_rand_q; /* seed div q */
lo = seed % qh_rand_q; /* seed mod q */
test = qh_rand_a * lo - qh_rand_r * hi;
if (test > 0)
seed= test;
else
seed= test + qh_rand_m;
qh_rand_seed= seed;
/* seed = seed < qh_RANDOMmax/2 ? 0 : qh_RANDOMmax; for testing */
/* seed = qh_RANDOMmax; for testing */
return seed;
} /* rand */
void qh_srand( int seed) {
if (seed < 1)
qh_rand_seed= 1;
else if (seed >= qh_rand_m)
qh_rand_seed= qh_rand_m - 1;
else
qh_rand_seed= seed;
} /* qh_srand */
/*-<a href="qh-geom.htm#TOC"
>-------------------------------</a><a name="randomfactor">-</a>
qh_randomfactor( scale, offset )
return a random factor r * scale + offset
notes:
qh.RANDOMa/b are defined in global.c
*/
realT qh_randomfactor(realT scale, realT offset) {
realT randr;
randr= qh_RANDOMint;
return randr * scale + offset;
} /* randomfactor */
/*-<a href="qh-geom.htm#TOC"
>-------------------------------</a><a name="randommatrix">-</a>
qh_randommatrix( buffer, dim, rows )
generate a random dim X dim matrix in range [-1,1]
assumes buffer is [dim+1, dim]
returns:
sets buffer to random numbers
sets rows to rows of buffer
sets row[dim] as scratch row
*/
void qh_randommatrix(realT *buffer, int dim, realT **rows) {
int i, k;
realT **rowi, *coord, realr;
coord= buffer;
rowi= rows;
for (i=0; i < dim; i++) {
*(rowi++)= coord;
for (k=0; k < dim; k++) {
realr= qh_RANDOMint;
*(coord++)= 2.0 * realr/(qh_RANDOMmax+1) - 1.0;
}
}
*rowi= coord;
} /* randommatrix */
/*-<a href="qh-globa.htm#TOC"
>-------------------------------</a><a name="strtol">-</a>
qh_strtol( s, endp) qh_strtod( s, endp)
internal versions of strtol() and strtod()
does not skip trailing spaces
notes:
some implementations of strtol()/strtod() skip trailing spaces
*/
double qh_strtod(const char *s, char **endp) {
double result;
result= strtod(s, endp);
if (s < (*endp) && (*endp)[-1] == ' ')
(*endp)--;
return result;
} /* strtod */
int qh_strtol(const char *s, char **endp) {
int result;
result= (int) strtol(s, endp, 10); /* WARN64 */
if (s< (*endp) && (*endp)[-1] == ' ')
(*endp)--;
return result;
} /* strtol */

View File

@@ -0,0 +1,34 @@
/*<html><pre> -<a href="qh-geom.htm"
>-------------------------------</a><a name="TOP">-</a>
random.h
header file for random routines
see qh-geom.htm and random.c
Copyright (c) 1993-2012 The Geometry Center.
$Id: //main/2011/qhull/src/libqhull/random.h#3 $$Change: 1464 $
$DateTime: 2012/01/25 22:58:41 $$Author: bbarber $
*/
#ifndef qhDEFrandom
#define qhDEFrandom 1
#include "libqhull.h"
/*============= prototypes in alphabetical order ======= */
int qh_argv_to_command(int argc, char *argv[], char* command, int max_size);
int qh_argv_to_command_size(int argc, char *argv[]);
int qh_rand( void);
void qh_srand( int seed);
realT qh_randomfactor(realT scale, realT offset);
void qh_randommatrix(realT *buffer, int dim, realT **row);
int qh_strtol(const char *s, char **endp);
double qh_strtod(const char *s, char **endp);
#endif /* qhDEFrandom */

View File

@@ -0,0 +1,793 @@
/*<html><pre> -<a href="index.htm#TOC"
>-------------------------------</a><a name="TOP">-</a>
rboxlib.c
Generate input points
notes:
For documentation, see prompt[] of rbox.c
50 points generated for 'rbox D4'
WARNING:
incorrect range if qh_RANDOMmax is defined wrong (user.h)
*/
#include "random.h"
#include "libqhull.h"
#include <ctype.h>
#include <limits.h>
#include <math.h>
#include <setjmp.h>
#include <string.h>
#include <time.h>
#include <stdio.h>
#include <stdlib.h>
#ifdef _MSC_VER /* Microsoft Visual C++ */
#pragma warning( disable : 4706) /* assignment within conditional expression. */
#pragma warning( disable : 4996) /* this function (strncat,sprintf,strcpy) or variable may be unsafe. */
#endif
#define MAXdim 200
/* ------------------------------ prototypes ----------------*/
int roundi( double a);
void out1( double a);
void out2n( double a, double b);
void out3n( double a, double b, double c);
void qh_fprintf_rbox(FILE *fp, int msgcode, const char *fmt, ... );
void qh_free(void *mem);
void *qh_malloc(size_t size);
int qh_rand( void);
void qh_srand( int seed);
/* ------------------------------ globals -------------------*/
/* No state is carried between rbox requests */
typedef struct rboxT rboxT;
struct rboxT {
FILE *fout;
FILE *ferr;
int isinteger;
double out_offset;
jmp_buf errexit; /* exit label for rboxpoints, defined by setjmp(), called by qh_errexit_rbox() */
};
int rbox_inuse= 0;
rboxT rbox;
/*-<a href="qh-qhull.htm#TOC"
>-------------------------------</a><a name="rboxpoints">-</a>
qh_rboxpoints( fout, ferr, rbox_command )
Generate points to fout according to rbox options
Report errors on ferr
returns:
0 (qh_ERRnone) on success
1 (qh_ERRinput) on input error
4 (qh_ERRmem) on memory error
5 (qh_ERRqhull) on internal error
notes:
To avoid stdio, redefine qh_malloc, qh_free, and qh_fprintf_rbox (user.c)
Rbox is not multithreaded.
design:
Straight line code (consider defining a struct and functions):
Parse arguments into variables
Determine the number of points
Generate the points
*/
int qh_rboxpoints(FILE* fout, FILE* ferr, char* rbox_command) {
int i,j,k;
int gendim;
int cubesize, diamondsize, seed=0, count, apex;
int dim=3 , numpoints= 0, totpoints, addpoints=0;
int issphere=0, isaxis=0, iscdd= 0, islens= 0, isregular=0, iswidth=0, addcube=0;
int isgap=0, isspiral=0, NOcommand= 0, adddiamond=0;
int israndom=0, istime=0;
int isbox=0, issimplex=0, issimplex2=0, ismesh=0;
double width=0.0, gap=0.0, radius= 0.0;
double coord[MAXdim], offset, meshm=3.0, meshn=4.0, meshr=5.0;
double *simplex= NULL, *simplexp;
int nthroot, mult[MAXdim];
double norm, factor, randr, rangap, lensangle= 0, lensbase= 1;
double anglediff, angle, x, y, cube= 0.0, diamond= 0.0;
double box= qh_DEFAULTbox; /* scale all numbers before output */
double randmax= qh_RANDOMmax;
char command[200], seedbuf[200];
char *s= command, *t, *first_point= NULL;
time_t timedata = 0;
int exitcode;
if (rbox_inuse) {
qh_fprintf_rbox(rbox.ferr, 6188, "rbox error: rbox in use by another process. Please lock calls to rbox.\n");
return qh_ERRqhull;
}
rbox_inuse= True;
rbox.ferr= ferr;
rbox.fout= fout;
exitcode= setjmp(rbox.errexit);
if (exitcode) {
/* same code for error exit and normal return */
if (simplex)
qh_free(simplex);
rbox_inuse= False;
return exitcode;
}
*command= '\0';
strncat(command, rbox_command, sizeof(command)-strlen(command)-1);
while (*s && !isspace(*s)) /* skip program name */
s++;
while (*s) {
while (*s && isspace(*s))
s++;
if (*s == '-')
s++;
if (!*s)
break;
if (isdigit(*s)) {
numpoints= qh_strtol(s, &s);
continue;
}
/* ============= read flags =============== */
switch (*s++) {
case 'c':
addcube= 1;
t= s;
while (isspace(*t))
t++;
if (*t == 'G')
cube= qh_strtod(++t, &s);
break;
case 'd':
adddiamond= 1;
t= s;
while (isspace(*t))
t++;
if (*t == 'G')
diamond= qh_strtod(++t, &s);
break;
case 'h':
iscdd= 1;
break;
case 'l':
isspiral= 1;
break;
case 'n':
NOcommand= 1;
break;
case 'r':
isregular= 1;
break;
case 's':
issphere= 1;
break;
case 't':
istime= 1;
if (isdigit(*s)) {
seed= qh_strtol(s, &s);
israndom= 0;
}else
israndom= 1;
break;
case 'x':
issimplex= 1;
break;
case 'y':
issimplex2= 1;
break;
case 'z':
rbox.isinteger= 1;
break;
case 'B':
box= qh_strtod(s, &s);
isbox= 1;
break;
case 'D':
dim= qh_strtol(s, &s);
if (dim < 1
|| dim > MAXdim) {
qh_fprintf_rbox(rbox.ferr, 6189, "rbox error: dimension, D%d, out of bounds (>=%d or <=0)", dim, MAXdim);
qh_errexit_rbox(qh_ERRinput);
}
break;
case 'G':
if (isdigit(*s))
gap= qh_strtod(s, &s);
else
gap= 0.5;
isgap= 1;
break;
case 'L':
if (isdigit(*s))
radius= qh_strtod(s, &s);
else
radius= 10;
islens= 1;
break;
case 'M':
ismesh= 1;
if (*s)
meshn= qh_strtod(s, &s);
if (*s == ',') {
++s;
meshm= qh_strtod(s, &s);
}else
meshm= 0.0;
if (*s == ',') {
++s;
meshr= qh_strtod(s, &s);
}else
meshr= sqrt(meshn*meshn + meshm*meshm);
if (*s && !isspace(*s)) {
qh_fprintf_rbox(rbox.ferr, 7069, "rbox warning: assuming 'M3,4,5' since mesh args are not integers or reals\n");
meshn= 3.0, meshm=4.0, meshr=5.0;
}
break;
case 'O':
rbox.out_offset= qh_strtod(s, &s);
break;
case 'P':
if (!first_point)
first_point= s-1;
addpoints++;
while (*s && !isspace(*s)) /* read points later */
s++;
break;
case 'W':
width= qh_strtod(s, &s);
iswidth= 1;
break;
case 'Z':
if (isdigit(*s))
radius= qh_strtod(s, &s);
else
radius= 1.0;
isaxis= 1;
break;
default:
qh_fprintf_rbox(rbox.ferr, 7070, "rbox error: unknown flag at %s.\nExecute 'rbox' without arguments for documentation.\n", s);
qh_errexit_rbox(qh_ERRinput);
}
if (*s && !isspace(*s)) {
qh_fprintf_rbox(rbox.ferr, 7071, "rbox error: missing space between flags at %s.\n", s);
qh_errexit_rbox(qh_ERRinput);
}
}
/* ============= defaults, constants, and sizes =============== */
if (rbox.isinteger && !isbox)
box= qh_DEFAULTzbox;
if (addcube) {
cubesize= (int)floor(ldexp(1.0,dim)+0.5);
if (cube == 0.0)
cube= box;
}else
cubesize= 0;
if (adddiamond) {
diamondsize= 2*dim;
if (diamond == 0.0)
diamond= box;
}else
diamondsize= 0;
if (islens) {
if (isaxis) {
qh_fprintf_rbox(rbox.ferr, 6190, "rbox error: can not combine 'Ln' with 'Zn'\n");
qh_errexit_rbox(qh_ERRinput);
}
if (radius <= 1.0) {
qh_fprintf_rbox(rbox.ferr, 6191, "rbox error: lens radius %.2g should be greater than 1.0\n",
radius);
qh_errexit_rbox(qh_ERRinput);
}
lensangle= asin(1.0/radius);
lensbase= radius * cos(lensangle);
}
if (!numpoints) {
if (issimplex2)
; /* ok */
else if (isregular + issimplex + islens + issphere + isaxis + isspiral + iswidth + ismesh) {
qh_fprintf_rbox(rbox.ferr, 6192, "rbox error: missing count\n");
qh_errexit_rbox(qh_ERRinput);
}else if (adddiamond + addcube + addpoints)
; /* ok */
else {
numpoints= 50; /* ./rbox D4 is the test case */
issphere= 1;
}
}
if ((issimplex + islens + isspiral + ismesh > 1)
|| (issimplex + issphere + isspiral + ismesh > 1)) {
qh_fprintf_rbox(rbox.ferr, 6193, "rbox error: can only specify one of 'l', 's', 'x', 'Ln', or 'Mn,m,r' ('Ln s' is ok).\n");
qh_errexit_rbox(qh_ERRinput);
}
/* ============= print header with total points =============== */
if (issimplex || ismesh)
totpoints= numpoints;
else if (issimplex2)
totpoints= numpoints+dim+1;
else if (isregular) {
totpoints= numpoints;
if (dim == 2) {
if (islens)
totpoints += numpoints - 2;
}else if (dim == 3) {
if (islens)
totpoints += 2 * numpoints;
else if (isgap)
totpoints += 1 + numpoints;
else
totpoints += 2;
}
}else
totpoints= numpoints + isaxis;
totpoints += cubesize + diamondsize + addpoints;
/* ============= seed randoms =============== */
if (istime == 0) {
for (s=command; *s; s++) {
if (issimplex2 && *s == 'y') /* make 'y' same seed as 'x' */
i= 'x';
else
i= *s;
seed= 11*seed + i;
}
}else if (israndom) {
seed= (int)time(&timedata);
sprintf(seedbuf, " t%d", seed); /* appends an extra t, not worth removing */
strncat(command, seedbuf, sizeof(command)-strlen(command)-1);
t= strstr(command, " t ");
if (t)
strcpy(t+1, t+3); /* remove " t " */
} /* else, seed explicitly set to n */
qh_RANDOMseed_(seed);
/* ============= print header =============== */
if (iscdd)
qh_fprintf_rbox(rbox.fout, 9391, "%s\nbegin\n %d %d %s\n",
NOcommand ? "" : command,
totpoints, dim+1,
rbox.isinteger ? "integer" : "real");
else if (NOcommand)
qh_fprintf_rbox(rbox.fout, 9392, "%d\n%d\n", dim, totpoints);
else
qh_fprintf_rbox(rbox.fout, 9393, "%d %s\n%d\n", dim, command, totpoints);
/* ============= explicit points =============== */
if ((s= first_point)) {
while (s && *s) { /* 'P' */
count= 0;
if (iscdd)
out1( 1.0);
while (*++s) {
out1( qh_strtod(s, &s));
count++;
if (isspace(*s) || !*s)
break;
if (*s != ',') {
qh_fprintf_rbox(rbox.ferr, 6194, "rbox error: missing comma after coordinate in %s\n\n", s);
qh_errexit_rbox(qh_ERRinput);
}
}
if (count < dim) {
for (k=dim-count; k--; )
out1( 0.0);
}else if (count > dim) {
qh_fprintf_rbox(rbox.ferr, 6195, "rbox error: %d coordinates instead of %d coordinates in %s\n\n",
count, dim, s);
qh_errexit_rbox(qh_ERRinput);
}
qh_fprintf_rbox(rbox.fout, 9394, "\n");
while ((s= strchr(s, 'P'))) {
if (isspace(s[-1]))
break;
}
}
}
/* ============= simplex distribution =============== */
if (issimplex+issimplex2) {
if (!(simplex= (double*)qh_malloc( dim * (dim+1) * sizeof(double)))) {
qh_fprintf_rbox(rbox.ferr, 6196, "rbox error: insufficient memory for simplex\n");
qh_errexit_rbox(qh_ERRmem); /* qh_ERRmem */
}
simplexp= simplex;
if (isregular) {
for (i=0; i<dim; i++) {
for (k=0; k<dim; k++)
*(simplexp++)= i==k ? 1.0 : 0.0;
}
for (k=0; k<dim; k++)
*(simplexp++)= -1.0;
}else {
for (i=0; i<dim+1; i++) {
for (k=0; k<dim; k++) {
randr= qh_RANDOMint;
*(simplexp++)= 2.0 * randr/randmax - 1.0;
}
}
}
if (issimplex2) {
simplexp= simplex;
for (i=0; i<dim+1; i++) {
if (iscdd)
out1( 1.0);
for (k=0; k<dim; k++)
out1( *(simplexp++) * box);
qh_fprintf_rbox(rbox.fout, 9395, "\n");
}
}
for (j=0; j<numpoints; j++) {
if (iswidth)
apex= qh_RANDOMint % (dim+1);
else
apex= -1;
for (k=0; k<dim; k++)
coord[k]= 0.0;
norm= 0.0;
for (i=0; i<dim+1; i++) {
randr= qh_RANDOMint;
factor= randr/randmax;
if (i == apex)
factor *= width;
norm += factor;
for (k=0; k<dim; k++) {
simplexp= simplex + i*dim + k;
coord[k] += factor * (*simplexp);
}
}
for (k=0; k<dim; k++)
coord[k] /= norm;
if (iscdd)
out1( 1.0);
for (k=0; k < dim; k++)
out1( coord[k] * box);
qh_fprintf_rbox(rbox.fout, 9396, "\n");
}
isregular= 0; /* continue with isbox */
numpoints= 0;
}
/* ============= mesh distribution =============== */
if (ismesh) {
nthroot= (int)(pow((double)numpoints, 1.0/dim) + 0.99999);
for (k=dim; k--; )
mult[k]= 0;
for (i=0; i < numpoints; i++) {
for (k=0; k < dim; k++) {
if (k == 0)
out1( mult[0] * meshn + mult[1] * (-meshm));
else if (k == 1)
out1( mult[0] * meshm + mult[1] * meshn);
else
out1( mult[k] * meshr );
}
qh_fprintf_rbox(rbox.fout, 9397, "\n");
for (k=0; k < dim; k++) {
if (++mult[k] < nthroot)
break;
mult[k]= 0;
}
}
}
/* ============= regular points for 's' =============== */
else if (isregular && !islens) {
if (dim != 2 && dim != 3) {
qh_fprintf_rbox(rbox.ferr, 6197, "rbox error: regular points can be used only in 2-d and 3-d\n\n");
qh_errexit_rbox(qh_ERRinput);
}
if (!isaxis || radius == 0.0) {
isaxis= 1;
radius= 1.0;
}
if (dim == 3) {
if (iscdd)
out1( 1.0);
out3n( 0.0, 0.0, -box);
if (!isgap) {
if (iscdd)
out1( 1.0);
out3n( 0.0, 0.0, box);
}
}
angle= 0.0;
anglediff= 2.0 * M_PI/numpoints;
for (i=0; i < numpoints; i++) {
angle += anglediff;
x= radius * cos(angle);
y= radius * sin(angle);
if (dim == 2) {
if (iscdd)
out1( 1.0);
out2n( x*box, y*box);
}else {
norm= sqrt(1.0 + x*x + y*y);
if (iscdd)
out1( 1.0);
out3n( box*x/norm, box*y/norm, box/norm);
if (isgap) {
x *= 1-gap;
y *= 1-gap;
norm= sqrt(1.0 + x*x + y*y);
if (iscdd)
out1( 1.0);
out3n( box*x/norm, box*y/norm, box/norm);
}
}
}
}
/* ============= regular points for 'r Ln D2' =============== */
else if (isregular && islens && dim == 2) {
double cos_0;
angle= lensangle;
anglediff= 2 * lensangle/(numpoints - 1);
cos_0= cos(lensangle);
for (i=0; i < numpoints; i++, angle -= anglediff) {
x= radius * sin(angle);
y= radius * (cos(angle) - cos_0);
if (iscdd)
out1( 1.0);
out2n( x*box, y*box);
if (i != 0 && i != numpoints - 1) {
if (iscdd)
out1( 1.0);
out2n( x*box, -y*box);
}
}
}
/* ============= regular points for 'r Ln D3' =============== */
else if (isregular && islens && dim != 2) {
if (dim != 3) {
qh_fprintf_rbox(rbox.ferr, 6198, "rbox error: regular points can be used only in 2-d and 3-d\n\n");
qh_errexit_rbox(qh_ERRinput);
}
angle= 0.0;
anglediff= 2* M_PI/numpoints;
if (!isgap) {
isgap= 1;
gap= 0.5;
}
offset= sqrt(radius * radius - (1-gap)*(1-gap)) - lensbase;
for (i=0; i < numpoints; i++, angle += anglediff) {
x= cos(angle);
y= sin(angle);
if (iscdd)
out1( 1.0);
out3n( box*x, box*y, 0.0);
x *= 1-gap;
y *= 1-gap;
if (iscdd)
out1( 1.0);
out3n( box*x, box*y, box * offset);
if (iscdd)
out1( 1.0);
out3n( box*x, box*y, -box * offset);
}
}
/* ============= apex of 'Zn' distribution + gendim =============== */
else {
if (isaxis) {
gendim= dim-1;
if (iscdd)
out1( 1.0);
for (j=0; j < gendim; j++)
out1( 0.0);
out1( -box);
qh_fprintf_rbox(rbox.fout, 9398, "\n");
}else if (islens)
gendim= dim-1;
else
gendim= dim;
/* ============= generate random point in unit cube =============== */
for (i=0; i < numpoints; i++) {
norm= 0.0;
for (j=0; j < gendim; j++) {
randr= qh_RANDOMint;
coord[j]= 2.0 * randr/randmax - 1.0;
norm += coord[j] * coord[j];
}
norm= sqrt(norm);
/* ============= dim-1 point of 'Zn' distribution ========== */
if (isaxis) {
if (!isgap) {
isgap= 1;
gap= 1.0;
}
randr= qh_RANDOMint;
rangap= 1.0 - gap * randr/randmax;
factor= radius * rangap / norm;
for (j=0; j<gendim; j++)
coord[j]= factor * coord[j];
/* ============= dim-1 point of 'Ln s' distribution =========== */
}else if (islens && issphere) {
if (!isgap) {
isgap= 1;
gap= 1.0;
}
randr= qh_RANDOMint;
rangap= 1.0 - gap * randr/randmax;
factor= rangap / norm;
for (j=0; j<gendim; j++)
coord[j]= factor * coord[j];
/* ============= dim-1 point of 'Ln' distribution ========== */
}else if (islens && !issphere) {
if (!isgap) {
isgap= 1;
gap= 1.0;
}
j= qh_RANDOMint % gendim;
if (coord[j] < 0)
coord[j]= -1.0 - coord[j] * gap;
else
coord[j]= 1.0 - coord[j] * gap;
/* ============= point of 'l' distribution =============== */
}else if (isspiral) {
if (dim != 3) {
qh_fprintf_rbox(rbox.ferr, 6199, "rbox error: spiral distribution is available only in 3d\n\n");
longjmp(rbox.errexit,qh_ERRinput);
}
coord[0]= cos(2*M_PI*i/(numpoints - 1));
coord[1]= sin(2*M_PI*i/(numpoints - 1));
coord[2]= 2.0*(double)i/(double)(numpoints-1) - 1.0;
/* ============= point of 's' distribution =============== */
}else if (issphere) {
factor= 1.0/norm;
if (iswidth) {
randr= qh_RANDOMint;
factor *= 1.0 - width * randr/randmax;
}
for (j=0; j<dim; j++)
coord[j]= factor * coord[j];
}
/* ============= project 'Zn s' point in to sphere =============== */
if (isaxis && issphere) {
coord[dim-1]= 1.0;
norm= 1.0;
for (j=0; j<gendim; j++)
norm += coord[j] * coord[j];
norm= sqrt(norm);
for (j=0; j<dim; j++)
coord[j]= coord[j] / norm;
if (iswidth) {
randr= qh_RANDOMint;
coord[dim-1] *= 1 - width * randr/randmax;
}
/* ============= project 'Zn' point onto cube =============== */
}else if (isaxis && !issphere) { /* not very interesting */
randr= qh_RANDOMint;
coord[dim-1]= 2.0 * randr/randmax - 1.0;
/* ============= project 'Ln' point out to sphere =============== */
}else if (islens) {
coord[dim-1]= lensbase;
for (j=0, norm= 0; j<dim; j++)
norm += coord[j] * coord[j];
norm= sqrt(norm);
for (j=0; j<dim; j++)
coord[j]= coord[j] * radius/ norm;
coord[dim-1] -= lensbase;
if (iswidth) {
randr= qh_RANDOMint;
coord[dim-1] *= 1 - width * randr/randmax;
}
if (qh_RANDOMint > randmax/2)
coord[dim-1]= -coord[dim-1];
/* ============= project 'Wn' point toward boundary =============== */
}else if (iswidth && !issphere) {
j= qh_RANDOMint % gendim;
if (coord[j] < 0)
coord[j]= -1.0 - coord[j] * width;
else
coord[j]= 1.0 - coord[j] * width;
}
/* ============= write point =============== */
if (iscdd)
out1( 1.0);
for (k=0; k < dim; k++)
out1( coord[k] * box);
qh_fprintf_rbox(rbox.fout, 9399, "\n");
}
}
/* ============= write cube vertices =============== */
if (addcube) {
for (j=0; j<cubesize; j++) {
if (iscdd)
out1( 1.0);
for (k=dim-1; k>=0; k--) {
if (j & ( 1 << k))
out1( cube);
else
out1( -cube);
}
qh_fprintf_rbox(rbox.fout, 9400, "\n");
}
}
/* ============= write diamond vertices =============== */
if (adddiamond) {
for (j=0; j<diamondsize; j++) {
if (iscdd)
out1( 1.0);
for (k=dim-1; k>=0; k--) {
if (j/2 != k)
out1( 0.0);
else if (j & 0x1)
out1( diamond);
else
out1( -diamond);
}
qh_fprintf_rbox(rbox.fout, 9401, "\n");
}
}
if (iscdd)
qh_fprintf_rbox(rbox.fout, 9402, "end\nhull\n");
/* same code for error exit and normal return */
if (simplex)
qh_free(simplex);
rbox_inuse= False;
return qh_ERRnone;
} /* rboxpoints */
/*------------------------------------------------
outxxx - output functions
*/
int roundi( double a) {
if (a < 0.0) {
if (a - 0.5 < INT_MIN) {
qh_fprintf_rbox(rbox.ferr, 6200, "rbox input error: negative coordinate %2.2g is too large. Reduce 'Bn'\n", a);
qh_errexit_rbox(qh_ERRinput);
}
return (int)(a - 0.5);
}else {
if (a + 0.5 > INT_MAX) {
qh_fprintf_rbox(rbox.ferr, 6201, "rbox input error: coordinate %2.2g is too large. Reduce 'Bn'\n", a);
qh_errexit_rbox(qh_ERRinput);
}
return (int)(a + 0.5);
}
} /* roundi */
void out1(double a) {
if (rbox.isinteger)
qh_fprintf_rbox(rbox.fout, 9403, "%d ", roundi( a+rbox.out_offset));
else
qh_fprintf_rbox(rbox.fout, 9404, qh_REAL_1, a+rbox.out_offset);
} /* out1 */
void out2n( double a, double b) {
if (rbox.isinteger)
qh_fprintf_rbox(rbox.fout, 9405, "%d %d\n", roundi(a+rbox.out_offset), roundi(b+rbox.out_offset));
else
qh_fprintf_rbox(rbox.fout, 9406, qh_REAL_2n, a+rbox.out_offset, b+rbox.out_offset);
} /* out2n */
void out3n( double a, double b, double c) {
if (rbox.isinteger)
qh_fprintf_rbox(rbox.fout, 9407, "%d %d %d\n", roundi(a+rbox.out_offset), roundi(b+rbox.out_offset), roundi(c+rbox.out_offset));
else
qh_fprintf_rbox(rbox.fout, 9408, qh_REAL_3n, a+rbox.out_offset, b+rbox.out_offset, c+rbox.out_offset);
} /* out3n */
void qh_errexit_rbox(int exitcode)
{
longjmp(rbox.errexit, exitcode);
} /* rbox_errexit */

View File

@@ -0,0 +1,714 @@
/*<html><pre> -<a href="qh-stat.htm"
>-------------------------------</a><a name="TOP">-</a>
stat.c
contains all statistics that are collected for qhull
see qh-stat.htm and stat.h
Copyright (c) 1993-2012 The Geometry Center.
$Id: //main/2011/qhull/src/libqhull/stat.c#3 $$Change: 1464 $
$DateTime: 2012/01/25 22:58:41 $$Author: bbarber $
*/
#include "qhull_a.h"
/*============ global data structure ==========*/
#if qh_QHpointer
qhstatT *qh_qhstat=NULL; /* global data structure */
#else
qhstatT qh_qhstat; /* add "={0}" if this causes a compiler error */
#endif
/*========== functions in alphabetic order ================*/
/*-<a href="qh-stat.htm#TOC"
>-------------------------------</a><a name="allstatA">-</a>
qh_allstatA()
define statistics in groups of 20
notes:
(otherwise, 'gcc -O2' uses too much memory)
uses qhstat.next
*/
void qh_allstatA(void) {
/* zdef_(type,name,doc,average) */
zzdef_(zdoc, Zdoc2, "precision statistics", -1);
zdef_(zinc, Znewvertex, NULL, -1);
zdef_(wadd, Wnewvertex, "ave. distance of a new vertex to a facet(!0s)", Znewvertex);
zzdef_(wmax, Wnewvertexmax, "max. distance of a new vertex to a facet", -1);
zdef_(wmax, Wvertexmax, "max. distance of an output vertex to a facet", -1);
zdef_(wmin, Wvertexmin, "min. distance of an output vertex to a facet", -1);
zdef_(wmin, Wmindenom, "min. denominator in hyperplane computation", -1);
qhstat precision= qhstat next; /* call qh_precision for each of these */
zzdef_(zdoc, Zdoc3, "precision problems (corrected unless 'Q0' or an error)", -1);
zzdef_(zinc, Zcoplanarridges, "coplanar half ridges in output", -1);
zzdef_(zinc, Zconcaveridges, "concave half ridges in output", -1);
zzdef_(zinc, Zflippedfacets, "flipped facets", -1);
zzdef_(zinc, Zcoplanarhorizon, "coplanar horizon facets for new vertices", -1);
zzdef_(zinc, Zcoplanarpart, "coplanar points during partitioning", -1);
zzdef_(zinc, Zminnorm, "degenerate hyperplanes recomputed with gaussian elimination", -1);
zzdef_(zinc, Znearlysingular, "nearly singular or axis-parallel hyperplanes", -1);
zzdef_(zinc, Zback0, "zero divisors during back substitute", -1);
zzdef_(zinc, Zgauss0, "zero divisors during gaussian elimination", -1);
zzdef_(zinc, Zmultiridge, "ridges with multiple neighbors", -1);
}
void qh_allstatB(void) {
zzdef_(zdoc, Zdoc1, "summary information", -1);
zdef_(zinc, Zvertices, "number of vertices in output", -1);
zdef_(zinc, Znumfacets, "number of facets in output", -1);
zdef_(zinc, Znonsimplicial, "number of non-simplicial facets in output", -1);
zdef_(zinc, Znowsimplicial, "number of simplicial facets that were merged", -1);
zdef_(zinc, Znumridges, "number of ridges in output", -1);
zdef_(zadd, Znumridges, "average number of ridges per facet", Znumfacets);
zdef_(zmax, Zmaxridges, "maximum number of ridges", -1);
zdef_(zadd, Znumneighbors, "average number of neighbors per facet", Znumfacets);
zdef_(zmax, Zmaxneighbors, "maximum number of neighbors", -1);
zdef_(zadd, Znumvertices, "average number of vertices per facet", Znumfacets);
zdef_(zmax, Zmaxvertices, "maximum number of vertices", -1);
zdef_(zadd, Znumvneighbors, "average number of neighbors per vertex", Zvertices);
zdef_(zmax, Zmaxvneighbors, "maximum number of neighbors", -1);
zdef_(wadd, Wcpu, "cpu seconds for qhull after input", -1);
zdef_(zinc, Ztotvertices, "vertices created altogether", -1);
zzdef_(zinc, Zsetplane, "facets created altogether", -1);
zdef_(zinc, Ztotridges, "ridges created altogether", -1);
zdef_(zinc, Zpostfacets, "facets before post merge", -1);
zdef_(zadd, Znummergetot, "average merges per facet(at most 511)", Znumfacets);
zdef_(zmax, Znummergemax, " maximum merges for a facet(at most 511)", -1);
zdef_(zinc, Zangle, NULL, -1);
zdef_(wadd, Wangle, "average angle(cosine) of facet normals for all ridges", Zangle);
zdef_(wmax, Wanglemax, " maximum angle(cosine) of facet normals across a ridge", -1);
zdef_(wmin, Wanglemin, " minimum angle(cosine) of facet normals across a ridge", -1);
zdef_(wadd, Wareatot, "total area of facets", -1);
zdef_(wmax, Wareamax, " maximum facet area", -1);
zdef_(wmin, Wareamin, " minimum facet area", -1);
}
void qh_allstatC(void) {
zdef_(zdoc, Zdoc9, "build hull statistics", -1);
zzdef_(zinc, Zprocessed, "points processed", -1);
zzdef_(zinc, Zretry, "retries due to precision problems", -1);
zdef_(wmax, Wretrymax, " max. random joggle", -1);
zdef_(zmax, Zmaxvertex, "max. vertices at any one time", -1);
zdef_(zinc, Ztotvisible, "ave. visible facets per iteration", Zprocessed);
zdef_(zinc, Zinsidevisible, " ave. visible facets without an horizon neighbor", Zprocessed);
zdef_(zadd, Zvisfacettot, " ave. facets deleted per iteration", Zprocessed);
zdef_(zmax, Zvisfacetmax, " maximum", -1);
zdef_(zadd, Zvisvertextot, "ave. visible vertices per iteration", Zprocessed);
zdef_(zmax, Zvisvertexmax, " maximum", -1);
zdef_(zinc, Ztothorizon, "ave. horizon facets per iteration", Zprocessed);
zdef_(zadd, Znewfacettot, "ave. new or merged facets per iteration", Zprocessed);
zdef_(zmax, Znewfacetmax, " maximum(includes initial simplex)", -1);
zdef_(wadd, Wnewbalance, "average new facet balance", Zprocessed);
zdef_(wadd, Wnewbalance2, " standard deviation", -1);
zdef_(wadd, Wpbalance, "average partition balance", Zpbalance);
zdef_(wadd, Wpbalance2, " standard deviation", -1);
zdef_(zinc, Zpbalance, " number of trials", -1);
zdef_(zinc, Zsearchpoints, "searches of all points for initial simplex", -1);
zdef_(zinc, Zdetsimplex, "determinants computed(area & initial hull)", -1);
zdef_(zinc, Znoarea, "determinants not computed because vertex too low", -1);
zdef_(zinc, Znotmax, "points ignored(!above max_outside)", -1);
zdef_(zinc, Znotgood, "points ignored(!above a good facet)", -1);
zdef_(zinc, Znotgoodnew, "points ignored(didn't create a good new facet)", -1);
zdef_(zinc, Zgoodfacet, "good facets found", -1);
zzdef_(zinc, Znumvisibility, "distance tests for facet visibility", -1);
zdef_(zinc, Zdistvertex, "distance tests to report minimum vertex", -1);
zzdef_(zinc, Ztotcheck, "points checked for facets' outer planes", -1);
zzdef_(zinc, Zcheckpart, " ave. distance tests per check", Ztotcheck);
}
void qh_allstatD(void) {
zdef_(zinc, Zvisit, "resets of visit_id", -1);
zdef_(zinc, Zvvisit, " resets of vertex_visit", -1);
zdef_(zmax, Zvisit2max, " max visit_id/2", -1);
zdef_(zmax, Zvvisit2max, " max vertex_visit/2", -1);
zdef_(zdoc, Zdoc4, "partitioning statistics(see previous for outer planes)", -1);
zzdef_(zadd, Zdelvertextot, "total vertices deleted", -1);
zdef_(zmax, Zdelvertexmax, " maximum vertices deleted per iteration", -1);
zdef_(zinc, Zfindbest, "calls to findbest", -1);
zdef_(zadd, Zfindbesttot, " ave. facets tested", Zfindbest);
zdef_(zmax, Zfindbestmax, " max. facets tested", -1);
zdef_(zadd, Zfindcoplanar, " ave. coplanar search", Zfindbest);
zdef_(zinc, Zfindnew, "calls to findbestnew", -1);
zdef_(zadd, Zfindnewtot, " ave. facets tested", Zfindnew);
zdef_(zmax, Zfindnewmax, " max. facets tested", -1);
zdef_(zinc, Zfindnewjump, " ave. clearly better", Zfindnew);
zdef_(zinc, Zfindnewsharp, " calls due to qh_sharpnewfacets", -1);
zdef_(zinc, Zfindhorizon, "calls to findhorizon", -1);
zdef_(zadd, Zfindhorizontot, " ave. facets tested", Zfindhorizon);
zdef_(zmax, Zfindhorizonmax, " max. facets tested", -1);
zdef_(zinc, Zfindjump, " ave. clearly better", Zfindhorizon);
zdef_(zinc, Zparthorizon, " horizon facets better than bestfacet", -1);
zdef_(zinc, Zpartangle, "angle tests for repartitioned coplanar points", -1);
zdef_(zinc, Zpartflip, " repartitioned coplanar points for flipped orientation", -1);
}
void qh_allstatE(void) {
zdef_(zinc, Zpartinside, "inside points", -1);
zdef_(zinc, Zpartnear, " inside points kept with a facet", -1);
zdef_(zinc, Zcoplanarinside, " inside points that were coplanar with a facet", -1);
zdef_(zinc, Zbestlower, "calls to findbestlower", -1);
zdef_(zinc, Zbestlowerv, " with search of vertex neighbors", -1);
zdef_(wadd, Wmaxout, "difference in max_outside at final check", -1);
zzdef_(zinc, Zpartitionall, "distance tests for initial partition", -1);
zdef_(zinc, Ztotpartition, "partitions of a point", -1);
zzdef_(zinc, Zpartition, "distance tests for partitioning", -1);
zzdef_(zinc, Zdistcheck, "distance tests for checking flipped facets", -1);
zzdef_(zinc, Zdistconvex, "distance tests for checking convexity", -1);
zdef_(zinc, Zdistgood, "distance tests for checking good point", -1);
zdef_(zinc, Zdistio, "distance tests for output", -1);
zdef_(zinc, Zdiststat, "distance tests for statistics", -1);
zdef_(zinc, Zdistplane, "total number of distance tests", -1);
zdef_(zinc, Ztotpartcoplanar, "partitions of coplanar points or deleted vertices", -1);
zzdef_(zinc, Zpartcoplanar, " distance tests for these partitions", -1);
zdef_(zinc, Zcomputefurthest, "distance tests for computing furthest", -1);
}
void qh_allstatE2(void) {
zdef_(zdoc, Zdoc5, "statistics for matching ridges", -1);
zdef_(zinc, Zhashlookup, "total lookups for matching ridges of new facets", -1);
zdef_(zinc, Zhashtests, "average number of tests to match a ridge", Zhashlookup);
zdef_(zinc, Zhashridge, "total lookups of subridges(duplicates and boundary)", -1);
zdef_(zinc, Zhashridgetest, "average number of tests per subridge", Zhashridge);
zdef_(zinc, Zdupsame, "duplicated ridges in same merge cycle", -1);
zdef_(zinc, Zdupflip, "duplicated ridges with flipped facets", -1);
zdef_(zdoc, Zdoc6, "statistics for determining merges", -1);
zdef_(zinc, Zangletests, "angles computed for ridge convexity", -1);
zdef_(zinc, Zbestcentrum, "best merges used centrum instead of vertices",-1);
zzdef_(zinc, Zbestdist, "distance tests for best merge", -1);
zzdef_(zinc, Zcentrumtests, "distance tests for centrum convexity", -1);
zzdef_(zinc, Zdistzero, "distance tests for checking simplicial convexity", -1);
zdef_(zinc, Zcoplanarangle, "coplanar angles in getmergeset", -1);
zdef_(zinc, Zcoplanarcentrum, "coplanar centrums in getmergeset", -1);
zdef_(zinc, Zconcaveridge, "concave ridges in getmergeset", -1);
}
void qh_allstatF(void) {
zdef_(zdoc, Zdoc7, "statistics for merging", -1);
zdef_(zinc, Zpremergetot, "merge iterations", -1);
zdef_(zadd, Zmergeinittot, "ave. initial non-convex ridges per iteration", Zpremergetot);
zdef_(zadd, Zmergeinitmax, " maximum", -1);
zdef_(zadd, Zmergesettot, " ave. additional non-convex ridges per iteration", Zpremergetot);
zdef_(zadd, Zmergesetmax, " maximum additional in one pass", -1);
zdef_(zadd, Zmergeinittot2, "initial non-convex ridges for post merging", -1);
zdef_(zadd, Zmergesettot2, " additional non-convex ridges", -1);
zdef_(wmax, Wmaxoutside, "max distance of vertex or coplanar point above facet(w/roundoff)", -1);
zdef_(wmin, Wminvertex, "max distance of merged vertex below facet(or roundoff)", -1);
zdef_(zinc, Zwidefacet, "centrums frozen due to a wide merge", -1);
zdef_(zinc, Zwidevertices, "centrums frozen due to extra vertices", -1);
zzdef_(zinc, Ztotmerge, "total number of facets or cycles of facets merged", -1);
zdef_(zinc, Zmergesimplex, "merged a simplex", -1);
zdef_(zinc, Zonehorizon, "simplices merged into coplanar horizon", -1);
zzdef_(zinc, Zcyclehorizon, "cycles of facets merged into coplanar horizon", -1);
zzdef_(zadd, Zcyclefacettot, " ave. facets per cycle", Zcyclehorizon);
zdef_(zmax, Zcyclefacetmax, " max. facets", -1);
zdef_(zinc, Zmergeintohorizon, "new facets merged into horizon", -1);
zdef_(zinc, Zmergenew, "new facets merged", -1);
zdef_(zinc, Zmergehorizon, "horizon facets merged into new facets", -1);
zdef_(zinc, Zmergevertex, "vertices deleted by merging", -1);
zdef_(zinc, Zcyclevertex, "vertices deleted by merging into coplanar horizon", -1);
zdef_(zinc, Zdegenvertex, "vertices deleted by degenerate facet", -1);
zdef_(zinc, Zmergeflipdup, "merges due to flipped facets in duplicated ridge", -1);
zdef_(zinc, Zneighbor, "merges due to redundant neighbors", -1);
zdef_(zadd, Ztestvneighbor, "non-convex vertex neighbors", -1);
}
void qh_allstatG(void) {
zdef_(zinc, Zacoplanar, "merges due to angle coplanar facets", -1);
zdef_(wadd, Wacoplanartot, " average merge distance", Zacoplanar);
zdef_(wmax, Wacoplanarmax, " maximum merge distance", -1);
zdef_(zinc, Zcoplanar, "merges due to coplanar facets", -1);
zdef_(wadd, Wcoplanartot, " average merge distance", Zcoplanar);
zdef_(wmax, Wcoplanarmax, " maximum merge distance", -1);
zdef_(zinc, Zconcave, "merges due to concave facets", -1);
zdef_(wadd, Wconcavetot, " average merge distance", Zconcave);
zdef_(wmax, Wconcavemax, " maximum merge distance", -1);
zdef_(zinc, Zavoidold, "coplanar/concave merges due to avoiding old merge", -1);
zdef_(wadd, Wavoidoldtot, " average merge distance", Zavoidold);
zdef_(wmax, Wavoidoldmax, " maximum merge distance", -1);
zdef_(zinc, Zdegen, "merges due to degenerate facets", -1);
zdef_(wadd, Wdegentot, " average merge distance", Zdegen);
zdef_(wmax, Wdegenmax, " maximum merge distance", -1);
zdef_(zinc, Zflipped, "merges due to removing flipped facets", -1);
zdef_(wadd, Wflippedtot, " average merge distance", Zflipped);
zdef_(wmax, Wflippedmax, " maximum merge distance", -1);
zdef_(zinc, Zduplicate, "merges due to duplicated ridges", -1);
zdef_(wadd, Wduplicatetot, " average merge distance", Zduplicate);
zdef_(wmax, Wduplicatemax, " maximum merge distance", -1);
}
void qh_allstatH(void) {
zdef_(zdoc, Zdoc8, "renamed vertex statistics", -1);
zdef_(zinc, Zrenameshare, "renamed vertices shared by two facets", -1);
zdef_(zinc, Zrenamepinch, "renamed vertices in a pinched facet", -1);
zdef_(zinc, Zrenameall, "renamed vertices shared by multiple facets", -1);
zdef_(zinc, Zfindfail, "rename failures due to duplicated ridges", -1);
zdef_(zinc, Zdupridge, " duplicate ridges detected", -1);
zdef_(zinc, Zdelridge, "deleted ridges due to renamed vertices", -1);
zdef_(zinc, Zdropneighbor, "dropped neighbors due to renamed vertices", -1);
zdef_(zinc, Zdropdegen, "degenerate facets due to dropped neighbors", -1);
zdef_(zinc, Zdelfacetdup, " facets deleted because of no neighbors", -1);
zdef_(zinc, Zremvertex, "vertices removed from facets due to no ridges", -1);
zdef_(zinc, Zremvertexdel, " deleted", -1);
zdef_(zinc, Zintersectnum, "vertex intersections for locating redundant vertices", -1);
zdef_(zinc, Zintersectfail, "intersections failed to find a redundant vertex", -1);
zdef_(zinc, Zintersect, "intersections found redundant vertices", -1);
zdef_(zadd, Zintersecttot, " ave. number found per vertex", Zintersect);
zdef_(zmax, Zintersectmax, " max. found for a vertex", -1);
zdef_(zinc, Zvertexridge, NULL, -1);
zdef_(zadd, Zvertexridgetot, " ave. number of ridges per tested vertex", Zvertexridge);
zdef_(zmax, Zvertexridgemax, " max. number of ridges per tested vertex", -1);
zdef_(zdoc, Zdoc10, "memory usage statistics(in bytes)", -1);
zdef_(zadd, Zmemfacets, "for facets and their normals, neighbor and vertex sets", -1);
zdef_(zadd, Zmemvertices, "for vertices and their neighbor sets", -1);
zdef_(zadd, Zmempoints, "for input points and outside and coplanar sets",-1);
zdef_(zadd, Zmemridges, "for ridges and their vertex sets", -1);
} /* allstat */
void qh_allstatI(void) {
qhstat vridges= qhstat next;
zzdef_(zdoc, Zdoc11, "Voronoi ridge statistics", -1);
zzdef_(zinc, Zridge, "non-simplicial Voronoi vertices for all ridges", -1);
zzdef_(wadd, Wridge, " ave. distance to ridge", Zridge);
zzdef_(wmax, Wridgemax, " max. distance to ridge", -1);
zzdef_(zinc, Zridgemid, "bounded ridges", -1);
zzdef_(wadd, Wridgemid, " ave. distance of midpoint to ridge", Zridgemid);
zzdef_(wmax, Wridgemidmax, " max. distance of midpoint to ridge", -1);
zzdef_(zinc, Zridgeok, "bounded ridges with ok normal", -1);
zzdef_(wadd, Wridgeok, " ave. angle to ridge", Zridgeok);
zzdef_(wmax, Wridgeokmax, " max. angle to ridge", -1);
zzdef_(zinc, Zridge0, "bounded ridges with near-zero normal", -1);
zzdef_(wadd, Wridge0, " ave. angle to ridge", Zridge0);
zzdef_(wmax, Wridge0max, " max. angle to ridge", -1);
zdef_(zdoc, Zdoc12, "Triangulation statistics(Qt)", -1);
zdef_(zinc, Ztricoplanar, "non-simplicial facets triangulated", -1);
zdef_(zadd, Ztricoplanartot, " ave. new facets created(may be deleted)", Ztricoplanar);
zdef_(zmax, Ztricoplanarmax, " max. new facets created", -1);
zdef_(zinc, Ztrinull, "null new facets deleted(duplicated vertex)", -1);
zdef_(zinc, Ztrimirror, "mirrored pairs of new facets deleted(same vertices)", -1);
zdef_(zinc, Ztridegen, "degenerate new facets in output(same ridge)", -1);
} /* allstat */
/*-<a href="qh-stat.htm#TOC"
>-------------------------------</a><a name="allstatistics">-</a>
qh_allstatistics()
reset printed flag for all statistics
*/
void qh_allstatistics(void) {
int i;
for(i=ZEND; i--; )
qhstat printed[i]= False;
} /* allstatistics */
#if qh_KEEPstatistics
/*-<a href="qh-stat.htm#TOC"
>-------------------------------</a><a name="collectstatistics">-</a>
qh_collectstatistics()
collect statistics for qh.facet_list
*/
void qh_collectstatistics(void) {
facetT *facet, *neighbor, **neighborp;
vertexT *vertex, **vertexp;
realT dotproduct, dist;
int sizneighbors, sizridges, sizvertices, i;
qh old_randomdist= qh RANDOMdist;
qh RANDOMdist= False;
zval_(Zmempoints)= qh num_points * qh normal_size +
sizeof(qhT) + sizeof(qhstatT);
zval_(Zmemfacets)= 0;
zval_(Zmemridges)= 0;
zval_(Zmemvertices)= 0;
zval_(Zangle)= 0;
wval_(Wangle)= 0.0;
zval_(Znumridges)= 0;
zval_(Znumfacets)= 0;
zval_(Znumneighbors)= 0;
zval_(Znumvertices)= 0;
zval_(Znumvneighbors)= 0;
zval_(Znummergetot)= 0;
zval_(Znummergemax)= 0;
zval_(Zvertices)= qh num_vertices - qh_setsize(qh del_vertices);
if (qh MERGING || qh APPROXhull || qh JOGGLEmax < REALmax/2)
wmax_(Wmaxoutside, qh max_outside);
if (qh MERGING)
wmin_(Wminvertex, qh min_vertex);
FORALLfacets
facet->seen= False;
if (qh DELAUNAY) {
FORALLfacets {
if (facet->upperdelaunay != qh UPPERdelaunay)
facet->seen= True; /* remove from angle statistics */
}
}
FORALLfacets {
if (facet->visible && qh NEWfacets)
continue;
sizvertices= qh_setsize(facet->vertices);
sizneighbors= qh_setsize(facet->neighbors);
sizridges= qh_setsize(facet->ridges);
zinc_(Znumfacets);
zadd_(Znumvertices, sizvertices);
zmax_(Zmaxvertices, sizvertices);
zadd_(Znumneighbors, sizneighbors);
zmax_(Zmaxneighbors, sizneighbors);
zadd_(Znummergetot, facet->nummerge);
i= facet->nummerge; /* avoid warnings */
zmax_(Znummergemax, i);
if (!facet->simplicial) {
if (sizvertices == qh hull_dim) {
zinc_(Znowsimplicial);
}else {
zinc_(Znonsimplicial);
}
}
if (sizridges) {
zadd_(Znumridges, sizridges);
zmax_(Zmaxridges, sizridges);
}
zadd_(Zmemfacets, sizeof(facetT) + qh normal_size + 2*sizeof(setT)
+ SETelemsize * (sizneighbors + sizvertices));
if (facet->ridges) {
zadd_(Zmemridges,
sizeof(setT) + SETelemsize * sizridges + sizridges *
(sizeof(ridgeT) + sizeof(setT) + SETelemsize * (qh hull_dim-1))/2);
}
if (facet->outsideset)
zadd_(Zmempoints, sizeof(setT) + SETelemsize * qh_setsize(facet->outsideset));
if (facet->coplanarset)
zadd_(Zmempoints, sizeof(setT) + SETelemsize * qh_setsize(facet->coplanarset));
if (facet->seen) /* Delaunay upper envelope */
continue;
facet->seen= True;
FOREACHneighbor_(facet) {
if (neighbor == qh_DUPLICATEridge || neighbor == qh_MERGEridge
|| neighbor->seen || !facet->normal || !neighbor->normal)
continue;
dotproduct= qh_getangle(facet->normal, neighbor->normal);
zinc_(Zangle);
wadd_(Wangle, dotproduct);
wmax_(Wanglemax, dotproduct)
wmin_(Wanglemin, dotproduct)
}
if (facet->normal) {
FOREACHvertex_(facet->vertices) {
zinc_(Zdiststat);
qh_distplane(vertex->point, facet, &dist);
wmax_(Wvertexmax, dist);
wmin_(Wvertexmin, dist);
}
}
}
FORALLvertices {
if (vertex->deleted)
continue;
zadd_(Zmemvertices, sizeof(vertexT));
if (vertex->neighbors) {
sizneighbors= qh_setsize(vertex->neighbors);
zadd_(Znumvneighbors, sizneighbors);
zmax_(Zmaxvneighbors, sizneighbors);
zadd_(Zmemvertices, sizeof(vertexT) + SETelemsize * sizneighbors);
}
}
qh RANDOMdist= qh old_randomdist;
} /* collectstatistics */
#endif /* qh_KEEPstatistics */
/*-<a href="qh-stat.htm#TOC"
>-------------------------------</a><a name="freestatistics">-</a>
qh_freestatistics( )
free memory used for statistics
*/
void qh_freestatistics(void) {
#if qh_QHpointer
qh_free(qh_qhstat);
qh_qhstat= NULL;
#endif
} /* freestatistics */
/*-<a href="qh-stat.htm#TOC"
>-------------------------------</a><a name="initstatistics">-</a>
qh_initstatistics( )
allocate and initialize statistics
notes:
uses qh_malloc() instead of qh_memalloc() since mem.c not set up yet
NOerrors -- qh_initstatistics can not use qh_errexit(). One first call, qh_memalloc is not initialized. Also invoked by QhullQh().
*/
void qh_initstatistics(void) {
int i;
realT realx;
int intx;
#if qh_QHpointer
if(qh_qhstat){ /* qh_initstatistics may be called from Qhull::resetStatistics() */
qh_free(qh_qhstat);
qh_qhstat= 0;
}
if (!(qh_qhstat= (qhstatT *)qh_malloc(sizeof(qhstatT)))) {
qh_fprintf(qhmem.ferr, 6183, "qhull error (qh_initstatistics): insufficient memory\n");
qh_exit(qh_ERRmem); /* can not use qh_errexit() */
}
#endif
qhstat next= 0;
qh_allstatA();
qh_allstatB();
qh_allstatC();
qh_allstatD();
qh_allstatE();
qh_allstatE2();
qh_allstatF();
qh_allstatG();
qh_allstatH();
qh_allstatI();
if (qhstat next > (int)sizeof(qhstat id)) {
qh_fprintf(qhmem.ferr, 6184, "qhull error (qh_initstatistics): increase size of qhstat.id[].\n\
qhstat.next %d should be <= sizeof(qhstat id) %d\n", qhstat next, (int)sizeof(qhstat id));
#if 0 /* for locating error, Znumridges should be duplicated */
for(i=0; i < ZEND; i++) {
int j;
for(j=i+1; j < ZEND; j++) {
if (qhstat id[i] == qhstat id[j]) {
qh_fprintf(qhmem.ferr, 6185, "qhull error (qh_initstatistics): duplicated statistic %d at indices %d and %d\n",
qhstat id[i], i, j);
}
}
}
#endif
qh_exit(qh_ERRqhull); /* can not use qh_errexit() */
}
qhstat init[zinc].i= 0;
qhstat init[zadd].i= 0;
qhstat init[zmin].i= INT_MAX;
qhstat init[zmax].i= INT_MIN;
qhstat init[wadd].r= 0;
qhstat init[wmin].r= REALmax;
qhstat init[wmax].r= -REALmax;
for(i=0; i < ZEND; i++) {
if (qhstat type[i] > ZTYPEreal) {
realx= qhstat init[(unsigned char)(qhstat type[i])].r;
qhstat stats[i].r= realx;
}else if (qhstat type[i] != zdoc) {
intx= qhstat init[(unsigned char)(qhstat type[i])].i;
qhstat stats[i].i= intx;
}
}
} /* initstatistics */
/*-<a href="qh-stat.htm#TOC"
>-------------------------------</a><a name="newstats">-</a>
qh_newstats( )
returns True if statistics for zdoc
returns:
next zdoc
*/
boolT qh_newstats(int idx, int *nextindex) {
boolT isnew= False;
int start, i;
if (qhstat type[qhstat id[idx]] == zdoc)
start= idx+1;
else
start= idx;
for(i= start; i < qhstat next && qhstat type[qhstat id[i]] != zdoc; i++) {
if (!qh_nostatistic(qhstat id[i]) && !qhstat printed[qhstat id[i]])
isnew= True;
}
*nextindex= i;
return isnew;
} /* newstats */
/*-<a href="qh-stat.htm#TOC"
>-------------------------------</a><a name="nostatistic">-</a>
qh_nostatistic( index )
true if no statistic to print
*/
boolT qh_nostatistic(int i) {
if ((qhstat type[i] > ZTYPEreal
&&qhstat stats[i].r == qhstat init[(unsigned char)(qhstat type[i])].r)
|| (qhstat type[i] < ZTYPEreal
&&qhstat stats[i].i == qhstat init[(unsigned char)(qhstat type[i])].i))
return True;
return False;
} /* nostatistic */
#if qh_KEEPstatistics
/*-<a href="qh-stat.htm#TOC"
>-------------------------------</a><a name="printallstatistics">-</a>
qh_printallstatistics( fp, string )
print all statistics with header 'string'
*/
void qh_printallstatistics(FILE *fp, const char *string) {
qh_allstatistics();
qh_collectstatistics();
qh_printstatistics(fp, string);
qh_memstatistics(fp);
}
/*-<a href="qh-stat.htm#TOC"
>-------------------------------</a><a name="printstatistics">-</a>
qh_printstatistics( fp, string )
print statistics to a file with header 'string'
skips statistics with qhstat.printed[] (reset with qh_allstatistics)
see:
qh_printallstatistics()
*/
void qh_printstatistics(FILE *fp, const char *string) {
int i, k;
realT ave;
if (qh num_points != qh num_vertices) {
wval_(Wpbalance)= 0;
wval_(Wpbalance2)= 0;
}else
wval_(Wpbalance2)= qh_stddev(zval_(Zpbalance), wval_(Wpbalance),
wval_(Wpbalance2), &ave);
wval_(Wnewbalance2)= qh_stddev(zval_(Zprocessed), wval_(Wnewbalance),
wval_(Wnewbalance2), &ave);
qh_fprintf(fp, 9350, "\n\
%s\n\
qhull invoked by: %s | %s\n%s with options:\n%s\n", string, qh rbox_command,
qh qhull_command, qh_version, qh qhull_options);
qh_fprintf(fp, 9351, "\nprecision constants:\n\
%6.2g max. abs. coordinate in the (transformed) input('Qbd:n')\n\
%6.2g max. roundoff error for distance computation('En')\n\
%6.2g max. roundoff error for angle computations\n\
%6.2g min. distance for outside points ('Wn')\n\
%6.2g min. distance for visible facets ('Vn')\n\
%6.2g max. distance for coplanar facets ('Un')\n\
%6.2g max. facet width for recomputing centrum and area\n\
",
qh MAXabs_coord, qh DISTround, qh ANGLEround, qh MINoutside,
qh MINvisible, qh MAXcoplanar, qh WIDEfacet);
if (qh KEEPnearinside)
qh_fprintf(fp, 9352, "\
%6.2g max. distance for near-inside points\n", qh NEARinside);
if (qh premerge_cos < REALmax/2) qh_fprintf(fp, 9353, "\
%6.2g max. cosine for pre-merge angle\n", qh premerge_cos);
if (qh PREmerge) qh_fprintf(fp, 9354, "\
%6.2g radius of pre-merge centrum\n", qh premerge_centrum);
if (qh postmerge_cos < REALmax/2) qh_fprintf(fp, 9355, "\
%6.2g max. cosine for post-merge angle\n", qh postmerge_cos);
if (qh POSTmerge) qh_fprintf(fp, 9356, "\
%6.2g radius of post-merge centrum\n", qh postmerge_centrum);
qh_fprintf(fp, 9357, "\
%6.2g max. distance for merging two simplicial facets\n\
%6.2g max. roundoff error for arithmetic operations\n\
%6.2g min. denominator for divisions\n\
zero diagonal for Gauss: ", qh ONEmerge, REALepsilon, qh MINdenom);
for(k=0; k < qh hull_dim; k++)
qh_fprintf(fp, 9358, "%6.2e ", qh NEARzero[k]);
qh_fprintf(fp, 9359, "\n\n");
for(i=0 ; i < qhstat next; )
qh_printstats(fp, i, &i);
} /* printstatistics */
#endif /* qh_KEEPstatistics */
/*-<a href="qh-stat.htm#TOC"
>-------------------------------</a><a name="printstatlevel">-</a>
qh_printstatlevel( fp, id )
print level information for a statistic
notes:
nop if id >= ZEND, printed, or same as initial value
*/
void qh_printstatlevel(FILE *fp, int id, int start) {
#define NULLfield " "
if (id >= ZEND || qhstat printed[id])
return;
if (qhstat type[id] == zdoc) {
qh_fprintf(fp, 9360, "%s\n", qhstat doc[id]);
return;
}
(void) start; /* not used */
if (qh_nostatistic(id) || !qhstat doc[id])
return;
qhstat printed[id]= True;
if (qhstat count[id] != -1
&& qhstat stats[(unsigned char)(qhstat count[id])].i == 0)
qh_fprintf(fp, 9361, " *0 cnt*");
else if (qhstat type[id] >= ZTYPEreal && qhstat count[id] == -1)
qh_fprintf(fp, 9362, "%7.2g", qhstat stats[id].r);
else if (qhstat type[id] >= ZTYPEreal && qhstat count[id] != -1)
qh_fprintf(fp, 9363, "%7.2g", qhstat stats[id].r/ qhstat stats[(unsigned char)(qhstat count[id])].i);
else if (qhstat type[id] < ZTYPEreal && qhstat count[id] == -1)
qh_fprintf(fp, 9364, "%7d", qhstat stats[id].i);
else if (qhstat type[id] < ZTYPEreal && qhstat count[id] != -1)
qh_fprintf(fp, 9365, "%7.3g", (realT) qhstat stats[id].i / qhstat stats[(unsigned char)(qhstat count[id])].i);
qh_fprintf(fp, 9366, " %s\n", qhstat doc[id]);
} /* printstatlevel */
/*-<a href="qh-stat.htm#TOC"
>-------------------------------</a><a name="printstats">-</a>
qh_printstats( fp, index, nextindex )
print statistics for a zdoc group
returns:
next zdoc if non-null
*/
void qh_printstats(FILE *fp, int idx, int *nextindex) {
int j, nexti;
if (qh_newstats(idx, &nexti)) {
qh_fprintf(fp, 9367, "\n");
for (j=idx; j<nexti; j++)
qh_printstatlevel(fp, qhstat id[j], 0);
}
if (nextindex)
*nextindex= nexti;
} /* printstats */
#if qh_KEEPstatistics
/*-<a href="qh-stat.htm#TOC"
>-------------------------------</a><a name="stddev">-</a>
qh_stddev( num, tot, tot2, ave )
compute the standard deviation and average from statistics
tot2 is the sum of the squares
notes:
computes r.m.s.:
(x-ave)^2
== x^2 - 2x tot/num + (tot/num)^2
== tot2 - 2 tot tot/num + tot tot/num
== tot2 - tot ave
*/
realT qh_stddev(int num, realT tot, realT tot2, realT *ave) {
realT stddev;
*ave= tot/num;
stddev= sqrt(tot2/num - *ave * *ave);
return stddev;
} /* stddev */
#endif /* qh_KEEPstatistics */
#if !qh_KEEPstatistics
void qh_collectstatistics(void) {}
void qh_printallstatistics(FILE *fp, char *string) {};
void qh_printstatistics(FILE *fp, char *string) {}
#endif

View File

@@ -0,0 +1,541 @@
/*<html><pre> -<a href="qh-stat.htm"
>-------------------------------</a><a name="TOP">-</a>
stat.h
contains all statistics that are collected for qhull
see qh-stat.htm and stat.c
Copyright (c) 1993-2012 The Geometry Center.
$Id: //main/2011/qhull/src/libqhull/stat.h#5 $$Change: 1464 $
$DateTime: 2012/01/25 22:58:41 $$Author: bbarber $
recompile qhull if you change this file
Integer statistics are Z* while real statistics are W*.
define maydebugx to call a routine at every statistic event
*/
#ifndef qhDEFstat
#define qhDEFstat 1
#include "libqhull.h"
/*-<a href="qh-stat.htm#TOC"
>-------------------------------</a><a name="KEEPstatistics">-</a>
qh_KEEPstatistics
0 turns off statistic gathering (except zzdef/zzinc/zzadd/zzval/wwval)
*/
#ifndef qh_KEEPstatistics
#define qh_KEEPstatistics 1
#endif
/*-<a href="qh-stat.htm#TOC"
>-------------------------------</a><a name="statistics">-</a>
Zxxx for integers, Wxxx for reals
notes:
be sure that all statistics are defined in stat.c
otherwise initialization may core dump
can pick up all statistics by:
grep '[zw].*_[(][ZW]' *.c >z.x
remove trailers with query">-</a>
remove leaders with query-replace-regexp [ ^I]+ (
*/
#if qh_KEEPstatistics
enum statistics { /* alphabetical after Z/W */
Zacoplanar,
Wacoplanarmax,
Wacoplanartot,
Zangle,
Wangle,
Wanglemax,
Wanglemin,
Zangletests,
Wareatot,
Wareamax,
Wareamin,
Zavoidold,
Wavoidoldmax,
Wavoidoldtot,
Zback0,
Zbestcentrum,
Zbestdist,
Zbestlower,
Zbestlowerv,
Zcentrumtests,
Zcheckpart,
Zcomputefurthest,
Zconcave,
Wconcavemax,
Wconcavetot,
Zconcaveridges,
Zconcaveridge,
Zcoplanar,
Wcoplanarmax,
Wcoplanartot,
Zcoplanarangle,
Zcoplanarcentrum,
Zcoplanarhorizon,
Zcoplanarinside,
Zcoplanarpart,
Zcoplanarridges,
Wcpu,
Zcyclefacetmax,
Zcyclefacettot,
Zcyclehorizon,
Zcyclevertex,
Zdegen,
Wdegenmax,
Wdegentot,
Zdegenvertex,
Zdelfacetdup,
Zdelridge,
Zdelvertextot,
Zdelvertexmax,
Zdetsimplex,
Zdistcheck,
Zdistconvex,
Zdistgood,
Zdistio,
Zdistplane,
Zdiststat,
Zdistvertex,
Zdistzero,
Zdoc1,
Zdoc2,
Zdoc3,
Zdoc4,
Zdoc5,
Zdoc6,
Zdoc7,
Zdoc8,
Zdoc9,
Zdoc10,
Zdoc11,
Zdoc12,
Zdropdegen,
Zdropneighbor,
Zdupflip,
Zduplicate,
Wduplicatemax,
Wduplicatetot,
Zdupridge,
Zdupsame,
Zflipped,
Wflippedmax,
Wflippedtot,
Zflippedfacets,
Zfindbest,
Zfindbestmax,
Zfindbesttot,
Zfindcoplanar,
Zfindfail,
Zfindhorizon,
Zfindhorizonmax,
Zfindhorizontot,
Zfindjump,
Zfindnew,
Zfindnewmax,
Zfindnewtot,
Zfindnewjump,
Zfindnewsharp,
Zgauss0,
Zgoodfacet,
Zhashlookup,
Zhashridge,
Zhashridgetest,
Zhashtests,
Zinsidevisible,
Zintersect,
Zintersectfail,
Zintersectmax,
Zintersectnum,
Zintersecttot,
Zmaxneighbors,
Wmaxout,
Wmaxoutside,
Zmaxridges,
Zmaxvertex,
Zmaxvertices,
Zmaxvneighbors,
Zmemfacets,
Zmempoints,
Zmemridges,
Zmemvertices,
Zmergeflipdup,
Zmergehorizon,
Zmergeinittot,
Zmergeinitmax,
Zmergeinittot2,
Zmergeintohorizon,
Zmergenew,
Zmergesettot,
Zmergesetmax,
Zmergesettot2,
Zmergesimplex,
Zmergevertex,
Wmindenom,
Wminvertex,
Zminnorm,
Zmultiridge,
Znearlysingular,
Zneighbor,
Wnewbalance,
Wnewbalance2,
Znewfacettot,
Znewfacetmax,
Znewvertex,
Wnewvertex,
Wnewvertexmax,
Znoarea,
Znonsimplicial,
Znowsimplicial,
Znotgood,
Znotgoodnew,
Znotmax,
Znumfacets,
Znummergemax,
Znummergetot,
Znumneighbors,
Znumridges,
Znumvertices,
Znumvisibility,
Znumvneighbors,
Zonehorizon,
Zpartangle,
Zpartcoplanar,
Zpartflip,
Zparthorizon,
Zpartinside,
Zpartition,
Zpartitionall,
Zpartnear,
Zpbalance,
Wpbalance,
Wpbalance2,
Zpostfacets,
Zpremergetot,
Zprocessed,
Zremvertex,
Zremvertexdel,
Zrenameall,
Zrenamepinch,
Zrenameshare,
Zretry,
Wretrymax,
Zridge,
Wridge,
Wridgemax,
Zridge0,
Wridge0,
Wridge0max,
Zridgemid,
Wridgemid,
Wridgemidmax,
Zridgeok,
Wridgeok,
Wridgeokmax,
Zsearchpoints,
Zsetplane,
Ztestvneighbor,
Ztotcheck,
Ztothorizon,
Ztotmerge,
Ztotpartcoplanar,
Ztotpartition,
Ztotridges,
Ztotvertices,
Ztotvisible,
Ztricoplanar,
Ztricoplanarmax,
Ztricoplanartot,
Ztridegen,
Ztrimirror,
Ztrinull,
Wvertexmax,
Wvertexmin,
Zvertexridge,
Zvertexridgetot,
Zvertexridgemax,
Zvertices,
Zvisfacettot,
Zvisfacetmax,
Zvisit,
Zvisit2max,
Zvisvertextot,
Zvisvertexmax,
Zvvisit,
Zvvisit2max,
Zwidefacet,
Zwidevertices,
ZEND};
/*-<a href="qh-stat.htm#TOC"
>-------------------------------</a><a name="ZZstat">-</a>
Zxxx/Wxxx statistics that remain defined if qh_KEEPstatistics=0
notes:
be sure to use zzdef, zzinc, etc. with these statistics (no double checking!)
*/
#else
enum statistics { /* for zzdef etc. macros */
Zback0,
Zbestdist,
Zcentrumtests,
Zcheckpart,
Zconcaveridges,
Zcoplanarhorizon,
Zcoplanarpart,
Zcoplanarridges,
Zcyclefacettot,
Zcyclehorizon,
Zdelvertextot,
Zdistcheck,
Zdistconvex,
Zdistzero,
Zdoc1,
Zdoc2,
Zdoc3,
Zdoc11,
Zflippedfacets,
Zgauss0,
Zminnorm,
Zmultiridge,
Znearlysingular,
Wnewvertexmax,
Znumvisibility,
Zpartcoplanar,
Zpartition,
Zpartitionall,
Zprocessed,
Zretry,
Zridge,
Wridge,
Wridgemax,
Zridge0,
Wridge0,
Wridge0max,
Zridgemid,
Wridgemid,
Wridgemidmax,
Zridgeok,
Wridgeok,
Wridgeokmax,
Zsetplane,
Ztotcheck,
Ztotmerge,
ZEND};
#endif
/*-<a href="qh-stat.htm#TOC"
>-------------------------------</a><a name="ztype">-</a>
ztype
the type of a statistic sets its initial value.
notes:
The type should be the same as the macro for collecting the statistic
*/
enum ztypes {zdoc,zinc,zadd,zmax,zmin,ZTYPEreal,wadd,wmax,wmin,ZTYPEend};
/*========== macros and constants =============*/
/*-<a href="qh-stat.htm#TOC"
>--------------------------------</a><a name="MAYdebugx">-</a>
MAYdebugx
define as maydebug() to be called frequently for error trapping
*/
#define MAYdebugx
/*-<a href="qh-stat.htm#TOC"
>--------------------------------</a><a name="zdef_">-</a>
zzdef_, zdef_( type, name, doc, -1)
define a statistic (assumes 'qhstat.next= 0;')
zdef_( type, name, doc, count)
define an averaged statistic
printed as name/count
*/
#define zzdef_(stype,name,string,cnt) qhstat id[qhstat next++]=name; \
qhstat doc[name]= string; qhstat count[name]= cnt; qhstat type[name]= stype
#if qh_KEEPstatistics
#define zdef_(stype,name,string,cnt) qhstat id[qhstat next++]=name; \
qhstat doc[name]= string; qhstat count[name]= cnt; qhstat type[name]= stype
#else
#define zdef_(type,name,doc,count)
#endif
/*-<a href="qh-stat.htm#TOC"
>--------------------------------</a><a name="zinc_">-</a>
zzinc_( name ), zinc_( name)
increment an integer statistic
*/
#define zzinc_(id) {MAYdebugx; qhstat stats[id].i++;}
#if qh_KEEPstatistics
#define zinc_(id) {MAYdebugx; qhstat stats[id].i++;}
#else
#define zinc_(id) {}
#endif
/*-<a href="qh-stat.htm#TOC"
>--------------------------------</a><a name="zadd_">-</a>
zzadd_( name, value ), zadd_( name, value ), wadd_( name, value )
add value to an integer or real statistic
*/
#define zzadd_(id, val) {MAYdebugx; qhstat stats[id].i += (val);}
#define wwadd_(id, val) {MAYdebugx; qhstat stats[id].r += (val);}
#if qh_KEEPstatistics
#define zadd_(id, val) {MAYdebugx; qhstat stats[id].i += (val);}
#define wadd_(id, val) {MAYdebugx; qhstat stats[id].r += (val);}
#else
#define zadd_(id, val) {}
#define wadd_(id, val) {}
#endif
/*-<a href="qh-stat.htm#TOC"
>--------------------------------</a><a name="zval_">-</a>
zzval_( name ), zval_( name ), wwval_( name )
set or return value of a statistic
*/
#define zzval_(id) ((qhstat stats[id]).i)
#define wwval_(id) ((qhstat stats[id]).r)
#if qh_KEEPstatistics
#define zval_(id) ((qhstat stats[id]).i)
#define wval_(id) ((qhstat stats[id]).r)
#else
#define zval_(id) qhstat tempi
#define wval_(id) qhstat tempr
#endif
/*-<a href="qh-stat.htm#TOC"
>--------------------------------</a><a name="zmax_">-</a>
zmax_( id, val ), wmax_( id, value )
maximize id with val
*/
#define wwmax_(id, val) {MAYdebugx; maximize_(qhstat stats[id].r,(val));}
#if qh_KEEPstatistics
#define zmax_(id, val) {MAYdebugx; maximize_(qhstat stats[id].i,(val));}
#define wmax_(id, val) {MAYdebugx; maximize_(qhstat stats[id].r,(val));}
#else
#define zmax_(id, val) {}
#define wmax_(id, val) {}
#endif
/*-<a href="qh-stat.htm#TOC"
>--------------------------------</a><a name="zmin_">-</a>
zmin_( id, val ), wmin_( id, value )
minimize id with val
*/
#if qh_KEEPstatistics
#define zmin_(id, val) {MAYdebugx; minimize_(qhstat stats[id].i,(val));}
#define wmin_(id, val) {MAYdebugx; minimize_(qhstat stats[id].r,(val));}
#else
#define zmin_(id, val) {}
#define wmin_(id, val) {}
#endif
/*================== stat.h types ==============*/
/*-<a href="qh-stat.htm#TOC"
>--------------------------------</a><a name="intrealT">-</a>
intrealT
union of integer and real, used for statistics
*/
typedef union intrealT intrealT; /* union of int and realT */
union intrealT {
int i;
realT r;
};
/*-<a href="qh-stat.htm#TOC"
>--------------------------------</a><a name="qhstat">-</a>
qhstat
global data structure for statistics, similar to qh and qhrbox
notes:
access to qh_qhstat is via the "qhstat" macro. There are two choices
qh_QHpointer = 1 access globals via a pointer
enables qh_saveqhull() and qh_restoreqhull()
= 0 qh_qhstat is a static data structure
only one instance of qhull() can be active at a time
default value
qh_QHpointer is defined in libqhull.h
qh_QHpointer_dllimport and qh_dllimport define qh_qh as __declspec(dllimport) [libqhull.h]
allocated in stat.c using qh_malloc()
*/
#ifndef DEFqhstatT
#define DEFqhstatT 1
typedef struct qhstatT qhstatT;
#endif
#if qh_QHpointer_dllimport
#define qhstat qh_qhstat->
__declspec(dllimport) extern qhstatT *qh_qhstat;
#elif qh_QHpointer
#define qhstat qh_qhstat->
extern qhstatT *qh_qhstat;
#elif qh_dllimport
#define qhstat qh_qhstat.
__declspec(dllimport) extern qhstatT qh_qhstat;
#else
#define qhstat qh_qhstat.
extern qhstatT qh_qhstat;
#endif
struct qhstatT {
intrealT stats[ZEND]; /* integer and real statistics */
unsigned char id[ZEND+10]; /* id's in print order */
const char *doc[ZEND]; /* array of documentation strings */
short int count[ZEND]; /* -1 if none, else index of count to use */
char type[ZEND]; /* type, see ztypes above */
char printed[ZEND]; /* true, if statistic has been printed */
intrealT init[ZTYPEend]; /* initial values by types, set initstatistics */
int next; /* next index for zdef_ */
int precision; /* index for precision problems */
int vridges; /* index for Voronoi ridges */
int tempi;
realT tempr;
};
/*========== function prototypes ===========*/
void qh_allstatA(void);
void qh_allstatB(void);
void qh_allstatC(void);
void qh_allstatD(void);
void qh_allstatE(void);
void qh_allstatE2(void);
void qh_allstatF(void);
void qh_allstatG(void);
void qh_allstatH(void);
void qh_allstatI(void);
void qh_allstatistics(void);
void qh_collectstatistics(void);
void qh_freestatistics(void);
void qh_initstatistics(void);
boolT qh_newstats(int idx, int *nextindex);
boolT qh_nostatistic(int i);
void qh_printallstatistics(FILE *fp, const char *string);
void qh_printstatistics(FILE *fp, const char *string);
void qh_printstatlevel(FILE *fp, int id, int start);
void qh_printstats(FILE *fp, int idx, int *nextindex);
realT qh_stddev(int num, realT tot, realT tot2, realT *ave);
#endif /* qhDEFstat */

View File

@@ -0,0 +1,527 @@
/*<html><pre> -<a href="qh-user.htm"
>-------------------------------</a><a name="TOP">-</a>
user.c
user redefinable functions
see user2.c for qh_fprintf, qh_malloc, qh_free
see README.txt see COPYING.txt for copyright information.
see libqhull.h for data structures, macros, and user-callable functions.
see user_eg.c, unix.c, and qhull_interface.cpp for examples.
see user.h for user-definable constants
use qh_NOmem in mem.h to turn off memory management
use qh_NOmerge in user.h to turn off facet merging
set qh_KEEPstatistics in user.h to 0 to turn off statistics
This is unsupported software. You're welcome to make changes,
but you're on your own if something goes wrong. Use 'Tc' to
check frequently. Usually qhull will report an error if
a data structure becomes inconsistent. If so, it also reports
the last point added to the hull, e.g., 102. You can then trace
the execution of qhull with "T4P102".
Please report any errors that you fix to qhull@qhull.org
call_qhull is a template for calling qhull from within your application
if you recompile and load this module, then user.o will not be loaded
from qhull.a
you can add additional quick allocation sizes in qh_user_memsizes
if the other functions here are redefined to not use qh_print...,
then io.o will not be loaded from qhull.a. See user_eg.c for an
example. We recommend keeping io.o for the extra debugging
information it supplies.
*/
#include "qhull_a.h"
#include <stdarg.h>
/*-<a href="qh-user.htm#TOC"
>-------------------------------</a><a name="call_qhull">-</a>
qh_call_qhull( void )
template for calling qhull from inside your program
remove #if 0, #endif to compile
returns:
exit code(see qh_ERR... in libqhull.h)
all memory freed
notes:
This can be called any number of times.
see:
qh_call_qhull_once()
*/
#if 0
{
int dim; /* dimension of points */
int numpoints; /* number of points */
coordT *points; /* array of coordinates for each point */
boolT ismalloc; /* True if qhull should free points in qh_freeqhull() or reallocation */
char flags[]= "qhull Tv"; /* option flags for qhull, see qh_opt.htm */
FILE *outfile= stdout; /* output from qh_produce_output()
use NULL to skip qh_produce_output() */
FILE *errfile= stderr; /* error messages from qhull code */
int exitcode; /* 0 if no error from qhull */
facetT *facet; /* set by FORALLfacets */
int curlong, totlong; /* memory remaining after qh_memfreeshort */
#if qh_QHpointer /* see user.h */
if (qh_qh){
printf ("QH6238: Qhull link error. The global variable qh_qh was not initialized\n\
to NULL by global.c. Please compile this program with -Dqh_QHpointer_dllimport\n\
as well as -Dqh_QHpointer, or use libqhullstatic, or use a different tool chain.\n\n");
exit -1;
}
#endif
/* initialize dim, numpoints, points[], ismalloc here */
exitcode= qh_new_qhull(dim, numpoints, points, ismalloc,
flags, outfile, errfile);
if (!exitcode) { /* if no error */
/* 'qh facet_list' contains the convex hull */
FORALLfacets {
/* ... your code ... */
}
}
qh_freeqhull(!qh_ALL);
qh_memfreeshort(&curlong, &totlong);
if (curlong || totlong)
qh_fprintf(errfile, 7068, "qhull internal warning (main): did not free %d bytes of long memory(%d pieces)\n", totlong, curlong);
}
#endif
/*-<a href="qh-user.htm#TOC"
>-------------------------------</a><a name="new_qhull">-</a>
qh_new_qhull( dim, numpoints, points, ismalloc, qhull_cmd, outfile, errfile )
build new qhull data structure and return exitcode (0 if no errors)
notes:
do not modify points until finished with results.
The qhull data structure contains pointers into the points array.
do not call qhull functions before qh_new_qhull().
The qhull data structure is not initialized until qh_new_qhull().
outfile may be null
qhull_cmd must start with "qhull "
projects points to a new point array for Delaunay triangulations ('d' and 'v')
transforms points into a new point array for halfspace intersection ('H')
To allow multiple, concurrent calls to qhull()
- set qh_QHpointer in user.h
- use qh_save_qhull and qh_restore_qhull to swap the global data structure between calls.
- use qh_freeqhull(qh_ALL) to free intermediate convex hulls
see:
user_eg.c for an example
*/
int qh_new_qhull(int dim, int numpoints, coordT *points, boolT ismalloc,
char *qhull_cmd, FILE *outfile, FILE *errfile) {
int exitcode, hulldim;
boolT new_ismalloc;
static boolT firstcall = True;
coordT *new_points;
if (firstcall) {
qh_meminit(errfile);
firstcall= False;
}
if (strncmp(qhull_cmd,"qhull ", (size_t)6)) {
qh_fprintf(errfile, 6186, "qhull error (qh_new_qhull): start qhull_cmd argument with \"qhull \"\n");
qh_exit(qh_ERRinput);
}
qh_initqhull_start(NULL, outfile, errfile);
trace1((qh ferr, 1044, "qh_new_qhull: build new Qhull for %d %d-d points with %s\n", numpoints, dim, qhull_cmd));
exitcode = setjmp(qh errexit);
if (!exitcode)
{
qh NOerrexit = False;
qh_initflags(qhull_cmd);
if (qh DELAUNAY)
qh PROJECTdelaunay= True;
if (qh HALFspace) {
/* points is an array of halfspaces,
the last coordinate of each halfspace is its offset */
hulldim= dim-1;
qh_setfeasible(hulldim);
new_points= qh_sethalfspace_all(dim, numpoints, points, qh feasible_point);
new_ismalloc= True;
if (ismalloc)
qh_free(points);
}else {
hulldim= dim;
new_points= points;
new_ismalloc= ismalloc;
}
qh_init_B(new_points, numpoints, hulldim, new_ismalloc);
qh_qhull();
qh_check_output();
if (outfile) {
qh_produce_output();
}else {
qh_prepare_output();
}
if (qh VERIFYoutput && !qh STOPpoint && !qh STOPcone)
qh_check_points();
}
qh NOerrexit = True;
return exitcode;
} /* new_qhull */
/*-<a href="qh-user.htm#TOC"
>-------------------------------</a><a name="errexit">-</a>
qh_errexit( exitcode, facet, ridge )
report and exit from an error
report facet and ridge if non-NULL
reports useful information such as last point processed
set qh.FORCEoutput to print neighborhood of facet
see:
qh_errexit2() in libqhull.c for printing 2 facets
design:
check for error within error processing
compute qh.hulltime
print facet and ridge (if any)
report commandString, options, qh.furthest_id
print summary and statistics (including precision statistics)
if qh_ERRsingular
print help text for singular data set
exit program via long jump (if defined) or exit()
*/
void qh_errexit(int exitcode, facetT *facet, ridgeT *ridge) {
if (qh ERREXITcalled) {
qh_fprintf(qh ferr, 8126, "\nqhull error while processing previous error. Exit program\n");
qh_exit(qh_ERRqhull);
}
qh ERREXITcalled= True;
if (!qh QHULLfinished)
qh hulltime= qh_CPUclock - qh hulltime;
qh_errprint("ERRONEOUS", facet, NULL, ridge, NULL);
qh_fprintf(qh ferr, 8127, "\nWhile executing: %s | %s\n", qh rbox_command, qh qhull_command);
qh_fprintf(qh ferr, 8128, "Options selected for Qhull %s:\n%s\n", qh_version, qh qhull_options);
if (qh furthest_id >= 0) {
qh_fprintf(qh ferr, 8129, "Last point added to hull was p%d.", qh furthest_id);
if (zzval_(Ztotmerge))
qh_fprintf(qh ferr, 8130, " Last merge was #%d.", zzval_(Ztotmerge));
if (qh QHULLfinished)
qh_fprintf(qh ferr, 8131, "\nQhull has finished constructing the hull.");
else if (qh POSTmerging)
qh_fprintf(qh ferr, 8132, "\nQhull has started post-merging.");
qh_fprintf(qh ferr, 8133, "\n");
}
if (qh FORCEoutput && (qh QHULLfinished || (!facet && !ridge)))
qh_produce_output();
else if (exitcode != qh_ERRinput) {
if (exitcode != qh_ERRsingular && zzval_(Zsetplane) > qh hull_dim+1) {
qh_fprintf(qh ferr, 8134, "\nAt error exit:\n");
qh_printsummary(qh ferr);
if (qh PRINTstatistics) {
qh_collectstatistics();
qh_printstatistics(qh ferr, "at error exit");
qh_memstatistics(qh ferr);
}
}
if (qh PRINTprecision)
qh_printstats(qh ferr, qhstat precision, NULL);
}
if (!exitcode)
exitcode= qh_ERRqhull;
else if (exitcode == qh_ERRsingular)
qh_printhelp_singular(qh ferr);
else if (exitcode == qh_ERRprec && !qh PREmerge)
qh_printhelp_degenerate(qh ferr);
if (qh NOerrexit) {
qh_fprintf(qh ferr, 6187, "qhull error while ending program. Exit program\n");
qh_exit(qh_ERRqhull);
}
qh ERREXITcalled= False;
qh NOerrexit= True;
longjmp(qh errexit, exitcode);
} /* errexit */
/*-<a href="qh-user.htm#TOC"
>-------------------------------</a><a name="errprint">-</a>
qh_errprint( fp, string, atfacet, otherfacet, atridge, atvertex )
prints out the information of facets and ridges to fp
also prints neighbors and geomview output
notes:
except for string, any parameter may be NULL
*/
void qh_errprint(const char *string, facetT *atfacet, facetT *otherfacet, ridgeT *atridge, vertexT *atvertex) {
int i;
if (atfacet) {
qh_fprintf(qh ferr, 8135, "%s FACET:\n", string);
qh_printfacet(qh ferr, atfacet);
}
if (otherfacet) {
qh_fprintf(qh ferr, 8136, "%s OTHER FACET:\n", string);
qh_printfacet(qh ferr, otherfacet);
}
if (atridge) {
qh_fprintf(qh ferr, 8137, "%s RIDGE:\n", string);
qh_printridge(qh ferr, atridge);
if (atridge->top && atridge->top != atfacet && atridge->top != otherfacet)
qh_printfacet(qh ferr, atridge->top);
if (atridge->bottom
&& atridge->bottom != atfacet && atridge->bottom != otherfacet)
qh_printfacet(qh ferr, atridge->bottom);
if (!atfacet)
atfacet= atridge->top;
if (!otherfacet)
otherfacet= otherfacet_(atridge, atfacet);
}
if (atvertex) {
qh_fprintf(qh ferr, 8138, "%s VERTEX:\n", string);
qh_printvertex(qh ferr, atvertex);
}
if (qh fout && qh FORCEoutput && atfacet && !qh QHULLfinished && !qh IStracing) {
qh_fprintf(qh ferr, 8139, "ERRONEOUS and NEIGHBORING FACETS to output\n");
for (i=0; i < qh_PRINTEND; i++) /* use fout for geomview output */
qh_printneighborhood(qh fout, qh PRINTout[i], atfacet, otherfacet,
!qh_ALL);
}
} /* errprint */
/*-<a href="qh-user.htm#TOC"
>-------------------------------</a><a name="printfacetlist">-</a>
qh_printfacetlist( fp, facetlist, facets, printall )
print all fields for a facet list and/or set of facets to fp
if !printall,
only prints good facets
notes:
also prints all vertices
*/
void qh_printfacetlist(facetT *facetlist, setT *facets, boolT printall) {
facetT *facet, **facetp;
qh_printbegin(qh ferr, qh_PRINTfacets, facetlist, facets, printall);
FORALLfacet_(facetlist)
qh_printafacet(qh ferr, qh_PRINTfacets, facet, printall);
FOREACHfacet_(facets)
qh_printafacet(qh ferr, qh_PRINTfacets, facet, printall);
qh_printend(qh ferr, qh_PRINTfacets, facetlist, facets, printall);
} /* printfacetlist */
/*-<a href="qh-io.htm#TOC"
>-------------------------------</a><a name="printhelp_degenerate">-</a>
qh_printhelp_degenerate( fp )
prints descriptive message for precision error
notes:
no message if qh_QUICKhelp
*/
void qh_printhelp_degenerate(FILE *fp) {
if (qh MERGEexact || qh PREmerge || qh JOGGLEmax < REALmax/2)
qh_fprintf(fp, 9368, "\n\
A Qhull error has occurred. Qhull should have corrected the above\n\
precision error. Please send the input and all of the output to\n\
qhull_bug@qhull.org\n");
else if (!qh_QUICKhelp) {
qh_fprintf(fp, 9369, "\n\
Precision problems were detected during construction of the convex hull.\n\
This occurs because convex hull algorithms assume that calculations are\n\
exact, but floating-point arithmetic has roundoff errors.\n\
\n\
To correct for precision problems, do not use 'Q0'. By default, Qhull\n\
selects 'C-0' or 'Qx' and merges non-convex facets. With option 'QJ',\n\
Qhull joggles the input to prevent precision problems. See \"Imprecision\n\
in Qhull\" (qh-impre.htm).\n\
\n\
If you use 'Q0', the output may include\n\
coplanar ridges, concave ridges, and flipped facets. In 4-d and higher,\n\
Qhull may produce a ridge with four neighbors or two facets with the same \n\
vertices. Qhull reports these events when they occur. It stops when a\n\
concave ridge, flipped facet, or duplicate facet occurs.\n");
#if REALfloat
qh_fprintf(fp, 9370, "\
\n\
Qhull is currently using single precision arithmetic. The following\n\
will probably remove the precision problems:\n\
- recompile qhull for realT precision(#define REALfloat 0 in user.h).\n");
#endif
if (qh DELAUNAY && !qh SCALElast && qh MAXabs_coord > 1e4)
qh_fprintf(fp, 9371, "\
\n\
When computing the Delaunay triangulation of coordinates > 1.0,\n\
- use 'Qbb' to scale the last coordinate to [0,m] (max previous coordinate)\n");
if (qh DELAUNAY && !qh ATinfinity)
qh_fprintf(fp, 9372, "\
When computing the Delaunay triangulation:\n\
- use 'Qz' to add a point at-infinity. This reduces precision problems.\n");
qh_fprintf(fp, 9373, "\
\n\
If you need triangular output:\n\
- use option 'Qt' to triangulate the output\n\
- use option 'QJ' to joggle the input points and remove precision errors\n\
- use option 'Ft'. It triangulates non-simplicial facets with added points.\n\
\n\
If you must use 'Q0',\n\
try one or more of the following options. They can not guarantee an output.\n\
- use 'QbB' to scale the input to a cube.\n\
- use 'Po' to produce output and prevent partitioning for flipped facets\n\
- use 'V0' to set min. distance to visible facet as 0 instead of roundoff\n\
- use 'En' to specify a maximum roundoff error less than %2.2g.\n\
- options 'Qf', 'Qbb', and 'QR0' may also help\n",
qh DISTround);
qh_fprintf(fp, 9374, "\
\n\
To guarantee simplicial output:\n\
- use option 'Qt' to triangulate the output\n\
- use option 'QJ' to joggle the input points and remove precision errors\n\
- use option 'Ft' to triangulate the output by adding points\n\
- use exact arithmetic (see \"Imprecision in Qhull\", qh-impre.htm)\n\
");
}
} /* printhelp_degenerate */
/*-<a href="qh-globa.htm#TOC"
>-------------------------------</a><a name="printhelp_narrowhull">-</a>
qh_printhelp_narrowhull( minangle )
Warn about a narrow hull
notes:
Alternatively, reduce qh_WARNnarrow in user.h
*/
void qh_printhelp_narrowhull(FILE *fp, realT minangle) {
qh_fprintf(fp, 9375, "qhull precision warning: \n\
The initial hull is narrow (cosine of min. angle is %.16f).\n\
Is the input lower dimensional (e.g., on a plane in 3-d)? Qhull may\n\
produce a wide facet. Options 'QbB' (scale to unit box) or 'Qbb' (scale\n\
last coordinate) may remove this warning. Use 'Pp' to skip this warning.\n\
See 'Limitations' in qh-impre.htm.\n",
-minangle); /* convert from angle between normals to angle between facets */
} /* printhelp_narrowhull */
/*-<a href="qh-io.htm#TOC"
>-------------------------------</a><a name="printhelp_singular">-</a>
qh_printhelp_singular( fp )
prints descriptive message for singular input
*/
void qh_printhelp_singular(FILE *fp) {
facetT *facet;
vertexT *vertex, **vertexp;
realT min, max, *coord, dist;
int i,k;
qh_fprintf(fp, 9376, "\n\
The input to qhull appears to be less than %d dimensional, or a\n\
computation has overflowed.\n\n\
Qhull could not construct a clearly convex simplex from points:\n",
qh hull_dim);
qh_printvertexlist(fp, "", qh facet_list, NULL, qh_ALL);
if (!qh_QUICKhelp)
qh_fprintf(fp, 9377, "\n\
The center point is coplanar with a facet, or a vertex is coplanar\n\
with a neighboring facet. The maximum round off error for\n\
computing distances is %2.2g. The center point, facets and distances\n\
to the center point are as follows:\n\n", qh DISTround);
qh_printpointid(fp, "center point", qh hull_dim, qh interior_point, -1);
qh_fprintf(fp, 9378, "\n");
FORALLfacets {
qh_fprintf(fp, 9379, "facet");
FOREACHvertex_(facet->vertices)
qh_fprintf(fp, 9380, " p%d", qh_pointid(vertex->point));
zinc_(Zdistio);
qh_distplane(qh interior_point, facet, &dist);
qh_fprintf(fp, 9381, " distance= %4.2g\n", dist);
}
if (!qh_QUICKhelp) {
if (qh HALFspace)
qh_fprintf(fp, 9382, "\n\
These points are the dual of the given halfspaces. They indicate that\n\
the intersection is degenerate.\n");
qh_fprintf(fp, 9383,"\n\
These points either have a maximum or minimum x-coordinate, or\n\
they maximize the determinant for k coordinates. Trial points\n\
are first selected from points that maximize a coordinate.\n");
if (qh hull_dim >= qh_INITIALmax)
qh_fprintf(fp, 9384, "\n\
Because of the high dimension, the min x-coordinate and max-coordinate\n\
points are used if the determinant is non-zero. Option 'Qs' will\n\
do a better, though much slower, job. Instead of 'Qs', you can change\n\
the points by randomly rotating the input with 'QR0'.\n");
}
qh_fprintf(fp, 9385, "\nThe min and max coordinates for each dimension are:\n");
for (k=0; k < qh hull_dim; k++) {
min= REALmax;
max= -REALmin;
for (i=qh num_points, coord= qh first_point+k; i--; coord += qh hull_dim) {
maximize_(max, *coord);
minimize_(min, *coord);
}
qh_fprintf(fp, 9386, " %d: %8.4g %8.4g difference= %4.4g\n", k, min, max, max-min);
}
if (!qh_QUICKhelp) {
qh_fprintf(fp, 9387, "\n\
If the input should be full dimensional, you have several options that\n\
may determine an initial simplex:\n\
- use 'QJ' to joggle the input and make it full dimensional\n\
- use 'QbB' to scale the points to the unit cube\n\
- use 'QR0' to randomly rotate the input for different maximum points\n\
- use 'Qs' to search all points for the initial simplex\n\
- use 'En' to specify a maximum roundoff error less than %2.2g.\n\
- trace execution with 'T3' to see the determinant for each point.\n",
qh DISTround);
#if REALfloat
qh_fprintf(fp, 9388, "\
- recompile qhull for realT precision(#define REALfloat 0 in libqhull.h).\n");
#endif
qh_fprintf(fp, 9389, "\n\
If the input is lower dimensional:\n\
- use 'QJ' to joggle the input and make it full dimensional\n\
- use 'Qbk:0Bk:0' to delete coordinate k from the input. You should\n\
pick the coordinate with the least range. The hull will have the\n\
correct topology.\n\
- determine the flat containing the points, rotate the points\n\
into a coordinate plane, and delete the other coordinates.\n\
- add one or more points to make the input full dimensional.\n\
");
}
} /* printhelp_singular */
/*-<a href="qh-globa.htm#TOC"
>-------------------------------</a><a name="user_memsizes">-</a>
qh_user_memsizes()
allocate up to 10 additional, quick allocation sizes
notes:
increase maximum number of allocations in qh_initqhull_mem()
*/
void qh_user_memsizes(void) {
/* qh_memsize(size); */
} /* user_memsizes */

View File

@@ -0,0 +1,858 @@
/*<html><pre> -<a href="qh-user.htm"
>-------------------------------</a><a name="TOP">-</a>
user.h
user redefinable constants
see qh-user.htm. see COPYING for copyright information.
before reading any code, review libqhull.h for data structure definitions and
the "qh" macro.
Sections:
============= qhull library constants ======================
============= data types and configuration macros ==========
============= performance related constants ================
============= memory constants =============================
============= joggle constants =============================
============= conditional compilation ======================
============= -merge constants- ============================
Code flags --
NOerrors -- the code does not call qh_errexit()
WARN64 -- the code may be incompatible with 64-bit pointers
*/
#include <time.h>
#ifndef qhDEFuser
#define qhDEFuser 1
/*============================================================*/
/*============= qhull library constants ======================*/
/*============================================================*/
/*-<a href="qh-user.htm#TOC"
>--------------------------------</a><a name="filenamelen">-</a>
FILENAMElen -- max length for TI and TO filenames
*/
#define qh_FILENAMElen 500
/*-<a href="qh-user.htm#TOC"
>--------------------------------</a><a name="msgcode">-</a>
msgcode -- Unique message codes for qh_fprintf
If add new messages, assign these values and increment.
def counters = [27, 1047, 2059, 3025, 4068, 5003,
6241, 7079, 8143, 9410, 10000, 11026]
See: qh_ERR* [libqhull.h]
*/
#define MSG_TRACE0 0
#define MSG_TRACE1 1000
#define MSG_TRACE2 2000
#define MSG_TRACE3 3000
#define MSG_TRACE4 4000
#define MSG_TRACE5 5000
#define MSG_ERROR 6000 /* errors written to qh.ferr */
#define MSG_WARNING 7000
#define MSG_STDERR 8000 /* log messages Written to qh.ferr */
#define MSG_OUTPUT 9000
#define MSG_QHULL_ERROR 10000 /* errors thrown by QhullError [QhullError.h] */
#define MSG_FIXUP 11000 /* FIXUP QH11... */
#define MSG_MAXLEN 3000 /* qh_printhelp_degenerate() in user.c */
/*-<a href="qh-user.htm#TOC"
>--------------------------------</a><a name="qh_OPTIONline">-</a>
qh_OPTIONline -- max length of an option line 'FO'
*/
#define qh_OPTIONline 80
/*============================================================*/
/*============= data types and configuration macros ==========*/
/*============================================================*/
/*-<a href="qh-user.htm#TOC"
>--------------------------------</a><a name="realT">-</a>
realT
set the size of floating point numbers
qh_REALdigits
maximum number of significant digits
qh_REAL_1, qh_REAL_2n, qh_REAL_3n
format strings for printf
qh_REALmax, qh_REALmin
maximum and minimum (near zero) values
qh_REALepsilon
machine roundoff. Maximum roundoff error for addition and multiplication.
notes:
Select whether to store floating point numbers in single precision (float)
or double precision (double).
Use 'float' to save about 8% in time and 25% in space. This is particularly
helpful if high-d where convex hulls are space limited. Using 'float' also
reduces the printed size of Qhull's output since numbers have 8 digits of
precision.
Use 'double' when greater arithmetic precision is needed. This is needed
for Delaunay triangulations and Voronoi diagrams when you are not merging
facets.
If 'double' gives insufficient precision, your data probably includes
degeneracies. If so you should use facet merging (done by default)
or exact arithmetic (see imprecision section of manual, qh-impre.htm).
You may also use option 'Po' to force output despite precision errors.
You may use 'long double', but many format statements need to be changed
and you may need a 'long double' square root routine. S. Grundmann
(sg@eeiwzb.et.tu-dresden.de) has done this. He reports that the code runs
much slower with little gain in precision.
WARNING: on some machines, int f(){realT a= REALmax;return (a == REALmax);}
returns False. Use (a > REALmax/2) instead of (a == REALmax).
REALfloat = 1 all numbers are 'float' type
= 0 all numbers are 'double' type
*/
#define REALfloat 0
#if (REALfloat == 1)
#define realT float
#define REALmax FLT_MAX
#define REALmin FLT_MIN
#define REALepsilon FLT_EPSILON
#define qh_REALdigits 8 /* maximum number of significant digits */
#define qh_REAL_1 "%6.8g "
#define qh_REAL_2n "%6.8g %6.8g\n"
#define qh_REAL_3n "%6.8g %6.8g %6.8g\n"
#elif (REALfloat == 0)
#define realT double
#define REALmax DBL_MAX
#define REALmin DBL_MIN
#define REALepsilon DBL_EPSILON
#define qh_REALdigits 16 /* maximum number of significant digits */
#define qh_REAL_1 "%6.16g "
#define qh_REAL_2n "%6.16g %6.16g\n"
#define qh_REAL_3n "%6.16g %6.16g %6.16g\n"
#else
#error unknown float option
#endif
/*-<a href="qh-user.htm#TOC"
>--------------------------------</a><a name="CPUclock">-</a>
qh_CPUclock
define the clock() function for reporting the total time spent by Qhull
returns CPU ticks as a 'long int'
qh_CPUclock is only used for reporting the total time spent by Qhull
qh_SECticks
the number of clock ticks per second
notes:
looks for CLOCKS_PER_SEC, CLOCKS_PER_SECOND, or assumes microseconds
to define a custom clock, set qh_CLOCKtype to 0
if your system does not use clock() to return CPU ticks, replace
qh_CPUclock with the corresponding function. It is converted
to 'unsigned long' to prevent wrap-around during long runs. By default,
<time.h> defines clock_t as 'long'
Set qh_CLOCKtype to
1 for CLOCKS_PER_SEC, CLOCKS_PER_SECOND, or microsecond
Note: may fail if more than 1 hour elapsed time
2 use qh_clock() with POSIX times() (see global.c)
*/
#define qh_CLOCKtype 1 /* change to the desired number */
#if (qh_CLOCKtype == 1)
#if defined(CLOCKS_PER_SECOND)
#define qh_CPUclock ((unsigned long)clock()) /* return CPU clock */
#define qh_SECticks CLOCKS_PER_SECOND
#elif defined(CLOCKS_PER_SEC)
#define qh_CPUclock ((unsigned long)clock()) /* return CPU clock */
#define qh_SECticks CLOCKS_PER_SEC
#elif defined(CLK_TCK)
#define qh_CPUclock ((unsigned long)clock()) /* return CPU clock */
#define qh_SECticks CLK_TCK
#else
#define qh_CPUclock ((unsigned long)clock()) /* return CPU clock */
#define qh_SECticks 1E6
#endif
#elif (qh_CLOCKtype == 2)
#define qh_CPUclock qh_clock() /* return CPU clock */
#define qh_SECticks 100
#else /* qh_CLOCKtype == ? */
#error unknown clock option
#endif
/*-<a href="qh-user.htm#TOC"
>--------------------------------</a><a name="RANDOM">-</a>
qh_RANDOMtype, qh_RANDOMmax, qh_RANDOMseed
define random number generator
qh_RANDOMint generates a random integer between 0 and qh_RANDOMmax.
qh_RANDOMseed sets the random number seed for qh_RANDOMint
Set qh_RANDOMtype (default 5) to:
1 for random() with 31 bits (UCB)
2 for rand() with RAND_MAX or 15 bits (system 5)
3 for rand() with 31 bits (Sun)
4 for lrand48() with 31 bits (Solaris)
5 for qh_rand() with 31 bits (included with Qhull)
notes:
Random numbers are used by rbox to generate point sets. Random
numbers are used by Qhull to rotate the input ('QRn' option),
simulate a randomized algorithm ('Qr' option), and to simulate
roundoff errors ('Rn' option).
Random number generators differ between systems. Most systems provide
rand() but the period varies. The period of rand() is not critical
since qhull does not normally use random numbers.
The default generator is Park & Miller's minimal standard random
number generator [CACM 31:1195 '88]. It is included with Qhull.
If qh_RANDOMmax is wrong, qhull will report a warning and Geomview
output will likely be invisible.
*/
#define qh_RANDOMtype 5 /* *** change to the desired number *** */
#if (qh_RANDOMtype == 1)
#define qh_RANDOMmax ((realT)0x7fffffffUL) /* 31 bits, random()/MAX */
#define qh_RANDOMint random()
#define qh_RANDOMseed_(seed) srandom(seed);
#elif (qh_RANDOMtype == 2)
#ifdef RAND_MAX
#define qh_RANDOMmax ((realT)RAND_MAX)
#else
#define qh_RANDOMmax ((realT)32767) /* 15 bits (System 5) */
#endif
#define qh_RANDOMint rand()
#define qh_RANDOMseed_(seed) srand((unsigned)seed);
#elif (qh_RANDOMtype == 3)
#define qh_RANDOMmax ((realT)0x7fffffffUL) /* 31 bits, Sun */
#define qh_RANDOMint rand()
#define qh_RANDOMseed_(seed) srand((unsigned)seed);
#elif (qh_RANDOMtype == 4)
#define qh_RANDOMmax ((realT)0x7fffffffUL) /* 31 bits, lrand38()/MAX */
#define qh_RANDOMint lrand48()
#define qh_RANDOMseed_(seed) srand48(seed);
#elif (qh_RANDOMtype == 5)
#define qh_RANDOMmax ((realT)2147483646UL) /* 31 bits, qh_rand/MAX */
#define qh_RANDOMint qh_rand()
#define qh_RANDOMseed_(seed) qh_srand(seed);
/* unlike rand(), never returns 0 */
#else
#error: unknown random option
#endif
/*-<a href="qh-user.htm#TOC"
>--------------------------------</a><a name="ORIENTclock">-</a>
qh_ORIENTclock
0 for inward pointing normals by Geomview convention
*/
#define qh_ORIENTclock 0
/*============================================================*/
/*============= joggle constants =============================*/
/*============================================================*/
/*-<a href="qh-user.htm#TOC"
>--------------------------------</a><a name="JOGGLEdefault">-</a>
qh_JOGGLEdefault
default qh.JOGGLEmax is qh.DISTround * qh_JOGGLEdefault
notes:
rbox s r 100 | qhull QJ1e-15 QR0 generates 90% faults at distround 7e-16
rbox s r 100 | qhull QJ1e-14 QR0 generates 70% faults
rbox s r 100 | qhull QJ1e-13 QR0 generates 35% faults
rbox s r 100 | qhull QJ1e-12 QR0 generates 8% faults
rbox s r 100 | qhull QJ1e-11 QR0 generates 1% faults
rbox s r 100 | qhull QJ1e-10 QR0 generates 0% faults
rbox 1000 W0 | qhull QJ1e-12 QR0 generates 86% faults
rbox 1000 W0 | qhull QJ1e-11 QR0 generates 20% faults
rbox 1000 W0 | qhull QJ1e-10 QR0 generates 2% faults
the later have about 20 points per facet, each of which may interfere
pick a value large enough to avoid retries on most inputs
*/
#define qh_JOGGLEdefault 30000.0
/*-<a href="qh-user.htm#TOC"
>--------------------------------</a><a name="JOGGLEincrease">-</a>
qh_JOGGLEincrease
factor to increase qh.JOGGLEmax on qh_JOGGLEretry or qh_JOGGLEagain
*/
#define qh_JOGGLEincrease 10.0
/*-<a href="qh-user.htm#TOC"
>--------------------------------</a><a name="JOGGLEretry">-</a>
qh_JOGGLEretry
if ZZretry = qh_JOGGLEretry, increase qh.JOGGLEmax
notes:
try twice at the original value in case of bad luck the first time
*/
#define qh_JOGGLEretry 2
/*-<a href="qh-user.htm#TOC"
>--------------------------------</a><a name="JOGGLEagain">-</a>
qh_JOGGLEagain
every following qh_JOGGLEagain, increase qh.JOGGLEmax
notes:
1 is OK since it's already failed qh_JOGGLEretry times
*/
#define qh_JOGGLEagain 1
/*-<a href="qh-user.htm#TOC"
>--------------------------------</a><a name="JOGGLEmaxincrease">-</a>
qh_JOGGLEmaxincrease
maximum qh.JOGGLEmax due to qh_JOGGLEincrease
relative to qh.MAXwidth
notes:
qh.joggleinput will retry at this value until qh_JOGGLEmaxretry
*/
#define qh_JOGGLEmaxincrease 1e-2
/*-<a href="qh-user.htm#TOC"
>--------------------------------</a><a name="JOGGLEmaxretry">-</a>
qh_JOGGLEmaxretry
stop after qh_JOGGLEmaxretry attempts
*/
#define qh_JOGGLEmaxretry 100
/*============================================================*/
/*============= performance related constants ================*/
/*============================================================*/
/*-<a href="qh-user.htm#TOC"
>--------------------------------</a><a name="HASHfactor">-</a>
qh_HASHfactor
total hash slots / used hash slots. Must be at least 1.1.
notes:
=2 for at worst 50% occupancy for qh hash_table and normally 25% occupancy
*/
#define qh_HASHfactor 2
/*-<a href="qh-user.htm#TOC"
>--------------------------------</a><a name="VERIFYdirect">-</a>
qh_VERIFYdirect
with 'Tv' verify all points against all facets if op count is smaller
notes:
if greater, calls qh_check_bestdist() instead
*/
#define qh_VERIFYdirect 1000000
/*-<a href="qh-user.htm#TOC"
>--------------------------------</a><a name="INITIALsearch">-</a>
qh_INITIALsearch
if qh_INITIALmax, search points up to this dimension
*/
#define qh_INITIALsearch 6
/*-<a href="qh-user.htm#TOC"
>--------------------------------</a><a name="INITIALmax">-</a>
qh_INITIALmax
if dim >= qh_INITIALmax, use min/max coordinate points for initial simplex
notes:
from points with non-zero determinants
use option 'Qs' to override (much slower)
*/
#define qh_INITIALmax 8
/*============================================================*/
/*============= memory constants =============================*/
/*============================================================*/
/*-<a href="qh-user.htm#TOC"
>--------------------------------</a><a name="MEMalign">-</a>
qh_MEMalign
memory alignment for qh_meminitbuffers() in global.c
notes:
to avoid bus errors, memory allocation must consider alignment requirements.
malloc() automatically takes care of alignment. Since mem.c manages
its own memory, we need to explicitly specify alignment in
qh_meminitbuffers().
A safe choice is sizeof(double). sizeof(float) may be used if doubles
do not occur in data structures and pointers are the same size. Be careful
of machines (e.g., DEC Alpha) with large pointers.
If using gcc, best alignment is
#define qh_MEMalign fmax_(__alignof__(realT),__alignof__(void *))
*/
#define qh_MEMalign ((int)(fmax_(sizeof(realT), sizeof(void *))))
/*-<a href="qh-user.htm#TOC"
>--------------------------------</a><a name="MEMbufsize">-</a>
qh_MEMbufsize
size of additional memory buffers
notes:
used for qh_meminitbuffers() in global.c
*/
#define qh_MEMbufsize 0x10000 /* allocate 64K memory buffers */
/*-<a href="qh-user.htm#TOC"
>--------------------------------</a><a name="MEMinitbuf">-</a>
qh_MEMinitbuf
size of initial memory buffer
notes:
use for qh_meminitbuffers() in global.c
*/
#define qh_MEMinitbuf 0x20000 /* initially allocate 128K buffer */
/*-<a href="qh-user.htm#TOC"
>--------------------------------</a><a name="INFINITE">-</a>
qh_INFINITE
on output, indicates Voronoi center at infinity
*/
#define qh_INFINITE -10.101
/*-<a href="qh-user.htm#TOC"
>--------------------------------</a><a name="DEFAULTbox">-</a>
qh_DEFAULTbox
default box size (Geomview expects 0.5)
qh_DEFAULTbox
default box size for integer coordinate (rbox only)
*/
#define qh_DEFAULTbox 0.5
#define qh_DEFAULTzbox 1e6
/*============================================================*/
/*============= conditional compilation ======================*/
/*============================================================*/
/*-<a href="qh-user.htm#TOC"
>--------------------------------</a><a name="compiler">-</a>
__cplusplus
defined by C++ compilers
__MSC_VER
defined by Microsoft Visual C++
__MWERKS__ && __POWERPC__
defined by Metrowerks when compiling for the Power Macintosh
__STDC__
defined for strict ANSI C
*/
/*-<a href="qh-user.htm#TOC"
>--------------------------------</a><a name="COMPUTEfurthest">-</a>
qh_COMPUTEfurthest
compute furthest distance to an outside point instead of storing it with the facet
=1 to compute furthest
notes:
computing furthest saves memory but costs time
about 40% more distance tests for partitioning
removes facet->furthestdist
*/
#define qh_COMPUTEfurthest 0
/*-<a href="qh-user.htm#TOC"
>--------------------------------</a><a name="KEEPstatistics">-</a>
qh_KEEPstatistics
=0 removes most of statistic gathering and reporting
notes:
if 0, code size is reduced by about 4%.
*/
#define qh_KEEPstatistics 1
/*-<a href="qh-user.htm#TOC"
>--------------------------------</a><a name="MAXoutside">-</a>
qh_MAXoutside
record outer plane for each facet
=1 to record facet->maxoutside
notes:
this takes a realT per facet and slightly slows down qhull
it produces better outer planes for geomview output
*/
#define qh_MAXoutside 1
/*-<a href="qh-user.htm#TOC"
>--------------------------------</a><a name="NOmerge">-</a>
qh_NOmerge
disables facet merging if defined
notes:
This saves about 10% space.
Unless 'Q0'
qh_NOmerge sets 'QJ' to avoid precision errors
#define qh_NOmerge
see:
<a href="mem.h#NOmem">qh_NOmem</a> in mem.c
see user.c/user_eg.c for removing io.o
*/
/*-<a href="qh-user.htm#TOC"
>--------------------------------</a><a name="NOtrace">-</a>
qh_NOtrace
no tracing if defined
notes:
This saves about 5% space.
#define qh_NOtrace
*/
/*-<a href="qh-user.htm#TOC"
>--------------------------------</a><a name="QHpointer">-</a>
qh_QHpointer
access global data with pointer or static structure
qh_QHpointer = 1 access globals via a pointer to allocated memory
enables qh_saveqhull() and qh_restoreqhull()
[2010, gcc] costs about 4% in time and 4% in space
[2003, msvc] costs about 8% in time and 2% in space
= 0 qh_qh and qh_qhstat are static data structures
only one instance of qhull() can be active at a time
default value
qh_QHpointer_dllimport and qh_dllimport define qh_qh as __declspec(dllimport) [libqhull.h]
It is required for msvc-2005. It is not needed for gcc.
notes:
all global variables for qhull are in qh, qhmem, and qhstat
qh is defined in libqhull.h
qhmem is defined in mem.h
qhstat is defined in stat.h
C++ build defines qh_QHpointer [libqhullp.pro, libqhullcpp.pro]
see:
user_eg.c for an example
*/
#ifdef qh_QHpointer
#if qh_dllimport
#error QH6207 Qhull error: Use qh_QHpointer_dllimport instead of qh_dllimport with qh_QHpointer
#endif
#else
#define qh_QHpointer 0
#if qh_QHpointer_dllimport
#error QH6234 Qhull error: Use qh_dllimport instead of qh_QHpointer_dllimport when qh_QHpointer is not defined
#endif
#endif
#if 0 /* sample code */
qhT *oldqhA, *oldqhB;
exitcode= qh_new_qhull(dim, numpoints, points, ismalloc,
flags, outfile, errfile);
/* use results from first call to qh_new_qhull */
oldqhA= qh_save_qhull();
exitcode= qh_new_qhull(dimB, numpointsB, pointsB, ismalloc,
flags, outfile, errfile);
/* use results from second call to qh_new_qhull */
oldqhB= qh_save_qhull();
qh_restore_qhull(&oldqhA);
/* use results from first call to qh_new_qhull */
qh_freeqhull(qh_ALL); /* frees all memory used by first call */
qh_restore_qhull(&oldqhB);
/* use results from second call to qh_new_qhull */
qh_freeqhull(!qh_ALL); /* frees long memory used by second call */
qh_memfreeshort(&curlong, &totlong); /* frees short memory and memory allocator */
#endif
/*-<a href="qh-user.htm#TOC"
>--------------------------------</a><a name="QUICKhelp">-</a>
qh_QUICKhelp
=1 to use abbreviated help messages, e.g., for degenerate inputs
*/
#define qh_QUICKhelp 0
/*============================================================*/
/*============= -merge constants- ============================*/
/*============================================================*/
/*
These constants effect facet merging. You probably will not need
to modify them. They effect the performance of facet merging.
*/
/*-<a href="qh-user.htm#TOC"
>--------------------------------</a><a name="DIMmergeVertex">-</a>
qh_DIMmergeVertex
max dimension for vertex merging (it is not effective in high-d)
*/
#define qh_DIMmergeVertex 6
/*-<a href="qh-user.htm#TOC"
>--------------------------------</a><a name="DIMreduceBuild">-</a>
qh_DIMreduceBuild
max dimension for vertex reduction during build (slow in high-d)
*/
#define qh_DIMreduceBuild 5
/*-<a href="qh-user.htm#TOC"
>--------------------------------</a><a name="BESTcentrum">-</a>
qh_BESTcentrum
if > 2*dim+n vertices, qh_findbestneighbor() tests centrums (faster)
else, qh_findbestneighbor() tests all vertices (much better merges)
qh_BESTcentrum2
if qh_BESTcentrum2 * DIM3 + BESTcentrum < #vertices tests centrums
*/
#define qh_BESTcentrum 20
#define qh_BESTcentrum2 2
/*-<a href="qh-user.htm#TOC"
>--------------------------------</a><a name="BESTnonconvex">-</a>
qh_BESTnonconvex
if > dim+n neighbors, qh_findbestneighbor() tests nonconvex ridges.
notes:
It is needed because qh_findbestneighbor is slow for large facets
*/
#define qh_BESTnonconvex 15
/*-<a href="qh-user.htm#TOC"
>--------------------------------</a><a name="MAXnewmerges">-</a>
qh_MAXnewmerges
if >n newmerges, qh_merge_nonconvex() calls qh_reducevertices_centrums.
notes:
It is needed because postmerge can merge many facets at once
*/
#define qh_MAXnewmerges 2
/*-<a href="qh-user.htm#TOC"
>--------------------------------</a><a name="MAXnewcentrum">-</a>
qh_MAXnewcentrum
if <= dim+n vertices (n approximates the number of merges),
reset the centrum in qh_updatetested() and qh_mergecycle_facets()
notes:
needed to reduce cost and because centrums may move too much if
many vertices in high-d
*/
#define qh_MAXnewcentrum 5
/*-<a href="qh-user.htm#TOC"
>--------------------------------</a><a name="COPLANARratio">-</a>
qh_COPLANARratio
for 3-d+ merging, qh.MINvisible is n*premerge_centrum
notes:
for non-merging, it's DISTround
*/
#define qh_COPLANARratio 3
/*-<a href="qh-user.htm#TOC"
>--------------------------------</a><a name="DISToutside">-</a>
qh_DISToutside
When is a point clearly outside of a facet?
Stops search in qh_findbestnew or qh_partitionall
qh_findbest uses qh.MINoutside since since it is only called if no merges.
notes:
'Qf' always searches for best facet
if !qh.MERGING, same as qh.MINoutside.
if qh_USEfindbestnew, increase value since neighboring facets may be ill-behaved
[Note: Zdelvertextot occurs normally with interior points]
RBOX 1000 s Z1 G1e-13 t1001188774 | QHULL Tv
When there is a sharp edge, need to move points to a
clearly good facet; otherwise may be lost in another partitioning.
if too big then O(n^2) behavior for partitioning in cone
if very small then important points not processed
Needed in qh_partitionall for
RBOX 1000 s Z1 G1e-13 t1001032651 | QHULL Tv
Needed in qh_findbestnew for many instances of
RBOX 1000 s Z1 G1e-13 t | QHULL Tv
See:
qh_DISToutside -- when is a point clearly outside of a facet
qh_SEARCHdist -- when is facet coplanar with the best facet?
qh_USEfindbestnew -- when to use qh_findbestnew for qh_partitionpoint()
*/
#define qh_DISToutside ((qh_USEfindbestnew ? 2 : 1) * \
fmax_((qh MERGING ? 2 : 1)*qh MINoutside, qh max_outside))
/*-<a href="qh-user.htm#TOC"
>--------------------------------</a><a name="RATIOnearinside">-</a>
qh_RATIOnearinside
ratio of qh.NEARinside to qh.ONEmerge for retaining inside points for
qh_check_maxout().
notes:
This is overkill since do not know the correct value.
It effects whether 'Qc' reports all coplanar points
Not used for 'd' since non-extreme points are coplanar
*/
#define qh_RATIOnearinside 5
/*-<a href="qh-user.htm#TOC"
>--------------------------------</a><a name="SEARCHdist">-</a>
qh_SEARCHdist
When is a facet coplanar with the best facet?
qh_findbesthorizon: all coplanar facets of the best facet need to be searched.
See:
qh_DISToutside -- when is a point clearly outside of a facet
qh_SEARCHdist -- when is facet coplanar with the best facet?
qh_USEfindbestnew -- when to use qh_findbestnew for qh_partitionpoint()
*/
#define qh_SEARCHdist ((qh_USEfindbestnew ? 2 : 1) * \
(qh max_outside + 2 * qh DISTround + fmax_( qh MINvisible, qh MAXcoplanar)));
/*-<a href="qh-user.htm#TOC"
>--------------------------------</a><a name="USEfindbestnew">-</a>
qh_USEfindbestnew
Always use qh_findbestnew for qh_partitionpoint, otherwise use
qh_findbestnew if merged new facet or sharpnewfacets.
See:
qh_DISToutside -- when is a point clearly outside of a facet
qh_SEARCHdist -- when is facet coplanar with the best facet?
qh_USEfindbestnew -- when to use qh_findbestnew for qh_partitionpoint()
*/
#define qh_USEfindbestnew (zzval_(Ztotmerge) > 50)
/*-<a href="qh-user.htm#TOC"
>--------------------------------</a><a name="WIDEcoplanar">-</a>
qh_WIDEcoplanar
n*MAXcoplanar or n*MINvisible for a WIDEfacet
if vertex is further than qh.WIDEfacet from the hyperplane
then its ridges are not counted in computing the area, and
the facet's centrum is frozen.
notes:
qh.WIDEfacet= max(qh.MAXoutside,qh_WIDEcoplanar*qh.MAXcoplanar,
qh_WIDEcoplanar * qh.MINvisible);
*/
#define qh_WIDEcoplanar 6
/*-<a href="qh-user.htm#TOC"
>--------------------------------</a><a name="MAXnarrow">-</a>
qh_MAXnarrow
max. cosine in initial hull that sets qh.NARROWhull
notes:
If qh.NARROWhull, the initial partition does not make
coplanar points. If narrow, a coplanar point can be
coplanar to two facets of opposite orientations and
distant from the exact convex hull.
Conservative estimate. Don't actually see problems until it is -1.0
*/
#define qh_MAXnarrow -0.99999999
/*-<a href="qh-user.htm#TOC"
>--------------------------------</a><a name="WARNnarrow">-</a>
qh_WARNnarrow
max. cosine in initial hull to warn about qh.NARROWhull
notes:
this is a conservative estimate.
Don't actually see problems until it is -1.0. See qh-impre.htm
*/
#define qh_WARNnarrow -0.999999999999999
/*-<a href="qh-user.htm#TOC"
>--------------------------------</a><a name="ZEROdelaunay">-</a>
qh_ZEROdelaunay
a zero Delaunay facet occurs for input sites coplanar with their convex hull
the last normal coefficient of a zero Delaunay facet is within
qh_ZEROdelaunay * qh.ANGLEround of 0
notes:
qh_ZEROdelaunay does not allow for joggled input ('QJ').
You can avoid zero Delaunay facets by surrounding the input with a box.
Use option 'PDk:-n' to explicitly define zero Delaunay facets
k= dimension of input sites (e.g., 3 for 3-d Delaunay triangulation)
n= the cutoff for zero Delaunay facets (e.g., 'PD3:-1e-12')
*/
#define qh_ZEROdelaunay 2
#endif /* qh_DEFuser */

View File

@@ -0,0 +1,64 @@
/*<html><pre> -<a href="qh-user.htm"
>-------------------------------</a><a name="TOP">-</a>
usermem.c
qh_exit(), qh_free(), and qh_malloc()
See README.txt.
If you redefine one of these functions you must redefine all of them.
If you recompile and load this file, then usermem.o will not be loaded
from qhull.a or qhull.lib
See libqhull.h for data structures, macros, and user-callable functions.
See user.c for qhull-related, redefinable functions
see user.h for user-definable constants
See userprintf.c for qh_fprintf and userprintf_rbox,c for qh_fprintf_rbox
Please report any errors that you fix to qhull@qhull.org
*/
#include "libqhull.h"
#include <stdlib.h>
/*-<a href="qh-user.htm#TOC"
>-------------------------------</a><a name="qh_exit">-</a>
qh_exit( exitcode )
exit program
notes:
same as exit()
*/
void qh_exit(int exitcode) {
exit(exitcode);
} /* exit */
/*-<a href="qh-user.htm#TOC"
>-------------------------------</a><a name="qh_free">-</a>
qh_free( mem )
free memory
notes:
same as free()
*/
void qh_free(void *mem) {
free(mem);
} /* free */
/*-<a href="qh-user.htm#TOC"
>-------------------------------</a><a name="qh_malloc">-</a>
qh_malloc( mem )
allocate memory
notes:
same as malloc()
*/
void *qh_malloc(size_t size) {
return malloc(size);
} /* malloc */

View File

@@ -0,0 +1,64 @@
/*<html><pre> -<a href="qh-user.htm"
>-------------------------------</a><a name="TOP">-</a>
userprintf.c
qh_fprintf()
see README.txt see COPYING.txt for copyright information.
If you recompile and load this file, then userprintf.o will not be loaded
from qhull.a or qhull.lib
See libqhull.h for data structures, macros, and user-callable functions.
See user.c for qhull-related, redefinable functions
see user.h for user-definable constants
See usermem.c for qh_exit(), qh_free(), and qh_malloc()
see Qhull.cpp and RboxPoints.cpp for examples.
Please report any errors that you fix to qhull@qhull.org
*/
#include "libqhull.h"
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
/*-<a href="qh-user.htm#TOC"
>-------------------------------</a><a name="qh_fprintf">-</a>
qh_fprintf(fp, msgcode, format, list of args )
print arguments to *fp according to format
Use qh_fprintf_rbox() for rboxlib.c
notes:
same as fprintf()
fgets() is not trapped like fprintf()
exit qh_fprintf via qh_errexit()
*/
void qh_fprintf(FILE *fp, int msgcode, const char *fmt, ... ) {
va_list args;
if (!fp) {
fprintf(stderr, "QH6232 Qhull internal error (userprintf.c): fp is 0. Wrong qh_fprintf called.\n");
qh_errexit(6232, NULL, NULL);
}
va_start(args, fmt);
#if qh_QHpointer
if (qh_qh && qh ANNOTATEoutput)
#else
if (qh ANNOTATEoutput)
#endif
{
fprintf(fp, "[QH%.4d]", msgcode);
}else if (msgcode >= MSG_ERROR && msgcode < MSG_STDERR ) {
fprintf(fp, "QH%.4d ", msgcode);
}
vfprintf(fp, fmt, args);
va_end(args);
/* Place debugging traps here. Use with option 'Tn' */
} /* qh_fprintf */

View File

@@ -0,0 +1,53 @@
/*<html><pre> -<a href="qh-user.htm"
>-------------------------------</a><a name="TOP">-</a>
userprintf_rbox.c
qh_fprintf_rbox()
see README.txt see COPYING.txt for copyright information.
If you recompile and load this file, then userprintf_rbox.o will not be loaded
from qhull.a or qhull.lib
See libqhull.h for data structures, macros, and user-callable functions.
See user.c for qhull-related, redefinable functions
see user.h for user-definable constants
See usermem.c for qh_exit(), qh_free(), and qh_malloc()
see Qhull.cpp and RboxPoints.cpp for examples.
Please report any errors that you fix to qhull@qhull.org
*/
#include "libqhull.h"
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
/*-<a href="qh-user.htm#TOC"
>-------------------------------</a><a name="qh_fprintf_rbox">-</a>
qh_fprintf_rbox(fp, msgcode, format, list of args )
print arguments to *fp according to format
Use qh_fprintf_rbox() for rboxlib.c
notes:
same as fprintf()
fgets() is not trapped like fprintf()
exit qh_fprintf_rbox via qh_errexit_rbox()
*/
void qh_fprintf_rbox(FILE *fp, int msgcode, const char *fmt, ... ) {
va_list args;
if (!fp) {
fprintf(stderr, "QH6231 Qhull internal error (userprintf.c): fp is 0. Wrong qh_fprintf_rbox called.\n");
qh_errexit_rbox(6231);
}
if (msgcode >= MSG_ERROR && msgcode < MSG_STDERR)
fprintf(fp, "QH%.4d ", msgcode);
va_start(args, fmt);
vfprintf(fp, fmt, args);
va_end(args);
} /* qh_fprintf_rbox */

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,616 @@
/******************************************************************************
*
* Project: GDAL
* Purpose: Vector polygon rasterization code.
* Author: Frank Warmerdam, warmerdam@pobox.com
*
******************************************************************************
* Copyright (c) 2000, Frank Warmerdam <warmerdam@pobox.com>
* Copyright (c) 2011, Even Rouault <even dot rouault at mines-paris dot org>
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included
* in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
****************************************************************************/
#include "cpl_port.h"
#include "gdal_alg_priv.h"
#include <cmath>
#include <cstdlib>
#include <cstring>
#include <algorithm>
#include <utility>
#include "gdal_alg.h"
CPL_CVSID("$Id: llrasterize.cpp 9ff327806cd64df6d73a6c91f92d12ca0c5e07df 2018-04-07 20:25:06 +0200 Even Rouault $")
static int llCompareInt(const void *a, const void *b)
{
return *static_cast<const int*>(a) - *static_cast<const int*>(b);
}
/************************************************************************/
/* dllImageFilledPolygon() */
/* */
/* Perform scanline conversion of the passed multi-ring */
/* polygon. Note the polygon does not need to be explicitly */
/* closed. The scanline function will be called with */
/* horizontal scanline chunks which may not be entirely */
/* contained within the valid raster area (in the X */
/* direction). */
/* */
/* NEW: Nodes' coordinate are kept as double in order */
/* to compute accurately the intersections with the lines */
/* */
/* Two methods for determining the border pixels: */
/* */
/* 1) method = 0 */
/* Inherits algorithm from version above but with several bugs */
/* fixed except for the cone facing down. */
/* A pixel on which a line intersects a segment of a */
/* polygon will always be considered as inside the shape. */
/* Note that we only compute intersections with lines that */
/* passes through the middle of a pixel (line coord = 0.5, */
/* 1.5, 2.5, etc.) */
/* */
/* 2) method = 1: */
/* A pixel is considered inside a polygon if its center */
/* falls inside the polygon. This is somehow more robust unless */
/* the nodes are placed in the center of the pixels in which */
/* case, due to numerical inaccuracies, it's hard to predict */
/* if the pixel will be considered inside or outside the shape. */
/************************************************************************/
/*
* NOTE: This code was originally adapted from the gdImageFilledPolygon()
* function in libgd.
*
* http://www.boutell.com/gd/
*
* It was later adapted for direct inclusion in GDAL and relicensed under
* the GDAL MIT/X license (pulled from the OpenEV distribution).
*/
void GDALdllImageFilledPolygon(int nRasterXSize, int nRasterYSize,
int nPartCount, int *panPartSize,
double *padfX, double *padfY,
double *dfVariant,
llScanlineFunc pfnScanlineFunc, void *pCBData )
{
/*************************************************************************
2nd Method (method=1):
=====================
No known bug
*************************************************************************/
if( !nPartCount )
{
return;
}
int n = 0;
for( int part = 0; part < nPartCount; part++ )
n += panPartSize[part];
// +1 to make clang static analyzer not warn about potential malloc(0).
int *polyInts = static_cast<int *>(malloc(sizeof(int) * (n + 1)));
double dminy = padfY[0];
double dmaxy = padfY[0];
for( int i = 1; i < n; i++ )
{
if( padfY[i] < dminy )
{
dminy = padfY[i];
}
if( padfY[i] > dmaxy )
{
dmaxy = padfY[i];
}
}
int miny = static_cast<int>(dminy);
int maxy = static_cast<int>(dmaxy);
if( miny < 0 )
miny = 0;
if( maxy >= nRasterYSize )
maxy = nRasterYSize - 1;
int minx = 0;
const int maxx = nRasterXSize - 1;
// Fix in 1.3: count a vertex only once.
for( int y = miny; y <= maxy; y++ )
{
int partoffset = 0;
const double dy = y + 0.5; // Center height of line.
int part = 0;
int ints = 0;
// Initialize polyInts, otherwise it can sometimes causes a seg fault.
memset(polyInts, -1, sizeof(int) * n);
for( int i = 0; i < n; i++ )
{
if( i == partoffset + panPartSize[part] )
{
partoffset += panPartSize[part];
part++;
}
int ind1 = 0;
int ind2 = 0;
if( i == partoffset )
{
ind1 = partoffset + panPartSize[part] - 1;
ind2 = partoffset;
}
else
{
ind1 = i-1;
ind2 = i;
}
double dy1 = padfY[ind1];
double dy2 = padfY[ind2];
if( (dy1 < dy && dy2 < dy) || (dy1 > dy && dy2 > dy) )
continue;
double dx1 = 0.0;
double dx2 = 0.0;
if( dy1 < dy2 )
{
dx1 = padfX[ind1];
dx2 = padfX[ind2];
}
else if( dy1 > dy2 )
{
dy2 = padfY[ind1];
dy1 = padfY[ind2];
dx2 = padfX[ind1];
dx1 = padfX[ind2];
}
else // if( fabs(dy1-dy2) < 1.e-6 )
{
// AE: DO NOT skip bottom horizontal segments
// -Fill them separately-
// They are not taken into account twice.
if( padfX[ind1] > padfX[ind2] )
{
const int horizontal_x1 =
static_cast<int>(floor(padfX[ind2] + 0.5));
const int horizontal_x2 =
static_cast<int>(floor(padfX[ind1] + 0.5));
if( (horizontal_x1 > maxx) || (horizontal_x2 <= minx) )
continue;
// Fill the horizontal segment (separately from the rest).
pfnScanlineFunc( pCBData, y, horizontal_x1,
horizontal_x2 - 1,
(dfVariant == nullptr)?0:dfVariant[0] );
}
// else: Skip top horizontal segments.
// They are already filled in the regular loop.
continue;
}
if( dy < dy2 && dy >= dy1 )
{
const double intersect = (dy-dy1) * (dx2-dx1) / (dy2-dy1) + dx1;
polyInts[ints++] = static_cast<int>(floor(intersect + 0.5));
}
}
// It would be more efficient to do this inline, to avoid
// a function call for each comparison.
// NOTE - mloskot: make llCompareInt a functor and use std
// algorithm and it will be optimized and expanded
// automatically in compile-time, with modularity preserved.
//
// TODO(schwehr): Use std::sort.
qsort(polyInts, ints, sizeof(int), llCompareInt);
for( int i = 0; i < ints; i += 2 )
{
if( polyInts[i] <= maxx && polyInts[i+1] > minx )
{
pfnScanlineFunc(pCBData, y, polyInts[i], polyInts[i+1] - 1,
dfVariant == nullptr ? 0 : dfVariant[0]);
}
}
}
free( polyInts );
}
/************************************************************************/
/* GDALdllImagePoint() */
/************************************************************************/
void GDALdllImagePoint( int nRasterXSize, int nRasterYSize,
int nPartCount,
CPL_UNUSED int *panPartSize,
double *padfX, double *padfY, double *padfVariant,
llPointFunc pfnPointFunc, void *pCBData )
{
for( int i = 0; i < nPartCount; i++ )
{
const int nX = static_cast<int>(floor( padfX[i] ));
const int nY = static_cast<int>(floor( padfY[i] ));
double dfVariant = 0.0;
if( padfVariant != nullptr )
dfVariant = padfVariant[i];
if( 0 <= nX && nX < nRasterXSize && 0 <= nY && nY < nRasterYSize )
pfnPointFunc( pCBData, nY, nX, dfVariant );
}
}
/************************************************************************/
/* GDALdllImageLine() */
/************************************************************************/
void GDALdllImageLine( int nRasterXSize, int nRasterYSize,
int nPartCount, int *panPartSize,
double *padfX, double *padfY, double *padfVariant,
llPointFunc pfnPointFunc, void *pCBData )
{
if( !nPartCount )
return;
for( int i = 0, n = 0; i < nPartCount; n += panPartSize[i++] )
{
for( int j = 1; j < panPartSize[i]; j++ )
{
int iX = static_cast<int>(floor( padfX[n + j - 1] ));
int iY = static_cast<int>(floor( padfY[n + j - 1] ));
const int iX1 = static_cast<int>(floor(padfX[n + j]));
const int iY1 = static_cast<int>(floor(padfY[n + j]));
double dfVariant = 0.0;
double dfVariant1 = 0.0;
if( padfVariant != nullptr &&
static_cast<GDALRasterizeInfo *>(pCBData)->eBurnValueSource !=
GBV_UserBurnValue )
{
dfVariant = padfVariant[n + j - 1];
dfVariant1 = padfVariant[n + j];
}
int nDeltaX = std::abs(iX1 - iX);
int nDeltaY = std::abs(iY1 - iY);
// Step direction depends on line direction.
const int nXStep = ( iX > iX1 ) ? -1 : 1;
const int nYStep = ( iY > iY1 ) ? -1 : 1;
// Determine the line slope.
if( nDeltaX >= nDeltaY )
{
const int nXError = nDeltaY << 1;
const int nYError = nXError - (nDeltaX << 1);
int nError = nXError - nDeltaX;
// == 0 makes clang -fcatch-undefined-behavior -ftrapv happy,
// but if it is == 0, dfDeltaVariant is not really used, so any
// value is okay.
const double dfDeltaVariant =
nDeltaX == 0
? 0.0
: (dfVariant1 - dfVariant) / nDeltaX;
while( nDeltaX-- >= 0 )
{
if( 0 <= iX && iX < nRasterXSize
&& 0 <= iY && iY < nRasterYSize )
pfnPointFunc( pCBData, iY, iX, dfVariant );
dfVariant += dfDeltaVariant;
iX += nXStep;
if( nError > 0 )
{
iY += nYStep;
nError += nYError;
}
else
{
nError += nXError;
}
}
}
else
{
const int nXError = nDeltaX << 1;
const int nYError = nXError - (nDeltaY << 1);
int nError = nXError - nDeltaY;
// == 0 makes clang -fcatch-undefined-behavior -ftrapv happy,
// but if it is == 0, dfDeltaVariant is not really used, so any
// value is okay.
double dfDeltaVariant =
nDeltaY == 0
? 0.0
: (dfVariant1 - dfVariant) / nDeltaY;
while( nDeltaY-- >= 0 )
{
if( 0 <= iX && iX < nRasterXSize
&& 0 <= iY && iY < nRasterYSize )
pfnPointFunc( pCBData, iY, iX, dfVariant );
dfVariant += dfDeltaVariant;
iY += nYStep;
if( nError > 0 )
{
iX += nXStep;
nError += nYError;
}
else
{
nError += nXError;
}
}
}
}
}
}
/************************************************************************/
/* GDALdllImageLineAllTouched() */
/* */
/* This alternate line drawing algorithm attempts to ensure */
/* that every pixel touched at all by the line will get set. */
/* @param padfVariant should contain the values that are to be */
/* added to the burn value. The values along the line between the */
/* points will be linearly interpolated. These values are used */
/* only if pCBData->eBurnValueSource is set to something other */
/* than GBV_UserBurnValue. If NULL is passed, a monotonous line */
/* will be drawn with the burn value. */
/************************************************************************/
void
GDALdllImageLineAllTouched( int nRasterXSize, int nRasterYSize,
int nPartCount, int *panPartSize,
double *padfX, double *padfY, double *padfVariant,
llPointFunc pfnPointFunc, void *pCBData )
{
if( !nPartCount )
return;
for( int i = 0, n = 0; i < nPartCount; n += panPartSize[i++] )
{
for( int j = 1; j < panPartSize[i]; j++ )
{
double dfX = padfX[n + j - 1];
double dfY = padfY[n + j - 1];
double dfXEnd = padfX[n + j];
double dfYEnd = padfY[n + j];
double dfVariant = 0.0;
double dfVariantEnd = 0.0;
if( padfVariant != nullptr &&
static_cast<GDALRasterizeInfo *>(pCBData)->eBurnValueSource !=
GBV_UserBurnValue )
{
dfVariant = padfVariant[n + j - 1];
dfVariantEnd = padfVariant[n + j];
}
// Skip segments that are off the target region.
if( (dfY < 0.0 && dfYEnd < 0.0)
|| (dfY > nRasterYSize && dfYEnd > nRasterYSize)
|| (dfX < 0.0 && dfXEnd < 0.0)
|| (dfX > nRasterXSize && dfXEnd > nRasterXSize) )
continue;
// Swap if needed so we can proceed from left2right (X increasing)
if( dfX > dfXEnd )
{
std::swap(dfX, dfXEnd);
std::swap(dfY, dfYEnd );
std::swap(dfVariant, dfVariantEnd);
}
// Special case for vertical lines.
if( floor(dfX) == floor(dfXEnd) || fabs(dfX - dfXEnd) < .01 )
{
if( dfYEnd < dfY )
{
std::swap(dfY, dfYEnd );
std::swap(dfVariant, dfVariantEnd);
}
const int iX = static_cast<int>(floor(dfXEnd));
int iY = static_cast<int>(floor(dfY));
int iYEnd = static_cast<int>(floor(dfYEnd));
if( iX < 0 || iX >= nRasterXSize )
continue;
double dfDeltaVariant = 0.0;
if( dfYEnd - dfY > 0.0 )
dfDeltaVariant =
( dfVariantEnd - dfVariant ) /
( dfYEnd - dfY ); // Per unit change in iY.
// Clip to the borders of the target region.
if( iY < 0 )
iY = 0;
if( iYEnd >= nRasterYSize )
iYEnd = nRasterYSize - 1;
dfVariant += dfDeltaVariant * (iY - dfY);
if( padfVariant == nullptr )
for( ; iY <= iYEnd; iY++ )
pfnPointFunc( pCBData, iY, iX, 0.0 );
else
for( ; iY <= iYEnd; iY++, dfVariant += dfDeltaVariant )
pfnPointFunc( pCBData, iY, iX, dfVariant );
continue; // Next segment.
}
const double dfDeltaVariant =
( dfVariantEnd - dfVariant ) /
( dfXEnd - dfX ); // Per unit change in iX.
// Special case for horizontal lines.
if( floor(dfY) == floor(dfYEnd) || fabs(dfY - dfYEnd) < .01 )
{
if( dfXEnd < dfX )
{
std::swap(dfX, dfXEnd);
std::swap(dfVariant, dfVariantEnd);
}
int iX = static_cast<int>(floor(dfX));
const int iY = static_cast<int>(floor(dfY));
int iXEnd = static_cast<int>(floor(dfXEnd));
if( iY < 0 || iY >= nRasterYSize )
continue;
// Clip to the borders of the target region.
if( iX < 0 )
iX = 0;
if( iXEnd >= nRasterXSize )
iXEnd = nRasterXSize - 1;
dfVariant += dfDeltaVariant * (iX - dfX);
if( padfVariant == nullptr )
for( ; iX <= iXEnd; iX++ )
pfnPointFunc( pCBData, iY, iX, 0.0 );
else
for( ; iX <= iXEnd; iX++, dfVariant += dfDeltaVariant )
pfnPointFunc( pCBData, iY, iX, dfVariant );
continue; // Next segment.
}
/* -------------------------------------------------------------------- */
/* General case - left to right sloped. */
/* -------------------------------------------------------------------- */
const double dfSlope = (dfYEnd - dfY) / (dfXEnd - dfX);
// Clip segment in X.
if( dfXEnd > nRasterXSize )
{
dfYEnd -= (dfXEnd - nRasterXSize) * dfSlope;
dfXEnd = nRasterXSize;
}
if( dfX < 0.0 )
{
dfY += (0.0 - dfX) * dfSlope;
dfVariant += dfDeltaVariant * (0.0 - dfX);
dfX = 0.0;
}
// Clip segment in Y.
double dfDiffX = 0.0;
if( dfYEnd > dfY )
{
if( dfY < 0.0 )
{
dfDiffX = (0.0 - dfY) / dfSlope;
dfX += dfDiffX;
dfVariant += dfDeltaVariant * dfDiffX;
dfY = 0.0;
}
if( dfYEnd >= nRasterYSize )
{
dfXEnd += (dfYEnd - nRasterYSize) / dfSlope;
// dfYEnd is no longer used afterwards, but for
// consistency it should be:
// dfYEnd = nRasterXSize;
}
}
else
{
if( dfY >= nRasterYSize )
{
dfDiffX = (nRasterYSize - dfY) / dfSlope;
dfX += dfDiffX;
dfVariant += dfDeltaVariant * dfDiffX;
dfY = nRasterYSize;
}
if( dfYEnd < 0.0 )
{
dfXEnd -= ( dfYEnd - 0 ) / dfSlope;
// dfYEnd is no longer used afterwards, but for
// consistency it should be:
// dfYEnd = 0.0;
}
}
// Step from pixel to pixel.
while( dfX >= 0.0 && dfX < dfXEnd )
{
const int iX = static_cast<int>(floor(dfX));
const int iY = static_cast<int>(floor(dfY));
// Burn in the current point.
// We should be able to drop the Y check because we clipped
// in Y, but there may be some error with all the small steps.
if( iY >= 0 && iY < nRasterYSize )
pfnPointFunc( pCBData, iY, iX, dfVariant );
double dfStepX = floor(dfX+1.0) - dfX;
double dfStepY = dfStepX * dfSlope;
// Step to right pixel without changing scanline?
if( static_cast<int>(floor(dfY + dfStepY)) == iY )
{
dfX += dfStepX;
dfY += dfStepY;
dfVariant += dfDeltaVariant * dfStepX;
}
else if( dfSlope < 0 )
{
dfStepY = iY - dfY;
if( dfStepY > -0.000000001 )
dfStepY = -0.000000001;
dfStepX = dfStepY / dfSlope;
dfX += dfStepX;
dfY += dfStepY;
dfVariant += dfDeltaVariant * dfStepX;
}
else
{
dfStepY = (iY + 1) - dfY;
if( dfStepY < 0.000000001 )
dfStepY = 0.000000001;
dfStepX = dfStepY / dfSlope;
dfX += dfStepX;
dfY += dfStepY;
dfVariant += dfDeltaVariant * dfStepX;
}
} // Next step along segment.
} // Next segment.
} // Next part.
}

Some files were not shown because too many files have changed in this diff Show More