Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
path: root/extern
diff options
context:
space:
mode:
Diffstat (limited to 'extern')
-rw-r--r--extern/CMakeLists.txt4
-rw-r--r--extern/SConscript3
-rw-r--r--extern/libmv/CMakeLists.txt210
-rw-r--r--extern/libmv/ChangeLog312
-rw-r--r--extern/libmv/SConscript60
-rwxr-xr-xextern/libmv/bundle.sh250
-rw-r--r--extern/libmv/files.txt141
-rw-r--r--extern/libmv/libmv-capi.cpp770
-rw-r--r--extern/libmv/libmv-capi.h128
-rw-r--r--extern/libmv/libmv/base/id_generator.h37
-rw-r--r--extern/libmv/libmv/base/scoped_ptr.h60
-rw-r--r--extern/libmv/libmv/base/vector.h172
-rw-r--r--extern/libmv/libmv/base/vector_utils.h34
-rw-r--r--extern/libmv/libmv/image/array_nd.cc108
-rw-r--r--extern/libmv/libmv/image/array_nd.h473
-rw-r--r--extern/libmv/libmv/image/convolve.cc305
-rw-r--r--extern/libmv/libmv/image/convolve.h93
-rw-r--r--extern/libmv/libmv/image/image.h158
-rw-r--r--extern/libmv/libmv/image/sample.h103
-rw-r--r--extern/libmv/libmv/image/tuple.h90
-rw-r--r--extern/libmv/libmv/logging/logging.h31
-rw-r--r--extern/libmv/libmv/multiview/conditioning.cc99
-rw-r--r--extern/libmv/libmv/multiview/conditioning.h60
-rw-r--r--extern/libmv/libmv/multiview/euclidean_resection.cc661
-rw-r--r--extern/libmv/libmv/multiview/euclidean_resection.h124
-rw-r--r--extern/libmv/libmv/multiview/fundamental.cc391
-rw-r--r--extern/libmv/libmv/multiview/fundamental.h144
-rw-r--r--extern/libmv/libmv/multiview/nviewtriangulation.h80
-rw-r--r--extern/libmv/libmv/multiview/projection.cc221
-rw-r--r--extern/libmv/libmv/multiview/projection.h231
-rw-r--r--extern/libmv/libmv/multiview/resection.h62
-rw-r--r--extern/libmv/libmv/multiview/triangulation.cc49
-rw-r--r--extern/libmv/libmv/multiview/triangulation.h38
-rw-r--r--extern/libmv/libmv/numeric/dogleg.h261
-rw-r--r--extern/libmv/libmv/numeric/function_derivative.h107
-rw-r--r--extern/libmv/libmv/numeric/levenberg_marquardt.h183
-rw-r--r--extern/libmv/libmv/numeric/numeric.cc136
-rw-r--r--extern/libmv/libmv/numeric/numeric.h479
-rw-r--r--extern/libmv/libmv/numeric/poly.cc23
-rw-r--r--extern/libmv/libmv/numeric/poly.h123
-rw-r--r--extern/libmv/libmv/simple_pipeline/bundle.cc184
-rw-r--r--extern/libmv/libmv/simple_pipeline/bundle.h72
-rw-r--r--extern/libmv/libmv/simple_pipeline/camera_intrinsics.cc351
-rw-r--r--extern/libmv/libmv/simple_pipeline/camera_intrinsics.h152
-rw-r--r--extern/libmv/libmv/simple_pipeline/detect.cc184
-rw-r--r--extern/libmv/libmv/simple_pipeline/detect.h95
-rw-r--r--extern/libmv/libmv/simple_pipeline/initialize_reconstruction.cc218
-rw-r--r--extern/libmv/libmv/simple_pipeline/initialize_reconstruction.h74
-rw-r--r--extern/libmv/libmv/simple_pipeline/intersect.cc205
-rw-r--r--extern/libmv/libmv/simple_pipeline/intersect.h77
-rw-r--r--extern/libmv/libmv/simple_pipeline/pipeline.cc317
-rw-r--r--extern/libmv/libmv/simple_pipeline/pipeline.h95
-rw-r--r--extern/libmv/libmv/simple_pipeline/reconstruction.cc191
-rw-r--r--extern/libmv/libmv/simple_pipeline/reconstruction.h217
-rw-r--r--extern/libmv/libmv/simple_pipeline/resect.cc271
-rw-r--r--extern/libmv/libmv/simple_pipeline/resect.h86
-rw-r--r--extern/libmv/libmv/simple_pipeline/tracks.cc159
-rw-r--r--extern/libmv/libmv/simple_pipeline/tracks.h119
-rw-r--r--extern/libmv/libmv/tracking/klt_region_tracker.cc132
-rw-r--r--extern/libmv/libmv/tracking/klt_region_tracker.h55
-rw-r--r--extern/libmv/libmv/tracking/pyramid_region_tracker.cc80
-rw-r--r--extern/libmv/libmv/tracking/pyramid_region_tracker.h46
-rw-r--r--extern/libmv/libmv/tracking/region_tracker.h48
-rw-r--r--extern/libmv/libmv/tracking/retrack_region_tracker.cc47
-rw-r--r--extern/libmv/libmv/tracking/retrack_region_tracker.h48
-rw-r--r--extern/libmv/libmv/tracking/sad.cc174
-rw-r--r--extern/libmv/libmv/tracking/sad.h109
-rw-r--r--extern/libmv/libmv/tracking/trklt_region_tracker.cc135
-rw-r--r--extern/libmv/libmv/tracking/trklt_region_tracker.h65
-rwxr-xr-xextern/libmv/mkfiles.sh4
-rw-r--r--extern/libmv/patches/bundle_tweaks.patch122
-rw-r--r--extern/libmv/patches/config_mac.patch13
-rw-r--r--extern/libmv/patches/detect.patch181
-rw-r--r--extern/libmv/patches/fast.patch24
-rw-r--r--extern/libmv/patches/function_derivative.patch21
-rw-r--r--extern/libmv/patches/high_distortion_crash_fix.patch21
-rw-r--r--extern/libmv/patches/levenberg_marquardt.patch71
-rw-r--r--extern/libmv/patches/mingw.patch13
-rw-r--r--extern/libmv/patches/msvc2010.patch12
-rw-r--r--extern/libmv/patches/overscan.patch182
-rw-r--r--extern/libmv/patches/scaled_distortion.patch261
-rw-r--r--extern/libmv/patches/series13
-rw-r--r--extern/libmv/patches/snrptinf_fix.patch15
-rw-r--r--extern/libmv/patches/v3d_verbosity.patch12
-rw-r--r--extern/libmv/third_party/fast/LICENSE30
-rw-r--r--extern/libmv/third_party/fast/README31
-rw-r--r--extern/libmv/third_party/fast/README.libmv9
-rw-r--r--extern/libmv/third_party/fast/fast.c71
-rw-r--r--extern/libmv/third_party/fast/fast.h39
-rw-r--r--extern/libmv/third_party/fast/fast_10.c4666
-rw-r--r--extern/libmv/third_party/fast/fast_11.c3910
-rw-r--r--extern/libmv/third_party/fast/fast_12.c3134
-rw-r--r--extern/libmv/third_party/fast/fast_9.c5910
-rw-r--r--extern/libmv/third_party/fast/nonmax.c117
-rw-r--r--extern/libmv/third_party/gflags/README.libmv14
-rw-r--r--extern/libmv/third_party/gflags/config.h110
-rw-r--r--extern/libmv/third_party/gflags/gflags.cc1971
-rw-r--r--extern/libmv/third_party/gflags/gflags.h589
-rw-r--r--extern/libmv/third_party/gflags/gflags_completions.cc765
-rw-r--r--extern/libmv/third_party/gflags/gflags_completions.h121
-rw-r--r--extern/libmv/third_party/gflags/gflags_reporting.cc446
-rw-r--r--extern/libmv/third_party/gflags/mutex.h349
-rw-r--r--extern/libmv/third_party/glog/AUTHORS2
-rw-r--r--extern/libmv/third_party/glog/COPYING65
-rw-r--r--extern/libmv/third_party/glog/ChangeLog59
-rw-r--r--extern/libmv/third_party/glog/NEWS0
-rw-r--r--extern/libmv/third_party/glog/README5
-rw-r--r--extern/libmv/third_party/glog/README.libmv38
-rw-r--r--extern/libmv/third_party/glog/src/base/commandlineflags.h132
-rw-r--r--extern/libmv/third_party/glog/src/base/googleinit.h51
-rw-r--r--extern/libmv/third_party/glog/src/base/mutex.h325
-rw-r--r--extern/libmv/third_party/glog/src/config.h11
-rw-r--r--extern/libmv/third_party/glog/src/config_linux.h164
-rw-r--r--extern/libmv/third_party/glog/src/config_mac.h159
-rw-r--r--extern/libmv/third_party/glog/src/demangle.cc1231
-rw-r--r--extern/libmv/third_party/glog/src/demangle.h84
-rw-r--r--extern/libmv/third_party/glog/src/glog/log_severity.h84
-rw-r--r--extern/libmv/third_party/glog/src/glog/logging.h1507
-rw-r--r--extern/libmv/third_party/glog/src/glog/raw_logging.h185
-rw-r--r--extern/libmv/third_party/glog/src/glog/vlog_is_on.h129
-rw-r--r--extern/libmv/third_party/glog/src/logging.cc1783
-rw-r--r--extern/libmv/third_party/glog/src/raw_logging.cc172
-rw-r--r--extern/libmv/third_party/glog/src/signalhandler.cc348
-rw-r--r--extern/libmv/third_party/glog/src/stacktrace.h60
-rw-r--r--extern/libmv/third_party/glog/src/stacktrace_generic-inl.h59
-rw-r--r--extern/libmv/third_party/glog/src/stacktrace_libunwind-inl.h87
-rw-r--r--extern/libmv/third_party/glog/src/stacktrace_powerpc-inl.h130
-rw-r--r--extern/libmv/third_party/glog/src/stacktrace_x86-inl.h139
-rw-r--r--extern/libmv/third_party/glog/src/stacktrace_x86_64-inl.h105
-rw-r--r--extern/libmv/third_party/glog/src/symbolize.cc681
-rw-r--r--extern/libmv/third_party/glog/src/symbolize.h116
-rw-r--r--extern/libmv/third_party/glog/src/utilities.cc335
-rw-r--r--extern/libmv/third_party/glog/src/utilities.h222
-rw-r--r--extern/libmv/third_party/glog/src/vlog_is_on.cc249
-rw-r--r--extern/libmv/third_party/glog/src/windows/config.h136
-rw-r--r--extern/libmv/third_party/glog/src/windows/glog/log_severity.h88
-rw-r--r--extern/libmv/third_party/glog/src/windows/glog/logging.h1510
-rw-r--r--extern/libmv/third_party/glog/src/windows/glog/raw_logging.h189
-rw-r--r--extern/libmv/third_party/glog/src/windows/glog/vlog_is_on.h133
-rw-r--r--extern/libmv/third_party/glog/src/windows/port.cc64
-rw-r--r--extern/libmv/third_party/glog/src/windows/port.h149
-rwxr-xr-xextern/libmv/third_party/glog/src/windows/preprocess.sh118
-rw-r--r--extern/libmv/third_party/ldl/CMakeLists.txt5
-rw-r--r--extern/libmv/third_party/ldl/Doc/ChangeLog39
-rw-r--r--extern/libmv/third_party/ldl/Doc/lesser.txt504
-rw-r--r--extern/libmv/third_party/ldl/Include/ldl.h104
-rw-r--r--extern/libmv/third_party/ldl/README.libmv10
-rw-r--r--extern/libmv/third_party/ldl/README.txt136
-rw-r--r--extern/libmv/third_party/ldl/Source/ldl.c507
-rw-r--r--extern/libmv/third_party/msinttypes/README.libmv5
-rw-r--r--extern/libmv/third_party/msinttypes/inttypes.h305
-rw-r--r--extern/libmv/third_party/msinttypes/stdint.h247
-rw-r--r--extern/libmv/third_party/ssba/COPYING.TXT165
-rw-r--r--extern/libmv/third_party/ssba/Geometry/v3d_cameramatrix.h204
-rw-r--r--extern/libmv/third_party/ssba/Geometry/v3d_distortion.h97
-rw-r--r--extern/libmv/third_party/ssba/Geometry/v3d_metricbundle.cpp365
-rw-r--r--extern/libmv/third_party/ssba/Geometry/v3d_metricbundle.h346
-rw-r--r--extern/libmv/third_party/ssba/Math/v3d_linear.h923
-rw-r--r--extern/libmv/third_party/ssba/Math/v3d_linear_utils.h391
-rw-r--r--extern/libmv/third_party/ssba/Math/v3d_mathutilities.h59
-rw-r--r--extern/libmv/third_party/ssba/Math/v3d_optimization.cpp955
-rw-r--r--extern/libmv/third_party/ssba/Math/v3d_optimization.h273
-rw-r--r--extern/libmv/third_party/ssba/README.TXT92
-rwxr-xr-xextern/libmv/third_party/ssba/README.libmv23
164 files changed, 51126 insertions, 0 deletions
diff --git a/extern/CMakeLists.txt b/extern/CMakeLists.txt
index 321ebc11985..a5dd3b16860 100644
--- a/extern/CMakeLists.txt
+++ b/extern/CMakeLists.txt
@@ -63,3 +63,7 @@ endif()
if(WITH_LZMA)
add_subdirectory(lzma)
endif()
+
+if(WITH_LIBMV)
+ add_subdirectory(libmv)
+endif()
diff --git a/extern/SConscript b/extern/SConscript
index f363d75d068..031471a8a01 100644
--- a/extern/SConscript
+++ b/extern/SConscript
@@ -28,3 +28,6 @@ if env['WITH_BF_LZO']:
if env['WITH_BF_LZMA']:
SConscript(['lzma/SConscript'])
+
+if env['WITH_BF_LIBMV']:
+ SConscript(['libmv/SConscript'])
diff --git a/extern/libmv/CMakeLists.txt b/extern/libmv/CMakeLists.txt
new file mode 100644
index 00000000000..41fc39c97ac
--- /dev/null
+++ b/extern/libmv/CMakeLists.txt
@@ -0,0 +1,210 @@
+# ***** BEGIN GPL LICENSE BLOCK *****
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software Foundation,
+# Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+#
+# The Original Code is Copyright (C) 2011, Blender Foundation
+# All rights reserved.
+#
+# Contributor(s): Blender Foundation,
+# Sergey Sharybin
+#
+# ***** END GPL LICENSE BLOCK *****
+
+set(INC
+ .
+ ../Eigen3
+ ./third_party/ssba
+ ./third_party/ldl/Include
+ ../colamd/Include
+)
+
+set(INC_SYS
+ ${PNG_INCLUDE_DIR}
+ ${ZLIB_INCLUDE_DIRS}
+)
+
+set(SRC
+ libmv-capi.cpp
+ libmv/numeric/numeric.cc
+ libmv/numeric/poly.cc
+ libmv/simple_pipeline/reconstruction.cc
+ libmv/simple_pipeline/resect.cc
+ libmv/simple_pipeline/intersect.cc
+ libmv/simple_pipeline/initialize_reconstruction.cc
+ libmv/simple_pipeline/camera_intrinsics.cc
+ libmv/simple_pipeline/pipeline.cc
+ libmv/simple_pipeline/detect.cc
+ libmv/simple_pipeline/tracks.cc
+ libmv/simple_pipeline/bundle.cc
+ libmv/image/convolve.cc
+ libmv/image/array_nd.cc
+ libmv/tracking/pyramid_region_tracker.cc
+ libmv/tracking/sad.cc
+ libmv/tracking/trklt_region_tracker.cc
+ libmv/tracking/klt_region_tracker.cc
+ libmv/tracking/retrack_region_tracker.cc
+ libmv/multiview/projection.cc
+ libmv/multiview/conditioning.cc
+ libmv/multiview/fundamental.cc
+ libmv/multiview/euclidean_resection.cc
+ libmv/multiview/triangulation.cc
+
+ third_party/ssba/Geometry/v3d_metricbundle.cpp
+ third_party/ssba/Math/v3d_optimization.cpp
+ third_party/gflags/gflags.cc
+ third_party/gflags/gflags_reporting.cc
+ third_party/gflags/gflags_completions.cc
+ third_party/fast/fast_9.c
+ third_party/fast/fast_10.c
+ third_party/fast/fast_11.c
+ third_party/fast/fast_12.c
+ third_party/fast/fast.c
+ third_party/fast/nonmax.c
+ third_party/ldl/Source/ldl.c
+
+ libmv-capi.h
+ libmv/logging/logging.h
+ libmv/numeric/dogleg.h
+ libmv/numeric/levenberg_marquardt.h
+ libmv/numeric/poly.h
+ libmv/numeric/function_derivative.h
+ libmv/numeric/numeric.h
+ libmv/simple_pipeline/resect.h
+ libmv/simple_pipeline/reconstruction.h
+ libmv/simple_pipeline/camera_intrinsics.h
+ libmv/simple_pipeline/tracks.h
+ libmv/simple_pipeline/detect.h
+ libmv/simple_pipeline/pipeline.h
+ libmv/simple_pipeline/intersect.h
+ libmv/simple_pipeline/bundle.h
+ libmv/simple_pipeline/initialize_reconstruction.h
+ libmv/image/convolve.h
+ libmv/image/tuple.h
+ libmv/image/array_nd.h
+ libmv/image/sample.h
+ libmv/image/image.h
+ libmv/tracking/region_tracker.h
+ libmv/tracking/retrack_region_tracker.h
+ libmv/tracking/sad.h
+ libmv/tracking/pyramid_region_tracker.h
+ libmv/tracking/trklt_region_tracker.h
+ libmv/tracking/klt_region_tracker.h
+ libmv/base/id_generator.h
+ libmv/base/vector.h
+ libmv/base/scoped_ptr.h
+ libmv/base/vector_utils.h
+ libmv/multiview/nviewtriangulation.h
+ libmv/multiview/resection.h
+ libmv/multiview/euclidean_resection.h
+ libmv/multiview/triangulation.h
+ libmv/multiview/projection.h
+ libmv/multiview/fundamental.h
+ libmv/multiview/conditioning.h
+
+ third_party/ssba/Geometry/v3d_metricbundle.h
+ third_party/ssba/Geometry/v3d_cameramatrix.h
+ third_party/ssba/Geometry/v3d_distortion.h
+ third_party/ssba/Math/v3d_linear_utils.h
+ third_party/ssba/Math/v3d_optimization.h
+ third_party/ssba/Math/v3d_mathutilities.h
+ third_party/ssba/Math/v3d_linear.h
+ third_party/gflags/gflags_completions.h
+ third_party/gflags/mutex.h
+ third_party/gflags/config.h
+ third_party/gflags/gflags.h
+ third_party/fast/fast.h
+ third_party/ldl/Include/ldl.h
+ third_party/msinttypes/stdint.h
+ third_party/msinttypes/inttypes.h
+)
+
+IF(WIN32)
+ list(APPEND SRC
+ third_party/glog/src/logging.cc
+ third_party/glog/src/raw_logging.cc
+ third_party/glog/src/utilities.cc
+ third_party/glog/src/vlog_is_on.cc
+ third_party/glog/src/windows/port.cc
+
+ third_party/glog/src/utilities.h
+ third_party/glog/src/stacktrace_generic-inl.h
+ third_party/glog/src/stacktrace.h
+ third_party/glog/src/stacktrace_x86_64-inl.h
+ third_party/glog/src/base/googleinit.h
+ third_party/glog/src/base/mutex.h
+ third_party/glog/src/base/commandlineflags.h
+ third_party/glog/src/stacktrace_powerpc-inl.h
+ third_party/glog/src/stacktrace_x86-inl.h
+ third_party/glog/src/config.h
+ third_party/glog/src/stacktrace_libunwind-inl.h
+ third_party/glog/src/windows/glog/raw_logging.h
+ third_party/glog/src/windows/glog/vlog_is_on.h
+ third_party/glog/src/windows/glog/logging.h
+ third_party/glog/src/windows/glog/log_severity.h
+ third_party/glog/src/windows/port.h
+ third_party/glog/src/windows/config.h
+ )
+
+ list(APPEND INC
+ ./third_party/glog/src/windows
+ ./third_party/msinttypes
+ )
+
+ IF(MSVC)
+ set(MSVC_OFLAGS O1 O2 Ox)
+ foreach(FLAG )
+ string(REPLACE "" "Od" CMAKE_CXX_FLAGS_RELEASE "")
+ string(REPLACE "" "Od" CMAKE_C_FLAGS_RELWITHDEBINFO "")
+ endforeach()
+ ENDIF(MSVC)
+ELSE(WIN32)
+ list(APPEND SRC
+ third_party/glog/src/utilities.cc
+ third_party/glog/src/symbolize.cc
+ third_party/glog/src/vlog_is_on.cc
+ third_party/glog/src/signalhandler.cc
+ third_party/glog/src/logging.cc
+ third_party/glog/src/demangle.cc
+ third_party/glog/src/raw_logging.cc
+
+ third_party/glog/src/utilities.h
+ third_party/glog/src/stacktrace_generic-inl.h
+ third_party/glog/src/config_mac.h
+ third_party/glog/src/stacktrace.h
+ third_party/glog/src/stacktrace_x86_64-inl.h
+ third_party/glog/src/symbolize.h
+ third_party/glog/src/base/googleinit.h
+ third_party/glog/src/base/mutex.h
+ third_party/glog/src/base/commandlineflags.h
+ third_party/glog/src/stacktrace_powerpc-inl.h
+ third_party/glog/src/stacktrace_x86-inl.h
+ third_party/glog/src/config.h
+ third_party/glog/src/demangle.h
+ third_party/glog/src/stacktrace_libunwind-inl.h
+ third_party/glog/src/glog/raw_logging.h
+ third_party/glog/src/glog/vlog_is_on.h
+ third_party/glog/src/glog/logging.h
+ third_party/glog/src/glog/log_severity.h
+ third_party/glog/src/config_linux.h
+ )
+
+ list(APPEND INC
+ ./third_party/glog/src
+ )
+ENDIF(WIN32)
+
+add_definitions(-DV3DLIB_ENABLE_SUITESPARSE -DGOOGLE_GLOG_DLL_DECL=)
+
+blender_add_lib(extern_libmv "${SRC}" "${INC}" "${INC_SYS}")
diff --git a/extern/libmv/ChangeLog b/extern/libmv/ChangeLog
new file mode 100644
index 00000000000..7e10abfead6
--- /dev/null
+++ b/extern/libmv/ChangeLog
@@ -0,0 +1,312 @@
+commit 531c79bf95fddaaa70707d1abcd4fdafda16bbf0
+Author: Matthias Fauconneau <matthias.fauconneau@gmail.com>
+Date: Sat Aug 20 00:00:42 2011 +0200
+
+ Display warped pattern in marker preview.
+
+commit bb5c27e671b6f8eb56ddf490f0795d59bede591b
+Author: Matthias Fauconneau <matthias.fauconneau@gmail.com>
+Date: Fri Aug 19 18:37:48 2011 +0200
+
+ Fix CMake build.
+
+commit 2ac7281ff6b9545b425dd84fb03bf9c5c98b4de2
+Author: Matthias Fauconneau <matthias.fauconneau@gmail.com>
+Date: Fri Aug 19 17:34:45 2011 +0200
+
+ Avoid symbol shadowing.
+
+commit 2a7c3de4acc60e0433b4952f69e30528dbafe0d2
+Author: Matthias Fauconneau <matthias.fauconneau@gmail.com>
+Date: Fri Aug 19 17:22:47 2011 +0200
+
+ Better dragging behavior when hitting borders.
+
+commit a14eb3953c9521b2e08ff9ddd45b33ff1f8aeafb
+Author: Matthias Fauconneau <matthias.fauconneau@gmail.com>
+Date: Fri Aug 19 17:12:12 2011 +0200
+
+ Update marker preview to new affine tracking.
+
+commit 5299ea67043459eda147950e589c2d327a8fbced
+Author: Matthias Fauconneau <matthias.fauconneau@gmail.com>
+Date: Fri Aug 19 16:05:54 2011 +0200
+
+ sqrt takes double precision.
+
+commit 9f9221ce151d788c49b48f6f293ab2e2f8813978
+Author: Matthias Fauconneau <matthias.fauconneau@gmail.com>
+Date: Fri Aug 19 16:04:37 2011 +0200
+
+ MSVC compatibility: heap allocate pattern, explicit float cast.
+
+commit 702658d2f8616964a6eeb3743fd85e97ac7ff09d
+Author: Matthias Fauconneau <matthias.fauconneau@gmail.com>
+Date: Fri Aug 19 14:59:24 2011 +0200
+
+ Expose regularization parameters (areaPenalty and conditionPenalty) in API.
+
+commit 3e84ae5fbac10451d4935418f6281a90cedace11
+Author: Matthias Fauconneau <matthias.fauconneau@gmail.com>
+Date: Fri Aug 19 14:19:27 2011 +0200
+
+ Add LaplaceFilter.
+ Add regularization in affine SAD Tracker (keep constant area and good condition number).
+ UI: Better track display (+enable line antialiasing).
+
+commit 6d26d9a8ccc4ce009fbf253898fea8864dd5001a
+Author: Matthias Fauconneau <matthias.fauconneau@gmail.com>
+Date: Fri Aug 19 10:25:26 2011 +0200
+
+ Add optimization for integer pixel search.
+ Allows more agressive settings for affine coordinate descent.
+
+commit 70ceae81c0ab561b07e640ecb9933f0a902b57cd
+Author: Matthias Fauconneau <matthias.fauconneau@gmail.com>
+Date: Fri Aug 19 00:02:12 2011 +0200
+
+ Document coordinate descent method in affine SAD matcher.
+ Add heuristic to prevent high distortions.
+
+commit 75520f4bc4ccbb272a1b4149d3b8d05a90f7f896
+Author: Matthias Fauconneau <matthias.fauconneau@gmail.com>
+Date: Thu Aug 18 23:14:17 2011 +0200
+
+ Fix affine iteration.
+
+commit 4e8e0aa6018e3eb2fbebdad7f1cbd6c909d26e79
+Author: Matthias Fauconneau <matthias.fauconneau@gmail.com>
+Date: Thu Aug 18 23:03:26 2011 +0200
+
+ Handle rotations.
+
+commit 3ce41cf3c1b5c136a61d8f4c63ccae3cafbdb8da
+Author: Matthias Fauconneau <matthias.fauconneau@gmail.com>
+Date: Thu Aug 18 22:24:47 2011 +0200
+
+ Slow brute-force affine diamond search implementation.
+
+commit 1c4acd03e030c1c50dc6fc36c419c72ea69a0713
+Author: Matthias Fauconneau <matthias.fauconneau@gmail.com>
+Date: Thu Aug 18 20:51:43 2011 +0200
+
+ Fix detect.cc.
+
+commit ec18cc5ea9ae2e641075a847e82d0aacb8415ad8
+Author: Matthias Fauconneau <matthias.fauconneau@gmail.com>
+Date: Thu Aug 18 17:45:37 2011 +0200
+
+ Compute and return Pearson product-moment correlation coefficient between reference and matched pattern.
+
+commit 21d4245c63a01bfc736192d55baf10983e7c9ec7
+Author: Matthias Fauconneau <matthias.fauconneau@gmail.com>
+Date: Thu Aug 18 16:18:44 2011 +0200
+
+ UI and API support for affine tracking.
+
+commit a4876d8c40dcde615b44009c38c49e9a1b1d4698
+Author: Matthias Fauconneau <matthias.fauconneau@gmail.com>
+Date: Wed Aug 17 20:26:01 2011 +0200
+
+ Hack to make sad.cc compile with MSVC on system without support for the SSE instruction set.
+
+commit 0de723dfce5bbe44dbd19be8cd6dd6e9b03b7924
+Author: Matthias Fauconneau <matthias.fauconneau@gmail.com>
+Date: Wed Aug 17 20:10:46 2011 +0200
+
+ Fix slow path (for computers without SSE2).
+ Heap allocate scores in detect.cc
+
+commit 65a9d496f81e8b37eae39a4063957b8be9a4e6f0
+Author: Matthias Fauconneau <matthias.fauconneau@gmail.com>
+Date: Wed Aug 17 19:25:17 2011 +0200
+
+ Fix compilation on OSX.
+
+commit d22720e618456329388d2c107422c3b371657cba
+Author: Matthias Fauconneau <matthias.fauconneau@gmail.com>
+Date: Wed Aug 17 14:14:45 2011 +0200
+
+ Improve Detect and SAD Tracker API and documentation.
+
+commit 5d6cd4ad365b061901bad40695b51d568487a0cf
+Author: Matthias Fauconneau <matthias.fauconneau@gmail.com>
+Date: Wed Aug 17 11:57:29 2011 +0200
+
+ MSVC support fixes.
+
+commit 50f0323173c6deebd6aaf9c126f0b51b2a79c3c1
+Author: Matthias Fauconneau <matthias.fauconneau@gmail.com>
+Date: Tue Aug 16 23:21:37 2011 +0200
+
+ Detector can detect features similar to a given pattern.
+
+commit 5734cc27bbf84c2b6edcfcc1ea736798e12d5820
+Author: Matthias Fauconneau <matthias.fauconneau@gmail.com>
+Date: Tue Aug 16 22:53:54 2011 +0200
+
+ Ensure SAD Tracker is C compatible.
+ Update Detect API documentation.
+
+commit 701c42842574064fea992f8822e3899cb9066108
+Author: Matthias Fauconneau <matthias.fauconneau@gmail.com>
+Date: Tue Aug 16 21:56:42 2011 +0200
+
+ Remove FAST detector.
+ Add Moravec detector.
+ This detector is more suited to tracking since it try to choose patterns which are unlikely to drift by computing SAD with neighbouring patches.
+ It could be improved to better avoid edges.
+
+commit 9bdf93e13fc880c78b6f34397da673388c16040e
+Author: Matthias Fauconneau <matthias.fauconneau@gmail.com>
+Date: Tue Aug 16 21:55:08 2011 +0200
+
+ Fix Qt Tracker GL to work with AMD drivers.
+
+commit 81613ee0cc94b315f333c9632b18b95d426aad05
+Author: Matthias Fauconneau <matthias.fauconneau@gmail.com>
+Date: Tue Aug 16 21:54:12 2011 +0200
+
+ Make CameraIntrinsics (and thus Qt tracker) compilable without linking libmv.
+
+commit a1d9a8fa8b01ef7cf2a79b3b891633fc333fc9cf
+Author: Matthias Fauconneau <matthias.fauconneau@gmail.com>
+Date: Tue Aug 16 21:24:51 2011 +0200
+
+ Fix SAD tracker. Pattern was transposed by affine pattern sampler.
+
+commit c3b794da2e7fd23f2fbdf90dbd71de0e6b3bc811
+Author: Matthias Fauconneau <matthias.fauconneau@gmail.com>
+Date: Tue Aug 16 21:19:02 2011 +0200
+
+ Fix SAD tracker. Pattern was transposed by affine pattern sampler.
+
+commit a9b61bf3356f27174cdd983f562f99c3a6a2cc35
+Author: Matthias Fauconneau <matthias.fauconneau@gmail.com>
+Date: Sun Aug 14 09:56:51 2011 +0200
+
+ Clarify CameraIntrinsics documentation.
+ Edit CameraInstrinsics test to fail.
+
+commit 10bdad9ad2cea2603896263cde5a5339169a9af0
+Author: Matthias Fauconneau <matthias.fauconneau@gmail.com>
+Date: Fri Aug 12 21:05:32 2011 +0200
+
+ Fix out of bound access in warp bilinear sampling.
+
+commit dd9a418db021a28af2c1198d5e5b9e68fe048a03
+Author: Matthias Fauconneau <matthias.fauconneau@gmail.com>
+Date: Fri Aug 12 19:14:36 2011 +0200
+
+ Fix compilation with -funsigned-char.
+
+commit bd1a268ede39b67f2ba4b360f6fc693419e7cd7f
+Author: Matthias Fauconneau <matthias.fauconneau@gmail.com>
+Date: Fri Aug 12 18:39:27 2011 +0200
+
+ CameraIntrinsics fixes.
+
+commit ae513b39fb779632f96ceff7c1e014fb8e68702a
+Author: Matthias Fauconneau <matthias.fauconneau@gmail.com>
+Date: Tue Aug 9 19:38:58 2011 +0200
+
+ Remove stray QDebug include.
+
+commit 1e58f55078ce6009a885be30ae0316aec6ed8239
+Author: Matthias Fauconneau <matthias.fauconneau@gmail.com>
+Date: Tue Aug 9 14:16:31 2011 +0200
+
+ Make API future-proof (for an eventual affine or planar tracker).
+
+commit c2af303e7bf0dddcb02937323ac5846b1801e6cc
+Author: Matthias Fauconneau <matthias.fauconneau@gmail.com>
+Date: Tue Aug 9 11:13:29 2011 +0200
+
+ Remove reconstruction breaking debug code.
+
+commit 8792a633e5c5f1c1f12e164b9e8897ca0790ac59
+Author: Matthias Fauconneau <matthias.fauconneau@gmail.com>
+Date: Tue Aug 9 10:49:18 2011 +0200
+
+ Remove getchar()s.
+
+commit 63a9bdee0cbd1197e0315d01c27bfc2361bd5656
+Author: Matthias Fauconneau <matthias.fauconneau@gmail.com>
+Date: Tue Aug 9 10:35:07 2011 +0200
+
+ Adapt patch to new PipelineRoutines code generation strategy.
+
+commit 096ff1a4070f7212c50fb0a4b2feec7ca9d97158
+Author: Matthias Fauconneau <matthias.fauconneau@gmail.com>
+Date: Tue Aug 9 09:54:12 2011 +0200
+
+ Merge max_image and max_track fix from tomato.
+
+commit d8450cd3c37278a397482cd36b1e2419f154cfb9
+Author: Matthias Fauconneau <matthias.fauconneau@gmail.com>
+Date: Tue Aug 9 09:38:49 2011 +0200
+
+ Synchronize tree with Tomato: Merge patch for better resection, keep deprecated KLT tracker.
+
+commit e9b2dca920cf9575c15150a4988634b00e343a41
+Author: Matthias Fauconneau <matthias.fauconneau@gmail.com>
+Date: Mon Aug 8 17:07:08 2011 +0200
+
+ Fixes, Documentation.
+
+commit 4fc1c57a2d92442808ac4a3676e6d9a25a51e310
+Author: Matthias Fauconneau <matthias.fauconneau@gmail.com>
+Date: Sun Aug 7 14:35:08 2011 +0200
+
+ Improve tracker resilience by penalizing large motion vectors.
+
+commit cc8e7e8e08cd91f75c080a0091461ca9fe969664
+Author: Matthias Fauconneau <matthias.fauconneau@gmail.com>
+Date: Sun Aug 7 09:28:09 2011 +0200
+
+ Leverage SSE2 SAD instruction for 16x speed improvement in integer pixel search resulting in ~1ms per marker for 16x16 pattern on 128x128 region.
+
+commit f362ab4999a768370fca57552464b459eb9fbddc
+Author: Matthias Fauconneau <matthias.fauconneau@gmail.com>
+Date: Sun Aug 7 09:06:04 2011 +0200
+
+ Improve SAD Tracker subpixel precision (avoid drift even when adapting at each frame).
+
+commit fce7a214c561b5f5f0e17115c31fb48814bde2db
+Author: Matthias Fauconneau <matthias.fauconneau@gmail.com>
+Date: Sat Aug 6 21:57:06 2011 +0200
+
+ Track using simple Sum of Absolute Differences matching.
+ This method is simpler, more robust, faster and accurate.
+
+commit 620a7a35d9a2818bf6e9dbf5d11debda4be6bc26
+Author: Matthias Fauconneau <matthias.fauconneau@gmail.com>
+Date: Fri Jul 29 12:35:57 2011 +0200
+
+ Add Intersect unit test.
+
+commit a2bf58fa57be11215eb17ff7f7de58f97d480ec3
+Author: Matthias Fauconneau <matthias.fauconneau@gmail.com>
+Date: Thu Jul 28 11:08:06 2011 +0200
+
+ Remove tests depending on dead code.
+ Fix CameraIntrinsics test.
+ Add Intersect and Resect tests.
+
+commit 19bddee10b4879c8cd2238ccdf5b8f7620cf8384
+Author: Matthias Fauconneau <matthias.fauconneau@gmail.com>
+Date: Wed Jul 27 12:07:21 2011 +0200
+
+ Image Distortion: Fixes and more testing.
+
+commit 0454d97da328fb0eda8c6c50511ac31864a6d3d6
+Author: Matthias Fauconneau <matthias.fauconneau@gmail.com>
+Date: Wed Jul 27 10:32:37 2011 +0200
+
+ Test float image distortion.
+
+commit 8db01595a8721f766d85931a8d92b780461d8741
+Author: Matthias Fauconneau <matthias.fauconneau@gmail.com>
+Date: Wed Jul 27 10:27:07 2011 +0200
+
+ Image Distortion: Bilinear sampling, Optimization, Instantiate all variants (Distort/Undistort, float/ubyte, 1-4 channels).
diff --git a/extern/libmv/SConscript b/extern/libmv/SConscript
new file mode 100644
index 00000000000..1ffc6233c1d
--- /dev/null
+++ b/extern/libmv/SConscript
@@ -0,0 +1,60 @@
+#!/usr/bin/python
+import sys
+import os
+
+Import('env')
+
+defs = []
+
+cflags_libmv = Split(env['CFLAGS'])
+ccflags_libmv = Split(env['CCFLAGS'])
+cxxflags_libmv = Split(env['CXXFLAGS'])
+
+defs.append('V3DLIB_ENABLE_SUITESPARSE')
+defs.append('GOOGLE_GLOG_DLL_DECL=')
+
+src = env.Glob("*.cpp")
+src += env.Glob('libmv/image/*.cc')
+src += env.Glob('libmv/multiview/*.cc')
+src += env.Glob('libmv/numeric/*.cc')
+src += env.Glob('libmv/simple_pipeline/*.cc')
+src += env.Glob('libmv/tracking/*.cc')
+src += env.Glob('third_party/fast/*.c')
+src += env.Glob('third_party/gflags/*.cc')
+src += env.Glob('third_party/ldl/Source/*.c')
+src += env.Glob('third_party/ssba/Geometry/*.cpp')
+src += env.Glob('third_party/ssba/Math/*.cpp')
+
+incs = '. ../Eigen3'
+incs += ' ' + env['BF_PNG_INC']
+incs += ' ' + env['BF_ZLIB_INC']
+
+if env['OURPLATFORM'] in ('win32-vc', 'win32-mingw', 'linuxcross', 'win64-vc'):
+ incs += ' ./third_party/glog/src/windows ./third_party/glog/src/windows/glog ./third_party/msinttypes'
+
+ src += ['./third_party/glog/src/logging.cc', './third_party/glog/src/raw_logging.cc', './third_party/glog/src/utilities.cc', './third_party/glog/src/vlog_is_on.cc']
+ src += ['./third_party/glog/src/windows/port.cc']
+
+ if env['OURPLATFORM'] in ('win32-vc', 'win64-vc'):
+ cflags_libmv.append('/Od')
+ ccflags_libmv.append('/Od')
+ cxxflags_libmv.append('/Od')
+
+ if not env['BF_DEBUG']:
+ defs.append('NDEBUG')
+ else:
+ if not env['BF_DEBUG']:
+ cflags_libmv = Split(env['REL_CFLAGS'])
+ ccflags_libmv = Split(env['REL_CCFLAGS'])
+ cxxflags_libmv = Split(env['REL_CXXFLAGS'])
+else:
+ src += env.Glob("third_party/glog/src/*.cc")
+ incs += ' ./third_party/glog/src'
+ if not env['BF_DEBUG']:
+ cflags_libmv = Split(env['REL_CFLAGS'])
+ ccflags_libmv = Split(env['REL_CCFLAGS'])
+ cxxflags_libmv = Split(env['REL_CXXFLAGS'])
+
+incs += ' ./third_party/ssba ./third_party/ldl/Include ../colamd/Include'
+
+env.BlenderLib ( libname = 'extern_libmv', sources=src, includes=Split(incs), defines=defs, libtype=['extern', 'player'], priority=[20,137], compileflags=cflags_libmv, cc_compileflags=ccflags_libmv, cxx_compileflags=cxxflags_libmv )
diff --git a/extern/libmv/bundle.sh b/extern/libmv/bundle.sh
new file mode 100755
index 00000000000..c8df8ae7341
--- /dev/null
+++ b/extern/libmv/bundle.sh
@@ -0,0 +1,250 @@
+#!/bin/sh
+
+#BRANCH="keir"
+BRANCH="Matthias-Fauconneau"
+
+if [ -d ./.svn ]; then
+ echo "This script is supposed to work only when using git-svn"
+ exit 1
+fi
+
+repo="git://github.com/${BRANCH}/libmv.git"
+tmp=`mktemp -d`
+
+git clone $repo $tmp/libmv
+
+#git --git-dir $tmp/libmv/.git --work-tree $tmp/libmv log --since="1 month ago" > ChangeLog
+git --git-dir $tmp/libmv/.git --work-tree $tmp/libmv log -n 50 > ChangeLog
+
+for p in `cat ./patches/series`; do
+ echo "Applying patch $p..."
+ cat ./patches/$p | patch -d $tmp/libmv -p1
+done
+
+rm -rf libmv
+rm -rf third_party
+
+cat "files.txt" | while f=`line`; do
+ mkdir -p `dirname $f`
+ cp $tmp/libmv/src/$f $f
+done
+
+rm -rf $tmp
+
+chmod 664 ./third_party/glog/src/windows/*.cc ./third_party/glog/src/windows/*.h ./third_party/glog/src/windows/glog/*.h
+
+sources=`find ./libmv -type f -iname '*.cc' -or -iname '*.cpp' -or -iname '*.c' | sed -r 's/^\.\//\t/'`
+headers=`find ./libmv -type f -iname '*.h' | sed -r 's/^\.\//\t/'`
+
+third_sources=`find ./third_party -type f -iname '*.cc' -or -iname '*.cpp' -or -iname '*.c' | grep -v glog | sed -r 's/^\.\//\t/'`
+third_headers=`find ./third_party -type f -iname '*.h' | grep -v glog | sed -r 's/^\.\//\t/'`
+
+third_glog_sources=`find ./third_party -type f -iname '*.cc' -or -iname '*.cpp' -or -iname '*.c' | grep glog | grep -v windows | sed -r 's/^\.\//\t\t/'`
+third_glog_headers=`find ./third_party -type f -iname '*.h' | grep glog | grep -v windows | sed -r 's/^\.\//\t\t/'`
+
+src_dir=`find ./libmv -type f -iname '*.cc' -exec dirname {} \; -or -iname '*.cpp' -exec dirname {} \; -or -iname '*.c' -exec dirname {} \; | sed -r 's/^\.\//\t/' | sort | uniq`
+src_third_dir=`find ./third_party -type f -iname '*.cc' -exec dirname {} \; -or -iname '*.cpp' -exec dirname {} \; -or -iname '*.c' -exec dirname {} \; | sed -r 's/^\.\//\t/' | sort | uniq`
+src=""
+win_src=""
+for x in $src_dir $src_third_dir; do
+ t=""
+
+ if test `echo "$x" | grep -c glog ` -eq 1; then
+ continue;
+ fi
+
+ if stat $x/*.cpp > /dev/null 2>&1; then
+ t="src += env.Glob('`echo $x'/*.cpp'`')"
+ fi
+
+ if stat $x/*.c > /dev/null 2>&1; then
+ if [ -z "$t" ]; then
+ t="src += env.Glob('`echo $x'/*.c'`')"
+ else
+ t="$t + env.Glob('`echo $x'/*.c'`')"
+ fi
+ fi
+
+ if stat $x/*.cc > /dev/null 2>&1; then
+ if [ -z "$t" ]; then
+ t="src += env.Glob('`echo $x'/*.cc'`')"
+ else
+ t="$t + env.Glob('`echo $x'/*.cc'`')"
+ fi
+ fi
+
+ if test `echo $x | grep -c windows ` -eq 0; then
+ if [ -z "$src" ]; then
+ src=$t
+ else
+ src=`echo "$src\n$t"`
+ fi
+ else
+ if [ -z "$win_src" ]; then
+ win_src=`echo " $t"`
+ else
+ win_src=`echo "$win_src\n $t"`
+ fi
+ fi
+done
+
+cat > CMakeLists.txt << EOF
+# \$Id\$
+# ***** BEGIN GPL LICENSE BLOCK *****
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software Foundation,
+# Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+#
+# The Original Code is Copyright (C) 2011, Blender Foundation
+# All rights reserved.
+#
+# Contributor(s): Blender Foundation,
+# Sergey Sharybin
+#
+# ***** END GPL LICENSE BLOCK *****
+
+set(INC
+ .
+ ../Eigen3
+ ./third_party/ssba
+ ./third_party/ldl/Include
+ ../colamd/Include
+)
+
+set(INC_SYS
+ ${PNG_INCLUDE_DIR}
+ ${ZLIB_INCLUDE_DIRS}
+)
+
+set(SRC
+ libmv-capi.cpp
+${sources}
+
+${third_sources}
+
+ libmv-capi.h
+${headers}
+
+${third_headers}
+)
+
+IF(WIN32)
+ list(APPEND SRC
+ third_party/glog/src/logging.cc
+ third_party/glog/src/raw_logging.cc
+ third_party/glog/src/utilities.cc
+ third_party/glog/src/vlog_is_on.cc
+ third_party/glog/src/windows/port.cc
+
+ third_party/glog/src/utilities.h
+ third_party/glog/src/stacktrace_generic-inl.h
+ third_party/glog/src/stacktrace.h
+ third_party/glog/src/stacktrace_x86_64-inl.h
+ third_party/glog/src/base/googleinit.h
+ third_party/glog/src/base/mutex.h
+ third_party/glog/src/base/commandlineflags.h
+ third_party/glog/src/stacktrace_powerpc-inl.h
+ third_party/glog/src/stacktrace_x86-inl.h
+ third_party/glog/src/config.h
+ third_party/glog/src/stacktrace_libunwind-inl.h
+ third_party/glog/src/windows/glog/raw_logging.h
+ third_party/glog/src/windows/glog/vlog_is_on.h
+ third_party/glog/src/windows/glog/logging.h
+ third_party/glog/src/windows/glog/log_severity.h
+ third_party/glog/src/windows/port.h
+ third_party/glog/src/windows/config.h
+ )
+
+ list(APPEND INC
+ ./third_party/glog/src/windows
+ ./third_party/msinttypes
+ )
+
+ IF(MSVC)
+ set(MSVC_OFLAGS O1 O2 Ox)
+ foreach(FLAG ${MSVC_OFLAGS})
+ string(REPLACE "${FLAG}" "Od" CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE}")
+ string(REPLACE "${FLAG}" "Od" CMAKE_C_FLAGS_RELWITHDEBINFO "${CMAKE_C_FLAGS_RELWITHDEBINFO}")
+ endforeach()
+ ENDIF(MSVC)
+ELSE(WIN32)
+ list(APPEND SRC
+${third_glog_sources}
+
+${third_glog_headers}
+ )
+
+ list(APPEND INC
+ ./third_party/glog/src
+ )
+ENDIF(WIN32)
+
+add_definitions(-DV3DLIB_ENABLE_SUITESPARSE -DGOOGLE_GLOG_DLL_DECL=)
+
+blender_add_lib(extern_libmv "\${SRC}" "\${INC}" "\${INC_SYS}")
+EOF
+
+cat > SConscript << EOF
+#!/usr/bin/python
+import sys
+import os
+
+Import('env')
+
+defs = []
+
+cflags_libmv = Split(env['CFLAGS'])
+ccflags_libmv = Split(env['CCFLAGS'])
+cxxflags_libmv = Split(env['CXXFLAGS'])
+
+defs.append('V3DLIB_ENABLE_SUITESPARSE')
+defs.append('GOOGLE_GLOG_DLL_DECL=')
+
+src = env.Glob("*.cpp")
+$src
+
+incs = '. ../Eigen3'
+incs += ' ' + env['BF_PNG_INC']
+incs += ' ' + env['BF_ZLIB_INC']
+
+if env['OURPLATFORM'] in ('win32-vc', 'win32-mingw', 'linuxcross', 'win64-vc'):
+ incs += ' ./third_party/glog/src/windows ./third_party/glog/src/windows/glog ./third_party/msinttypes'
+${win_src}
+ src += ['./third_party/glog/src/logging.cc', './third_party/glog/src/raw_logging.cc', './third_party/glog/src/utilities.cc', './third_party/glog/src/vlog_is_on.cc']
+ src += ['./third_party/glog/src/windows/port.cc']
+
+ if env['OURPLATFORM'] in ('win32-vc', 'win64-vc'):
+ cflags_libmv.append('/Od')
+ ccflags_libmv.append('/Od')
+ cxxflags_libmv.append('/Od')
+
+ if not env['BF_DEBUG']:
+ defs.append('NDEBUG')
+ else:
+ if not env['BF_DEBUG']:
+ cflags_libmv = Split(env['REL_CFLAGS'])
+ ccflags_libmv = Split(env['REL_CCFLAGS'])
+ cxxflags_libmv = Split(env['REL_CXXFLAGS'])
+else:
+ src += env.Glob("third_party/glog/src/*.cc")
+ incs += ' ./third_party/glog/src'
+ if not env['BF_DEBUG']:
+ cflags_libmv = Split(env['REL_CFLAGS'])
+ ccflags_libmv = Split(env['REL_CCFLAGS'])
+ cxxflags_libmv = Split(env['REL_CXXFLAGS'])
+
+incs += ' ./third_party/ssba ./third_party/ldl/Include ../colamd/Include'
+
+env.BlenderLib ( libname = 'extern_libmv', sources=src, includes=Split(incs), defines=defs, libtype=['extern', 'player'], priority=[20,137], compileflags=cflags_libmv, cc_compileflags=ccflags_libmv, cxx_compileflags=cxxflags_libmv )
+EOF
diff --git a/extern/libmv/files.txt b/extern/libmv/files.txt
new file mode 100644
index 00000000000..fe6be5d0b20
--- /dev/null
+++ b/extern/libmv/files.txt
@@ -0,0 +1,141 @@
+libmv/logging/logging.h
+libmv/numeric/dogleg.h
+libmv/numeric/levenberg_marquardt.h
+libmv/numeric/poly.h
+libmv/numeric/numeric.cc
+libmv/numeric/function_derivative.h
+libmv/numeric/poly.cc
+libmv/numeric/tinyvector.cc
+libmv/numeric/numeric.h
+libmv/simple_pipeline/reconstruction.cc
+libmv/simple_pipeline/resect.h
+libmv/simple_pipeline/resect.cc
+libmv/simple_pipeline/reconstruction.h
+libmv/simple_pipeline/camera_intrinsics.h
+libmv/simple_pipeline/intersect.cc
+libmv/simple_pipeline/initialize_reconstruction.cc
+libmv/simple_pipeline/camera_intrinsics.cc
+libmv/simple_pipeline/pipeline.cc
+libmv/simple_pipeline/tracks.h
+libmv/simple_pipeline/detect.h
+libmv/simple_pipeline/detect.cc
+libmv/simple_pipeline/pipeline.h
+libmv/simple_pipeline/tracks.cc
+libmv/simple_pipeline/bundle.cc
+libmv/simple_pipeline/intersect.h
+libmv/simple_pipeline/bundle.h
+libmv/simple_pipeline/initialize_reconstruction.h
+libmv/image/convolve.h
+libmv/image/tuple.h
+libmv/image/array_nd.h
+libmv/image/convolve.cc
+libmv/image/array_nd.cc
+libmv/image/sample.h
+libmv/image/image.h
+libmv/tracking/pyramid_region_tracker.cc
+libmv/tracking/region_tracker.h
+libmv/tracking/sad.cc
+libmv/tracking/trklt_region_tracker.cc
+libmv/tracking/klt_region_tracker.cc
+libmv/tracking/retrack_region_tracker.h
+libmv/tracking/sad.h
+libmv/tracking/pyramid_region_tracker.h
+libmv/tracking/trklt_region_tracker.h
+libmv/tracking/retrack_region_tracker.cc
+libmv/tracking/klt_region_tracker.h
+libmv/base/id_generator.h
+libmv/base/vector.h
+libmv/base/scoped_ptr.h
+libmv/base/vector_utils.h
+libmv/multiview/projection.cc
+libmv/multiview/conditioning.cc
+libmv/multiview/nviewtriangulation.h
+libmv/multiview/resection.h
+libmv/multiview/fundamental.cc
+libmv/multiview/euclidean_resection.cc
+libmv/multiview/euclidean_resection.h
+libmv/multiview/triangulation.h
+libmv/multiview/projection.h
+libmv/multiview/triangulation.cc
+libmv/multiview/fundamental.h
+libmv/multiview/conditioning.h
+third_party/ssba/README.TXT
+third_party/ssba/COPYING.TXT
+third_party/ssba/Geometry/v3d_metricbundle.h
+third_party/ssba/Geometry/v3d_metricbundle.cpp
+third_party/ssba/Geometry/v3d_cameramatrix.h
+third_party/ssba/Geometry/v3d_distortion.h
+third_party/ssba/README.libmv
+third_party/ssba/Math/v3d_linear_utils.h
+third_party/ssba/Math/v3d_optimization.h
+third_party/ssba/Math/v3d_mathutilities.h
+third_party/ssba/Math/v3d_linear.h
+third_party/ssba/Math/v3d_optimization.cpp
+third_party/gflags/gflags_completions.h
+third_party/gflags/mutex.h
+third_party/gflags/gflags.cc
+third_party/gflags/gflags_reporting.cc
+third_party/gflags/README.libmv
+third_party/gflags/config.h
+third_party/gflags/gflags_completions.cc
+third_party/gflags/gflags.h
+third_party/fast/fast_9.c
+third_party/fast/fast_10.c
+third_party/fast/fast_11.c
+third_party/fast/fast.h
+third_party/fast/LICENSE
+third_party/fast/fast_12.c
+third_party/fast/fast.c
+third_party/fast/README
+third_party/fast/README.libmv
+third_party/fast/nonmax.c
+third_party/ldl/Include/ldl.h
+third_party/ldl/CMakeLists.txt
+third_party/ldl/README.libmv
+third_party/ldl/Doc/ChangeLog
+third_party/ldl/Doc/lesser.txt
+third_party/ldl/README.txt
+third_party/ldl/Source/ldl.c
+third_party/glog/ChangeLog
+third_party/glog/COPYING
+third_party/glog/src/utilities.cc
+third_party/glog/src/utilities.h
+third_party/glog/src/symbolize.cc
+third_party/glog/src/stacktrace_generic-inl.h
+third_party/glog/src/config_mac.h
+third_party/glog/src/vlog_is_on.cc
+third_party/glog/src/signalhandler.cc
+third_party/glog/src/stacktrace.h
+third_party/glog/src/stacktrace_x86_64-inl.h
+third_party/glog/src/symbolize.h
+third_party/glog/src/base/googleinit.h
+third_party/glog/src/base/mutex.h
+third_party/glog/src/base/commandlineflags.h
+third_party/glog/src/windows/preprocess.sh
+third_party/glog/src/windows/port.h
+third_party/glog/src/windows/config.h
+third_party/glog/src/windows/glog/raw_logging.h
+third_party/glog/src/windows/glog/vlog_is_on.h
+third_party/glog/src/windows/glog/logging.h
+third_party/glog/src/windows/glog/log_severity.h
+third_party/glog/src/windows/port.cc
+third_party/glog/src/logging.cc
+third_party/glog/src/stacktrace_powerpc-inl.h
+third_party/glog/src/stacktrace_x86-inl.h
+third_party/glog/src/demangle.cc
+third_party/glog/src/config.h
+third_party/glog/src/demangle.h
+third_party/glog/src/stacktrace_libunwind-inl.h
+third_party/glog/src/glog/raw_logging.h
+third_party/glog/src/glog/vlog_is_on.h
+third_party/glog/src/glog/logging.h
+third_party/glog/src/glog/log_severity.h
+third_party/glog/src/raw_logging.cc
+third_party/glog/src/config_linux.h
+third_party/glog/NEWS
+third_party/glog/README
+third_party/glog/README.libmv
+third_party/glog/AUTHORS
+third_party/msinttypes/stdint.h
+third_party/msinttypes/inttypes.h
+third_party/msinttypes/README.libmv
diff --git a/extern/libmv/libmv-capi.cpp b/extern/libmv/libmv-capi.cpp
new file mode 100644
index 00000000000..2e007bb47b2
--- /dev/null
+++ b/extern/libmv/libmv-capi.cpp
@@ -0,0 +1,770 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2011 Blender Foundation.
+ * All rights reserved.
+ *
+ * Contributor(s): Blender Foundation,
+ * Sergey Sharybin
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/* define this to generate PNG images with content of search areas
+ tracking between which failed */
+#undef DUMP_FAILURE
+
+#include "libmv-capi.h"
+
+#include "glog/logging.h"
+#include "Math/v3d_optimization.h"
+
+#include "libmv/tracking/klt_region_tracker.h"
+#include "libmv/tracking/trklt_region_tracker.h"
+#include "libmv/tracking/pyramid_region_tracker.h"
+
+#include "libmv/tracking/sad.h"
+
+#include "libmv/simple_pipeline/tracks.h"
+#include "libmv/simple_pipeline/initialize_reconstruction.h"
+#include "libmv/simple_pipeline/bundle.h"
+#include "libmv/simple_pipeline/detect.h"
+#include "libmv/simple_pipeline/pipeline.h"
+#include "libmv/simple_pipeline/camera_intrinsics.h"
+
+#include <stdlib.h>
+
+#ifdef DUMP_FAILURE
+# include <png.h>
+#endif
+
+#ifdef _MSC_VER
+# define snprintf _snprintf
+#endif
+
+#define DEFAULT_WINDOW_HALFSIZE 5
+
+typedef struct libmv_RegionTracker {
+ libmv::TrkltRegionTracker *trklt_region_tracker;
+ libmv::RegionTracker *region_tracker;
+} libmv_RegionTracker;
+
+typedef struct libmv_Reconstruction {
+ libmv::EuclideanReconstruction reconstruction;
+
+ /* used for per-track average error calculation after reconstruction */
+ libmv::Tracks tracks;
+ libmv::CameraIntrinsics intrinsics;
+
+ double error;
+} libmv_Reconstruction;
+
+typedef struct libmv_Features {
+ int count, margin;
+ libmv::Feature *features;
+} libmv_Features;
+
+/* ************ Logging ************ */
+
+void libmv_initLogging(const char *argv0)
+{
+ google::InitGoogleLogging(argv0);
+ google::SetCommandLineOption("logtostderr", "1");
+ google::SetCommandLineOption("v", "0");
+ google::SetCommandLineOption("stderrthreshold", "7");
+ google::SetCommandLineOption("minloglevel", "7");
+ V3D::optimizerVerbosenessLevel = 0;
+}
+
+void libmv_startDebugLogging(void)
+{
+ google::SetCommandLineOption("logtostderr", "1");
+ google::SetCommandLineOption("v", "0");
+ google::SetCommandLineOption("stderrthreshold", "1");
+ google::SetCommandLineOption("minloglevel", "0");
+ V3D::optimizerVerbosenessLevel = 1;
+}
+
+void libmv_setLoggingVerbosity(int verbosity)
+{
+ char val[10];
+ snprintf(val, sizeof(val), "%d", verbosity);
+
+ google::SetCommandLineOption("v", val);
+ V3D::optimizerVerbosenessLevel = verbosity;
+}
+
+/* ************ RegionTracker ************ */
+
+libmv_RegionTracker *libmv_regionTrackerNew(int max_iterations, int pyramid_level)
+{
+ libmv::TrkltRegionTracker *trklt_region_tracker = new libmv::TrkltRegionTracker;
+
+ trklt_region_tracker->half_window_size = DEFAULT_WINDOW_HALFSIZE;
+ trklt_region_tracker->max_iterations = max_iterations;
+ trklt_region_tracker->min_determinant = 1e-4;
+
+ libmv::PyramidRegionTracker *region_tracker =
+ new libmv::PyramidRegionTracker(trklt_region_tracker, pyramid_level);
+
+ libmv_RegionTracker *configured_region_tracker = new libmv_RegionTracker;
+ configured_region_tracker->trklt_region_tracker = trklt_region_tracker;
+ configured_region_tracker->region_tracker = region_tracker;
+
+ return configured_region_tracker;
+}
+
+static void floatBufToImage(const float *buf, int width, int height, libmv::FloatImage *image)
+{
+ int x, y, a = 0;
+
+ image->resize(height, width);
+
+ for (y = 0; y < height; y++) {
+ for (x = 0; x < width; x++) {
+ (*image)(y, x, 0) = buf[a++];
+ }
+ }
+}
+
+#ifdef DUMP_FAILURE
+void savePNGImage(png_bytep *row_pointers, int width, int height, int depth, int color_type, char *file_name)
+{
+ png_infop info_ptr;
+ png_structp png_ptr;
+ FILE *fp = fopen(file_name, "wb");
+
+ if (!fp)
+ return;
+
+ /* Initialize stuff */
+ png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
+ info_ptr = png_create_info_struct(png_ptr);
+
+ if (setjmp(png_jmpbuf(png_ptr))) {
+ fclose(fp);
+ return;
+ }
+
+ png_init_io(png_ptr, fp);
+
+ /* write header */
+ if (setjmp(png_jmpbuf(png_ptr))) {
+ fclose(fp);
+ return;
+ }
+
+ png_set_IHDR(png_ptr, info_ptr, width, height,
+ depth, color_type, PNG_INTERLACE_NONE,
+ PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE);
+
+ png_write_info(png_ptr, info_ptr);
+
+ /* write bytes */
+ if (setjmp(png_jmpbuf(png_ptr))) {
+ fclose(fp);
+ return;
+ }
+
+ png_write_image(png_ptr, row_pointers);
+
+ /* end write */
+ if (setjmp(png_jmpbuf(png_ptr))) {
+ fclose(fp);
+ return;
+ }
+
+ png_write_end(png_ptr, NULL);
+
+ fclose(fp);
+}
+
+static void saveImage(char *prefix, libmv::FloatImage image, int x0, int y0)
+{
+ int x, y;
+ png_bytep *row_pointers;
+
+ row_pointers= (png_bytep*)malloc(sizeof(png_bytep)*image.Height());
+
+ for (y = 0; y < image.Height(); y++) {
+ row_pointers[y]= (png_bytep)malloc(sizeof(png_byte)*4*image.Width());
+
+ for (x = 0; x < image.Width(); x++) {
+ if (x0 == x && y0 == y) {
+ row_pointers[y][x*4+0]= 255;
+ row_pointers[y][x*4+1]= 0;
+ row_pointers[y][x*4+2]= 0;
+ row_pointers[y][x*4+3]= 255;
+ }
+ else {
+ float pixel = image(y, x, 0);
+ row_pointers[y][x*4+0]= pixel*255;
+ row_pointers[y][x*4+1]= pixel*255;
+ row_pointers[y][x*4+2]= pixel*255;
+ row_pointers[y][x*4+3]= 255;
+ }
+ }
+ }
+
+ {
+ static int a= 0;
+ char buf[128];
+ snprintf(buf, sizeof(buf), "%s_%02d.png", prefix, ++a);
+ savePNGImage(row_pointers, image.Width(), image.Height(), 8, PNG_COLOR_TYPE_RGBA, buf);
+ }
+
+ for (y = 0; y < image.Height(); y++) {
+ free(row_pointers[y]);
+ }
+ free(row_pointers);
+}
+
+static void saveBytesImage(char *prefix, unsigned char *data, int width, int height)
+{
+ int x, y;
+ png_bytep *row_pointers;
+
+ row_pointers= (png_bytep*)malloc(sizeof(png_bytep)*height);
+
+ for (y = 0; y < height; y++) {
+ row_pointers[y]= (png_bytep)malloc(sizeof(png_byte)*4*width);
+
+ for (x = 0; x < width; x++) {
+ char pixel = data[width*y+x];
+ row_pointers[y][x*4+0]= pixel;
+ row_pointers[y][x*4+1]= pixel;
+ row_pointers[y][x*4+2]= pixel;
+ row_pointers[y][x*4+3]= 255;
+ }
+ }
+
+ {
+ static int a= 0;
+ char buf[128];
+ snprintf(buf, sizeof(buf), "%s_%02d.png", prefix, ++a);
+ savePNGImage(row_pointers, width, height, 8, PNG_COLOR_TYPE_RGBA, buf);
+ }
+
+ for (y = 0; y < height; y++) {
+ free(row_pointers[y]);
+ }
+ free(row_pointers);
+}
+#endif
+
+int libmv_regionTrackerTrack(libmv_RegionTracker *libmv_tracker, const float *ima1, const float *ima2,
+ int width, int height, int half_window_size,
+ double x1, double y1, double *x2, double *y2)
+{
+ libmv::RegionTracker *region_tracker;
+ libmv::TrkltRegionTracker *trklt_region_tracker;
+ libmv::FloatImage old_patch, new_patch;
+
+ trklt_region_tracker = libmv_tracker->trklt_region_tracker;
+ region_tracker = libmv_tracker->region_tracker;
+
+ trklt_region_tracker->half_window_size = half_window_size;
+
+ floatBufToImage(ima1, width, height, &old_patch);
+ floatBufToImage(ima2, width, height, &new_patch);
+
+#ifndef DUMP_FAILURE
+ return region_tracker->Track(old_patch, new_patch, x1, y1, x2, y2);
+#else
+ {
+ double sx2 = *x2, sy2 = *y2;
+ int result = region_tracker->Track(old_patch, new_patch, x1, y1, x2, y2);
+
+ if (!result) {
+ saveImage("old_patch", old_patch, x1, y1);
+ saveImage("new_patch", new_patch, sx2, sy2);
+ }
+
+ return result;
+ }
+#endif
+}
+
+void libmv_regionTrackerDestroy(libmv_RegionTracker *libmv_tracker)
+{
+ delete libmv_tracker->region_tracker;
+ delete libmv_tracker;
+}
+
+/* ************ Tracks ************ */
+
+void libmv_SADSamplePattern(unsigned char *image, int stride,
+ float warp[3][2], unsigned char *pattern)
+{
+ libmv::mat32 mat32;
+
+ memcpy(mat32.data, warp, sizeof(float)*3*2);
+
+ libmv::SamplePattern(image, stride, mat32, pattern, 16);
+}
+
+float libmv_SADTrackerTrack(unsigned char *pattern, unsigned char *warped, unsigned char *image, int stride,
+ int width, int height, float warp[3][2])
+{
+ float result;
+ libmv::mat32 mat32;
+
+ memcpy(mat32.data, warp, sizeof(float)*3*2);
+
+ result = libmv::Track(pattern, warped, 16, image, stride, width, height, &mat32, 16, 16);
+
+ memcpy(warp, mat32.data, sizeof(float)*3*2);
+
+ return result;
+}
+
+/* ************ Tracks ************ */
+
+libmv_Tracks *libmv_tracksNew(void)
+{
+ libmv::Tracks *libmv_tracks = new libmv::Tracks();
+
+ return (libmv_Tracks *)libmv_tracks;
+}
+
+void libmv_tracksInsert(struct libmv_Tracks *libmv_tracks, int image, int track, double x, double y)
+{
+ ((libmv::Tracks*)libmv_tracks)->Insert(image, track, x, y);
+}
+
+void libmv_tracksDestroy(libmv_Tracks *libmv_tracks)
+{
+ delete (libmv::Tracks*)libmv_tracks;
+}
+
+/* ************ Reconstruction solver ************ */
+
+libmv_Reconstruction *libmv_solveReconstruction(libmv_Tracks *tracks, int keyframe1, int keyframe2,
+ double focal_length, double principal_x, double principal_y, double k1, double k2, double k3)
+{
+ /* Invert the camera intrinsics. */
+ libmv::vector<libmv::Marker> markers = ((libmv::Tracks*)tracks)->AllMarkers();
+ libmv_Reconstruction *libmv_reconstruction = new libmv_Reconstruction();
+ libmv::EuclideanReconstruction *reconstruction = &libmv_reconstruction->reconstruction;
+ libmv::CameraIntrinsics *intrinsics = &libmv_reconstruction->intrinsics;
+
+ intrinsics->SetFocalLength(focal_length, focal_length);
+ intrinsics->SetPrincipalPoint(principal_x, principal_y);
+ intrinsics->SetRadialDistortion(k1, k2, k3);
+
+ if(focal_length) {
+ /* do a lens undistortion if focal length is non-zero only */
+ for (int i = 0; i < markers.size(); ++i) {
+ intrinsics->InvertIntrinsics(markers[i].x,
+ markers[i].y,
+ &(markers[i].x),
+ &(markers[i].y));
+ }
+ }
+
+ libmv::Tracks normalized_tracks(markers);
+
+ libmv::vector<libmv::Marker> keyframe_markers =
+ normalized_tracks.MarkersForTracksInBothImages(keyframe1, keyframe2);
+
+ libmv::EuclideanReconstructTwoFrames(keyframe_markers, reconstruction);
+ libmv::EuclideanBundle(normalized_tracks, reconstruction);
+ libmv::EuclideanCompleteReconstruction(normalized_tracks, reconstruction);
+
+ libmv_reconstruction->tracks = *(libmv::Tracks *)tracks;
+ libmv_reconstruction->error = libmv::EuclideanReprojectionError(*(libmv::Tracks *)tracks, *reconstruction, *intrinsics);
+
+ return (libmv_Reconstruction *)libmv_reconstruction;
+}
+
+int libmv_reporojectionPointForTrack(libmv_Reconstruction *libmv_reconstruction, int track, double pos[3])
+{
+ libmv::EuclideanReconstruction *reconstruction = &libmv_reconstruction->reconstruction;
+ libmv::EuclideanPoint *point = reconstruction->PointForTrack(track);
+
+ if(point) {
+ pos[0] = point->X[0];
+ pos[1] = point->X[2];
+ pos[2] = point->X[1];
+
+ return 1;
+ }
+
+ return 0;
+}
+
+static libmv::Marker ProjectMarker(const libmv::EuclideanPoint &point, const libmv::EuclideanCamera &camera,
+ const libmv::CameraIntrinsics &intrinsics) {
+ libmv::Vec3 projected = camera.R * point.X + camera.t;
+ projected /= projected(2);
+
+ libmv::Marker reprojected_marker;
+ intrinsics.ApplyIntrinsics(projected(0), projected(1), &reprojected_marker.x, &reprojected_marker.y);
+
+ reprojected_marker.image = camera.image;
+ reprojected_marker.track = point.track;
+
+ return reprojected_marker;
+}
+
+double libmv_reporojectionErrorForTrack(libmv_Reconstruction *libmv_reconstruction, int track)
+{
+ libmv::EuclideanReconstruction *reconstruction = &libmv_reconstruction->reconstruction;
+ libmv::CameraIntrinsics *intrinsics = &libmv_reconstruction->intrinsics;
+ libmv::vector<libmv::Marker> markers = libmv_reconstruction->tracks.MarkersForTrack(track);
+
+ int num_reprojected = 0;
+ double total_error = 0.0;
+
+ for (int i = 0; i < markers.size(); ++i) {
+ const libmv::EuclideanCamera *camera = reconstruction->CameraForImage(markers[i].image);
+ const libmv::EuclideanPoint *point = reconstruction->PointForTrack(markers[i].track);
+
+ if (!camera || !point) {
+ continue;
+ }
+
+ num_reprojected++;
+
+ libmv::Marker reprojected_marker = ProjectMarker(*point, *camera, *intrinsics);
+ double ex = reprojected_marker.x - markers[i].x;
+ double ey = reprojected_marker.y - markers[i].y;
+
+ total_error += sqrt(ex*ex + ey*ey);
+ }
+
+ return total_error / num_reprojected;
+}
+
+double libmv_reporojectionErrorForImage(libmv_Reconstruction *libmv_reconstruction, int image)
+{
+ libmv::EuclideanReconstruction *reconstruction = &libmv_reconstruction->reconstruction;
+ libmv::CameraIntrinsics *intrinsics = &libmv_reconstruction->intrinsics;
+ libmv::vector<libmv::Marker> markers = libmv_reconstruction->tracks.MarkersInImage(image);
+ const libmv::EuclideanCamera *camera = reconstruction->CameraForImage(image);
+ int num_reprojected = 0;
+ double total_error = 0.0;
+
+ if (!camera)
+ return 0;
+
+ for (int i = 0; i < markers.size(); ++i) {
+ const libmv::EuclideanPoint *point = reconstruction->PointForTrack(markers[i].track);
+
+ if (!point) {
+ continue;
+ }
+
+ num_reprojected++;
+
+ libmv::Marker reprojected_marker = ProjectMarker(*point, *camera, *intrinsics);
+ double ex = reprojected_marker.x - markers[i].x;
+ double ey = reprojected_marker.y - markers[i].y;
+
+ total_error += sqrt(ex*ex + ey*ey);
+ }
+
+ return total_error / num_reprojected;
+}
+
+int libmv_reporojectionCameraForImage(libmv_Reconstruction *libmv_reconstruction, int image, double mat[4][4])
+{
+ libmv::EuclideanReconstruction *reconstruction = &libmv_reconstruction->reconstruction;
+ libmv::EuclideanCamera *camera = reconstruction->CameraForImage(image);
+
+ if(camera) {
+ for (int j = 0; j < 3; ++j) {
+ for (int k = 0; k < 3; ++k) {
+ int l = k;
+
+ if (k == 1) l = 2;
+ else if (k == 2) l = 1;
+
+ if (j == 2) mat[j][l] = -camera->R(j,k);
+ else mat[j][l] = camera->R(j,k);
+ }
+ mat[j][3]= 0.0;
+ }
+
+ libmv::Vec3 optical_center = -camera->R.transpose() * camera->t;
+
+ mat[3][0] = optical_center(0);
+ mat[3][1] = optical_center(2);
+ mat[3][2] = optical_center(1);
+
+ mat[3][3]= 1.0;
+
+ return 1;
+ }
+
+ return 0;
+}
+
+double libmv_reprojectionError(libmv_Reconstruction *libmv_reconstruction)
+{
+ return libmv_reconstruction->error;
+}
+
+void libmv_destroyReconstruction(libmv_Reconstruction *libmv_reconstruction)
+{
+ delete libmv_reconstruction;
+}
+
+/* ************ feature detector ************ */
+
+struct libmv_Features *libmv_detectFeaturesFAST(unsigned char *data, int width, int height, int stride,
+ int margin, int min_trackness, int min_distance)
+{
+ libmv::Feature *features = NULL;
+ std::vector<libmv::Feature> v;
+ libmv_Features *libmv_features = new libmv_Features();
+ int i= 0, count;
+
+ if(margin) {
+ data += margin*stride+margin;
+ width -= 2*margin;
+ height -= 2*margin;
+ }
+
+ v = libmv::DetectFAST(data, width, height, stride, min_trackness, min_distance);
+
+ count = v.size();
+
+ if(count) {
+ features= new libmv::Feature[count];
+
+ for(std::vector<libmv::Feature>::iterator it = v.begin(); it != v.end(); it++) {
+ features[i++]= *it;
+ }
+ }
+
+ libmv_features->features = features;
+ libmv_features->count = count;
+ libmv_features->margin = margin;
+
+ return (libmv_Features *)libmv_features;
+}
+
+struct libmv_Features *libmv_detectFeaturesMORAVEC(unsigned char *data, int width, int height, int stride,
+ int margin, int count, int min_distance)
+{
+ libmv::Feature *features = NULL;
+ libmv_Features *libmv_features = new libmv_Features;
+
+ if(count) {
+ if(margin) {
+ data += margin*stride+margin;
+ width -= 2*margin;
+ height -= 2*margin;
+ }
+
+ features = new libmv::Feature[count];
+ libmv::DetectMORAVEC(data, stride, width, height, features, &count, min_distance, NULL);
+ }
+
+ libmv_features->count = count;
+ libmv_features->margin = margin;
+ libmv_features->features = features;
+
+ return libmv_features;
+}
+
+int libmv_countFeatures(struct libmv_Features *libmv_features)
+{
+ return libmv_features->count;
+}
+
+void libmv_getFeature(struct libmv_Features *libmv_features, int number, double *x, double *y, double *score, double *size)
+{
+ libmv::Feature feature= libmv_features->features[number];
+
+ *x = feature.x + libmv_features->margin;
+ *y = feature.y + libmv_features->margin;
+ *score = feature.score;
+ *size = feature.size;
+}
+
+void libmv_destroyFeatures(struct libmv_Features *libmv_features)
+{
+ if(libmv_features->features)
+ delete [] libmv_features->features;
+
+ delete libmv_features;
+}
+
+/* ************ camera intrinsics ************ */
+
+struct libmv_CameraIntrinsics *libmv_CameraIntrinsicsNew(double focal_length, double principal_x, double principal_y,
+ double k1, double k2, double k3, int width, int height)
+{
+ libmv::CameraIntrinsics *intrinsics= new libmv::CameraIntrinsics();
+
+ intrinsics->SetFocalLength(focal_length, focal_length);
+ intrinsics->SetPrincipalPoint(principal_x, principal_y);
+ intrinsics->SetRadialDistortion(k1, k2, k3);
+ intrinsics->SetImageSize(width, height);
+
+ return (struct libmv_CameraIntrinsics *) intrinsics;
+}
+
+struct libmv_CameraIntrinsics *libmv_CameraIntrinsicsCopy(struct libmv_CameraIntrinsics *libmvIntrinsics)
+{
+ libmv::CameraIntrinsics *orig_intrinsics = (libmv::CameraIntrinsics *) libmvIntrinsics;
+ libmv::CameraIntrinsics *new_intrinsics= new libmv::CameraIntrinsics(*orig_intrinsics);
+
+ return (struct libmv_CameraIntrinsics *) new_intrinsics;
+}
+
+void libmv_CameraIntrinsicsDestroy(struct libmv_CameraIntrinsics *libmvIntrinsics)
+{
+ libmv::CameraIntrinsics *intrinsics = (libmv::CameraIntrinsics *) libmvIntrinsics;
+
+ delete intrinsics;
+}
+
+void libmv_CameraIntrinsicsUpdate(struct libmv_CameraIntrinsics *libmvIntrinsics, double focal_length,
+ double principal_x, double principal_y, double k1, double k2, double k3, int width, int height)
+{
+ libmv::CameraIntrinsics *intrinsics = (libmv::CameraIntrinsics *) libmvIntrinsics;
+
+ if (intrinsics->focal_length() != focal_length)
+ intrinsics->SetFocalLength(focal_length, focal_length);
+
+ if (intrinsics->principal_point_x() != principal_x || intrinsics->principal_point_y() != principal_y)
+ intrinsics->SetFocalLength(focal_length, focal_length);
+
+ if (intrinsics->k1() != k1 || intrinsics->k2() != k2 || intrinsics->k3() != k3)
+ intrinsics->SetRadialDistortion(k1, k2, k3);
+
+ if (intrinsics->image_width() != width || intrinsics->image_height() != height)
+ intrinsics->SetImageSize(width, height);
+}
+
+void libmv_CameraIntrinsicsUndistortByte(struct libmv_CameraIntrinsics *libmvIntrinsics,
+ unsigned char *src, unsigned char *dst, int width, int height, float overscan, int channels)
+{
+ libmv::CameraIntrinsics *intrinsics = (libmv::CameraIntrinsics *) libmvIntrinsics;
+
+ intrinsics->Undistort(src, dst, width, height, overscan, channels);
+}
+
+void libmv_CameraIntrinsicsUndistortFloat(struct libmv_CameraIntrinsics *libmvIntrinsics,
+ float *src, float *dst, int width, int height, float overscan, int channels)
+{
+ libmv::CameraIntrinsics *intrinsics = (libmv::CameraIntrinsics *) libmvIntrinsics;
+
+ intrinsics->Undistort(src, dst, width, height, overscan, channels);
+}
+
+void libmv_CameraIntrinsicsDistortByte(struct libmv_CameraIntrinsics *libmvIntrinsics,
+ unsigned char *src, unsigned char *dst, int width, int height, float overscan, int channels)
+{
+ libmv::CameraIntrinsics *intrinsics = (libmv::CameraIntrinsics *) libmvIntrinsics;
+ intrinsics->Distort(src, dst, width, height, overscan, channels);
+}
+
+void libmv_CameraIntrinsicsDistortFloat(struct libmv_CameraIntrinsics *libmvIntrinsics,
+ float *src, float *dst, int width, int height, float overscan, int channels)
+{
+ libmv::CameraIntrinsics *intrinsics = (libmv::CameraIntrinsics *) libmvIntrinsics;
+
+ intrinsics->Distort(src, dst, width, height, overscan, channels);
+}
+
+/* ************ distortion ************ */
+
+void libmv_undistortByte(double focal_length, double principal_x, double principal_y, double k1, double k2, double k3,
+ unsigned char *src, unsigned char *dst, int width, int height, float overscan, int channels)
+{
+ libmv::CameraIntrinsics intrinsics;
+
+ intrinsics.SetFocalLength(focal_length, focal_length);
+ intrinsics.SetPrincipalPoint(principal_x, principal_y);
+ intrinsics.SetRadialDistortion(k1, k2, k3);
+
+ intrinsics.Undistort(src, dst, width, height, overscan, channels);
+}
+
+void libmv_undistortFloat(double focal_length, double principal_x, double principal_y, double k1, double k2, double k3,
+ float *src, float *dst, int width, int height, float overscan, int channels)
+{
+ libmv::CameraIntrinsics intrinsics;
+
+ intrinsics.SetFocalLength(focal_length, focal_length);
+ intrinsics.SetPrincipalPoint(principal_x, principal_y);
+ intrinsics.SetRadialDistortion(k1, k2, k3);
+
+ intrinsics.Undistort(src, dst, width, height, overscan, channels);
+}
+
+void libmv_distortByte(double focal_length, double principal_x, double principal_y, double k1, double k2, double k3,
+ unsigned char *src, unsigned char *dst, int width, int height, float overscan, int channels)
+{
+ libmv::CameraIntrinsics intrinsics;
+
+ intrinsics.SetFocalLength(focal_length, focal_length);
+ intrinsics.SetPrincipalPoint(principal_x, principal_y);
+ intrinsics.SetRadialDistortion(k1, k2, k3);
+
+ intrinsics.Distort(src, dst, width, height, overscan, channels);
+}
+
+void libmv_distortFloat(double focal_length, double principal_x, double principal_y, double k1, double k2, double k3,
+ float *src, float *dst, int width, int height, float overscan, int channels)
+{
+ libmv::CameraIntrinsics intrinsics;
+
+ intrinsics.SetFocalLength(focal_length, focal_length);
+ intrinsics.SetPrincipalPoint(principal_x, principal_y);
+ intrinsics.SetRadialDistortion(k1, k2, k3);
+
+ intrinsics.Distort(src, dst, width, height, overscan, channels);
+}
+
+/* ************ utils ************ */
+
+void libmv_applyCameraIntrinsics(double focal_length, double principal_x, double principal_y, double k1, double k2, double k3,
+ double x, double y, double *x1, double *y1)
+{
+ libmv::CameraIntrinsics intrinsics;
+
+ intrinsics.SetFocalLength(focal_length, focal_length);
+ intrinsics.SetPrincipalPoint(principal_x, principal_y);
+ intrinsics.SetRadialDistortion(k1, k2, k3);
+
+ if(focal_length) {
+ /* do a lens undistortion if focal length is non-zero only */
+
+ intrinsics.ApplyIntrinsics(x, y, x1, y1);
+ }
+}
+
+void libmv_InvertIntrinsics(double focal_length, double principal_x, double principal_y, double k1, double k2, double k3,
+ double x, double y, double *x1, double *y1)
+{
+ libmv::CameraIntrinsics intrinsics;
+
+ intrinsics.SetFocalLength(focal_length, focal_length);
+ intrinsics.SetPrincipalPoint(principal_x, principal_y);
+ intrinsics.SetRadialDistortion(k1, k2, k3);
+
+ if(focal_length) {
+ /* do a lens distortion if focal length is non-zero only */
+
+ intrinsics.InvertIntrinsics(x, y, x1, y1);
+ }
+}
diff --git a/extern/libmv/libmv-capi.h b/extern/libmv/libmv-capi.h
new file mode 100644
index 00000000000..b71a66b73a6
--- /dev/null
+++ b/extern/libmv/libmv-capi.h
@@ -0,0 +1,128 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2011 Blender Foundation.
+ * All rights reserved.
+ *
+ * Contributor(s): Blender Foundation,
+ * Sergey Sharybin
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#ifndef LIBMV_C_API_H
+#define LIBMV_C_API_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct libmv_RegionTracker;
+struct libmv_Tracks;
+struct libmv_Reconstruction;
+struct libmv_Features;
+struct libmv_CameraIntrinsics;
+
+/* Logging */
+void libmv_initLogging(const char *argv0);
+void libmv_startDebugLogging(void);
+void libmv_setLoggingVerbosity(int verbosity);
+
+/* RegionTracker */
+struct libmv_RegionTracker *libmv_regionTrackerNew(int max_iterations, int pyramid_level);
+int libmv_regionTrackerTrack(struct libmv_RegionTracker *libmv_tracker, const float *ima1, const float *ima2,
+ int width, int height, int half_window_size,
+ double x1, double y1, double *x2, double *y2);
+void libmv_regionTrackerDestroy(struct libmv_RegionTracker *libmv_tracker);
+
+/* SAD Tracker */
+void libmv_SADSamplePattern(unsigned char *image, int stride,
+ float warp[3][2], unsigned char *pattern);
+float libmv_SADTrackerTrack(unsigned char *pattern, unsigned char *warped, unsigned char *image,
+ int stride, int width, int height, float warp[3][2]);
+
+/* Tracks */
+struct libmv_Tracks *libmv_tracksNew(void);
+void libmv_tracksInsert(struct libmv_Tracks *libmv_tracks, int image, int track, double x, double y);
+void libmv_tracksDestroy(struct libmv_Tracks *libmv_tracks);
+
+/* Reconstruction solver */
+struct libmv_Reconstruction *libmv_solveReconstruction(struct libmv_Tracks *tracks, int keyframe1, int keyframe2,
+ double focal_length, double principal_x, double principal_y, double k1, double k2, double k3);
+int libmv_reporojectionPointForTrack(struct libmv_Reconstruction *libmv_reconstruction, int track, double pos[3]);
+double libmv_reporojectionErrorForTrack(struct libmv_Reconstruction *libmv_reconstruction, int track);
+double libmv_reporojectionErrorForImage(struct libmv_Reconstruction *libmv_reconstruction, int image);
+int libmv_reporojectionCameraForImage(struct libmv_Reconstruction *libmv_reconstruction, int image, double mat[4][4]);
+double libmv_reprojectionError(struct libmv_Reconstruction *libmv_reconstruction);
+void libmv_destroyReconstruction(struct libmv_Reconstruction *libmv_reconstruction);
+
+/* feature detector */
+struct libmv_Features *libmv_detectFeaturesFAST(unsigned char *data, int width, int height, int stride,
+ int margin, int min_trackness, int min_distance);
+struct libmv_Features *libmv_detectFeaturesMORAVEC(unsigned char *data, int width, int height, int stride,
+ int margin, int count, int min_distance);
+int libmv_countFeatures(struct libmv_Features *libmv_features);
+void libmv_getFeature(struct libmv_Features *libmv_features, int number, double *x, double *y, double *score, double *size);
+void libmv_destroyFeatures(struct libmv_Features *libmv_features);
+
+/* camera intrinsics */
+struct libmv_CameraIntrinsics *libmv_CameraIntrinsicsNew(double focal_length, double principal_x, double principal_y,
+ double k1, double k2, double k3, int width, int height);
+
+struct libmv_CameraIntrinsics *libmv_CameraIntrinsicsCopy(struct libmv_CameraIntrinsics *libmvIntrinsics);
+
+struct libmv_CameraIntrinsics *libmv_CameraIntrinsicsCopy(struct libmv_CameraIntrinsics *libmvIntrinsics);
+
+void libmv_CameraIntrinsicsDestroy(struct libmv_CameraIntrinsics *libmvIntrinsics);
+
+void libmv_CameraIntrinsicsUpdate(struct libmv_CameraIntrinsics *libmvIntrinsics, double focal_length,
+ double principal_x, double principal_y, double k1, double k2, double k3, int width, int height);
+
+void libmv_CameraIntrinsicsUndistortByte(struct libmv_CameraIntrinsics *libmvIntrinsics,
+ unsigned char *src, unsigned char *dst, int width, int height, float overscan, int channels);
+
+void libmv_CameraIntrinsicsUndistortFloat(struct libmv_CameraIntrinsics *libmvIntrinsics,
+ float *src, float *dst, int width, int height, float overscan, int channels);
+
+void libmv_CameraIntrinsicsDistortByte(struct libmv_CameraIntrinsics *libmvIntrinsics,
+ unsigned char *src, unsigned char *dst, int width, int height, float overscan, int channels);
+
+void libmv_CameraIntrinsicsDistortFloat(struct libmv_CameraIntrinsics *libmvIntrinsics,
+ float *src, float *dst, int width, int height, float overscan, int channels);
+
+/* dsitortion */
+void libmv_undistortByte(double focal_length, double principal_x, double principal_y, double k1, double k2, double k3,
+ unsigned char *src, unsigned char *dst, int width, int height, int channels);
+void libmv_undistortFloat(double focal_length, double principal_x, double principal_y, double k1, double k2, double k3,
+ float *src, float *dst, int width, int height, int channels);
+
+void libmv_distortByte(double focal_length, double principal_x, double principal_y, double k1, double k2, double k3,
+ unsigned char *src, unsigned char *dst, int width, int height, int channels);
+void libmv_distortFloat(double focal_length, double principal_x, double principal_y, double k1, double k2, double k3,
+ float *src, float *dst, int width, int height, int channels);
+
+/* utils */
+void libmv_applyCameraIntrinsics(double focal_length, double principal_x, double principal_y, double k1, double k2, double k3,
+ double x, double y, double *x1, double *y1);
+void libmv_InvertIntrinsics(double focal_length, double principal_x, double principal_y, double k1, double k2, double k3,
+ double x, double y, double *x1, double *y1);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // LIBMV_C_API_H
diff --git a/extern/libmv/libmv/base/id_generator.h b/extern/libmv/libmv/base/id_generator.h
new file mode 100644
index 00000000000..bf1eafd218e
--- /dev/null
+++ b/extern/libmv/libmv/base/id_generator.h
@@ -0,0 +1,37 @@
+// Copyright (c) 2007, 2008 libmv authors.
+//
+// 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 LIBMV_ID_GENERATOR_H
+#define LIBMV_ID_GENERATOR_H
+
+namespace libmv {
+
+template <typename ID>
+class IdGenerator {
+ public:
+ IdGenerator() : next_(0) {}
+ ID Generate() { return next_++; }
+ private:
+ ID next_;
+};
+
+} // namespace libmv
+
+#endif // LIBMV_ID_GENERATOR_H
diff --git a/extern/libmv/libmv/base/scoped_ptr.h b/extern/libmv/libmv/base/scoped_ptr.h
new file mode 100644
index 00000000000..f1e89eb5625
--- /dev/null
+++ b/extern/libmv/libmv/base/scoped_ptr.h
@@ -0,0 +1,60 @@
+// Copyright (c) 2009 libmv authors.
+//
+// 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 LIBMV_BASE_SCOPED_PTR_H
+#define LIBMV_BASE_SCOPED_PTR_H
+
+namespace libmv {
+
+/**
+ * A handle for a heap-allocated resource that should be freed when it goes out
+ * of scope. This looks similar to the one found in TR1.
+ */
+template<typename T>
+class scoped_ptr {
+ public:
+ scoped_ptr(T *resource) : resource_(resource) {}
+ ~scoped_ptr() { reset(0); }
+
+ T *get() const { return resource_; }
+ T *operator->() const { return resource_; }
+ T &operator*() const { return *resource_; }
+
+ void reset(T *new_resource) {
+ if (sizeof(T)) {
+ delete resource_;
+ }
+ resource_ = new_resource;
+ }
+
+ T *release() {
+ T *released_resource = resource_;
+ resource_ = 0;
+ return released_resource;
+ }
+
+ private:
+ // No copying allowed.
+ T *resource_;
+};
+
+} // namespace libmv
+
+#endif // LIBMV_BASE_SCOPED_PTR_H
diff --git a/extern/libmv/libmv/base/vector.h b/extern/libmv/libmv/base/vector.h
new file mode 100644
index 00000000000..9dc48676629
--- /dev/null
+++ b/extern/libmv/libmv/base/vector.h
@@ -0,0 +1,172 @@
+// Copyright (c) 2007, 2008 libmv authors.
+//
+// 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.
+//
+// Get an aligned vector implementation. Must be included before <vector>. The
+// Eigen guys went through some trouble to make a portable override for the
+// fixed size vector types.
+
+#ifndef LIBMV_BASE_VECTOR_H
+#define LIBMV_BASE_VECTOR_H
+
+#include <cstring>
+#include <new>
+
+#include <Eigen/Core>
+
+namespace libmv {
+
+// A simple container class, which guarantees 16 byte alignment needed for most
+// vectorization. Don't use this container for classes that cannot be copied
+// via memcpy.
+// FIXME: this class has some issues:
+// - doesn't support iterators.
+// - impede compatibility with code using STL.
+// - the STL already provide support for custom allocators
+// it could be replaced with a simple
+// template <T> class vector : std::vector<T, aligned_allocator> {} declaration
+// provided it doesn't break code relying on libmv::vector specific behavior
+template <typename T,
+ typename Allocator = Eigen::aligned_allocator<T> >
+class vector {
+ public:
+ ~vector() { clear(); }
+
+ vector() { init(); }
+ vector(int size) { init(); resize(size); }
+ vector(int size, const T & val) {
+ init();
+ resize(size);
+ std::fill(data_, data_+size_, val); }
+
+ // Copy constructor and assignment.
+ vector(const vector<T, Allocator> &rhs) {
+ init();
+ copy(rhs);
+ }
+ vector<T, Allocator> &operator=(const vector<T, Allocator> &rhs) {
+ if (&rhs != this) {
+ copy(rhs);
+ }
+ return *this;
+ }
+
+ /// Swaps the contents of two vectors in constant time.
+ void swap(vector<T, Allocator> &other) {
+ std::swap(allocator_, other.allocator_);
+ std::swap(size_, other.size_);
+ std::swap(capacity_, other.capacity_);
+ std::swap(data_, other.data_);
+ }
+
+ T *data() const { return data_; }
+ int size() const { return size_; }
+ int capacity() const { return capacity_; }
+ const T& back() const { return data_[size_ - 1]; }
+ T& back() { return data_[size_ - 1]; }
+ const T& front() const { return data_[0]; }
+ T& front() { return data_[0]; }
+ const T& operator[](int n) const { return data_[n]; }
+ T& operator[](int n) { return data_[n]; }
+ const T * begin() const { return data_; }
+ const T * end() const { return data_+size_; }
+ T * begin() { return data_; }
+ T * end() { return data_+size_; }
+
+ void resize(size_t size) {
+ reserve(size);
+ if (size > size_) {
+ construct(size_, size);
+ } else if (size < size_) {
+ destruct(size, size_);
+ }
+ size_ = size;
+ }
+
+
+
+ void push_back(const T &value) {
+ if (size_ == capacity_) {
+ reserve(size_ ? 2 * size_ : 1);
+ }
+ new (&data_[size_++]) T(value);
+ }
+
+ void pop_back() {
+ resize(size_ - 1);
+ }
+
+ void clear() {
+ destruct(0, size_);
+ deallocate();
+ init();
+ }
+
+ void reserve(unsigned int size) {
+ if (size > size_) {
+ T *data = static_cast<T *>(allocate(size));
+ memcpy(data, data_, sizeof(*data)*size_);
+ allocator_.deallocate(data_, capacity_);
+ data_ = data;
+ capacity_ = size;
+ }
+ }
+
+ private:
+ void construct(int start, int end) {
+ for (int i = start; i < end; ++i) {
+ new (&data_[i]) T;
+ }
+ }
+ void destruct(int start, int end) {
+ for (int i = start; i < end; ++i) {
+ data_[i].~T();
+ }
+ }
+ void init() {
+ size_ = 0;
+ data_ = 0;
+ capacity_ = 0;
+ }
+
+ void *allocate(int size) {
+ return size ? allocator_.allocate(size) : 0;
+ }
+
+ void deallocate() {
+ allocator_.deallocate(data_, size_);
+ data_ = 0;
+ }
+
+ void copy(const vector<T, Allocator> &rhs) {
+ resize(rhs.size());
+ for (int i = 0; i < rhs.size(); ++i) {
+ (*this)[i] = rhs[i];
+ }
+ }
+
+ Allocator allocator_;
+ size_t size_;
+ size_t capacity_;
+ T *data_;
+};
+
+} // namespace libmv
+
+#endif // LIBMV_BASE_VECTOR_H
diff --git a/extern/libmv/libmv/base/vector_utils.h b/extern/libmv/libmv/base/vector_utils.h
new file mode 100644
index 00000000000..7a0c3ba24f5
--- /dev/null
+++ b/extern/libmv/libmv/base/vector_utils.h
@@ -0,0 +1,34 @@
+// Copyright (c) 2009 libmv authors.
+//
+// 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 LIBMV_BASE_VECTOR_UTILS_H_
+#define LIBMV_BASE_VECTOR_UTILS_H_
+
+/// Delete the contents of a container.
+template <class Array>
+void DeleteElements(Array *array) {
+ for (int i = 0; i < array->size(); ++i) {
+ delete (*array)[i];
+ }
+ array->clear();
+}
+
+#endif // LIBMV_BASE_VECTOR_UTILS_H_
diff --git a/extern/libmv/libmv/image/array_nd.cc b/extern/libmv/libmv/image/array_nd.cc
new file mode 100644
index 00000000000..3a77e3e4881
--- /dev/null
+++ b/extern/libmv/libmv/image/array_nd.cc
@@ -0,0 +1,108 @@
+// Copyright (c) 2007, 2008 libmv authors.
+//
+// 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 "libmv/image/image.h"
+#include <iostream>
+#include <cmath>
+
+namespace libmv {
+
+void FloatArrayToScaledByteArray(const Array3Df &float_array,
+ Array3Du *byte_array,
+ bool automatic_range_detection
+ ) {
+ byte_array->ResizeLike(float_array);
+ float minval = HUGE_VAL;
+ float maxval = -HUGE_VAL;
+ if (automatic_range_detection) {
+ for (int i = 0; i < float_array.Height(); ++i) {
+ for (int j = 0; j < float_array.Width(); ++j) {
+ for (int k = 0; k < float_array.Depth(); ++k) {
+ minval = std::min(minval, float_array(i,j,k));
+ maxval = std::max(maxval, float_array(i,j,k));
+ }
+ }
+ }
+ } else {
+ minval = 0;
+ maxval = 1;
+ }
+ for (int i = 0; i < float_array.Height(); ++i) {
+ for (int j = 0; j < float_array.Width(); ++j) {
+ for (int k = 0; k < float_array.Depth(); ++k) {
+ float unscaled = (float_array(i,j,k) - minval) / (maxval - minval);
+ (*byte_array)(i,j,k) = (unsigned char)(255 * unscaled);
+ }
+ }
+ }
+}
+
+void ByteArrayToScaledFloatArray(const Array3Du &byte_array,
+ Array3Df *float_array) {
+ float_array->ResizeLike(byte_array);
+ for (int i = 0; i < byte_array.Height(); ++i) {
+ for (int j = 0; j < byte_array.Width(); ++j) {
+ for (int k = 0; k < byte_array.Depth(); ++k) {
+ (*float_array)(i,j,k) = float(byte_array(i,j,k)) / 255.0f;
+ }
+ }
+ }
+}
+
+void SplitChannels(const Array3Df &input,
+ Array3Df *channel0,
+ Array3Df *channel1,
+ Array3Df *channel2) {
+ assert(input.Depth() >= 3);
+ channel0->Resize(input.Height(), input.Width());
+ channel1->Resize(input.Height(), input.Width());
+ channel2->Resize(input.Height(), input.Width());
+ for (int row = 0; row < input.Height(); ++row) {
+ for (int column = 0; column < input.Width(); ++column) {
+ (*channel0)(row, column) = input(row, column, 0);
+ (*channel1)(row, column) = input(row, column, 1);
+ (*channel2)(row, column) = input(row, column, 2);
+ }
+ }
+}
+
+void PrintArray(const Array3Df &array) {
+ using namespace std;
+
+ printf("[\n");
+ for (int r = 0; r < array.Height(); ++r) {
+ printf("[");
+ for (int c = 0; c < array.Width(); ++c) {
+ if (array.Depth() == 1) {
+ printf("%11f, ", array(r, c));
+ } else {
+ printf("[");
+ for (int k = 0; k < array.Depth(); ++k) {
+ printf("%11f, ", array(r, c, k));
+ }
+ printf("],");
+ }
+ }
+ printf("],\n");
+ }
+ printf("]\n");
+}
+
+} // namespace libmv
diff --git a/extern/libmv/libmv/image/array_nd.h b/extern/libmv/libmv/image/array_nd.h
new file mode 100644
index 00000000000..6d7570cda9b
--- /dev/null
+++ b/extern/libmv/libmv/image/array_nd.h
@@ -0,0 +1,473 @@
+// Copyright (c) 2007, 2008 libmv authors.
+//
+// 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 LIBMV_IMAGE_ARRAY_ND_H
+#define LIBMV_IMAGE_ARRAY_ND_H
+
+#include <cassert>
+#include <cstdio>
+#include <cstring>
+
+#include "libmv/image/tuple.h"
+
+namespace libmv {
+
+class BaseArray {};
+
+/// A multidimensional array class.
+template <typename T, int N>
+class ArrayND : public BaseArray {
+ public:
+ typedef T Scalar;
+
+ /// Type for the multidimensional indices.
+ typedef Tuple<int, N> Index;
+
+ /// Create an empty array.
+ ArrayND() : data_(NULL), own_data(true) { Resize(Index(0)); }
+
+ /// Create an array with the specified shape.
+ ArrayND(const Index &shape) : data_(NULL), own_data(true) { Resize(shape); }
+
+ /// Create an array with the specified shape.
+ ArrayND(int *shape) : data_(NULL), own_data(true) { Resize(shape); }
+
+ /// Copy constructor.
+ ArrayND(const ArrayND<T, N> &b) : data_(NULL), own_data(true) {
+ ResizeLike(b);
+ std::memcpy(Data(), b.Data(), sizeof(T) * Size());
+ }
+
+ ArrayND(int s0) : data_(NULL), own_data(true) { Resize(s0); }
+ ArrayND(int s0, int s1) : data_(NULL), own_data(true) { Resize(s0, s1); }
+ ArrayND(int s0, int s1, int s2) : data_(NULL), own_data(true) { Resize(s0, s1, s2); }
+
+ ArrayND(T* data, int s0, int s1, int s2) : data_(data), own_data(false) { Resize(s0, s1, s2); }
+
+ /// Destructor deletes pixel data.
+ ~ArrayND() {
+ delete [] data_;
+ }
+
+ /// Assignation copies pixel data.
+ ArrayND &operator=(const ArrayND<T, N> &b) {
+ assert(this != &b);
+ ResizeLike(b);
+ std::memcpy(Data(), b.Data(), sizeof(T) * Size());
+ return *this;
+ }
+
+ const Index &Shapes() const {
+ return shape_;
+ }
+
+ const Index &Strides() const {
+ return strides_;
+ }
+
+ /// Create an array of shape s.
+ void Resize(const Index &new_shape) {
+ if (data_ != NULL && shape_ == new_shape) {
+ // Don't bother realloacting if the shapes match.
+ return;
+ }
+ shape_.Reset(new_shape);
+ strides_(N - 1) = 1;
+ for (int i = N - 1; i > 0; --i) {
+ strides_(i - 1) = strides_(i) * shape_(i);
+ }
+ if(own_data) {
+ delete [] data_;
+ data_ = NULL;
+ if (Size() > 0) {
+ data_ = new T[Size()];
+ }
+ }
+ }
+
+ template<typename D>
+ void ResizeLike(const ArrayND<D,N> &other) {
+ Resize(other.Shape());
+ }
+
+ /// Resizes the array to shape s. All data is lost.
+ void Resize(const int *new_shape_array) {
+ Resize(Index(new_shape_array));
+ }
+
+ /// Resize a 1D array to length s0.
+ void Resize(int s0) {
+ assert(N == 1);
+ int shape[] = {s0};
+ Resize(shape);
+ }
+
+ /// Resize a 2D array to shape (s0,s1).
+ void Resize(int s0, int s1) {
+ int shape[N] = {s0, s1};
+ for (int i = 2; i < N; ++i) {
+ shape[i] = 1;
+ }
+ Resize(shape);
+ }
+
+ // Match Eigen2's API.
+ void resize(int rows, int cols) {
+ Resize(rows, cols);
+ }
+
+ /// Resize a 3D array to shape (s0,s1,s2).
+ void Resize(int s0, int s1, int s2) {
+ assert(N == 3);
+ int shape[] = {s0,s1,s2};
+ Resize(shape);
+ }
+
+ template<typename D>
+ void CopyFrom(const ArrayND<D,N> &other) {
+ ResizeLike(other);
+ T *data = Data();
+ const D *other_data = other.Data();
+ for (int i = 0; i < Size(); ++i) {
+ data[i] = T(other_data[i]);
+ }
+ }
+
+ void Fill(T value) {
+ for (int i = 0; i < Size(); ++i) {
+ Data()[i] = value;
+ }
+ }
+
+ // Match Eigen's API.
+ void fill(T value) {
+ for (int i = 0; i < Size(); ++i) {
+ Data()[i] = value;
+ }
+ }
+
+ /// Return a tuple containing the length of each axis.
+ const Index &Shape() const {
+ return shape_;
+ }
+
+ /// Return the length of an axis.
+ int Shape(int axis) const {
+ return shape_(axis);
+ }
+
+ /// Return the distance between neighboring elements along axis.
+ int Stride(int axis) const {
+ return strides_(axis);
+ }
+
+ /// Return the number of elements of the array.
+ int Size() const {
+ int size = 1;
+ for (int i = 0; i < N; ++i)
+ size *= Shape(i);
+ return size;
+ }
+
+ /// Return the total amount of memory used by the array.
+ int MemorySizeInBytes() const {
+ return sizeof(*this) + Size() * sizeof(T);
+ }
+
+ /// Pointer to the first element of the array.
+ T *Data() { return data_; }
+
+ /// Constant pointer to the first element of the array.
+ const T *Data() const { return data_; }
+
+ /// Distance between the first element and the element at position index.
+ int Offset(const Index &index) const {
+ int offset = 0;
+ for (int i = 0; i < N; ++i)
+ offset += index(i) * Stride(i);
+ return offset;
+ }
+
+ /// 1D specialization.
+ int Offset(int i0) const {
+ assert(N == 1);
+ return i0 * Stride(0);
+ }
+
+ /// 2D specialization.
+ int Offset(int i0, int i1) const {
+ assert(N == 2);
+ return i0 * Stride(0) + i1 * Stride(1);
+ }
+
+ /// 3D specialization.
+ int Offset(int i0, int i1, int i2) const {
+ assert(N == 3);
+ return i0 * Stride(0) + i1 * Stride(1) + i2 * Stride(2);
+ }
+
+ /// Return a reference to the element at position index.
+ T &operator()(const Index &index) {
+ // TODO(pau) Boundary checking in debug mode.
+ return *( Data() + Offset(index) );
+ }
+
+ /// 1D specialization.
+ T &operator()(int i0) {
+ return *( Data() + Offset(i0) );
+ }
+
+ /// 2D specialization.
+ T &operator()(int i0, int i1) {
+ assert(0 <= i0 && i0 < Shape(0));
+ assert(0 <= i1 && i1 < Shape(1));
+ return *( Data() + Offset(i0,i1) );
+ }
+
+ /// 3D specialization.
+ T &operator()(int i0, int i1, int i2) {
+ assert(0 <= i0 && i0 < Shape(0));
+ assert(0 <= i1 && i1 < Shape(1));
+ assert(0 <= i2 && i2 < Shape(2));
+ return *( Data() + Offset(i0,i1,i2) );
+ }
+
+ /// Return a constant reference to the element at position index.
+ const T &operator()(const Index &index) const {
+ return *( Data() + Offset(index) );
+ }
+
+ /// 1D specialization.
+ const T &operator()(int i0) const {
+ return *( Data() + Offset(i0) );
+ }
+
+ /// 2D specialization.
+ const T &operator()(int i0, int i1) const {
+ assert(0 <= i0 && i0 < Shape(0));
+ assert(0 <= i1 && i1 < Shape(1));
+ return *( Data() + Offset(i0,i1) );
+ }
+
+ /// 3D specialization.
+ const T &operator()(int i0, int i1, int i2) const {
+ return *( Data() + Offset(i0,i1,i2) );
+ }
+
+ /// True if index is inside array.
+ bool Contains(const Index &index) const {
+ for (int i = 0; i < N; ++i)
+ if (index(i) < 0 || index(i) >= Shape(i))
+ return false;
+ return true;
+ }
+
+ /// 1D specialization.
+ bool Contains(int i0) const {
+ return 0 <= i0 && i0 < Shape(0);
+ }
+
+ /// 2D specialization.
+ bool Contains(int i0, int i1) const {
+ return 0 <= i0 && i0 < Shape(0)
+ && 0 <= i1 && i1 < Shape(1);
+ }
+
+ /// 3D specialization.
+ bool Contains(int i0, int i1, int i2) const {
+ return 0 <= i0 && i0 < Shape(0)
+ && 0 <= i1 && i1 < Shape(1)
+ && 0 <= i2 && i2 < Shape(2);
+ }
+
+ bool operator==(const ArrayND<T, N> &other) const {
+ if (shape_ != other.shape_) return false;
+ if (strides_ != other.strides_) return false;
+ for (int i = 0; i < Size(); ++i) {
+ if (this->Data()[i] != other.Data()[i])
+ return false;
+ }
+ return true;
+ }
+
+ bool operator!=(const ArrayND<T, N> &other) const {
+ return !(*this == other);
+ }
+
+ ArrayND<T, N> operator*(const ArrayND<T, N> &other) const {
+ assert(Shape() = other.Shape());
+ ArrayND<T, N> res;
+ res.ResizeLike(*this);
+ for (int i = 0; i < res.Size(); ++i) {
+ res.Data()[i] = Data()[i] * other.Data()[i];
+ }
+ return res;
+ }
+
+ protected:
+ /// The number of element in each dimension.
+ Index shape_;
+
+ /// How to jump to neighbors in each dimension.
+ Index strides_;
+
+ /// Pointer to the first element of the array.
+ T *data_;
+
+ /// Flag if this Array either own or reference the data
+ bool own_data;
+};
+
+/// 3D array (row, column, channel).
+template <typename T>
+class Array3D : public ArrayND<T, 3> {
+ typedef ArrayND<T, 3> Base;
+ public:
+ Array3D()
+ : Base() {
+ }
+ Array3D(int height, int width, int depth=1)
+ : Base(height, width, depth) {
+ }
+ Array3D(T* data, int height, int width, int depth=1)
+ : Base(data, height, width, depth) {
+ }
+
+ void Resize(int height, int width, int depth=1) {
+ Base::Resize(height, width, depth);
+ }
+
+ int Height() const {
+ return Base::Shape(0);
+ }
+ int Width() const {
+ return Base::Shape(1);
+ }
+ int Depth() const {
+ return Base::Shape(2);
+ }
+
+ // Match Eigen2's API so that Array3D's and Mat*'s can work together via
+ // template magic.
+ int rows() const { return Height(); }
+ int cols() const { return Width(); }
+ int depth() const { return Depth(); }
+
+ int Get_Step() const { return Width()*Depth(); }
+
+ /// Enable accessing with 2 indices for grayscale images.
+ T &operator()(int i0, int i1, int i2 = 0) {
+ assert(0 <= i0 && i0 < Height());
+ assert(0 <= i1 && i1 < Width());
+ return Base::operator()(i0,i1,i2);
+ }
+ const T &operator()(int i0, int i1, int i2 = 0) const {
+ assert(0 <= i0 && i0 < Height());
+ assert(0 <= i1 && i1 < Width());
+ return Base::operator()(i0,i1,i2);
+ }
+};
+
+typedef Array3D<unsigned char> Array3Du;
+typedef Array3D<unsigned int> Array3Dui;
+typedef Array3D<int> Array3Di;
+typedef Array3D<float> Array3Df;
+typedef Array3D<short> Array3Ds;
+
+void SplitChannels(const Array3Df &input,
+ Array3Df *channel0,
+ Array3Df *channel1,
+ Array3Df *channel2);
+
+void PrintArray(const Array3Df &array);
+
+/** Convert a float array into a byte array by scaling values by 255* (max-min).
+ * where max and min are automatically detected
+ * (if automatic_range_detection = true)
+ * \note and TODO this automatic detection only works when the image contains
+ * at least one pixel of both bounds.
+ **/
+void FloatArrayToScaledByteArray(const Array3Df &float_array,
+ Array3Du *byte_array,
+ bool automatic_range_detection = false);
+
+//! Convert a byte array into a float array by dividing values by 255.
+void ByteArrayToScaledFloatArray(const Array3Du &byte_array,
+ Array3Df *float_array);
+
+template <typename AArrayType, typename BArrayType, typename CArrayType>
+void MultiplyElements( const AArrayType &a,
+ const BArrayType &b,
+ CArrayType *c ) {
+ // This function does an element-wise multiply between
+ // the two Arrays A and B, and stores the result in C.
+ // A and B must have the same dimensions.
+ assert( a.Shape() == b.Shape() );
+ c->ResizeLike(a);
+
+ // To perform the multiplcation, a "current" index into the N-dimensions of
+ // the A and B matrix specifies which elements are being multiplied.
+ typename CArrayType::Index index;
+
+ // The index starts at the maximum value for each dimension
+ const typename CArrayType::Index& cShape = c->Shape();
+ for ( int i = 0; i < CArrayType::Index::SIZE; ++i )
+ index(i) = cShape(i) - 1;
+
+ // After each multiplication, the highest-dimensional index is reduced.
+ // if this reduces it less than zero, it resets to its maximum value
+ // and decrements the index of the next lower dimension.
+ // This ripple-action continues until the entire new array has been
+ // calculated, indicated by dimension zero having a negative index.
+ while ( index(0) >= 0 ) {
+ (*c)(index) = a(index) * b(index);
+
+ int dimension = CArrayType::Index::SIZE - 1;
+ index(dimension) = index(dimension) - 1;
+ while ( dimension > 0 && index(dimension) < 0 ) {
+ index(dimension) = cShape(dimension) - 1;
+ index(dimension - 1) = index(dimension - 1) - 1;
+ --dimension;
+ }
+ }
+}
+
+template <typename TA, typename TB, typename TC>
+void MultiplyElements(const ArrayND<TA, 3> &a,
+ const ArrayND<TB, 3> &b,
+ ArrayND<TC, 3> *c) {
+ // Specialization for N==3
+ c->ResizeLike(a);
+ assert(a.Shape(0) == b.Shape(0));
+ assert(a.Shape(1) == b.Shape(1));
+ assert(a.Shape(2) == b.Shape(2));
+ for (int i = 0; i < a.Shape(0); ++i) {
+ for (int j = 0; j < a.Shape(1); ++j) {
+ for (int k = 0; k < a.Shape(2); ++k) {
+ (*c)(i, j, k) = TC(a(i, j, k) * b(i, j, k));
+ }
+ }
+ }
+}
+
+
+} // namespace libmv
+
+#endif // LIBMV_IMAGE_ARRAY_ND_H
diff --git a/extern/libmv/libmv/image/convolve.cc b/extern/libmv/libmv/image/convolve.cc
new file mode 100644
index 00000000000..be73a1a3263
--- /dev/null
+++ b/extern/libmv/libmv/image/convolve.cc
@@ -0,0 +1,305 @@
+// Copyright (c) 2007, 2008 libmv authors.
+//
+// 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 <cmath>
+
+#include "libmv/image/image.h"
+#include "libmv/image/convolve.h"
+
+namespace libmv {
+
+// Compute a Gaussian kernel and derivative, such that you can take the
+// derivative of an image by convolving with the kernel horizontally then the
+// derivative vertically to get (eg) the y derivative.
+void ComputeGaussianKernel(double sigma, Vec *kernel, Vec *derivative) {
+ assert(sigma >= 0.0);
+
+ // 0.004 implies a 3 pixel kernel with 1 pixel sigma.
+ const float truncation_factor = 0.004f;
+
+ // Calculate the kernel size based on sigma such that it is odd.
+ float precisehalfwidth = GaussianInversePositive(truncation_factor, sigma);
+ int width = lround(2*precisehalfwidth);
+ if (width % 2 == 0) {
+ width++;
+ }
+ // Calculate the gaussian kernel and its derivative.
+ kernel->resize(width);
+ derivative->resize(width);
+ kernel->setZero();
+ derivative->setZero();
+ int halfwidth = width / 2;
+ for (int i = -halfwidth; i <= halfwidth; ++i) {
+ (*kernel)(i + halfwidth) = Gaussian(i, sigma);
+ (*derivative)(i + halfwidth) = GaussianDerivative(i, sigma);
+ }
+ // Since images should not get brighter or darker, normalize.
+ NormalizeL1(kernel);
+
+ // Normalize the derivative differently. See
+ // www.cs.duke.edu/courses/spring03/cps296.1/handouts/Image%20Processing.pdf
+ double factor = 0.;
+ for (int i = -halfwidth; i <= halfwidth; ++i) {
+ factor -= i*(*derivative)(i+halfwidth);
+ }
+ *derivative /= factor;
+}
+
+template <int size, bool vertical>
+void FastConvolve(const Vec &kernel, int width, int height,
+ const float* src, int src_stride, int src_line_stride,
+ float* dst, int dst_stride) {
+ double coefficients[2 * size + 1];
+ for (int k = 0; k < 2 * size + 1; ++k) {
+ coefficients[k] = kernel(2 * size - k);
+ }
+ // Fast path: if the kernel has a certain size, use the constant sized loops.
+ for (int y = 0; y < height; ++y) {
+ for (int x = 0; x < width; ++x) {
+ double sum = 0;
+ for (int k = -size; k <= size; ++k) {
+ if (vertical) {
+ if (y + k >= 0 && y + k < height) {
+ sum += src[k * src_line_stride] * coefficients[k + size];
+ }
+ } else {
+ if (x + k >= 0 && x + k < width) {
+ sum += src[k * src_stride] * coefficients[k + size];
+ }
+ }
+ }
+ dst[0] = static_cast<float>(sum);
+ src += src_stride;
+ dst += dst_stride;
+ }
+ }
+}
+
+template<bool vertical>
+void Convolve(const Array3Df &in,
+ const Vec &kernel,
+ Array3Df *out_pointer,
+ int plane) {
+ int width = in.Width();
+ int height = in.Height();
+ Array3Df &out = *out_pointer;
+ if (plane == -1) {
+ out.ResizeLike(in);
+ plane = 0;
+ }
+
+ assert(kernel.size() % 2 == 1);
+ assert(&in != out_pointer);
+
+ int src_line_stride = in.Stride(0);
+ int src_stride = in.Stride(1);
+ int dst_stride = out.Stride(1);
+ const float* src = in.Data();
+ float* dst = out.Data() + plane;
+
+ // Use a dispatch table to make most convolutions used in practice use the
+ // fast path.
+ int half_width = kernel.size() / 2;
+ switch (half_width) {
+#define static_convolution( size ) case size: \
+ FastConvolve<size, vertical>(kernel, width, height, src, src_stride, \
+ src_line_stride, dst, dst_stride); break;
+ static_convolution(1)
+ static_convolution(2)
+ static_convolution(3)
+ static_convolution(4)
+ static_convolution(5)
+ static_convolution(6)
+ static_convolution(7)
+#undef static_convolution
+ default:
+ int dynamic_size = kernel.size() / 2;
+ for (int y = 0; y < height; ++y) {
+ for (int x = 0; x < width; ++x) {
+ double sum = 0;
+ // Slow path: this loop cannot be unrolled.
+ for (int k = -dynamic_size; k <= dynamic_size; ++k) {
+ if(vertical) {
+ if (y + k >= 0 && y + k < height) {
+ sum += src[k * src_line_stride] * kernel(2 * dynamic_size - (k + dynamic_size));
+ }
+ } else {
+ if (x + k >= 0 && x + k < width) {
+ sum += src[k * src_stride] * kernel(2 * dynamic_size - (k + dynamic_size));
+ }
+ }
+ }
+ dst[0] = static_cast<float>(sum);
+ src += src_stride;
+ dst += dst_stride;
+ }
+ }
+ }
+}
+
+void ConvolveHorizontal(const Array3Df &in,
+ const Vec &kernel,
+ Array3Df *out_pointer,
+ int plane) {
+ Convolve<false>(in, kernel, out_pointer, plane);
+}
+
+void ConvolveVertical(const Array3Df &in,
+ const Vec &kernel,
+ Array3Df *out_pointer,
+ int plane) {
+ Convolve<true>(in, kernel, out_pointer, plane);
+}
+
+void ConvolveGaussian(const Array3Df &in,
+ double sigma,
+ Array3Df *out_pointer) {
+ Vec kernel, derivative;
+ ComputeGaussianKernel(sigma, &kernel, &derivative);
+
+ Array3Df tmp;
+ ConvolveVertical(in, kernel, &tmp);
+ ConvolveHorizontal(tmp, kernel, out_pointer);
+}
+
+void BlurredImageAndDerivatives(const Array3Df &in,
+ double sigma,
+ Array3Df *blurred_image,
+ Array3Df *gradient_x,
+ Array3Df *gradient_y) {
+ Vec kernel, derivative;
+ ComputeGaussianKernel(sigma, &kernel, &derivative);
+ Array3Df tmp;
+
+ // Compute convolved image.
+ ConvolveVertical(in, kernel, &tmp);
+ ConvolveHorizontal(tmp, kernel, blurred_image);
+
+ // Compute first derivative in x (reusing vertical convolution above).
+ ConvolveHorizontal(tmp, derivative, gradient_x);
+
+ // Compute first derivative in y.
+ ConvolveHorizontal(in, kernel, &tmp);
+ ConvolveVertical(tmp, derivative, gradient_y);
+}
+
+// Compute the gaussian blur of an image and the derivatives of the blurred
+// image, and store the results in three channels. Since the blurred value and
+// gradients are closer in memory, this leads to better performance if all
+// three values are needed at the same time.
+void BlurredImageAndDerivativesChannels(const Array3Df &in,
+ double sigma,
+ Array3Df *blurred_and_gradxy) {
+ assert(in.Depth() == 1);
+
+ Vec kernel, derivative;
+ ComputeGaussianKernel(sigma, &kernel, &derivative);
+
+ // Compute convolved image.
+ Array3Df tmp;
+ ConvolveVertical(in, kernel, &tmp);
+ blurred_and_gradxy->Resize(in.Height(), in.Width(), 3);
+ ConvolveHorizontal(tmp, kernel, blurred_and_gradxy, 0);
+
+ // Compute first derivative in x.
+ ConvolveHorizontal(tmp, derivative, blurred_and_gradxy, 1);
+
+ // Compute first derivative in y.
+ ConvolveHorizontal(in, kernel, &tmp);
+ ConvolveVertical(tmp, derivative, blurred_and_gradxy, 2);
+}
+
+void BoxFilterHorizontal(const Array3Df &in,
+ int window_size,
+ Array3Df *out_pointer) {
+ Array3Df &out = *out_pointer;
+ out.ResizeLike(in);
+ int half_width = (window_size - 1) / 2;
+
+ for (int k = 0; k < in.Depth(); ++k) {
+ for (int i=0; i<in.Height(); ++i) {
+ float sum = 0;
+ // Init sum.
+ for (int j=0; j<half_width; ++j) {
+ sum += in(i, j, k);
+ }
+ // Fill left border.
+ for (int j=0; j < half_width + 1; ++j) {
+ sum += in(i, j + half_width, k);
+ out(i, j, k) = sum;
+ }
+ // Fill interior.
+ for (int j = half_width + 1; j<in.Width()-half_width; ++j) {
+ sum -= in(i, j - half_width - 1, k);
+ sum += in(i, j + half_width, k);
+ out(i, j, k) = sum;
+ }
+ // Fill right border.
+ for (int j = in.Width() - half_width; j<in.Width(); ++j) {
+ sum -= in(i, j - half_width - 1, k);
+ out(i, j, k) = sum;
+ }
+ }
+ }
+}
+
+void BoxFilterVertical(const Array3Df &in,
+ int window_size,
+ Array3Df *out_pointer) {
+ Array3Df &out = *out_pointer;
+ out.ResizeLike(in);
+ int half_width = (window_size - 1) / 2;
+
+ for (int k = 0; k < in.Depth(); ++k) {
+ for (int j = 0; j < in.Width(); ++j) {
+ float sum = 0;
+ // Init sum.
+ for (int i=0; i<half_width; ++i) {
+ sum += in(i, j, k);
+ }
+ // Fill left border.
+ for (int i=0; i < half_width + 1; ++i) {
+ sum += in(i + half_width, j, k);
+ out(i, j, k) = sum;
+ }
+ // Fill interior.
+ for (int i = half_width + 1; i<in.Height()-half_width; ++i) {
+ sum -= in(i - half_width - 1, j, k);
+ sum += in(i + half_width, j, k);
+ out(i, j, k) = sum;
+ }
+ // Fill right border.
+ for (int i = in.Height() - half_width; i<in.Height(); ++i) {
+ sum -= in(i - half_width - 1, j, k);
+ out(i, j, k) = sum;
+ }
+ }
+ }
+}
+
+void BoxFilter(const Array3Df &in,
+ int box_width,
+ Array3Df *out) {
+ Array3Df tmp;
+ BoxFilterHorizontal(in, box_width, &tmp);
+ BoxFilterVertical(tmp, box_width, out);
+}
+
+} // namespace libmv
diff --git a/extern/libmv/libmv/image/convolve.h b/extern/libmv/libmv/image/convolve.h
new file mode 100644
index 00000000000..c6c995fd674
--- /dev/null
+++ b/extern/libmv/libmv/image/convolve.h
@@ -0,0 +1,93 @@
+// Copyright (c) 2007, 2008, 2011 libmv authors.
+//
+// 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 LIBMV_IMAGE_CONVOLVE_H_
+#define LIBMV_IMAGE_CONVOLVE_H_
+
+#include "libmv/image/image.h"
+#include "libmv/numeric/numeric.h"
+
+namespace libmv {
+
+// TODO(keir): Find a better place for these functions. gaussian.h in numeric?
+
+// Zero mean Gaussian.
+inline double Gaussian(double x, double sigma) {
+ return 1/sqrt(2*M_PI*sigma*sigma) * exp(-(x*x/2/sigma/sigma));
+}
+// 2D gaussian (zero mean)
+// (9) in http://mathworld.wolfram.com/GaussianFunction.html
+inline double Gaussian2D(double x, double y, double sigma) {
+ return 1.0/(2.0*M_PI*sigma*sigma) * exp( -(x*x+y*y)/(2.0*sigma*sigma));
+}
+inline double GaussianDerivative(double x, double sigma) {
+ return -x / sigma / sigma * Gaussian(x, sigma);
+}
+// Solve the inverse of the Gaussian for positive x.
+inline double GaussianInversePositive(double y, double sigma) {
+ return sqrt(-2 * sigma * sigma * log(y * sigma * sqrt(2*M_PI)));
+}
+
+void ComputeGaussianKernel(double sigma, Vec *kernel, Vec *derivative);
+void ConvolveHorizontal(const FloatImage &in,
+ const Vec &kernel,
+ FloatImage *out_pointer,
+ int plane = -1);
+void ConvolveVertical(const FloatImage &in,
+ const Vec &kernel,
+ FloatImage *out_pointer,
+ int plane = -1);
+void ConvolveGaussian(const FloatImage &in,
+ double sigma,
+ FloatImage *out_pointer);
+
+void ImageDerivatives(const FloatImage &in,
+ double sigma,
+ FloatImage *gradient_x,
+ FloatImage *gradient_y);
+
+void BlurredImageAndDerivatives(const FloatImage &in,
+ double sigma,
+ FloatImage *blurred_image,
+ FloatImage *gradient_x,
+ FloatImage *gradient_y);
+
+// Blur and take the gradients of an image, storing the results inside the
+// three channels of blurred_and_gradxy.
+void BlurredImageAndDerivativesChannels(const FloatImage &in,
+ double sigma,
+ FloatImage *blurred_and_gradxy);
+
+void BoxFilterHorizontal(const FloatImage &in,
+ int window_size,
+ FloatImage *out_pointer);
+
+void BoxFilterVertical(const FloatImage &in,
+ int window_size,
+ FloatImage *out_pointer);
+
+void BoxFilter(const FloatImage &in,
+ int box_width,
+ FloatImage *out);
+
+} // namespace libmv
+
+#endif // LIBMV_IMAGE_CONVOLVE_H_
+
diff --git a/extern/libmv/libmv/image/image.h b/extern/libmv/libmv/image/image.h
new file mode 100644
index 00000000000..d158b0e0397
--- /dev/null
+++ b/extern/libmv/libmv/image/image.h
@@ -0,0 +1,158 @@
+// Copyright (c) 2007, 2008 libmv authors.
+//
+// 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 LIBMV_IMAGE_IMAGE_H
+#define LIBMV_IMAGE_IMAGE_H
+
+#include <cmath>
+
+#include "libmv/image/array_nd.h"
+
+namespace libmv {
+
+typedef Array3Du ByteImage; // For backwards compatibility.
+typedef Array3Df FloatImage;
+
+// Type added only to manage special 2D array for feature detection
+typedef Array3Di IntImage;
+typedef Array3Ds ShortImage;
+
+// An image class that is a thin wrapper around Array3D's of various types.
+// TODO(keir): Decide if we should add reference counting semantics... Maybe it
+// is the best solution after all.
+class Image {
+ public:
+
+ // Create an image from an array. The image takes ownership of the array.
+ Image(Array3Du *array) : array_type_(BYTE), array_(array) {}
+ Image(Array3Df *array) : array_type_(FLOAT), array_(array) {}
+
+ Image(const Image &img): array_type_(NONE), array_(NULL) {
+ *this = img;
+ }
+
+ // Underlying data type.
+ enum DataType {
+ NONE,
+ BYTE,
+ FLOAT,
+ INT,
+ SHORT,
+ };
+
+ // Size in bytes that the image takes in memory.
+ int MemorySizeInBytes() {
+ int size;
+ switch (array_type_)
+ {
+ case BYTE:
+ size = reinterpret_cast<Array3Du *>(array_)->MemorySizeInBytes();
+ break;
+ case FLOAT:
+ size = reinterpret_cast<Array3Df *>(array_)->MemorySizeInBytes();
+ break;
+ case INT:
+ size = reinterpret_cast<Array3Di *>(array_)->MemorySizeInBytes();
+ break;
+ case SHORT:
+ size = reinterpret_cast<Array3Ds *>(array_)->MemorySizeInBytes();
+ break;
+ default :
+ size = 0;
+ assert(0);
+ }
+ size += sizeof(*this);
+ return size;
+ }
+
+ ~Image() {
+ switch (array_type_)
+ {
+ case BYTE:
+ delete reinterpret_cast<Array3Du *>(array_);
+
+ break;
+ case FLOAT:
+ delete reinterpret_cast<Array3Df *>(array_);
+
+ break;
+ case INT:
+ delete reinterpret_cast<Array3Di *>(array_);
+
+ break;
+ case SHORT:
+ delete reinterpret_cast<Array3Ds *>(array_);
+
+ break;
+ default:
+ assert(0);
+ }
+ }
+
+ Image& operator= (const Image& f) {
+ if (this != &f) {
+ array_type_ = f.array_type_;
+ switch (array_type_)
+ {
+ case BYTE:
+ delete reinterpret_cast<Array3Du *>(array_);
+ array_ = new Array3Du( *(Array3Du *)f.array_);
+ break;
+ case FLOAT:
+ delete reinterpret_cast<Array3Df *>(array_);
+ array_ = new Array3Df( *(Array3Df *)f.array_);
+ break;
+ case INT:
+ delete reinterpret_cast<Array3Di *>(array_);
+ array_ = new Array3Di( *(Array3Di *)f.array_);
+ break;
+ case SHORT:
+ delete reinterpret_cast<Array3Ds *>(array_);
+ array_ = new Array3Ds( *(Array3Ds *)f.array_);
+ break;
+ default:
+ assert(0);
+ }
+ }
+ return *this;
+ }
+
+ Array3Du *AsArray3Du() const {
+ if (array_type_ == BYTE) {
+ return reinterpret_cast<Array3Du *>(array_);
+ }
+ return NULL;
+ }
+
+ Array3Df *AsArray3Df() const {
+ if (array_type_ == FLOAT) {
+ return reinterpret_cast<Array3Df *>(array_);
+ }
+ return NULL;
+ }
+
+ private:
+ DataType array_type_;
+ BaseArray *array_;
+};
+
+} // namespace libmv
+
+#endif // LIBMV_IMAGE_IMAGE_IMAGE_H
diff --git a/extern/libmv/libmv/image/sample.h b/extern/libmv/libmv/image/sample.h
new file mode 100644
index 00000000000..cd361231b58
--- /dev/null
+++ b/extern/libmv/libmv/image/sample.h
@@ -0,0 +1,103 @@
+// Copyright (c) 2007, 2008 libmv authors.
+//
+// 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 LIBMV_IMAGE_SAMPLE_H_
+#define LIBMV_IMAGE_SAMPLE_H_
+
+#include "libmv/image/image.h"
+
+namespace libmv {
+
+/// Nearest neighbor interpolation.
+template<typename T>
+inline T SampleNearest(const Array3D<T> &image,
+ float y, float x, int v = 0) {
+ const int i = int(round(y));
+ const int j = int(round(x));
+ return image(i, j, v);
+}
+
+static inline void LinearInitAxis(float fx, int width,
+ int *x1, int *x2,
+ float *dx1, float *dx2) {
+ const int ix = int(fx);
+ if (ix < 0) {
+ *x1 = 0;
+ *x2 = 0;
+ *dx1 = 1;
+ *dx2 = 0;
+ } else if (ix > width-2) {
+ *x1 = width-1;
+ *x2 = width-1;
+ *dx1 = 1;
+ *dx2 = 0;
+ } else {
+ *x1 = ix;
+ *x2 = *x1 + 1;
+ *dx1 = *x2 - fx;
+ *dx2 = 1 - *dx1;
+ }
+}
+
+/// Linear interpolation.
+template<typename T>
+inline T SampleLinear(const Array3D<T> &image, float y, float x, int v = 0) {
+ int x1, y1, x2, y2;
+ float dx1, dy1, dx2, dy2;
+
+ LinearInitAxis(y, image.Height(), &y1, &y2, &dy1, &dy2);
+ LinearInitAxis(x, image.Width(), &x1, &x2, &dx1, &dx2);
+
+ const T im11 = image(y1, x1, v);
+ const T im12 = image(y1, x2, v);
+ const T im21 = image(y2, x1, v);
+ const T im22 = image(y2, x2, v);
+
+ return T(dy1 * ( dx1 * im11 + dx2 * im12 ) +
+ dy2 * ( dx1 * im21 + dx2 * im22 ));
+}
+
+// Downsample all channels by 2. If the image has odd width or height, the last
+// row or column is ignored.
+// FIXME(MatthiasF): this implementation shouldn't be in an interface file
+inline void DownsampleChannelsBy2(const Array3Df &in, Array3Df *out) {
+ int height = in.Height() / 2;
+ int width = in.Width() / 2;
+ int depth = in.Depth();
+
+ out->Resize(height, width, depth);
+
+ // 2x2 box filter downsampling.
+ for (int r = 0; r < height; ++r) {
+ for (int c = 0; c < width; ++c) {
+ for (int k = 0; k < depth; ++k) {
+ (*out)(r, c, k) = (in(2 * r, 2 * c, k) +
+ in(2 * r + 1, 2 * c, k) +
+ in(2 * r, 2 * c + 1, k) +
+ in(2 * r + 1, 2 * c + 1, k)) / 4.0f;
+ }
+ }
+ }
+
+}
+
+} // namespace libmv
+
+#endif // LIBMV_IMAGE_SAMPLE_H_
diff --git a/extern/libmv/libmv/image/tuple.h b/extern/libmv/libmv/image/tuple.h
new file mode 100644
index 00000000000..79acc9579d0
--- /dev/null
+++ b/extern/libmv/libmv/image/tuple.h
@@ -0,0 +1,90 @@
+// Copyright (c) 2007, 2008 libmv authors.
+//
+// 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 LIBMV_IMAGE_TUPLE_H
+#define LIBMV_IMAGE_TUPLE_H
+
+#include <algorithm>
+
+namespace libmv {
+
+// A vector of elements with fixed lenght and deep copy semantics.
+template <typename T, int N>
+class Tuple {
+ public:
+ enum { SIZE = N };
+ Tuple() {}
+ Tuple(T initial_value) { Reset(initial_value); }
+
+ template <typename D>
+ Tuple(D *values) { Reset(values); }
+
+ template <typename D>
+ Tuple(const Tuple<D,N> &b) { Reset(b); }
+
+ template <typename D>
+ Tuple& operator=(const Tuple<D,N>& b) {
+ Reset(b);
+ return *this;
+ }
+
+ template <typename D>
+ void Reset(const Tuple<D, N>& b) { Reset(b.Data()); }
+
+ template <typename D>
+ void Reset(D *values) {
+ for(int i=0;i<N;i++) {
+ data_[i] = T(values[i]);
+ }
+ }
+
+ // Set all tuple values to the same thing.
+ void Reset(T value) {
+ for(int i=0;i<N;i++) {
+ data_[i] = value;
+ }
+ }
+
+ // Pointer to the first element.
+ T *Data() { return &data_[0]; }
+ const T *Data() const { return &data_[0]; }
+
+ T &operator()(int i) { return data_[i]; }
+ const T &operator()(int i) const { return data_[i]; }
+
+ bool operator==(const Tuple<T, N> &other) const {
+ for (int i = 0; i < N; ++i) {
+ if ((*this)(i) != other(i)) {
+ return false;
+ }
+ }
+ return true;
+ }
+ bool operator!=(const Tuple<T, N> &other) const {
+ return !(*this == other);
+ }
+
+ private:
+ T data_[N];
+};
+
+} // namespace libmv
+
+#endif // LIBMV_IMAGE_TUPLE_H
diff --git a/extern/libmv/libmv/logging/logging.h b/extern/libmv/libmv/logging/logging.h
new file mode 100644
index 00000000000..af86c4baa42
--- /dev/null
+++ b/extern/libmv/libmv/logging/logging.h
@@ -0,0 +1,31 @@
+// Copyright (c) 2007, 2008, 2009 libmv authors.
+//
+// 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 LIBMV_LOGGING_LOGGING_H
+#define LIBMV_LOGGING_LOGGING_H
+
+#include "glog/logging.h"
+
+#define LG LOG(INFO)
+#define V0 LOG(INFO)
+#define V1 LOG(INFO)
+#define V2 LOG(INFO)
+
+#endif // LIBMV_LOGGING_LOGGING_H
diff --git a/extern/libmv/libmv/multiview/conditioning.cc b/extern/libmv/libmv/multiview/conditioning.cc
new file mode 100644
index 00000000000..20e3a88e6cb
--- /dev/null
+++ b/extern/libmv/libmv/multiview/conditioning.cc
@@ -0,0 +1,99 @@
+// Copyright (c) 2010 libmv authors.
+//
+// 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 "libmv/multiview/conditioning.h"
+#include "libmv/multiview/projection.h"
+
+namespace libmv {
+
+// HZ 4.4.4 pag.109: Point conditioning (non isotropic)
+void PreconditionerFromPoints(const Mat &points, Mat3 *T) {
+ Vec mean, variance;
+ MeanAndVarianceAlongRows(points, &mean, &variance);
+
+ double xfactor = sqrt(2.0 / variance(0));
+ double yfactor = sqrt(2.0 / variance(1));
+
+ // If variance is equal to 0.0 set scaling factor to identity.
+ // -> Else it will provide nan value (because division by 0).
+ if (variance(0) < 1e-8)
+ xfactor = mean(0) = 1.0;
+ if (variance(1) < 1e-8)
+ yfactor = mean(1) = 1.0;
+
+ *T << xfactor, 0, -xfactor * mean(0),
+ 0, yfactor, -yfactor * mean(1),
+ 0, 0, 1;
+}
+// HZ 4.4.4 pag.107: Point conditioning (isotropic)
+void IsotropicPreconditionerFromPoints(const Mat &points, Mat3 *T) {
+ Vec mean, variance;
+ MeanAndVarianceAlongRows(points, &mean, &variance);
+
+ double var_norm = variance.norm();
+ double factor = sqrt(2.0 / var_norm);
+
+ // If variance is equal to 0.0 set scaling factor to identity.
+ // -> Else it will provide nan value (because division by 0).
+ if (var_norm < 1e-8) {
+ factor = 1.0;
+ mean.setOnes();
+ }
+
+ *T << factor, 0, -factor * mean(0),
+ 0, factor, -factor * mean(1),
+ 0, 0, 1;
+}
+
+void ApplyTransformationToPoints(const Mat &points,
+ const Mat3 &T,
+ Mat *transformed_points) {
+ int n = points.cols();
+ transformed_points->resize(2,n);
+ Mat3X p(3, n);
+ EuclideanToHomogeneous(points, &p);
+ p = T * p;
+ HomogeneousToEuclidean(p, transformed_points);
+}
+
+void NormalizePoints(const Mat &points,
+ Mat *normalized_points,
+ Mat3 *T) {
+ PreconditionerFromPoints(points, T);
+ ApplyTransformationToPoints(points, *T, normalized_points);
+}
+
+void NormalizeIsotropicPoints(const Mat &points,
+ Mat *normalized_points,
+ Mat3 *T) {
+ IsotropicPreconditionerFromPoints(points, T);
+ ApplyTransformationToPoints(points, *T, normalized_points);
+}
+
+// Denormalize the results. See HZ page 109.
+void UnnormalizerT::Unnormalize(const Mat3 &T1, const Mat3 &T2, Mat3 *H) {
+ *H = T2.transpose() * (*H) * T1;
+}
+
+void UnnormalizerI::Unnormalize(const Mat3 &T1, const Mat3 &T2, Mat3 *H) {
+ *H = T2.inverse() * (*H) * T1;
+}
+
+} // namespace libmv
diff --git a/extern/libmv/libmv/multiview/conditioning.h b/extern/libmv/libmv/multiview/conditioning.h
new file mode 100644
index 00000000000..181d7485374
--- /dev/null
+++ b/extern/libmv/libmv/multiview/conditioning.h
@@ -0,0 +1,60 @@
+// Copyright (c) 2010 libmv authors.
+//
+// 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 LIBMV_MULTIVIEW_CONDITIONNING_H_
+#define LIBMV_MULTIVIEW_CONDITIONNING_H_
+
+#include "libmv/numeric/numeric.h"
+
+namespace libmv {
+
+// Point conditioning (non isotropic)
+void PreconditionerFromPoints(const Mat &points, Mat3 *T);
+// Point conditioning (isotropic)
+void IsotropicPreconditionerFromPoints(const Mat &points, Mat3 *T);
+
+void ApplyTransformationToPoints(const Mat &points,
+ const Mat3 &T,
+ Mat *transformed_points);
+
+void NormalizePoints(const Mat &points,
+ Mat *normalized_points,
+ Mat3 *T);
+
+void NormalizeIsotropicPoints(const Mat &points,
+ Mat *normalized_points,
+ Mat3 *T);
+
+/// Use inverse for unnormalize
+struct UnnormalizerI {
+ // Denormalize the results. See HZ page 109.
+ static void Unnormalize(const Mat3 &T1, const Mat3 &T2, Mat3 *H);
+};
+
+/// Use transpose for unnormalize
+struct UnnormalizerT {
+ // Denormalize the results. See HZ page 109.
+ static void Unnormalize(const Mat3 &T1, const Mat3 &T2, Mat3 *H);
+};
+
+} //namespace libmv
+
+
+#endif // LIBMV_MULTIVIEW_CONDITIONNING_H_
diff --git a/extern/libmv/libmv/multiview/euclidean_resection.cc b/extern/libmv/libmv/multiview/euclidean_resection.cc
new file mode 100644
index 00000000000..6d918a1a8bc
--- /dev/null
+++ b/extern/libmv/libmv/multiview/euclidean_resection.cc
@@ -0,0 +1,661 @@
+// Copyright (c) 2009 libmv authors.
+//
+// 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 <cmath>
+#include <limits>
+
+#include <Eigen/SVD>
+#include <Eigen/Geometry>
+
+#include "libmv/base/vector.h"
+#include "libmv/logging/logging.h"
+#include "libmv/multiview/euclidean_resection.h"
+#include "libmv/multiview/projection.h"
+
+namespace libmv {
+namespace euclidean_resection {
+
+bool EuclideanResection(const Mat2X &x_camera,
+ const Mat3X &X_world,
+ Mat3 *R, Vec3 *t,
+ ResectionMethod method) {
+ switch (method) {
+ case RESECTION_ANSAR_DANIILIDIS:
+ EuclideanResectionAnsarDaniilidis(x_camera, X_world, R, t);
+ break;
+ case RESECTION_EPNP:
+ return EuclideanResectionEPnP(x_camera, X_world, R, t);
+ break;
+ default:
+ LOG(FATAL) << "Unknown resection method.";
+ }
+ return false;
+}
+
+bool EuclideanResection(const Mat &x_image,
+ const Mat3X &X_world,
+ const Mat3 &K,
+ Mat3 *R, Vec3 *t,
+ ResectionMethod method) {
+ CHECK(x_image.rows() == 2 || x_image.rows() == 3)
+ << "Invalid size for x_image: "
+ << x_image.rows() << "x" << x_image.cols();
+
+ Mat2X x_camera;
+ if (x_image.rows() == 2) {
+ EuclideanToNormalizedCamera(x_image, K, &x_camera);
+ } else if (x_image.rows() == 3) {
+ HomogeneousToNormalizedCamera(x_image, K, &x_camera);
+ }
+ return EuclideanResection(x_camera, X_world, R, t, method);
+}
+
+void AbsoluteOrientation(const Mat3X &X,
+ const Mat3X &Xp,
+ Mat3 *R,
+ Vec3 *t) {
+ int num_points = X.cols();
+ Vec3 C = X.rowwise().sum() / num_points; // Centroid of X.
+ Vec3 Cp = Xp.rowwise().sum() / num_points; // Centroid of Xp.
+
+ // Normalize the two point sets.
+ Mat3X Xn(3, num_points), Xpn(3, num_points);
+ for( int i = 0; i < num_points; ++i ){
+ Xn.col(i) = X.col(i) - C;
+ Xpn.col(i) = Xp.col(i) - Cp;
+ }
+
+ // Construct the N matrix (pg. 635).
+ double Sxx = Xn.row(0).dot(Xpn.row(0));
+ double Syy = Xn.row(1).dot(Xpn.row(1));
+ double Szz = Xn.row(2).dot(Xpn.row(2));
+ double Sxy = Xn.row(0).dot(Xpn.row(1));
+ double Syx = Xn.row(1).dot(Xpn.row(0));
+ double Sxz = Xn.row(0).dot(Xpn.row(2));
+ double Szx = Xn.row(2).dot(Xpn.row(0));
+ double Syz = Xn.row(1).dot(Xpn.row(2));
+ double Szy = Xn.row(2).dot(Xpn.row(1));
+
+ Mat4 N;
+ N << Sxx + Syy + Szz, Syz - Szy, Szx - Sxz, Sxy - Syx,
+ Syz - Szy, Sxx - Syy - Szz, Sxy + Syx, Szx + Sxz,
+ Szx - Sxz, Sxy + Syx, -Sxx + Syy - Szz, Syz + Szy,
+ Sxy - Syx, Szx + Sxz, Syz + Szy, -Sxx - Syy + Szz;
+
+ // Find the unit quaternion q that maximizes qNq. It is the eigenvector
+ // corresponding to the lagest eigenvalue.
+ Vec4 q = N.jacobiSvd(Eigen::ComputeFullU).matrixU().col(0);
+
+ // Retrieve the 3x3 rotation matrix.
+ Vec4 qq = q.array() * q.array();
+ double q0q1 = q(0) * q(1);
+ double q0q2 = q(0) * q(2);
+ double q0q3 = q(0) * q(3);
+ double q1q2 = q(1) * q(2);
+ double q1q3 = q(1) * q(3);
+ double q2q3 = q(2) * q(3);
+
+ (*R) << qq(0) + qq(1) - qq(2) - qq(3),
+ 2 * (q1q2 - q0q3),
+ 2 * (q1q3 + q0q2),
+ 2 * (q1q2+ q0q3),
+ qq(0) - qq(1) + qq(2) - qq(3),
+ 2 * (q2q3 - q0q1),
+ 2 * (q1q3 - q0q2),
+ 2 * (q2q3 + q0q1),
+ qq(0) - qq(1) - qq(2) + qq(3);
+
+ // Fix the handedness of the R matrix.
+ if (R->determinant() < 0) {
+ R->row(2) = -R->row(2);
+ }
+ // Compute the final translation.
+ *t = Cp - *R * C;
+}
+
+// Convert i and j indices of the original variables into their quadratic
+// permutation single index. It follows that t_ij = t_ji.
+static int IJToPointIndex(int i, int j, int num_points) {
+ // Always make sure that j is bigger than i. This handles t_ij = t_ji.
+ if (j < i) {
+ std::swap(i, j);
+ }
+ int idx;
+ int num_permutation_rows = num_points * (num_points - 1) / 2;
+
+ // All t_ii's are located at the end of the t vector after all t_ij's.
+ if (j == i) {
+ idx = num_permutation_rows + i;
+ } else {
+ int offset = (num_points - i - 1) * (num_points - i) / 2;
+ idx = (num_permutation_rows - offset + j - i - 1);
+ }
+ return idx;
+};
+
+// Convert i and j indexes of the solution for lambda to their linear indexes.
+static int IJToIndex(int i, int j, int num_lambda) {
+ if (j < i) {
+ std::swap(i, j);
+ }
+ int A = num_lambda * (num_lambda + 1) / 2;
+ int B = num_lambda - i;
+ int C = B * (B + 1) / 2;
+ int idx = A - C + j - i;
+ return idx;
+};
+
+static int Sign(double value) {
+ return (value < 0) ? -1 : 1;
+};
+
+// Organizes a square matrix into a single row constraint on the elements of
+// Lambda to create the constraints in equation (5) in "Linear Pose Estimation
+// from Points or Lines", by Ansar, A. and Daniilidis, PAMI 2003. vol. 25, no.
+// 5.
+static Vec MatrixToConstraint(const Mat &A,
+ int num_k_columns,
+ int num_lambda) {
+ Vec C(num_k_columns);
+ C.setZero();
+ int idx = 0;
+ for (int i = 0; i < num_lambda; ++i) {
+ for( int j = i; j < num_lambda; ++j) {
+ C(idx) = A(i, j);
+ if (i != j){
+ C(idx) += A(j, i);
+ }
+ ++ idx;
+ }
+ }
+ return C;
+}
+
+// Normalizes the columns of vectors.
+static void NormalizeColumnVectors(Mat3X *vectors) {
+ int num_columns = vectors->cols();
+ for (int i = 0; i < num_columns; ++i){
+ vectors->col(i).normalize();
+ }
+}
+
+void EuclideanResectionAnsarDaniilidis(const Mat2X &x_camera,
+ const Mat3X &X_world,
+ Mat3 *R,
+ Vec3 *t) {
+ CHECK(x_camera.cols() == X_world.cols());
+ CHECK(x_camera.cols() > 3);
+
+ int num_points = x_camera.cols();
+
+ // Copy the normalized camera coords into 3 vectors and normalize them so
+ // that they are unit vectors from the camera center.
+ Mat3X x_camera_unit(3, num_points);
+ x_camera_unit.block(0, 0, 2, num_points) = x_camera;
+ x_camera_unit.row(2).setOnes();
+ NormalizeColumnVectors(&x_camera_unit);
+
+ int num_m_rows = num_points * (num_points - 1) / 2;
+ int num_tt_variables = num_points * (num_points + 1) / 2;
+ int num_m_columns = num_tt_variables + 1;
+ Mat M(num_m_columns, num_m_columns);
+ M.setZero();
+ Matu ij_index(num_tt_variables, 2);
+
+ // Create the constraint equations for the t_ij variables (7) and arrange
+ // them into the M matrix (8). Also store the initial (i, j) indices.
+ int row=0;
+ for (int i = 0; i < num_points; ++i) {
+ for (int j = i+1; j < num_points; ++j) {
+ M(row, row) = -2 * x_camera_unit.col(i).dot(x_camera_unit.col(j));
+ M(row, num_m_rows + i) = x_camera_unit.col(i).dot(x_camera_unit.col(i));
+ M(row, num_m_rows + j) = x_camera_unit.col(j).dot(x_camera_unit.col(j));
+ Vec3 Xdiff = X_world.col(i) - X_world.col(j);
+ double center_to_point_distance = Xdiff.norm();
+ M(row, num_m_columns - 1) =
+ - center_to_point_distance * center_to_point_distance;
+ ij_index(row, 0) = i;
+ ij_index(row, 1) = j;
+ ++row;
+ }
+ ij_index(i + num_m_rows, 0) = i;
+ ij_index(i + num_m_rows, 1) = i;
+ }
+
+ int num_lambda = num_points + 1; // Dimension of the null space of M.
+ Mat V = M.jacobiSvd(Eigen::ComputeFullV).matrixV().block(0,
+ num_m_rows,
+ num_m_columns,
+ num_lambda);
+
+ // TODO(vess): The number of constraint equations in K (num_k_rows) must be
+ // (num_points + 1) * (num_points + 2)/2. This creates a performance issue
+ // for more than 4 points. It is fine for 4 points at the moment with 18
+ // instead of 15 equations.
+ int num_k_rows = num_m_rows + num_points *
+ (num_points*(num_points-1)/2 - num_points+1);
+ int num_k_columns = num_lambda * (num_lambda + 1) / 2;
+ Mat K(num_k_rows, num_k_columns);
+ K.setZero();
+
+ // Construct the first part of the K matrix corresponding to (t_ii, t_jk) for
+ // i != j.
+ int counter_k_row = 0;
+ for (int idx1 = num_m_rows; idx1 < num_tt_variables; ++idx1) {
+ for (int idx2 = 0; idx2 < num_m_rows; ++idx2) {
+
+ unsigned int i = ij_index(idx1, 0);
+ unsigned int j = ij_index(idx2, 0);
+ unsigned int k = ij_index(idx2, 1);
+
+ if( i != j && i != k ){
+ int idx3 = IJToPointIndex(i, j, num_points);
+ int idx4 = IJToPointIndex(i, k, num_points);
+
+ K.row(counter_k_row) =
+ MatrixToConstraint(V.row(idx1).transpose() * V.row(idx2)-
+ V.row(idx3).transpose() * V.row(idx4),
+ num_k_columns,
+ num_lambda);
+ ++counter_k_row;
+ }
+ }
+ }
+
+ // Construct the second part of the K matrix corresponding to (t_ii,t_jk) for
+ // j==k.
+ for (int idx1 = num_m_rows; idx1 < num_tt_variables; ++idx1) {
+ for (int idx2 = idx1 + 1; idx2 < num_tt_variables; ++idx2) {
+ unsigned int i = ij_index(idx1, 0);
+ unsigned int j = ij_index(idx2, 0);
+ unsigned int k = ij_index(idx2, 1);
+
+ int idx3 = IJToPointIndex(i, j, num_points);
+ int idx4 = IJToPointIndex(i, k, num_points);
+
+ K.row(counter_k_row) =
+ MatrixToConstraint(V.row(idx1).transpose() * V.row(idx2)-
+ V.row(idx3).transpose() * V.row(idx4),
+ num_k_columns,
+ num_lambda);
+ ++counter_k_row;
+ }
+ }
+ Vec L_sq = K.jacobiSvd(Eigen::ComputeFullV).matrixV().col(num_k_columns - 1);
+
+ // Pivot on the largest element for numerical stability. Afterwards recover
+ // the sign of the lambda solution.
+ double max_L_sq_value = fabs(L_sq(IJToIndex(0, 0, num_lambda)));
+ int max_L_sq_index = 1;
+ for (int i = 1; i < num_lambda; ++i) {
+ double abs_sq_value = fabs(L_sq(IJToIndex(i, i, num_lambda)));
+ if (max_L_sq_value < abs_sq_value) {
+ max_L_sq_value = abs_sq_value;
+ max_L_sq_index = i;
+ }
+ }
+ // Ensure positiveness of the largest value corresponding to lambda_ii.
+ L_sq = L_sq * Sign(L_sq(IJToIndex(max_L_sq_index,
+ max_L_sq_index,
+ num_lambda)));
+
+
+ Vec L(num_lambda);
+ L(max_L_sq_index) = sqrt(L_sq(IJToIndex(max_L_sq_index,
+ max_L_sq_index,
+ num_lambda)));
+
+ for (int i = 0; i < num_lambda; ++i) {
+ if (i != max_L_sq_index) {
+ L(i) = L_sq(IJToIndex(max_L_sq_index, i, num_lambda)) / L(max_L_sq_index);
+ }
+ }
+
+ // Correct the scale using the fact that the last constraint is equal to 1.
+ L = L / (V.row(num_m_columns - 1).dot(L));
+ Vec X = V * L;
+
+ // Recover the distances from the camera center to the 3D points Q.
+ Vec d(num_points);
+ d.setZero();
+ for (int c_point = num_m_rows; c_point < num_tt_variables; ++c_point) {
+ d(c_point - num_m_rows) = sqrt(X(c_point));
+ }
+
+ // Create the 3D points in the camera system.
+ Mat X_cam(3, num_points);
+ for (int c_point = 0; c_point < num_points; ++c_point ) {
+ X_cam.col(c_point) = d(c_point) * x_camera_unit.col(c_point);
+ }
+ // Recover the camera translation and rotation.
+ AbsoluteOrientation(X_world, X_cam, R, t);
+}
+
+// Selects 4 virtual control points using mean and PCA.
+void SelectControlPoints(const Mat3X &X_world,
+ Mat *X_centered,
+ Mat34 *X_control_points) {
+ size_t num_points = X_world.cols();
+
+ // The first virtual control point, C0, is the centroid.
+ Vec mean, variance;
+ MeanAndVarianceAlongRows(X_world, &mean, &variance);
+ X_control_points->col(0) = mean;
+
+ // Computes PCA
+ X_centered->resize (3, num_points);
+ for (size_t c = 0; c < num_points; c++) {
+ X_centered->col(c) = X_world.col (c) - mean;
+ }
+ Mat3 X_centered_sq = (*X_centered) * X_centered->transpose();
+ Eigen::JacobiSVD<Mat3> X_centered_sq_svd(X_centered_sq, Eigen::ComputeFullU);
+ Vec3 w = X_centered_sq_svd.singularValues();
+ Mat3 u = X_centered_sq_svd.matrixU();
+ for (size_t c = 0; c < 3; c++) {
+ double k = sqrt (w (c) / num_points);
+ X_control_points->col (c + 1) = mean + k * u.col (c);
+ }
+}
+
+// Computes the barycentric coordinates for all real points
+void ComputeBarycentricCoordinates(const Mat3X &X_world_centered,
+ const Mat34 &X_control_points,
+ Mat4X *alphas) {
+ size_t num_points = X_world_centered.cols();
+ Mat3 C2 ;
+ for (size_t c = 1; c < 4; c++) {
+ C2.col(c-1) = X_control_points.col(c) - X_control_points.col(0);
+ }
+
+ Mat3 C2inv = C2.inverse();
+ Mat3X a = C2inv * X_world_centered;
+
+ alphas->resize(4, num_points);
+ alphas->setZero();
+ alphas->block(1, 0, 3, num_points) = a;
+ for (size_t c = 0; c < num_points; c++) {
+ (*alphas)(0, c) = 1.0 - alphas->col(c).sum();
+ }
+}
+
+// Estimates the coordinates of all real points in the camera coordinate frame
+void ComputePointsCoordinatesInCameraFrame(
+ const Mat4X &alphas,
+ const Vec4 &betas,
+ const Eigen::Matrix<double, 12, 12> &U,
+ Mat3X *X_camera) {
+ size_t num_points = alphas.cols();
+
+ // Estimates the control points in the camera reference frame.
+ Mat34 C2b; C2b.setZero();
+ for (size_t cu = 0; cu < 4; cu++) {
+ for (size_t c = 0; c < 4; c++) {
+ C2b.col(c) += betas(cu) * U.block(11 - cu, c * 3, 1, 3).transpose();
+ }
+ }
+
+ // Estimates the 3D points in the camera reference frame
+ X_camera->resize(3, num_points);
+ for (size_t c = 0; c < num_points; c++) {
+ X_camera->col(c) = C2b * alphas.col(c);
+ }
+
+ // Check the sign of the z coordinate of the points (should be positive)
+ uint num_z_neg = 0;
+ for (size_t i = 0; i < X_camera->cols(); ++i) {
+ if ((*X_camera)(2,i) < 0) {
+ num_z_neg++;
+ }
+ }
+
+ // If more than 50% of z are negative, we change the signs
+ if (num_z_neg > 0.5 * X_camera->cols()) {
+ C2b = -C2b;
+ *X_camera = -(*X_camera);
+ }
+}
+
+bool EuclideanResectionEPnP(const Mat2X &x_camera,
+ const Mat3X &X_world,
+ Mat3 *R, Vec3 *t) {
+ CHECK(x_camera.cols() == X_world.cols());
+ CHECK(x_camera.cols() > 3);
+ size_t num_points = X_world.cols();
+
+ // Select the control points.
+ Mat34 X_control_points;
+ Mat X_centered;
+ SelectControlPoints(X_world, &X_centered, &X_control_points);
+
+ // Compute the barycentric coordinates.
+ Mat4X alphas(4, num_points);
+ ComputeBarycentricCoordinates(X_centered, X_control_points, &alphas);
+
+ // Estimates the M matrix with the barycentric coordinates
+ Mat M(2 * num_points, 12);
+ Eigen::Matrix<double, 2, 12> sub_M;
+ for (size_t c = 0; c < num_points; c++) {
+ double a0 = alphas(0, c);
+ double a1 = alphas(1, c);
+ double a2 = alphas(2, c);
+ double a3 = alphas(3, c);
+ double ui = x_camera(0, c);
+ double vi = x_camera(1, c);
+ M.block(2*c, 0, 2, 12) << a0, 0,
+ a0*(-ui), a1, 0,
+ a1*(-ui), a2, 0,
+ a2*(-ui), a3, 0,
+ a3*(-ui), 0,
+ a0, a0*(-vi), 0,
+ a1, a1*(-vi), 0,
+ a2, a2*(-vi), 0,
+ a3, a3*(-vi);
+ }
+
+ // TODO(julien): Avoid the transpose by rewriting the u2.block() calls.
+ Eigen::JacobiSVD<Mat> MtMsvd(M.transpose()*M, Eigen::ComputeFullU);
+ Eigen::Matrix<double, 12, 12> u2 = MtMsvd.matrixU().transpose();
+
+ // Estimate the L matrix.
+ Eigen::Matrix<double, 6, 3> dv1;
+ Eigen::Matrix<double, 6, 3> dv2;
+ Eigen::Matrix<double, 6, 3> dv3;
+ Eigen::Matrix<double, 6, 3> dv4;
+
+ dv1.row(0) = u2.block(11, 0, 1, 3) - u2.block(11, 3, 1, 3);
+ dv1.row(1) = u2.block(11, 0, 1, 3) - u2.block(11, 6, 1, 3);
+ dv1.row(2) = u2.block(11, 0, 1, 3) - u2.block(11, 9, 1, 3);
+ dv1.row(3) = u2.block(11, 3, 1, 3) - u2.block(11, 6, 1, 3);
+ dv1.row(4) = u2.block(11, 3, 1, 3) - u2.block(11, 9, 1, 3);
+ dv1.row(5) = u2.block(11, 6, 1, 3) - u2.block(11, 9, 1, 3);
+ dv2.row(0) = u2.block(10, 0, 1, 3) - u2.block(10, 3, 1, 3);
+ dv2.row(1) = u2.block(10, 0, 1, 3) - u2.block(10, 6, 1, 3);
+ dv2.row(2) = u2.block(10, 0, 1, 3) - u2.block(10, 9, 1, 3);
+ dv2.row(3) = u2.block(10, 3, 1, 3) - u2.block(10, 6, 1, 3);
+ dv2.row(4) = u2.block(10, 3, 1, 3) - u2.block(10, 9, 1, 3);
+ dv2.row(5) = u2.block(10, 6, 1, 3) - u2.block(10, 9, 1, 3);
+ dv3.row(0) = u2.block( 9, 0, 1, 3) - u2.block( 9, 3, 1, 3);
+ dv3.row(1) = u2.block( 9, 0, 1, 3) - u2.block( 9, 6, 1, 3);
+ dv3.row(2) = u2.block( 9, 0, 1, 3) - u2.block( 9, 9, 1, 3);
+ dv3.row(3) = u2.block( 9, 3, 1, 3) - u2.block( 9, 6, 1, 3);
+ dv3.row(4) = u2.block( 9, 3, 1, 3) - u2.block( 9, 9, 1, 3);
+ dv3.row(5) = u2.block( 9, 6, 1, 3) - u2.block( 9, 9, 1, 3);
+ dv4.row(0) = u2.block( 8, 0, 1, 3) - u2.block( 8, 3, 1, 3);
+ dv4.row(1) = u2.block( 8, 0, 1, 3) - u2.block( 8, 6, 1, 3);
+ dv4.row(2) = u2.block( 8, 0, 1, 3) - u2.block( 8, 9, 1, 3);
+ dv4.row(3) = u2.block( 8, 3, 1, 3) - u2.block( 8, 6, 1, 3);
+ dv4.row(4) = u2.block( 8, 3, 1, 3) - u2.block( 8, 9, 1, 3);
+ dv4.row(5) = u2.block( 8, 6, 1, 3) - u2.block( 8, 9, 1, 3);
+
+ Eigen::Matrix<double, 6, 10> L;
+ for (size_t r = 0; r < 6; r++) {
+ L.row(r) << dv1.row(r).dot(dv1.row(r)),
+ 2.0 * dv1.row(r).dot(dv2.row(r)),
+ dv2.row(r).dot(dv2.row(r)),
+ 2.0 * dv1.row(r).dot(dv3.row(r)),
+ 2.0 * dv2.row(r).dot(dv3.row(r)),
+ dv3.row(r).dot(dv3.row(r)),
+ 2.0 * dv1.row(r).dot(dv4.row(r)),
+ 2.0 * dv2.row(r).dot(dv4.row(r)),
+ 2.0 * dv3.row(r).dot(dv4.row(r)),
+ dv4.row(r).dot(dv4.row(r));
+ }
+ Vec6 rho;
+ rho << (X_control_points.col(0) - X_control_points.col(1)).squaredNorm(),
+ (X_control_points.col(0) - X_control_points.col(2)).squaredNorm(),
+ (X_control_points.col(0) - X_control_points.col(3)).squaredNorm(),
+ (X_control_points.col(1) - X_control_points.col(2)).squaredNorm(),
+ (X_control_points.col(1) - X_control_points.col(3)).squaredNorm(),
+ (X_control_points.col(2) - X_control_points.col(3)).squaredNorm();
+
+ // There are three possible solutions based on the three approximations of L
+ // (betas). Below, each one is solved for then the best one is chosen.
+ Mat3X X_camera;
+ Mat3 K; K.setIdentity();
+ vector<Mat3> Rs(3);
+ vector<Vec3> ts(3);
+ Vec rmse(3);
+
+ // TODO(julien): Document where the "1e-3" magical constant comes from below.
+
+ // Find the first possible solution for R, t corresponding to:
+ // Betas = [b00 b01 b11 b02 b12 b22 b03 b13 b23 b33]
+ // Betas_approx_1 = [b00 b01 b02 b03]
+ Vec4 betas = Vec4::Zero();
+ Eigen::Matrix<double, 6, 4> l_6x4;
+ for (size_t r = 0; r < 6; r++) {
+ l_6x4.row(r) << L(r, 0), L(r, 1), L(r, 3), L(r, 6);
+ }
+ Eigen::JacobiSVD<Mat> svd_of_l4(l_6x4,
+ Eigen::ComputeFullU | Eigen::ComputeFullV);
+ Vec4 b4 = svd_of_l4.solve(rho);
+ if ((l_6x4 * b4).isApprox(rho, 1e-3)) {
+ if (b4(0) < 0) {
+ b4 = -b4;
+ }
+ b4(0) = std::sqrt(b4(0));
+ betas << b4(0), b4(1) / b4(0), b4(2) / b4(0), b4(3) / b4(0);
+ ComputePointsCoordinatesInCameraFrame(alphas, betas, u2, &X_camera);
+ AbsoluteOrientation(X_world, X_camera, &Rs[0], &ts[0]);
+ rmse(0) = RootMeanSquareError(x_camera, X_world, K, Rs[0], ts[0]);
+ } else {
+ LOG(ERROR) << "First approximation of beta not good enough.";
+ ts[0].setZero();
+ rmse(0) = std::numeric_limits<double>::max();
+ }
+
+ // Find the second possible solution for R, t corresponding to:
+ // Betas = [b00 b01 b11 b02 b12 b22 b03 b13 b23 b33]
+ // Betas_approx_2 = [b00 b01 b11]
+ betas.setZero();
+ Eigen::Matrix<double, 6, 3> l_6x3;
+ l_6x3 = L.block(0, 0, 6, 3);
+ Eigen::JacobiSVD<Mat> svdOfL3(l_6x3,
+ Eigen::ComputeFullU | Eigen::ComputeFullV);
+ Vec3 b3 = svdOfL3.solve(rho);
+ VLOG(2) << " rho = " << rho;
+ VLOG(2) << " l_6x3 * b3 = " << l_6x3 * b3;
+ if ((l_6x3 * b3).isApprox(rho, 1e-3)) {
+ if (b3(0) < 0) {
+ betas(0) = std::sqrt(-b3(0));
+ betas(1) = (b3(2) < 0) ? std::sqrt(-b3(2)) : 0;
+ } else {
+ betas(0) = std::sqrt(b3(0));
+ betas(1) = (b3(2) > 0) ? std::sqrt(b3(2)) : 0;
+ }
+ if (b3(1) < 0) {
+ betas(0) = -betas(0);
+ }
+ betas(2) = 0;
+ betas(3) = 0;
+ ComputePointsCoordinatesInCameraFrame(alphas, betas, u2, &X_camera);
+ AbsoluteOrientation(X_world, X_camera, &Rs[1], &ts[1]);
+ rmse(1) = RootMeanSquareError(x_camera, X_world, K, Rs[1], ts[1]);
+ } else {
+ LOG(ERROR) << "Second approximation of beta not good enough.";
+ ts[1].setZero();
+ rmse(1) = std::numeric_limits<double>::max();
+ }
+
+ // Find the third possible solution for R, t corresponding to:
+ // Betas = [b00 b01 b11 b02 b12 b22 b03 b13 b23 b33]
+ // Betas_approx_3 = [b00 b01 b11 b02 b12]
+ betas.setZero();
+ Eigen::Matrix<double, 6, 5> l_6x5;
+ l_6x5 = L.block(0, 0, 6, 5);
+ Eigen::JacobiSVD<Mat> svdOfL5(l_6x5,
+ Eigen::ComputeFullU | Eigen::ComputeFullV);
+ Vec5 b5 = svdOfL5.solve(rho);
+ if ((l_6x5 * b5).isApprox(rho, 1e-3)) {
+ if (b5(0) < 0) {
+ betas(0) = std::sqrt(-b5(0));
+ if (b5(2) < 0) {
+ betas(1) = std::sqrt(-b5(2));
+ } else {
+ b5(2) = 0;
+ }
+ } else {
+ betas(0) = std::sqrt(b5(0));
+ if (b5(2) > 0) {
+ betas(1) = std::sqrt(b5(2));
+ } else {
+ b5(2) = 0;
+ }
+ }
+ if (b5(1) < 0) {
+ betas(0) = -betas(0);
+ }
+ betas(2) = b5(3) / betas(0);
+ betas(3) = 0;
+ ComputePointsCoordinatesInCameraFrame(alphas, betas, u2, &X_camera);
+ AbsoluteOrientation(X_world, X_camera, &Rs[2], &ts[2]);
+ rmse(2) = RootMeanSquareError(x_camera, X_world, K, Rs[2], ts[2]);
+ } else {
+ LOG(ERROR) << "Third approximation of beta not good enough.";
+ ts[2].setZero();
+ rmse(2) = std::numeric_limits<double>::max();
+ }
+
+ // Finally, with all three solutions, select the (R, t) with the best RMSE.
+ VLOG(2) << "RMSE for solution 0: " << rmse(0);
+ VLOG(2) << "RMSE for solution 1: " << rmse(0);
+ VLOG(2) << "RMSE for solution 2: " << rmse(0);
+ size_t n = 0;
+ if (rmse(1) < rmse(0)) {
+ n = 1;
+ }
+ if (rmse(2) < rmse(n)) {
+ n = 2;
+ }
+ if (rmse(n) == std::numeric_limits<double>::max()) {
+ LOG(ERROR) << "All three possibilities failed. Reporting failure.";
+ return false;
+ }
+
+ VLOG(1) << "RMSE for best solution #" << n << ": " << rmse(n);
+ *R = Rs[n];
+ *t = ts[n];
+
+ // TODO(julien): Improve the solutions with non-linear refinement.
+ return true;
+}
+
+} // namespace resection
+} // namespace libmv
diff --git a/extern/libmv/libmv/multiview/euclidean_resection.h b/extern/libmv/libmv/multiview/euclidean_resection.h
new file mode 100644
index 00000000000..08fa3d90bd3
--- /dev/null
+++ b/extern/libmv/libmv/multiview/euclidean_resection.h
@@ -0,0 +1,124 @@
+// Copyright (c) 2010 libmv authors.
+//
+// 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 LIBMV_MULTIVIEW_EUCLIDEAN_RESECTION_H_
+#define LIBMV_MULTIVIEW_EUCLIDEAN_RESECTION_H_
+
+#include "libmv/numeric/numeric.h"
+#include "libmv/multiview/projection.h"
+
+namespace libmv {
+namespace euclidean_resection {
+
+enum ResectionMethod {
+ RESECTION_ANSAR_DANIILIDIS,
+ RESECTION_EPNP,
+};
+
+/**
+ * Computes the extrinsic parameters, R and t for a calibrated camera
+ * from 4 or more 3D points and their normalized images.
+ *
+ * \param x_camera Image points in normalized camera coordinates e.g. x_camera
+ * = inv(K) * x_image.
+ * \param X_world 3D points in the world coordinate system
+ * \param R Solution for the camera rotation matrix
+ * \param t Solution for the camera translation vector
+ * \param method The resection method to use.
+ */
+bool EuclideanResection(const Mat2X &x_camera,
+ const Mat3X &X_world,
+ Mat3 *R, Vec3 *t,
+ ResectionMethod method = RESECTION_EPNP);
+
+/**
+ * Computes the extrinsic parameters, R and t for a calibrated camera
+ * from 4 or more 3D points and their images.
+ *
+ * \param x_image Image points in non-normalized image coordinates. The
+ * coordates are laid out one per row. The matrix can be Nx2
+ * or Nx3 for euclidean or homogenous 2D coordinates.
+ * \param X_world 3D points in the world coordinate system
+ * \param K Intrinsic parameters camera matrix
+ * \param R Solution for the camera rotation matrix
+ * \param t Solution for the camera translation vector
+ * \param method Resection method
+ */
+bool EuclideanResection(const Mat &x_image,
+ const Mat3X &X_world,
+ const Mat3 &K,
+ Mat3 *R, Vec3 *t,
+ ResectionMethod method = RESECTION_EPNP);
+
+/**
+ * The absolute orientation algorithm recovers the transformation between a set
+ * of 3D points, X and Xp such that:
+ *
+ * Xp = R*X + t
+ *
+ * The recovery of the absolute orientation is implemented after this article:
+ * Horn, Hilden, "Closed-form solution of absolute orientation using
+ * orthonormal matrices"
+ */
+void AbsoluteOrientation(const Mat3X &X,
+ const Mat3X &Xp,
+ Mat3 *R,
+ Vec3 *t);
+
+/**
+ * Computes the extrinsic parameters, R and t for a calibrated camera from 4 or
+ * more 3D points and their images.
+ *
+ * \param x_camera Image points in normalized camera coordinates, e.g.
+ * x_camera=inv(K)*x_image
+ * \param X_world 3D points in the world coordinate system
+ * \param R Solution for the camera rotation matrix
+ * \param t Solution for the camera translation vector
+ *
+ * This is the algorithm described in: "Linear Pose Estimation from Points or
+ * Lines", by Ansar, A. and Daniilidis, PAMI 2003. vol. 25, no. 5.
+ */
+void EuclideanResectionAnsarDaniilidis(const Mat2X &x_camera,
+ const Mat3X &X_world,
+ Mat3 *R, Vec3 *t);
+/**
+ * Computes the extrinsic parameters, R and t for a calibrated camera from 4 or
+ * more 3D points and their images.
+ *
+ * \param x_camera Image points in normalized camera coordinates,
+ * e.g. x_camera = inv(K) * x_image
+ * \param X_world 3D points in the world coordinate system
+ * \param R Solution for the camera rotation matrix
+ * \param t Solution for the camera translation vector
+ *
+ * This is the algorithm described in:
+ * "{EP$n$P: An Accurate $O(n)$ Solution to the P$n$P Problem", by V. Lepetit
+ * and F. Moreno-Noguer and P. Fua, IJCV 2009. vol. 81, no. 2
+ * \note: the non-linear optimization is not implemented here.
+ */
+bool EuclideanResectionEPnP(const Mat2X &x_camera,
+ const Mat3X &X_world,
+ Mat3 *R, Vec3 *t);
+
+} // namespace euclidean_resection
+} // namespace libmv
+
+
+#endif /* LIBMV_MULTIVIEW_EUCLIDEAN_RESECTION_H_ */
diff --git a/extern/libmv/libmv/multiview/fundamental.cc b/extern/libmv/libmv/multiview/fundamental.cc
new file mode 100644
index 00000000000..7a6b4a08439
--- /dev/null
+++ b/extern/libmv/libmv/multiview/fundamental.cc
@@ -0,0 +1,391 @@
+// Copyright (c) 2007, 2008 libmv authors.
+//
+// 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 "libmv/logging/logging.h"
+#include "libmv/numeric/numeric.h"
+#include "libmv/numeric/poly.h"
+#include "libmv/multiview/conditioning.h"
+#include "libmv/multiview/projection.h"
+#include "libmv/multiview/triangulation.h"
+#include "libmv/multiview/fundamental.h"
+
+namespace libmv {
+
+void EliminateRow(const Mat34 &P, int row, Mat *X) {
+ X->resize(2, 4);
+
+ int first_row = (row + 1) % 3;
+ int second_row = (row + 2) % 3;
+
+ for (int i = 0; i < 4; ++i) {
+ (*X)(0, i) = P(first_row, i);
+ (*X)(1, i) = P(second_row, i);
+ }
+}
+
+void ProjectionsFromFundamental(const Mat3 &F, Mat34 *P1, Mat34 *P2) {
+ *P1 << Mat3::Identity(), Vec3::Zero();
+ Vec3 e2;
+ Mat3 Ft = F.transpose();
+ Nullspace(&Ft, &e2);
+ *P2 << CrossProductMatrix(e2) * F, e2;
+}
+
+// Addapted from vgg_F_from_P.
+void FundamentalFromProjections(const Mat34 &P1, const Mat34 &P2, Mat3 *F) {
+ Mat X[3];
+ Mat Y[3];
+ Mat XY;
+
+ for (int i = 0; i < 3; ++i) {
+ EliminateRow(P1, i, X + i);
+ EliminateRow(P2, i, Y + i);
+ }
+
+ for (int i = 0; i < 3; ++i) {
+ for (int j = 0; j < 3; ++j) {
+ VerticalStack(X[j], Y[i], &XY);
+ (*F)(i, j) = XY.determinant();
+ }
+ }
+}
+
+// HZ 11.1 pag.279 (x1 = x, x2 = x')
+// http://www.cs.unc.edu/~marc/tutorial/node54.html
+double EightPointSolver(const Mat &x1, const Mat &x2, Mat3 *F) {
+ DCHECK_EQ(x1.rows(), 2);
+ DCHECK_GE(x1.cols(), 8);
+ DCHECK_EQ(x1.rows(), x2.rows());
+ DCHECK_EQ(x1.cols(), x2.cols());
+
+ int n = x1.cols();
+ Mat A(n, 9);
+ for (int i = 0; i < n; ++i) {
+ A(i, 0) = x2(0, i) * x1(0, i);
+ A(i, 1) = x2(0, i) * x1(1, i);
+ A(i, 2) = x2(0, i);
+ A(i, 3) = x2(1, i) * x1(0, i);
+ A(i, 4) = x2(1, i) * x1(1, i);
+ A(i, 5) = x2(1, i);
+ A(i, 6) = x1(0, i);
+ A(i, 7) = x1(1, i);
+ A(i, 8) = 1;
+ }
+
+ Vec9 f;
+ double smaller_singular_value = Nullspace(&A, &f);
+ *F = Map<RMat3>(f.data());
+ return smaller_singular_value;
+}
+
+// HZ 11.1.1 pag.280
+void EnforceFundamentalRank2Constraint(Mat3 *F) {
+ Eigen::JacobiSVD<Mat3> USV(*F, Eigen::ComputeFullU | Eigen::ComputeFullV);
+ Vec3 d = USV.singularValues();
+ d(2) = 0.0;
+ *F = USV.matrixU() * d.asDiagonal() * USV.matrixV().transpose();
+}
+
+// HZ 11.2 pag.281 (x1 = x, x2 = x')
+double NormalizedEightPointSolver(const Mat &x1,
+ const Mat &x2,
+ Mat3 *F) {
+ DCHECK_EQ(x1.rows(), 2);
+ DCHECK_GE(x1.cols(), 8);
+ DCHECK_EQ(x1.rows(), x2.rows());
+ DCHECK_EQ(x1.cols(), x2.cols());
+
+ // Normalize the data.
+ Mat3 T1, T2;
+ PreconditionerFromPoints(x1, &T1);
+ PreconditionerFromPoints(x2, &T2);
+ Mat x1_normalized, x2_normalized;
+ ApplyTransformationToPoints(x1, T1, &x1_normalized);
+ ApplyTransformationToPoints(x2, T2, &x2_normalized);
+
+ // Estimate the fundamental matrix.
+ double smaller_singular_value =
+ EightPointSolver(x1_normalized, x2_normalized, F);
+ EnforceFundamentalRank2Constraint(F);
+
+ // Denormalize the fundamental matrix.
+ *F = T2.transpose() * (*F) * T1;
+
+ return smaller_singular_value;
+}
+
+// Seven-point algorithm.
+// http://www.cs.unc.edu/~marc/tutorial/node55.html
+double FundamentalFrom7CorrespondencesLinear(const Mat &x1,
+ const Mat &x2,
+ std::vector<Mat3> *F) {
+ DCHECK_EQ(x1.rows(), 2);
+ DCHECK_EQ(x1.cols(), 7);
+ DCHECK_EQ(x1.rows(), x2.rows());
+ DCHECK_EQ(x2.cols(), x2.cols());
+
+ // Build a 9 x n matrix from point matches, where each row is equivalent to
+ // the equation x'T*F*x = 0 for a single correspondence pair (x', x). The
+ // domain of the matrix is a 9 element vector corresponding to F. The
+ // nullspace should be rank two; the two dimensions correspond to the set of
+ // F matrices satisfying the epipolar geometry.
+ Matrix<double, 7, 9> A;
+ for (int ii = 0; ii < 7; ++ii) {
+ A(ii, 0) = x1(0, ii) * x2(0, ii); // 0 represents x coords,
+ A(ii, 1) = x1(1, ii) * x2(0, ii); // 1 represents y coords.
+ A(ii, 2) = x2(0, ii);
+ A(ii, 3) = x1(0, ii) * x2(1, ii);
+ A(ii, 4) = x1(1, ii) * x2(1, ii);
+ A(ii, 5) = x2(1, ii);
+ A(ii, 6) = x1(0, ii);
+ A(ii, 7) = x1(1, ii);
+ A(ii, 8) = 1.0;
+ }
+
+ // Find the two F matrices in the nullspace of A.
+ Vec9 f1, f2;
+ double s = Nullspace2(&A, &f1, &f2);
+ Mat3 F1 = Map<RMat3>(f1.data());
+ Mat3 F2 = Map<RMat3>(f2.data());
+
+ // Then, use the condition det(F) = 0 to determine F. In other words, solve
+ // det(F1 + a*F2) = 0 for a.
+ double a = F1(0, 0), j = F2(0, 0),
+ b = F1(0, 1), k = F2(0, 1),
+ c = F1(0, 2), l = F2(0, 2),
+ d = F1(1, 0), m = F2(1, 0),
+ e = F1(1, 1), n = F2(1, 1),
+ f = F1(1, 2), o = F2(1, 2),
+ g = F1(2, 0), p = F2(2, 0),
+ h = F1(2, 1), q = F2(2, 1),
+ i = F1(2, 2), r = F2(2, 2);
+
+ // Run fundamental_7point_coeffs.py to get the below coefficients.
+ // The coefficients are in ascending powers of alpha, i.e. P[N]*x^N.
+ double P[4] = {
+ a*e*i + b*f*g + c*d*h - a*f*h - b*d*i - c*e*g,
+ a*e*r + a*i*n + b*f*p + b*g*o + c*d*q + c*h*m + d*h*l + e*i*j + f*g*k -
+ a*f*q - a*h*o - b*d*r - b*i*m - c*e*p - c*g*n - d*i*k - e*g*l - f*h*j,
+ a*n*r + b*o*p + c*m*q + d*l*q + e*j*r + f*k*p + g*k*o + h*l*m + i*j*n -
+ a*o*q - b*m*r - c*n*p - d*k*r - e*l*p - f*j*q - g*l*n - h*j*o - i*k*m,
+ j*n*r + k*o*p + l*m*q - j*o*q - k*m*r - l*n*p,
+ };
+
+ // Solve for the roots of P[3]*x^3 + P[2]*x^2 + P[1]*x + P[0] = 0.
+ double roots[3];
+ int num_roots = SolveCubicPolynomial(P, roots);
+
+ // Build the fundamental matrix for each solution.
+ for (int kk = 0; kk < num_roots; ++kk) {
+ F->push_back(F1 + roots[kk] * F2);
+ }
+ return s;
+}
+
+double FundamentalFromCorrespondences7Point(const Mat &x1,
+ const Mat &x2,
+ std::vector<Mat3> *F) {
+ DCHECK_EQ(x1.rows(), 2);
+ DCHECK_GE(x1.cols(), 7);
+ DCHECK_EQ(x1.rows(), x2.rows());
+ DCHECK_EQ(x1.cols(), x2.cols());
+
+ // Normalize the data.
+ Mat3 T1, T2;
+ PreconditionerFromPoints(x1, &T1);
+ PreconditionerFromPoints(x2, &T2);
+ Mat x1_normalized, x2_normalized;
+ ApplyTransformationToPoints(x1, T1, &x1_normalized);
+ ApplyTransformationToPoints(x2, T2, &x2_normalized);
+
+ // Estimate the fundamental matrix.
+ double smaller_singular_value =
+ FundamentalFrom7CorrespondencesLinear(x1_normalized, x2_normalized, &(*F));
+
+ for (int k = 0; k < F->size(); ++k) {
+ Mat3 & Fmat = (*F)[k];
+ // Denormalize the fundamental matrix.
+ Fmat = T2.transpose() * Fmat * T1;
+ }
+ return smaller_singular_value;
+}
+
+void NormalizeFundamental(const Mat3 &F, Mat3 *F_normalized) {
+ *F_normalized = F / FrobeniusNorm(F);
+ if ((*F_normalized)(2, 2) < 0) {
+ *F_normalized *= -1;
+ }
+}
+
+double SampsonDistance(const Mat &F, const Vec2 &x1, const Vec2 &x2) {
+ Vec3 x(x1(0), x1(1), 1.0);
+ Vec3 y(x2(0), x2(1), 1.0);
+
+ Vec3 F_x = F * x;
+ Vec3 Ft_y = F.transpose() * y;
+ double y_F_x = y.dot(F_x);
+
+ return Square(y_F_x) / ( F_x.head<2>().squaredNorm()
+ + Ft_y.head<2>().squaredNorm());
+}
+
+double SymmetricEpipolarDistance(const Mat &F, const Vec2 &x1, const Vec2 &x2) {
+ Vec3 x(x1(0), x1(1), 1.0);
+ Vec3 y(x2(0), x2(1), 1.0);
+
+ Vec3 F_x = F * x;
+ Vec3 Ft_y = F.transpose() * y;
+ double y_F_x = y.dot(F_x);
+
+ return Square(y_F_x) * ( 1 / F_x.head<2>().squaredNorm()
+ + 1 / Ft_y.head<2>().squaredNorm());
+}
+
+// HZ 9.6 pag 257 (formula 9.12)
+void EssentialFromFundamental(const Mat3 &F,
+ const Mat3 &K1,
+ const Mat3 &K2,
+ Mat3 *E) {
+ *E = K2.transpose() * F * K1;
+}
+
+// HZ 9.6 pag 257 (formula 9.12)
+// Or http://ai.stanford.edu/~birch/projective/node20.html
+void FundamentalFromEssential(const Mat3 &E,
+ const Mat3 &K1,
+ const Mat3 &K2,
+ Mat3 *F) {
+ *F = K2.inverse().transpose() * E * K1.inverse();
+}
+
+void RelativeCameraMotion(const Mat3 &R1,
+ const Vec3 &t1,
+ const Mat3 &R2,
+ const Vec3 &t2,
+ Mat3 *R,
+ Vec3 *t) {
+ *R = R2 * R1.transpose();
+ *t = t2 - (*R) * t1;
+}
+
+// HZ 9.6 pag 257
+void EssentialFromRt(const Mat3 &R1,
+ const Vec3 &t1,
+ const Mat3 &R2,
+ const Vec3 &t2,
+ Mat3 *E) {
+ Mat3 R;
+ Vec3 t;
+ RelativeCameraMotion(R1, t1, R2, t2, &R, &t);
+ Mat3 Tx = CrossProductMatrix(t);
+ *E = Tx * R;
+}
+
+// HZ 9.6 pag 259 (Result 9.19)
+void MotionFromEssential(const Mat3 &E,
+ std::vector<Mat3> *Rs,
+ std::vector<Vec3> *ts) {
+ Eigen::JacobiSVD<Mat3> USV(E, Eigen::ComputeFullU | Eigen::ComputeFullV);
+ Mat3 U = USV.matrixU();
+ Vec3 d = USV.singularValues();
+ Mat3 Vt = USV.matrixV().transpose();
+
+ // Last column of U is undetermined since d = (a a 0).
+ if (U.determinant() < 0) {
+ U.col(2) *= -1;
+ }
+ // Last row of Vt is undetermined since d = (a a 0).
+ if (Vt.determinant() < 0) {
+ Vt.row(2) *= -1;
+ }
+
+ Mat3 W;
+ W << 0, -1, 0,
+ 1, 0, 0,
+ 0, 0, 1;
+
+ Mat3 U_W_Vt = U * W * Vt;
+ Mat3 U_Wt_Vt = U * W.transpose() * Vt;
+
+ Rs->resize(4);
+ (*Rs)[0] = U_W_Vt;
+ (*Rs)[1] = U_W_Vt;
+ (*Rs)[2] = U_Wt_Vt;
+ (*Rs)[3] = U_Wt_Vt;
+
+ ts->resize(4);
+ (*ts)[0] = U.col(2);
+ (*ts)[1] = -U.col(2);
+ (*ts)[2] = U.col(2);
+ (*ts)[3] = -U.col(2);
+}
+
+int MotionFromEssentialChooseSolution(const std::vector<Mat3> &Rs,
+ const std::vector<Vec3> &ts,
+ const Mat3 &K1,
+ const Vec2 &x1,
+ const Mat3 &K2,
+ const Vec2 &x2) {
+ DCHECK_EQ(4, Rs.size());
+ DCHECK_EQ(4, ts.size());
+
+ Mat34 P1, P2;
+ Mat3 R1;
+ Vec3 t1;
+ R1.setIdentity();
+ t1.setZero();
+ P_From_KRt(K1, R1, t1, &P1);
+ for (int i = 0; i < 4; ++i) {
+ const Mat3 &R2 = Rs[i];
+ const Vec3 &t2 = ts[i];
+ P_From_KRt(K2, R2, t2, &P2);
+ Vec3 X;
+ TriangulateDLT(P1, x1, P2, x2, &X);
+ double d1 = Depth(R1, t1, X);
+ double d2 = Depth(R2, t2, X);
+ // Test if point is front to the two cameras.
+ if (d1 > 0 && d2 > 0) {
+ return i;
+ }
+ }
+ return -1;
+}
+
+bool MotionFromEssentialAndCorrespondence(const Mat3 &E,
+ const Mat3 &K1,
+ const Vec2 &x1,
+ const Mat3 &K2,
+ const Vec2 &x2,
+ Mat3 *R,
+ Vec3 *t) {
+ std::vector<Mat3> Rs;
+ std::vector<Vec3> ts;
+ MotionFromEssential(E, &Rs, &ts);
+ int solution = MotionFromEssentialChooseSolution(Rs, ts, K1, x1, K2, x2);
+ if (solution >= 0) {
+ *R = Rs[solution];
+ *t = ts[solution];
+ return true;
+ } else {
+ return false;
+ }
+}
+
+} // namespace libmv
diff --git a/extern/libmv/libmv/multiview/fundamental.h b/extern/libmv/libmv/multiview/fundamental.h
new file mode 100644
index 00000000000..3f4a3b7b211
--- /dev/null
+++ b/extern/libmv/libmv/multiview/fundamental.h
@@ -0,0 +1,144 @@
+// Copyright (c) 2007, 2008, 2011 libmv authors.
+//
+// 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 LIBMV_MULTIVIEW_FUNDAMENTAL_H_
+#define LIBMV_MULTIVIEW_FUNDAMENTAL_H_
+
+#include <vector>
+
+#include "libmv/numeric/numeric.h"
+
+namespace libmv {
+
+void ProjectionsFromFundamental(const Mat3 &F, Mat34 *P1, Mat34 *P2);
+void FundamentalFromProjections(const Mat34 &P1, const Mat34 &P2, Mat3 *F);
+
+/**
+ * The normalized 8-point fundamental matrix solver.
+ */
+double NormalizedEightPointSolver(const Mat &x1,
+ const Mat &x2,
+ Mat3 *F);
+
+/**
+ * 7 points (minimal case, points coordinates must be normalized before):
+ */
+double FundamentalFrom7CorrespondencesLinear(const Mat &x1,
+ const Mat &x2,
+ std::vector<Mat3> *F);
+
+/**
+ * 7 points (points coordinates must be in image space):
+ */
+double FundamentalFromCorrespondences7Point(const Mat &x1,
+ const Mat &x2,
+ std::vector<Mat3> *F);
+
+/**
+ * 8 points (points coordinates must be in image space):
+ */
+double NormalizedEightPointSolver(const Mat &x1,
+ const Mat &x2,
+ Mat3 *F);
+
+/**
+ * Fundamental matrix utility function:
+ */
+void EnforceFundamentalRank2Constraint(Mat3 *F);
+
+void NormalizeFundamental(const Mat3 &F, Mat3 *F_normalized);
+
+/**
+ * Approximate squared reprojection errror.
+ *
+ * See page 287 of HZ equation 11.9. This avoids triangulating the point,
+ * relying only on the entries in F.
+ */
+double SampsonDistance(const Mat &F, const Vec2 &x1, const Vec2 &x2);
+
+/**
+ * Calculates the sum of the distances from the points to the epipolar lines.
+ *
+ * See page 288 of HZ equation 11.10.
+ */
+double SymmetricEpipolarDistance(const Mat &F, const Vec2 &x1, const Vec2 &x2);
+
+/**
+ * Compute the relative camera motion between two cameras.
+ *
+ * Given the motion parameters of two cameras, computes the motion parameters
+ * of the second one assuming the first one to be at the origin.
+ * If T1 and T2 are the camera motions, the computed relative motion is
+ * T = T2 T1^{-1}
+ */
+void RelativeCameraMotion(const Mat3 &R1,
+ const Vec3 &t1,
+ const Mat3 &R2,
+ const Vec3 &t2,
+ Mat3 *R,
+ Vec3 *t);
+
+void EssentialFromFundamental(const Mat3 &F,
+ const Mat3 &K1,
+ const Mat3 &K2,
+ Mat3 *E);
+
+void FundamentalFromEssential(const Mat3 &E,
+ const Mat3 &K1,
+ const Mat3 &K2,
+ Mat3 *F);
+
+void EssentialFromRt(const Mat3 &R1,
+ const Vec3 &t1,
+ const Mat3 &R2,
+ const Vec3 &t2,
+ Mat3 *E);
+
+void MotionFromEssential(const Mat3 &E,
+ std::vector<Mat3> *Rs,
+ std::vector<Vec3> *ts);
+
+/**
+ * Choose one of the four possible motion solutions from an essential matrix.
+ *
+ * Decides the right solution by checking that the triangulation of a match
+ * x1--x2 lies in front of the cameras. See HZ 9.6 pag 259 (9.6.3 Geometrical
+ * interpretation of the 4 solutions)
+ *
+ * \return index of the right solution or -1 if no solution.
+ */
+int MotionFromEssentialChooseSolution(const std::vector<Mat3> &Rs,
+ const std::vector<Vec3> &ts,
+ const Mat3 &K1,
+ const Vec2 &x1,
+ const Mat3 &K2,
+ const Vec2 &x2);
+
+bool MotionFromEssentialAndCorrespondence(const Mat3 &E,
+ const Mat3 &K1,
+ const Vec2 &x1,
+ const Mat3 &K2,
+ const Vec2 &x2,
+ Mat3 *R,
+ Vec3 *t);
+
+} // namespace libmv
+
+#endif // LIBMV_MULTIVIEW_FUNDAMENTAL_H_
diff --git a/extern/libmv/libmv/multiview/nviewtriangulation.h b/extern/libmv/libmv/multiview/nviewtriangulation.h
new file mode 100644
index 00000000000..b4f521f185d
--- /dev/null
+++ b/extern/libmv/libmv/multiview/nviewtriangulation.h
@@ -0,0 +1,80 @@
+// Copyright (c) 2009 libmv authors.
+//
+// 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.
+//
+// Compute a 3D position of a point from several images of it. In particular,
+// compute the projective point X in R^4 such that x = PX.
+//
+// Algorithm is the standard DLT; for derivation see appendix of Keir's thesis.
+
+#ifndef LIBMV_MULTIVIEW_NVIEWTRIANGULATION_H
+#define LIBMV_MULTIVIEW_NVIEWTRIANGULATION_H
+
+#include "libmv/base/vector.h"
+#include "libmv/logging/logging.h"
+#include "libmv/numeric/numeric.h"
+
+namespace libmv {
+
+// x's are 2D coordinates (x,y,1) in each image; Ps are projective cameras. The
+// output, X, is a homogeneous four vectors.
+template<typename T>
+void NViewTriangulate(const Matrix<T, 2, Dynamic> &x,
+ const vector<Matrix<T, 3, 4> > &Ps,
+ Matrix<T, 4, 1> *X) {
+ int nviews = x.cols();
+ assert(nviews == Ps.size());
+
+ Matrix<T, Dynamic, Dynamic> design(3*nviews, 4 + nviews);
+ design.setConstant(0.0);
+ for (int i = 0; i < nviews; i++) {
+ design.template block<3, 4>(3*i, 0) = -Ps[i];
+ design(3*i + 0, 4 + i) = x(0, i);
+ design(3*i + 1, 4 + i) = x(1, i);
+ design(3*i + 2, 4 + i) = 1.0;
+ }
+ Matrix<T, Dynamic, 1> X_and_alphas;
+ Nullspace(&design, &X_and_alphas);
+ X->resize(4);
+ *X = X_and_alphas.head(4);
+}
+
+// x's are 2D coordinates (x,y,1) in each image; Ps are projective cameras. The
+// output, X, is a homogeneous four vectors.
+// This method uses the algebraic distance approximation.
+// Note that this method works better when the 2D points are normalized
+// with an isotopic normalization.
+template<typename T>
+void NViewTriangulateAlgebraic(const Matrix<T, 2, Dynamic> &x,
+ const vector<Matrix<T, 3, 4> > &Ps,
+ Matrix<T, 4, 1> *X) {
+ int nviews = x.cols();
+ assert(nviews == Ps.size());
+
+ Matrix<T, Dynamic, 4> design(2*nviews, 4);
+ for (int i = 0; i < nviews; i++) {
+ design.template block<2, 4>(2*i, 0) = SkewMatMinimal(x.col(i)) * Ps[i];
+ }
+ X->resize(4);
+ Nullspace(&design, X);
+}
+
+} // namespace libmv
+
+#endif // LIBMV_MULTIVIEW_RESECTION_H
diff --git a/extern/libmv/libmv/multiview/projection.cc b/extern/libmv/libmv/multiview/projection.cc
new file mode 100644
index 00000000000..a7d1a058e9c
--- /dev/null
+++ b/extern/libmv/libmv/multiview/projection.cc
@@ -0,0 +1,221 @@
+// Copyright (c) 2007, 2008 libmv authors.
+//
+// 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 "libmv/multiview/projection.h"
+#include "libmv/numeric/numeric.h"
+
+namespace libmv {
+
+void P_From_KRt(const Mat3 &K, const Mat3 &R, const Vec3 &t, Mat34 *P) {
+ P->block<3, 3>(0, 0) = R;
+ P->col(3) = t;
+ (*P) = K * (*P);
+}
+
+void KRt_From_P(const Mat34 &P, Mat3 *Kp, Mat3 *Rp, Vec3 *tp) {
+ // Decompose using the RQ decomposition HZ A4.1.1 pag.579.
+ Mat3 K = P.block(0, 0, 3, 3);
+
+ Mat3 Q;
+ Q.setIdentity();
+
+ // Set K(2,1) to zero.
+ if (K(2, 1) != 0) {
+ double c = -K(2,2);
+ double s = K(2,1);
+ double l = sqrt(c * c + s * s);
+ c /= l; s /= l;
+ Mat3 Qx;
+ Qx << 1, 0, 0,
+ 0, c, -s,
+ 0, s, c;
+ K = K * Qx;
+ Q = Qx.transpose() * Q;
+ }
+ // Set K(2,0) to zero.
+ if (K(2, 0) != 0) {
+ double c = K(2, 2);
+ double s = K(2, 0);
+ double l = sqrt(c * c + s * s);
+ c /= l; s /= l;
+ Mat3 Qy;
+ Qy << c, 0, s,
+ 0, 1, 0,
+ -s, 0, c;
+ K = K * Qy;
+ Q = Qy.transpose() * Q;
+ }
+ // Set K(1,0) to zero.
+ if (K(1, 0) != 0) {
+ double c = -K(1, 1);
+ double s = K(1, 0);
+ double l = sqrt(c * c + s * s);
+ c /= l; s /= l;
+ Mat3 Qz;
+ Qz << c,-s, 0,
+ s, c, 0,
+ 0, 0, 1;
+ K = K * Qz;
+ Q = Qz.transpose() * Q;
+ }
+
+ Mat3 R = Q;
+
+ // Ensure that the diagonal is positive.
+ // TODO(pau) Change this to ensure that:
+ // - K(0,0) > 0
+ // - K(2,2) = 1
+ // - det(R) = 1
+ if (K(2,2) < 0) {
+ K = -K;
+ R = -R;
+ }
+ if (K(1,1) < 0) {
+ Mat3 S;
+ S << 1, 0, 0,
+ 0,-1, 0,
+ 0, 0, 1;
+ K = K * S;
+ R = S * R;
+ }
+ if (K(0,0) < 0) {
+ Mat3 S;
+ S << -1, 0, 0,
+ 0, 1, 0,
+ 0, 0, 1;
+ K = K * S;
+ R = S * R;
+ }
+
+ // Compute translation.
+ Vec p(3);
+ p << P(0,3), P(1,3), P(2,3);
+ // TODO(pau) This sould be done by a SolveLinearSystem(A, b, &x) call.
+ // TODO(keir) use the eigen LU solver syntax...
+ Vec3 t = K.inverse() * p;
+
+ // scale K so that K(2,2) = 1
+ K = K / K(2,2);
+
+ *Kp = K;
+ *Rp = R;
+ *tp = t;
+}
+
+void ProjectionShiftPrincipalPoint(const Mat34 &P,
+ const Vec2 &principal_point,
+ const Vec2 &principal_point_new,
+ Mat34 *P_new) {
+ Mat3 T;
+ T << 1, 0, principal_point_new(0) - principal_point(0),
+ 0, 1, principal_point_new(1) - principal_point(1),
+ 0, 0, 1;
+ *P_new = T * P;
+}
+
+void ProjectionChangeAspectRatio(const Mat34 &P,
+ const Vec2 &principal_point,
+ double aspect_ratio,
+ double aspect_ratio_new,
+ Mat34 *P_new) {
+ Mat3 T;
+ T << 1, 0, 0,
+ 0, aspect_ratio_new / aspect_ratio, 0,
+ 0, 0, 1;
+ Mat34 P_temp;
+
+ ProjectionShiftPrincipalPoint(P, principal_point, Vec2(0,0), &P_temp);
+ P_temp = T * P_temp;
+ ProjectionShiftPrincipalPoint(P_temp, Vec2(0,0), principal_point, P_new);
+}
+
+void HomogeneousToEuclidean(const Mat &H, Mat *X) {
+ int d = H.rows() - 1;
+ int n = H.cols();
+ X->resize(d, n);
+ for (size_t i = 0; i < n; ++i) {
+ double h = H(d, i);
+ for (int j = 0; j < d; ++j) {
+ (*X)(j, i) = H(j, i) / h;
+ }
+ }
+}
+
+void HomogeneousToEuclidean(const Mat3X &h, Mat2X *e) {
+ e->resize(2, h.cols());
+ e->row(0) = h.row(0).array() / h.row(2).array();
+ e->row(1) = h.row(1).array() / h.row(2).array();
+}
+void HomogeneousToEuclidean(const Mat4X &h, Mat3X *e) {
+ e->resize(3, h.cols());
+ e->row(0) = h.row(0).array() / h.row(3).array();
+ e->row(1) = h.row(1).array() / h.row(3).array();
+ e->row(2) = h.row(2).array() / h.row(3).array();
+}
+
+void HomogeneousToEuclidean(const Vec3 &H, Vec2 *X) {
+ double w = H(2);
+ *X << H(0) / w, H(1) / w;
+}
+
+void HomogeneousToEuclidean(const Vec4 &H, Vec3 *X) {
+ double w = H(3);
+ *X << H(0) / w, H(1) / w, H(2) / w;
+}
+
+void EuclideanToHomogeneous(const Mat &X, Mat *H) {
+ int d = X.rows();
+ int n = X.cols();
+ H->resize(d + 1, n);
+ H->block(0, 0, d, n) = X;
+ H->row(d).setOnes();
+}
+
+void EuclideanToHomogeneous(const Vec2 &X, Vec3 *H) {
+ *H << X(0), X(1), 1;
+}
+
+void EuclideanToHomogeneous(const Vec3 &X, Vec4 *H) {
+ *H << X(0), X(1), X(2), 1;
+}
+
+// TODO(julien) Call conditioning.h/ApplyTransformationToPoints ?
+void EuclideanToNormalizedCamera(const Mat2X &x, const Mat3 &K, Mat2X *n) {
+ Mat3X x_image_h;
+ EuclideanToHomogeneous(x, &x_image_h);
+ Mat3X x_camera_h = K.inverse() * x_image_h;
+ HomogeneousToEuclidean(x_camera_h, n);
+}
+
+void HomogeneousToNormalizedCamera(const Mat3X &x, const Mat3 &K, Mat2X *n) {
+ Mat3X x_camera_h = K.inverse() * x;
+ HomogeneousToEuclidean(x_camera_h, n);
+}
+
+double Depth(const Mat3 &R, const Vec3 &t, const Vec3 &X) {
+ return (R*X)(2) + t(2);
+}
+
+double Depth(const Mat3 &R, const Vec3 &t, const Vec4 &X) {
+ Vec3 Xe = X.head<3>() / X(3);
+ return Depth(R, t, Xe);
+}
+
+} // namespace libmv
diff --git a/extern/libmv/libmv/multiview/projection.h b/extern/libmv/libmv/multiview/projection.h
new file mode 100644
index 00000000000..bc353b64c08
--- /dev/null
+++ b/extern/libmv/libmv/multiview/projection.h
@@ -0,0 +1,231 @@
+// Copyright (c) 2007, 2008 libmv authors.
+//
+// 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 LIBMV_MULTIVIEW_PROJECTION_H_
+#define LIBMV_MULTIVIEW_PROJECTION_H_
+
+#include "libmv/numeric/numeric.h"
+
+namespace libmv {
+
+void P_From_KRt(const Mat3 &K, const Mat3 &R, const Vec3 &t, Mat34 *P);
+void KRt_From_P(const Mat34 &P, Mat3 *K, Mat3 *R, Vec3 *t);
+
+// Applies a change of basis to the image coordinates of the projection matrix
+// so that the principal point becomes principal_point_new.
+void ProjectionShiftPrincipalPoint(const Mat34 &P,
+ const Vec2 &principal_point,
+ const Vec2 &principal_point_new,
+ Mat34 *P_new);
+
+// Applies a change of basis to the image coordinates of the projection matrix
+// so that the aspect ratio becomes aspect_ratio_new. This is done by
+// stretching the y axis. The aspect ratio is defined as the quotient between
+// the focal length of the y and the x axis.
+void ProjectionChangeAspectRatio(const Mat34 &P,
+ const Vec2 &principal_point,
+ double aspect_ratio,
+ double aspect_ratio_new,
+ Mat34 *P_new);
+
+void HomogeneousToEuclidean(const Mat &H, Mat *X);
+void HomogeneousToEuclidean(const Mat3X &h, Mat2X *e);
+void HomogeneousToEuclidean(const Mat4X &h, Mat3X *e);
+void HomogeneousToEuclidean(const Vec3 &H, Vec2 *X);
+void HomogeneousToEuclidean(const Vec4 &H, Vec3 *X);
+inline Vec2 HomogeneousToEuclidean(const Vec3 &h) {
+ return h.head<2>() / h(2);
+}
+inline Vec3 HomogeneousToEuclidean(const Vec4 &h) {
+ return h.head<3>() / h(3);
+}
+inline Mat2X HomogeneousToEuclidean(const Mat3X &h) {
+ Mat2X e(2, h.cols());
+ e.row(0) = h.row(0).array() / h.row(2).array();
+ e.row(1) = h.row(1).array() / h.row(2).array();
+ return e;
+}
+
+void EuclideanToHomogeneous(const Mat &X, Mat *H);
+inline Mat3X EuclideanToHomogeneous(const Mat2X &x) {
+ Mat3X h(3, x.cols());
+ h.block(0, 0, 2, x.cols()) = x;
+ h.row(2).setOnes();
+ return h;
+}
+inline void EuclideanToHomogeneous(const Mat2X &x, Mat3X *h) {
+ h->resize(3, x.cols());
+ h->block(0, 0, 2, x.cols()) = x;
+ h->row(2).setOnes();
+}
+inline Mat4X EuclideanToHomogeneous(const Mat3X &x) {
+ Mat4X h(4, x.cols());
+ h.block(0, 0, 3, x.cols()) = x;
+ h.row(3).setOnes();
+ return h;
+}
+inline void EuclideanToHomogeneous(const Mat3X &x, Mat4X *h) {
+ h->resize(4, x.cols());
+ h->block(0, 0, 3, x.cols()) = x;
+ h->row(3).setOnes();
+}
+void EuclideanToHomogeneous(const Vec2 &X, Vec3 *H);
+void EuclideanToHomogeneous(const Vec3 &X, Vec4 *H);
+inline Vec3 EuclideanToHomogeneous(const Vec2 &x) {
+ return Vec3(x(0), x(1), 1);
+}
+inline Vec4 EuclideanToHomogeneous(const Vec3 &x) {
+ return Vec4(x(0), x(1), x(2), 1);
+}
+// Conversion from image coordinates to normalized camera coordinates
+void EuclideanToNormalizedCamera(const Mat2X &x, const Mat3 &K, Mat2X *n);
+void HomogeneousToNormalizedCamera(const Mat3X &x, const Mat3 &K, Mat2X *n);
+
+inline Vec2 Project(const Mat34 &P, const Vec3 &X) {
+ Vec4 HX;
+ HX << X, 1.0;
+ Vec3 hx = P * HX;
+ return hx.head<2>() / hx(2);
+}
+
+inline void Project(const Mat34 &P, const Vec4 &X, Vec3 *x) {
+ *x = P * X;
+}
+
+inline void Project(const Mat34 &P, const Vec4 &X, Vec2 *x) {
+ Vec3 hx = P * X;
+ *x = hx.head<2>() / hx(2);
+}
+
+inline void Project(const Mat34 &P, const Vec3 &X, Vec3 *x) {
+ Vec4 HX;
+ HX << X, 1.0;
+ Project(P, HX, x);
+}
+
+inline void Project(const Mat34 &P, const Vec3 &X, Vec2 *x) {
+ Vec3 hx;
+ Project(P, X, x);
+ *x = hx.head<2>() / hx(2);
+}
+
+inline void Project(const Mat34 &P, const Mat4X &X, Mat2X *x) {
+ x->resize(2, X.cols());
+ for (int c = 0; c < X.cols(); ++c) {
+ Vec3 hx = P * X.col(c);
+ x->col(c) = hx.head<2>() / hx(2);
+ }
+}
+
+inline Mat2X Project(const Mat34 &P, const Mat4X &X) {
+ Mat2X x;
+ Project(P, X, &x);
+ return x;
+}
+
+inline void Project(const Mat34 &P, const Mat3X &X, Mat2X *x) {
+ x->resize(2, X.cols());
+ for (int c = 0; c < X.cols(); ++c) {
+ Vec4 HX;
+ HX << X.col(c), 1.0;
+ Vec3 hx = P * HX;
+ x->col(c) = hx.head<2>() / hx(2);
+ }
+}
+
+inline void Project(const Mat34 &P, const Mat3X &X, const Vecu &ids, Mat2X *x) {
+ x->resize(2, ids.size());
+ Vec4 HX;
+ Vec3 hx;
+ for (int c = 0; c < ids.size(); ++c) {
+ HX << X.col(ids[c]), 1.0;
+ hx = P * HX;
+ x->col(c) = hx.head<2>() / hx(2);
+ }
+}
+
+inline Mat2X Project(const Mat34 &P, const Mat3X &X) {
+ Mat2X x(2, X.cols());
+ Project(P, X, &x);
+ return x;
+}
+
+inline Mat2X Project(const Mat34 &P, const Mat3X &X, const Vecu &ids) {
+ Mat2X x(2, ids.size());
+ Project(P, X, ids, &x);
+ return x;
+}
+
+double Depth(const Mat3 &R, const Vec3 &t, const Vec3 &X);
+double Depth(const Mat3 &R, const Vec3 &t, const Vec4 &X);
+
+/**
+* Returns true if the homogenious 3D point X is in front of
+* the camera P.
+*/
+inline bool isInFrontOfCamera(const Mat34 &P, const Vec4 &X){
+ double condition_1 = P.row(2).dot(X) * X[3];
+ double condition_2 = X[2] * X[3];
+ if( condition_1 > 0 && condition_2 > 0 )
+ return true;
+ else
+ return false;
+}
+
+inline bool isInFrontOfCamera(const Mat34 &P, const Vec3 &X){
+ Vec4 X_homo;
+ X_homo.segment<3>(0) = X;
+ X_homo(3) = 1;
+ return isInFrontOfCamera( P, X_homo);
+}
+
+/**
+* Transforms a 2D point from pixel image coordinates to a 2D point in
+* normalized image coordinates.
+*/
+inline Vec2 ImageToNormImageCoordinates(Mat3 &Kinverse, Vec2 &x){
+ Vec3 x_h = Kinverse*EuclideanToHomogeneous(x);
+ return HomogeneousToEuclidean( x_h );
+}
+
+/// Estimates the root mean square error (2D)
+inline double RootMeanSquareError(const Mat2X &x_image,
+ const Mat4X &X_world,
+ const Mat34 &P) {
+ size_t num_points = x_image.cols();
+ Mat2X dx = Project(P, X_world) - x_image;
+ return dx.norm() / num_points;
+}
+
+/// Estimates the root mean square error (2D)
+inline double RootMeanSquareError(const Mat2X &x_image,
+ const Mat3X &X_world,
+ const Mat3 &K,
+ const Mat3 &R,
+ const Vec3 &t) {
+ Mat34 P;
+ P_From_KRt(K, R, t, &P);
+ size_t num_points = x_image.cols();
+ Mat2X dx = Project(P, X_world) - x_image;
+ return dx.norm() / num_points;
+}
+} // namespace libmv
+
+#endif // LIBMV_MULTIVIEW_PROJECTION_H_
diff --git a/extern/libmv/libmv/multiview/resection.h b/extern/libmv/libmv/multiview/resection.h
new file mode 100644
index 00000000000..e4623899147
--- /dev/null
+++ b/extern/libmv/libmv/multiview/resection.h
@@ -0,0 +1,62 @@
+// Copyright (c) 2009 libmv authors.
+//
+// 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.
+//
+// Compute the projection matrix from a set of 3D points X and their
+// projections x = PX in 2D. This is useful if a point cloud is reconstructed.
+//
+// Algorithm is the standard DLT as described in Hartley & Zisserman, page 179.
+
+#ifndef LIBMV_MULTIVIEW_RESECTION_H
+#define LIBMV_MULTIVIEW_RESECTION_H
+
+#include "libmv/logging/logging.h"
+#include "libmv/numeric/numeric.h"
+
+namespace libmv {
+namespace resection {
+
+// x's are 2D image coordinates, (x,y,1), and X's are homogeneous four vectors.
+template<typename T>
+void Resection(const Matrix<T, 2, Dynamic> &x,
+ const Matrix<T, 4, Dynamic> &X,
+ Matrix<T, 3, 4> *P) {
+ int N = x.cols();
+ assert(X.cols() == N);
+
+ Matrix<T, Dynamic, 12> design(2*N, 12);
+ design.setZero();
+ for (int i = 0; i < N; i++) {
+ T xi = x(0, i);
+ T yi = x(1, i);
+ // See equation (7.2) on page 179 of H&Z.
+ design.template block<1,4>(2*i, 4) = -X.col(i).transpose();
+ design.template block<1,4>(2*i, 8) = yi*X.col(i).transpose();
+ design.template block<1,4>(2*i + 1, 0) = X.col(i).transpose();
+ design.template block<1,4>(2*i + 1, 8) = -xi*X.col(i).transpose();
+ }
+ Matrix<T, 12, 1> p;
+ Nullspace(&design, &p);
+ reshape(p, 3, 4, P);
+}
+
+} // namespace resection
+} // namespace libmv
+
+#endif // LIBMV_MULTIVIEW_RESECTION_H
diff --git a/extern/libmv/libmv/multiview/triangulation.cc b/extern/libmv/libmv/multiview/triangulation.cc
new file mode 100644
index 00000000000..b9d38cef936
--- /dev/null
+++ b/extern/libmv/libmv/multiview/triangulation.cc
@@ -0,0 +1,49 @@
+// Copyright (c) 2007, 2008 libmv authors.
+//
+// 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 "libmv/numeric/numeric.h"
+#include "libmv/multiview/projection.h"
+#include "libmv/multiview/triangulation.h"
+
+namespace libmv {
+
+// HZ 12.2 pag.312
+void TriangulateDLT(const Mat34 &P1, const Vec2 &x1,
+ const Mat34 &P2, const Vec2 &x2,
+ Vec4 *X_homogeneous) {
+ Mat4 design;
+ for (int i = 0; i < 4; ++i) {
+ design(0,i) = x1(0) * P1(2,i) - P1(0,i);
+ design(1,i) = x1(1) * P1(2,i) - P1(1,i);
+ design(2,i) = x2(0) * P2(2,i) - P2(0,i);
+ design(3,i) = x2(1) * P2(2,i) - P2(1,i);
+ }
+ Nullspace(&design, X_homogeneous);
+}
+
+void TriangulateDLT(const Mat34 &P1, const Vec2 &x1,
+ const Mat34 &P2, const Vec2 &x2,
+ Vec3 *X_euclidean) {
+ Vec4 X_homogeneous;
+ TriangulateDLT(P1, x1, P2, x2, &X_homogeneous);
+ HomogeneousToEuclidean(X_homogeneous, X_euclidean);
+}
+
+} // namespace libmv
diff --git a/extern/libmv/libmv/multiview/triangulation.h b/extern/libmv/libmv/multiview/triangulation.h
new file mode 100644
index 00000000000..c35774d9e1b
--- /dev/null
+++ b/extern/libmv/libmv/multiview/triangulation.h
@@ -0,0 +1,38 @@
+// Copyright (c) 2007, 2008 libmv authors.
+//
+// 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 LIBMV_MULTIVIEW_TRIANGULATION_H_
+#define LIBMV_MULTIVIEW_TRIANGULATION_H_
+
+#include "libmv/numeric/numeric.h"
+
+namespace libmv {
+
+void TriangulateDLT(const Mat34 &P1, const Vec2 &x1,
+ const Mat34 &P2, const Vec2 &x2,
+ Vec4 *X_homogeneous);
+
+void TriangulateDLT(const Mat34 &P1, const Vec2 &x1,
+ const Mat34 &P2, const Vec2 &x2,
+ Vec3 *X_euclidean);
+
+} // namespace libmv
+
+#endif // LIBMV_MULTIVIEW_TRIANGULATION_H_
diff --git a/extern/libmv/libmv/numeric/dogleg.h b/extern/libmv/libmv/numeric/dogleg.h
new file mode 100644
index 00000000000..f05882c1191
--- /dev/null
+++ b/extern/libmv/libmv/numeric/dogleg.h
@@ -0,0 +1,261 @@
+// Copyright (c) 2007, 2008, 2009 libmv authors.
+//
+// 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.
+//
+// A simple implementation of Powell's dogleg nonlinear minimization.
+//
+// [1] K. Madsen, H. Nielsen, O. Tingleoff. Methods for Non-linear Least
+// Squares Problems.
+// http://www2.imm.dtu.dk/pubdb/views/edoc_download.php/3215/pdf/imm3215.pdf
+//
+// TODO(keir): Cite the Lourakis' dogleg paper.
+
+#ifndef LIBMV_NUMERIC_DOGLEG_H
+#define LIBMV_NUMERIC_DOGLEG_H
+
+#include <cmath>
+#include <cstdio>
+
+#include "libmv/numeric/numeric.h"
+#include "libmv/numeric/function_derivative.h"
+#include "libmv/logging/logging.h"
+
+namespace libmv {
+
+template<typename Function,
+ typename Jacobian = NumericJacobian<Function>,
+ typename Solver = Eigen::PartialPivLU<
+ Matrix<typename Function::FMatrixType::RealScalar,
+ Function::XMatrixType::RowsAtCompileTime,
+ Function::XMatrixType::RowsAtCompileTime> > >
+class Dogleg {
+ public:
+ typedef typename Function::XMatrixType::RealScalar Scalar;
+ typedef typename Function::FMatrixType FVec;
+ typedef typename Function::XMatrixType Parameters;
+ typedef Matrix<typename Function::FMatrixType::RealScalar,
+ Function::FMatrixType::RowsAtCompileTime,
+ Function::XMatrixType::RowsAtCompileTime> JMatrixType;
+ typedef Matrix<typename JMatrixType::RealScalar,
+ JMatrixType::ColsAtCompileTime,
+ JMatrixType::ColsAtCompileTime> AMatrixType;
+
+ enum Status {
+ RUNNING,
+ GRADIENT_TOO_SMALL, // eps > max(J'*f(x))
+ RELATIVE_STEP_SIZE_TOO_SMALL, // eps > ||dx|| / ||x||
+ TRUST_REGION_TOO_SMALL, // eps > radius / ||x||
+ ERROR_TOO_SMALL, // eps > ||f(x)||
+ HIT_MAX_ITERATIONS,
+ };
+
+ enum Step {
+ DOGLEG,
+ GAUSS_NEWTON,
+ STEEPEST_DESCENT,
+ };
+
+ Dogleg(const Function &f)
+ : f_(f), df_(f) {}
+
+ struct SolverParameters {
+ SolverParameters()
+ : gradient_threshold(1e-16),
+ relative_step_threshold(1e-16),
+ error_threshold(1e-16),
+ initial_trust_radius(1e0),
+ max_iterations(500) {}
+ Scalar gradient_threshold; // eps > max(J'*f(x))
+ Scalar relative_step_threshold; // eps > ||dx|| / ||x||
+ Scalar error_threshold; // eps > ||f(x)||
+ Scalar initial_trust_radius; // Initial u for solving normal equations.
+ int max_iterations; // Maximum number of solver iterations.
+ };
+
+ struct Results {
+ Scalar error_magnitude; // ||f(x)||
+ Scalar gradient_magnitude; // ||J'f(x)||
+ int iterations;
+ Status status;
+ };
+
+ Status Update(const Parameters &x, const SolverParameters &params,
+ JMatrixType *J, AMatrixType *A, FVec *error, Parameters *g) {
+ *J = df_(x);
+ // TODO(keir): In the case of m = n, avoid computing A and just do J^-1 directly.
+ *A = (*J).transpose() * (*J);
+ *error = f_(x);
+ *g = (*J).transpose() * *error;
+ if (g->array().abs().maxCoeff() < params.gradient_threshold) {
+ return GRADIENT_TOO_SMALL;
+ } else if (error->array().abs().maxCoeff() < params.error_threshold) {
+ return ERROR_TOO_SMALL;
+ }
+ return RUNNING;
+ }
+
+ Step SolveDoglegDirection(const Parameters &dx_sd,
+ const Parameters &dx_gn,
+ Scalar radius,
+ Scalar alpha,
+ Parameters *dx_dl,
+ Scalar *beta) {
+ Parameters a, b_minus_a;
+ // Solve for Dogleg step dx_dl.
+ if (dx_gn.norm() < radius) {
+ *dx_dl = dx_gn;
+ return GAUSS_NEWTON;
+
+ } else if (alpha * dx_sd.norm() > radius) {
+ *dx_dl = (radius / dx_sd.norm()) * dx_sd;
+ return STEEPEST_DESCENT;
+
+ } else {
+ Parameters a = alpha * dx_sd;
+ const Parameters &b = dx_gn;
+ b_minus_a = a - b;
+ Scalar Mbma2 = b_minus_a.squaredNorm();
+ Scalar Ma2 = a.squaredNorm();
+ Scalar c = a.dot(b_minus_a);
+ Scalar radius2 = radius*radius;
+ if (c <= 0) {
+ *beta = (-c + sqrt(c*c + Mbma2*(radius2 - Ma2)))/(Mbma2);
+ } else {
+ *beta = (radius2 - Ma2) /
+ (c + sqrt(c*c + Mbma2*(radius2 - Ma2)));
+ }
+ *dx_dl = alpha * dx_sd + (*beta) * (dx_gn - alpha*dx_sd);
+ return DOGLEG;
+ }
+ }
+
+ Results minimize(Parameters *x_and_min) {
+ SolverParameters params;
+ return minimize(params, x_and_min);
+ }
+
+ Results minimize(const SolverParameters &params, Parameters *x_and_min) {
+ Parameters &x = *x_and_min;
+ JMatrixType J;
+ AMatrixType A;
+ FVec error;
+ Parameters g;
+
+ Results results;
+ results.status = Update(x, params, &J, &A, &error, &g);
+
+ Scalar radius = params.initial_trust_radius;
+ bool x_updated = true;
+
+ Parameters x_new;
+ Parameters dx_sd; // Steepest descent step.
+ Parameters dx_dl; // Dogleg step.
+ Parameters dx_gn; // Gauss-Newton step.
+ printf("iteration ||f(x)|| max(g) radius\n");
+ int i = 0;
+ for (; results.status == RUNNING && i < params.max_iterations; ++i) {
+ printf("%9d %12g %12g %12g",
+ i, f_(x).norm(), g.array().abs().maxCoeff(), radius);
+
+ //LG << "iteration: " << i;
+ //LG << "||f(x)||: " << f_(x).norm();
+ //LG << "max(g): " << g.cwise().abs().maxCoeff();
+ //LG << "radius: " << radius;
+ // Eqn 3.19 from [1]
+ Scalar alpha = g.squaredNorm() / (J*g).squaredNorm();
+
+ // Solve for steepest descent direction dx_sd.
+ dx_sd = -g;
+
+ // Solve for Gauss-Newton direction dx_gn.
+ if (x_updated) {
+ // TODO(keir): See Appendix B of [1] for discussion of when A is
+ // singular and there are many solutions. Solving that involves the SVD
+ // and is slower, but should still work.
+ Solver solver(A);
+ dx_gn = solver.solve(-g);
+ if (!(A * dx_gn).isApprox(-g)) {
+ LOG(ERROR) << "Failed to solve normal eqns. TODO: Solve via SVD.";
+ return results;
+ }
+ x_updated = false;
+ }
+
+ // Solve for dogleg direction dx_dl.
+ Scalar beta = 0;
+ Step step = SolveDoglegDirection(dx_sd, dx_gn, radius, alpha,
+ &dx_dl, &beta);
+
+ Scalar e3 = params.relative_step_threshold;
+ if (dx_dl.norm() < e3*(x.norm() + e3)) {
+ results.status = RELATIVE_STEP_SIZE_TOO_SMALL;
+ break;
+ }
+
+ x_new = x + dx_dl;
+ Scalar actual = f_(x).squaredNorm() - f_(x_new).squaredNorm();
+ Scalar predicted = 0;
+ if (step == GAUSS_NEWTON) {
+ predicted = f_(x).squaredNorm();
+ } else if (step == STEEPEST_DESCENT) {
+ predicted = radius * (2*alpha*g.norm() - radius) / 2 / alpha;
+ } else if (step == DOGLEG) {
+ predicted = 0.5 * alpha * (1-beta)*(1-beta)*g.squaredNorm() +
+ beta*(2-beta)*f_(x).squaredNorm();
+ }
+ Scalar rho = actual / predicted;
+
+ if (step == GAUSS_NEWTON) printf(" GAUSS");
+ if (step == STEEPEST_DESCENT) printf(" STEE");
+ if (step == DOGLEG) printf(" DOGL");
+
+ printf(" %12g %12g %12g\n", rho, actual, predicted);
+
+ if (rho > 0) {
+ // Accept update because the linear model is a good fit.
+ x = x_new;
+ results.status = Update(x, params, &J, &A, &error, &g);
+ x_updated = true;
+ }
+ if (rho > 0.75) {
+ radius = std::max(radius, 3*dx_dl.norm());
+ } else if (rho < 0.25) {
+ radius /= 2;
+ if (radius < e3 * (x.norm() + e3)) {
+ results.status = TRUST_REGION_TOO_SMALL;
+ }
+ }
+ }
+ if (results.status == RUNNING) {
+ results.status = HIT_MAX_ITERATIONS;
+ }
+ results.error_magnitude = error.norm();
+ results.gradient_magnitude = g.norm();
+ results.iterations = i;
+ return results;
+ }
+
+ private:
+ const Function &f_;
+ Jacobian df_;
+};
+
+} // namespace mv
+
+#endif // LIBMV_NUMERIC_DOGLEG_H
diff --git a/extern/libmv/libmv/numeric/function_derivative.h b/extern/libmv/libmv/numeric/function_derivative.h
new file mode 100644
index 00000000000..d7bc437b2e0
--- /dev/null
+++ b/extern/libmv/libmv/numeric/function_derivative.h
@@ -0,0 +1,107 @@
+// Copyright (c) 2007, 2008, 2009 libmv authors.
+//
+// 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 LIBMV_NUMERIC_DERIVATIVE_H
+#define LIBMV_NUMERIC_DERIVATIVE_H
+
+#include <cmath>
+
+#include "libmv/numeric/numeric.h"
+#include "libmv/logging/logging.h"
+
+namespace libmv {
+
+// Numeric derivative of a function.
+// TODO(keir): Consider adding a quadratic approximation.
+
+enum NumericJacobianMode {
+ CENTRAL,
+ FORWARD,
+};
+
+template<typename Function, NumericJacobianMode mode=CENTRAL>
+class NumericJacobian {
+ public:
+ typedef typename Function::XMatrixType Parameters;
+ typedef typename Function::XMatrixType::RealScalar XScalar;
+ typedef typename Function::FMatrixType FMatrixType;
+ typedef Matrix<typename Function::FMatrixType::RealScalar,
+ Function::FMatrixType::RowsAtCompileTime,
+ Function::XMatrixType::RowsAtCompileTime>
+ JMatrixType;
+
+ NumericJacobian(const Function &f) : f_(f) {}
+
+ // TODO(keir): Perhaps passing the jacobian back by value is not a good idea.
+ JMatrixType operator()(const Parameters &x) {
+ // Empirically determined constant.
+ Parameters eps = x.array().abs() * XScalar(1e-5);
+ // To handle cases where a paremeter is exactly zero, instead use the mean
+ // eps for the other dimensions.
+ XScalar mean_eps = eps.sum() / eps.rows();
+ if (mean_eps == XScalar(0)) {
+ // TODO(keir): Do something better here.
+ mean_eps = 1e-8; // ~sqrt(machine precision).
+ }
+ // TODO(keir): Elimininate this needless function evaluation for the
+ // central difference case.
+ FMatrixType fx = f_(x);
+ const int rows = fx.rows();
+ const int cols = x.rows();
+ JMatrixType jacobian(rows, cols);
+ Parameters x_plus_delta = x;
+ for (int c = 0; c < cols; ++c) {
+ if (eps(c) == XScalar(0)) {
+ eps(c) = mean_eps;
+ }
+ x_plus_delta(c) = x(c) + eps(c);
+ jacobian.col(c) = f_(x_plus_delta);
+
+ XScalar one_over_h = 1 / eps(c);
+ if (mode == CENTRAL) {
+ x_plus_delta(c) = x(c) - eps(c);
+ jacobian.col(c) -= f_(x_plus_delta);
+ one_over_h /= 2;
+ } else {
+ jacobian.col(c) -= fx;
+ }
+ x_plus_delta(c) = x(c);
+ jacobian.col(c) = jacobian.col(c) * one_over_h;
+ }
+ return jacobian;
+ }
+ private:
+ const Function &f_;
+};
+
+template<typename Function, typename Jacobian>
+bool CheckJacobian(const Function &f, const typename Function::XMatrixType &x) {
+ Jacobian j_analytic(f);
+ NumericJacobian<Function> j_numeric(f);
+
+ typename NumericJacobian<Function>::JMatrixType J_numeric = j_numeric(x);
+ typename NumericJacobian<Function>::JMatrixType J_analytic = j_analytic(x);
+ LG << J_numeric - J_analytic;
+ return true;
+}
+
+} // namespace libmv
+
+#endif // LIBMV_NUMERIC_DERIVATIVE_H
diff --git a/extern/libmv/libmv/numeric/levenberg_marquardt.h b/extern/libmv/libmv/numeric/levenberg_marquardt.h
new file mode 100644
index 00000000000..4473b72f156
--- /dev/null
+++ b/extern/libmv/libmv/numeric/levenberg_marquardt.h
@@ -0,0 +1,183 @@
+// Copyright (c) 2007, 2008, 2009 libmv authors.
+//
+// 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.
+//
+// A simple implementation of levenberg marquardt.
+//
+// [1] K. Madsen, H. Nielsen, O. Tingleoff. Methods for Non-linear Least
+// Squares Problems.
+// http://www2.imm.dtu.dk/pubdb/views/edoc_download.php/3215/pdf/imm3215.pdf
+//
+// TODO(keir): Cite the Lourakis' dogleg paper.
+
+#ifndef LIBMV_NUMERIC_LEVENBERG_MARQUARDT_H
+#define LIBMV_NUMERIC_LEVENBERG_MARQUARDT_H
+
+#include <cmath>
+
+#include "libmv/numeric/numeric.h"
+#include "libmv/numeric/function_derivative.h"
+#include "libmv/logging/logging.h"
+
+namespace libmv {
+
+template<typename Function,
+ typename Jacobian = NumericJacobian<Function>,
+ typename Solver = Eigen::PartialPivLU<
+ Matrix<typename Function::FMatrixType::RealScalar,
+ Function::XMatrixType::RowsAtCompileTime,
+ Function::XMatrixType::RowsAtCompileTime> > >
+class LevenbergMarquardt {
+ public:
+ typedef typename Function::XMatrixType::RealScalar Scalar;
+ typedef typename Function::FMatrixType FVec;
+ typedef typename Function::XMatrixType Parameters;
+ typedef Matrix<typename Function::FMatrixType::RealScalar,
+ Function::FMatrixType::RowsAtCompileTime,
+ Function::XMatrixType::RowsAtCompileTime> JMatrixType;
+ typedef Matrix<typename JMatrixType::RealScalar,
+ JMatrixType::ColsAtCompileTime,
+ JMatrixType::ColsAtCompileTime> AMatrixType;
+
+ // TODO(keir): Some of these knobs can be derived from each other and
+ // removed, instead of requiring the user to set them.
+ enum Status {
+ RUNNING,
+ GRADIENT_TOO_SMALL, // eps > max(J'*f(x))
+ RELATIVE_STEP_SIZE_TOO_SMALL, // eps > ||dx|| / ||x||
+ ERROR_TOO_SMALL, // eps > ||f(x)||
+ HIT_MAX_ITERATIONS,
+ };
+
+ LevenbergMarquardt(const Function &f)
+ : f_(f), df_(f) {}
+
+ struct SolverParameters {
+ SolverParameters()
+ : gradient_threshold(1e-16),
+ relative_step_threshold(1e-16),
+ error_threshold(1e-16),
+ initial_scale_factor(1e-3),
+ max_iterations(100) {}
+ Scalar gradient_threshold; // eps > max(J'*f(x))
+ Scalar relative_step_threshold; // eps > ||dx|| / ||x||
+ Scalar error_threshold; // eps > ||f(x)||
+ Scalar initial_scale_factor; // Initial u for solving normal equations.
+ int max_iterations; // Maximum number of solver iterations.
+ };
+
+ struct Results {
+ Scalar error_magnitude; // ||f(x)||
+ Scalar gradient_magnitude; // ||J'f(x)||
+ int iterations;
+ Status status;
+ };
+
+ Status Update(const Parameters &x, const SolverParameters &params,
+ JMatrixType *J, AMatrixType *A, FVec *error, Parameters *g) {
+ *J = df_(x);
+ *A = (*J).transpose() * (*J);
+ *error = -f_(x);
+ *g = (*J).transpose() * *error;
+ if (g->array().abs().maxCoeff() < params.gradient_threshold) {
+ return GRADIENT_TOO_SMALL;
+ } else if (error->norm() < params.error_threshold) {
+ return ERROR_TOO_SMALL;
+ }
+ return RUNNING;
+ }
+
+ Results minimize(Parameters *x_and_min) {
+ SolverParameters params;
+ minimize(params, x_and_min);
+ }
+
+ Results minimize(const SolverParameters &params, Parameters *x_and_min) {
+ Parameters &x = *x_and_min;
+ JMatrixType J;
+ AMatrixType A;
+ FVec error;
+ Parameters g;
+
+ Results results;
+ results.status = Update(x, params, &J, &A, &error, &g);
+
+ Scalar u = Scalar(params.initial_scale_factor*A.diagonal().maxCoeff());
+ Scalar v = 2;
+
+ Parameters dx, x_new;
+ int i;
+ for (i = 0; results.status == RUNNING && i < params.max_iterations; ++i) {
+ VLOG(1) << "iteration: " << i;
+ VLOG(1) << "||f(x)||: " << f_(x).norm();
+ VLOG(1) << "max(g): " << g.array().abs().maxCoeff();
+ VLOG(1) << "u: " << u;
+ VLOG(1) << "v: " << v;
+
+ AMatrixType A_augmented = A + u*AMatrixType::Identity(J.cols(), J.cols());
+ Solver solver(A_augmented);
+ dx = solver.solve(g);
+ bool solved = (A_augmented * dx).isApprox(g);
+ if (!solved) {
+ LOG(ERROR) << "Failed to solve";
+ }
+ if (solved && dx.norm() <= params.relative_step_threshold * x.norm()) {
+ results.status = RELATIVE_STEP_SIZE_TOO_SMALL;
+ break;
+ }
+ if (solved) {
+ x_new = x + dx;
+ // Rho is the ratio of the actual reduction in error to the reduction
+ // in error that would be obtained if the problem was linear.
+ // See [1] for details.
+ Scalar rho((error.squaredNorm() - f_(x_new).squaredNorm())
+ / dx.dot(u*dx + g));
+ if (rho > 0) {
+ // Accept the Gauss-Newton step because the linear model fits well.
+ x = x_new;
+ results.status = Update(x, params, &J, &A, &error, &g);
+ Scalar tmp = Scalar(2*rho-1);
+ u = u*std::max(1/3., 1 - (tmp*tmp*tmp));
+ v = 2;
+ continue;
+ }
+ }
+ // Reject the update because either the normal equations failed to solve
+ // or the local linear model was not good (rho < 0). Instead, increase u
+ // to move closer to gradient descent.
+ u *= v;
+ v *= 2;
+ }
+ if (results.status == RUNNING) {
+ results.status = HIT_MAX_ITERATIONS;
+ }
+ results.error_magnitude = error.norm();
+ results.gradient_magnitude = g.norm();
+ results.iterations = i;
+ return results;
+ }
+
+ private:
+ const Function &f_;
+ Jacobian df_;
+};
+
+} // namespace mv
+
+#endif // LIBMV_NUMERIC_LEVENBERG_MARQUARDT_H
diff --git a/extern/libmv/libmv/numeric/numeric.cc b/extern/libmv/libmv/numeric/numeric.cc
new file mode 100644
index 00000000000..0ca3a64e4f4
--- /dev/null
+++ b/extern/libmv/libmv/numeric/numeric.cc
@@ -0,0 +1,136 @@
+// Copyright (c) 2007, 2008 libmv authors.
+//
+// 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 "libmv/numeric/numeric.h"
+
+namespace libmv {
+
+Mat3 RotationAroundX(double angle) {
+ double c, s;
+ sincos(angle, &s, &c);
+ Mat3 R;
+ R << 1, 0, 0,
+ 0, c, -s,
+ 0, s, c;
+ return R;
+}
+
+Mat3 RotationAroundY(double angle) {
+ double c, s;
+ sincos(angle, &s, &c);
+ Mat3 R;
+ R << c, 0, s,
+ 0, 1, 0,
+ -s, 0, c;
+ return R;
+}
+
+Mat3 RotationAroundZ(double angle) {
+ double c, s;
+ sincos(angle, &s, &c);
+ Mat3 R;
+ R << c, -s, 0,
+ s, c, 0,
+ 0, 0, 1;
+ return R;
+}
+
+
+Mat3 RotationRodrigues(const Vec3 &axis) {
+ double theta = axis.norm();
+ Vec3 w = axis / theta;
+ Mat3 W = CrossProductMatrix(w);
+
+ return Mat3::Identity() + sin(theta) * W + (1 - cos(theta)) * W * W;
+}
+
+
+Mat3 LookAt(Vec3 center) {
+ Vec3 zc = center.normalized();
+ Vec3 xc = Vec3::UnitY().cross(zc).normalized();
+ Vec3 yc = zc.cross(xc);
+ Mat3 R;
+ R.row(0) = xc;
+ R.row(1) = yc;
+ R.row(2) = zc;
+ return R;
+}
+
+Mat3 CrossProductMatrix(const Vec3 &x) {
+ Mat3 X;
+ X << 0, -x(2), x(1),
+ x(2), 0, -x(0),
+ -x(1), x(0), 0;
+ return X;
+}
+
+void MeanAndVarianceAlongRows(const Mat &A,
+ Vec *mean_pointer,
+ Vec *variance_pointer) {
+ Vec &mean = *mean_pointer;
+ Vec &variance = *variance_pointer;
+ int n = A.rows();
+ int m = A.cols();
+ mean.resize(n);
+ variance.resize(n);
+
+ for (int i = 0; i < n; ++i) {
+ mean(i) = 0;
+ variance(i) = 0;
+ for (int j = 0; j < m; ++j) {
+ double x = A(i, j);
+ mean(i) += x;
+ variance(i) += x * x;
+ }
+ }
+
+ mean /= m;
+ for (int i = 0; i < n; ++i) {
+ variance(i) = variance(i) / m - Square(mean(i));
+ }
+}
+
+void HorizontalStack(const Mat &left, const Mat &right, Mat *stacked) {
+ assert(left.rows() == left.rows());
+ int n = left.rows();
+ int m1 = left.cols();
+ int m2 = right.cols();
+
+ stacked->resize(n, m1 + m2);
+ stacked->block(0, 0, n, m1) = left;
+ stacked->block(0, m1, n, m2) = right;
+}
+
+void MatrixColumn(const Mat &A, int i, Vec2 *v) {
+ assert(A.rows() == 2);
+ *v << A(0,i), A(1,i);
+}
+void MatrixColumn(const Mat &A, int i, Vec3 *v) {
+ assert(A.rows() == 3);
+ *v << A(0,i), A(1,i), A(2,i);
+}
+void MatrixColumn(const Mat &A, int i, Vec4 *v) {
+ assert(A.rows() == 4);
+ *v << A(0,i), A(1,i), A(2,i), A(3,i);
+}
+
+} // namespace libmv
+
diff --git a/extern/libmv/libmv/numeric/numeric.h b/extern/libmv/libmv/numeric/numeric.h
new file mode 100644
index 00000000000..21e0f067446
--- /dev/null
+++ b/extern/libmv/libmv/numeric/numeric.h
@@ -0,0 +1,479 @@
+// Copyright (c) 2007, 2008 libmv authors.
+//
+// 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.
+//
+// Matrix and vector classes, based on Eigen2.
+//
+// Avoid using Eigen2 classes directly; instead typedef them here.
+
+#ifndef LIBMV_NUMERIC_NUMERIC_H
+#define LIBMV_NUMERIC_NUMERIC_H
+
+#include <Eigen/Cholesky>
+#include <Eigen/Core>
+#include <Eigen/Eigenvalues>
+#include <Eigen/Geometry>
+#include <Eigen/LU>
+#include <Eigen/QR>
+#include <Eigen/SVD>
+
+#if _WIN32 || __APPLE__
+ void static sincos (double x, double *sinx, double *cosx) {
+ *sinx = sin(x);
+ *cosx = cos(x);
+ }
+#endif //_WIN32 || __APPLE__
+
+#if (defined(WIN32) || defined(WIN64)) && !defined(__MINGW32__)
+ inline long lround(double d) {
+ return (long)(d>0 ? d+0.5 : ceil(d-0.5));
+ }
+ inline int round(double d) {
+ return (d>0) ? int(d+0.5) : int(d-0.5);
+ }
+ typedef unsigned int uint;
+#endif //_WIN32
+
+namespace libmv {
+
+typedef Eigen::MatrixXd Mat;
+typedef Eigen::VectorXd Vec;
+
+typedef Eigen::MatrixXf Matf;
+typedef Eigen::VectorXf Vecf;
+
+typedef Eigen::Matrix<unsigned int, Eigen::Dynamic, Eigen::Dynamic> Matu;
+typedef Eigen::Matrix<unsigned int, Eigen::Dynamic, 1> Vecu;
+typedef Eigen::Matrix<unsigned int, 2, 1> Vec2u;
+
+typedef Eigen::Matrix<double, 2, 2> Mat2;
+typedef Eigen::Matrix<double, 2, 3> Mat23;
+typedef Eigen::Matrix<double, 3, 3> Mat3;
+typedef Eigen::Matrix<double, 3, 4> Mat34;
+typedef Eigen::Matrix<double, 3, 5> Mat35;
+typedef Eigen::Matrix<double, 4, 1> Mat41;
+typedef Eigen::Matrix<double, 4, 3> Mat43;
+typedef Eigen::Matrix<double, 4, 4> Mat4;
+typedef Eigen::Matrix<double, 4, 6> Mat46;
+typedef Eigen::Matrix<float, 2, 2> Mat2f;
+typedef Eigen::Matrix<float, 2, 3> Mat23f;
+typedef Eigen::Matrix<float, 3, 3> Mat3f;
+typedef Eigen::Matrix<float, 3, 4> Mat34f;
+typedef Eigen::Matrix<float, 3, 5> Mat35f;
+typedef Eigen::Matrix<float, 4, 3> Mat43f;
+typedef Eigen::Matrix<float, 4, 4> Mat4f;
+typedef Eigen::Matrix<float, 4, 6> Mat46f;
+
+typedef Eigen::Matrix<double, 3, 3, Eigen::RowMajor> RMat3;
+typedef Eigen::Matrix<double, 4, 4, Eigen::RowMajor> RMat4;
+
+typedef Eigen::Matrix<double, 2, Eigen::Dynamic> Mat2X;
+typedef Eigen::Matrix<double, 3, Eigen::Dynamic> Mat3X;
+typedef Eigen::Matrix<double, 4, Eigen::Dynamic> Mat4X;
+typedef Eigen::Matrix<double, Eigen::Dynamic, 2> MatX2;
+typedef Eigen::Matrix<double, Eigen::Dynamic, 3> MatX3;
+typedef Eigen::Matrix<double, Eigen::Dynamic, 4> MatX4;
+typedef Eigen::Matrix<double, Eigen::Dynamic, 5> MatX5;
+typedef Eigen::Matrix<double, Eigen::Dynamic, 6> MatX6;
+typedef Eigen::Matrix<double, Eigen::Dynamic, 7> MatX7;
+typedef Eigen::Matrix<double, Eigen::Dynamic, 8> MatX8;
+typedef Eigen::Matrix<double, Eigen::Dynamic, 9> MatX9;
+typedef Eigen::Matrix<double, Eigen::Dynamic,15> MatX15;
+typedef Eigen::Matrix<double, Eigen::Dynamic,16> MatX16;
+
+typedef Eigen::Vector2d Vec2;
+typedef Eigen::Vector3d Vec3;
+typedef Eigen::Vector4d Vec4;
+typedef Eigen::Matrix<double, 5, 1> Vec5;
+typedef Eigen::Matrix<double, 6, 1> Vec6;
+typedef Eigen::Matrix<double, 7, 1> Vec7;
+typedef Eigen::Matrix<double, 8, 1> Vec8;
+typedef Eigen::Matrix<double, 9, 1> Vec9;
+typedef Eigen::Matrix<double, 10, 1> Vec10;
+typedef Eigen::Matrix<double, 11, 1> Vec11;
+typedef Eigen::Matrix<double, 12, 1> Vec12;
+typedef Eigen::Matrix<double, 13, 1> Vec13;
+typedef Eigen::Matrix<double, 14, 1> Vec14;
+typedef Eigen::Matrix<double, 15, 1> Vec15;
+typedef Eigen::Matrix<double, 16, 1> Vec16;
+typedef Eigen::Matrix<double, 17, 1> Vec17;
+typedef Eigen::Matrix<double, 18, 1> Vec18;
+typedef Eigen::Matrix<double, 19, 1> Vec19;
+typedef Eigen::Matrix<double, 20, 1> Vec20;
+
+typedef Eigen::Vector2f Vec2f;
+typedef Eigen::Vector3f Vec3f;
+typedef Eigen::Vector4f Vec4f;
+
+typedef Eigen::VectorXi VecXi;
+
+typedef Eigen::Vector2i Vec2i;
+typedef Eigen::Vector3i Vec3i;
+typedef Eigen::Vector4i Vec4i;
+
+typedef Eigen::Matrix<float,
+ Eigen::Dynamic,
+ Eigen::Dynamic,
+ Eigen::RowMajor> RMatf;
+
+typedef Eigen::NumTraits<double> EigenDouble;
+
+using Eigen::Map;
+using Eigen::Dynamic;
+using Eigen::Matrix;
+
+// Find U, s, and VT such that
+//
+// A = U * diag(s) * VT
+//
+template <typename TMat, typename TVec>
+inline void SVD(TMat *A, Vec *s, Mat *U, Mat *VT) {
+ assert(0);
+}
+
+// Solve the linear system Ax = 0 via SVD. Store the solution in x, such that
+// ||x|| = 1.0. Return the singluar value corresponding to the solution.
+// Destroys A and resizes x if necessary.
+// TODO(maclean): Take the SVD of the transpose instead of this zero padding.
+template <typename TMat, typename TVec>
+double Nullspace(TMat *A, TVec *nullspace) {
+ Eigen::JacobiSVD<TMat> svd(*A, Eigen::ComputeFullV);
+ (*nullspace) = svd.matrixV().col(A->cols()-1);
+ if (A->rows() >= A->cols())
+ return svd.singularValues()(A->cols()-1);
+ else
+ return 0.0;
+}
+
+// Solve the linear system Ax = 0 via SVD. Finds two solutions, x1 and x2, such
+// that x1 is the best solution and x2 is the next best solution (in the L2
+// norm sense). Store the solution in x1 and x2, such that ||x|| = 1.0. Return
+// the singluar value corresponding to the solution x1. Destroys A and resizes
+// x if necessary.
+template <typename TMat, typename TVec1, typename TVec2>
+double Nullspace2(TMat *A, TVec1 *x1, TVec2 *x2) {
+ Eigen::JacobiSVD<TMat> svd(*A, Eigen::ComputeFullV);
+ *x1 = svd.matrixV().col(A->cols() - 1);
+ *x2 = svd.matrixV().col(A->cols() - 2);
+ if (A->rows() >= A->cols())
+ return svd.singularValues()(A->cols()-1);
+ else
+ return 0.0;
+}
+
+// In place transpose for square matrices.
+template<class TA>
+inline void TransposeInPlace(TA *A) {
+ *A = A->transpose().eval();
+}
+
+template<typename TVec>
+inline double NormL1(const TVec &x) {
+ return x.array().abs().sum();
+}
+
+template<typename TVec>
+inline double NormL2(const TVec &x) {
+ return x.norm();
+}
+
+template<typename TVec>
+inline double NormLInfinity(const TVec &x) {
+ return x.array().abs().maxCoeff();
+}
+
+template<typename TVec>
+inline double DistanceL1(const TVec &x, const TVec &y) {
+ return (x - y).array().abs().sum();
+}
+
+template<typename TVec>
+inline double DistanceL2(const TVec &x, const TVec &y) {
+ return (x - y).norm();
+}
+template<typename TVec>
+inline double DistanceLInfinity(const TVec &x, const TVec &y) {
+ return (x - y).array().abs().maxCoeff();
+}
+
+// Normalize a vector with the L1 norm, and return the norm before it was
+// normalized.
+template<typename TVec>
+inline double NormalizeL1(TVec *x) {
+ double norm = NormL1(*x);
+ *x /= norm;
+ return norm;
+}
+
+// Normalize a vector with the L2 norm, and return the norm before it was
+// normalized.
+template<typename TVec>
+inline double NormalizeL2(TVec *x) {
+ double norm = NormL2(*x);
+ *x /= norm;
+ return norm;
+}
+
+// Normalize a vector with the L^Infinity norm, and return the norm before it
+// was normalized.
+template<typename TVec>
+inline double NormalizeLInfinity(TVec *x) {
+ double norm = NormLInfinity(*x);
+ *x /= norm;
+ return norm;
+}
+
+// Return the square of a number.
+template<typename T>
+inline T Square(T x) {
+ return x * x;
+}
+
+Mat3 RotationAroundX(double angle);
+Mat3 RotationAroundY(double angle);
+Mat3 RotationAroundZ(double angle);
+
+// Returns the rotation matrix of a rotation of angle |axis| around axis.
+// This is computed using the Rodrigues formula, see:
+// http://mathworld.wolfram.com/RodriguesRotationFormula.html
+Mat3 RotationRodrigues(const Vec3 &axis);
+
+// Make a rotation matrix such that center becomes the direction of the
+// positive z-axis, and y is oriented close to up.
+Mat3 LookAt(Vec3 center);
+
+// Return a diagonal matrix from a vector containg the diagonal values.
+template <typename TVec>
+inline Mat Diag(const TVec &x) {
+ return x.asDiagonal();
+}
+
+template<typename TMat>
+inline double FrobeniusNorm(const TMat &A) {
+ return sqrt(A.array().abs2().sum());
+}
+
+template<typename TMat>
+inline double FrobeniusDistance(const TMat &A, const TMat &B) {
+ return FrobeniusNorm(A - B);
+}
+
+inline Vec3 CrossProduct(const Vec3 &x, const Vec3 &y) {
+ return x.cross(y);
+}
+
+Mat3 CrossProductMatrix(const Vec3 &x);
+
+void MeanAndVarianceAlongRows(const Mat &A,
+ Vec *mean_pointer,
+ Vec *variance_pointer);
+
+#if _WIN32
+ // TODO(bomboze): un-#if this for both platforms once tested under Windows
+ /* This solution was extensively discussed here http://forum.kde.org/viewtopic.php?f=74&t=61940 */
+ #define SUM_OR_DYNAMIC(x,y) (x==Eigen::Dynamic||y==Eigen::Dynamic)?Eigen::Dynamic:(x+y)
+
+ template<typename Derived1, typename Derived2>
+ struct hstack_return {
+ typedef typename Derived1::Scalar Scalar;
+ enum {
+ RowsAtCompileTime = Derived1::RowsAtCompileTime,
+ ColsAtCompileTime = SUM_OR_DYNAMIC(Derived1::ColsAtCompileTime, Derived2::ColsAtCompileTime),
+ Options = Derived1::Flags&Eigen::RowMajorBit ? Eigen::RowMajor : 0,
+ MaxRowsAtCompileTime = Derived1::MaxRowsAtCompileTime,
+ MaxColsAtCompileTime = SUM_OR_DYNAMIC(Derived1::MaxColsAtCompileTime, Derived2::MaxColsAtCompileTime)
+ };
+ typedef Eigen::Matrix<Scalar,
+ RowsAtCompileTime,
+ ColsAtCompileTime,
+ Options,
+ MaxRowsAtCompileTime,
+ MaxColsAtCompileTime> type;
+ };
+
+ template<typename Derived1, typename Derived2>
+ typename hstack_return<Derived1,Derived2>::type
+ HStack (const Eigen::MatrixBase<Derived1>& lhs, const Eigen::MatrixBase<Derived2>& rhs) {
+ typename hstack_return<Derived1,Derived2>::type res;
+ res.resize(lhs.rows(), lhs.cols()+rhs.cols());
+ res << lhs, rhs;
+ return res;
+ };
+
+
+ template<typename Derived1, typename Derived2>
+ struct vstack_return {
+ typedef typename Derived1::Scalar Scalar;
+ enum {
+ RowsAtCompileTime = SUM_OR_DYNAMIC(Derived1::RowsAtCompileTime, Derived2::RowsAtCompileTime),
+ ColsAtCompileTime = Derived1::ColsAtCompileTime,
+ Options = Derived1::Flags&Eigen::RowMajorBit ? Eigen::RowMajor : 0,
+ MaxRowsAtCompileTime = SUM_OR_DYNAMIC(Derived1::MaxRowsAtCompileTime, Derived2::MaxRowsAtCompileTime),
+ MaxColsAtCompileTime = Derived1::MaxColsAtCompileTime
+ };
+ typedef Eigen::Matrix<Scalar,
+ RowsAtCompileTime,
+ ColsAtCompileTime,
+ Options,
+ MaxRowsAtCompileTime,
+ MaxColsAtCompileTime> type;
+ };
+
+ template<typename Derived1, typename Derived2>
+ typename vstack_return<Derived1,Derived2>::type
+ VStack (const Eigen::MatrixBase<Derived1>& lhs, const Eigen::MatrixBase<Derived2>& rhs) {
+ typename vstack_return<Derived1,Derived2>::type res;
+ res.resize(lhs.rows()+rhs.rows(), lhs.cols());
+ res << lhs, rhs;
+ return res;
+ };
+
+
+#else //_WIN32
+
+ // Since it is not possible to typedef privately here, use a macro.
+ // Always take dynamic columns if either side is dynamic.
+ #define COLS \
+ ((ColsLeft == Eigen::Dynamic || ColsRight == Eigen::Dynamic) \
+ ? Eigen::Dynamic : (ColsLeft + ColsRight))
+
+ // Same as above, except that prefer fixed size if either is fixed.
+ #define ROWS \
+ ((RowsLeft == Eigen::Dynamic && RowsRight == Eigen::Dynamic) \
+ ? Eigen::Dynamic \
+ : ((RowsLeft == Eigen::Dynamic) \
+ ? RowsRight \
+ : RowsLeft \
+ ) \
+ )
+
+ // TODO(keir): Add a static assert if both rows are at compiletime.
+ template<typename T, int RowsLeft, int RowsRight, int ColsLeft, int ColsRight>
+ Eigen::Matrix<T, ROWS, COLS>
+ HStack(const Eigen::Matrix<T, RowsLeft, ColsLeft> &left,
+ const Eigen::Matrix<T, RowsRight, ColsRight> &right) {
+ assert(left.rows() == right.rows());
+ int n = left.rows();
+ int m1 = left.cols();
+ int m2 = right.cols();
+
+ Eigen::Matrix<T, ROWS, COLS> stacked(n, m1 + m2);
+ stacked.block(0, 0, n, m1) = left;
+ stacked.block(0, m1, n, m2) = right;
+ return stacked;
+ }
+
+ // Reuse the above macros by swapping the order of Rows and Cols. Nasty, but
+ // the duplication is worse.
+ // TODO(keir): Add a static assert if both rows are at compiletime.
+ // TODO(keir): Mail eigen list about making this work for general expressions
+ // rather than only matrix types.
+ template<typename T, int RowsLeft, int RowsRight, int ColsLeft, int ColsRight>
+ Eigen::Matrix<T, COLS, ROWS>
+ VStack(const Eigen::Matrix<T, ColsLeft, RowsLeft> &top,
+ const Eigen::Matrix<T, ColsRight, RowsRight> &bottom) {
+ assert(top.cols() == bottom.cols());
+ int n1 = top.rows();
+ int n2 = bottom.rows();
+ int m = top.cols();
+
+ Eigen::Matrix<T, COLS, ROWS> stacked(n1 + n2, m);
+ stacked.block(0, 0, n1, m) = top;
+ stacked.block(n1, 0, n2, m) = bottom;
+ return stacked;
+ }
+ #undef COLS
+ #undef ROWS
+#endif //_WIN32
+
+
+
+void HorizontalStack(const Mat &left, const Mat &right, Mat *stacked);
+
+template<typename TTop, typename TBot, typename TStacked>
+void VerticalStack(const TTop &top, const TBot &bottom, TStacked *stacked) {
+ assert(top.cols() == bottom.cols());
+ int n1 = top.rows();
+ int n2 = bottom.rows();
+ int m = top.cols();
+
+ stacked->resize(n1 + n2, m);
+ stacked->block(0, 0, n1, m) = top;
+ stacked->block(n1, 0, n2, m) = bottom;
+}
+
+void MatrixColumn(const Mat &A, int i, Vec2 *v);
+void MatrixColumn(const Mat &A, int i, Vec3 *v);
+void MatrixColumn(const Mat &A, int i, Vec4 *v);
+
+template <typename TMat, typename TCols>
+TMat ExtractColumns(const TMat &A, const TCols &columns) {
+ TMat compressed(A.rows(), columns.size());
+ for (int i = 0; i < columns.size(); ++i) {
+ compressed.col(i) = A.col(columns[i]);
+ }
+ return compressed;
+}
+
+template <typename TMat, typename TDest>
+void reshape(const TMat &a, int rows, int cols, TDest *b) {
+ assert(a.rows()*a.cols() == rows*cols);
+ b->resize(rows, cols);
+ for (int i = 0; i < rows; i++) {
+ for (int j = 0; j < cols; j++) {
+ (*b)(i, j) = a[cols*i + j];
+ }
+ }
+}
+
+inline bool isnan(double i) {
+#ifdef WIN32
+ return _isnan(i) > 0;
+#else
+ return std::isnan(i);
+#endif
+}
+
+/// Ceil function that has the same behaviour for positive
+/// and negative values
+template <typename FloatType>
+FloatType ceil0(const FloatType& value) {
+ FloatType result = std::ceil( std::fabs( value ) );
+ return (value < 0.0) ? -result : result;
+}
+
+/// Returns the skew anti-symmetric matrix of a vector
+inline Mat3 SkewMat(const Vec3 &x) {
+ Mat3 skew;
+ skew << 0 , -x(2), x(1),
+ x(2), 0 , -x(0),
+ -x(1), x(0), 0;
+ return skew;
+}
+/// Returns the skew anti-symmetric matrix of a vector with only
+/// the first two (independent) lines
+inline Mat23 SkewMatMinimal(const Vec2 &x) {
+ Mat23 skew;
+ skew << 0,-1, x(1),
+ 1, 0, -x(0);
+ return skew;
+}
+} // namespace libmv
+
+#endif // LIBMV_NUMERIC_NUMERIC_H
diff --git a/extern/libmv/libmv/numeric/poly.cc b/extern/libmv/libmv/numeric/poly.cc
new file mode 100644
index 00000000000..d96e3c104c7
--- /dev/null
+++ b/extern/libmv/libmv/numeric/poly.cc
@@ -0,0 +1,23 @@
+// Copyright (c) 2007, 2008 libmv authors.
+//
+// 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.
+//
+// Routines for solving polynomials.
+
+// TODO(keir): Add a solver for degree > 3 polynomials.
diff --git a/extern/libmv/libmv/numeric/poly.h b/extern/libmv/libmv/numeric/poly.h
new file mode 100644
index 00000000000..cb1d65b32c4
--- /dev/null
+++ b/extern/libmv/libmv/numeric/poly.h
@@ -0,0 +1,123 @@
+// Copyright (c) 2007, 2008 libmv authors.
+//
+// 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 LIBMV_NUMERIC_POLY_H_
+#define LIBMV_NUMERIC_POLY_H_
+
+#include <cmath>
+#include <stdio.h>
+
+namespace libmv {
+
+// Solve the cubic polynomial
+//
+// x^3 + a*x^2 + b*x + c = 0
+//
+// The number of roots (from zero to three) is returned. If the number of roots
+// is less than three, then higher numbered x's are not changed. For example,
+// if there are 2 roots, only x0 and x1 are set.
+//
+// The GSL cubic solver was used as a reference for this routine.
+template<typename Real>
+int SolveCubicPolynomial(Real a, Real b, Real c,
+ Real *x0, Real *x1, Real *x2) {
+ Real q = a * a - 3 * b;
+ Real r = 2 * a * a * a - 9 * a * b + 27 * c;
+
+ Real Q = q / 9;
+ Real R = r / 54;
+
+ Real Q3 = Q * Q * Q;
+ Real R2 = R * R;
+
+ Real CR2 = 729 * r * r;
+ Real CQ3 = 2916 * q * q * q;
+
+ if (R == 0 && Q == 0) {
+ // Tripple root in one place.
+ *x0 = *x1 = *x2 = -a / 3 ;
+ return 3;
+
+ } else if (CR2 == CQ3) {
+ // This test is actually R2 == Q3, written in a form suitable for exact
+ // computation with integers.
+ //
+ // Due to finite precision some double roots may be missed, and considered
+ // to be a pair of complex roots z = x +/- epsilon i close to the real
+ // axis.
+ Real sqrtQ = sqrt (Q);
+ if (R > 0) {
+ *x0 = -2 * sqrtQ - a / 3;
+ *x1 = sqrtQ - a / 3;
+ *x2 = sqrtQ - a / 3;
+ } else {
+ *x0 = -sqrtQ - a / 3;
+ *x1 = -sqrtQ - a / 3;
+ *x2 = 2 * sqrtQ - a / 3;
+ }
+ return 3;
+
+ } else if (CR2 < CQ3) {
+ // This case is equivalent to R2 < Q3.
+ Real sqrtQ = sqrt (Q);
+ Real sqrtQ3 = sqrtQ * sqrtQ * sqrtQ;
+ Real theta = acos (R / sqrtQ3);
+ Real norm = -2 * sqrtQ;
+ *x0 = norm * cos (theta / 3) - a / 3;
+ *x1 = norm * cos ((theta + 2.0 * M_PI) / 3) - a / 3;
+ *x2 = norm * cos ((theta - 2.0 * M_PI) / 3) - a / 3;
+
+ // Put the roots in ascending order.
+ if (*x0 > *x1) {
+ std::swap(*x0, *x1);
+ }
+ if (*x1 > *x2) {
+ std::swap(*x1, *x2);
+ if (*x0 > *x1) {
+ std::swap(*x0, *x1);
+ }
+ }
+ return 3;
+ }
+ Real sgnR = (R >= 0 ? 1 : -1);
+ Real A = -sgnR * pow (fabs (R) + sqrt (R2 - Q3), 1.0/3.0);
+ Real B = Q / A ;
+ *x0 = A + B - a / 3;
+ return 1;
+}
+
+// The coefficients are in ascending powers, i.e. coeffs[N]*x^N.
+template<typename Real>
+int SolveCubicPolynomial(const Real *coeffs, Real *solutions) {
+ if (coeffs[0] == 0.0) {
+ // TODO(keir): This is a quadratic not a cubic. Implement a quadratic
+ // solver!
+ return 0;
+ }
+ Real a = coeffs[2] / coeffs[3];
+ Real b = coeffs[1] / coeffs[3];
+ Real c = coeffs[0] / coeffs[3];
+ return SolveCubicPolynomial(a, b, c,
+ solutions + 0,
+ solutions + 1,
+ solutions + 2);
+}
+} // namespace libmv
+#endif // LIBMV_NUMERIC_POLY_H_
diff --git a/extern/libmv/libmv/simple_pipeline/bundle.cc b/extern/libmv/libmv/simple_pipeline/bundle.cc
new file mode 100644
index 00000000000..cb8822dcf44
--- /dev/null
+++ b/extern/libmv/libmv/simple_pipeline/bundle.cc
@@ -0,0 +1,184 @@
+// Copyright (c) 2011 libmv authors.
+//
+// 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.
+
+#define V3DLIB_ENABLE_SUITESPARSE 1
+
+#include <map>
+
+#include "libmv/base/vector.h"
+#include "libmv/logging/logging.h"
+#include "libmv/multiview/fundamental.h"
+#include "libmv/multiview/projection.h"
+#include "libmv/numeric/numeric.h"
+#include "libmv/simple_pipeline/reconstruction.h"
+#include "libmv/simple_pipeline/tracks.h"
+#include "third_party/ssba/Geometry/v3d_cameramatrix.h"
+#include "third_party/ssba/Geometry/v3d_metricbundle.h"
+#include "third_party/ssba/Math/v3d_linear.h"
+#include "third_party/ssba/Math/v3d_linear_utils.h"
+
+namespace libmv {
+
+void EuclideanBundle(const Tracks &tracks,
+ EuclideanReconstruction *reconstruction) {
+ vector<Marker> markers = tracks.AllMarkers();
+
+ // "index" in this context is the index that V3D's optimizer will see. The
+ // V3D index must be dense in that the cameras are numbered 0...n-1, which is
+ // not the case for the "image" numbering that arises from the tracks
+ // structure. The complicated mapping is necessary to convert between the two
+ // representations.
+ std::map<EuclideanCamera *, int> camera_to_index;
+ std::map<EuclideanPoint *, int> point_to_index;
+ vector<EuclideanCamera *> index_to_camera;
+ vector<EuclideanPoint *> index_to_point;
+ int num_cameras = 0;
+ int num_points = 0;
+ for (int i = 0; i < markers.size(); ++i) {
+ const Marker &marker = markers[i];
+ EuclideanCamera *camera = reconstruction->CameraForImage(marker.image);
+ EuclideanPoint *point = reconstruction->PointForTrack(marker.track);
+ if (camera && point) {
+ if (camera_to_index.find(camera) == camera_to_index.end()) {
+ camera_to_index[camera] = num_cameras;
+ index_to_camera.push_back(camera);
+ num_cameras++;
+ }
+ if (point_to_index.find(point) == point_to_index.end()) {
+ point_to_index[point] = num_points;
+ index_to_point.push_back(point);
+ num_points++;
+ }
+ }
+ }
+
+ // Make a V3D identity matrix, needed in a few places for K, since this
+ // assumes a calibrated setup.
+ V3D::Matrix3x3d identity3x3;
+ identity3x3[0][0] = 1.0;
+ identity3x3[0][1] = 0.0;
+ identity3x3[0][2] = 0.0;
+ identity3x3[1][0] = 0.0;
+ identity3x3[1][1] = 1.0;
+ identity3x3[1][2] = 0.0;
+ identity3x3[2][0] = 0.0;
+ identity3x3[2][1] = 0.0;
+ identity3x3[2][2] = 1.0;
+
+ // Convert libmv's cameras to V3D's cameras.
+ std::vector<V3D::CameraMatrix> v3d_cameras(index_to_camera.size());
+ for (int k = 0; k < index_to_camera.size(); ++k) {
+ V3D::Matrix3x3d R;
+ V3D::Vector3d t;
+
+ // Libmv's rotation matrix type.
+ const Mat3 &R_libmv = index_to_camera[k]->R;
+ const Vec3 &t_libmv = index_to_camera[k]->t;
+
+ for (int i = 0; i < 3; ++i) {
+ for (int j = 0; j < 3; ++j) {
+ R[i][j] = R_libmv(i, j);
+ }
+ t[i] = t_libmv(i);
+ }
+ v3d_cameras[k].setIntrinsic(identity3x3);
+ v3d_cameras[k].setRotation(R);
+ v3d_cameras[k].setTranslation(t);
+ }
+ LG << "Number of cameras: " << index_to_camera.size();
+
+ // Convert libmv's points to V3D's points.
+ std::vector<V3D::Vector3d> v3d_points(index_to_point.size());
+ for (int i = 0; i < index_to_point.size(); i++) {
+ v3d_points[i][0] = index_to_point[i]->X(0);
+ v3d_points[i][1] = index_to_point[i]->X(1);
+ v3d_points[i][2] = index_to_point[i]->X(2);
+ }
+ LG << "Number of points: " << index_to_point.size();
+
+ // Convert libmv's measurements to v3d measurements.
+ int num_residuals = 0;
+ std::vector<V3D::Vector2d> v3d_measurements;
+ std::vector<int> v3d_camera_for_measurement;
+ std::vector<int> v3d_point_for_measurement;
+ for (int i = 0; i < markers.size(); ++i) {
+ EuclideanCamera *camera = reconstruction->CameraForImage(markers[i].image);
+ EuclideanPoint *point = reconstruction->PointForTrack(markers[i].track);
+ if (!camera || !point) {
+ continue;
+ }
+ V3D::Vector2d v3d_point;
+ v3d_point[0] = markers[i].x;
+ v3d_point[1] = markers[i].y;
+ v3d_measurements.push_back(v3d_point);
+ v3d_camera_for_measurement.push_back(camera_to_index[camera]);
+ v3d_point_for_measurement.push_back(point_to_index[point]);
+ num_residuals++;
+ }
+ LG << "Number of residuals: " << num_residuals;
+
+ // This is calibrated reconstruction, so use zero distortion.
+ V3D::StdDistortionFunction v3d_distortion;
+ v3d_distortion.k1 = 0;
+ v3d_distortion.k2 = 0;
+ v3d_distortion.p1 = 0;
+ v3d_distortion.p2 = 0;
+
+ // Finally, run the bundle adjustment.
+ double const inlierThreshold = 500000.0;
+ V3D::CommonInternalsMetricBundleOptimizer opt(V3D::FULL_BUNDLE_METRIC,
+ inlierThreshold,
+ identity3x3,
+ v3d_distortion,
+ v3d_cameras,
+ v3d_points,
+ v3d_measurements,
+ v3d_camera_for_measurement,
+ v3d_point_for_measurement);
+ opt.maxIterations = 50;
+ opt.minimize();
+ LG << "Bundle status: " << opt.status;
+
+ // Convert V3D's cameras back to libmv's cameras.
+ for (int k = 0; k < num_cameras; k++) {
+ V3D::Matrix3x4d const Rt = v3d_cameras[k].getOrientation();
+ for (int i = 0; i < 3; ++i) {
+ for (int j = 0; j < 3; ++j) {
+ index_to_camera[k]->R(i, j) = Rt[i][j];
+ }
+ index_to_camera[k]->t(i) = Rt[i][3];
+ }
+ }
+
+ // Convert V3D's points back to libmv's points.
+ for (int k = 0; k < num_points; k++) {
+ for (int i = 0; i < 3; ++i) {
+ index_to_point[k]->X(i) = v3d_points[k][i];
+ }
+ }
+}
+
+void ProjectiveBundle(const Tracks & /*tracks*/,
+ ProjectiveReconstruction * /*reconstruction*/) {
+ // TODO(keir): Implement this! This can't work until we have a better bundler
+ // than SSBA, since SSBA has no support for projective bundling.
+}
+
+} // namespace libmv
diff --git a/extern/libmv/libmv/simple_pipeline/bundle.h b/extern/libmv/libmv/simple_pipeline/bundle.h
new file mode 100644
index 00000000000..c7fb2a79607
--- /dev/null
+++ b/extern/libmv/libmv/simple_pipeline/bundle.h
@@ -0,0 +1,72 @@
+// Copyright (c) 2011 libmv authors.
+//
+// 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 LIBMV_SIMPLE_PIPELINE_BUNDLE_H
+#define LIBMV_SIMPLE_PIPELINE_BUNDLE_H
+
+namespace libmv {
+
+class EuclideanReconstruction;
+class ProjectiveReconstruction;
+class Tracks;
+
+/*!
+ Refine camera poses and 3D coordinates using bundle adjustment.
+
+ This routine adjusts all cameras and points in \a *reconstruction. This
+ assumes a full observation for reconstructed tracks; this implies that if
+ there is a reconstructed 3D point (a bundle) for a track, then all markers
+ for that track will be included in the minimization. \a tracks should
+ contain markers used in the initial reconstruction.
+
+ The cameras and bundles (3D points) are refined in-place.
+
+ \note This assumes an outlier-free set of markers.
+ \note This assumes a calibrated reconstruction, e.g. the markers are
+ already corrected for camera intrinsics and radial distortion.
+
+ \sa EuclideanResect, EuclideanIntersect, EuclideanReconstructTwoFrames
+*/
+void EuclideanBundle(const Tracks &tracks,
+ EuclideanReconstruction *reconstruction);
+
+/*!
+ Refine camera poses and 3D coordinates using bundle adjustment.
+
+ This routine adjusts all cameras and points in \a *reconstruction. This
+ assumes a full observation for reconstructed tracks; this implies that if
+ there is a reconstructed 3D point (a bundle) for a track, then all markers
+ for that track will be included in the minimization. \a tracks should
+ contain markers used in the initial reconstruction.
+
+ The cameras and bundles (homogeneous 3D points) are refined in-place.
+
+ \note This assumes an outlier-free set of markers.
+ \note This assumes that radial distortion is already corrected for, but
+ does not assume that that other intrinsics are.
+
+ \sa ProjectiveResect, ProjectiveIntersect, ProjectiveReconstructTwoFrames
+*/
+void ProjectiveBundle(const Tracks &tracks,
+ ProjectiveReconstruction *reconstruction);
+
+} // namespace libmv
+
+#endif // LIBMV_SIMPLE_PIPELINE_BUNDLE_H
diff --git a/extern/libmv/libmv/simple_pipeline/camera_intrinsics.cc b/extern/libmv/libmv/simple_pipeline/camera_intrinsics.cc
new file mode 100644
index 00000000000..366129dd3d2
--- /dev/null
+++ b/extern/libmv/libmv/simple_pipeline/camera_intrinsics.cc
@@ -0,0 +1,351 @@
+// Copyright (c) 2011 libmv authors.
+//
+// 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 "libmv/simple_pipeline/camera_intrinsics.h"
+#include "libmv/numeric/levenberg_marquardt.h"
+
+namespace libmv {
+
+struct Offset {
+ signed char ix, iy;
+ unsigned char fx,fy;
+};
+
+struct Grid {
+ struct Offset *offset;
+ int width, height;
+ double overscan;
+};
+
+static struct Grid *copyGrid(struct Grid *from)
+{
+ struct Grid *to = NULL;
+
+ if (from) {
+ to = new Grid;
+
+ to->width = from->width;
+ to->height = from->height;
+ to->overscan = from->overscan;
+
+ to->offset = new Offset[to->width*to->height];
+ memcpy(to->offset, from->offset, sizeof(struct Offset)*to->width*to->height);
+ }
+
+ return to;
+}
+
+CameraIntrinsics::CameraIntrinsics()
+ : K_(Mat3::Identity()),
+ image_width_(0),
+ image_height_(0),
+ k1_(0),
+ k2_(0),
+ k3_(0),
+ p1_(0),
+ p2_(0),
+ distort_(0),
+ undistort_(0) {}
+
+CameraIntrinsics::CameraIntrinsics(const CameraIntrinsics &from)
+ : K_(from.K_),
+ image_width_(from.image_width_),
+ image_height_(from.image_height_),
+ k1_(from.k1_),
+ k2_(from.k2_),
+ k3_(from.k3_),
+ p1_(from.p1_),
+ p2_(from.p2_)
+{
+ distort_ = copyGrid(from.distort_);
+ undistort_ = copyGrid(from.undistort_);
+}
+
+CameraIntrinsics::~CameraIntrinsics() {
+ FreeLookupGrid();
+}
+
+/// Set the entire calibration matrix at once.
+void CameraIntrinsics::SetK(const Mat3 new_k) {
+ K_ = new_k;
+ FreeLookupGrid();
+}
+
+/// Set both x and y focal length in pixels.
+void CameraIntrinsics::SetFocalLength(double focal_x, double focal_y) {
+ K_(0, 0) = focal_x;
+ K_(1, 1) = focal_y;
+ FreeLookupGrid();
+}
+
+void CameraIntrinsics::SetPrincipalPoint(double cx, double cy) {
+ K_(0, 2) = cx;
+ K_(1, 2) = cy;
+ FreeLookupGrid();
+}
+
+void CameraIntrinsics::SetImageSize(int width, int height) {
+ image_width_ = width;
+ image_height_ = height;
+ FreeLookupGrid();
+}
+
+void CameraIntrinsics::SetRadialDistortion(double k1, double k2, double k3) {
+ k1_ = k1;
+ k2_ = k2;
+ k3_ = k3;
+ FreeLookupGrid();
+}
+
+void CameraIntrinsics::SetTangentialDistortion(double p1, double p2) {
+ p1_ = p1;
+ p2_ = p2;
+ FreeLookupGrid();
+}
+
+void CameraIntrinsics::ApplyIntrinsics(double normalized_x,
+ double normalized_y,
+ double *image_x,
+ double *image_y) const {
+ double x = normalized_x;
+ double y = normalized_y;
+
+ // Apply distortion to the normalized points to get (xd, yd).
+ double r2 = x*x + y*y;
+ double r4 = r2 * r2;
+ double r6 = r4 * r2;
+ double r_coeff = (1 + k1_*r2 + k2_*r4 + k3_*r6);
+ double xd = x * r_coeff + 2*p1_*x*y + p2_*(r2 + 2*x*x);
+ double yd = y * r_coeff + 2*p2_*x*y + p1_*(r2 + 2*y*y);
+
+ // Apply focal length and principal point to get the final image coordinates.
+ *image_x = focal_length_x() * xd + principal_point_x();
+ *image_y = focal_length_y() * yd + principal_point_y();
+}
+
+struct InvertIntrinsicsCostFunction {
+ public:
+ typedef Vec2 FMatrixType;
+ typedef Vec2 XMatrixType;
+
+ InvertIntrinsicsCostFunction(const CameraIntrinsics &intrinsics,
+ double image_x, double image_y)
+ : intrinsics(intrinsics), x(image_x), y(image_y) {}
+
+ Vec2 operator()(const Vec2 &u) const {
+ double xx, yy;
+ intrinsics.ApplyIntrinsics(u(0), u(1), &xx, &yy);
+ Vec2 fx;
+ fx << (xx - x), (yy - y);
+ return fx;
+ }
+ const CameraIntrinsics &intrinsics;
+ double x, y;
+};
+
+void CameraIntrinsics::InvertIntrinsics(double image_x,
+ double image_y,
+ double *normalized_x,
+ double *normalized_y) const {
+ // Compute the initial guess. For a camera with no distortion, this will also
+ // be the final answer; the LM iteration will terminate immediately.
+ Vec2 normalized;
+ normalized(0) = (image_x - principal_point_x()) / focal_length_x();
+ normalized(1) = (image_y - principal_point_y()) / focal_length_y();
+
+ typedef LevenbergMarquardt<InvertIntrinsicsCostFunction> Solver;
+
+ InvertIntrinsicsCostFunction intrinsics_cost(*this, image_x, image_y);
+ Solver::SolverParameters params;
+ Solver solver(intrinsics_cost);
+
+ /*Solver::Results results =*/ solver.minimize(params, &normalized);
+
+ // TODO(keir): Better error handling.
+
+ *normalized_x = normalized(0);
+ *normalized_y = normalized(1);
+}
+
+// TODO(MatthiasF): downsample lookup
+template<typename WarpFunction>
+void CameraIntrinsics::ComputeLookupGrid(Grid* grid, int width, int height, double overscan) {
+ double w = (double)width / (1 + overscan);
+ double h = (double)height / (1 + overscan);
+ double aspx = (double)w / image_width_;
+ double aspy = (double)h / image_height_;
+
+ for (int y = 0; y < height; y++) {
+ for (int x = 0; x < width; x++) {
+ double src_x = (x - 0.5 * overscan * w) / aspx, src_y = (y - 0.5 * overscan * h) / aspy;
+ double warp_x, warp_y;
+ WarpFunction(this,src_x,src_y,&warp_x,&warp_y);
+ warp_x = warp_x*aspx + 0.5 * overscan * w;
+ warp_y = warp_y*aspy + 0.5 * overscan * h;
+ int ix = int(warp_x), iy = int(warp_y);
+ int fx = round((warp_x-ix)*256), fy = round((warp_y-iy)*256);
+ if(fx == 256) { fx=0; ix++; }
+ if(fy == 256) { fy=0; iy++; }
+ // Use nearest border pixel
+ if( ix < 0 ) { ix = 0, fx = 0; }
+ if( iy < 0 ) { iy = 0, fy = 0; }
+ if( ix >= width-2 ) ix = width-2;
+ if( iy >= height-2 ) iy = height-2;
+ if ( ix-x > -128 && ix-x < 128 && iy-y > -128 && iy-y < 128 ) {
+ Offset offset = { ix-x, iy-y, fx, fy };
+ grid->offset[y*width+x] = offset;
+ } else {
+ Offset offset = { 0, 0, 0, 0 };
+ grid->offset[y*width+x] = offset;
+ }
+ }
+ }
+}
+
+// TODO(MatthiasF): cubic B-Spline image sampling, bilinear lookup
+template<typename T,int N>
+static void Warp(const Grid* grid, const T* src, T* dst,
+ int width, int height) {
+ for (int y = 0; y < height; y++) {
+ for (int x = 0; x < width; x++) {
+ Offset offset = grid->offset[y*width+x];
+ const T* s = &src[((y+offset.iy)*width+(x+offset.ix))*N];
+ for (int i = 0; i < N; i++) {
+ dst[(y*width+x)*N+i] = ((s[ i] * (256-offset.fx) + s[ N+i] * offset.fx) * (256-offset.fy)
+ +(s[width*N+i] * (256-offset.fx) + s[width*N+N+i] * offset.fx) * offset.fy) / (256*256);
+ }
+ }
+ }
+}
+
+void CameraIntrinsics::FreeLookupGrid() {
+ if(distort_) {
+ delete distort_->offset;
+ delete distort_;
+ distort_ = NULL;
+ }
+
+ if(undistort_) {
+ delete undistort_->offset;
+ delete undistort_;
+ undistort_ = NULL;
+ }
+}
+
+// FIXME: C++ templates limitations makes thing complicated, but maybe there is a simpler method.
+struct ApplyIntrinsicsFunction {
+ ApplyIntrinsicsFunction(CameraIntrinsics* intrinsics, double x, double y,
+ double *warp_x, double *warp_y) {
+ intrinsics->ApplyIntrinsics(
+ (x-intrinsics->principal_point_x())/intrinsics->focal_length_x(),
+ (y-intrinsics->principal_point_y())/intrinsics->focal_length_y(),
+ warp_x, warp_y);
+ }
+};
+struct InvertIntrinsicsFunction {
+ InvertIntrinsicsFunction(CameraIntrinsics* intrinsics, double x, double y,
+ double *warp_x, double *warp_y) {
+ intrinsics->InvertIntrinsics(x,y,warp_x,warp_y);
+ *warp_x = *warp_x*intrinsics->focal_length_x()+intrinsics->principal_point_x();
+ *warp_y = *warp_y*intrinsics->focal_length_y()+intrinsics->principal_point_y();
+ }
+};
+
+void CameraIntrinsics::CheckDistortLookupGrid(int width, int height, double overscan)
+{
+ if(distort_) {
+ if(distort_->width != width || distort_->height != height || distort_->overscan != overscan) {
+ delete [] distort_->offset;
+ distort_->offset = NULL;
+ }
+ } else {
+ distort_ = new Grid;
+ distort_->offset = NULL;
+ }
+
+ if(!distort_->offset) {
+ distort_->offset = new Offset[width*height];
+ ComputeLookupGrid<InvertIntrinsicsFunction>(distort_,width,height,overscan);
+ }
+
+ distort_->width = width;
+ distort_->height = height;
+ distort_->overscan = overscan;
+}
+
+void CameraIntrinsics::CheckUndistortLookupGrid(int width, int height, double overscan)
+{
+ if(undistort_) {
+ if(undistort_->width != width || undistort_->height != height || undistort_->overscan != overscan) {
+ delete [] undistort_->offset;
+ undistort_->offset = NULL;
+ }
+ } else {
+ undistort_ = new Grid;
+ undistort_->offset = NULL;
+ }
+
+ if(!undistort_->offset) {
+ undistort_->offset = new Offset[width*height];
+ ComputeLookupGrid<ApplyIntrinsicsFunction>(undistort_,width,height,overscan);
+ }
+
+ undistort_->width = width;
+ undistort_->height = height;
+ undistort_->overscan = overscan;
+}
+
+void CameraIntrinsics::Distort(const float* src, float* dst, int width, int height, double overscan, int channels) {
+ CheckDistortLookupGrid(width, height, overscan);
+ if(channels==1) Warp<float,1>(distort_,src,dst,width,height);
+ else if(channels==2) Warp<float,2>(distort_,src,dst,width,height);
+ else if(channels==3) Warp<float,3>(distort_,src,dst,width,height);
+ else if(channels==4) Warp<float,4>(distort_,src,dst,width,height);
+ //else assert("channels must be between 1 and 4");
+}
+
+void CameraIntrinsics::Distort(const unsigned char* src, unsigned char* dst, int width, int height, double overscan, int channels) {
+ CheckDistortLookupGrid(width, height, overscan);
+ if(channels==1) Warp<unsigned char,1>(distort_,src,dst,width,height);
+ else if(channels==2) Warp<unsigned char,2>(distort_,src,dst,width,height);
+ else if(channels==3) Warp<unsigned char,3>(distort_,src,dst,width,height);
+ else if(channels==4) Warp<unsigned char,4>(distort_,src,dst,width,height);
+ //else assert("channels must be between 1 and 4");
+}
+
+void CameraIntrinsics::Undistort(const float* src, float* dst, int width, int height, double overscan, int channels) {
+ CheckUndistortLookupGrid(width, height, overscan);
+ if(channels==1) Warp<float,1>(undistort_,src,dst,width,height);
+ else if(channels==2) Warp<float,2>(undistort_,src,dst,width,height);
+ else if(channels==3) Warp<float,3>(undistort_,src,dst,width,height);
+ else if(channels==4) Warp<float,4>(undistort_,src,dst,width,height);
+ //else assert("channels must be between 1 and 4");
+}
+
+void CameraIntrinsics::Undistort(const unsigned char* src, unsigned char* dst, int width, int height, double overscan, int channels) {
+ CheckUndistortLookupGrid(width, height, overscan);
+ if(channels==1) Warp<unsigned char,1>(undistort_,src,dst,width,height);
+ else if(channels==2) Warp<unsigned char,2>(undistort_,src,dst,width,height);
+ else if(channels==3) Warp<unsigned char,3>(undistort_,src,dst,width,height);
+ else if(channels==4) Warp<unsigned char,4>(undistort_,src,dst,width,height);
+ //else assert("channels must be between 1 and 4");
+}
+
+} // namespace libmv
diff --git a/extern/libmv/libmv/simple_pipeline/camera_intrinsics.h b/extern/libmv/libmv/simple_pipeline/camera_intrinsics.h
new file mode 100644
index 00000000000..f4bf903c36c
--- /dev/null
+++ b/extern/libmv/libmv/simple_pipeline/camera_intrinsics.h
@@ -0,0 +1,152 @@
+// Copyright (c) 2011 libmv authors.
+//
+// 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 LIBMV_SIMPLE_PIPELINE_CAMERA_INTRINSICS_H_
+#define LIBMV_SIMPLE_PIPELINE_CAMERA_INTRINSICS_H_
+
+#include <Eigen/Core>
+typedef Eigen::Matrix<double, 3, 3> Mat3;
+
+namespace libmv {
+
+struct Grid;
+
+class CameraIntrinsics {
+ public:
+ CameraIntrinsics();
+ CameraIntrinsics(const CameraIntrinsics &from);
+ ~CameraIntrinsics();
+
+ const Mat3 &K() const { return K_; }
+ // FIXME(MatthiasF): these should be CamelCase methods
+ double focal_length() const { return K_(0, 0); }
+ double focal_length_x() const { return K_(0, 0); }
+ double focal_length_y() const { return K_(1, 1); }
+ double principal_point_x() const { return K_(0, 2); }
+ double principal_point_y() const { return K_(1, 2); }
+ int image_width() const { return image_width_; }
+ int image_height() const { return image_height_; }
+ double k1() const { return k1_; }
+ double k2() const { return k2_; }
+ double k3() const { return k3_; }
+ double p1() const { return p1_; }
+ double p2() const { return p2_; }
+
+ /// Set the entire calibration matrix at once.
+ void SetK(const Mat3 new_k);
+
+ /// Set both x and y focal length in pixels.
+ void SetFocalLength(double focal_x, double focal_y);
+
+ void SetPrincipalPoint(double cx, double cy);
+
+ void SetImageSize(int width, int height);
+
+ void SetRadialDistortion(double k1, double k2, double k3 = 0);
+
+ void SetTangentialDistortion(double p1, double p2);
+
+ /*!
+ Apply camera intrinsics to the normalized point to get image coordinates.
+
+ This applies the lens distortion to a point which is in normalized
+ camera coordinates (i.e. the principal point is at (0, 0)) to get image
+ coordinates in pixels.
+ */
+ void ApplyIntrinsics(double normalized_x, double normalized_y,
+ double *image_x, double *image_y) const;
+
+ /*!
+ Invert camera intrinsics on the image point to get normalized coordinates.
+
+ This reverses the effect of lens distortion on a point which is in image
+ coordinates to get normalized camera coordinates.
+ */
+ void InvertIntrinsics(double image_x, double image_y,
+ double *normalized_x, double *normalized_y) const;
+
+ /*!
+ Distort an image using the current camera instrinsics
+
+ The distorted image is computed in \a dst using samples from \a src.
+ both buffers should be \a width x \a height x \a channels sized.
+
+ \note This is the reference implementation using floating point images.
+ */
+ void Distort(const float* src, float* dst,
+ int width, int height, double overscan, int channels);
+ /*!
+ Distort an image using the current camera instrinsics
+
+ The distorted image is computed in \a dst using samples from \a src.
+ both buffers should be \a width x \a height x \a channels sized.
+
+ \note This version is much faster.
+ */
+ void Distort(const unsigned char* src, unsigned char* dst,
+ int width, int height, double overscan, int channels);
+ /*!
+ Undistort an image using the current camera instrinsics
+
+ The undistorted image is computed in \a dst using samples from \a src.
+ both buffers should be \a width x \a height x \a channels sized.
+
+ \note This is the reference implementation using floating point images.
+ */
+ void Undistort(const float* src, float* dst,
+ int width, int height, double overscan, int channels);
+ /*!
+ Undistort an image using the current camera instrinsics
+
+ The undistorted image is computed in \a dst using samples from \a src.
+ both buffers should be \a width x \a height x \a channels sized.
+
+ \note This version is much faster.
+ */
+ void Undistort(const unsigned char* src, unsigned char* dst,
+ int width, int height, double overscan, int channels);
+
+ private:
+ template<typename WarpFunction> void ComputeLookupGrid(struct Grid* grid, int width, int height, double overscan);
+ void CheckUndistortLookupGrid(int width, int height, double overscan);
+ void CheckDistortLookupGrid(int width, int height, double overscan);
+ void FreeLookupGrid();
+
+ // The traditional intrinsics matrix from x = K[R|t]X.
+ Mat3 K_;
+
+ // This is the size of the image. This is necessary to, for example, handle
+ // the case of processing a scaled image.
+ int image_width_;
+ int image_height_;
+
+ // OpenCV's distortion model with third order polynomial radial distortion
+ // terms and second order tangential distortion. The distortion is applied to
+ // the normalized coordinates before the focal length, which makes them
+ // independent of image size.
+ double k1_, k2_, k3_, p1_, p2_;
+
+ struct Grid *distort_;
+ struct Grid *undistort_;
+};
+
+} // namespace libmv
+
+#endif // LIBMV_SIMPLE_PIPELINE_CAMERA_INTRINSICS_H_
diff --git a/extern/libmv/libmv/simple_pipeline/detect.cc b/extern/libmv/libmv/simple_pipeline/detect.cc
new file mode 100644
index 00000000000..8ac42ab0aba
--- /dev/null
+++ b/extern/libmv/libmv/simple_pipeline/detect.cc
@@ -0,0 +1,184 @@
+/****************************************************************************
+**
+** Copyright (c) 2011 libmv authors.
+**
+** 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 "libmv/simple_pipeline/detect.h"
+#include <third_party/fast/fast.h>
+#include <stdlib.h>
+#include <memory.h>
+
+#ifdef __SSE2__
+#include <emmintrin.h>
+#endif
+
+namespace libmv {
+
+typedef unsigned int uint;
+
+int featurecmp(const void *a_v, const void *b_v)
+{
+ Feature *a = (Feature*)a_v;
+ Feature *b = (Feature*)b_v;
+
+ return b->score - a->score;
+}
+
+std::vector<Feature> DetectFAST(const unsigned char* data, int width, int height, int stride,
+ int min_trackness, int min_distance) {
+ std::vector<Feature> features;
+ // TODO(MatthiasF): Support targetting a feature count (binary search trackness)
+ int num_features;
+ xy* all = fast9_detect(data, width, height,
+ stride, min_trackness, &num_features);
+ if(num_features == 0) {
+ free(all);
+ return features;
+ }
+ int* scores = fast9_score(data, stride, all, num_features, min_trackness);
+ // TODO: merge with close feature suppression
+ xy* nonmax = nonmax_suppression(all, scores, num_features, &num_features);
+ free(all);
+ // Remove too close features
+ // TODO(MatthiasF): A resolution independent parameter would be better than distance
+ // e.g. a coefficient going from 0 (no minimal distance) to 1 (optimal circle packing)
+ // FIXME(MatthiasF): this method will not necessarily give all maximum markers
+ if(num_features) {
+ Feature *all_features = new Feature[num_features];
+
+ for(int i = 0; i < num_features; ++i) {
+ Feature a = { nonmax[i].x, nonmax[i].y, scores[i], 0 };
+ all_features[i] = a;
+ }
+
+ qsort((void *)all_features, num_features, sizeof(Feature), featurecmp);
+
+ features.reserve(num_features);
+
+ int prev_score = all_features[0].score;
+ for(int i = 0; i < num_features; ++i) {
+ bool ok = true;
+ Feature a = all_features[i];
+ if(a.score>prev_score)
+ abort();
+ prev_score = a.score;
+
+ // compare each feature against filtered set
+ for(int j = 0; j < features.size(); j++) {
+ Feature& b = features[j];
+ if ( (a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y) < min_distance*min_distance ) {
+ // already a nearby feature
+ ok = false;
+ break;
+ }
+ }
+
+ if(ok) {
+ // add the new feature
+ features.push_back(a);
+ }
+ }
+
+ delete [] all_features;
+ }
+ free(scores);
+ free(nonmax);
+ return features;
+}
+
+#ifdef __SSE2__
+static uint SAD(const ubyte* imageA, const ubyte* imageB, int strideA, int strideB) {
+ __m128i a = _mm_setzero_si128();
+ for(int i = 0; i < 16; i++) {
+ a = _mm_adds_epu16(a, _mm_sad_epu8( _mm_loadu_si128((__m128i*)(imageA+i*strideA)),
+ _mm_loadu_si128((__m128i*)(imageB+i*strideB))));
+ }
+ return _mm_extract_epi16(a,0) + _mm_extract_epi16(a,4);
+}
+#else
+static uint SAD(const ubyte* imageA, const ubyte* imageB, int strideA, int strideB) {
+ uint sad=0;
+ for(int i = 0; i < 16; i++) {
+ for(int j = 0; j < 16; j++) {
+ sad += abs((int)imageA[i*strideA+j] - imageB[i*strideB+j]);
+ }
+ }
+ return sad;
+}
+#endif
+
+void DetectMORAVEC(ubyte* image, int stride, int width, int height, Feature* detected, int* count, int distance, ubyte* pattern) {
+ unsigned short histogram[256];
+ memset(histogram,0,sizeof(histogram));
+ ubyte* scores = new ubyte[width*height];
+ memset(scores,0,width*height);
+ const int r = 1; //radius for self similarity comparison
+ for(int y=distance; y<height-distance; y++) {
+ for(int x=distance; x<width-distance; x++) {
+ ubyte* s = &image[y*stride+x];
+ int score = // low self-similarity with overlapping patterns //OPTI: load pattern once
+ SAD(s, s-r*stride-r, stride, stride)+SAD(s, s-r*stride, stride, stride)+SAD(s, s-r*stride+r, stride, stride)+
+ SAD(s, s -r, stride, stride)+ SAD(s, s +r, stride, stride)+
+ SAD(s, s+r*stride-r, stride, stride)+SAD(s, s+r*stride, stride, stride)+SAD(s, s+r*stride+r, stride, stride);
+ score /= 256; // normalize
+ if(pattern) score -= SAD(s, pattern, stride, 16); // find only features similar to pattern
+ if(score<=16) continue; // filter very self-similar features
+ score -= 16; // translate to score/histogram values
+ if(score>255) score=255; // clip
+ ubyte* c = &scores[y*width+x];
+ for(int i=-distance; i<0; i++) {
+ for(int j=-distance; j<distance; j++) {
+ int s = c[i*width+j];
+ if(s == 0) continue;
+ if(s >= score) goto nonmax;
+ c[i*width+j]=0, histogram[s]--;
+ }
+ }
+ for(int i=0, j=-distance; j<0; j++) {
+ int s = c[i*width+j];
+ if(s == 0) continue;
+ if(s >= score) goto nonmax;
+ c[i*width+j]=0, histogram[s]--;
+ }
+ c[0] = score, histogram[score]++;
+ nonmax:;
+ }
+ }
+ int min=255, total=0;
+ for(; min>0; min--) {
+ int h = histogram[min];
+ if(total+h > *count) break;
+ total += h;
+ }
+ int i=0;
+ for(int y=16; y<height-16; y++) {
+ for(int x=16; x<width-16; x++) {
+ int s = scores[y*width+x];
+ Feature f = { x+8, y+8, s, 16 };
+ if(s>min) detected[i++] = f;
+ }
+ }
+ *count = i;
+ delete[] scores;
+}
+
+}
diff --git a/extern/libmv/libmv/simple_pipeline/detect.h b/extern/libmv/libmv/simple_pipeline/detect.h
new file mode 100644
index 00000000000..bbe7aed784c
--- /dev/null
+++ b/extern/libmv/libmv/simple_pipeline/detect.h
@@ -0,0 +1,95 @@
+/****************************************************************************
+**
+** Copyright (c) 2011 libmv authors.
+**
+** 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 LIBMV_SIMPLE_PIPELINE_DETECT_H_
+#define LIBMV_SIMPLE_PIPELINE_DETECT_H_
+
+#include <vector>
+
+namespace libmv {
+
+typedef unsigned char ubyte;
+
+/*!
+ A Feature is the 2D location of a detected feature in an image.
+
+ \a x, \a y is the position of the feature in pixels from the top left corner.
+ \a score is an estimate of how well the feature will be tracked.
+ \a size can be used as an initial pattern size to track the feature.
+
+ \sa Detect
+*/
+struct Feature {
+ /// Position in pixels (from top-left corner)
+ /// \note libmv might eventually support subpixel precision.
+ float x, y;
+ /// Trackness of the feature
+ float score;
+ /// Size of the feature in pixels
+ float size;
+};
+
+/*!
+ Detect features in an image.
+
+ You need to input a single channel 8-bit image using pointer to image \a data,
+ \a width, \a height and \a stride (i.e bytes per line).
+
+ You can tweak the count of detected features using \a min_trackness, which is
+ the minimum score to add a feature, and \a min_distance which is the minimal
+ distance accepted between two featuress.
+
+ \note You can binary search over \a min_trackness to get a given feature count.
+
+ \note a way to get an uniform distribution of a given feature count is:
+ \a min_distance = \a width * \a height / desired_feature_count ^ 2
+
+ \return All detected feartures matching given parameters
+*/
+std::vector<Feature> DetectFAST(const unsigned char* data, int width, int height,
+ int stride, int min_trackness = 128,
+ int min_distance = 120);
+
+/*!
+ Detect features in an image.
+
+ \a image is a single channel 8-bit image of size \a width x \a height
+
+ \a detected is an array with space to hold \a *count features.
+ \a *count is the maximum count to detect on input and the actual
+ detected count on output.
+
+ \a distance is the minimal distance between detected features.
+
+ if \a pattern is null all good features will be found.
+ if \a pattern is not null only features similar to \a pattern will be found.
+
+ \note \a You can crop the image (to avoid detecting markers near the borders) without copying:
+ image += marginY*stride+marginX, width -= 2*marginX, height -= 2*marginY;
+*/
+void DetectMORAVEC(ubyte* image, int stride, int width, int height, Feature* detected, int* count, int distance /*=32*/, ubyte* pattern /*=0*/);
+
+}
+
+#endif
diff --git a/extern/libmv/libmv/simple_pipeline/initialize_reconstruction.cc b/extern/libmv/libmv/simple_pipeline/initialize_reconstruction.cc
new file mode 100644
index 00000000000..0597f09f728
--- /dev/null
+++ b/extern/libmv/libmv/simple_pipeline/initialize_reconstruction.cc
@@ -0,0 +1,218 @@
+// Copyright (c) 2011 libmv authors.
+//
+// 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 "libmv/base/vector.h"
+#include "libmv/logging/logging.h"
+#include "libmv/multiview/fundamental.h"
+#include "libmv/multiview/projection.h"
+#include "libmv/numeric/levenberg_marquardt.h"
+#include "libmv/numeric/numeric.h"
+#include "libmv/simple_pipeline/reconstruction.h"
+#include "libmv/simple_pipeline/tracks.h"
+
+namespace libmv {
+namespace {
+
+void CoordinatesForMarkersInImage(const vector<Marker> &markers,
+ int image,
+ Mat *coordinates) {
+ vector<Vec2> coords;
+ for (int i = 0; i < markers.size(); ++i) {
+ const Marker &marker = markers[i];
+ if (markers[i].image == image) {
+ coords.push_back(Vec2(marker.x, marker.y));
+ }
+ }
+ coordinates->resize(2, coords.size());
+ for (int i = 0; i < coords.size(); i++) {
+ coordinates->col(i) = coords[i];
+ }
+}
+
+void GetImagesInMarkers(const vector<Marker> &markers,
+ int *image1, int *image2) {
+ if (markers.size() < 2) {
+ return;
+ }
+ *image1 = markers[0].image;
+ for (int i = 1; i < markers.size(); ++i) {
+ if (markers[i].image != *image1) {
+ *image2 = markers[i].image;
+ return;
+ }
+ }
+ *image2 = -1;
+ LOG(FATAL) << "Only one image in the markers.";
+}
+
+} // namespace
+
+bool EuclideanReconstructTwoFrames(const vector<Marker> &markers,
+ EuclideanReconstruction *reconstruction) {
+ if (markers.size() < 16) {
+ return false;
+ }
+
+ int image1, image2;
+ GetImagesInMarkers(markers, &image1, &image2);
+
+ Mat x1, x2;
+ CoordinatesForMarkersInImage(markers, image1, &x1);
+ CoordinatesForMarkersInImage(markers, image2, &x2);
+
+ Mat3 F;
+ NormalizedEightPointSolver(x1, x2, &F);
+
+ // The F matrix should be an E matrix, but squash it just to be sure.
+ Eigen::JacobiSVD<Mat3> svd(F, Eigen::ComputeFullU | Eigen::ComputeFullV);
+
+ // See Hartley & Zisserman page 294, result 11.1, which shows how to get the
+ // closest essential matrix to a matrix that is "almost" an essential matrix.
+ double a = svd.singularValues()(0);
+ double b = svd.singularValues()(1);
+ double s = (a + b) / 2.0;
+ LG << "Initial reconstruction's rotation is non-euclidean by "
+ << (((a - b) / std::max(a, b)) * 100) << "%; singular values:"
+ << svd.singularValues().transpose();
+
+ Vec3 diag;
+ diag << s, s, 0;
+ Mat3 E = svd.matrixU() * diag.asDiagonal() * svd.matrixV().transpose();
+
+ // Recover motion between the two images. Since this function assumes a
+ // calibrated camera, use the identity for K.
+ Mat3 R;
+ Vec3 t;
+ Mat3 K = Mat3::Identity();
+ if (!MotionFromEssentialAndCorrespondence(E,
+ K, x1.col(0),
+ K, x2.col(0),
+ &R, &t)) {
+ return false;
+ }
+
+ // Image 1 gets the reference frame, image 2 gets the relative motion.
+ reconstruction->InsertCamera(image1, Mat3::Identity(), Vec3::Zero());
+ reconstruction->InsertCamera(image2, R, t);
+
+ LG << "From two frame reconstruction got:\nR:\n" << R
+ << "\nt:" << t.transpose();
+ return true;
+}
+
+namespace {
+
+Mat3 DecodeF(const Vec9 &encoded_F) {
+ // Decode F and force it to be rank 2.
+ Map<const Mat3> full_rank_F(encoded_F.data(), 3, 3);
+ Eigen::JacobiSVD<Mat3> svd(full_rank_F, Eigen::ComputeFullU | Eigen::ComputeFullV);
+ Vec3 diagonal = svd.singularValues();
+ diagonal(2) = 0;
+ Mat3 F = svd.matrixU() * diagonal.asDiagonal() * svd.matrixV().transpose();
+ return F;
+}
+
+// This is the stupidest way to refine F known to mankind, since it requires
+// doing a full SVD of F at each iteration. This uses sampson error.
+struct FundamentalSampsonCostFunction {
+ public:
+ typedef Vec FMatrixType;
+ typedef Vec9 XMatrixType;
+
+ // Assumes markers are ordered by track.
+ FundamentalSampsonCostFunction(const vector<Marker> &markers)
+ : markers(markers) {}
+
+ Vec operator()(const Vec9 &encoded_F) const {
+ // Decode F and force it to be rank 2.
+ Mat3 F = DecodeF(encoded_F);
+
+ Vec residuals(markers.size() / 2);
+ residuals.setZero();
+ for (int i = 0; i < markers.size() / 2; ++i) {
+ const Marker &marker1 = markers[2*i + 0];
+ const Marker &marker2 = markers[2*i + 1];
+ CHECK_EQ(marker1.track, marker2.track);
+ Vec2 x1(marker1.x, marker1.y);
+ Vec2 x2(marker2.x, marker2.y);
+
+ residuals[i] = SampsonDistance(F, x1, x2);
+ }
+ return residuals;
+ }
+ const vector<Marker> &markers;
+};
+
+} // namespace
+
+bool ProjectiveReconstructTwoFrames(const vector<Marker> &markers,
+ ProjectiveReconstruction *reconstruction) {
+ if (markers.size() < 16) {
+ return false;
+ }
+
+ int image1, image2;
+ GetImagesInMarkers(markers, &image1, &image2);
+
+ Mat x1, x2;
+ CoordinatesForMarkersInImage(markers, image1, &x1);
+ CoordinatesForMarkersInImage(markers, image2, &x2);
+
+ Mat3 F;
+ NormalizedEightPointSolver(x1, x2, &F);
+
+ // XXX Verify sampson distance.
+#if 0
+ // Refine the resulting projection fundamental matrix using Sampson's
+ // approximation of geometric error. This avoids having to do a full bundle
+ // at the cost of some accuracy.
+ //
+ // TODO(keir): After switching to a better bundling library, use a proper
+ // full bundle adjust here instead of this lame bundle adjustment.
+ typedef LevenbergMarquardt<FundamentalSampsonCostFunction> Solver;
+
+ FundamentalSampsonCostFunction fundamental_cost(markers);
+
+ // Pack the initial P matrix into a size-12 vector..
+ Vec9 encoded_F = Map<Vec9>(F.data(), 3, 3);
+
+ Solver solver(fundamental_cost);
+
+ Solver::SolverParameters params;
+ Solver::Results results = solver.minimize(params, &encoded_F);
+ // TODO(keir): Check results to ensure clean termination.
+
+ // Recover F from the minimization.
+ F = DecodeF(encoded_F);
+#endif
+
+ // Image 1 gets P = [I|0], image 2 gets arbitrary P.
+ Mat34 P1 = Mat34::Zero();
+ P1.block<3, 3>(0, 0) = Mat3::Identity();
+ Mat34 P2;
+ ProjectionsFromFundamental(F, &P1, &P2);
+
+ reconstruction->InsertCamera(image1, P1);
+ reconstruction->InsertCamera(image2, P2);
+
+ LG << "From two frame reconstruction got P2:\n" << P2;
+ return true;
+}
+} // namespace libmv
diff --git a/extern/libmv/libmv/simple_pipeline/initialize_reconstruction.h b/extern/libmv/libmv/simple_pipeline/initialize_reconstruction.h
new file mode 100644
index 00000000000..f512c9a3439
--- /dev/null
+++ b/extern/libmv/libmv/simple_pipeline/initialize_reconstruction.h
@@ -0,0 +1,74 @@
+// Copyright (c) 2011 libmv authors.
+//
+// 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 LIBMV_SIMPLE_PIPELINE_INITIALIZE_RECONSTRUCTION_H
+#define LIBMV_SIMPLE_PIPELINE_INITIALIZE_RECONSTRUCTION_H
+
+#include "libmv/base/vector.h"
+
+namespace libmv {
+
+struct Marker;
+class EuclideanReconstruction;
+class ProjectiveReconstruction;
+
+/*!
+ Initialize the \link EuclideanReconstruction reconstruction \endlink using
+ two frames.
+
+ \a markers should contain all \l Marker markers \endlink belonging to
+ tracks visible in both frames. The pose estimation of the camera for
+ these frames will be inserted into \a *reconstruction.
+
+ \note The two frames need to have both enough parallax and enough common tracks
+ for accurate reconstruction. At least 8 tracks are suggested.
+ \note The origin of the coordinate system is defined to be the camera of
+ the first keyframe.
+ \note This assumes a calibrated reconstruction, e.g. the markers are
+ already corrected for camera intrinsics and radial distortion.
+ \note This assumes an outlier-free set of markers.
+
+ \sa EuclideanResect, EuclideanIntersect, EuclideanBundle
+*/
+bool EuclideanReconstructTwoFrames(const vector<Marker> &markers,
+ EuclideanReconstruction *reconstruction);
+
+/*!
+ Initialize the \link ProjectiveReconstruction reconstruction \endlink using
+ two frames.
+
+ \a markers should contain all \l Marker markers \endlink belonging to
+ tracks visible in both frames. An estimate of the projection matrices for
+ the two frames will get added to the reconstruction.
+
+ \note The two frames need to have both enough parallax and enough common tracks
+ for accurate reconstruction. At least 8 tracks are suggested.
+ \note The origin of the coordinate system is defined to be the camera of
+ the first keyframe.
+ \note This assumes the markers are already corrected for radial distortion.
+ \note This assumes an outlier-free set of markers.
+
+ \sa ProjectiveResect, ProjectiveIntersect, ProjectiveBundle
+*/
+bool ProjectiveReconstructTwoFrames(const vector<Marker> &markers,
+ ProjectiveReconstruction *reconstruction);
+} // namespace libmv
+
+#endif // LIBMV_SIMPLE_PIPELINE_INITIALIZE_RECONSTRUCTION_H
diff --git a/extern/libmv/libmv/simple_pipeline/intersect.cc b/extern/libmv/libmv/simple_pipeline/intersect.cc
new file mode 100644
index 00000000000..b1518e04651
--- /dev/null
+++ b/extern/libmv/libmv/simple_pipeline/intersect.cc
@@ -0,0 +1,205 @@
+// Copyright (c) 2011 libmv authors.
+//
+// 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 "libmv/base/vector.h"
+#include "libmv/logging/logging.h"
+#include "libmv/multiview/projection.h"
+#include "libmv/multiview/triangulation.h"
+#include "libmv/multiview/nviewtriangulation.h"
+#include "libmv/multiview/projection.h"
+#include "libmv/numeric/numeric.h"
+#include "libmv/numeric/levenberg_marquardt.h"
+#include "libmv/simple_pipeline/reconstruction.h"
+#include "libmv/simple_pipeline/tracks.h"
+
+namespace libmv {
+
+namespace {
+
+struct EuclideanIntersectCostFunction {
+ public:
+ typedef Vec FMatrixType;
+ typedef Vec3 XMatrixType;
+
+ EuclideanIntersectCostFunction(const vector<Marker> &markers,
+ const EuclideanReconstruction &reconstruction)
+ : markers(markers),
+ reconstruction(reconstruction) {}
+
+ Vec operator()(const Vec3 &X) const {
+ Vec residuals(2 * markers.size());
+ residuals.setZero();
+ for (int i = 0; i < markers.size(); ++i) {
+ const EuclideanCamera &camera =
+ *reconstruction.CameraForImage(markers[i].image);
+ Vec3 projected = camera.R * X + camera.t;
+ projected /= projected(2);
+ residuals[2*i + 0] = projected(0) - markers[i].x;
+ residuals[2*i + 1] = projected(1) - markers[i].y;
+ }
+ return residuals;
+ }
+ const vector<Marker> &markers;
+ const EuclideanReconstruction &reconstruction;
+};
+
+} // namespace
+
+bool EuclideanIntersect(const vector<Marker> &markers,
+ EuclideanReconstruction *reconstruction) {
+ if (markers.size() < 2) {
+ return false;
+ }
+
+ // Compute projective camera matrices for the cameras the intersection is
+ // going to use.
+ Mat3 K = Mat3::Identity();
+ vector<Mat34> cameras;
+ Mat34 P;
+ for (int i = 0; i < markers.size(); ++i) {
+ EuclideanCamera *camera = reconstruction->CameraForImage(markers[i].image);
+ P_From_KRt(K, camera->R, camera->t, &P);
+ cameras.push_back(P);
+ }
+
+ // Stack the 2D coordinates together as required by NViewTriangulate.
+ Mat2X points(2, markers.size());
+ for (int i = 0; i < markers.size(); ++i) {
+ points(0, i) = markers[i].x;
+ points(1, i) = markers[i].y;
+ }
+
+ Vec4 Xp;
+ LG << "Intersecting with " << markers.size() << " markers.";
+ NViewTriangulateAlgebraic(points, cameras, &Xp);
+
+ // Get euclidean version of the homogeneous point.
+ Xp /= Xp(3);
+ Vec3 X = Xp.head<3>();
+
+ typedef LevenbergMarquardt<EuclideanIntersectCostFunction> Solver;
+
+ EuclideanIntersectCostFunction triangulate_cost(markers, *reconstruction);
+ Solver::SolverParameters params;
+ Solver solver(triangulate_cost);
+
+ Solver::Results results = solver.minimize(params, &X);
+
+ // Try projecting the point; make sure it's in front of everyone.
+ for (int i = 0; i < cameras.size(); ++i) {
+ const EuclideanCamera &camera =
+ *reconstruction->CameraForImage(markers[i].image);
+ Vec3 x = camera.R * X + camera.t;
+ if (x(2) < 0) {
+ LOG(ERROR) << "POINT BEHIND CAMERA " << markers[i].image
+ << ": " << x.transpose();
+ }
+ }
+
+ Vec3 point = X.head<3>();
+ reconstruction->InsertPoint(markers[0].track, point);
+
+ // TODO(keir): Add proper error checking.
+ return true;
+}
+
+namespace {
+
+struct ProjectiveIntersectCostFunction {
+ public:
+ typedef Vec FMatrixType;
+ typedef Vec4 XMatrixType;
+
+ ProjectiveIntersectCostFunction(
+ const vector<Marker> &markers,
+ const ProjectiveReconstruction &reconstruction)
+ : markers(markers), reconstruction(reconstruction) {}
+
+ Vec operator()(const Vec4 &X) const {
+ Vec residuals(2 * markers.size());
+ residuals.setZero();
+ for (int i = 0; i < markers.size(); ++i) {
+ const ProjectiveCamera &camera =
+ *reconstruction.CameraForImage(markers[i].image);
+ Vec3 projected = camera.P * X;
+ projected /= projected(2);
+ residuals[2*i + 0] = projected(0) - markers[i].x;
+ residuals[2*i + 1] = projected(1) - markers[i].y;
+ }
+ return residuals;
+ }
+ const vector<Marker> &markers;
+ const ProjectiveReconstruction &reconstruction;
+};
+
+} // namespace
+
+bool ProjectiveIntersect(const vector<Marker> &markers,
+ ProjectiveReconstruction *reconstruction) {
+ if (markers.size() < 2) {
+ return false;
+ }
+
+ // Get the cameras to use for the intersection.
+ vector<Mat34> cameras;
+ for (int i = 0; i < markers.size(); ++i) {
+ ProjectiveCamera *camera = reconstruction->CameraForImage(markers[i].image);
+ cameras.push_back(camera->P);
+ }
+
+ // Stack the 2D coordinates together as required by NViewTriangulate.
+ Mat2X points(2, markers.size());
+ for (int i = 0; i < markers.size(); ++i) {
+ points(0, i) = markers[i].x;
+ points(1, i) = markers[i].y;
+ }
+
+ Vec4 X;
+ LG << "Intersecting with " << markers.size() << " markers.";
+ NViewTriangulateAlgebraic(points, cameras, &X);
+ X /= X(3);
+
+ typedef LevenbergMarquardt<ProjectiveIntersectCostFunction> Solver;
+
+ ProjectiveIntersectCostFunction triangulate_cost(markers, *reconstruction);
+ Solver::SolverParameters params;
+ Solver solver(triangulate_cost);
+
+ Solver::Results results = solver.minimize(params, &X);
+ (void) results; // TODO(keir): Ensure results are good.
+
+ // Try projecting the point; make sure it's in front of everyone.
+ for (int i = 0; i < cameras.size(); ++i) {
+ const ProjectiveCamera &camera =
+ *reconstruction->CameraForImage(markers[i].image);
+ Vec3 x = camera.P * X;
+ if (x(2) < 0) {
+ LOG(ERROR) << "POINT BEHIND CAMERA " << markers[i].image
+ << ": " << x.transpose();
+ }
+ }
+
+ reconstruction->InsertPoint(markers[0].track, X);
+
+ // TODO(keir): Add proper error checking.
+ return true;
+}
+
+} // namespace libmv
diff --git a/extern/libmv/libmv/simple_pipeline/intersect.h b/extern/libmv/libmv/simple_pipeline/intersect.h
new file mode 100644
index 00000000000..edbf4a0335b
--- /dev/null
+++ b/extern/libmv/libmv/simple_pipeline/intersect.h
@@ -0,0 +1,77 @@
+// Copyright (c) 2011 libmv authors.
+//
+// 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 LIBMV_SIMPLE_PIPELINE_INTERSECT_H
+#define LIBMV_SIMPLE_PIPELINE_INTERSECT_H
+
+#include "libmv/base/vector.h"
+#include "libmv/simple_pipeline/tracks.h"
+#include "libmv/simple_pipeline/reconstruction.h"
+
+namespace libmv {
+
+/*!
+ Estimate the 3D coordinates of a track by intersecting rays from images.
+
+ This takes a set of markers, where each marker is for the same track but
+ different images, and reconstructs the 3D position of that track. Each of
+ the frames for which there is a marker for that track must have a
+ corresponding reconstructed camera in \a *reconstruction.
+
+ \a markers should contain all \l Marker markers \endlink belonging to
+ tracks visible in all frames.
+ \a reconstruction should contain the cameras for all frames.
+ The new \l Point points \endlink will be inserted in \a reconstruction.
+
+ \note This assumes a calibrated reconstruction, e.g. the markers are
+ already corrected for camera intrinsics and radial distortion.
+ \note This assumes an outlier-free set of markers.
+
+ \sa EuclideanResect
+*/
+bool EuclideanIntersect(const vector<Marker> &markers,
+ EuclideanReconstruction *reconstruction);
+
+/*!
+ Estimate the homogeneous coordinates of a track by intersecting rays.
+
+ This takes a set of markers, where each marker is for the same track but
+ different images, and reconstructs the homogeneous 3D position of that
+ track. Each of the frames for which there is a marker for that track must
+ have a corresponding reconstructed camera in \a *reconstruction.
+
+ \a markers should contain all \l Marker markers \endlink belonging to
+ tracks visible in all frames.
+ \a reconstruction should contain the cameras for all frames.
+ The new \l Point points \endlink will be inserted in \a reconstruction.
+
+ \note This assumes that radial distortion is already corrected for, but
+ does not assume that e.g. focal length and principal point are
+ accounted for.
+ \note This assumes an outlier-free set of markers.
+
+ \sa Resect
+*/
+bool ProjectiveIntersect(const vector<Marker> &markers,
+ ProjectiveReconstruction *reconstruction);
+
+} // namespace libmv
+
+#endif // LIBMV_SIMPLE_PIPELINE_INTERSECT_H
diff --git a/extern/libmv/libmv/simple_pipeline/pipeline.cc b/extern/libmv/libmv/simple_pipeline/pipeline.cc
new file mode 100644
index 00000000000..818c24cb5e7
--- /dev/null
+++ b/extern/libmv/libmv/simple_pipeline/pipeline.cc
@@ -0,0 +1,317 @@
+// Copyright (c) 2011 libmv authors.
+//
+// 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 <cstdio>
+
+#include "libmv/logging/logging.h"
+#include "libmv/simple_pipeline/bundle.h"
+#include "libmv/simple_pipeline/intersect.h"
+#include "libmv/simple_pipeline/resect.h"
+#include "libmv/simple_pipeline/reconstruction.h"
+#include "libmv/simple_pipeline/tracks.h"
+#include "libmv/simple_pipeline/camera_intrinsics.h"
+
+#ifdef _MSC_VER
+# define snprintf _snprintf
+#endif
+
+namespace libmv {
+namespace {
+
+// These are "strategy" classes which make it possible to use the same code for
+// both projective and euclidean reconstruction.
+// FIXME(MatthiasF): OOP would achieve the same goal while avoiding
+// template bloat and making interface changes much easier.
+struct EuclideanPipelineRoutines {
+ typedef EuclideanReconstruction Reconstruction;
+ typedef EuclideanCamera Camera;
+ typedef EuclideanPoint Point;
+
+ static void Bundle(const Tracks &tracks,
+ EuclideanReconstruction *reconstruction) {
+ EuclideanBundle(tracks, reconstruction);
+ }
+
+ static bool Resect(const vector<Marker> &markers,
+ EuclideanReconstruction *reconstruction, bool final_pass) {
+ return EuclideanResect(markers, reconstruction, final_pass);
+ }
+
+ static bool Intersect(const vector<Marker> &markers,
+ EuclideanReconstruction *reconstruction) {
+ return EuclideanIntersect(markers, reconstruction);
+ }
+
+ static Marker ProjectMarker(const EuclideanPoint &point,
+ const EuclideanCamera &camera,
+ const CameraIntrinsics &intrinsics) {
+ Vec3 projected = camera.R * point.X + camera.t;
+ projected /= projected(2);
+
+ Marker reprojected_marker;
+ intrinsics.ApplyIntrinsics(projected(0),
+ projected(1),
+ &reprojected_marker.x,
+ &reprojected_marker.y);
+
+ reprojected_marker.image = camera.image;
+ reprojected_marker.track = point.track;
+ return reprojected_marker;
+ }
+};
+
+struct ProjectivePipelineRoutines {
+ typedef ProjectiveReconstruction Reconstruction;
+ typedef ProjectiveCamera Camera;
+ typedef ProjectivePoint Point;
+
+ static void Bundle(const Tracks &tracks,
+ ProjectiveReconstruction *reconstruction) {
+ ProjectiveBundle(tracks, reconstruction);
+ }
+
+ static bool Resect(const vector<Marker> &markers,
+ ProjectiveReconstruction *reconstruction, bool final_pass) {
+ return ProjectiveResect(markers, reconstruction);
+ }
+
+ static bool Intersect(const vector<Marker> &markers,
+ ProjectiveReconstruction *reconstruction) {
+ return ProjectiveIntersect(markers, reconstruction);
+ }
+
+ static Marker ProjectMarker(const ProjectivePoint &point,
+ const ProjectiveCamera &camera,
+ const CameraIntrinsics &intrinsics) {
+ Vec3 projected = camera.P * point.X;
+ projected /= projected(2);
+
+ Marker reprojected_marker;
+ intrinsics.ApplyIntrinsics(projected(0),
+ projected(1),
+ &reprojected_marker.x,
+ &reprojected_marker.y);
+
+ reprojected_marker.image = camera.image;
+ reprojected_marker.track = point.track;
+ return reprojected_marker;
+ }
+};
+
+} // namespace
+
+template<typename PipelineRoutines>
+void InternalCompleteReconstruction(
+ const Tracks &tracks,
+ typename PipelineRoutines::Reconstruction *reconstruction) {
+ int max_track = tracks.MaxTrack();
+ int max_image = tracks.MaxImage();
+ int num_resects = -1;
+ int num_intersects = -1;
+ LG << "Max track: " << max_track;
+ LG << "Max image: " << max_image;
+ LG << "Number of markers: " << tracks.NumMarkers();
+ while (num_resects != 0 || num_intersects != 0) {
+ // Do all possible intersections.
+ num_intersects = 0;
+ for (int track = 0; track <= max_track; ++track) {
+ if (reconstruction->PointForTrack(track)) {
+ LG << "Skipping point: " << track;
+ continue;
+ }
+ vector<Marker> all_markers = tracks.MarkersForTrack(track);
+ LG << "Got " << all_markers.size() << " markers for track " << track;
+
+ vector<Marker> reconstructed_markers;
+ for (int i = 0; i < all_markers.size(); ++i) {
+ if (reconstruction->CameraForImage(all_markers[i].image)) {
+ reconstructed_markers.push_back(all_markers[i]);
+ }
+ }
+ LG << "Got " << reconstructed_markers.size()
+ << " reconstructed markers for track " << track;
+ if (reconstructed_markers.size() >= 2) {
+ PipelineRoutines::Intersect(reconstructed_markers, reconstruction);
+ num_intersects++;
+ LG << "Ran Intersect() for track " << track;
+ }
+ }
+ if (num_intersects) {
+ PipelineRoutines::Bundle(tracks, reconstruction);
+ LG << "Ran Bundle() after intersections.";
+ }
+ LG << "Did " << num_intersects << " intersects.";
+
+ // Do all possible resections.
+ num_resects = 0;
+ for (int image = 0; image <= max_image; ++image) {
+ if (reconstruction->CameraForImage(image)) {
+ LG << "Skipping frame: " << image;
+ continue;
+ }
+ vector<Marker> all_markers = tracks.MarkersInImage(image);
+ LG << "Got " << all_markers.size() << " markers for image " << image;
+
+ vector<Marker> reconstructed_markers;
+ for (int i = 0; i < all_markers.size(); ++i) {
+ if (reconstruction->PointForTrack(all_markers[i].track)) {
+ reconstructed_markers.push_back(all_markers[i]);
+ }
+ }
+ LG << "Got " << reconstructed_markers.size()
+ << " reconstructed markers for image " << image;
+ if (reconstructed_markers.size() >= 5) {
+ if (PipelineRoutines::Resect(reconstructed_markers, reconstruction, false)) {
+ num_resects++;
+ LG << "Ran Resect() for image " << image;
+ } else {
+ LG << "Failed Resect() for image " << image;
+ }
+ }
+ }
+ if (num_resects) {
+ PipelineRoutines::Bundle(tracks, reconstruction);
+ }
+ LG << "Did " << num_resects << " resects.";
+ }
+
+ // One last pass...
+ num_resects = 0;
+ for (int image = 0; image <= max_image; ++image) {
+ if (reconstruction->CameraForImage(image)) {
+ LG << "Skipping frame: " << image;
+ continue;
+ }
+ vector<Marker> all_markers = tracks.MarkersInImage(image);
+
+ vector<Marker> reconstructed_markers;
+ for (int i = 0; i < all_markers.size(); ++i) {
+ if (reconstruction->PointForTrack(all_markers[i].track)) {
+ reconstructed_markers.push_back(all_markers[i]);
+ }
+ }
+ if (reconstructed_markers.size() >= 5) {
+ if (PipelineRoutines::Resect(reconstructed_markers, reconstruction, true)) {
+ num_resects++;
+ LG << "Ran Resect() for image " << image;
+ } else {
+ LG << "Failed Resect() for image " << image;
+ }
+ }
+ }
+ if (num_resects) {
+ PipelineRoutines::Bundle(tracks, reconstruction);
+ }
+}
+
+template<typename PipelineRoutines>
+double InternalReprojectionError(const Tracks &image_tracks,
+ const typename PipelineRoutines::Reconstruction &reconstruction,
+ const CameraIntrinsics &intrinsics) {
+ int num_skipped = 0;
+ int num_reprojected = 0;
+ double total_error = 0.0;
+ vector<Marker> markers = image_tracks.AllMarkers();
+ for (int i = 0; i < markers.size(); ++i) {
+ const typename PipelineRoutines::Camera *camera =
+ reconstruction.CameraForImage(markers[i].image);
+ const typename PipelineRoutines::Point *point =
+ reconstruction.PointForTrack(markers[i].track);
+ if (!camera || !point) {
+ num_skipped++;
+ continue;
+ }
+ num_reprojected++;
+
+ Marker reprojected_marker =
+ PipelineRoutines::ProjectMarker(*point, *camera, intrinsics);
+ double ex = reprojected_marker.x - markers[i].x;
+ double ey = reprojected_marker.y - markers[i].y;
+
+ const int N = 100;
+ char line[N];
+ snprintf(line, N,
+ "image %-3d track %-3d "
+ "x %7.1f y %7.1f "
+ "rx %7.1f ry %7.1f "
+ "ex %7.1f ey %7.1f"
+ " e %7.1f",
+ markers[i].image,
+ markers[i].track,
+ markers[i].x,
+ markers[i].y,
+ reprojected_marker.x,
+ reprojected_marker.y,
+ ex,
+ ey,
+ sqrt(ex*ex + ey*ey));
+ //LG << line;
+ total_error += sqrt(ex*ex + ey*ey);
+ }
+ LG << "Skipped " << num_skipped << " markers.";
+ LG << "Reprojected " << num_reprojected << " markers.";
+ LG << "Total error: " << total_error;
+ LG << "Average error: " << (total_error / num_reprojected) << " [pixels].";
+ return total_error / num_reprojected;
+}
+
+double EuclideanReprojectionError(const Tracks &image_tracks,
+ const EuclideanReconstruction &reconstruction,
+ const CameraIntrinsics &intrinsics) {
+ return InternalReprojectionError<EuclideanPipelineRoutines>(image_tracks,
+ reconstruction,
+ intrinsics);
+}
+
+double ProjectiveReprojectionError(
+ const Tracks &image_tracks,
+ const ProjectiveReconstruction &reconstruction,
+ const CameraIntrinsics &intrinsics) {
+ return InternalReprojectionError<ProjectivePipelineRoutines>(image_tracks,
+ reconstruction,
+ intrinsics);
+}
+
+void EuclideanCompleteReconstruction(const Tracks &tracks,
+ EuclideanReconstruction *reconstruction) {
+ InternalCompleteReconstruction<EuclideanPipelineRoutines>(tracks,
+ reconstruction);
+}
+
+void ProjectiveCompleteReconstruction(const Tracks &tracks,
+ ProjectiveReconstruction *reconstruction) {
+ InternalCompleteReconstruction<ProjectivePipelineRoutines>(tracks,
+ reconstruction);
+}
+
+void InvertIntrinsicsForTracks(const Tracks &raw_tracks,
+ const CameraIntrinsics &camera_intrinsics,
+ Tracks *calibrated_tracks) {
+ vector<Marker> markers = raw_tracks.AllMarkers();
+ for (int i = 0; i < markers.size(); ++i) {
+ camera_intrinsics.InvertIntrinsics(markers[i].x,
+ markers[i].y,
+ &(markers[i].x),
+ &(markers[i].y));
+ }
+ *calibrated_tracks = Tracks(markers);
+}
+
+} // namespace libmv
diff --git a/extern/libmv/libmv/simple_pipeline/pipeline.h b/extern/libmv/libmv/simple_pipeline/pipeline.h
new file mode 100644
index 00000000000..b7dfcb7993a
--- /dev/null
+++ b/extern/libmv/libmv/simple_pipeline/pipeline.h
@@ -0,0 +1,95 @@
+// Copyright (c) 2011 libmv authors.
+//
+// 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 LIBMV_SIMPLE_PIPELINE_PIPELINE_H_
+#define LIBMV_SIMPLE_PIPELINE_PIPELINE_H_
+
+#include "libmv/simple_pipeline/tracks.h"
+#include "libmv/simple_pipeline/reconstruction.h"
+
+namespace libmv {
+
+/*!
+ Estimate camera poses and scene 3D coordinates for all frames and tracks.
+
+ This method should be used once there is an initial reconstruction in
+ place, for example by reconstructing from two frames that have a sufficient
+ baseline and number of tracks in common. This function iteratively
+ triangulates points that are visible by cameras that have their pose
+ estimated, then resections (i.e. estimates the pose) of cameras that are
+ not estimated yet that can see triangulated points. This process is
+ repeated until all points and cameras are estimated. Periodically, bundle
+ adjustment is run to ensure a quality reconstruction.
+
+ \a tracks should contain markers used in the reconstruction.
+ \a reconstruction should contain at least some 3D points or some estimated
+ cameras. The minimum number of cameras is two (with no 3D points) and the
+ minimum number of 3D points (with no estimated cameras) is 5.
+
+ \sa EuclideanResect, EuclideanIntersect, EuclideanBundle
+*/
+void EuclideanCompleteReconstruction(const Tracks &tracks,
+ EuclideanReconstruction *reconstruction);
+
+/*!
+ Estimate camera matrices and homogeneous 3D coordinates for all frames and
+ tracks.
+
+ This method should be used once there is an initial reconstruction in
+ place, for example by reconstructing from two frames that have a sufficient
+ baseline and number of tracks in common. This function iteratively
+ triangulates points that are visible by cameras that have their pose
+ estimated, then resections (i.e. estimates the pose) of cameras that are
+ not estimated yet that can see triangulated points. This process is
+ repeated until all points and cameras are estimated. Periodically, bundle
+ adjustment is run to ensure a quality reconstruction.
+
+ \a tracks should contain markers used in the reconstruction.
+ \a reconstruction should contain at least some 3D points or some estimated
+ cameras. The minimum number of cameras is two (with no 3D points) and the
+ minimum number of 3D points (with no estimated cameras) is 5.
+
+ \sa ProjectiveResect, ProjectiveIntersect, ProjectiveBundle
+*/
+void ProjectiveCompleteReconstruction(const Tracks &tracks,
+ ProjectiveReconstruction *reconstruction);
+
+
+class CameraIntrinsics;
+
+// TODO(keir): Decide if we want these in the public API, and if so, what the
+// appropriate include file is.
+
+double EuclideanReprojectionError(const Tracks &image_tracks,
+ const EuclideanReconstruction &reconstruction,
+ const CameraIntrinsics &intrinsics);
+
+double ProjectiveReprojectionError(
+ const Tracks &image_tracks,
+ const ProjectiveReconstruction &reconstruction,
+ const CameraIntrinsics &intrinsics);
+
+void InvertIntrinsicsForTracks(const Tracks &raw_tracks,
+ const CameraIntrinsics &camera_intrinsics,
+ Tracks *calibrated_tracks);
+
+} // namespace libmv
+
+#endif // LIBMV_SIMPLE_PIPELINE_PIPELINE_H_
diff --git a/extern/libmv/libmv/simple_pipeline/reconstruction.cc b/extern/libmv/libmv/simple_pipeline/reconstruction.cc
new file mode 100644
index 00000000000..65e5dd27d5d
--- /dev/null
+++ b/extern/libmv/libmv/simple_pipeline/reconstruction.cc
@@ -0,0 +1,191 @@
+// Copyright (c) 2011 libmv authors.
+//
+// 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 "libmv/simple_pipeline/reconstruction.h"
+#include "libmv/numeric/numeric.h"
+#include "libmv/logging/logging.h"
+
+namespace libmv {
+
+EuclideanReconstruction::EuclideanReconstruction() {}
+EuclideanReconstruction::EuclideanReconstruction(
+ const EuclideanReconstruction &other) {
+ cameras_ = other.cameras_;
+ points_ = other.points_;
+}
+
+EuclideanReconstruction &EuclideanReconstruction::operator=(
+ const EuclideanReconstruction &other) {
+ if (&other != this) {
+ cameras_ = other.cameras_;
+ points_ = other.points_;
+ }
+ return *this;
+}
+
+void EuclideanReconstruction::InsertCamera(int image,
+ const Mat3 &R,
+ const Vec3 &t) {
+ LG << "InsertCamera " << image << ":\nR:\n"<< R << "\nt:\n" << t;
+ if (image >= cameras_.size()) {
+ cameras_.resize(image + 1);
+ }
+ cameras_[image].image = image;
+ cameras_[image].R = R;
+ cameras_[image].t = t;
+}
+
+void EuclideanReconstruction::InsertPoint(int track, const Vec3 &X) {
+ LG << "InsertPoint " << track << ":\n" << X;
+ if (track >= points_.size()) {
+ points_.resize(track + 1);
+ }
+ points_[track].track = track;
+ points_[track].X = X;
+}
+
+EuclideanCamera *EuclideanReconstruction::CameraForImage(int image) {
+ return const_cast<EuclideanCamera *>(
+ static_cast<const EuclideanReconstruction *>(
+ this)->CameraForImage(image));
+}
+
+const EuclideanCamera *EuclideanReconstruction::CameraForImage(
+ int image) const {
+ if (image < 0 || image >= cameras_.size()) {
+ return NULL;
+ }
+ const EuclideanCamera *camera = &cameras_[image];
+ if (camera->image == -1) {
+ return NULL;
+ }
+ return camera;
+}
+
+vector<EuclideanCamera> EuclideanReconstruction::AllCameras() const {
+ vector<EuclideanCamera> cameras;
+ for (int i = 0; i < cameras_.size(); ++i) {
+ if (cameras_[i].image != -1) {
+ cameras.push_back(cameras_[i]);
+ }
+ }
+ return cameras;
+}
+
+EuclideanPoint *EuclideanReconstruction::PointForTrack(int track) {
+ return const_cast<EuclideanPoint *>(
+ static_cast<const EuclideanReconstruction *>(this)->PointForTrack(track));
+}
+
+const EuclideanPoint *EuclideanReconstruction::PointForTrack(int track) const {
+ if (track < 0 || track >= points_.size()) {
+ return NULL;
+ }
+ const EuclideanPoint *point = &points_[track];
+ if (point->track == -1) {
+ return NULL;
+ }
+ return point;
+}
+
+vector<EuclideanPoint> EuclideanReconstruction::AllPoints() const {
+ vector<EuclideanPoint> points;
+ for (int i = 0; i < points_.size(); ++i) {
+ if (points_[i].track != -1) {
+ points.push_back(points_[i]);
+ }
+ }
+ return points;
+}
+
+void ProjectiveReconstruction::InsertCamera(int image,
+ const Mat34 &P) {
+ LG << "InsertCamera " << image << ":\nP:\n"<< P;
+ if (image >= cameras_.size()) {
+ cameras_.resize(image + 1);
+ }
+ cameras_[image].image = image;
+ cameras_[image].P = P;
+}
+
+void ProjectiveReconstruction::InsertPoint(int track, const Vec4 &X) {
+ LG << "InsertPoint " << track << ":\n" << X;
+ if (track >= points_.size()) {
+ points_.resize(track + 1);
+ }
+ points_[track].track = track;
+ points_[track].X = X;
+}
+
+ProjectiveCamera *ProjectiveReconstruction::CameraForImage(int image) {
+ return const_cast<ProjectiveCamera *>(
+ static_cast<const ProjectiveReconstruction *>(
+ this)->CameraForImage(image));
+}
+
+const ProjectiveCamera *ProjectiveReconstruction::CameraForImage(
+ int image) const {
+ if (image < 0 || image >= cameras_.size()) {
+ return NULL;
+ }
+ const ProjectiveCamera *camera = &cameras_[image];
+ if (camera->image == -1) {
+ return NULL;
+ }
+ return camera;
+}
+
+vector<ProjectiveCamera> ProjectiveReconstruction::AllCameras() const {
+ vector<ProjectiveCamera> cameras;
+ for (int i = 0; i < cameras_.size(); ++i) {
+ if (cameras_[i].image != -1) {
+ cameras.push_back(cameras_[i]);
+ }
+ }
+ return cameras;
+}
+
+ProjectivePoint *ProjectiveReconstruction::PointForTrack(int track) {
+ return const_cast<ProjectivePoint *>(
+ static_cast<const ProjectiveReconstruction *>(this)->PointForTrack(track));
+}
+
+const ProjectivePoint *ProjectiveReconstruction::PointForTrack(int track) const {
+ if (track < 0 || track >= points_.size()) {
+ return NULL;
+ }
+ const ProjectivePoint *point = &points_[track];
+ if (point->track == -1) {
+ return NULL;
+ }
+ return point;
+}
+
+vector<ProjectivePoint> ProjectiveReconstruction::AllPoints() const {
+ vector<ProjectivePoint> points;
+ for (int i = 0; i < points_.size(); ++i) {
+ if (points_[i].track != -1) {
+ points.push_back(points_[i]);
+ }
+ }
+ return points;
+}
+
+} // namespace libmv
diff --git a/extern/libmv/libmv/simple_pipeline/reconstruction.h b/extern/libmv/libmv/simple_pipeline/reconstruction.h
new file mode 100644
index 00000000000..947a0636476
--- /dev/null
+++ b/extern/libmv/libmv/simple_pipeline/reconstruction.h
@@ -0,0 +1,217 @@
+// Copyright (c) 2011 libmv authors.
+//
+// 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 LIBMV_SIMPLE_PIPELINE_RECONSTRUCTION_H_
+#define LIBMV_SIMPLE_PIPELINE_RECONSTRUCTION_H_
+
+#include "libmv/base/vector.h"
+#include "libmv/numeric/numeric.h"
+
+namespace libmv {
+
+/*!
+ A EuclideanCamera is the location and rotation of the camera viewing \a image.
+
+ \a image identify which image from \l Tracks this camera represents.
+ \a R is a 3x3 matrix representing the rotation of the camera.
+ \a t is a translation vector representing its positions.
+
+ \sa Reconstruction
+*/
+struct EuclideanCamera {
+ EuclideanCamera() : image(-1) {}
+ EuclideanCamera(const EuclideanCamera &c) : image(c.image), R(c.R), t(c.t) {}
+
+ int image;
+ Mat3 R;
+ Vec3 t;
+};
+
+/*!
+ A Point is the 3D location of a track.
+
+ \a track identify which track from \l Tracks this point corresponds to.
+ \a X represents the 3D position of the track.
+
+ \sa Reconstruction
+*/
+struct EuclideanPoint {
+ EuclideanPoint() : track(-1) {}
+ EuclideanPoint(const EuclideanPoint &p) : track(p.track), X(p.X) {}
+ int track;
+ Vec3 X;
+};
+
+/*!
+ The EuclideanReconstruction class stores \link EuclideanCamera cameras
+ \endlink and \link EuclideanPoint points \endlink.
+
+ The EuclideanReconstruction container is intended as the store of 3D
+ reconstruction data to be used with the MultiView API.
+
+ The container has lookups to query a \a EuclideanCamera from an \a image or
+ a \a EuclideanPoint from a \a track.
+
+ \sa Camera, Point
+*/
+class EuclideanReconstruction {
+ public:
+ // Default constructor starts with no cameras.
+ EuclideanReconstruction();
+
+ /// Copy constructor.
+ EuclideanReconstruction(const EuclideanReconstruction &other);
+
+ EuclideanReconstruction &operator=(const EuclideanReconstruction &other);
+
+ /*!
+ Insert a camera into the set. If there is already a camera for the given
+ \a image, the existing camera is replaced. If there is no camera for the
+ given \a image, a new one is added.
+
+ \a image is the key used to retrieve the cameras with the other methods
+ in this class.
+
+ \note You should use the same \a image identifier as in \l Tracks.
+ */
+ void InsertCamera(int image, const Mat3 &R, const Vec3 &t);
+
+ /*!
+ Insert a point into the reconstruction. If there is already a point for
+ the given \a track, the existing point is replaced. If there is no point
+ for the given \a track, a new one is added.
+
+ \a track is the key used to retrieve the points with the
+ other methods in this class.
+
+ \note You should use the same \a track identifier as in \l Tracks.
+ */
+ void InsertPoint(int track, const Vec3 &X);
+
+ /// Returns a pointer to the camera corresponding to \a image.
+ EuclideanCamera *CameraForImage(int image);
+ const EuclideanCamera *CameraForImage(int image) const;
+
+ /// Returns all cameras.
+ vector<EuclideanCamera> AllCameras() const;
+
+ /// Returns a pointer to the point corresponding to \a track.
+ EuclideanPoint *PointForTrack(int track);
+ const EuclideanPoint *PointForTrack(int track) const;
+
+ /// Returns all points.
+ vector<EuclideanPoint> AllPoints() const;
+
+ private:
+ vector<EuclideanCamera> cameras_;
+ vector<EuclideanPoint> points_;
+};
+
+/*!
+ A ProjectiveCamera is the projection matrix for the camera of \a image.
+
+ \a image identify which image from \l Tracks this camera represents.
+ \a P is the 3x4 projection matrix.
+
+ \sa ProjectiveReconstruction
+*/
+struct ProjectiveCamera {
+ ProjectiveCamera() : image(-1) {}
+ ProjectiveCamera(const ProjectiveCamera &c) : image(c.image), P(c.P) {}
+
+ int image;
+ Mat34 P;
+};
+
+/*!
+ A Point is the 3D location of a track.
+
+ \a track identifies which track from \l Tracks this point corresponds to.
+ \a X is the homogeneous 3D position of the track.
+
+ \sa Reconstruction
+*/
+struct ProjectivePoint {
+ ProjectivePoint() : track(-1) {}
+ ProjectivePoint(const ProjectivePoint &p) : track(p.track), X(p.X) {}
+ int track;
+ Vec4 X;
+};
+
+/*!
+ The ProjectiveReconstruction class stores \link ProjectiveCamera cameras
+ \endlink and \link ProjectivePoint points \endlink.
+
+ The ProjectiveReconstruction container is intended as the store of 3D
+ reconstruction data to be used with the MultiView API.
+
+ The container has lookups to query a \a ProjectiveCamera from an \a image or
+ a \a ProjectivePoint from a \a track.
+
+ \sa Camera, Point
+*/
+class ProjectiveReconstruction {
+ public:
+ /*!
+ Insert a camera into the set. If there is already a camera for the given
+ \a image, the existing camera is replaced. If there is no camera for the
+ given \a image, a new one is added.
+
+ \a image is the key used to retrieve the cameras with the other methods
+ in this class.
+
+ \note You should use the same \a image identifier as in \l Tracks.
+ */
+ void InsertCamera(int image, const Mat34 &P);
+
+ /*!
+ Insert a point into the reconstruction. If there is already a point for
+ the given \a track, the existing point is replaced. If there is no point
+ for the given \a track, a new one is added.
+
+ \a track is the key used to retrieve the points with the
+ other methods in this class.
+
+ \note You should use the same \a track identifier as in \l Tracks.
+ */
+ void InsertPoint(int track, const Vec4 &X);
+
+ /// Returns a pointer to the camera corresponding to \a image.
+ ProjectiveCamera *CameraForImage(int image);
+ const ProjectiveCamera *CameraForImage(int image) const;
+
+ /// Returns all cameras.
+ vector<ProjectiveCamera> AllCameras() const;
+
+ /// Returns a pointer to the point corresponding to \a track.
+ ProjectivePoint *PointForTrack(int track);
+ const ProjectivePoint *PointForTrack(int track) const;
+
+ /// Returns all points.
+ vector<ProjectivePoint> AllPoints() const;
+
+ private:
+ vector<ProjectiveCamera> cameras_;
+ vector<ProjectivePoint> points_;
+};
+
+} // namespace libmv
+
+#endif // LIBMV_SIMPLE_PIPELINE_RECONSTRUCTION_H_
diff --git a/extern/libmv/libmv/simple_pipeline/resect.cc b/extern/libmv/libmv/simple_pipeline/resect.cc
new file mode 100644
index 00000000000..6e71c3c7206
--- /dev/null
+++ b/extern/libmv/libmv/simple_pipeline/resect.cc
@@ -0,0 +1,271 @@
+// Copyright (c) 2011 libmv authors.
+//
+// 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 <cstdio>
+
+#include "libmv/base/vector.h"
+#include "libmv/logging/logging.h"
+#include "libmv/multiview/euclidean_resection.h"
+#include "libmv/multiview/resection.h"
+#include "libmv/multiview/projection.h"
+#include "libmv/numeric/numeric.h"
+#include "libmv/numeric/levenberg_marquardt.h"
+#include "libmv/simple_pipeline/reconstruction.h"
+#include "libmv/simple_pipeline/tracks.h"
+
+namespace libmv {
+namespace {
+
+Mat2X PointMatrixFromMarkers(const vector<Marker> &markers) {
+ Mat2X points(2, markers.size());
+ for (int i = 0; i < markers.size(); ++i) {
+ points(0, i) = markers[i].x;
+ points(1, i) = markers[i].y;
+ }
+ return points;
+}
+
+Mat3 RotationFromEulerVector(Vec3 euler_vector) {
+ double theta = euler_vector.norm();
+ if (theta == 0.0) {
+ return Mat3::Identity();
+ }
+ Vec3 w = euler_vector / theta;
+ Mat3 w_hat = CrossProductMatrix(w);
+ return Mat3::Identity() + w_hat*sin(theta) + w_hat*w_hat*(1 - cos(theta));
+}
+
+// Uses an incremental rotation:
+//
+// x = R' * R * X + t;
+//
+// to avoid issues with the rotation representation. R' is derived from a
+// euler vector encoding the rotation in 3 parameters; the direction is the
+// axis to rotate around and the magnitude is the amount of the rotation.
+struct EuclideanResectCostFunction {
+ public:
+ typedef Vec FMatrixType;
+ typedef Vec6 XMatrixType;
+
+ EuclideanResectCostFunction(const vector<Marker> &markers,
+ const EuclideanReconstruction &reconstruction,
+ const Mat3 initial_R)
+ : markers(markers),
+ reconstruction(reconstruction),
+ initial_R(initial_R) {}
+
+ // dRt has dR (delta R) encoded as a euler vector in the first 3 parameters,
+ // followed by t in the next 3 parameters.
+ Vec operator()(const Vec6 &dRt) const {
+ // Unpack R, t from dRt.
+ Mat3 R = RotationFromEulerVector(dRt.head<3>()) * initial_R;
+ Vec3 t = dRt.tail<3>();
+
+ // Compute the reprojection error for each coordinate.
+ Vec residuals(2 * markers.size());
+ residuals.setZero();
+ for (int i = 0; i < markers.size(); ++i) {
+ const EuclideanPoint &point =
+ *reconstruction.PointForTrack(markers[i].track);
+ Vec3 projected = R * point.X + t;
+ projected /= projected(2);
+ residuals[2*i + 0] = projected(0) - markers[i].x;
+ residuals[2*i + 1] = projected(1) - markers[i].y;
+ }
+ return residuals;
+ }
+
+ const vector<Marker> &markers;
+ const EuclideanReconstruction &reconstruction;
+ const Mat3 &initial_R;
+};
+
+} // namespace
+
+bool EuclideanResect(const vector<Marker> &markers,
+ EuclideanReconstruction *reconstruction, bool final_pass) {
+ if (markers.size() < 5) {
+ return false;
+ }
+ Mat2X points_2d = PointMatrixFromMarkers(markers);
+ Mat3X points_3d(3, markers.size());
+ for (int i = 0; i < markers.size(); i++) {
+ points_3d.col(i) = reconstruction->PointForTrack(markers[i].track)->X;
+ }
+ LG << "Points for resect:\n" << points_2d;
+
+ Mat3 R;
+ Vec3 t;
+ if (0 || !euclidean_resection::EuclideanResection(points_2d, points_3d, &R, &t)) {
+ // printf("Resection for image %d failed\n", markers[0].image);
+ LG << "Resection for image " << markers[0].image << " failed;"
+ << " trying fallback projective resection.";
+ if (!final_pass) return false;
+ // Euclidean resection failed. Fall back to projective resection, which is
+ // less reliable but better conditioned when there are many points.
+ Mat34 P;
+ Mat4X points_3d_homogeneous(4, markers.size());
+ for (int i = 0; i < markers.size(); i++) {
+ points_3d_homogeneous.col(i).head<3>() = points_3d.col(i);
+ points_3d_homogeneous(3, i) = 1.0;
+ }
+ resection::Resection(points_2d, points_3d_homogeneous, &P);
+ if ((P * points_3d_homogeneous.col(0))(2) < 0) {
+ LG << "Point behind camera; switch sign.";
+ P = -P;
+ }
+
+ Mat3 ignored;
+ KRt_From_P(P, &ignored, &R, &t);
+
+ // The R matrix should be a rotation, but don't rely on it.
+ Eigen::JacobiSVD<Mat3> svd(R, Eigen::ComputeFullU | Eigen::ComputeFullV);
+
+ LG << "Resection rotation is: " << svd.singularValues().transpose();
+ LG << "Determinant is: " << R.determinant();
+
+ // Correct to make R a rotation.
+ R = svd.matrixU() * svd.matrixV().transpose();
+
+ Vec3 xx = R * points_3d.col(0) + t;
+ if (xx(2) < 0.0) {
+ LG << "Final point is still behind camera...";
+ }
+ // XXX Need to check if error is horrible and fail here too in that case.
+ }
+
+ // Refine the result.
+ typedef LevenbergMarquardt<EuclideanResectCostFunction> Solver;
+
+ // Give the cost our initial guess for R.
+ EuclideanResectCostFunction resect_cost(markers, *reconstruction, R);
+
+ // Encode the initial parameters: start with zero delta rotation, and the
+ // guess for t obtained from resection.
+ Vec6 dRt = Vec6::Zero();
+ dRt.tail<3>() = t;
+
+ Solver solver(resect_cost);
+
+ Solver::SolverParameters params;
+ Solver::Results results = solver.minimize(params, &dRt);
+ LG << "LM found incremental rotation: " << dRt.head<3>().transpose();
+ // TODO(keir): Check results to ensure clean termination.
+
+ // Unpack the rotation and translation.
+ R = RotationFromEulerVector(dRt.head<3>()) * R;
+ t = dRt.tail<3>();
+
+ LG << "Resection for image " << markers[0].image << " got:\n"
+ << "R:\n" << R << "\nt:\n" << t;
+ reconstruction->InsertCamera(markers[0].image, R, t);
+ return true;
+}
+
+namespace {
+
+// Directly parameterize the projection matrix, P, which is a 12 parameter
+// homogeneous entry. In theory P should be parameterized with only 11
+// parametetrs, but in practice it works fine to let the extra degree of
+// freedom drift.
+struct ProjectiveResectCostFunction {
+ public:
+ typedef Vec FMatrixType;
+ typedef Vec12 XMatrixType;
+
+ ProjectiveResectCostFunction(const vector<Marker> &markers,
+ const ProjectiveReconstruction &reconstruction)
+ : markers(markers),
+ reconstruction(reconstruction) {}
+
+ Vec operator()(const Vec12 &vector_P) const {
+ // Unpack P from vector_P.
+ Map<const Mat34> P(vector_P.data(), 3, 4);
+
+ // Compute the reprojection error for each coordinate.
+ Vec residuals(2 * markers.size());
+ residuals.setZero();
+ for (int i = 0; i < markers.size(); ++i) {
+ const ProjectivePoint &point =
+ *reconstruction.PointForTrack(markers[i].track);
+ Vec3 projected = P * point.X;
+ projected /= projected(2);
+ residuals[2*i + 0] = projected(0) - markers[i].x;
+ residuals[2*i + 1] = projected(1) - markers[i].y;
+ }
+ return residuals;
+ }
+
+ const vector<Marker> &markers;
+ const ProjectiveReconstruction &reconstruction;
+};
+
+} // namespace
+
+bool ProjectiveResect(const vector<Marker> &markers,
+ ProjectiveReconstruction *reconstruction) {
+ if (markers.size() < 5) {
+ return false;
+ }
+
+ // Stack the homogeneous 3D points as the columns of a matrix.
+ Mat2X points_2d = PointMatrixFromMarkers(markers);
+ Mat4X points_3d_homogeneous(4, markers.size());
+ for (int i = 0; i < markers.size(); i++) {
+ points_3d_homogeneous.col(i) =
+ reconstruction->PointForTrack(markers[i].track)->X;
+ }
+ LG << "Points for resect:\n" << points_2d;
+
+ // Resection the point.
+ Mat34 P;
+ resection::Resection(points_2d, points_3d_homogeneous, &P);
+
+ // Flip the sign of P if necessary to keep the point in front of the camera.
+ if ((P * points_3d_homogeneous.col(0))(2) < 0) {
+ LG << "Point behind camera; switch sign.";
+ P = -P;
+ }
+
+ // TODO(keir): Check if error is horrible and fail in that case.
+
+ // Refine the resulting projection matrix using geometric error.
+ typedef LevenbergMarquardt<ProjectiveResectCostFunction> Solver;
+
+ ProjectiveResectCostFunction resect_cost(markers, *reconstruction);
+
+ // Pack the initial P matrix into a size-12 vector..
+ Vec12 vector_P = Map<Vec12>(P.data());
+
+ Solver solver(resect_cost);
+
+ Solver::SolverParameters params;
+ Solver::Results results = solver.minimize(params, &vector_P);
+ // TODO(keir): Check results to ensure clean termination.
+
+ // Unpack the projection matrix.
+ P = Map<Mat34>(vector_P.data(), 3, 4);
+
+ LG << "Resection for image " << markers[0].image << " got:\n"
+ << "P:\n" << P;
+ reconstruction->InsertCamera(markers[0].image, P);
+ return true;
+}
+} // namespace libmv
diff --git a/extern/libmv/libmv/simple_pipeline/resect.h b/extern/libmv/libmv/simple_pipeline/resect.h
new file mode 100644
index 00000000000..f8b5b9f68ee
--- /dev/null
+++ b/extern/libmv/libmv/simple_pipeline/resect.h
@@ -0,0 +1,86 @@
+// Copyright (c) 2011 libmv authors.
+//
+// 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 LIBMV_SIMPLE_PIPELINE_RESECT_H
+#define LIBMV_SIMPLE_PIPELINE_RESECT_H
+
+#include "libmv/base/vector.h"
+#include "libmv/simple_pipeline/tracks.h"
+#include "libmv/simple_pipeline/reconstruction.h"
+
+namespace libmv {
+
+/*!
+ Estimate the Euclidean pose of a camera from 2D to 3D correspondences.
+
+ This takes a set of markers visible in one frame (which is the one to
+ resection), such that the markers are also reconstructed in 3D in the
+ reconstruction object, and solves for the pose and orientation of the
+ camera for that frame.
+
+ \a markers should contain \l Marker markers \endlink belonging to tracks
+ visible in the one frame to be resectioned. Each of the tracks associated
+ with the markers must have a corresponding reconstructed 3D position in the
+ \a *reconstruction object.
+
+ \a *reconstruction should contain the 3D points associated with the tracks
+ for the markers present in \a markers.
+
+ \note This assumes a calibrated reconstruction, e.g. the markers are
+ already corrected for camera intrinsics and radial distortion.
+ \note This assumes an outlier-free set of markers.
+
+ \return True if the resection was successful, false otherwise.
+
+ \sa EuclideanIntersect, EuclideanReconstructTwoFrames
+*/
+bool EuclideanResect(const vector<Marker> &markers,
+ EuclideanReconstruction *reconstruction, bool final_pass);
+
+/*!
+ Estimate the projective pose of a camera from 2D to 3D correspondences.
+
+ This takes a set of markers visible in one frame (which is the one to
+ resection), such that the markers are also reconstructed in a projective
+ frame in the reconstruction object, and solves for the projective matrix of
+ the camera for that frame.
+
+ \a markers should contain \l Marker markers \endlink belonging to tracks
+ visible in the one frame to be resectioned. Each of the tracks associated
+ with the markers must have a corresponding reconstructed homogeneous 3D
+ position in the \a *reconstruction object.
+
+ \a *reconstruction should contain the homogeneous 3D points associated with
+ the tracks for the markers present in \a markers.
+
+ \note This assumes radial distortion has already been corrected, but
+ otherwise works for uncalibrated sequences.
+ \note This assumes an outlier-free set of markers.
+
+ \return True if the resection was successful, false otherwise.
+
+ \sa ProjectiveIntersect, ProjectiveReconstructTwoFrames
+*/
+bool ProjectiveResect(const vector<Marker> &markers,
+ ProjectiveReconstruction *reconstruction);
+
+} // namespace libmv
+
+#endif // LIBMV_SIMPLE_PIPELINE_RESECT_H
diff --git a/extern/libmv/libmv/simple_pipeline/tracks.cc b/extern/libmv/libmv/simple_pipeline/tracks.cc
new file mode 100644
index 00000000000..3fb8ddbe513
--- /dev/null
+++ b/extern/libmv/libmv/simple_pipeline/tracks.cc
@@ -0,0 +1,159 @@
+// Copyright (c) 2011 libmv authors.
+//
+// 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 <algorithm>
+#include <vector>
+#include <iterator>
+
+#include "libmv/numeric/numeric.h"
+#include "libmv/simple_pipeline/tracks.h"
+
+namespace libmv {
+
+Tracks::Tracks(const Tracks &other) {
+ markers_ = other.markers_;
+}
+
+Tracks::Tracks(const vector<Marker> &markers) : markers_(markers) {}
+
+void Tracks::Insert(int image, int track, double x, double y) {
+ // TODO(keir): Wow, this is quadratic for repeated insertions. Fix this by
+ // adding a smarter data structure like a set<>.
+ for (int i = 0; i < markers_.size(); ++i) {
+ if (markers_[i].image == image &&
+ markers_[i].track == track) {
+ markers_[i].x = x;
+ markers_[i].y = y;
+ return;
+ }
+ }
+ Marker marker = { image, track, x, y };
+ markers_.push_back(marker);
+}
+
+vector<Marker> Tracks::AllMarkers() const {
+ return markers_;
+}
+
+vector<Marker> Tracks::MarkersInImage(int image) const {
+ vector<Marker> markers;
+ for (int i = 0; i < markers_.size(); ++i) {
+ if (image == markers_[i].image) {
+ markers.push_back(markers_[i]);
+ }
+ }
+ return markers;
+}
+
+vector<Marker> Tracks::MarkersForTrack(int track) const {
+ vector<Marker> markers;
+ for (int i = 0; i < markers_.size(); ++i) {
+ if (track == markers_[i].track) {
+ markers.push_back(markers_[i]);
+ }
+ }
+ return markers;
+}
+
+vector<Marker> Tracks::MarkersForTracksInBothImages(int image1, int image2) const {
+ std::vector<int> image1_tracks;
+ std::vector<int> image2_tracks;
+
+ for (int i = 0; i < markers_.size(); ++i) {
+ int image = markers_[i].image;
+ if (image == image1) {
+ image1_tracks.push_back(markers_[i].track);
+ } else if (image == image2) {
+ image2_tracks.push_back(markers_[i].track);
+ }
+ }
+
+ std::sort(image1_tracks.begin(), image1_tracks.end());
+ std::sort(image2_tracks.begin(), image2_tracks.end());
+
+ std::vector<int> intersection;
+ std::set_intersection(image1_tracks.begin(), image1_tracks.end(),
+ image2_tracks.begin(), image2_tracks.end(),
+ std::back_inserter(intersection));
+
+ vector<Marker> markers;
+ for (int i = 0; i < markers_.size(); ++i) {
+ if ((markers_[i].image == image1 || markers_[i].image == image2) &&
+ std::binary_search(intersection.begin(),intersection.end(),
+ markers_[i].track)) {
+ markers.push_back(markers_[i]);
+ }
+ }
+ return markers;
+}
+
+Marker Tracks::MarkerInImageForTrack(int image, int track) const {
+ for (int i = 0; i < markers_.size(); ++i) {
+ if (markers_[i].image == image && markers_[i].track == track) {
+ return markers_[i];
+ }
+ }
+ Marker null = { -1, -1, -1, -1 };
+ return null;
+}
+
+void Tracks::RemoveMarkersForTrack(int track) {
+ int size = 0;
+ for (int i = 0; i < markers_.size(); ++i) {
+ if (markers_[i].track != track) {
+ markers_[size++] = markers_[i];
+ }
+ }
+ markers_.resize(size);
+}
+
+void Tracks::RemoveMarker(int image, int track) {
+ int size = 0;
+ for (int i = 0; i < markers_.size(); ++i) {
+ if (markers_[i].image != image || markers_[i].track != track) {
+ markers_[size++] = markers_[i];
+ }
+ }
+ markers_.resize(size);
+}
+
+int Tracks::MaxImage() const {
+ // TODO(MatthiasF): maintain a max_image_ member (updated on Insert)
+ int max_image = 0;
+ for (int i = 0; i < markers_.size(); ++i) {
+ max_image = std::max(markers_[i].image, max_image);
+ }
+ return max_image;
+}
+
+int Tracks::MaxTrack() const {
+ // TODO(MatthiasF): maintain a max_track_ member (updated on Insert)
+ int max_track = 0;
+ for (int i = 0; i < markers_.size(); ++i) {
+ max_track = std::max(markers_[i].track, max_track);
+ }
+ return max_track;
+}
+
+int Tracks::NumMarkers() const {
+ return markers_.size();
+}
+
+} // namespace libmv
diff --git a/extern/libmv/libmv/simple_pipeline/tracks.h b/extern/libmv/libmv/simple_pipeline/tracks.h
new file mode 100644
index 00000000000..739c3c4f243
--- /dev/null
+++ b/extern/libmv/libmv/simple_pipeline/tracks.h
@@ -0,0 +1,119 @@
+// Copyright (c) 2011 libmv authors.
+//
+// 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 LIBMV_SIMPLE_PIPELINE_TRACKS_H_
+#define LIBMV_SIMPLE_PIPELINE_TRACKS_H_
+
+#include "libmv/base/vector.h"
+
+namespace libmv {
+
+/*!
+ A Marker is the 2D location of a tracked point in an image.
+
+ \a x, \a y is the position of the marker in pixels from the top left corner
+ in the image identified by \a image. All markers for to the same target
+ form a track identified by a common \a track number.
+
+ \note Markers are typically aggregated with the help of the \l Tracks class.
+
+ \sa Tracks
+*/
+struct Marker {
+ int image;
+ int track;
+ double x, y;
+};
+
+/*!
+ The Tracks class stores \link Marker reconstruction markers \endlink.
+
+ The Tracks container is intended as the store of correspondences between
+ images, which must get created before any 3D reconstruction can take place.
+
+ The container has several fast lookups for queries typically needed for
+ structure from motion algorithms, such as \l MarkersForTracksInBothImages().
+
+ \sa Marker
+*/
+class Tracks {
+ public:
+ Tracks() {}
+
+ // Copy constructor for a tracks object.
+ Tracks(const Tracks &other);
+
+ /// Construct a new tracks object using the given markers to start.
+ Tracks(const vector<Marker> &markers);
+
+ /*!
+ Inserts a marker into the set. If there is already a marker for the given
+ \a image and \a track, the existing marker is replaced. If there is no
+ marker for the given \a image and \a track, a new one is added.
+
+ \a image and \a track are the keys used to retrieve the markers with the
+ other methods in this class.
+
+ \note To get an identifier for a new track, use \l MaxTrack() + 1.
+ */
+ void Insert(int image, int track, double x, double y);
+
+ /// Returns all the markers.
+ vector<Marker> AllMarkers() const;
+
+ /// Returns all the markers belonging to a track.
+ vector<Marker> MarkersForTrack(int track) const;
+
+ /// Returns all the markers visible in \a image.
+ vector<Marker> MarkersInImage(int image) const;
+
+ /*!
+ Returns the markers in \a image1 and \a image2 which have a common track.
+
+ This is not the same as the union of the markers in \a image1 and \a
+ image2; each marker is for a track that appears in both images.
+ */
+ vector<Marker> MarkersForTracksInBothImages(int image1, int image2) const;
+
+ /// Returns the marker in \a image belonging to \a track.
+ Marker MarkerInImageForTrack(int image, int track) const;
+
+ /// Removes all the markers belonging to \a track.
+ void RemoveMarkersForTrack(int track);
+
+ /// Removes the marker in \a image belonging to \a track.
+ void RemoveMarker(int image, int track);
+
+ /// Returns the maximum image identifier used.
+ int MaxImage() const;
+
+ /// Returns the maximum track identifier used.
+ int MaxTrack() const;
+
+ /// Returns the number of markers.
+ int NumMarkers() const;
+
+ private:
+ vector<Marker> markers_;
+};
+
+} // namespace libmv
+
+#endif // LIBMV_SIMPLE_PIPELINE_MARKERS_H_
diff --git a/extern/libmv/libmv/tracking/klt_region_tracker.cc b/extern/libmv/libmv/tracking/klt_region_tracker.cc
new file mode 100644
index 00000000000..299077be155
--- /dev/null
+++ b/extern/libmv/libmv/tracking/klt_region_tracker.cc
@@ -0,0 +1,132 @@
+// Copyright (c) 2007, 2008, 2009, 2011 libmv authors.
+//
+// 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 "libmv/logging/logging.h"
+#include "libmv/tracking/klt_region_tracker.h"
+#include "libmv/image/image.h"
+#include "libmv/image/convolve.h"
+#include "libmv/image/sample.h"
+
+namespace libmv {
+
+// Compute the gradient matrix noted by Z and the error vector e. See Good
+// Features to Track.
+//
+// TODO(keir): The calls to SampleLinear() do boundary checking that should
+// instead happen outside the loop. Since this is the innermost loop, the extra
+// bounds checking hurts performance.
+static void ComputeTrackingEquation(const Array3Df &image_and_gradient1,
+ const Array3Df &image_and_gradient2,
+ double x1, double y1,
+ double x2, double y2,
+ int half_width,
+ float *gxx,
+ float *gxy,
+ float *gyy,
+ float *ex,
+ float *ey) {
+ *gxx = *gxy = *gyy = 0;
+ *ex = *ey = 0;
+ for (int r = -half_width; r <= half_width; ++r) {
+ for (int c = -half_width; c <= half_width; ++c) {
+ float xx1 = x1 + c;
+ float yy1 = y1 + r;
+ float xx2 = x2 + c;
+ float yy2 = y2 + r;
+ float I = SampleLinear(image_and_gradient1, yy1, xx1, 0);
+ float J = SampleLinear(image_and_gradient2, yy2, xx2, 0);
+ float gx = SampleLinear(image_and_gradient2, yy2, xx2, 1);
+ float gy = SampleLinear(image_and_gradient2, yy2, xx2, 2);
+ *gxx += gx * gx;
+ *gxy += gx * gy;
+ *gyy += gy * gy;
+ *ex += (I - J) * gx;
+ *ey += (I - J) * gy;
+ }
+ }
+}
+
+// Solve the tracking equation
+//
+// [gxx gxy] [dx] = [ex]
+// [gxy gyy] [dy] = [ey]
+//
+// for dx and dy. Borrowed from Stan Birchfield's KLT implementation.
+static bool SolveTrackingEquation(float gxx, float gxy, float gyy,
+ float ex, float ey,
+ float min_determinant,
+ float *dx, float *dy) {
+ float det = gxx * gyy - gxy * gxy;
+ if (det < min_determinant) {
+ *dx = 0;
+ *dy = 0;
+ return false;
+ }
+ *dx = (gyy * ex - gxy * ey) / det;
+ *dy = (gxx * ey - gxy * ex) / det;
+ return true;
+}
+
+bool KltRegionTracker::Track(const FloatImage &image1,
+ const FloatImage &image2,
+ double x1, double y1,
+ double *x2, double *y2) const {
+ Array3Df image_and_gradient1;
+ Array3Df image_and_gradient2;
+ BlurredImageAndDerivativesChannels(image1, sigma, &image_and_gradient1);
+ BlurredImageAndDerivativesChannels(image2, sigma, &image_and_gradient2);
+
+ int i;
+ float dx = 0, dy = 0;
+ for (i = 0; i < max_iterations; ++i) {
+ // Compute gradient matrix and error vector.
+ float gxx, gxy, gyy, ex, ey;
+ ComputeTrackingEquation(image_and_gradient1,
+ image_and_gradient2,
+ x1, y1,
+ *x2, *y2,
+ half_window_size,
+ &gxx, &gxy, &gyy, &ex, &ey);
+
+ // Solve the linear system for the best update to x2 and y2.
+ if (!SolveTrackingEquation(gxx, gxy, gyy, ex, ey, min_determinant,
+ &dx, &dy)) {
+ // The determinant, which indicates the trackiness of the point, is too
+ // small, so fail out.
+ LG << "Determinant too small; failing tracking.";
+ return false;
+ }
+
+ // Update the position with the solved displacement.
+ *x2 += dx;
+ *y2 += dy;
+
+ // If the update is small, then we probably found the target.
+ if (dx * dx + dy * dy < min_update_squared_distance) {
+ LG << "Successful track in " << i << " iterations.";
+ return true;
+ }
+ }
+ // Getting here means we hit max iterations, so tracking failed.
+ LG << "Too many iterations.";
+ return false;
+}
+
+} // namespace libmv
diff --git a/extern/libmv/libmv/tracking/klt_region_tracker.h b/extern/libmv/libmv/tracking/klt_region_tracker.h
new file mode 100644
index 00000000000..2b2d8a9a49d
--- /dev/null
+++ b/extern/libmv/libmv/tracking/klt_region_tracker.h
@@ -0,0 +1,55 @@
+// Copyright (c) 2007, 2008, 2009, 2011 libmv authors.
+//
+// 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 LIBMV_REGION_TRACKING_KLT_REGION_TRACKER_H_
+#define LIBMV_REGION_TRACKING_KLT_REGION_TRACKER_H_
+
+#include "libmv/image/image.h"
+#include "libmv/tracking/region_tracker.h"
+
+namespace libmv {
+
+struct KltRegionTracker : public RegionTracker {
+ KltRegionTracker()
+ : half_window_size(4),
+ max_iterations(16),
+ min_determinant(1e-6),
+ min_update_squared_distance(1e-6),
+ sigma(0.9) {}
+
+ virtual ~KltRegionTracker() {}
+
+ // Tracker interface.
+ virtual bool Track(const FloatImage &image1,
+ const FloatImage &image2,
+ double x1, double y1,
+ double *x2, double *y2) const;
+
+ // No point in creating getters or setters.
+ int half_window_size;
+ int max_iterations;
+ double min_determinant;
+ double min_update_squared_distance;
+ double sigma;
+};
+
+} // namespace libmv
+
+#endif // LIBMV_REGION_TRACKING_KLT_REGION_TRACKER_H_
diff --git a/extern/libmv/libmv/tracking/pyramid_region_tracker.cc b/extern/libmv/libmv/tracking/pyramid_region_tracker.cc
new file mode 100644
index 00000000000..58f42b26d7c
--- /dev/null
+++ b/extern/libmv/libmv/tracking/pyramid_region_tracker.cc
@@ -0,0 +1,80 @@
+// Copyright (c) 2007, 2008, 2009, 2011 libmv authors.
+//
+// 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 <vector>
+
+#include "libmv/image/convolve.h"
+#include "libmv/image/image.h"
+#include "libmv/image/sample.h"
+#include "libmv/logging/logging.h"
+#include "libmv/tracking/pyramid_region_tracker.h"
+
+namespace libmv {
+
+static void MakePyramid(const FloatImage &image, int num_levels,
+ std::vector<FloatImage> *pyramid) {
+ pyramid->resize(num_levels);
+ (*pyramid)[0] = image;
+ for (int i = 1; i < num_levels; ++i) {
+ DownsampleChannelsBy2((*pyramid)[i - 1], &(*pyramid)[i]);
+ }
+}
+
+bool PyramidRegionTracker::Track(const FloatImage &image1,
+ const FloatImage &image2,
+ double x1, double y1,
+ double *x2, double *y2) const {
+ // Shrink the guessed x and y location to match the coarsest level + 1 (which
+ // when gets corrected in the loop).
+ *x2 /= pow(2., num_levels_);
+ *y2 /= pow(2., num_levels_);
+
+ // Create all the levels of the pyramid, since tracking has to happen from
+ // the coarsest to finest levels, which means holding on to all levels of the
+ // pyraid at once.
+ std::vector<FloatImage> pyramid1(num_levels_);
+ std::vector<FloatImage> pyramid2(num_levels_);
+ MakePyramid(image1, num_levels_, &pyramid1);
+ MakePyramid(image2, num_levels_, &pyramid2);
+
+ for (int i = num_levels_ - 1; i >= 0; --i) {
+ // Position in the first image at pyramid level i.
+ double xx = x1 / pow(2., i);
+ double yy = y1 / pow(2., i);
+
+ // Guess the new tracked position is where the last level tracked to.
+ *x2 *= 2;
+ *y2 *= 2;
+
+ // Track the point on this level with the base tracker.
+ bool succeeded = tracker_->Track(pyramid1[i], pyramid2[i], xx, yy, x2, y2);
+
+ if (i == 0 && !succeeded) {
+ // Only fail on the highest-resolution level, because a failure on a
+ // coarse level does not mean failure at a lower level (consider
+ // out-of-bounds conditions).
+ LG << "Finest level of pyramid tracking failed; failing.";
+ return false;
+ }
+ }
+ return true;
+}
+
+} // namespace libmv
diff --git a/extern/libmv/libmv/tracking/pyramid_region_tracker.h b/extern/libmv/libmv/tracking/pyramid_region_tracker.h
new file mode 100644
index 00000000000..1f9675469f4
--- /dev/null
+++ b/extern/libmv/libmv/tracking/pyramid_region_tracker.h
@@ -0,0 +1,46 @@
+// Copyright (c) 2011 libmv authors.
+//
+// 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 LIBMV_CORRESPONDENCE_PYRAMID_TRACKER_H_
+#define LIBMV_CORRESPONDENCE_PYRAMID_TRACKER_H_
+
+#include "libmv/image/image.h"
+#include "libmv/base/scoped_ptr.h"
+#include "libmv/tracking/region_tracker.h"
+
+namespace libmv {
+
+class PyramidRegionTracker : public RegionTracker {
+ public:
+ PyramidRegionTracker(RegionTracker *tracker, int num_levels)
+ : tracker_(tracker), num_levels_(num_levels) {}
+
+ virtual bool Track(const FloatImage &image1,
+ const FloatImage &image2,
+ double x1, double y1,
+ double *x2, double *y2) const;
+ private:
+ scoped_ptr<RegionTracker> tracker_;
+ int num_levels_;
+};
+
+} // namespace libmv
+
+#endif // LIBMV_CORRESPONDENCE_PYRAMID_TRACKER_H_
diff --git a/extern/libmv/libmv/tracking/region_tracker.h b/extern/libmv/libmv/tracking/region_tracker.h
new file mode 100644
index 00000000000..4f7574df1a3
--- /dev/null
+++ b/extern/libmv/libmv/tracking/region_tracker.h
@@ -0,0 +1,48 @@
+// Copyright (c) 2011 libmv authors.
+//
+// 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 LIBMV_TRACKING_TRACKER_H_
+#define LIBMV_TRACKING_TRACKER_H_
+
+#include "libmv/image/image.h"
+
+namespace libmv {
+
+class RegionTracker {
+ public:
+ RegionTracker() {}
+ virtual ~RegionTracker() {}
+
+ /*!
+ Track a point from \a image1 to \a image2.
+
+ \a x2, \a y2 should start out as a best guess for the position in \a
+ image2. If no guess is available, (\a x1, \a y1) is a good start. Returns
+ true on success, false otherwise
+ */
+ virtual bool Track(const FloatImage &image1,
+ const FloatImage &image2,
+ double x1, double y1,
+ double *x2, double *y2) const = 0;
+};
+
+} // namespace libmv
+
+#endif // LIBMV_CORRESPONDENCE_TRACKER_H_
diff --git a/extern/libmv/libmv/tracking/retrack_region_tracker.cc b/extern/libmv/libmv/tracking/retrack_region_tracker.cc
new file mode 100644
index 00000000000..b3230b1b173
--- /dev/null
+++ b/extern/libmv/libmv/tracking/retrack_region_tracker.cc
@@ -0,0 +1,47 @@
+// Copyright (c) 2011 libmv authors.
+//
+// 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 <cmath>
+#include <vector>
+
+#include "libmv/tracking/retrack_region_tracker.h"
+
+namespace libmv {
+
+bool RetrackRegionTracker::Track(const FloatImage &image1,
+ const FloatImage &image2,
+ double x1, double y1,
+ double *x2, double *y2) const {
+ // Track forward, getting x2 and y2.
+ if (!tracker_->Track(image1, image2, x1, y1, x2, y2)) {
+ return false;
+ }
+ // Now track x2 and y2 backward, to get xx1 and yy1 which, if the track is
+ // good, should match x1 and y1 (but may not if the track is bad).
+ double xx1 = *x2, yy1 = *x2;
+ if (!tracker_->Track(image2, image1, *x2, *y2, &xx1, &yy1)) {
+ return false;
+ }
+ double dx = xx1 - x1;
+ double dy = yy1 - y1;
+ return sqrt(dx * dx + dy * dy) < tolerance_;
+}
+
+} // namespace libmv
diff --git a/extern/libmv/libmv/tracking/retrack_region_tracker.h b/extern/libmv/libmv/tracking/retrack_region_tracker.h
new file mode 100644
index 00000000000..ab05f320834
--- /dev/null
+++ b/extern/libmv/libmv/tracking/retrack_region_tracker.h
@@ -0,0 +1,48 @@
+// Copyright (c) 2011 libmv authors.
+//
+// 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 LIBMV_TRACKING_RETRACK_REGION_TRACKER_H_
+#define LIBMV_TRACKING_RETRACK_REGION_TRACKER_H_
+
+#include "libmv/image/image.h"
+#include "libmv/base/scoped_ptr.h"
+#include "libmv/tracking/region_tracker.h"
+
+namespace libmv {
+
+// A region tracker that tries tracking backwards and forwards, rejecting a
+// track that doesn't track backwards to the starting point.
+class RetrackRegionTracker : public RegionTracker {
+ public:
+ RetrackRegionTracker(RegionTracker *tracker, double tolerance)
+ : tracker_(tracker), tolerance_(tolerance) {}
+
+ virtual bool Track(const FloatImage &image1,
+ const FloatImage &image2,
+ double x1, double y1,
+ double *x2, double *y2) const;
+ private:
+ scoped_ptr<RegionTracker> tracker_;
+ double tolerance_;
+};
+
+} // namespace libmv
+
+#endif // LIBMV_TRACKING_RETRACK_REGION_TRACKER_H_
diff --git a/extern/libmv/libmv/tracking/sad.cc b/extern/libmv/libmv/tracking/sad.cc
new file mode 100644
index 00000000000..9b446bb4c35
--- /dev/null
+++ b/extern/libmv/libmv/tracking/sad.cc
@@ -0,0 +1,174 @@
+/****************************************************************************
+**
+** Copyright (c) 2011 libmv authors.
+**
+** 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 "libmv/tracking/sad.h"
+#include <stdlib.h>
+#include <math.h>
+
+namespace libmv {
+
+void LaplaceFilter(ubyte* src, ubyte* dst, int width, int height, int strength) {
+ for(int y=1; y<height-1; y++) for(int x=1; x<width-1; x++) {
+ const ubyte* s = &src[y*width+x];
+ int l = 128 +
+ s[-width-1] + s[-width] + s[-width+1] +
+ s[1] - 8*s[0] + s[1] +
+ s[ width-1] + s[ width] + s[ width+1] ;
+ int d = ((256-strength)*s[0] + strength*l) / 256;
+ if(d < 0) d=0;
+ if(d > 255) d=255;
+ dst[y*width+x] = d;
+ }
+}
+
+struct vec2 {
+ float x,y;
+ inline vec2(float x, float y):x(x),y(y){}
+};
+inline vec2 operator*(mat32 m, vec2 v) {
+ return vec2(v.x*m(0,0)+v.y*m(0,1)+m(0,2),v.x*m(1,0)+v.y*m(1,1)+m(1,2));
+}
+
+//! fixed point bilinear sample with precision k
+template <int k> inline int sample(const ubyte* image,int stride, int x, int y, int u, int v) {
+ const ubyte* s = &image[y*stride+x];
+ return ((s[ 0] * (k-u) + s[ 1] * u) * (k-v)
+ + (s[stride] * (k-u) + s[stride+1] * u) * ( v) ) / (k*k);
+}
+
+#ifdef __SSE__
+#include <xmmintrin.h>
+int lround(float x) { return _mm_cvtss_si32(_mm_set_ss(x)); }
+#elif defined(_MSC_VER)
+int lround(float x) { return x+0.5; }
+#endif
+
+//TODO(MatthiasF): SSE optimization
+void SamplePattern(ubyte* image, int stride, mat32 warp, ubyte* pattern, int size) {
+ const int k = 256;
+ for (int i = 0; i < size; i++) for (int j = 0; j < size; j++) {
+ vec2 p = warp*vec2(j-size/2,i-size/2);
+ int fx = lround(p.x*k), fy = lround(p.y*k);
+ int ix = fx/k, iy = fy/k;
+ int u = fx%k, v = fy%k;
+ pattern[i*size+j] = sample<k>(image,stride,ix,iy,u,v);
+ }
+}
+
+#ifdef __SSE2__
+#include <emmintrin.h>
+static uint SAD(const ubyte* pattern, const ubyte* image, int stride, int size) {
+ __m128i a = _mm_setzero_si128();
+ for(int i = 0; i < size; i++) {
+ for(int j = 0; j < size/16; j++) {
+ a = _mm_adds_epu16(a, _mm_sad_epu8( _mm_loadu_si128((__m128i*)(pattern+i*size+j*16)),
+ _mm_loadu_si128((__m128i*)(image+i*stride+j*16))));
+ }
+ }
+ return _mm_extract_epi16(a,0) + _mm_extract_epi16(a,4);
+}
+#else
+static uint SAD(const ubyte* pattern, const ubyte* image, int stride, int size) {
+ uint sad=0;
+ for(int i = 0; i < size; i++) {
+ for(int j = 0; j < size; j++) {
+ sad += abs((int)pattern[i*size+j] - image[i*stride+j]);
+ }
+ }
+ return sad;
+}
+#endif
+
+float sq(float x) { return x*x; }
+float Track(ubyte* reference, ubyte* warped, int size, ubyte* image, int stride, int w, int h, mat32* warp, float areaPenalty, float conditionPenalty) {
+ mat32 m=*warp;
+ uint min=-1;
+
+ // exhaustive search integer pixel translation
+ int ix = m(0,2), iy = m(1,2);
+ for(int y = size/2; y < h-size/2; y++) {
+ for(int x = size/2; x < w-size/2; x++) {
+ m(0,2) = x, m(1,2) = y;
+ uint sad = SAD(warped,&image[(y-size/2)*stride+(x-size/2)],stride,size);
+ // TODO: using chroma could help disambiguate some cases
+ if(sad < min) {
+ min = sad;
+ ix = x, iy = y;
+ }
+ }
+ }
+ m(0,2) = ix, m(1,2) = iy;
+ min=-1; //reset score since direct warped search match too well (but the wrong pattern).
+
+ // 6D coordinate descent to find affine transform
+ ubyte* match = new ubyte[size*size];
+ float step = 0.5;
+ for(int p = 0; p < 8; p++) { //foreach precision level
+ for(int i = 0; i < 2; i++) { // iterate twice per precision level
+ //TODO: other sweep pattern might converge better
+ for(int d=0; d < 6; d++) { // iterate dimension sequentially (cyclic descent)
+ for(float e = -step; e <= step; e+=step) { //solve subproblem (evaluate only along one coordinate)
+ mat32 t = m;
+ t.data[d] += e;
+ //TODO: better performance would also allow a more exhaustive search
+ SamplePattern(image,stride,t,match,size);
+ uint sad = SAD(reference,match,size,size);
+ // regularization: keep constant area and good condition
+ float area = t(0,0)*t(1,1)-t(0,1)*t(1,0);
+ float x = sq(t(0,0))+sq(t(0,1)), y = sq(t(1,0))+sq(t(1,1));
+ float condition = x>y ? x/y : y/x;
+ sad += size*size*( areaPenalty*sq(area-1) + conditionPenalty*sq(condition-1) );
+ if(sad < min) {
+ min = sad;
+ m = t;
+ }
+ }
+ }
+ }
+ step /= 2;
+ }
+ *warp = m;
+
+ // Compute Pearson product-moment correlation coefficient
+ uint sX=0,sY=0,sXX=0,sYY=0,sXY=0;
+ SamplePattern(image,stride,m,match,size);
+ SAD(reference,match,size,size);
+ for(int i = 0; i < size; i++) {
+ for(int j = 0; j < size; j++) {
+ int x = reference[i*size+j];
+ int y = match[i*size+j];
+ sX += x;
+ sY += y;
+ sXX += x*x;
+ sYY += y*y;
+ sXY += x*y;
+ }
+ }
+ delete[] match;
+ const int N = size*size;
+ sX /= N, sY /= N, sXX /= N, sYY /= N, sXY /= N;
+ return (sXY-sX*sY)/sqrt(double((sXX-sX*sX)*(sYY-sY*sY)));
+}
+
+} // namespace libmv
diff --git a/extern/libmv/libmv/tracking/sad.h b/extern/libmv/libmv/tracking/sad.h
new file mode 100644
index 00000000000..9fe323b74c4
--- /dev/null
+++ b/extern/libmv/libmv/tracking/sad.h
@@ -0,0 +1,109 @@
+/****************************************************************************
+**
+** Copyright (c) 2011 libmv authors.
+**
+** 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 LIBMV_TRACKING_SAD_H_
+#define LIBMV_TRACKING_SAD_H_
+
+#ifdef __cplusplus
+namespace libmv {
+#endif
+
+typedef unsigned char ubyte;
+typedef unsigned int uint;
+
+/*!
+ Convolve \a src into \a dst with the discrete laplacian operator.
+
+ \a src and \a dst should be \a width x \a height images.
+ \a strength is an interpolation coefficient (0-256) between original image and the laplacian.
+
+ \note Make sure the search region is filtered with the same strength as the pattern.
+*/
+void LaplaceFilter(ubyte* src, ubyte* dst, int width, int height, int strength);
+
+/// Affine transformation matrix in column major order.
+struct mat32 {
+ float data[3*2];
+#ifdef __cplusplus
+ inline mat32(int d=1) { for(int i=0;i<3*2;i++) data[i]=0; if(d!=0) for(int i=0;i<2;i++) m(i,i)=d; }
+ inline float m(int i, int j) const { return data[j*2+i]; }
+ inline float& m(int i, int j) { return data[j*2+i]; }
+ inline float operator()(int i, int j) const { return m(i,j); }
+ inline float& operator()(int i, int j) { return m(i,j); }
+ inline operator bool() const { for (int i=0; i<3*2; i++) if(data[i]!=0) return true; return false; }
+#endif
+};
+
+/*!
+ Sample \a pattern from \a image.
+
+ \a warp is the transformation to apply to \a image when sampling the \a pattern.
+*/
+void SamplePattern(ubyte* image, int stride, mat32 warp, ubyte* pattern, int size);
+
+/*!
+ Track \a pattern in \a image.
+
+ This template matcher computes the
+ \link http://en.wikipedia.org/wiki/Sum_of_absolute_differences Sum of Absolute Differences (SAD) \endlink
+ for each integer pixel position in the search region and then iteratively
+ refine subpixel position using a square search.
+ A similar method is used for motion estimation in video encoders.
+
+ \a reference is the pattern to track.
+ \a warped is a warped version of reference for fast unsampled integer search.
+ Best is to directly extract an already warped pattern from previous frame.
+ The \a size of the patterns should be aligned to 16.
+ \a image is a reference to the region to search.
+ \a stride is size of \a image lines.
+
+ On input, \a warp is the predicted affine transformation (e.g from previous frame)
+ On return, \a warp is the affine transformation which best match the reference \a pattern
+
+ \a areaPenalty and conditionPenalty control the regularization and need to be tweaked depending on the motion.
+ Setting them to 0 will allow any transformation (including unrealistic distortions and scaling).
+ Good values are between 0-32. 16 can be used as a realistic default.
+ areaPenalty control scaling (decrease to allow pull/zoom, increase to allow only 2D rotation).
+ a large conditionPenalty avoid a large ratio between the largest and smallest axices.
+ It need to be decreased for non-2D rotation (when pattern appears to scale along an axis).
+
+ \return Pearson product-moment correlation coefficient between reference and matched pattern.
+ This measure of the linear dependence between the patterns
+ ranges from −1 (negative correlation) to 1 (positive correlation).
+ A value of 0 implies that there is no linear correlation between the variables.
+
+ \note To track affine features:
+ - Sample reference pattern using estimated (e.g previous frame) warp.
+ -
+ \note \a stride allow you to reference your search region instead of copying.
+ \note For a 16x speedup, compile this tracker with SSE2 support.
+*/
+float Track(ubyte* reference, ubyte* warped, int size, ubyte* image, int stride, int width, int height, mat32* warp,
+ float areaPenalty, float conditionPenalty);
+
+#ifdef __cplusplus
+} // namespace libmv
+#endif
+
+#endif // LIBMV_TRACKING_SAD_H_
diff --git a/extern/libmv/libmv/tracking/trklt_region_tracker.cc b/extern/libmv/libmv/tracking/trklt_region_tracker.cc
new file mode 100644
index 00000000000..94319fcb7d3
--- /dev/null
+++ b/extern/libmv/libmv/tracking/trklt_region_tracker.cc
@@ -0,0 +1,135 @@
+// Copyright (c) 2011 libmv authors.
+//
+// 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 "libmv/tracking/trklt_region_tracker.h"
+
+#include "libmv/logging/logging.h"
+#include "libmv/numeric/numeric.h"
+#include "libmv/image/image.h"
+#include "libmv/image/convolve.h"
+#include "libmv/image/sample.h"
+
+namespace libmv {
+
+// Computes U and e from the Ud = e equation (number 14) from the paper.
+static void ComputeTrackingEquation(const Array3Df &image_and_gradient1,
+ const Array3Df &image_and_gradient2,
+ double x1, double y1,
+ double x2, double y2,
+ int half_width,
+ double lambda,
+ Mat2f *U,
+ Vec2f *e) {
+ Mat2f A, B, C, D;
+ A = B = C = D = Mat2f::Zero();
+
+ Vec2f R, S, V, W;
+ R = S = V = W = Vec2f::Zero();
+
+ for (int r = -half_width; r <= half_width; ++r) {
+ for (int c = -half_width; c <= half_width; ++c) {
+ float xx1 = x1 + c;
+ float yy1 = y1 + r;
+ float xx2 = x2 + c;
+ float yy2 = y2 + r;
+
+ float I = SampleLinear(image_and_gradient1, yy1, xx1, 0);
+ float J = SampleLinear(image_and_gradient2, yy2, xx2, 0);
+
+ Vec2f gI, gJ;
+ gI << SampleLinear(image_and_gradient1, yy1, xx1, 1),
+ SampleLinear(image_and_gradient1, yy1, xx1, 2);
+ gJ << SampleLinear(image_and_gradient2, yy2, xx2, 1),
+ SampleLinear(image_and_gradient2, yy2, xx2, 2);
+
+ // Equation 15 from the paper.
+ A += gI * gI.transpose();
+ B += gI * gJ.transpose();
+ C += gJ * gJ.transpose();
+ R += I * gI;
+ S += J * gI;
+ V += I * gJ;
+ W += J * gJ;
+ }
+ }
+
+ // In the paper they show a D matrix, but it is just B transpose, so use that
+ // instead of explicitly computing D.
+ Mat2f Di = B.transpose().inverse();
+
+ // Equation 14 from the paper.
+ *U = A*Di*C + lambda*Di*C - 0.5*B;
+ *e = (A + lambda*Mat2f::Identity())*Di*(V - W) + 0.5*(S - R);
+}
+
+bool TrkltRegionTracker::Track(const FloatImage &image1,
+ const FloatImage &image2,
+ double x1, double y1,
+ double *x2, double *y2) const {
+ Array3Df image_and_gradient1;
+ Array3Df image_and_gradient2;
+ BlurredImageAndDerivativesChannels(image1, sigma, &image_and_gradient1);
+ BlurredImageAndDerivativesChannels(image2, sigma, &image_and_gradient2);
+
+ int i;
+ Vec2f d = Vec2f::Zero();
+ for (i = 0; i < max_iterations; ++i) {
+ // Compute gradient matrix and error vector.
+ Mat2f U;
+ Vec2f e;
+ ComputeTrackingEquation(image_and_gradient1,
+ image_and_gradient2,
+ x1, y1,
+ *x2, *y2,
+ half_window_size,
+ lambda,
+ &U, &e);
+
+ // Solve the linear system for the best update to x2 and y2.
+ d = U.lu().solve(e);
+
+ // Update the position with the solved displacement.
+ *x2 += d[0];
+ *y2 += d[1];
+
+ // Check for the quality of the solution, but not until having already
+ // updated the position with our best estimate. The reason to do the update
+ // anyway is that the user already knows the position is bad, so we may as
+ // well try our best.
+ float determinant = U.determinant();
+ if (fabs(determinant) < min_determinant) {
+ // The determinant, which indicates the trackiness of the point, is too
+ // small, so fail out.
+ LG << "Determinant " << determinant << " is too small; failing tracking.";
+ return false;
+ }
+
+ // If the update is small, then we probably found the target.
+ if (d.squaredNorm() < min_update_squared_distance) {
+ LG << "Successful track in " << i << " iterations.";
+ return true;
+ }
+ }
+ // Getting here means we hit max iterations, so tracking failed.
+ LG << "Too many iterations; max is set to " << max_iterations << ".";
+ return false;
+}
+
+} // namespace libmv
diff --git a/extern/libmv/libmv/tracking/trklt_region_tracker.h b/extern/libmv/libmv/tracking/trklt_region_tracker.h
new file mode 100644
index 00000000000..5046e0f069d
--- /dev/null
+++ b/extern/libmv/libmv/tracking/trklt_region_tracker.h
@@ -0,0 +1,65 @@
+// Copyright (c) 2011 libmv authors.
+//
+// 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 LIBMV_REGION_TRACKING_TRKLT_REGION_TRACKER_H_
+#define LIBMV_REGION_TRACKING_TRKLT_REGION_TRACKER_H_
+
+#include "libmv/image/image.h"
+#include "libmv/tracking/region_tracker.h"
+
+namespace libmv {
+
+// An improved KLT algorithm that enforces that the tracking is time-reversible
+// [1]. This is not the same as the "symmetric" KLT that is sometimes used.
+// Anecdotally, this tracks much more consistently than vanilla KLT.
+//
+// [1] H. Wu, R. Chellappa, and A. Sankaranarayanan and S. Kevin Zhou. Robust
+// visual tracking using the time-reversibility constraint. International
+// Conference on Computer Vision (ICCV), Rio de Janeiro, October 2007.
+//
+struct TrkltRegionTracker : public RegionTracker {
+ TrkltRegionTracker()
+ : half_window_size(4),
+ max_iterations(100),
+ min_determinant(1e-6),
+ min_update_squared_distance(1e-6),
+ sigma(0.9),
+ lambda(0.05) {}
+
+ virtual ~TrkltRegionTracker() {}
+
+ // Tracker interface.
+ virtual bool Track(const FloatImage &image1,
+ const FloatImage &image2,
+ double x1, double y1,
+ double *x2, double *y2) const;
+
+ // No point in creating getters or setters.
+ int half_window_size;
+ int max_iterations;
+ double min_determinant;
+ double min_update_squared_distance;
+ double sigma;
+ double lambda;
+};
+
+} // namespace libmv
+
+#endif // LIBMV_REGION_TRACKING_TRKLT_REGION_TRACKER_H_
diff --git a/extern/libmv/mkfiles.sh b/extern/libmv/mkfiles.sh
new file mode 100755
index 00000000000..6618f2849ea
--- /dev/null
+++ b/extern/libmv/mkfiles.sh
@@ -0,0 +1,4 @@
+#!/bin/sh
+
+find ./libmv/ -type f | sed -r 's/^\.\///' > files.txt
+find ./third_party/ -type f | sed -r 's/^\.\///' >> files.txt
diff --git a/extern/libmv/patches/bundle_tweaks.patch b/extern/libmv/patches/bundle_tweaks.patch
new file mode 100644
index 00000000000..f7b06b0a2dd
--- /dev/null
+++ b/extern/libmv/patches/bundle_tweaks.patch
@@ -0,0 +1,122 @@
+diff --git a/src/libmv/logging/logging.h b/src/libmv/logging/logging.h
+index 067da52..af86c4b 100644
+--- a/src/libmv/logging/logging.h
++++ b/src/libmv/logging/logging.h
+@@ -21,7 +21,7 @@
+ #ifndef LIBMV_LOGGING_LOGGING_H
+ #define LIBMV_LOGGING_LOGGING_H
+
+-#include "third_party/glog/src/glog/logging.h"
++#include "glog/logging.h"
+
+ #define LG LOG(INFO)
+ #define V0 LOG(INFO)
+diff --git a/src/third_party/glog/src/glog/logging.h b/src/third_party/glog/src/glog/logging.h
+index 57615ef..a58d478 100644
+--- a/src/third_party/glog/src/glog/logging.h
++++ b/src/third_party/glog/src/glog/logging.h
+@@ -33,6 +33,7 @@
+ // Pretty much everybody needs to #include this file so that they can
+ // log various happenings.
+ //
++
+ #ifndef _LOGGING_H_
+ #define _LOGGING_H_
+
+diff --git a/src/third_party/glog/src/logging.cc b/src/third_party/glog/src/logging.cc
+index 868898f..1bb3867 100644
+--- a/src/third_party/glog/src/logging.cc
++++ b/src/third_party/glog/src/logging.cc
+@@ -58,8 +58,8 @@
+ #include <errno.h> // for errno
+ #include <sstream>
+ #include "base/commandlineflags.h" // to get the program name
+-#include "glog/logging.h"
+-#include "glog/raw_logging.h"
++#include <glog/logging.h>
++#include <glog/raw_logging.h>
+ #include "base/googleinit.h"
+
+ #ifdef HAVE_STACKTRACE
+@@ -1232,7 +1232,9 @@ void LogMessage::RecordCrashReason(
+ }
+
+ static void logging_fail() {
+-#if defined(_DEBUG) && defined(_MSC_VER)
++// #if defined(_DEBUG) && defined(_MSC_VER)
++// doesn't work for my laptop (sergey)
++#if 0
+ // When debugging on windows, avoid the obnoxious dialog and make
+ // it possible to continue past a LOG(FATAL) in the debugger
+ _asm int 3
+diff --git a/src/third_party/glog/src/raw_logging.cc b/src/third_party/glog/src/raw_logging.cc
+index 50c6a71..b179a1e 100644
+--- a/src/third_party/glog/src/raw_logging.cc
++++ b/src/third_party/glog/src/raw_logging.cc
+@@ -42,8 +42,8 @@
+ #include <fcntl.h> // for open()
+ #include <time.h>
+ #include "config.h"
+-#include "glog/logging.h" // To pick up flag settings etc.
+-#include "glog/raw_logging.h"
++#include <glog/logging.h> // To pick up flag settings etc.
++#include <glog/raw_logging.h>
+ #include "base/commandlineflags.h"
+
+ #ifdef HAVE_STACKTRACE
+diff --git a/src/third_party/glog/src/utilities.h b/src/third_party/glog/src/utilities.h
+index ee54f94..2d4e99e 100644
+--- a/src/third_party/glog/src/utilities.h
++++ b/src/third_party/glog/src/utilities.h
+@@ -79,7 +79,7 @@
+ #endif
+
+ #include "config.h"
+-#include "glog/logging.h"
++#include <glog/logging.h>
+
+ // There are three different ways we can try to get the stack trace:
+ //
+diff --git a/src/third_party/glog/src/vlog_is_on.cc b/src/third_party/glog/src/vlog_is_on.cc
+index ee0e412..ed88514 100644
+--- a/src/third_party/glog/src/vlog_is_on.cc
++++ b/src/third_party/glog/src/vlog_is_on.cc
+@@ -40,8 +40,8 @@
+ #include <cstdio>
+ #include <string>
+ #include "base/commandlineflags.h"
+-#include "glog/logging.h"
+-#include "glog/raw_logging.h"
++#include <glog/logging.h>
++#include <glog/raw_logging.h>
+ #include "base/googleinit.h"
+
+ // glog doesn't have annotation
+diff --git a/src/third_party/glog/src/windows/config.h b/src/third_party/glog/src/windows/config.h
+index 114762e..682a1b9 100755
+--- a/src/third_party/glog/src/windows/config.h
++++ b/src/third_party/glog/src/windows/config.h
+@@ -19,7 +19,7 @@
+ #undef HAVE_LIBUNWIND_H
+
+ /* define if you have google gflags library */
+-#undef HAVE_LIB_GFLAGS
++#define HAVE_LIB_GFLAGS 1
+
+ /* define if you have libunwind */
+ #undef HAVE_LIB_UNWIND
+diff --git a/src/third_party/glog/src/windows/glog/logging.h b/src/third_party/glog/src/windows/glog/logging.h
+index 7a6df74..de51586 100755
+--- a/src/third_party/glog/src/windows/glog/logging.h
++++ b/src/third_party/glog/src/windows/glog/logging.h
+@@ -82,8 +82,8 @@
+ #include <inttypes.h> // a third place for uint16_t or u_int16_t
+ #endif
+
+-#if 0
+-#include <gflags/gflags.h>
++#if 1
++#include "third_party/gflags/gflags.h"
+ #endif
+
+ namespace google {
diff --git a/extern/libmv/patches/config_mac.patch b/extern/libmv/patches/config_mac.patch
new file mode 100644
index 00000000000..5a880155bfa
--- /dev/null
+++ b/extern/libmv/patches/config_mac.patch
@@ -0,0 +1,13 @@
+diff --git a/src/third_party/glog/src/config_mac.h b/src/third_party/glog/src/config_mac.h
+index a45575b..5f953d1 100644
+--- a/src/third_party/glog/src/config_mac.h
++++ b/src/third_party/glog/src/config_mac.h
+@@ -131,7 +131,7 @@
+ #define PACKAGE_VERSION "0.3.1"
+
+ /* How to access the PC from a struct ucontext */
+-#define PC_FROM_UCONTEXT uc_mcontext->__ss.__rip
++#undef PC_FROM_UCONTEXT
+
+ /* Define to necessary symbol if this constant uses a non-standard name on
+ your system. */
diff --git a/extern/libmv/patches/detect.patch b/extern/libmv/patches/detect.patch
new file mode 100644
index 00000000000..36fea8427db
--- /dev/null
+++ b/extern/libmv/patches/detect.patch
@@ -0,0 +1,181 @@
+diff --git a/src/libmv/simple_pipeline/detect.cc b/src/libmv/simple_pipeline/detect.cc
+index 6fc0cdd..8ac42ab 100644
+--- a/src/libmv/simple_pipeline/detect.cc
++++ b/src/libmv/simple_pipeline/detect.cc
+@@ -23,15 +23,89 @@
+ ****************************************************************************/
+
+ #include "libmv/simple_pipeline/detect.h"
++#include <third_party/fast/fast.h>
+ #include <stdlib.h>
+-#include <string.h>
++#include <memory.h>
++
++#ifdef __SSE2__
++#include <emmintrin.h>
++#endif
+
+ namespace libmv {
+
+ typedef unsigned int uint;
+
++int featurecmp(const void *a_v, const void *b_v)
++{
++ Feature *a = (Feature*)a_v;
++ Feature *b = (Feature*)b_v;
++
++ return b->score - a->score;
++}
++
++std::vector<Feature> DetectFAST(const unsigned char* data, int width, int height, int stride,
++ int min_trackness, int min_distance) {
++ std::vector<Feature> features;
++ // TODO(MatthiasF): Support targetting a feature count (binary search trackness)
++ int num_features;
++ xy* all = fast9_detect(data, width, height,
++ stride, min_trackness, &num_features);
++ if(num_features == 0) {
++ free(all);
++ return features;
++ }
++ int* scores = fast9_score(data, stride, all, num_features, min_trackness);
++ // TODO: merge with close feature suppression
++ xy* nonmax = nonmax_suppression(all, scores, num_features, &num_features);
++ free(all);
++ // Remove too close features
++ // TODO(MatthiasF): A resolution independent parameter would be better than distance
++ // e.g. a coefficient going from 0 (no minimal distance) to 1 (optimal circle packing)
++ // FIXME(MatthiasF): this method will not necessarily give all maximum markers
++ if(num_features) {
++ Feature *all_features = new Feature[num_features];
++
++ for(int i = 0; i < num_features; ++i) {
++ Feature a = { nonmax[i].x, nonmax[i].y, scores[i], 0 };
++ all_features[i] = a;
++ }
++
++ qsort((void *)all_features, num_features, sizeof(Feature), featurecmp);
++
++ features.reserve(num_features);
++
++ int prev_score = all_features[0].score;
++ for(int i = 0; i < num_features; ++i) {
++ bool ok = true;
++ Feature a = all_features[i];
++ if(a.score>prev_score)
++ abort();
++ prev_score = a.score;
++
++ // compare each feature against filtered set
++ for(int j = 0; j < features.size(); j++) {
++ Feature& b = features[j];
++ if ( (a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y) < min_distance*min_distance ) {
++ // already a nearby feature
++ ok = false;
++ break;
++ }
++ }
++
++ if(ok) {
++ // add the new feature
++ features.push_back(a);
++ }
++ }
++
++ delete [] all_features;
++ }
++ free(scores);
++ free(nonmax);
++ return features;
++}
++
+ #ifdef __SSE2__
+-#include <emmintrin.h>
+ static uint SAD(const ubyte* imageA, const ubyte* imageB, int strideA, int strideB) {
+ __m128i a = _mm_setzero_si128();
+ for(int i = 0; i < 16; i++) {
+@@ -52,7 +126,7 @@ static uint SAD(const ubyte* imageA, const ubyte* imageB, int strideA, int strid
+ }
+ #endif
+
+-void Detect(ubyte* image, int stride, int width, int height, Feature* detected, int* count, int distance, ubyte* pattern) {
++void DetectMORAVEC(ubyte* image, int stride, int width, int height, Feature* detected, int* count, int distance, ubyte* pattern) {
+ unsigned short histogram[256];
+ memset(histogram,0,sizeof(histogram));
+ ubyte* scores = new ubyte[width*height];
+diff --git a/src/libmv/simple_pipeline/detect.h b/src/libmv/simple_pipeline/detect.h
+index 23b239b..bbe7aed 100644
+--- a/src/libmv/simple_pipeline/detect.h
++++ b/src/libmv/simple_pipeline/detect.h
+@@ -25,27 +25,52 @@
+ #ifndef LIBMV_SIMPLE_PIPELINE_DETECT_H_
+ #define LIBMV_SIMPLE_PIPELINE_DETECT_H_
+
+-#ifdef __cplusplus
++#include <vector>
++
+ namespace libmv {
+-#endif
+
+ typedef unsigned char ubyte;
+
+ /*!
+- \a Feature is the 2D location of a detected feature in an image.
++ A Feature is the 2D location of a detected feature in an image.
+
+- \a x, \a y is the position of the center in pixels (from image top-left).
+- \a score is an estimate of how well the pattern will be tracked.
+- \a size can be used as an initial size to track the pattern.
++ \a x, \a y is the position of the feature in pixels from the top left corner.
++ \a score is an estimate of how well the feature will be tracked.
++ \a size can be used as an initial pattern size to track the feature.
+
+ \sa Detect
+ */
+ struct Feature {
++ /// Position in pixels (from top-left corner)
++ /// \note libmv might eventually support subpixel precision.
+ float x, y;
++ /// Trackness of the feature
+ float score;
++ /// Size of the feature in pixels
+ float size;
+ };
+- //radius for non maximal suppression
++
++/*!
++ Detect features in an image.
++
++ You need to input a single channel 8-bit image using pointer to image \a data,
++ \a width, \a height and \a stride (i.e bytes per line).
++
++ You can tweak the count of detected features using \a min_trackness, which is
++ the minimum score to add a feature, and \a min_distance which is the minimal
++ distance accepted between two featuress.
++
++ \note You can binary search over \a min_trackness to get a given feature count.
++
++ \note a way to get an uniform distribution of a given feature count is:
++ \a min_distance = \a width * \a height / desired_feature_count ^ 2
++
++ \return All detected feartures matching given parameters
++*/
++std::vector<Feature> DetectFAST(const unsigned char* data, int width, int height,
++ int stride, int min_trackness = 128,
++ int min_distance = 120);
++
+ /*!
+ Detect features in an image.
+
+@@ -63,10 +88,8 @@ struct Feature {
+ \note \a You can crop the image (to avoid detecting markers near the borders) without copying:
+ image += marginY*stride+marginX, width -= 2*marginX, height -= 2*marginY;
+ */
+-void Detect(ubyte* image, int stride, int width, int height, Feature* detected, int* count, int distance /*=32*/, ubyte* pattern /*=0*/);
++void DetectMORAVEC(ubyte* image, int stride, int width, int height, Feature* detected, int* count, int distance /*=32*/, ubyte* pattern /*=0*/);
+
+-#ifdef __cplusplus
+ }
+-#endif
+
+ #endif
diff --git a/extern/libmv/patches/fast.patch b/extern/libmv/patches/fast.patch
new file mode 100644
index 00000000000..8e0aeb7e721
--- /dev/null
+++ b/extern/libmv/patches/fast.patch
@@ -0,0 +1,24 @@
+diff --git a/src/third_party/fast/fast.h b/src/third_party/fast/fast.h
+index 2b3825a..06fa90e 100644
+--- a/src/third_party/fast/fast.h
++++ b/src/third_party/fast/fast.h
+@@ -1,6 +1,10 @@
+ #ifndef FAST_H
+ #define FAST_H
+
++#ifdef __cplusplus
++extern "C" {
++#endif
++
+ typedef struct { int x, y; } xy;
+ typedef unsigned char byte;
+
+@@ -28,4 +32,8 @@ xy* fast12_detect_nonmax(const byte* im, int xsize, int ysize, int stride, int b
+ xy* nonmax_suppression(const xy* corners, const int* scores, int num_corners, int* ret_num_nonmax);
+
+
++#ifdef __cplusplus
++}
++#endif
++
+ #endif
diff --git a/extern/libmv/patches/function_derivative.patch b/extern/libmv/patches/function_derivative.patch
new file mode 100644
index 00000000000..be7ccfc911a
--- /dev/null
+++ b/extern/libmv/patches/function_derivative.patch
@@ -0,0 +1,21 @@
+diff --git a/src/libmv/numeric/function_derivative.h b/src/libmv/numeric/function_derivative.h
+index 0075d23..d7bc437 100644
+--- a/src/libmv/numeric/function_derivative.h
++++ b/src/libmv/numeric/function_derivative.h
+@@ -24,6 +24,7 @@
+ #include <cmath>
+
+ #include "libmv/numeric/numeric.h"
++#include "libmv/logging/logging.h"
+
+ namespace libmv {
+
+@@ -97,7 +98,7 @@ bool CheckJacobian(const Function &f, const typename Function::XMatrixType &x) {
+
+ typename NumericJacobian<Function>::JMatrixType J_numeric = j_numeric(x);
+ typename NumericJacobian<Function>::JMatrixType J_analytic = j_analytic(x);
+- //LG << J_numeric - J_analytic;
++ LG << J_numeric - J_analytic;
+ return true;
+ }
+
diff --git a/extern/libmv/patches/high_distortion_crash_fix.patch b/extern/libmv/patches/high_distortion_crash_fix.patch
new file mode 100644
index 00000000000..54ab66fa27c
--- /dev/null
+++ b/extern/libmv/patches/high_distortion_crash_fix.patch
@@ -0,0 +1,21 @@
+diff --git a/src/libmv/simple_pipeline/camera_intrinsics.cc b/src/libmv/simple_pipeline/camera_intrinsics.cc
+index 4e88e1f..f9888ff 100644
+--- a/src/libmv/simple_pipeline/camera_intrinsics.cc
++++ b/src/libmv/simple_pipeline/camera_intrinsics.cc
+@@ -160,9 +160,13 @@ void CameraIntrinsics::ComputeLookupGrid(Offset* grid, int width, int height) {
+ if( iy < 0 ) { iy = 0, fy = 0; }
+ if( ix >= width-2 ) ix = width-2;
+ if( iy >= height-2 ) iy = height-2;
+- //assert( ix-x > -128 && ix-x < 128 && iy-y > -128 && iy-y < 128 );
+- Offset offset = { ix-x, iy-y, fx, fy };
+- grid[y*width+x] = offset;
++ if ( ix-x > -128 && ix-x < 128 && iy-y > -128 && iy-y < 128 ) {
++ Offset offset = { ix-x, iy-y, fx, fy };
++ grid[y*width+x] = offset;
++ } else {
++ Offset offset = { 0, 0, 0, 0 };
++ grid[y*width+x] = offset;
++ }
+ }
+ }
+ }
diff --git a/extern/libmv/patches/levenberg_marquardt.patch b/extern/libmv/patches/levenberg_marquardt.patch
new file mode 100644
index 00000000000..49ef82d73d2
--- /dev/null
+++ b/extern/libmv/patches/levenberg_marquardt.patch
@@ -0,0 +1,71 @@
+diff --git a/src/libmv/numeric/levenberg_marquardt.h b/src/libmv/numeric/levenberg_marquardt.h
+index 6a54f66..4473b72 100644
+--- a/src/libmv/numeric/levenberg_marquardt.h
++++ b/src/libmv/numeric/levenberg_marquardt.h
+@@ -33,6 +33,7 @@
+
+ #include "libmv/numeric/numeric.h"
+ #include "libmv/numeric/function_derivative.h"
++#include "libmv/logging/logging.h"
+
+ namespace libmv {
+
+@@ -123,26 +124,40 @@ class LevenbergMarquardt {
+ Parameters dx, x_new;
+ int i;
+ for (i = 0; results.status == RUNNING && i < params.max_iterations; ++i) {
+- if (dx.norm() <= params.relative_step_threshold * x.norm()) {
++ VLOG(1) << "iteration: " << i;
++ VLOG(1) << "||f(x)||: " << f_(x).norm();
++ VLOG(1) << "max(g): " << g.array().abs().maxCoeff();
++ VLOG(1) << "u: " << u;
++ VLOG(1) << "v: " << v;
++
++ AMatrixType A_augmented = A + u*AMatrixType::Identity(J.cols(), J.cols());
++ Solver solver(A_augmented);
++ dx = solver.solve(g);
++ bool solved = (A_augmented * dx).isApprox(g);
++ if (!solved) {
++ LOG(ERROR) << "Failed to solve";
++ }
++ if (solved && dx.norm() <= params.relative_step_threshold * x.norm()) {
+ results.status = RELATIVE_STEP_SIZE_TOO_SMALL;
+ break;
+- }
+- x_new = x + dx;
+- // Rho is the ratio of the actual reduction in error to the reduction
+- // in error that would be obtained if the problem was linear.
+- // See [1] for details.
+- Scalar rho((error.squaredNorm() - f_(x_new).squaredNorm())
+- / dx.dot(u*dx + g));
+- if (rho > 0) {
+- // Accept the Gauss-Newton step because the linear model fits well.
+- x = x_new;
+- results.status = Update(x, params, &J, &A, &error, &g);
+- Scalar tmp = Scalar(2*rho-1);
+- u = u*std::max(1/3., 1 - (tmp*tmp*tmp));
+- v = 2;
+- continue;
+- }
+-
++ }
++ if (solved) {
++ x_new = x + dx;
++ // Rho is the ratio of the actual reduction in error to the reduction
++ // in error that would be obtained if the problem was linear.
++ // See [1] for details.
++ Scalar rho((error.squaredNorm() - f_(x_new).squaredNorm())
++ / dx.dot(u*dx + g));
++ if (rho > 0) {
++ // Accept the Gauss-Newton step because the linear model fits well.
++ x = x_new;
++ results.status = Update(x, params, &J, &A, &error, &g);
++ Scalar tmp = Scalar(2*rho-1);
++ u = u*std::max(1/3., 1 - (tmp*tmp*tmp));
++ v = 2;
++ continue;
++ }
++ }
+ // Reject the update because either the normal equations failed to solve
+ // or the local linear model was not good (rho < 0). Instead, increase u
+ // to move closer to gradient descent.
diff --git a/extern/libmv/patches/mingw.patch b/extern/libmv/patches/mingw.patch
new file mode 100644
index 00000000000..0b08a483bea
--- /dev/null
+++ b/extern/libmv/patches/mingw.patch
@@ -0,0 +1,13 @@
+diff --git a/src/libmv/numeric/numeric.h b/src/libmv/numeric/numeric.h
+index f39d126..21e0f06 100644
+--- a/src/libmv/numeric/numeric.h
++++ b/src/libmv/numeric/numeric.h
+@@ -40,7 +40,7 @@
+ }
+ #endif //_WIN32 || __APPLE__
+
+-#if _WIN32
++#if (defined(WIN32) || defined(WIN64)) && !defined(__MINGW32__)
+ inline long lround(double d) {
+ return (long)(d>0 ? d+0.5 : ceil(d-0.5));
+ }
diff --git a/extern/libmv/patches/msvc2010.patch b/extern/libmv/patches/msvc2010.patch
new file mode 100644
index 00000000000..c090b070628
--- /dev/null
+++ b/extern/libmv/patches/msvc2010.patch
@@ -0,0 +1,12 @@
+diff --git a/src/libmv/simple_pipeline/tracks.cc b/src/libmv/simple_pipeline/tracks.cc
+index 0e2a1b6..3fb8ddb 100644
+--- a/src/libmv/simple_pipeline/tracks.cc
++++ b/src/libmv/simple_pipeline/tracks.cc
+@@ -20,6 +20,7 @@
+
+ #include <algorithm>
+ #include <vector>
++#include <iterator>
+
+ #include "libmv/numeric/numeric.h"
+ #include "libmv/simple_pipeline/tracks.h"
diff --git a/extern/libmv/patches/overscan.patch b/extern/libmv/patches/overscan.patch
new file mode 100644
index 00000000000..c68f36804ec
--- /dev/null
+++ b/extern/libmv/patches/overscan.patch
@@ -0,0 +1,182 @@
+diff --git a/src/libmv/simple_pipeline/camera_intrinsics.cc b/src/libmv/simple_pipeline/camera_intrinsics.cc
+index 110a16d..366129d 100644
+--- a/src/libmv/simple_pipeline/camera_intrinsics.cc
++++ b/src/libmv/simple_pipeline/camera_intrinsics.cc
+@@ -31,6 +31,7 @@ struct Offset {
+ struct Grid {
+ struct Offset *offset;
+ int width, height;
++ double overscan;
+ };
+
+ static struct Grid *copyGrid(struct Grid *from)
+@@ -42,6 +43,7 @@ static struct Grid *copyGrid(struct Grid *from)
+
+ to->width = from->width;
+ to->height = from->height;
++ to->overscan = from->overscan;
+
+ to->offset = new Offset[to->width*to->height];
+ memcpy(to->offset, from->offset, sizeof(struct Offset)*to->width*to->height);
+@@ -184,17 +186,19 @@ void CameraIntrinsics::InvertIntrinsics(double image_x,
+
+ // TODO(MatthiasF): downsample lookup
+ template<typename WarpFunction>
+-void CameraIntrinsics::ComputeLookupGrid(Grid* grid, int width, int height) {
+- double aspx = (double)width / image_width_;
+- double aspy = (double)height / image_height_;
++void CameraIntrinsics::ComputeLookupGrid(Grid* grid, int width, int height, double overscan) {
++ double w = (double)width / (1 + overscan);
++ double h = (double)height / (1 + overscan);
++ double aspx = (double)w / image_width_;
++ double aspy = (double)h / image_height_;
+
+ for (int y = 0; y < height; y++) {
+ for (int x = 0; x < width; x++) {
+- double src_x = x / aspx, src_y = y / aspy;
++ double src_x = (x - 0.5 * overscan * w) / aspx, src_y = (y - 0.5 * overscan * h) / aspy;
+ double warp_x, warp_y;
+ WarpFunction(this,src_x,src_y,&warp_x,&warp_y);
+- warp_x = warp_x*aspx;
+- warp_y = warp_y*aspy;
++ warp_x = warp_x*aspx + 0.5 * overscan * w;
++ warp_y = warp_y*aspy + 0.5 * overscan * h;
+ int ix = int(warp_x), iy = int(warp_y);
+ int fx = round((warp_x-ix)*256), fy = round((warp_y-iy)*256);
+ if(fx == 256) { fx=0; ix++; }
+@@ -264,10 +268,10 @@ struct InvertIntrinsicsFunction {
+ }
+ };
+
+-void CameraIntrinsics::CheckDistortLookupGrid(int width, int height)
++void CameraIntrinsics::CheckDistortLookupGrid(int width, int height, double overscan)
+ {
+ if(distort_) {
+- if(distort_->width != width || distort_->height != height) {
++ if(distort_->width != width || distort_->height != height || distort_->overscan != overscan) {
+ delete [] distort_->offset;
+ distort_->offset = NULL;
+ }
+@@ -278,17 +282,18 @@ void CameraIntrinsics::CheckDistortLookupGrid(int width, int height)
+
+ if(!distort_->offset) {
+ distort_->offset = new Offset[width*height];
+- ComputeLookupGrid<InvertIntrinsicsFunction>(distort_,width,height);
++ ComputeLookupGrid<InvertIntrinsicsFunction>(distort_,width,height,overscan);
+ }
+
+ distort_->width = width;
+ distort_->height = height;
++ distort_->overscan = overscan;
+ }
+
+-void CameraIntrinsics::CheckUndistortLookupGrid(int width, int height)
++void CameraIntrinsics::CheckUndistortLookupGrid(int width, int height, double overscan)
+ {
+ if(undistort_) {
+- if(undistort_->width != width || undistort_->height != height) {
++ if(undistort_->width != width || undistort_->height != height || undistort_->overscan != overscan) {
+ delete [] undistort_->offset;
+ undistort_->offset = NULL;
+ }
+@@ -299,15 +304,16 @@ void CameraIntrinsics::CheckUndistortLookupGrid(int width, int height)
+
+ if(!undistort_->offset) {
+ undistort_->offset = new Offset[width*height];
+- ComputeLookupGrid<ApplyIntrinsicsFunction>(undistort_,width,height);
++ ComputeLookupGrid<ApplyIntrinsicsFunction>(undistort_,width,height,overscan);
+ }
+
+ undistort_->width = width;
+ undistort_->height = height;
++ undistort_->overscan = overscan;
+ }
+
+-void CameraIntrinsics::Distort(const float* src, float* dst, int width, int height, int channels) {
+- CheckDistortLookupGrid(width, height);
++void CameraIntrinsics::Distort(const float* src, float* dst, int width, int height, double overscan, int channels) {
++ CheckDistortLookupGrid(width, height, overscan);
+ if(channels==1) Warp<float,1>(distort_,src,dst,width,height);
+ else if(channels==2) Warp<float,2>(distort_,src,dst,width,height);
+ else if(channels==3) Warp<float,3>(distort_,src,dst,width,height);
+@@ -315,8 +321,8 @@ void CameraIntrinsics::Distort(const float* src, float* dst, int width, int heig
+ //else assert("channels must be between 1 and 4");
+ }
+
+-void CameraIntrinsics::Distort(const unsigned char* src, unsigned char* dst, int width, int height, int channels) {
+- CheckDistortLookupGrid(width, height);
++void CameraIntrinsics::Distort(const unsigned char* src, unsigned char* dst, int width, int height, double overscan, int channels) {
++ CheckDistortLookupGrid(width, height, overscan);
+ if(channels==1) Warp<unsigned char,1>(distort_,src,dst,width,height);
+ else if(channels==2) Warp<unsigned char,2>(distort_,src,dst,width,height);
+ else if(channels==3) Warp<unsigned char,3>(distort_,src,dst,width,height);
+@@ -324,8 +330,8 @@ void CameraIntrinsics::Distort(const unsigned char* src, unsigned char* dst, int
+ //else assert("channels must be between 1 and 4");
+ }
+
+-void CameraIntrinsics::Undistort(const float* src, float* dst, int width, int height, int channels) {
+- CheckUndistortLookupGrid(width, height);
++void CameraIntrinsics::Undistort(const float* src, float* dst, int width, int height, double overscan, int channels) {
++ CheckUndistortLookupGrid(width, height, overscan);
+ if(channels==1) Warp<float,1>(undistort_,src,dst,width,height);
+ else if(channels==2) Warp<float,2>(undistort_,src,dst,width,height);
+ else if(channels==3) Warp<float,3>(undistort_,src,dst,width,height);
+@@ -333,8 +339,8 @@ void CameraIntrinsics::Undistort(const float* src, float* dst, int width, int he
+ //else assert("channels must be between 1 and 4");
+ }
+
+-void CameraIntrinsics::Undistort(const unsigned char* src, unsigned char* dst, int width, int height, int channels) {
+- CheckUndistortLookupGrid(width, height);
++void CameraIntrinsics::Undistort(const unsigned char* src, unsigned char* dst, int width, int height, double overscan, int channels) {
++ CheckUndistortLookupGrid(width, height, overscan);
+ if(channels==1) Warp<unsigned char,1>(undistort_,src,dst,width,height);
+ else if(channels==2) Warp<unsigned char,2>(undistort_,src,dst,width,height);
+ else if(channels==3) Warp<unsigned char,3>(undistort_,src,dst,width,height);
+diff --git a/src/libmv/simple_pipeline/camera_intrinsics.h b/src/libmv/simple_pipeline/camera_intrinsics.h
+index f525571..f4bf903 100644
+--- a/src/libmv/simple_pipeline/camera_intrinsics.h
++++ b/src/libmv/simple_pipeline/camera_intrinsics.h
+@@ -91,7 +91,7 @@ class CameraIntrinsics {
+ \note This is the reference implementation using floating point images.
+ */
+ void Distort(const float* src, float* dst,
+- int width, int height, int channels);
++ int width, int height, double overscan, int channels);
+ /*!
+ Distort an image using the current camera instrinsics
+
+@@ -101,7 +101,7 @@ class CameraIntrinsics {
+ \note This version is much faster.
+ */
+ void Distort(const unsigned char* src, unsigned char* dst,
+- int width, int height, int channels);
++ int width, int height, double overscan, int channels);
+ /*!
+ Undistort an image using the current camera instrinsics
+
+@@ -111,7 +111,7 @@ class CameraIntrinsics {
+ \note This is the reference implementation using floating point images.
+ */
+ void Undistort(const float* src, float* dst,
+- int width, int height, int channels);
++ int width, int height, double overscan, int channels);
+ /*!
+ Undistort an image using the current camera instrinsics
+
+@@ -121,12 +121,12 @@ class CameraIntrinsics {
+ \note This version is much faster.
+ */
+ void Undistort(const unsigned char* src, unsigned char* dst,
+- int width, int height, int channels);
++ int width, int height, double overscan, int channels);
+
+ private:
+- template<typename WarpFunction> void ComputeLookupGrid(struct Grid* grid, int width, int height);
+- void CheckUndistortLookupGrid(int width, int height);
+- void CheckDistortLookupGrid(int width, int height);
++ template<typename WarpFunction> void ComputeLookupGrid(struct Grid* grid, int width, int height, double overscan);
++ void CheckUndistortLookupGrid(int width, int height, double overscan);
++ void CheckDistortLookupGrid(int width, int height, double overscan);
+ void FreeLookupGrid();
+
+ // The traditional intrinsics matrix from x = K[R|t]X.
diff --git a/extern/libmv/patches/scaled_distortion.patch b/extern/libmv/patches/scaled_distortion.patch
new file mode 100644
index 00000000000..2da832931d1
--- /dev/null
+++ b/extern/libmv/patches/scaled_distortion.patch
@@ -0,0 +1,261 @@
+diff --git a/src/libmv/simple_pipeline/camera_intrinsics.cc b/src/libmv/simple_pipeline/camera_intrinsics.cc
+index f9888ff..110a16d 100644
+--- a/src/libmv/simple_pipeline/camera_intrinsics.cc
++++ b/src/libmv/simple_pipeline/camera_intrinsics.cc
+@@ -23,7 +23,32 @@
+
+ namespace libmv {
+
+-struct Offset { signed char ix,iy; unsigned char fx,fy; };
++struct Offset {
++ signed char ix, iy;
++ unsigned char fx,fy;
++};
++
++struct Grid {
++ struct Offset *offset;
++ int width, height;
++};
++
++static struct Grid *copyGrid(struct Grid *from)
++{
++ struct Grid *to = NULL;
++
++ if (from) {
++ to = new Grid;
++
++ to->width = from->width;
++ to->height = from->height;
++
++ to->offset = new Offset[to->width*to->height];
++ memcpy(to->offset, from->offset, sizeof(struct Offset)*to->width*to->height);
++ }
++
++ return to;
++}
+
+ CameraIntrinsics::CameraIntrinsics()
+ : K_(Mat3::Identity()),
+@@ -37,9 +62,22 @@ CameraIntrinsics::CameraIntrinsics()
+ distort_(0),
+ undistort_(0) {}
+
++CameraIntrinsics::CameraIntrinsics(const CameraIntrinsics &from)
++ : K_(from.K_),
++ image_width_(from.image_width_),
++ image_height_(from.image_height_),
++ k1_(from.k1_),
++ k2_(from.k2_),
++ k3_(from.k3_),
++ p1_(from.p1_),
++ p2_(from.p2_)
++{
++ distort_ = copyGrid(from.distort_);
++ undistort_ = copyGrid(from.undistort_);
++}
++
+ CameraIntrinsics::~CameraIntrinsics() {
+- if(distort_) delete[] distort_;
+- if(undistort_) delete[] undistort_;
++ FreeLookupGrid();
+ }
+
+ /// Set the entire calibration matrix at once.
+@@ -146,11 +184,17 @@ void CameraIntrinsics::InvertIntrinsics(double image_x,
+
+ // TODO(MatthiasF): downsample lookup
+ template<typename WarpFunction>
+-void CameraIntrinsics::ComputeLookupGrid(Offset* grid, int width, int height) {
++void CameraIntrinsics::ComputeLookupGrid(Grid* grid, int width, int height) {
++ double aspx = (double)width / image_width_;
++ double aspy = (double)height / image_height_;
++
+ for (int y = 0; y < height; y++) {
+ for (int x = 0; x < width; x++) {
++ double src_x = x / aspx, src_y = y / aspy;
+ double warp_x, warp_y;
+- WarpFunction(this,x,y,&warp_x,&warp_y);
++ WarpFunction(this,src_x,src_y,&warp_x,&warp_y);
++ warp_x = warp_x*aspx;
++ warp_y = warp_y*aspy;
+ int ix = int(warp_x), iy = int(warp_y);
+ int fx = round((warp_x-ix)*256), fy = round((warp_y-iy)*256);
+ if(fx == 256) { fx=0; ix++; }
+@@ -162,10 +206,10 @@ void CameraIntrinsics::ComputeLookupGrid(Offset* grid, int width, int height) {
+ if( iy >= height-2 ) iy = height-2;
+ if ( ix-x > -128 && ix-x < 128 && iy-y > -128 && iy-y < 128 ) {
+ Offset offset = { ix-x, iy-y, fx, fy };
+- grid[y*width+x] = offset;
++ grid->offset[y*width+x] = offset;
+ } else {
+ Offset offset = { 0, 0, 0, 0 };
+- grid[y*width+x] = offset;
++ grid->offset[y*width+x] = offset;
+ }
+ }
+ }
+@@ -173,11 +217,11 @@ void CameraIntrinsics::ComputeLookupGrid(Offset* grid, int width, int height) {
+
+ // TODO(MatthiasF): cubic B-Spline image sampling, bilinear lookup
+ template<typename T,int N>
+-static void Warp(const Offset* grid, const T* src, T* dst,
++static void Warp(const Grid* grid, const T* src, T* dst,
+ int width, int height) {
+ for (int y = 0; y < height; y++) {
+ for (int x = 0; x < width; x++) {
+- Offset offset = grid[y*width+x];
++ Offset offset = grid->offset[y*width+x];
+ const T* s = &src[((y+offset.iy)*width+(x+offset.ix))*N];
+ for (int i = 0; i < N; i++) {
+ dst[(y*width+x)*N+i] = ((s[ i] * (256-offset.fx) + s[ N+i] * offset.fx) * (256-offset.fy)
+@@ -188,8 +232,17 @@ static void Warp(const Offset* grid, const T* src, T* dst,
+ }
+
+ void CameraIntrinsics::FreeLookupGrid() {
+- if(distort_) delete distort_, distort_=0;
+- if(undistort_) delete undistort_, undistort_=0;
++ if(distort_) {
++ delete distort_->offset;
++ delete distort_;
++ distort_ = NULL;
++ }
++
++ if(undistort_) {
++ delete undistort_->offset;
++ delete undistort_;
++ undistort_ = NULL;
++ }
+ }
+
+ // FIXME: C++ templates limitations makes thing complicated, but maybe there is a simpler method.
+@@ -211,11 +264,50 @@ struct InvertIntrinsicsFunction {
+ }
+ };
+
+-void CameraIntrinsics::Distort(const float* src, float* dst, int width, int height, int channels) {
+- if(!distort_) {
+- distort_ = new Offset[width*height];
+- ComputeLookupGrid<InvertIntrinsicsFunction>(distort_,width,height);
++void CameraIntrinsics::CheckDistortLookupGrid(int width, int height)
++{
++ if(distort_) {
++ if(distort_->width != width || distort_->height != height) {
++ delete [] distort_->offset;
++ distort_->offset = NULL;
++ }
++ } else {
++ distort_ = new Grid;
++ distort_->offset = NULL;
++ }
++
++ if(!distort_->offset) {
++ distort_->offset = new Offset[width*height];
++ ComputeLookupGrid<InvertIntrinsicsFunction>(distort_,width,height);
+ }
++
++ distort_->width = width;
++ distort_->height = height;
++}
++
++void CameraIntrinsics::CheckUndistortLookupGrid(int width, int height)
++{
++ if(undistort_) {
++ if(undistort_->width != width || undistort_->height != height) {
++ delete [] undistort_->offset;
++ undistort_->offset = NULL;
++ }
++ } else {
++ undistort_ = new Grid;
++ undistort_->offset = NULL;
++ }
++
++ if(!undistort_->offset) {
++ undistort_->offset = new Offset[width*height];
++ ComputeLookupGrid<ApplyIntrinsicsFunction>(undistort_,width,height);
++ }
++
++ undistort_->width = width;
++ undistort_->height = height;
++}
++
++void CameraIntrinsics::Distort(const float* src, float* dst, int width, int height, int channels) {
++ CheckDistortLookupGrid(width, height);
+ if(channels==1) Warp<float,1>(distort_,src,dst,width,height);
+ else if(channels==2) Warp<float,2>(distort_,src,dst,width,height);
+ else if(channels==3) Warp<float,3>(distort_,src,dst,width,height);
+@@ -224,10 +316,7 @@ void CameraIntrinsics::Distort(const float* src, float* dst, int width, int heig
+ }
+
+ void CameraIntrinsics::Distort(const unsigned char* src, unsigned char* dst, int width, int height, int channels) {
+- if(!distort_) {
+- distort_ = new Offset[width*height];
+- ComputeLookupGrid<InvertIntrinsicsFunction>(distort_,width,height);
+- }
++ CheckDistortLookupGrid(width, height);
+ if(channels==1) Warp<unsigned char,1>(distort_,src,dst,width,height);
+ else if(channels==2) Warp<unsigned char,2>(distort_,src,dst,width,height);
+ else if(channels==3) Warp<unsigned char,3>(distort_,src,dst,width,height);
+@@ -236,10 +325,7 @@ void CameraIntrinsics::Distort(const unsigned char* src, unsigned char* dst, int
+ }
+
+ void CameraIntrinsics::Undistort(const float* src, float* dst, int width, int height, int channels) {
+- if(!undistort_) {
+- undistort_ = new Offset[width*height];
+- ComputeLookupGrid<ApplyIntrinsicsFunction>(undistort_,width,height);
+- }
++ CheckUndistortLookupGrid(width, height);
+ if(channels==1) Warp<float,1>(undistort_,src,dst,width,height);
+ else if(channels==2) Warp<float,2>(undistort_,src,dst,width,height);
+ else if(channels==3) Warp<float,3>(undistort_,src,dst,width,height);
+@@ -248,10 +334,7 @@ void CameraIntrinsics::Undistort(const float* src, float* dst, int width, int he
+ }
+
+ void CameraIntrinsics::Undistort(const unsigned char* src, unsigned char* dst, int width, int height, int channels) {
+- if(!undistort_) {
+- undistort_ = new Offset[width*height];
+- ComputeLookupGrid<ApplyIntrinsicsFunction>(undistort_,width,height);
+- }
++ CheckUndistortLookupGrid(width, height);
+ if(channels==1) Warp<unsigned char,1>(undistort_,src,dst,width,height);
+ else if(channels==2) Warp<unsigned char,2>(undistort_,src,dst,width,height);
+ else if(channels==3) Warp<unsigned char,3>(undistort_,src,dst,width,height);
+diff --git a/src/libmv/simple_pipeline/camera_intrinsics.h b/src/libmv/simple_pipeline/camera_intrinsics.h
+index 29bc8a1..f525571 100644
+--- a/src/libmv/simple_pipeline/camera_intrinsics.h
++++ b/src/libmv/simple_pipeline/camera_intrinsics.h
+@@ -26,11 +26,12 @@ typedef Eigen::Matrix<double, 3, 3> Mat3;
+
+ namespace libmv {
+
+-struct Offset;
++struct Grid;
+
+ class CameraIntrinsics {
+ public:
+ CameraIntrinsics();
++ CameraIntrinsics(const CameraIntrinsics &from);
+ ~CameraIntrinsics();
+
+ const Mat3 &K() const { return K_; }
+@@ -123,7 +124,9 @@ class CameraIntrinsics {
+ int width, int height, int channels);
+
+ private:
+- template<typename WarpFunction> void ComputeLookupGrid(Offset* grid, int width, int height);
++ template<typename WarpFunction> void ComputeLookupGrid(struct Grid* grid, int width, int height);
++ void CheckUndistortLookupGrid(int width, int height);
++ void CheckDistortLookupGrid(int width, int height);
+ void FreeLookupGrid();
+
+ // The traditional intrinsics matrix from x = K[R|t]X.
+@@ -140,8 +143,8 @@ class CameraIntrinsics {
+ // independent of image size.
+ double k1_, k2_, k3_, p1_, p2_;
+
+- Offset* distort_;
+- Offset* undistort_;
++ struct Grid *distort_;
++ struct Grid *undistort_;
+ };
+
+ } // namespace libmv
diff --git a/extern/libmv/patches/series b/extern/libmv/patches/series
new file mode 100644
index 00000000000..00a52c1cfaa
--- /dev/null
+++ b/extern/libmv/patches/series
@@ -0,0 +1,13 @@
+v3d_verbosity.patch
+snrptinf_fix.patch
+bundle_tweaks.patch
+fast.patch
+config_mac.patch
+levenberg_marquardt.patch
+function_derivative.patch
+high_distortion_crash_fix.patch
+mingw.patch
+msvc2010.patch
+scaled_distortion.patch
+overscan.patch
+detect.patch
diff --git a/extern/libmv/patches/snrptinf_fix.patch b/extern/libmv/patches/snrptinf_fix.patch
new file mode 100644
index 00000000000..e886a671de0
--- /dev/null
+++ b/extern/libmv/patches/snrptinf_fix.patch
@@ -0,0 +1,15 @@
+diff --git a/src/libmv/simple_pipeline/pipeline.cc b/src/libmv/simple_pipeline/pipeline.cc
+index 652d70c..25cd2c2 100644
+--- a/src/libmv/simple_pipeline/pipeline.cc
++++ b/src/libmv/simple_pipeline/pipeline.cc
+@@ -28,6 +28,10 @@
+ #include "libmv/simple_pipeline/tracks.h"
+ #include "libmv/simple_pipeline/camera_intrinsics.h"
+
++#ifdef _MSC_VER
++# define snprintf _snprintf
++#endif
++
+ namespace libmv {
+
+ void CompleteReconstruction(const Tracks &tracks,
diff --git a/extern/libmv/patches/v3d_verbosity.patch b/extern/libmv/patches/v3d_verbosity.patch
new file mode 100644
index 00000000000..a54f3dc44be
--- /dev/null
+++ b/extern/libmv/patches/v3d_verbosity.patch
@@ -0,0 +1,12 @@
+diff --git a/src/libmv/simple_pipeline/bundle.cc b/src/libmv/simple_pipeline/bundle.cc
+index 310660d..f819603 100644
+--- a/src/libmv/simple_pipeline/bundle.cc
++++ b/src/libmv/simple_pipeline/bundle.cc
+@@ -141,7 +141,6 @@ void Bundle(const Tracks &tracks, Reconstruction *reconstruction) {
+ v3d_distortion.p2 = 0;
+
+ // Finally, run the bundle adjustment.
+- V3D::optimizerVerbosenessLevel = 1;
+ double const inlierThreshold = 500000.0;
+ V3D::CommonInternalsMetricBundleOptimizer opt(V3D::FULL_BUNDLE_METRIC,
+ inlierThreshold,
diff --git a/extern/libmv/third_party/fast/LICENSE b/extern/libmv/third_party/fast/LICENSE
new file mode 100644
index 00000000000..f347008d6ef
--- /dev/null
+++ b/extern/libmv/third_party/fast/LICENSE
@@ -0,0 +1,30 @@
+Copyright (c) 2006, 2008 Edward Rosten
+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 University of Cambridge 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.
diff --git a/extern/libmv/third_party/fast/README b/extern/libmv/third_party/fast/README
new file mode 100644
index 00000000000..77017078d08
--- /dev/null
+++ b/extern/libmv/third_party/fast/README
@@ -0,0 +1,31 @@
+FAST feature detectors in C Version 2.0
+---------------------------------------
+
+The files are valid C and C++ code, and have no special requirements for
+compiling, and they do not depend on any libraries. Just compile them along with
+the rest of your project.
+
+To use the functions, #include "fast.h"
+
+The corner detectors have the following prototype (where X is 9, 10, 11 or 12):
+
+xy* fastX_detect_nonmax(const unsigned char * data, int xsize, int ysize, int stride, int threshold, int* numcorners)
+
+Where xy is the following simple struct typedef:
+
+typedef struct
+{
+ int x, y;
+} xy;
+
+The image is passed in as a block of data and dimensions, and the list of
+corners is returned as an array of xy structs, and an integer (numcorners)
+with the number of corners returned. The data can be deallocated with free().
+Nonmaximal suppression is performed on the corners. Note that the stride
+is the number of bytes between rows. If your image has no padding, then this
+is the same as xsize.
+
+The detection, scoring and nonmaximal suppression are available as individual
+functions. To see how to use the individual functions, see fast.c
+
+
diff --git a/extern/libmv/third_party/fast/README.libmv b/extern/libmv/third_party/fast/README.libmv
new file mode 100644
index 00000000000..2110976dd14
--- /dev/null
+++ b/extern/libmv/third_party/fast/README.libmv
@@ -0,0 +1,9 @@
+Project: FAST (FAST Corner Detection)
+URL: http://mi.eng.cam.ac.uk/~er258/work/fast-C-src/
+License: BSD
+Upstream version: 2.1, released 12-Jan-2009
+
+Local modifications:
+- Created CMakeLists.txt for CMake build.
+- Update CMakeLists to be sure that the library is a compatible with C++ linkage.
+- Update CMakeLists to not include fast.h to compile fast library with VS2005.
diff --git a/extern/libmv/third_party/fast/fast.c b/extern/libmv/third_party/fast/fast.c
new file mode 100644
index 00000000000..c675f0af883
--- /dev/null
+++ b/extern/libmv/third_party/fast/fast.c
@@ -0,0 +1,71 @@
+#include <stdlib.h>
+#include "fast.h"
+
+
+xy* fast9_detect_nonmax(const byte* im, int xsize, int ysize, int stride, int b, int* ret_num_corners)
+{
+ xy* corners;
+ int num_corners;
+ int* scores;
+ xy* nonmax;
+
+ corners = fast9_detect(im, xsize, ysize, stride, b, &num_corners);
+ scores = fast9_score(im, stride, corners, num_corners, b);
+ nonmax = nonmax_suppression(corners, scores, num_corners, ret_num_corners);
+
+ free(corners);
+ free(scores);
+
+ return nonmax;
+}
+
+xy* fast10_detect_nonmax(const byte* im, int xsize, int ysize, int stride, int b, int* ret_num_corners)
+{
+ xy* corners;
+ int num_corners;
+ int* scores;
+ xy* nonmax;
+
+ corners = fast10_detect(im, xsize, ysize, stride, b, &num_corners);
+ scores = fast10_score(im, stride, corners, num_corners, b);
+ nonmax = nonmax_suppression(corners, scores, num_corners, ret_num_corners);
+
+ free(corners);
+ free(scores);
+
+ return nonmax;
+}
+
+xy* fast11_detect_nonmax(const byte* im, int xsize, int ysize, int stride, int b, int* ret_num_corners)
+{
+ xy* corners;
+ int num_corners;
+ int* scores;
+ xy* nonmax;
+
+ corners = fast11_detect(im, xsize, ysize, stride, b, &num_corners);
+ scores = fast11_score(im, stride, corners, num_corners, b);
+ nonmax = nonmax_suppression(corners, scores, num_corners, ret_num_corners);
+
+ free(corners);
+ free(scores);
+
+ return nonmax;
+}
+
+xy* fast12_detect_nonmax(const byte* im, int xsize, int ysize, int stride, int b, int* ret_num_corners)
+{
+ xy* corners;
+ int num_corners;
+ int* scores;
+ xy* nonmax;
+
+ corners = fast12_detect(im, xsize, ysize, stride, b, &num_corners);
+ scores = fast12_score(im, stride, corners, num_corners, b);
+ nonmax = nonmax_suppression(corners, scores, num_corners, ret_num_corners);
+
+ free(corners);
+ free(scores);
+
+ return nonmax;
+}
diff --git a/extern/libmv/third_party/fast/fast.h b/extern/libmv/third_party/fast/fast.h
new file mode 100644
index 00000000000..06fa90ec98c
--- /dev/null
+++ b/extern/libmv/third_party/fast/fast.h
@@ -0,0 +1,39 @@
+#ifndef FAST_H
+#define FAST_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef struct { int x, y; } xy;
+typedef unsigned char byte;
+
+int fast9_corner_score(const byte* p, const int pixel[], int bstart);
+int fast10_corner_score(const byte* p, const int pixel[], int bstart);
+int fast11_corner_score(const byte* p, const int pixel[], int bstart);
+int fast12_corner_score(const byte* p, const int pixel[], int bstart);
+
+xy* fast9_detect(const byte* im, int xsize, int ysize, int stride, int b, int* ret_num_corners);
+xy* fast10_detect(const byte* im, int xsize, int ysize, int stride, int b, int* ret_num_corners);
+xy* fast11_detect(const byte* im, int xsize, int ysize, int stride, int b, int* ret_num_corners);
+xy* fast12_detect(const byte* im, int xsize, int ysize, int stride, int b, int* ret_num_corners);
+
+int* fast9_score(const byte* i, int stride, xy* corners, int num_corners, int b);
+int* fast10_score(const byte* i, int stride, xy* corners, int num_corners, int b);
+int* fast11_score(const byte* i, int stride, xy* corners, int num_corners, int b);
+int* fast12_score(const byte* i, int stride, xy* corners, int num_corners, int b);
+
+
+xy* fast9_detect_nonmax(const byte* im, int xsize, int ysize, int stride, int b, int* ret_num_corners);
+xy* fast10_detect_nonmax(const byte* im, int xsize, int ysize, int stride, int b, int* ret_num_corners);
+xy* fast11_detect_nonmax(const byte* im, int xsize, int ysize, int stride, int b, int* ret_num_corners);
+xy* fast12_detect_nonmax(const byte* im, int xsize, int ysize, int stride, int b, int* ret_num_corners);
+
+xy* nonmax_suppression(const xy* corners, const int* scores, int num_corners, int* ret_num_nonmax);
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/extern/libmv/third_party/fast/fast_10.c b/extern/libmv/third_party/fast/fast_10.c
new file mode 100644
index 00000000000..3af63869478
--- /dev/null
+++ b/extern/libmv/third_party/fast/fast_10.c
@@ -0,0 +1,4666 @@
+/*This is mechanically generated code*/
+#include <stdlib.h>
+
+typedef struct { int x, y; } xy;
+typedef unsigned char byte;
+
+int fast10_corner_score(const byte* p, const int pixel[], int bstart)
+{
+ int bmin = bstart;
+ int bmax = 255;
+ int b = (bmax + bmin)/2;
+
+ /*Compute the score using binary search*/
+ for(;;)
+ {
+ int cb = *p + b;
+ int c_b= *p - b;
+
+
+ if( p[pixel[0]] > cb)
+ if( p[pixel[1]] > cb)
+ if( p[pixel[2]] > cb)
+ if( p[pixel[3]] > cb)
+ if( p[pixel[4]] > cb)
+ if( p[pixel[5]] > cb)
+ if( p[pixel[6]] > cb)
+ if( p[pixel[7]] > cb)
+ if( p[pixel[8]] > cb)
+ if( p[pixel[9]] > cb)
+ goto is_a_corner;
+ else
+ if( p[pixel[15]] > cb)
+ goto is_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ if( p[pixel[14]] > cb)
+ if( p[pixel[15]] > cb)
+ goto is_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ if( p[pixel[13]] > cb)
+ if( p[pixel[14]] > cb)
+ if( p[pixel[15]] > cb)
+ goto is_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else if( p[pixel[6]] < c_b)
+ if( p[pixel[12]] > cb)
+ if( p[pixel[13]] > cb)
+ if( p[pixel[14]] > cb)
+ if( p[pixel[15]] > cb)
+ goto is_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else if( p[pixel[12]] < c_b)
+ if( p[pixel[7]] < c_b)
+ if( p[pixel[8]] < c_b)
+ if( p[pixel[9]] < c_b)
+ if( p[pixel[10]] < c_b)
+ if( p[pixel[11]] < c_b)
+ if( p[pixel[13]] < c_b)
+ if( p[pixel[14]] < c_b)
+ if( p[pixel[15]] < c_b)
+ goto is_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ if( p[pixel[12]] > cb)
+ if( p[pixel[13]] > cb)
+ if( p[pixel[14]] > cb)
+ if( p[pixel[15]] > cb)
+ goto is_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else if( p[pixel[5]] < c_b)
+ if( p[pixel[15]] > cb)
+ if( p[pixel[11]] > cb)
+ if( p[pixel[12]] > cb)
+ if( p[pixel[13]] > cb)
+ if( p[pixel[14]] > cb)
+ goto is_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else if( p[pixel[11]] < c_b)
+ if( p[pixel[6]] < c_b)
+ if( p[pixel[7]] < c_b)
+ if( p[pixel[8]] < c_b)
+ if( p[pixel[9]] < c_b)
+ if( p[pixel[10]] < c_b)
+ if( p[pixel[12]] < c_b)
+ if( p[pixel[13]] < c_b)
+ if( p[pixel[14]] < c_b)
+ goto is_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ if( p[pixel[6]] < c_b)
+ if( p[pixel[7]] < c_b)
+ if( p[pixel[8]] < c_b)
+ if( p[pixel[9]] < c_b)
+ if( p[pixel[10]] < c_b)
+ if( p[pixel[11]] < c_b)
+ if( p[pixel[12]] < c_b)
+ if( p[pixel[13]] < c_b)
+ if( p[pixel[14]] < c_b)
+ goto is_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ if( p[pixel[11]] > cb)
+ if( p[pixel[12]] > cb)
+ if( p[pixel[13]] > cb)
+ if( p[pixel[14]] > cb)
+ if( p[pixel[15]] > cb)
+ goto is_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else if( p[pixel[11]] < c_b)
+ if( p[pixel[6]] < c_b)
+ if( p[pixel[7]] < c_b)
+ if( p[pixel[8]] < c_b)
+ if( p[pixel[9]] < c_b)
+ if( p[pixel[10]] < c_b)
+ if( p[pixel[12]] < c_b)
+ if( p[pixel[13]] < c_b)
+ if( p[pixel[14]] < c_b)
+ if( p[pixel[15]] < c_b)
+ goto is_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else if( p[pixel[4]] < c_b)
+ if( p[pixel[14]] > cb)
+ if( p[pixel[10]] > cb)
+ if( p[pixel[11]] > cb)
+ if( p[pixel[12]] > cb)
+ if( p[pixel[13]] > cb)
+ if( p[pixel[15]] > cb)
+ goto is_a_corner;
+ else
+ if( p[pixel[5]] > cb)
+ if( p[pixel[6]] > cb)
+ if( p[pixel[7]] > cb)
+ if( p[pixel[8]] > cb)
+ if( p[pixel[9]] > cb)
+ goto is_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else if( p[pixel[10]] < c_b)
+ if( p[pixel[5]] < c_b)
+ if( p[pixel[6]] < c_b)
+ if( p[pixel[7]] < c_b)
+ if( p[pixel[8]] < c_b)
+ if( p[pixel[9]] < c_b)
+ if( p[pixel[11]] < c_b)
+ if( p[pixel[12]] < c_b)
+ if( p[pixel[13]] < c_b)
+ goto is_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else if( p[pixel[14]] < c_b)
+ if( p[pixel[6]] < c_b)
+ if( p[pixel[7]] < c_b)
+ if( p[pixel[8]] < c_b)
+ if( p[pixel[9]] < c_b)
+ if( p[pixel[10]] < c_b)
+ if( p[pixel[11]] < c_b)
+ if( p[pixel[12]] < c_b)
+ if( p[pixel[13]] < c_b)
+ if( p[pixel[5]] < c_b)
+ goto is_a_corner;
+ else
+ if( p[pixel[15]] < c_b)
+ goto is_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ if( p[pixel[5]] < c_b)
+ if( p[pixel[6]] < c_b)
+ if( p[pixel[7]] < c_b)
+ if( p[pixel[8]] < c_b)
+ if( p[pixel[9]] < c_b)
+ if( p[pixel[10]] < c_b)
+ if( p[pixel[11]] < c_b)
+ if( p[pixel[12]] < c_b)
+ if( p[pixel[13]] < c_b)
+ goto is_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ if( p[pixel[10]] > cb)
+ if( p[pixel[11]] > cb)
+ if( p[pixel[12]] > cb)
+ if( p[pixel[13]] > cb)
+ if( p[pixel[14]] > cb)
+ if( p[pixel[15]] > cb)
+ goto is_a_corner;
+ else
+ if( p[pixel[5]] > cb)
+ if( p[pixel[6]] > cb)
+ if( p[pixel[7]] > cb)
+ if( p[pixel[8]] > cb)
+ if( p[pixel[9]] > cb)
+ goto is_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else if( p[pixel[10]] < c_b)
+ if( p[pixel[6]] < c_b)
+ if( p[pixel[7]] < c_b)
+ if( p[pixel[8]] < c_b)
+ if( p[pixel[9]] < c_b)
+ if( p[pixel[11]] < c_b)
+ if( p[pixel[12]] < c_b)
+ if( p[pixel[13]] < c_b)
+ if( p[pixel[14]] < c_b)
+ if( p[pixel[5]] < c_b)
+ goto is_a_corner;
+ else
+ if( p[pixel[15]] < c_b)
+ goto is_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else if( p[pixel[3]] < c_b)
+ if( p[pixel[9]] > cb)
+ if( p[pixel[10]] > cb)
+ if( p[pixel[11]] > cb)
+ if( p[pixel[12]] > cb)
+ if( p[pixel[13]] > cb)
+ if( p[pixel[14]] > cb)
+ if( p[pixel[15]] > cb)
+ goto is_a_corner;
+ else
+ if( p[pixel[5]] > cb)
+ if( p[pixel[6]] > cb)
+ if( p[pixel[7]] > cb)
+ if( p[pixel[8]] > cb)
+ goto is_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ if( p[pixel[4]] > cb)
+ if( p[pixel[5]] > cb)
+ if( p[pixel[6]] > cb)
+ if( p[pixel[7]] > cb)
+ if( p[pixel[8]] > cb)
+ goto is_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else if( p[pixel[9]] < c_b)
+ if( p[pixel[6]] < c_b)
+ if( p[pixel[7]] < c_b)
+ if( p[pixel[8]] < c_b)
+ if( p[pixel[10]] < c_b)
+ if( p[pixel[11]] < c_b)
+ if( p[pixel[12]] < c_b)
+ if( p[pixel[5]] < c_b)
+ if( p[pixel[4]] < c_b)
+ goto is_a_corner;
+ else
+ if( p[pixel[13]] < c_b)
+ if( p[pixel[14]] < c_b)
+ goto is_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ if( p[pixel[13]] < c_b)
+ if( p[pixel[14]] < c_b)
+ if( p[pixel[15]] < c_b)
+ goto is_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ if( p[pixel[9]] > cb)
+ if( p[pixel[10]] > cb)
+ if( p[pixel[11]] > cb)
+ if( p[pixel[12]] > cb)
+ if( p[pixel[13]] > cb)
+ if( p[pixel[14]] > cb)
+ if( p[pixel[15]] > cb)
+ goto is_a_corner;
+ else
+ if( p[pixel[5]] > cb)
+ if( p[pixel[6]] > cb)
+ if( p[pixel[7]] > cb)
+ if( p[pixel[8]] > cb)
+ goto is_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ if( p[pixel[4]] > cb)
+ if( p[pixel[5]] > cb)
+ if( p[pixel[6]] > cb)
+ if( p[pixel[7]] > cb)
+ if( p[pixel[8]] > cb)
+ goto is_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else if( p[pixel[9]] < c_b)
+ if( p[pixel[6]] < c_b)
+ if( p[pixel[7]] < c_b)
+ if( p[pixel[8]] < c_b)
+ if( p[pixel[10]] < c_b)
+ if( p[pixel[11]] < c_b)
+ if( p[pixel[12]] < c_b)
+ if( p[pixel[13]] < c_b)
+ if( p[pixel[5]] < c_b)
+ if( p[pixel[4]] < c_b)
+ goto is_a_corner;
+ else
+ if( p[pixel[14]] < c_b)
+ goto is_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ if( p[pixel[14]] < c_b)
+ if( p[pixel[15]] < c_b)
+ goto is_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else if( p[pixel[2]] < c_b)
+ if( p[pixel[8]] > cb)
+ if( p[pixel[9]] > cb)
+ if( p[pixel[10]] > cb)
+ if( p[pixel[11]] > cb)
+ if( p[pixel[12]] > cb)
+ if( p[pixel[13]] > cb)
+ if( p[pixel[14]] > cb)
+ if( p[pixel[15]] > cb)
+ goto is_a_corner;
+ else
+ if( p[pixel[5]] > cb)
+ if( p[pixel[6]] > cb)
+ if( p[pixel[7]] > cb)
+ goto is_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ if( p[pixel[4]] > cb)
+ if( p[pixel[5]] > cb)
+ if( p[pixel[6]] > cb)
+ if( p[pixel[7]] > cb)
+ goto is_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ if( p[pixel[3]] > cb)
+ if( p[pixel[4]] > cb)
+ if( p[pixel[5]] > cb)
+ if( p[pixel[6]] > cb)
+ if( p[pixel[7]] > cb)
+ goto is_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else if( p[pixel[8]] < c_b)
+ if( p[pixel[6]] < c_b)
+ if( p[pixel[7]] < c_b)
+ if( p[pixel[9]] < c_b)
+ if( p[pixel[10]] < c_b)
+ if( p[pixel[11]] < c_b)
+ if( p[pixel[5]] < c_b)
+ if( p[pixel[4]] < c_b)
+ if( p[pixel[3]] < c_b)
+ goto is_a_corner;
+ else
+ if( p[pixel[12]] < c_b)
+ if( p[pixel[13]] < c_b)
+ goto is_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ if( p[pixel[12]] < c_b)
+ if( p[pixel[13]] < c_b)
+ if( p[pixel[14]] < c_b)
+ goto is_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ if( p[pixel[12]] < c_b)
+ if( p[pixel[13]] < c_b)
+ if( p[pixel[14]] < c_b)
+ if( p[pixel[15]] < c_b)
+ goto is_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ if( p[pixel[8]] > cb)
+ if( p[pixel[9]] > cb)
+ if( p[pixel[10]] > cb)
+ if( p[pixel[11]] > cb)
+ if( p[pixel[12]] > cb)
+ if( p[pixel[13]] > cb)
+ if( p[pixel[14]] > cb)
+ if( p[pixel[15]] > cb)
+ goto is_a_corner;
+ else
+ if( p[pixel[5]] > cb)
+ if( p[pixel[6]] > cb)
+ if( p[pixel[7]] > cb)
+ goto is_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ if( p[pixel[4]] > cb)
+ if( p[pixel[5]] > cb)
+ if( p[pixel[6]] > cb)
+ if( p[pixel[7]] > cb)
+ goto is_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ if( p[pixel[3]] > cb)
+ if( p[pixel[4]] > cb)
+ if( p[pixel[5]] > cb)
+ if( p[pixel[6]] > cb)
+ if( p[pixel[7]] > cb)
+ goto is_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else if( p[pixel[8]] < c_b)
+ if( p[pixel[6]] < c_b)
+ if( p[pixel[7]] < c_b)
+ if( p[pixel[9]] < c_b)
+ if( p[pixel[10]] < c_b)
+ if( p[pixel[11]] < c_b)
+ if( p[pixel[12]] < c_b)
+ if( p[pixel[5]] < c_b)
+ if( p[pixel[4]] < c_b)
+ if( p[pixel[3]] < c_b)
+ goto is_a_corner;
+ else
+ if( p[pixel[13]] < c_b)
+ goto is_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ if( p[pixel[13]] < c_b)
+ if( p[pixel[14]] < c_b)
+ goto is_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ if( p[pixel[13]] < c_b)
+ if( p[pixel[14]] < c_b)
+ if( p[pixel[15]] < c_b)
+ goto is_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else if( p[pixel[1]] < c_b)
+ if( p[pixel[7]] > cb)
+ if( p[pixel[8]] > cb)
+ if( p[pixel[9]] > cb)
+ if( p[pixel[10]] > cb)
+ if( p[pixel[11]] > cb)
+ if( p[pixel[12]] > cb)
+ if( p[pixel[13]] > cb)
+ if( p[pixel[14]] > cb)
+ if( p[pixel[15]] > cb)
+ goto is_a_corner;
+ else
+ if( p[pixel[5]] > cb)
+ if( p[pixel[6]] > cb)
+ goto is_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ if( p[pixel[4]] > cb)
+ if( p[pixel[5]] > cb)
+ if( p[pixel[6]] > cb)
+ goto is_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ if( p[pixel[3]] > cb)
+ if( p[pixel[4]] > cb)
+ if( p[pixel[5]] > cb)
+ if( p[pixel[6]] > cb)
+ goto is_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ if( p[pixel[2]] > cb)
+ if( p[pixel[3]] > cb)
+ if( p[pixel[4]] > cb)
+ if( p[pixel[5]] > cb)
+ if( p[pixel[6]] > cb)
+ goto is_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else if( p[pixel[7]] < c_b)
+ if( p[pixel[6]] < c_b)
+ if( p[pixel[8]] < c_b)
+ if( p[pixel[9]] < c_b)
+ if( p[pixel[10]] < c_b)
+ if( p[pixel[5]] < c_b)
+ if( p[pixel[4]] < c_b)
+ if( p[pixel[3]] < c_b)
+ if( p[pixel[2]] < c_b)
+ goto is_a_corner;
+ else
+ if( p[pixel[11]] < c_b)
+ if( p[pixel[12]] < c_b)
+ goto is_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ if( p[pixel[11]] < c_b)
+ if( p[pixel[12]] < c_b)
+ if( p[pixel[13]] < c_b)
+ goto is_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ if( p[pixel[11]] < c_b)
+ if( p[pixel[12]] < c_b)
+ if( p[pixel[13]] < c_b)
+ if( p[pixel[14]] < c_b)
+ goto is_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ if( p[pixel[11]] < c_b)
+ if( p[pixel[12]] < c_b)
+ if( p[pixel[13]] < c_b)
+ if( p[pixel[14]] < c_b)
+ if( p[pixel[15]] < c_b)
+ goto is_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ if( p[pixel[7]] > cb)
+ if( p[pixel[8]] > cb)
+ if( p[pixel[9]] > cb)
+ if( p[pixel[10]] > cb)
+ if( p[pixel[11]] > cb)
+ if( p[pixel[12]] > cb)
+ if( p[pixel[13]] > cb)
+ if( p[pixel[14]] > cb)
+ if( p[pixel[15]] > cb)
+ goto is_a_corner;
+ else
+ if( p[pixel[5]] > cb)
+ if( p[pixel[6]] > cb)
+ goto is_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ if( p[pixel[4]] > cb)
+ if( p[pixel[5]] > cb)
+ if( p[pixel[6]] > cb)
+ goto is_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ if( p[pixel[3]] > cb)
+ if( p[pixel[4]] > cb)
+ if( p[pixel[5]] > cb)
+ if( p[pixel[6]] > cb)
+ goto is_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ if( p[pixel[2]] > cb)
+ if( p[pixel[3]] > cb)
+ if( p[pixel[4]] > cb)
+ if( p[pixel[5]] > cb)
+ if( p[pixel[6]] > cb)
+ goto is_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else if( p[pixel[7]] < c_b)
+ if( p[pixel[6]] < c_b)
+ if( p[pixel[8]] < c_b)
+ if( p[pixel[9]] < c_b)
+ if( p[pixel[10]] < c_b)
+ if( p[pixel[11]] < c_b)
+ if( p[pixel[5]] < c_b)
+ if( p[pixel[4]] < c_b)
+ if( p[pixel[3]] < c_b)
+ if( p[pixel[2]] < c_b)
+ goto is_a_corner;
+ else
+ if( p[pixel[12]] < c_b)
+ goto is_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ if( p[pixel[12]] < c_b)
+ if( p[pixel[13]] < c_b)
+ goto is_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ if( p[pixel[12]] < c_b)
+ if( p[pixel[13]] < c_b)
+ if( p[pixel[14]] < c_b)
+ goto is_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ if( p[pixel[12]] < c_b)
+ if( p[pixel[13]] < c_b)
+ if( p[pixel[14]] < c_b)
+ if( p[pixel[15]] < c_b)
+ goto is_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else if( p[pixel[0]] < c_b)
+ if( p[pixel[1]] > cb)
+ if( p[pixel[7]] > cb)
+ if( p[pixel[6]] > cb)
+ if( p[pixel[8]] > cb)
+ if( p[pixel[9]] > cb)
+ if( p[pixel[10]] > cb)
+ if( p[pixel[5]] > cb)
+ if( p[pixel[4]] > cb)
+ if( p[pixel[3]] > cb)
+ if( p[pixel[2]] > cb)
+ goto is_a_corner;
+ else
+ if( p[pixel[11]] > cb)
+ if( p[pixel[12]] > cb)
+ goto is_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ if( p[pixel[11]] > cb)
+ if( p[pixel[12]] > cb)
+ if( p[pixel[13]] > cb)
+ goto is_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ if( p[pixel[11]] > cb)
+ if( p[pixel[12]] > cb)
+ if( p[pixel[13]] > cb)
+ if( p[pixel[14]] > cb)
+ goto is_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ if( p[pixel[11]] > cb)
+ if( p[pixel[12]] > cb)
+ if( p[pixel[13]] > cb)
+ if( p[pixel[14]] > cb)
+ if( p[pixel[15]] > cb)
+ goto is_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else if( p[pixel[7]] < c_b)
+ if( p[pixel[8]] < c_b)
+ if( p[pixel[9]] < c_b)
+ if( p[pixel[10]] < c_b)
+ if( p[pixel[11]] < c_b)
+ if( p[pixel[12]] < c_b)
+ if( p[pixel[13]] < c_b)
+ if( p[pixel[14]] < c_b)
+ if( p[pixel[15]] < c_b)
+ goto is_a_corner;
+ else
+ if( p[pixel[5]] < c_b)
+ if( p[pixel[6]] < c_b)
+ goto is_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ if( p[pixel[4]] < c_b)
+ if( p[pixel[5]] < c_b)
+ if( p[pixel[6]] < c_b)
+ goto is_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ if( p[pixel[3]] < c_b)
+ if( p[pixel[4]] < c_b)
+ if( p[pixel[5]] < c_b)
+ if( p[pixel[6]] < c_b)
+ goto is_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ if( p[pixel[2]] < c_b)
+ if( p[pixel[3]] < c_b)
+ if( p[pixel[4]] < c_b)
+ if( p[pixel[5]] < c_b)
+ if( p[pixel[6]] < c_b)
+ goto is_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else if( p[pixel[1]] < c_b)
+ if( p[pixel[2]] > cb)
+ if( p[pixel[8]] > cb)
+ if( p[pixel[6]] > cb)
+ if( p[pixel[7]] > cb)
+ if( p[pixel[9]] > cb)
+ if( p[pixel[10]] > cb)
+ if( p[pixel[11]] > cb)
+ if( p[pixel[5]] > cb)
+ if( p[pixel[4]] > cb)
+ if( p[pixel[3]] > cb)
+ goto is_a_corner;
+ else
+ if( p[pixel[12]] > cb)
+ if( p[pixel[13]] > cb)
+ goto is_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ if( p[pixel[12]] > cb)
+ if( p[pixel[13]] > cb)
+ if( p[pixel[14]] > cb)
+ goto is_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ if( p[pixel[12]] > cb)
+ if( p[pixel[13]] > cb)
+ if( p[pixel[14]] > cb)
+ if( p[pixel[15]] > cb)
+ goto is_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else if( p[pixel[8]] < c_b)
+ if( p[pixel[9]] < c_b)
+ if( p[pixel[10]] < c_b)
+ if( p[pixel[11]] < c_b)
+ if( p[pixel[12]] < c_b)
+ if( p[pixel[13]] < c_b)
+ if( p[pixel[14]] < c_b)
+ if( p[pixel[15]] < c_b)
+ goto is_a_corner;
+ else
+ if( p[pixel[5]] < c_b)
+ if( p[pixel[6]] < c_b)
+ if( p[pixel[7]] < c_b)
+ goto is_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ if( p[pixel[4]] < c_b)
+ if( p[pixel[5]] < c_b)
+ if( p[pixel[6]] < c_b)
+ if( p[pixel[7]] < c_b)
+ goto is_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ if( p[pixel[3]] < c_b)
+ if( p[pixel[4]] < c_b)
+ if( p[pixel[5]] < c_b)
+ if( p[pixel[6]] < c_b)
+ if( p[pixel[7]] < c_b)
+ goto is_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else if( p[pixel[2]] < c_b)
+ if( p[pixel[3]] > cb)
+ if( p[pixel[9]] > cb)
+ if( p[pixel[6]] > cb)
+ if( p[pixel[7]] > cb)
+ if( p[pixel[8]] > cb)
+ if( p[pixel[10]] > cb)
+ if( p[pixel[11]] > cb)
+ if( p[pixel[12]] > cb)
+ if( p[pixel[5]] > cb)
+ if( p[pixel[4]] > cb)
+ goto is_a_corner;
+ else
+ if( p[pixel[13]] > cb)
+ if( p[pixel[14]] > cb)
+ goto is_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ if( p[pixel[13]] > cb)
+ if( p[pixel[14]] > cb)
+ if( p[pixel[15]] > cb)
+ goto is_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else if( p[pixel[9]] < c_b)
+ if( p[pixel[10]] < c_b)
+ if( p[pixel[11]] < c_b)
+ if( p[pixel[12]] < c_b)
+ if( p[pixel[13]] < c_b)
+ if( p[pixel[14]] < c_b)
+ if( p[pixel[15]] < c_b)
+ goto is_a_corner;
+ else
+ if( p[pixel[5]] < c_b)
+ if( p[pixel[6]] < c_b)
+ if( p[pixel[7]] < c_b)
+ if( p[pixel[8]] < c_b)
+ goto is_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ if( p[pixel[4]] < c_b)
+ if( p[pixel[5]] < c_b)
+ if( p[pixel[6]] < c_b)
+ if( p[pixel[7]] < c_b)
+ if( p[pixel[8]] < c_b)
+ goto is_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else if( p[pixel[3]] < c_b)
+ if( p[pixel[4]] > cb)
+ if( p[pixel[14]] > cb)
+ if( p[pixel[6]] > cb)
+ if( p[pixel[7]] > cb)
+ if( p[pixel[8]] > cb)
+ if( p[pixel[9]] > cb)
+ if( p[pixel[10]] > cb)
+ if( p[pixel[11]] > cb)
+ if( p[pixel[12]] > cb)
+ if( p[pixel[13]] > cb)
+ if( p[pixel[5]] > cb)
+ goto is_a_corner;
+ else
+ if( p[pixel[15]] > cb)
+ goto is_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else if( p[pixel[14]] < c_b)
+ if( p[pixel[10]] > cb)
+ if( p[pixel[5]] > cb)
+ if( p[pixel[6]] > cb)
+ if( p[pixel[7]] > cb)
+ if( p[pixel[8]] > cb)
+ if( p[pixel[9]] > cb)
+ if( p[pixel[11]] > cb)
+ if( p[pixel[12]] > cb)
+ if( p[pixel[13]] > cb)
+ goto is_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else if( p[pixel[10]] < c_b)
+ if( p[pixel[11]] < c_b)
+ if( p[pixel[12]] < c_b)
+ if( p[pixel[13]] < c_b)
+ if( p[pixel[15]] < c_b)
+ goto is_a_corner;
+ else
+ if( p[pixel[5]] < c_b)
+ if( p[pixel[6]] < c_b)
+ if( p[pixel[7]] < c_b)
+ if( p[pixel[8]] < c_b)
+ if( p[pixel[9]] < c_b)
+ goto is_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ if( p[pixel[5]] > cb)
+ if( p[pixel[6]] > cb)
+ if( p[pixel[7]] > cb)
+ if( p[pixel[8]] > cb)
+ if( p[pixel[9]] > cb)
+ if( p[pixel[10]] > cb)
+ if( p[pixel[11]] > cb)
+ if( p[pixel[12]] > cb)
+ if( p[pixel[13]] > cb)
+ goto is_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else if( p[pixel[4]] < c_b)
+ if( p[pixel[5]] > cb)
+ if( p[pixel[15]] < c_b)
+ if( p[pixel[11]] > cb)
+ if( p[pixel[6]] > cb)
+ if( p[pixel[7]] > cb)
+ if( p[pixel[8]] > cb)
+ if( p[pixel[9]] > cb)
+ if( p[pixel[10]] > cb)
+ if( p[pixel[12]] > cb)
+ if( p[pixel[13]] > cb)
+ if( p[pixel[14]] > cb)
+ goto is_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else if( p[pixel[11]] < c_b)
+ if( p[pixel[12]] < c_b)
+ if( p[pixel[13]] < c_b)
+ if( p[pixel[14]] < c_b)
+ goto is_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ if( p[pixel[6]] > cb)
+ if( p[pixel[7]] > cb)
+ if( p[pixel[8]] > cb)
+ if( p[pixel[9]] > cb)
+ if( p[pixel[10]] > cb)
+ if( p[pixel[11]] > cb)
+ if( p[pixel[12]] > cb)
+ if( p[pixel[13]] > cb)
+ if( p[pixel[14]] > cb)
+ goto is_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else if( p[pixel[5]] < c_b)
+ if( p[pixel[6]] > cb)
+ if( p[pixel[12]] > cb)
+ if( p[pixel[7]] > cb)
+ if( p[pixel[8]] > cb)
+ if( p[pixel[9]] > cb)
+ if( p[pixel[10]] > cb)
+ if( p[pixel[11]] > cb)
+ if( p[pixel[13]] > cb)
+ if( p[pixel[14]] > cb)
+ if( p[pixel[15]] > cb)
+ goto is_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else if( p[pixel[12]] < c_b)
+ if( p[pixel[13]] < c_b)
+ if( p[pixel[14]] < c_b)
+ if( p[pixel[15]] < c_b)
+ goto is_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else if( p[pixel[6]] < c_b)
+ if( p[pixel[7]] < c_b)
+ if( p[pixel[8]] < c_b)
+ if( p[pixel[9]] < c_b)
+ goto is_a_corner;
+ else
+ if( p[pixel[15]] < c_b)
+ goto is_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ if( p[pixel[14]] < c_b)
+ if( p[pixel[15]] < c_b)
+ goto is_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ if( p[pixel[13]] < c_b)
+ if( p[pixel[14]] < c_b)
+ if( p[pixel[15]] < c_b)
+ goto is_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ if( p[pixel[12]] < c_b)
+ if( p[pixel[13]] < c_b)
+ if( p[pixel[14]] < c_b)
+ if( p[pixel[15]] < c_b)
+ goto is_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ if( p[pixel[11]] > cb)
+ if( p[pixel[6]] > cb)
+ if( p[pixel[7]] > cb)
+ if( p[pixel[8]] > cb)
+ if( p[pixel[9]] > cb)
+ if( p[pixel[10]] > cb)
+ if( p[pixel[12]] > cb)
+ if( p[pixel[13]] > cb)
+ if( p[pixel[14]] > cb)
+ if( p[pixel[15]] > cb)
+ goto is_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else if( p[pixel[11]] < c_b)
+ if( p[pixel[12]] < c_b)
+ if( p[pixel[13]] < c_b)
+ if( p[pixel[14]] < c_b)
+ if( p[pixel[15]] < c_b)
+ goto is_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ if( p[pixel[10]] > cb)
+ if( p[pixel[6]] > cb)
+ if( p[pixel[7]] > cb)
+ if( p[pixel[8]] > cb)
+ if( p[pixel[9]] > cb)
+ if( p[pixel[11]] > cb)
+ if( p[pixel[12]] > cb)
+ if( p[pixel[13]] > cb)
+ if( p[pixel[14]] > cb)
+ if( p[pixel[5]] > cb)
+ goto is_a_corner;
+ else
+ if( p[pixel[15]] > cb)
+ goto is_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else if( p[pixel[10]] < c_b)
+ if( p[pixel[11]] < c_b)
+ if( p[pixel[12]] < c_b)
+ if( p[pixel[13]] < c_b)
+ if( p[pixel[14]] < c_b)
+ if( p[pixel[15]] < c_b)
+ goto is_a_corner;
+ else
+ if( p[pixel[5]] < c_b)
+ if( p[pixel[6]] < c_b)
+ if( p[pixel[7]] < c_b)
+ if( p[pixel[8]] < c_b)
+ if( p[pixel[9]] < c_b)
+ goto is_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ if( p[pixel[9]] > cb)
+ if( p[pixel[6]] > cb)
+ if( p[pixel[7]] > cb)
+ if( p[pixel[8]] > cb)
+ if( p[pixel[10]] > cb)
+ if( p[pixel[11]] > cb)
+ if( p[pixel[12]] > cb)
+ if( p[pixel[13]] > cb)
+ if( p[pixel[5]] > cb)
+ if( p[pixel[4]] > cb)
+ goto is_a_corner;
+ else
+ if( p[pixel[14]] > cb)
+ goto is_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ if( p[pixel[14]] > cb)
+ if( p[pixel[15]] > cb)
+ goto is_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else if( p[pixel[9]] < c_b)
+ if( p[pixel[10]] < c_b)
+ if( p[pixel[11]] < c_b)
+ if( p[pixel[12]] < c_b)
+ if( p[pixel[13]] < c_b)
+ if( p[pixel[14]] < c_b)
+ if( p[pixel[15]] < c_b)
+ goto is_a_corner;
+ else
+ if( p[pixel[5]] < c_b)
+ if( p[pixel[6]] < c_b)
+ if( p[pixel[7]] < c_b)
+ if( p[pixel[8]] < c_b)
+ goto is_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ if( p[pixel[4]] < c_b)
+ if( p[pixel[5]] < c_b)
+ if( p[pixel[6]] < c_b)
+ if( p[pixel[7]] < c_b)
+ if( p[pixel[8]] < c_b)
+ goto is_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ if( p[pixel[8]] > cb)
+ if( p[pixel[6]] > cb)
+ if( p[pixel[7]] > cb)
+ if( p[pixel[9]] > cb)
+ if( p[pixel[10]] > cb)
+ if( p[pixel[11]] > cb)
+ if( p[pixel[12]] > cb)
+ if( p[pixel[5]] > cb)
+ if( p[pixel[4]] > cb)
+ if( p[pixel[3]] > cb)
+ goto is_a_corner;
+ else
+ if( p[pixel[13]] > cb)
+ goto is_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ if( p[pixel[13]] > cb)
+ if( p[pixel[14]] > cb)
+ goto is_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ if( p[pixel[13]] > cb)
+ if( p[pixel[14]] > cb)
+ if( p[pixel[15]] > cb)
+ goto is_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else if( p[pixel[8]] < c_b)
+ if( p[pixel[9]] < c_b)
+ if( p[pixel[10]] < c_b)
+ if( p[pixel[11]] < c_b)
+ if( p[pixel[12]] < c_b)
+ if( p[pixel[13]] < c_b)
+ if( p[pixel[14]] < c_b)
+ if( p[pixel[15]] < c_b)
+ goto is_a_corner;
+ else
+ if( p[pixel[5]] < c_b)
+ if( p[pixel[6]] < c_b)
+ if( p[pixel[7]] < c_b)
+ goto is_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ if( p[pixel[4]] < c_b)
+ if( p[pixel[5]] < c_b)
+ if( p[pixel[6]] < c_b)
+ if( p[pixel[7]] < c_b)
+ goto is_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ if( p[pixel[3]] < c_b)
+ if( p[pixel[4]] < c_b)
+ if( p[pixel[5]] < c_b)
+ if( p[pixel[6]] < c_b)
+ if( p[pixel[7]] < c_b)
+ goto is_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ if( p[pixel[7]] > cb)
+ if( p[pixel[6]] > cb)
+ if( p[pixel[8]] > cb)
+ if( p[pixel[9]] > cb)
+ if( p[pixel[10]] > cb)
+ if( p[pixel[11]] > cb)
+ if( p[pixel[5]] > cb)
+ if( p[pixel[4]] > cb)
+ if( p[pixel[3]] > cb)
+ if( p[pixel[2]] > cb)
+ goto is_a_corner;
+ else
+ if( p[pixel[12]] > cb)
+ goto is_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ if( p[pixel[12]] > cb)
+ if( p[pixel[13]] > cb)
+ goto is_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ if( p[pixel[12]] > cb)
+ if( p[pixel[13]] > cb)
+ if( p[pixel[14]] > cb)
+ goto is_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ if( p[pixel[12]] > cb)
+ if( p[pixel[13]] > cb)
+ if( p[pixel[14]] > cb)
+ if( p[pixel[15]] > cb)
+ goto is_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else if( p[pixel[7]] < c_b)
+ if( p[pixel[8]] < c_b)
+ if( p[pixel[9]] < c_b)
+ if( p[pixel[10]] < c_b)
+ if( p[pixel[11]] < c_b)
+ if( p[pixel[12]] < c_b)
+ if( p[pixel[13]] < c_b)
+ if( p[pixel[14]] < c_b)
+ if( p[pixel[15]] < c_b)
+ goto is_a_corner;
+ else
+ if( p[pixel[5]] < c_b)
+ if( p[pixel[6]] < c_b)
+ goto is_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ if( p[pixel[4]] < c_b)
+ if( p[pixel[5]] < c_b)
+ if( p[pixel[6]] < c_b)
+ goto is_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ if( p[pixel[3]] < c_b)
+ if( p[pixel[4]] < c_b)
+ if( p[pixel[5]] < c_b)
+ if( p[pixel[6]] < c_b)
+ goto is_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ if( p[pixel[2]] < c_b)
+ if( p[pixel[3]] < c_b)
+ if( p[pixel[4]] < c_b)
+ if( p[pixel[5]] < c_b)
+ if( p[pixel[6]] < c_b)
+ goto is_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ if( p[pixel[6]] > cb)
+ if( p[pixel[7]] > cb)
+ if( p[pixel[8]] > cb)
+ if( p[pixel[9]] > cb)
+ if( p[pixel[10]] > cb)
+ if( p[pixel[5]] > cb)
+ if( p[pixel[4]] > cb)
+ if( p[pixel[3]] > cb)
+ if( p[pixel[2]] > cb)
+ if( p[pixel[1]] > cb)
+ goto is_a_corner;
+ else
+ if( p[pixel[11]] > cb)
+ goto is_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ if( p[pixel[11]] > cb)
+ if( p[pixel[12]] > cb)
+ goto is_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ if( p[pixel[11]] > cb)
+ if( p[pixel[12]] > cb)
+ if( p[pixel[13]] > cb)
+ goto is_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ if( p[pixel[11]] > cb)
+ if( p[pixel[12]] > cb)
+ if( p[pixel[13]] > cb)
+ if( p[pixel[14]] > cb)
+ goto is_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ if( p[pixel[11]] > cb)
+ if( p[pixel[12]] > cb)
+ if( p[pixel[13]] > cb)
+ if( p[pixel[14]] > cb)
+ if( p[pixel[15]] > cb)
+ goto is_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else if( p[pixel[6]] < c_b)
+ if( p[pixel[7]] < c_b)
+ if( p[pixel[8]] < c_b)
+ if( p[pixel[9]] < c_b)
+ if( p[pixel[10]] < c_b)
+ if( p[pixel[5]] < c_b)
+ if( p[pixel[4]] < c_b)
+ if( p[pixel[3]] < c_b)
+ if( p[pixel[2]] < c_b)
+ if( p[pixel[1]] < c_b)
+ goto is_a_corner;
+ else
+ if( p[pixel[11]] < c_b)
+ goto is_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ if( p[pixel[11]] < c_b)
+ if( p[pixel[12]] < c_b)
+ goto is_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ if( p[pixel[11]] < c_b)
+ if( p[pixel[12]] < c_b)
+ if( p[pixel[13]] < c_b)
+ goto is_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ if( p[pixel[11]] < c_b)
+ if( p[pixel[12]] < c_b)
+ if( p[pixel[13]] < c_b)
+ if( p[pixel[14]] < c_b)
+ goto is_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ if( p[pixel[11]] < c_b)
+ if( p[pixel[12]] < c_b)
+ if( p[pixel[13]] < c_b)
+ if( p[pixel[14]] < c_b)
+ if( p[pixel[15]] < c_b)
+ goto is_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+
+ is_a_corner:
+ bmin=b;
+ goto end_if;
+
+ is_not_a_corner:
+ bmax=b;
+ goto end_if;
+
+ end_if:
+
+ if(bmin == bmax - 1 || bmin == bmax)
+ return bmin;
+ b = (bmin + bmax) / 2;
+ }
+}
+
+static void make_offsets(int pixel[], int row_stride)
+{
+ pixel[0] = 0 + row_stride * 3;
+ pixel[1] = 1 + row_stride * 3;
+ pixel[2] = 2 + row_stride * 2;
+ pixel[3] = 3 + row_stride * 1;
+ pixel[4] = 3 + row_stride * 0;
+ pixel[5] = 3 + row_stride * -1;
+ pixel[6] = 2 + row_stride * -2;
+ pixel[7] = 1 + row_stride * -3;
+ pixel[8] = 0 + row_stride * -3;
+ pixel[9] = -1 + row_stride * -3;
+ pixel[10] = -2 + row_stride * -2;
+ pixel[11] = -3 + row_stride * -1;
+ pixel[12] = -3 + row_stride * 0;
+ pixel[13] = -3 + row_stride * 1;
+ pixel[14] = -2 + row_stride * 2;
+ pixel[15] = -1 + row_stride * 3;
+}
+
+
+
+int* fast10_score(const byte* i, int stride, xy* corners, int num_corners, int b)
+{
+ int* scores = (int*)malloc(sizeof(int)* num_corners);
+ int n;
+
+ int pixel[16];
+ make_offsets(pixel, stride);
+
+ for(n=0; n < num_corners; n++)
+ scores[n] = fast10_corner_score(i + corners[n].y*stride + corners[n].x, pixel, b);
+
+ return scores;
+}
+
+
+xy* fast10_detect(const byte* im, int xsize, int ysize, int stride, int b, int* ret_num_corners)
+{
+ int num_corners=0;
+ xy* ret_corners;
+ int rsize=512;
+ int pixel[16];
+ int x, y;
+
+ ret_corners = (xy*)malloc(sizeof(xy)*rsize);
+ make_offsets(pixel, stride);
+
+ for(y=3; y < ysize - 3; y++)
+ for(x=3; x < xsize - 3; x++)
+ {
+ const byte* p = im + y*stride + x;
+
+ int cb = *p + b;
+ int c_b= *p - b;
+ if(p[pixel[0]] > cb)
+ if(p[pixel[1]] > cb)
+ if(p[pixel[2]] > cb)
+ if(p[pixel[3]] > cb)
+ if(p[pixel[4]] > cb)
+ if(p[pixel[5]] > cb)
+ if(p[pixel[6]] > cb)
+ if(p[pixel[7]] > cb)
+ if(p[pixel[8]] > cb)
+ if(p[pixel[9]] > cb)
+ {}
+ else
+ if(p[pixel[15]] > cb)
+ {}
+ else
+ continue;
+ else
+ if(p[pixel[14]] > cb)
+ if(p[pixel[15]] > cb)
+ {}
+ else
+ continue;
+ else
+ continue;
+ else
+ if(p[pixel[13]] > cb)
+ if(p[pixel[14]] > cb)
+ if(p[pixel[15]] > cb)
+ {}
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else if(p[pixel[6]] < c_b)
+ if(p[pixel[12]] > cb)
+ if(p[pixel[13]] > cb)
+ if(p[pixel[14]] > cb)
+ if(p[pixel[15]] > cb)
+ {}
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else if(p[pixel[12]] < c_b)
+ if(p[pixel[7]] < c_b)
+ if(p[pixel[8]] < c_b)
+ if(p[pixel[9]] < c_b)
+ if(p[pixel[10]] < c_b)
+ if(p[pixel[11]] < c_b)
+ if(p[pixel[13]] < c_b)
+ if(p[pixel[14]] < c_b)
+ if(p[pixel[15]] < c_b)
+ {}
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ if(p[pixel[12]] > cb)
+ if(p[pixel[13]] > cb)
+ if(p[pixel[14]] > cb)
+ if(p[pixel[15]] > cb)
+ {}
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else if(p[pixel[5]] < c_b)
+ if(p[pixel[15]] > cb)
+ if(p[pixel[11]] > cb)
+ if(p[pixel[12]] > cb)
+ if(p[pixel[13]] > cb)
+ if(p[pixel[14]] > cb)
+ {}
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else if(p[pixel[11]] < c_b)
+ if(p[pixel[6]] < c_b)
+ if(p[pixel[7]] < c_b)
+ if(p[pixel[8]] < c_b)
+ if(p[pixel[9]] < c_b)
+ if(p[pixel[10]] < c_b)
+ if(p[pixel[12]] < c_b)
+ if(p[pixel[13]] < c_b)
+ if(p[pixel[14]] < c_b)
+ {}
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ if(p[pixel[6]] < c_b)
+ if(p[pixel[7]] < c_b)
+ if(p[pixel[8]] < c_b)
+ if(p[pixel[9]] < c_b)
+ if(p[pixel[10]] < c_b)
+ if(p[pixel[11]] < c_b)
+ if(p[pixel[12]] < c_b)
+ if(p[pixel[13]] < c_b)
+ if(p[pixel[14]] < c_b)
+ {}
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ if(p[pixel[11]] > cb)
+ if(p[pixel[12]] > cb)
+ if(p[pixel[13]] > cb)
+ if(p[pixel[14]] > cb)
+ if(p[pixel[15]] > cb)
+ {}
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else if(p[pixel[11]] < c_b)
+ if(p[pixel[6]] < c_b)
+ if(p[pixel[7]] < c_b)
+ if(p[pixel[8]] < c_b)
+ if(p[pixel[9]] < c_b)
+ if(p[pixel[10]] < c_b)
+ if(p[pixel[12]] < c_b)
+ if(p[pixel[13]] < c_b)
+ if(p[pixel[14]] < c_b)
+ if(p[pixel[15]] < c_b)
+ {}
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else if(p[pixel[4]] < c_b)
+ if(p[pixel[14]] > cb)
+ if(p[pixel[10]] > cb)
+ if(p[pixel[11]] > cb)
+ if(p[pixel[12]] > cb)
+ if(p[pixel[13]] > cb)
+ if(p[pixel[15]] > cb)
+ {}
+ else
+ if(p[pixel[5]] > cb)
+ if(p[pixel[6]] > cb)
+ if(p[pixel[7]] > cb)
+ if(p[pixel[8]] > cb)
+ if(p[pixel[9]] > cb)
+ {}
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else if(p[pixel[10]] < c_b)
+ if(p[pixel[5]] < c_b)
+ if(p[pixel[6]] < c_b)
+ if(p[pixel[7]] < c_b)
+ if(p[pixel[8]] < c_b)
+ if(p[pixel[9]] < c_b)
+ if(p[pixel[11]] < c_b)
+ if(p[pixel[12]] < c_b)
+ if(p[pixel[13]] < c_b)
+ {}
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else if(p[pixel[14]] < c_b)
+ if(p[pixel[6]] < c_b)
+ if(p[pixel[7]] < c_b)
+ if(p[pixel[8]] < c_b)
+ if(p[pixel[9]] < c_b)
+ if(p[pixel[10]] < c_b)
+ if(p[pixel[11]] < c_b)
+ if(p[pixel[12]] < c_b)
+ if(p[pixel[13]] < c_b)
+ if(p[pixel[5]] < c_b)
+ {}
+ else
+ if(p[pixel[15]] < c_b)
+ {}
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ if(p[pixel[5]] < c_b)
+ if(p[pixel[6]] < c_b)
+ if(p[pixel[7]] < c_b)
+ if(p[pixel[8]] < c_b)
+ if(p[pixel[9]] < c_b)
+ if(p[pixel[10]] < c_b)
+ if(p[pixel[11]] < c_b)
+ if(p[pixel[12]] < c_b)
+ if(p[pixel[13]] < c_b)
+ {}
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ if(p[pixel[10]] > cb)
+ if(p[pixel[11]] > cb)
+ if(p[pixel[12]] > cb)
+ if(p[pixel[13]] > cb)
+ if(p[pixel[14]] > cb)
+ if(p[pixel[15]] > cb)
+ {}
+ else
+ if(p[pixel[5]] > cb)
+ if(p[pixel[6]] > cb)
+ if(p[pixel[7]] > cb)
+ if(p[pixel[8]] > cb)
+ if(p[pixel[9]] > cb)
+ {}
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else if(p[pixel[10]] < c_b)
+ if(p[pixel[6]] < c_b)
+ if(p[pixel[7]] < c_b)
+ if(p[pixel[8]] < c_b)
+ if(p[pixel[9]] < c_b)
+ if(p[pixel[11]] < c_b)
+ if(p[pixel[12]] < c_b)
+ if(p[pixel[13]] < c_b)
+ if(p[pixel[14]] < c_b)
+ if(p[pixel[5]] < c_b)
+ {}
+ else
+ if(p[pixel[15]] < c_b)
+ {}
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else if(p[pixel[3]] < c_b)
+ if(p[pixel[9]] > cb)
+ if(p[pixel[10]] > cb)
+ if(p[pixel[11]] > cb)
+ if(p[pixel[12]] > cb)
+ if(p[pixel[13]] > cb)
+ if(p[pixel[14]] > cb)
+ if(p[pixel[15]] > cb)
+ {}
+ else
+ if(p[pixel[5]] > cb)
+ if(p[pixel[6]] > cb)
+ if(p[pixel[7]] > cb)
+ if(p[pixel[8]] > cb)
+ {}
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ if(p[pixel[4]] > cb)
+ if(p[pixel[5]] > cb)
+ if(p[pixel[6]] > cb)
+ if(p[pixel[7]] > cb)
+ if(p[pixel[8]] > cb)
+ {}
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else if(p[pixel[9]] < c_b)
+ if(p[pixel[6]] < c_b)
+ if(p[pixel[7]] < c_b)
+ if(p[pixel[8]] < c_b)
+ if(p[pixel[10]] < c_b)
+ if(p[pixel[11]] < c_b)
+ if(p[pixel[12]] < c_b)
+ if(p[pixel[5]] < c_b)
+ if(p[pixel[4]] < c_b)
+ {}
+ else
+ if(p[pixel[13]] < c_b)
+ if(p[pixel[14]] < c_b)
+ {}
+ else
+ continue;
+ else
+ continue;
+ else
+ if(p[pixel[13]] < c_b)
+ if(p[pixel[14]] < c_b)
+ if(p[pixel[15]] < c_b)
+ {}
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ if(p[pixel[9]] > cb)
+ if(p[pixel[10]] > cb)
+ if(p[pixel[11]] > cb)
+ if(p[pixel[12]] > cb)
+ if(p[pixel[13]] > cb)
+ if(p[pixel[14]] > cb)
+ if(p[pixel[15]] > cb)
+ {}
+ else
+ if(p[pixel[5]] > cb)
+ if(p[pixel[6]] > cb)
+ if(p[pixel[7]] > cb)
+ if(p[pixel[8]] > cb)
+ {}
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ if(p[pixel[4]] > cb)
+ if(p[pixel[5]] > cb)
+ if(p[pixel[6]] > cb)
+ if(p[pixel[7]] > cb)
+ if(p[pixel[8]] > cb)
+ {}
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else if(p[pixel[9]] < c_b)
+ if(p[pixel[6]] < c_b)
+ if(p[pixel[7]] < c_b)
+ if(p[pixel[8]] < c_b)
+ if(p[pixel[10]] < c_b)
+ if(p[pixel[11]] < c_b)
+ if(p[pixel[12]] < c_b)
+ if(p[pixel[13]] < c_b)
+ if(p[pixel[5]] < c_b)
+ if(p[pixel[4]] < c_b)
+ {}
+ else
+ if(p[pixel[14]] < c_b)
+ {}
+ else
+ continue;
+ else
+ if(p[pixel[14]] < c_b)
+ if(p[pixel[15]] < c_b)
+ {}
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else if(p[pixel[2]] < c_b)
+ if(p[pixel[8]] > cb)
+ if(p[pixel[9]] > cb)
+ if(p[pixel[10]] > cb)
+ if(p[pixel[11]] > cb)
+ if(p[pixel[12]] > cb)
+ if(p[pixel[13]] > cb)
+ if(p[pixel[14]] > cb)
+ if(p[pixel[15]] > cb)
+ {}
+ else
+ if(p[pixel[5]] > cb)
+ if(p[pixel[6]] > cb)
+ if(p[pixel[7]] > cb)
+ {}
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ if(p[pixel[4]] > cb)
+ if(p[pixel[5]] > cb)
+ if(p[pixel[6]] > cb)
+ if(p[pixel[7]] > cb)
+ {}
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ if(p[pixel[3]] > cb)
+ if(p[pixel[4]] > cb)
+ if(p[pixel[5]] > cb)
+ if(p[pixel[6]] > cb)
+ if(p[pixel[7]] > cb)
+ {}
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else if(p[pixel[8]] < c_b)
+ if(p[pixel[6]] < c_b)
+ if(p[pixel[7]] < c_b)
+ if(p[pixel[9]] < c_b)
+ if(p[pixel[10]] < c_b)
+ if(p[pixel[11]] < c_b)
+ if(p[pixel[5]] < c_b)
+ if(p[pixel[4]] < c_b)
+ if(p[pixel[3]] < c_b)
+ {}
+ else
+ if(p[pixel[12]] < c_b)
+ if(p[pixel[13]] < c_b)
+ {}
+ else
+ continue;
+ else
+ continue;
+ else
+ if(p[pixel[12]] < c_b)
+ if(p[pixel[13]] < c_b)
+ if(p[pixel[14]] < c_b)
+ {}
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ if(p[pixel[12]] < c_b)
+ if(p[pixel[13]] < c_b)
+ if(p[pixel[14]] < c_b)
+ if(p[pixel[15]] < c_b)
+ {}
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ if(p[pixel[8]] > cb)
+ if(p[pixel[9]] > cb)
+ if(p[pixel[10]] > cb)
+ if(p[pixel[11]] > cb)
+ if(p[pixel[12]] > cb)
+ if(p[pixel[13]] > cb)
+ if(p[pixel[14]] > cb)
+ if(p[pixel[15]] > cb)
+ {}
+ else
+ if(p[pixel[5]] > cb)
+ if(p[pixel[6]] > cb)
+ if(p[pixel[7]] > cb)
+ {}
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ if(p[pixel[4]] > cb)
+ if(p[pixel[5]] > cb)
+ if(p[pixel[6]] > cb)
+ if(p[pixel[7]] > cb)
+ {}
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ if(p[pixel[3]] > cb)
+ if(p[pixel[4]] > cb)
+ if(p[pixel[5]] > cb)
+ if(p[pixel[6]] > cb)
+ if(p[pixel[7]] > cb)
+ {}
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else if(p[pixel[8]] < c_b)
+ if(p[pixel[6]] < c_b)
+ if(p[pixel[7]] < c_b)
+ if(p[pixel[9]] < c_b)
+ if(p[pixel[10]] < c_b)
+ if(p[pixel[11]] < c_b)
+ if(p[pixel[12]] < c_b)
+ if(p[pixel[5]] < c_b)
+ if(p[pixel[4]] < c_b)
+ if(p[pixel[3]] < c_b)
+ {}
+ else
+ if(p[pixel[13]] < c_b)
+ {}
+ else
+ continue;
+ else
+ if(p[pixel[13]] < c_b)
+ if(p[pixel[14]] < c_b)
+ {}
+ else
+ continue;
+ else
+ continue;
+ else
+ if(p[pixel[13]] < c_b)
+ if(p[pixel[14]] < c_b)
+ if(p[pixel[15]] < c_b)
+ {}
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else if(p[pixel[1]] < c_b)
+ if(p[pixel[7]] > cb)
+ if(p[pixel[8]] > cb)
+ if(p[pixel[9]] > cb)
+ if(p[pixel[10]] > cb)
+ if(p[pixel[11]] > cb)
+ if(p[pixel[12]] > cb)
+ if(p[pixel[13]] > cb)
+ if(p[pixel[14]] > cb)
+ if(p[pixel[15]] > cb)
+ {}
+ else
+ if(p[pixel[5]] > cb)
+ if(p[pixel[6]] > cb)
+ {}
+ else
+ continue;
+ else
+ continue;
+ else
+ if(p[pixel[4]] > cb)
+ if(p[pixel[5]] > cb)
+ if(p[pixel[6]] > cb)
+ {}
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ if(p[pixel[3]] > cb)
+ if(p[pixel[4]] > cb)
+ if(p[pixel[5]] > cb)
+ if(p[pixel[6]] > cb)
+ {}
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ if(p[pixel[2]] > cb)
+ if(p[pixel[3]] > cb)
+ if(p[pixel[4]] > cb)
+ if(p[pixel[5]] > cb)
+ if(p[pixel[6]] > cb)
+ {}
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else if(p[pixel[7]] < c_b)
+ if(p[pixel[6]] < c_b)
+ if(p[pixel[8]] < c_b)
+ if(p[pixel[9]] < c_b)
+ if(p[pixel[10]] < c_b)
+ if(p[pixel[5]] < c_b)
+ if(p[pixel[4]] < c_b)
+ if(p[pixel[3]] < c_b)
+ if(p[pixel[2]] < c_b)
+ {}
+ else
+ if(p[pixel[11]] < c_b)
+ if(p[pixel[12]] < c_b)
+ {}
+ else
+ continue;
+ else
+ continue;
+ else
+ if(p[pixel[11]] < c_b)
+ if(p[pixel[12]] < c_b)
+ if(p[pixel[13]] < c_b)
+ {}
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ if(p[pixel[11]] < c_b)
+ if(p[pixel[12]] < c_b)
+ if(p[pixel[13]] < c_b)
+ if(p[pixel[14]] < c_b)
+ {}
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ if(p[pixel[11]] < c_b)
+ if(p[pixel[12]] < c_b)
+ if(p[pixel[13]] < c_b)
+ if(p[pixel[14]] < c_b)
+ if(p[pixel[15]] < c_b)
+ {}
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ if(p[pixel[7]] > cb)
+ if(p[pixel[8]] > cb)
+ if(p[pixel[9]] > cb)
+ if(p[pixel[10]] > cb)
+ if(p[pixel[11]] > cb)
+ if(p[pixel[12]] > cb)
+ if(p[pixel[13]] > cb)
+ if(p[pixel[14]] > cb)
+ if(p[pixel[15]] > cb)
+ {}
+ else
+ if(p[pixel[5]] > cb)
+ if(p[pixel[6]] > cb)
+ {}
+ else
+ continue;
+ else
+ continue;
+ else
+ if(p[pixel[4]] > cb)
+ if(p[pixel[5]] > cb)
+ if(p[pixel[6]] > cb)
+ {}
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ if(p[pixel[3]] > cb)
+ if(p[pixel[4]] > cb)
+ if(p[pixel[5]] > cb)
+ if(p[pixel[6]] > cb)
+ {}
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ if(p[pixel[2]] > cb)
+ if(p[pixel[3]] > cb)
+ if(p[pixel[4]] > cb)
+ if(p[pixel[5]] > cb)
+ if(p[pixel[6]] > cb)
+ {}
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else if(p[pixel[7]] < c_b)
+ if(p[pixel[6]] < c_b)
+ if(p[pixel[8]] < c_b)
+ if(p[pixel[9]] < c_b)
+ if(p[pixel[10]] < c_b)
+ if(p[pixel[11]] < c_b)
+ if(p[pixel[5]] < c_b)
+ if(p[pixel[4]] < c_b)
+ if(p[pixel[3]] < c_b)
+ if(p[pixel[2]] < c_b)
+ {}
+ else
+ if(p[pixel[12]] < c_b)
+ {}
+ else
+ continue;
+ else
+ if(p[pixel[12]] < c_b)
+ if(p[pixel[13]] < c_b)
+ {}
+ else
+ continue;
+ else
+ continue;
+ else
+ if(p[pixel[12]] < c_b)
+ if(p[pixel[13]] < c_b)
+ if(p[pixel[14]] < c_b)
+ {}
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ if(p[pixel[12]] < c_b)
+ if(p[pixel[13]] < c_b)
+ if(p[pixel[14]] < c_b)
+ if(p[pixel[15]] < c_b)
+ {}
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else if(p[pixel[0]] < c_b)
+ if(p[pixel[1]] > cb)
+ if(p[pixel[7]] > cb)
+ if(p[pixel[6]] > cb)
+ if(p[pixel[8]] > cb)
+ if(p[pixel[9]] > cb)
+ if(p[pixel[10]] > cb)
+ if(p[pixel[5]] > cb)
+ if(p[pixel[4]] > cb)
+ if(p[pixel[3]] > cb)
+ if(p[pixel[2]] > cb)
+ {}
+ else
+ if(p[pixel[11]] > cb)
+ if(p[pixel[12]] > cb)
+ {}
+ else
+ continue;
+ else
+ continue;
+ else
+ if(p[pixel[11]] > cb)
+ if(p[pixel[12]] > cb)
+ if(p[pixel[13]] > cb)
+ {}
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ if(p[pixel[11]] > cb)
+ if(p[pixel[12]] > cb)
+ if(p[pixel[13]] > cb)
+ if(p[pixel[14]] > cb)
+ {}
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ if(p[pixel[11]] > cb)
+ if(p[pixel[12]] > cb)
+ if(p[pixel[13]] > cb)
+ if(p[pixel[14]] > cb)
+ if(p[pixel[15]] > cb)
+ {}
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else if(p[pixel[7]] < c_b)
+ if(p[pixel[8]] < c_b)
+ if(p[pixel[9]] < c_b)
+ if(p[pixel[10]] < c_b)
+ if(p[pixel[11]] < c_b)
+ if(p[pixel[12]] < c_b)
+ if(p[pixel[13]] < c_b)
+ if(p[pixel[14]] < c_b)
+ if(p[pixel[15]] < c_b)
+ {}
+ else
+ if(p[pixel[5]] < c_b)
+ if(p[pixel[6]] < c_b)
+ {}
+ else
+ continue;
+ else
+ continue;
+ else
+ if(p[pixel[4]] < c_b)
+ if(p[pixel[5]] < c_b)
+ if(p[pixel[6]] < c_b)
+ {}
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ if(p[pixel[3]] < c_b)
+ if(p[pixel[4]] < c_b)
+ if(p[pixel[5]] < c_b)
+ if(p[pixel[6]] < c_b)
+ {}
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ if(p[pixel[2]] < c_b)
+ if(p[pixel[3]] < c_b)
+ if(p[pixel[4]] < c_b)
+ if(p[pixel[5]] < c_b)
+ if(p[pixel[6]] < c_b)
+ {}
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else if(p[pixel[1]] < c_b)
+ if(p[pixel[2]] > cb)
+ if(p[pixel[8]] > cb)
+ if(p[pixel[6]] > cb)
+ if(p[pixel[7]] > cb)
+ if(p[pixel[9]] > cb)
+ if(p[pixel[10]] > cb)
+ if(p[pixel[11]] > cb)
+ if(p[pixel[5]] > cb)
+ if(p[pixel[4]] > cb)
+ if(p[pixel[3]] > cb)
+ {}
+ else
+ if(p[pixel[12]] > cb)
+ if(p[pixel[13]] > cb)
+ {}
+ else
+ continue;
+ else
+ continue;
+ else
+ if(p[pixel[12]] > cb)
+ if(p[pixel[13]] > cb)
+ if(p[pixel[14]] > cb)
+ {}
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ if(p[pixel[12]] > cb)
+ if(p[pixel[13]] > cb)
+ if(p[pixel[14]] > cb)
+ if(p[pixel[15]] > cb)
+ {}
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else if(p[pixel[8]] < c_b)
+ if(p[pixel[9]] < c_b)
+ if(p[pixel[10]] < c_b)
+ if(p[pixel[11]] < c_b)
+ if(p[pixel[12]] < c_b)
+ if(p[pixel[13]] < c_b)
+ if(p[pixel[14]] < c_b)
+ if(p[pixel[15]] < c_b)
+ {}
+ else
+ if(p[pixel[5]] < c_b)
+ if(p[pixel[6]] < c_b)
+ if(p[pixel[7]] < c_b)
+ {}
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ if(p[pixel[4]] < c_b)
+ if(p[pixel[5]] < c_b)
+ if(p[pixel[6]] < c_b)
+ if(p[pixel[7]] < c_b)
+ {}
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ if(p[pixel[3]] < c_b)
+ if(p[pixel[4]] < c_b)
+ if(p[pixel[5]] < c_b)
+ if(p[pixel[6]] < c_b)
+ if(p[pixel[7]] < c_b)
+ {}
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else if(p[pixel[2]] < c_b)
+ if(p[pixel[3]] > cb)
+ if(p[pixel[9]] > cb)
+ if(p[pixel[6]] > cb)
+ if(p[pixel[7]] > cb)
+ if(p[pixel[8]] > cb)
+ if(p[pixel[10]] > cb)
+ if(p[pixel[11]] > cb)
+ if(p[pixel[12]] > cb)
+ if(p[pixel[5]] > cb)
+ if(p[pixel[4]] > cb)
+ {}
+ else
+ if(p[pixel[13]] > cb)
+ if(p[pixel[14]] > cb)
+ {}
+ else
+ continue;
+ else
+ continue;
+ else
+ if(p[pixel[13]] > cb)
+ if(p[pixel[14]] > cb)
+ if(p[pixel[15]] > cb)
+ {}
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else if(p[pixel[9]] < c_b)
+ if(p[pixel[10]] < c_b)
+ if(p[pixel[11]] < c_b)
+ if(p[pixel[12]] < c_b)
+ if(p[pixel[13]] < c_b)
+ if(p[pixel[14]] < c_b)
+ if(p[pixel[15]] < c_b)
+ {}
+ else
+ if(p[pixel[5]] < c_b)
+ if(p[pixel[6]] < c_b)
+ if(p[pixel[7]] < c_b)
+ if(p[pixel[8]] < c_b)
+ {}
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ if(p[pixel[4]] < c_b)
+ if(p[pixel[5]] < c_b)
+ if(p[pixel[6]] < c_b)
+ if(p[pixel[7]] < c_b)
+ if(p[pixel[8]] < c_b)
+ {}
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else if(p[pixel[3]] < c_b)
+ if(p[pixel[4]] > cb)
+ if(p[pixel[14]] > cb)
+ if(p[pixel[6]] > cb)
+ if(p[pixel[7]] > cb)
+ if(p[pixel[8]] > cb)
+ if(p[pixel[9]] > cb)
+ if(p[pixel[10]] > cb)
+ if(p[pixel[11]] > cb)
+ if(p[pixel[12]] > cb)
+ if(p[pixel[13]] > cb)
+ if(p[pixel[5]] > cb)
+ {}
+ else
+ if(p[pixel[15]] > cb)
+ {}
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else if(p[pixel[14]] < c_b)
+ if(p[pixel[10]] > cb)
+ if(p[pixel[5]] > cb)
+ if(p[pixel[6]] > cb)
+ if(p[pixel[7]] > cb)
+ if(p[pixel[8]] > cb)
+ if(p[pixel[9]] > cb)
+ if(p[pixel[11]] > cb)
+ if(p[pixel[12]] > cb)
+ if(p[pixel[13]] > cb)
+ {}
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else if(p[pixel[10]] < c_b)
+ if(p[pixel[11]] < c_b)
+ if(p[pixel[12]] < c_b)
+ if(p[pixel[13]] < c_b)
+ if(p[pixel[15]] < c_b)
+ {}
+ else
+ if(p[pixel[5]] < c_b)
+ if(p[pixel[6]] < c_b)
+ if(p[pixel[7]] < c_b)
+ if(p[pixel[8]] < c_b)
+ if(p[pixel[9]] < c_b)
+ {}
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ if(p[pixel[5]] > cb)
+ if(p[pixel[6]] > cb)
+ if(p[pixel[7]] > cb)
+ if(p[pixel[8]] > cb)
+ if(p[pixel[9]] > cb)
+ if(p[pixel[10]] > cb)
+ if(p[pixel[11]] > cb)
+ if(p[pixel[12]] > cb)
+ if(p[pixel[13]] > cb)
+ {}
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else if(p[pixel[4]] < c_b)
+ if(p[pixel[5]] > cb)
+ if(p[pixel[15]] < c_b)
+ if(p[pixel[11]] > cb)
+ if(p[pixel[6]] > cb)
+ if(p[pixel[7]] > cb)
+ if(p[pixel[8]] > cb)
+ if(p[pixel[9]] > cb)
+ if(p[pixel[10]] > cb)
+ if(p[pixel[12]] > cb)
+ if(p[pixel[13]] > cb)
+ if(p[pixel[14]] > cb)
+ {}
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else if(p[pixel[11]] < c_b)
+ if(p[pixel[12]] < c_b)
+ if(p[pixel[13]] < c_b)
+ if(p[pixel[14]] < c_b)
+ {}
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ if(p[pixel[6]] > cb)
+ if(p[pixel[7]] > cb)
+ if(p[pixel[8]] > cb)
+ if(p[pixel[9]] > cb)
+ if(p[pixel[10]] > cb)
+ if(p[pixel[11]] > cb)
+ if(p[pixel[12]] > cb)
+ if(p[pixel[13]] > cb)
+ if(p[pixel[14]] > cb)
+ {}
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else if(p[pixel[5]] < c_b)
+ if(p[pixel[6]] > cb)
+ if(p[pixel[12]] > cb)
+ if(p[pixel[7]] > cb)
+ if(p[pixel[8]] > cb)
+ if(p[pixel[9]] > cb)
+ if(p[pixel[10]] > cb)
+ if(p[pixel[11]] > cb)
+ if(p[pixel[13]] > cb)
+ if(p[pixel[14]] > cb)
+ if(p[pixel[15]] > cb)
+ {}
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else if(p[pixel[12]] < c_b)
+ if(p[pixel[13]] < c_b)
+ if(p[pixel[14]] < c_b)
+ if(p[pixel[15]] < c_b)
+ {}
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else if(p[pixel[6]] < c_b)
+ if(p[pixel[7]] < c_b)
+ if(p[pixel[8]] < c_b)
+ if(p[pixel[9]] < c_b)
+ {}
+ else
+ if(p[pixel[15]] < c_b)
+ {}
+ else
+ continue;
+ else
+ if(p[pixel[14]] < c_b)
+ if(p[pixel[15]] < c_b)
+ {}
+ else
+ continue;
+ else
+ continue;
+ else
+ if(p[pixel[13]] < c_b)
+ if(p[pixel[14]] < c_b)
+ if(p[pixel[15]] < c_b)
+ {}
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ if(p[pixel[12]] < c_b)
+ if(p[pixel[13]] < c_b)
+ if(p[pixel[14]] < c_b)
+ if(p[pixel[15]] < c_b)
+ {}
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ if(p[pixel[11]] > cb)
+ if(p[pixel[6]] > cb)
+ if(p[pixel[7]] > cb)
+ if(p[pixel[8]] > cb)
+ if(p[pixel[9]] > cb)
+ if(p[pixel[10]] > cb)
+ if(p[pixel[12]] > cb)
+ if(p[pixel[13]] > cb)
+ if(p[pixel[14]] > cb)
+ if(p[pixel[15]] > cb)
+ {}
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else if(p[pixel[11]] < c_b)
+ if(p[pixel[12]] < c_b)
+ if(p[pixel[13]] < c_b)
+ if(p[pixel[14]] < c_b)
+ if(p[pixel[15]] < c_b)
+ {}
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ if(p[pixel[10]] > cb)
+ if(p[pixel[6]] > cb)
+ if(p[pixel[7]] > cb)
+ if(p[pixel[8]] > cb)
+ if(p[pixel[9]] > cb)
+ if(p[pixel[11]] > cb)
+ if(p[pixel[12]] > cb)
+ if(p[pixel[13]] > cb)
+ if(p[pixel[14]] > cb)
+ if(p[pixel[5]] > cb)
+ {}
+ else
+ if(p[pixel[15]] > cb)
+ {}
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else if(p[pixel[10]] < c_b)
+ if(p[pixel[11]] < c_b)
+ if(p[pixel[12]] < c_b)
+ if(p[pixel[13]] < c_b)
+ if(p[pixel[14]] < c_b)
+ if(p[pixel[15]] < c_b)
+ {}
+ else
+ if(p[pixel[5]] < c_b)
+ if(p[pixel[6]] < c_b)
+ if(p[pixel[7]] < c_b)
+ if(p[pixel[8]] < c_b)
+ if(p[pixel[9]] < c_b)
+ {}
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ if(p[pixel[9]] > cb)
+ if(p[pixel[6]] > cb)
+ if(p[pixel[7]] > cb)
+ if(p[pixel[8]] > cb)
+ if(p[pixel[10]] > cb)
+ if(p[pixel[11]] > cb)
+ if(p[pixel[12]] > cb)
+ if(p[pixel[13]] > cb)
+ if(p[pixel[5]] > cb)
+ if(p[pixel[4]] > cb)
+ {}
+ else
+ if(p[pixel[14]] > cb)
+ {}
+ else
+ continue;
+ else
+ if(p[pixel[14]] > cb)
+ if(p[pixel[15]] > cb)
+ {}
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else if(p[pixel[9]] < c_b)
+ if(p[pixel[10]] < c_b)
+ if(p[pixel[11]] < c_b)
+ if(p[pixel[12]] < c_b)
+ if(p[pixel[13]] < c_b)
+ if(p[pixel[14]] < c_b)
+ if(p[pixel[15]] < c_b)
+ {}
+ else
+ if(p[pixel[5]] < c_b)
+ if(p[pixel[6]] < c_b)
+ if(p[pixel[7]] < c_b)
+ if(p[pixel[8]] < c_b)
+ {}
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ if(p[pixel[4]] < c_b)
+ if(p[pixel[5]] < c_b)
+ if(p[pixel[6]] < c_b)
+ if(p[pixel[7]] < c_b)
+ if(p[pixel[8]] < c_b)
+ {}
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ if(p[pixel[8]] > cb)
+ if(p[pixel[6]] > cb)
+ if(p[pixel[7]] > cb)
+ if(p[pixel[9]] > cb)
+ if(p[pixel[10]] > cb)
+ if(p[pixel[11]] > cb)
+ if(p[pixel[12]] > cb)
+ if(p[pixel[5]] > cb)
+ if(p[pixel[4]] > cb)
+ if(p[pixel[3]] > cb)
+ {}
+ else
+ if(p[pixel[13]] > cb)
+ {}
+ else
+ continue;
+ else
+ if(p[pixel[13]] > cb)
+ if(p[pixel[14]] > cb)
+ {}
+ else
+ continue;
+ else
+ continue;
+ else
+ if(p[pixel[13]] > cb)
+ if(p[pixel[14]] > cb)
+ if(p[pixel[15]] > cb)
+ {}
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else if(p[pixel[8]] < c_b)
+ if(p[pixel[9]] < c_b)
+ if(p[pixel[10]] < c_b)
+ if(p[pixel[11]] < c_b)
+ if(p[pixel[12]] < c_b)
+ if(p[pixel[13]] < c_b)
+ if(p[pixel[14]] < c_b)
+ if(p[pixel[15]] < c_b)
+ {}
+ else
+ if(p[pixel[5]] < c_b)
+ if(p[pixel[6]] < c_b)
+ if(p[pixel[7]] < c_b)
+ {}
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ if(p[pixel[4]] < c_b)
+ if(p[pixel[5]] < c_b)
+ if(p[pixel[6]] < c_b)
+ if(p[pixel[7]] < c_b)
+ {}
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ if(p[pixel[3]] < c_b)
+ if(p[pixel[4]] < c_b)
+ if(p[pixel[5]] < c_b)
+ if(p[pixel[6]] < c_b)
+ if(p[pixel[7]] < c_b)
+ {}
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ if(p[pixel[7]] > cb)
+ if(p[pixel[6]] > cb)
+ if(p[pixel[8]] > cb)
+ if(p[pixel[9]] > cb)
+ if(p[pixel[10]] > cb)
+ if(p[pixel[11]] > cb)
+ if(p[pixel[5]] > cb)
+ if(p[pixel[4]] > cb)
+ if(p[pixel[3]] > cb)
+ if(p[pixel[2]] > cb)
+ {}
+ else
+ if(p[pixel[12]] > cb)
+ {}
+ else
+ continue;
+ else
+ if(p[pixel[12]] > cb)
+ if(p[pixel[13]] > cb)
+ {}
+ else
+ continue;
+ else
+ continue;
+ else
+ if(p[pixel[12]] > cb)
+ if(p[pixel[13]] > cb)
+ if(p[pixel[14]] > cb)
+ {}
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ if(p[pixel[12]] > cb)
+ if(p[pixel[13]] > cb)
+ if(p[pixel[14]] > cb)
+ if(p[pixel[15]] > cb)
+ {}
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else if(p[pixel[7]] < c_b)
+ if(p[pixel[8]] < c_b)
+ if(p[pixel[9]] < c_b)
+ if(p[pixel[10]] < c_b)
+ if(p[pixel[11]] < c_b)
+ if(p[pixel[12]] < c_b)
+ if(p[pixel[13]] < c_b)
+ if(p[pixel[14]] < c_b)
+ if(p[pixel[15]] < c_b)
+ {}
+ else
+ if(p[pixel[5]] < c_b)
+ if(p[pixel[6]] < c_b)
+ {}
+ else
+ continue;
+ else
+ continue;
+ else
+ if(p[pixel[4]] < c_b)
+ if(p[pixel[5]] < c_b)
+ if(p[pixel[6]] < c_b)
+ {}
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ if(p[pixel[3]] < c_b)
+ if(p[pixel[4]] < c_b)
+ if(p[pixel[5]] < c_b)
+ if(p[pixel[6]] < c_b)
+ {}
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ if(p[pixel[2]] < c_b)
+ if(p[pixel[3]] < c_b)
+ if(p[pixel[4]] < c_b)
+ if(p[pixel[5]] < c_b)
+ if(p[pixel[6]] < c_b)
+ {}
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ if(p[pixel[6]] > cb)
+ if(p[pixel[7]] > cb)
+ if(p[pixel[8]] > cb)
+ if(p[pixel[9]] > cb)
+ if(p[pixel[10]] > cb)
+ if(p[pixel[5]] > cb)
+ if(p[pixel[4]] > cb)
+ if(p[pixel[3]] > cb)
+ if(p[pixel[2]] > cb)
+ if(p[pixel[1]] > cb)
+ {}
+ else
+ if(p[pixel[11]] > cb)
+ {}
+ else
+ continue;
+ else
+ if(p[pixel[11]] > cb)
+ if(p[pixel[12]] > cb)
+ {}
+ else
+ continue;
+ else
+ continue;
+ else
+ if(p[pixel[11]] > cb)
+ if(p[pixel[12]] > cb)
+ if(p[pixel[13]] > cb)
+ {}
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ if(p[pixel[11]] > cb)
+ if(p[pixel[12]] > cb)
+ if(p[pixel[13]] > cb)
+ if(p[pixel[14]] > cb)
+ {}
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ if(p[pixel[11]] > cb)
+ if(p[pixel[12]] > cb)
+ if(p[pixel[13]] > cb)
+ if(p[pixel[14]] > cb)
+ if(p[pixel[15]] > cb)
+ {}
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else if(p[pixel[6]] < c_b)
+ if(p[pixel[7]] < c_b)
+ if(p[pixel[8]] < c_b)
+ if(p[pixel[9]] < c_b)
+ if(p[pixel[10]] < c_b)
+ if(p[pixel[5]] < c_b)
+ if(p[pixel[4]] < c_b)
+ if(p[pixel[3]] < c_b)
+ if(p[pixel[2]] < c_b)
+ if(p[pixel[1]] < c_b)
+ {}
+ else
+ if(p[pixel[11]] < c_b)
+ {}
+ else
+ continue;
+ else
+ if(p[pixel[11]] < c_b)
+ if(p[pixel[12]] < c_b)
+ {}
+ else
+ continue;
+ else
+ continue;
+ else
+ if(p[pixel[11]] < c_b)
+ if(p[pixel[12]] < c_b)
+ if(p[pixel[13]] < c_b)
+ {}
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ if(p[pixel[11]] < c_b)
+ if(p[pixel[12]] < c_b)
+ if(p[pixel[13]] < c_b)
+ if(p[pixel[14]] < c_b)
+ {}
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ if(p[pixel[11]] < c_b)
+ if(p[pixel[12]] < c_b)
+ if(p[pixel[13]] < c_b)
+ if(p[pixel[14]] < c_b)
+ if(p[pixel[15]] < c_b)
+ {}
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ if(num_corners == rsize)
+ {
+ rsize*=2;
+ ret_corners = (xy*)realloc(ret_corners, sizeof(xy)*rsize);
+ }
+
+ ret_corners[num_corners].x = x;
+ ret_corners[num_corners].y = y;
+ num_corners++;
+ }
+
+ *ret_num_corners = num_corners;
+ return ret_corners;
+
+}
+
+
diff --git a/extern/libmv/third_party/fast/fast_11.c b/extern/libmv/third_party/fast/fast_11.c
new file mode 100644
index 00000000000..b4af4309521
--- /dev/null
+++ b/extern/libmv/third_party/fast/fast_11.c
@@ -0,0 +1,3910 @@
+/*This is mechanically generated code*/
+#include <stdlib.h>
+
+typedef struct { int x, y; } xy;
+typedef unsigned char byte;
+
+int fast11_corner_score(const byte* p, const int pixel[], int bstart)
+{
+ int bmin = bstart;
+ int bmax = 255;
+ int b = (bmax + bmin)/2;
+
+ /*Compute the score using binary search*/
+ for(;;)
+ {
+ int cb = *p + b;
+ int c_b= *p - b;
+
+
+ if( p[pixel[0]] > cb)
+ if( p[pixel[1]] > cb)
+ if( p[pixel[2]] > cb)
+ if( p[pixel[3]] > cb)
+ if( p[pixel[4]] > cb)
+ if( p[pixel[5]] > cb)
+ if( p[pixel[6]] > cb)
+ if( p[pixel[7]] > cb)
+ if( p[pixel[8]] > cb)
+ if( p[pixel[9]] > cb)
+ if( p[pixel[10]] > cb)
+ goto is_a_corner;
+ else
+ if( p[pixel[15]] > cb)
+ goto is_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ if( p[pixel[14]] > cb)
+ if( p[pixel[15]] > cb)
+ goto is_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ if( p[pixel[13]] > cb)
+ if( p[pixel[14]] > cb)
+ if( p[pixel[15]] > cb)
+ goto is_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ if( p[pixel[12]] > cb)
+ if( p[pixel[13]] > cb)
+ if( p[pixel[14]] > cb)
+ if( p[pixel[15]] > cb)
+ goto is_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ if( p[pixel[11]] > cb)
+ if( p[pixel[12]] > cb)
+ if( p[pixel[13]] > cb)
+ if( p[pixel[14]] > cb)
+ if( p[pixel[15]] > cb)
+ goto is_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else if( p[pixel[5]] < c_b)
+ if( p[pixel[10]] > cb)
+ if( p[pixel[11]] > cb)
+ if( p[pixel[12]] > cb)
+ if( p[pixel[13]] > cb)
+ if( p[pixel[14]] > cb)
+ if( p[pixel[15]] > cb)
+ goto is_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else if( p[pixel[10]] < c_b)
+ if( p[pixel[6]] < c_b)
+ if( p[pixel[7]] < c_b)
+ if( p[pixel[8]] < c_b)
+ if( p[pixel[9]] < c_b)
+ if( p[pixel[11]] < c_b)
+ if( p[pixel[12]] < c_b)
+ if( p[pixel[13]] < c_b)
+ if( p[pixel[14]] < c_b)
+ if( p[pixel[15]] < c_b)
+ goto is_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ if( p[pixel[10]] > cb)
+ if( p[pixel[11]] > cb)
+ if( p[pixel[12]] > cb)
+ if( p[pixel[13]] > cb)
+ if( p[pixel[14]] > cb)
+ if( p[pixel[15]] > cb)
+ goto is_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else if( p[pixel[4]] < c_b)
+ if( p[pixel[15]] > cb)
+ if( p[pixel[9]] > cb)
+ if( p[pixel[10]] > cb)
+ if( p[pixel[11]] > cb)
+ if( p[pixel[12]] > cb)
+ if( p[pixel[13]] > cb)
+ if( p[pixel[14]] > cb)
+ goto is_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else if( p[pixel[9]] < c_b)
+ if( p[pixel[5]] < c_b)
+ if( p[pixel[6]] < c_b)
+ if( p[pixel[7]] < c_b)
+ if( p[pixel[8]] < c_b)
+ if( p[pixel[10]] < c_b)
+ if( p[pixel[11]] < c_b)
+ if( p[pixel[12]] < c_b)
+ if( p[pixel[13]] < c_b)
+ if( p[pixel[14]] < c_b)
+ goto is_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ if( p[pixel[5]] < c_b)
+ if( p[pixel[6]] < c_b)
+ if( p[pixel[7]] < c_b)
+ if( p[pixel[8]] < c_b)
+ if( p[pixel[9]] < c_b)
+ if( p[pixel[10]] < c_b)
+ if( p[pixel[11]] < c_b)
+ if( p[pixel[12]] < c_b)
+ if( p[pixel[13]] < c_b)
+ if( p[pixel[14]] < c_b)
+ goto is_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ if( p[pixel[9]] > cb)
+ if( p[pixel[10]] > cb)
+ if( p[pixel[11]] > cb)
+ if( p[pixel[12]] > cb)
+ if( p[pixel[13]] > cb)
+ if( p[pixel[14]] > cb)
+ if( p[pixel[15]] > cb)
+ goto is_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else if( p[pixel[9]] < c_b)
+ if( p[pixel[5]] < c_b)
+ if( p[pixel[6]] < c_b)
+ if( p[pixel[7]] < c_b)
+ if( p[pixel[8]] < c_b)
+ if( p[pixel[10]] < c_b)
+ if( p[pixel[11]] < c_b)
+ if( p[pixel[12]] < c_b)
+ if( p[pixel[13]] < c_b)
+ if( p[pixel[14]] < c_b)
+ if( p[pixel[15]] < c_b)
+ goto is_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else if( p[pixel[3]] < c_b)
+ if( p[pixel[14]] > cb)
+ if( p[pixel[8]] > cb)
+ if( p[pixel[9]] > cb)
+ if( p[pixel[10]] > cb)
+ if( p[pixel[11]] > cb)
+ if( p[pixel[12]] > cb)
+ if( p[pixel[13]] > cb)
+ if( p[pixel[15]] > cb)
+ goto is_a_corner;
+ else
+ if( p[pixel[4]] > cb)
+ if( p[pixel[5]] > cb)
+ if( p[pixel[6]] > cb)
+ if( p[pixel[7]] > cb)
+ goto is_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else if( p[pixel[8]] < c_b)
+ if( p[pixel[4]] < c_b)
+ if( p[pixel[5]] < c_b)
+ if( p[pixel[6]] < c_b)
+ if( p[pixel[7]] < c_b)
+ if( p[pixel[9]] < c_b)
+ if( p[pixel[10]] < c_b)
+ if( p[pixel[11]] < c_b)
+ if( p[pixel[12]] < c_b)
+ if( p[pixel[13]] < c_b)
+ goto is_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else if( p[pixel[14]] < c_b)
+ if( p[pixel[5]] < c_b)
+ if( p[pixel[6]] < c_b)
+ if( p[pixel[7]] < c_b)
+ if( p[pixel[8]] < c_b)
+ if( p[pixel[9]] < c_b)
+ if( p[pixel[10]] < c_b)
+ if( p[pixel[11]] < c_b)
+ if( p[pixel[12]] < c_b)
+ if( p[pixel[13]] < c_b)
+ if( p[pixel[4]] < c_b)
+ goto is_a_corner;
+ else
+ if( p[pixel[15]] < c_b)
+ goto is_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ if( p[pixel[4]] < c_b)
+ if( p[pixel[5]] < c_b)
+ if( p[pixel[6]] < c_b)
+ if( p[pixel[7]] < c_b)
+ if( p[pixel[8]] < c_b)
+ if( p[pixel[9]] < c_b)
+ if( p[pixel[10]] < c_b)
+ if( p[pixel[11]] < c_b)
+ if( p[pixel[12]] < c_b)
+ if( p[pixel[13]] < c_b)
+ goto is_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ if( p[pixel[8]] > cb)
+ if( p[pixel[9]] > cb)
+ if( p[pixel[10]] > cb)
+ if( p[pixel[11]] > cb)
+ if( p[pixel[12]] > cb)
+ if( p[pixel[13]] > cb)
+ if( p[pixel[14]] > cb)
+ if( p[pixel[15]] > cb)
+ goto is_a_corner;
+ else
+ if( p[pixel[4]] > cb)
+ if( p[pixel[5]] > cb)
+ if( p[pixel[6]] > cb)
+ if( p[pixel[7]] > cb)
+ goto is_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else if( p[pixel[8]] < c_b)
+ if( p[pixel[5]] < c_b)
+ if( p[pixel[6]] < c_b)
+ if( p[pixel[7]] < c_b)
+ if( p[pixel[9]] < c_b)
+ if( p[pixel[10]] < c_b)
+ if( p[pixel[11]] < c_b)
+ if( p[pixel[12]] < c_b)
+ if( p[pixel[13]] < c_b)
+ if( p[pixel[14]] < c_b)
+ if( p[pixel[4]] < c_b)
+ goto is_a_corner;
+ else
+ if( p[pixel[15]] < c_b)
+ goto is_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else if( p[pixel[2]] < c_b)
+ if( p[pixel[7]] > cb)
+ if( p[pixel[8]] > cb)
+ if( p[pixel[9]] > cb)
+ if( p[pixel[10]] > cb)
+ if( p[pixel[11]] > cb)
+ if( p[pixel[12]] > cb)
+ if( p[pixel[13]] > cb)
+ if( p[pixel[14]] > cb)
+ if( p[pixel[15]] > cb)
+ goto is_a_corner;
+ else
+ if( p[pixel[4]] > cb)
+ if( p[pixel[5]] > cb)
+ if( p[pixel[6]] > cb)
+ goto is_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ if( p[pixel[3]] > cb)
+ if( p[pixel[4]] > cb)
+ if( p[pixel[5]] > cb)
+ if( p[pixel[6]] > cb)
+ goto is_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else if( p[pixel[7]] < c_b)
+ if( p[pixel[5]] < c_b)
+ if( p[pixel[6]] < c_b)
+ if( p[pixel[8]] < c_b)
+ if( p[pixel[9]] < c_b)
+ if( p[pixel[10]] < c_b)
+ if( p[pixel[11]] < c_b)
+ if( p[pixel[12]] < c_b)
+ if( p[pixel[4]] < c_b)
+ if( p[pixel[3]] < c_b)
+ goto is_a_corner;
+ else
+ if( p[pixel[13]] < c_b)
+ if( p[pixel[14]] < c_b)
+ goto is_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ if( p[pixel[13]] < c_b)
+ if( p[pixel[14]] < c_b)
+ if( p[pixel[15]] < c_b)
+ goto is_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ if( p[pixel[7]] > cb)
+ if( p[pixel[8]] > cb)
+ if( p[pixel[9]] > cb)
+ if( p[pixel[10]] > cb)
+ if( p[pixel[11]] > cb)
+ if( p[pixel[12]] > cb)
+ if( p[pixel[13]] > cb)
+ if( p[pixel[14]] > cb)
+ if( p[pixel[15]] > cb)
+ goto is_a_corner;
+ else
+ if( p[pixel[4]] > cb)
+ if( p[pixel[5]] > cb)
+ if( p[pixel[6]] > cb)
+ goto is_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ if( p[pixel[3]] > cb)
+ if( p[pixel[4]] > cb)
+ if( p[pixel[5]] > cb)
+ if( p[pixel[6]] > cb)
+ goto is_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else if( p[pixel[7]] < c_b)
+ if( p[pixel[5]] < c_b)
+ if( p[pixel[6]] < c_b)
+ if( p[pixel[8]] < c_b)
+ if( p[pixel[9]] < c_b)
+ if( p[pixel[10]] < c_b)
+ if( p[pixel[11]] < c_b)
+ if( p[pixel[12]] < c_b)
+ if( p[pixel[13]] < c_b)
+ if( p[pixel[4]] < c_b)
+ if( p[pixel[3]] < c_b)
+ goto is_a_corner;
+ else
+ if( p[pixel[14]] < c_b)
+ goto is_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ if( p[pixel[14]] < c_b)
+ if( p[pixel[15]] < c_b)
+ goto is_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else if( p[pixel[1]] < c_b)
+ if( p[pixel[6]] > cb)
+ if( p[pixel[7]] > cb)
+ if( p[pixel[8]] > cb)
+ if( p[pixel[9]] > cb)
+ if( p[pixel[10]] > cb)
+ if( p[pixel[11]] > cb)
+ if( p[pixel[12]] > cb)
+ if( p[pixel[13]] > cb)
+ if( p[pixel[14]] > cb)
+ if( p[pixel[15]] > cb)
+ goto is_a_corner;
+ else
+ if( p[pixel[4]] > cb)
+ if( p[pixel[5]] > cb)
+ goto is_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ if( p[pixel[3]] > cb)
+ if( p[pixel[4]] > cb)
+ if( p[pixel[5]] > cb)
+ goto is_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ if( p[pixel[2]] > cb)
+ if( p[pixel[3]] > cb)
+ if( p[pixel[4]] > cb)
+ if( p[pixel[5]] > cb)
+ goto is_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else if( p[pixel[6]] < c_b)
+ if( p[pixel[5]] < c_b)
+ if( p[pixel[7]] < c_b)
+ if( p[pixel[8]] < c_b)
+ if( p[pixel[9]] < c_b)
+ if( p[pixel[10]] < c_b)
+ if( p[pixel[11]] < c_b)
+ if( p[pixel[4]] < c_b)
+ if( p[pixel[3]] < c_b)
+ if( p[pixel[2]] < c_b)
+ goto is_a_corner;
+ else
+ if( p[pixel[12]] < c_b)
+ if( p[pixel[13]] < c_b)
+ goto is_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ if( p[pixel[12]] < c_b)
+ if( p[pixel[13]] < c_b)
+ if( p[pixel[14]] < c_b)
+ goto is_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ if( p[pixel[12]] < c_b)
+ if( p[pixel[13]] < c_b)
+ if( p[pixel[14]] < c_b)
+ if( p[pixel[15]] < c_b)
+ goto is_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ if( p[pixel[6]] > cb)
+ if( p[pixel[7]] > cb)
+ if( p[pixel[8]] > cb)
+ if( p[pixel[9]] > cb)
+ if( p[pixel[10]] > cb)
+ if( p[pixel[11]] > cb)
+ if( p[pixel[12]] > cb)
+ if( p[pixel[13]] > cb)
+ if( p[pixel[14]] > cb)
+ if( p[pixel[15]] > cb)
+ goto is_a_corner;
+ else
+ if( p[pixel[4]] > cb)
+ if( p[pixel[5]] > cb)
+ goto is_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ if( p[pixel[3]] > cb)
+ if( p[pixel[4]] > cb)
+ if( p[pixel[5]] > cb)
+ goto is_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ if( p[pixel[2]] > cb)
+ if( p[pixel[3]] > cb)
+ if( p[pixel[4]] > cb)
+ if( p[pixel[5]] > cb)
+ goto is_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else if( p[pixel[6]] < c_b)
+ if( p[pixel[5]] < c_b)
+ if( p[pixel[7]] < c_b)
+ if( p[pixel[8]] < c_b)
+ if( p[pixel[9]] < c_b)
+ if( p[pixel[10]] < c_b)
+ if( p[pixel[11]] < c_b)
+ if( p[pixel[12]] < c_b)
+ if( p[pixel[4]] < c_b)
+ if( p[pixel[3]] < c_b)
+ if( p[pixel[2]] < c_b)
+ goto is_a_corner;
+ else
+ if( p[pixel[13]] < c_b)
+ goto is_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ if( p[pixel[13]] < c_b)
+ if( p[pixel[14]] < c_b)
+ goto is_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ if( p[pixel[13]] < c_b)
+ if( p[pixel[14]] < c_b)
+ if( p[pixel[15]] < c_b)
+ goto is_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else if( p[pixel[0]] < c_b)
+ if( p[pixel[1]] > cb)
+ if( p[pixel[6]] > cb)
+ if( p[pixel[5]] > cb)
+ if( p[pixel[7]] > cb)
+ if( p[pixel[8]] > cb)
+ if( p[pixel[9]] > cb)
+ if( p[pixel[10]] > cb)
+ if( p[pixel[11]] > cb)
+ if( p[pixel[4]] > cb)
+ if( p[pixel[3]] > cb)
+ if( p[pixel[2]] > cb)
+ goto is_a_corner;
+ else
+ if( p[pixel[12]] > cb)
+ if( p[pixel[13]] > cb)
+ goto is_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ if( p[pixel[12]] > cb)
+ if( p[pixel[13]] > cb)
+ if( p[pixel[14]] > cb)
+ goto is_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ if( p[pixel[12]] > cb)
+ if( p[pixel[13]] > cb)
+ if( p[pixel[14]] > cb)
+ if( p[pixel[15]] > cb)
+ goto is_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else if( p[pixel[6]] < c_b)
+ if( p[pixel[7]] < c_b)
+ if( p[pixel[8]] < c_b)
+ if( p[pixel[9]] < c_b)
+ if( p[pixel[10]] < c_b)
+ if( p[pixel[11]] < c_b)
+ if( p[pixel[12]] < c_b)
+ if( p[pixel[13]] < c_b)
+ if( p[pixel[14]] < c_b)
+ if( p[pixel[15]] < c_b)
+ goto is_a_corner;
+ else
+ if( p[pixel[4]] < c_b)
+ if( p[pixel[5]] < c_b)
+ goto is_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ if( p[pixel[3]] < c_b)
+ if( p[pixel[4]] < c_b)
+ if( p[pixel[5]] < c_b)
+ goto is_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ if( p[pixel[2]] < c_b)
+ if( p[pixel[3]] < c_b)
+ if( p[pixel[4]] < c_b)
+ if( p[pixel[5]] < c_b)
+ goto is_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else if( p[pixel[1]] < c_b)
+ if( p[pixel[2]] > cb)
+ if( p[pixel[7]] > cb)
+ if( p[pixel[5]] > cb)
+ if( p[pixel[6]] > cb)
+ if( p[pixel[8]] > cb)
+ if( p[pixel[9]] > cb)
+ if( p[pixel[10]] > cb)
+ if( p[pixel[11]] > cb)
+ if( p[pixel[12]] > cb)
+ if( p[pixel[4]] > cb)
+ if( p[pixel[3]] > cb)
+ goto is_a_corner;
+ else
+ if( p[pixel[13]] > cb)
+ if( p[pixel[14]] > cb)
+ goto is_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ if( p[pixel[13]] > cb)
+ if( p[pixel[14]] > cb)
+ if( p[pixel[15]] > cb)
+ goto is_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else if( p[pixel[7]] < c_b)
+ if( p[pixel[8]] < c_b)
+ if( p[pixel[9]] < c_b)
+ if( p[pixel[10]] < c_b)
+ if( p[pixel[11]] < c_b)
+ if( p[pixel[12]] < c_b)
+ if( p[pixel[13]] < c_b)
+ if( p[pixel[14]] < c_b)
+ if( p[pixel[15]] < c_b)
+ goto is_a_corner;
+ else
+ if( p[pixel[4]] < c_b)
+ if( p[pixel[5]] < c_b)
+ if( p[pixel[6]] < c_b)
+ goto is_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ if( p[pixel[3]] < c_b)
+ if( p[pixel[4]] < c_b)
+ if( p[pixel[5]] < c_b)
+ if( p[pixel[6]] < c_b)
+ goto is_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else if( p[pixel[2]] < c_b)
+ if( p[pixel[3]] > cb)
+ if( p[pixel[14]] > cb)
+ if( p[pixel[5]] > cb)
+ if( p[pixel[6]] > cb)
+ if( p[pixel[7]] > cb)
+ if( p[pixel[8]] > cb)
+ if( p[pixel[9]] > cb)
+ if( p[pixel[10]] > cb)
+ if( p[pixel[11]] > cb)
+ if( p[pixel[12]] > cb)
+ if( p[pixel[13]] > cb)
+ if( p[pixel[4]] > cb)
+ goto is_a_corner;
+ else
+ if( p[pixel[15]] > cb)
+ goto is_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else if( p[pixel[14]] < c_b)
+ if( p[pixel[8]] > cb)
+ if( p[pixel[4]] > cb)
+ if( p[pixel[5]] > cb)
+ if( p[pixel[6]] > cb)
+ if( p[pixel[7]] > cb)
+ if( p[pixel[9]] > cb)
+ if( p[pixel[10]] > cb)
+ if( p[pixel[11]] > cb)
+ if( p[pixel[12]] > cb)
+ if( p[pixel[13]] > cb)
+ goto is_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else if( p[pixel[8]] < c_b)
+ if( p[pixel[9]] < c_b)
+ if( p[pixel[10]] < c_b)
+ if( p[pixel[11]] < c_b)
+ if( p[pixel[12]] < c_b)
+ if( p[pixel[13]] < c_b)
+ if( p[pixel[15]] < c_b)
+ goto is_a_corner;
+ else
+ if( p[pixel[4]] < c_b)
+ if( p[pixel[5]] < c_b)
+ if( p[pixel[6]] < c_b)
+ if( p[pixel[7]] < c_b)
+ goto is_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ if( p[pixel[4]] > cb)
+ if( p[pixel[5]] > cb)
+ if( p[pixel[6]] > cb)
+ if( p[pixel[7]] > cb)
+ if( p[pixel[8]] > cb)
+ if( p[pixel[9]] > cb)
+ if( p[pixel[10]] > cb)
+ if( p[pixel[11]] > cb)
+ if( p[pixel[12]] > cb)
+ if( p[pixel[13]] > cb)
+ goto is_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else if( p[pixel[3]] < c_b)
+ if( p[pixel[4]] > cb)
+ if( p[pixel[15]] < c_b)
+ if( p[pixel[9]] > cb)
+ if( p[pixel[5]] > cb)
+ if( p[pixel[6]] > cb)
+ if( p[pixel[7]] > cb)
+ if( p[pixel[8]] > cb)
+ if( p[pixel[10]] > cb)
+ if( p[pixel[11]] > cb)
+ if( p[pixel[12]] > cb)
+ if( p[pixel[13]] > cb)
+ if( p[pixel[14]] > cb)
+ goto is_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else if( p[pixel[9]] < c_b)
+ if( p[pixel[10]] < c_b)
+ if( p[pixel[11]] < c_b)
+ if( p[pixel[12]] < c_b)
+ if( p[pixel[13]] < c_b)
+ if( p[pixel[14]] < c_b)
+ goto is_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ if( p[pixel[5]] > cb)
+ if( p[pixel[6]] > cb)
+ if( p[pixel[7]] > cb)
+ if( p[pixel[8]] > cb)
+ if( p[pixel[9]] > cb)
+ if( p[pixel[10]] > cb)
+ if( p[pixel[11]] > cb)
+ if( p[pixel[12]] > cb)
+ if( p[pixel[13]] > cb)
+ if( p[pixel[14]] > cb)
+ goto is_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else if( p[pixel[4]] < c_b)
+ if( p[pixel[5]] > cb)
+ if( p[pixel[10]] > cb)
+ if( p[pixel[6]] > cb)
+ if( p[pixel[7]] > cb)
+ if( p[pixel[8]] > cb)
+ if( p[pixel[9]] > cb)
+ if( p[pixel[11]] > cb)
+ if( p[pixel[12]] > cb)
+ if( p[pixel[13]] > cb)
+ if( p[pixel[14]] > cb)
+ if( p[pixel[15]] > cb)
+ goto is_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else if( p[pixel[10]] < c_b)
+ if( p[pixel[11]] < c_b)
+ if( p[pixel[12]] < c_b)
+ if( p[pixel[13]] < c_b)
+ if( p[pixel[14]] < c_b)
+ if( p[pixel[15]] < c_b)
+ goto is_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else if( p[pixel[5]] < c_b)
+ if( p[pixel[6]] < c_b)
+ if( p[pixel[7]] < c_b)
+ if( p[pixel[8]] < c_b)
+ if( p[pixel[9]] < c_b)
+ if( p[pixel[10]] < c_b)
+ goto is_a_corner;
+ else
+ if( p[pixel[15]] < c_b)
+ goto is_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ if( p[pixel[14]] < c_b)
+ if( p[pixel[15]] < c_b)
+ goto is_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ if( p[pixel[13]] < c_b)
+ if( p[pixel[14]] < c_b)
+ if( p[pixel[15]] < c_b)
+ goto is_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ if( p[pixel[12]] < c_b)
+ if( p[pixel[13]] < c_b)
+ if( p[pixel[14]] < c_b)
+ if( p[pixel[15]] < c_b)
+ goto is_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ if( p[pixel[11]] < c_b)
+ if( p[pixel[12]] < c_b)
+ if( p[pixel[13]] < c_b)
+ if( p[pixel[14]] < c_b)
+ if( p[pixel[15]] < c_b)
+ goto is_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ if( p[pixel[10]] < c_b)
+ if( p[pixel[11]] < c_b)
+ if( p[pixel[12]] < c_b)
+ if( p[pixel[13]] < c_b)
+ if( p[pixel[14]] < c_b)
+ if( p[pixel[15]] < c_b)
+ goto is_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ if( p[pixel[9]] > cb)
+ if( p[pixel[5]] > cb)
+ if( p[pixel[6]] > cb)
+ if( p[pixel[7]] > cb)
+ if( p[pixel[8]] > cb)
+ if( p[pixel[10]] > cb)
+ if( p[pixel[11]] > cb)
+ if( p[pixel[12]] > cb)
+ if( p[pixel[13]] > cb)
+ if( p[pixel[14]] > cb)
+ if( p[pixel[15]] > cb)
+ goto is_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else if( p[pixel[9]] < c_b)
+ if( p[pixel[10]] < c_b)
+ if( p[pixel[11]] < c_b)
+ if( p[pixel[12]] < c_b)
+ if( p[pixel[13]] < c_b)
+ if( p[pixel[14]] < c_b)
+ if( p[pixel[15]] < c_b)
+ goto is_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ if( p[pixel[8]] > cb)
+ if( p[pixel[5]] > cb)
+ if( p[pixel[6]] > cb)
+ if( p[pixel[7]] > cb)
+ if( p[pixel[9]] > cb)
+ if( p[pixel[10]] > cb)
+ if( p[pixel[11]] > cb)
+ if( p[pixel[12]] > cb)
+ if( p[pixel[13]] > cb)
+ if( p[pixel[14]] > cb)
+ if( p[pixel[4]] > cb)
+ goto is_a_corner;
+ else
+ if( p[pixel[15]] > cb)
+ goto is_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else if( p[pixel[8]] < c_b)
+ if( p[pixel[9]] < c_b)
+ if( p[pixel[10]] < c_b)
+ if( p[pixel[11]] < c_b)
+ if( p[pixel[12]] < c_b)
+ if( p[pixel[13]] < c_b)
+ if( p[pixel[14]] < c_b)
+ if( p[pixel[15]] < c_b)
+ goto is_a_corner;
+ else
+ if( p[pixel[4]] < c_b)
+ if( p[pixel[5]] < c_b)
+ if( p[pixel[6]] < c_b)
+ if( p[pixel[7]] < c_b)
+ goto is_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ if( p[pixel[7]] > cb)
+ if( p[pixel[5]] > cb)
+ if( p[pixel[6]] > cb)
+ if( p[pixel[8]] > cb)
+ if( p[pixel[9]] > cb)
+ if( p[pixel[10]] > cb)
+ if( p[pixel[11]] > cb)
+ if( p[pixel[12]] > cb)
+ if( p[pixel[13]] > cb)
+ if( p[pixel[4]] > cb)
+ if( p[pixel[3]] > cb)
+ goto is_a_corner;
+ else
+ if( p[pixel[14]] > cb)
+ goto is_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ if( p[pixel[14]] > cb)
+ if( p[pixel[15]] > cb)
+ goto is_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else if( p[pixel[7]] < c_b)
+ if( p[pixel[8]] < c_b)
+ if( p[pixel[9]] < c_b)
+ if( p[pixel[10]] < c_b)
+ if( p[pixel[11]] < c_b)
+ if( p[pixel[12]] < c_b)
+ if( p[pixel[13]] < c_b)
+ if( p[pixel[14]] < c_b)
+ if( p[pixel[15]] < c_b)
+ goto is_a_corner;
+ else
+ if( p[pixel[4]] < c_b)
+ if( p[pixel[5]] < c_b)
+ if( p[pixel[6]] < c_b)
+ goto is_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ if( p[pixel[3]] < c_b)
+ if( p[pixel[4]] < c_b)
+ if( p[pixel[5]] < c_b)
+ if( p[pixel[6]] < c_b)
+ goto is_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ if( p[pixel[6]] > cb)
+ if( p[pixel[5]] > cb)
+ if( p[pixel[7]] > cb)
+ if( p[pixel[8]] > cb)
+ if( p[pixel[9]] > cb)
+ if( p[pixel[10]] > cb)
+ if( p[pixel[11]] > cb)
+ if( p[pixel[12]] > cb)
+ if( p[pixel[4]] > cb)
+ if( p[pixel[3]] > cb)
+ if( p[pixel[2]] > cb)
+ goto is_a_corner;
+ else
+ if( p[pixel[13]] > cb)
+ goto is_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ if( p[pixel[13]] > cb)
+ if( p[pixel[14]] > cb)
+ goto is_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ if( p[pixel[13]] > cb)
+ if( p[pixel[14]] > cb)
+ if( p[pixel[15]] > cb)
+ goto is_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else if( p[pixel[6]] < c_b)
+ if( p[pixel[7]] < c_b)
+ if( p[pixel[8]] < c_b)
+ if( p[pixel[9]] < c_b)
+ if( p[pixel[10]] < c_b)
+ if( p[pixel[11]] < c_b)
+ if( p[pixel[12]] < c_b)
+ if( p[pixel[13]] < c_b)
+ if( p[pixel[14]] < c_b)
+ if( p[pixel[15]] < c_b)
+ goto is_a_corner;
+ else
+ if( p[pixel[4]] < c_b)
+ if( p[pixel[5]] < c_b)
+ goto is_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ if( p[pixel[3]] < c_b)
+ if( p[pixel[4]] < c_b)
+ if( p[pixel[5]] < c_b)
+ goto is_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ if( p[pixel[2]] < c_b)
+ if( p[pixel[3]] < c_b)
+ if( p[pixel[4]] < c_b)
+ if( p[pixel[5]] < c_b)
+ goto is_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ if( p[pixel[5]] > cb)
+ if( p[pixel[6]] > cb)
+ if( p[pixel[7]] > cb)
+ if( p[pixel[8]] > cb)
+ if( p[pixel[9]] > cb)
+ if( p[pixel[10]] > cb)
+ if( p[pixel[11]] > cb)
+ if( p[pixel[4]] > cb)
+ if( p[pixel[3]] > cb)
+ if( p[pixel[2]] > cb)
+ if( p[pixel[1]] > cb)
+ goto is_a_corner;
+ else
+ if( p[pixel[12]] > cb)
+ goto is_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ if( p[pixel[12]] > cb)
+ if( p[pixel[13]] > cb)
+ goto is_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ if( p[pixel[12]] > cb)
+ if( p[pixel[13]] > cb)
+ if( p[pixel[14]] > cb)
+ goto is_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ if( p[pixel[12]] > cb)
+ if( p[pixel[13]] > cb)
+ if( p[pixel[14]] > cb)
+ if( p[pixel[15]] > cb)
+ goto is_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else if( p[pixel[5]] < c_b)
+ if( p[pixel[6]] < c_b)
+ if( p[pixel[7]] < c_b)
+ if( p[pixel[8]] < c_b)
+ if( p[pixel[9]] < c_b)
+ if( p[pixel[10]] < c_b)
+ if( p[pixel[11]] < c_b)
+ if( p[pixel[4]] < c_b)
+ if( p[pixel[3]] < c_b)
+ if( p[pixel[2]] < c_b)
+ if( p[pixel[1]] < c_b)
+ goto is_a_corner;
+ else
+ if( p[pixel[12]] < c_b)
+ goto is_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ if( p[pixel[12]] < c_b)
+ if( p[pixel[13]] < c_b)
+ goto is_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ if( p[pixel[12]] < c_b)
+ if( p[pixel[13]] < c_b)
+ if( p[pixel[14]] < c_b)
+ goto is_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ if( p[pixel[12]] < c_b)
+ if( p[pixel[13]] < c_b)
+ if( p[pixel[14]] < c_b)
+ if( p[pixel[15]] < c_b)
+ goto is_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+
+ is_a_corner:
+ bmin=b;
+ goto end_if;
+
+ is_not_a_corner:
+ bmax=b;
+ goto end_if;
+
+ end_if:
+
+ if(bmin == bmax - 1 || bmin == bmax)
+ return bmin;
+ b = (bmin + bmax) / 2;
+ }
+}
+
+static void make_offsets(int pixel[], int row_stride)
+{
+ pixel[0] = 0 + row_stride * 3;
+ pixel[1] = 1 + row_stride * 3;
+ pixel[2] = 2 + row_stride * 2;
+ pixel[3] = 3 + row_stride * 1;
+ pixel[4] = 3 + row_stride * 0;
+ pixel[5] = 3 + row_stride * -1;
+ pixel[6] = 2 + row_stride * -2;
+ pixel[7] = 1 + row_stride * -3;
+ pixel[8] = 0 + row_stride * -3;
+ pixel[9] = -1 + row_stride * -3;
+ pixel[10] = -2 + row_stride * -2;
+ pixel[11] = -3 + row_stride * -1;
+ pixel[12] = -3 + row_stride * 0;
+ pixel[13] = -3 + row_stride * 1;
+ pixel[14] = -2 + row_stride * 2;
+ pixel[15] = -1 + row_stride * 3;
+}
+
+
+
+int* fast11_score(const byte* i, int stride, xy* corners, int num_corners, int b)
+{
+ int* scores = (int*)malloc(sizeof(int)* num_corners);
+ int n;
+
+ int pixel[16];
+ make_offsets(pixel, stride);
+
+ for(n=0; n < num_corners; n++)
+ scores[n] = fast11_corner_score(i + corners[n].y*stride + corners[n].x, pixel, b);
+
+ return scores;
+}
+
+
+xy* fast11_detect(const byte* im, int xsize, int ysize, int stride, int b, int* ret_num_corners)
+{
+ int num_corners=0;
+ xy* ret_corners;
+ int rsize=512;
+ int pixel[16];
+ int x, y;
+
+ ret_corners = (xy*)malloc(sizeof(xy)*rsize);
+ make_offsets(pixel, stride);
+
+ for(y=3; y < ysize - 3; y++)
+ for(x=3; x < xsize - 3; x++)
+ {
+ const byte* p = im + y*stride + x;
+
+ int cb = *p + b;
+ int c_b= *p - b;
+ if(p[pixel[0]] > cb)
+ if(p[pixel[1]] > cb)
+ if(p[pixel[2]] > cb)
+ if(p[pixel[3]] > cb)
+ if(p[pixel[4]] > cb)
+ if(p[pixel[5]] > cb)
+ if(p[pixel[6]] > cb)
+ if(p[pixel[7]] > cb)
+ if(p[pixel[8]] > cb)
+ if(p[pixel[9]] > cb)
+ if(p[pixel[10]] > cb)
+ {}
+ else
+ if(p[pixel[15]] > cb)
+ {}
+ else
+ continue;
+ else
+ if(p[pixel[14]] > cb)
+ if(p[pixel[15]] > cb)
+ {}
+ else
+ continue;
+ else
+ continue;
+ else
+ if(p[pixel[13]] > cb)
+ if(p[pixel[14]] > cb)
+ if(p[pixel[15]] > cb)
+ {}
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ if(p[pixel[12]] > cb)
+ if(p[pixel[13]] > cb)
+ if(p[pixel[14]] > cb)
+ if(p[pixel[15]] > cb)
+ {}
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ if(p[pixel[11]] > cb)
+ if(p[pixel[12]] > cb)
+ if(p[pixel[13]] > cb)
+ if(p[pixel[14]] > cb)
+ if(p[pixel[15]] > cb)
+ {}
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else if(p[pixel[5]] < c_b)
+ if(p[pixel[10]] > cb)
+ if(p[pixel[11]] > cb)
+ if(p[pixel[12]] > cb)
+ if(p[pixel[13]] > cb)
+ if(p[pixel[14]] > cb)
+ if(p[pixel[15]] > cb)
+ {}
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else if(p[pixel[10]] < c_b)
+ if(p[pixel[6]] < c_b)
+ if(p[pixel[7]] < c_b)
+ if(p[pixel[8]] < c_b)
+ if(p[pixel[9]] < c_b)
+ if(p[pixel[11]] < c_b)
+ if(p[pixel[12]] < c_b)
+ if(p[pixel[13]] < c_b)
+ if(p[pixel[14]] < c_b)
+ if(p[pixel[15]] < c_b)
+ {}
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ if(p[pixel[10]] > cb)
+ if(p[pixel[11]] > cb)
+ if(p[pixel[12]] > cb)
+ if(p[pixel[13]] > cb)
+ if(p[pixel[14]] > cb)
+ if(p[pixel[15]] > cb)
+ {}
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else if(p[pixel[4]] < c_b)
+ if(p[pixel[15]] > cb)
+ if(p[pixel[9]] > cb)
+ if(p[pixel[10]] > cb)
+ if(p[pixel[11]] > cb)
+ if(p[pixel[12]] > cb)
+ if(p[pixel[13]] > cb)
+ if(p[pixel[14]] > cb)
+ {}
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else if(p[pixel[9]] < c_b)
+ if(p[pixel[5]] < c_b)
+ if(p[pixel[6]] < c_b)
+ if(p[pixel[7]] < c_b)
+ if(p[pixel[8]] < c_b)
+ if(p[pixel[10]] < c_b)
+ if(p[pixel[11]] < c_b)
+ if(p[pixel[12]] < c_b)
+ if(p[pixel[13]] < c_b)
+ if(p[pixel[14]] < c_b)
+ {}
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ if(p[pixel[5]] < c_b)
+ if(p[pixel[6]] < c_b)
+ if(p[pixel[7]] < c_b)
+ if(p[pixel[8]] < c_b)
+ if(p[pixel[9]] < c_b)
+ if(p[pixel[10]] < c_b)
+ if(p[pixel[11]] < c_b)
+ if(p[pixel[12]] < c_b)
+ if(p[pixel[13]] < c_b)
+ if(p[pixel[14]] < c_b)
+ {}
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ if(p[pixel[9]] > cb)
+ if(p[pixel[10]] > cb)
+ if(p[pixel[11]] > cb)
+ if(p[pixel[12]] > cb)
+ if(p[pixel[13]] > cb)
+ if(p[pixel[14]] > cb)
+ if(p[pixel[15]] > cb)
+ {}
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else if(p[pixel[9]] < c_b)
+ if(p[pixel[5]] < c_b)
+ if(p[pixel[6]] < c_b)
+ if(p[pixel[7]] < c_b)
+ if(p[pixel[8]] < c_b)
+ if(p[pixel[10]] < c_b)
+ if(p[pixel[11]] < c_b)
+ if(p[pixel[12]] < c_b)
+ if(p[pixel[13]] < c_b)
+ if(p[pixel[14]] < c_b)
+ if(p[pixel[15]] < c_b)
+ {}
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else if(p[pixel[3]] < c_b)
+ if(p[pixel[14]] > cb)
+ if(p[pixel[8]] > cb)
+ if(p[pixel[9]] > cb)
+ if(p[pixel[10]] > cb)
+ if(p[pixel[11]] > cb)
+ if(p[pixel[12]] > cb)
+ if(p[pixel[13]] > cb)
+ if(p[pixel[15]] > cb)
+ {}
+ else
+ if(p[pixel[4]] > cb)
+ if(p[pixel[5]] > cb)
+ if(p[pixel[6]] > cb)
+ if(p[pixel[7]] > cb)
+ {}
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else if(p[pixel[8]] < c_b)
+ if(p[pixel[4]] < c_b)
+ if(p[pixel[5]] < c_b)
+ if(p[pixel[6]] < c_b)
+ if(p[pixel[7]] < c_b)
+ if(p[pixel[9]] < c_b)
+ if(p[pixel[10]] < c_b)
+ if(p[pixel[11]] < c_b)
+ if(p[pixel[12]] < c_b)
+ if(p[pixel[13]] < c_b)
+ {}
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else if(p[pixel[14]] < c_b)
+ if(p[pixel[5]] < c_b)
+ if(p[pixel[6]] < c_b)
+ if(p[pixel[7]] < c_b)
+ if(p[pixel[8]] < c_b)
+ if(p[pixel[9]] < c_b)
+ if(p[pixel[10]] < c_b)
+ if(p[pixel[11]] < c_b)
+ if(p[pixel[12]] < c_b)
+ if(p[pixel[13]] < c_b)
+ if(p[pixel[4]] < c_b)
+ {}
+ else
+ if(p[pixel[15]] < c_b)
+ {}
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ if(p[pixel[4]] < c_b)
+ if(p[pixel[5]] < c_b)
+ if(p[pixel[6]] < c_b)
+ if(p[pixel[7]] < c_b)
+ if(p[pixel[8]] < c_b)
+ if(p[pixel[9]] < c_b)
+ if(p[pixel[10]] < c_b)
+ if(p[pixel[11]] < c_b)
+ if(p[pixel[12]] < c_b)
+ if(p[pixel[13]] < c_b)
+ {}
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ if(p[pixel[8]] > cb)
+ if(p[pixel[9]] > cb)
+ if(p[pixel[10]] > cb)
+ if(p[pixel[11]] > cb)
+ if(p[pixel[12]] > cb)
+ if(p[pixel[13]] > cb)
+ if(p[pixel[14]] > cb)
+ if(p[pixel[15]] > cb)
+ {}
+ else
+ if(p[pixel[4]] > cb)
+ if(p[pixel[5]] > cb)
+ if(p[pixel[6]] > cb)
+ if(p[pixel[7]] > cb)
+ {}
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else if(p[pixel[8]] < c_b)
+ if(p[pixel[5]] < c_b)
+ if(p[pixel[6]] < c_b)
+ if(p[pixel[7]] < c_b)
+ if(p[pixel[9]] < c_b)
+ if(p[pixel[10]] < c_b)
+ if(p[pixel[11]] < c_b)
+ if(p[pixel[12]] < c_b)
+ if(p[pixel[13]] < c_b)
+ if(p[pixel[14]] < c_b)
+ if(p[pixel[4]] < c_b)
+ {}
+ else
+ if(p[pixel[15]] < c_b)
+ {}
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else if(p[pixel[2]] < c_b)
+ if(p[pixel[7]] > cb)
+ if(p[pixel[8]] > cb)
+ if(p[pixel[9]] > cb)
+ if(p[pixel[10]] > cb)
+ if(p[pixel[11]] > cb)
+ if(p[pixel[12]] > cb)
+ if(p[pixel[13]] > cb)
+ if(p[pixel[14]] > cb)
+ if(p[pixel[15]] > cb)
+ {}
+ else
+ if(p[pixel[4]] > cb)
+ if(p[pixel[5]] > cb)
+ if(p[pixel[6]] > cb)
+ {}
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ if(p[pixel[3]] > cb)
+ if(p[pixel[4]] > cb)
+ if(p[pixel[5]] > cb)
+ if(p[pixel[6]] > cb)
+ {}
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else if(p[pixel[7]] < c_b)
+ if(p[pixel[5]] < c_b)
+ if(p[pixel[6]] < c_b)
+ if(p[pixel[8]] < c_b)
+ if(p[pixel[9]] < c_b)
+ if(p[pixel[10]] < c_b)
+ if(p[pixel[11]] < c_b)
+ if(p[pixel[12]] < c_b)
+ if(p[pixel[4]] < c_b)
+ if(p[pixel[3]] < c_b)
+ {}
+ else
+ if(p[pixel[13]] < c_b)
+ if(p[pixel[14]] < c_b)
+ {}
+ else
+ continue;
+ else
+ continue;
+ else
+ if(p[pixel[13]] < c_b)
+ if(p[pixel[14]] < c_b)
+ if(p[pixel[15]] < c_b)
+ {}
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ if(p[pixel[7]] > cb)
+ if(p[pixel[8]] > cb)
+ if(p[pixel[9]] > cb)
+ if(p[pixel[10]] > cb)
+ if(p[pixel[11]] > cb)
+ if(p[pixel[12]] > cb)
+ if(p[pixel[13]] > cb)
+ if(p[pixel[14]] > cb)
+ if(p[pixel[15]] > cb)
+ {}
+ else
+ if(p[pixel[4]] > cb)
+ if(p[pixel[5]] > cb)
+ if(p[pixel[6]] > cb)
+ {}
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ if(p[pixel[3]] > cb)
+ if(p[pixel[4]] > cb)
+ if(p[pixel[5]] > cb)
+ if(p[pixel[6]] > cb)
+ {}
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else if(p[pixel[7]] < c_b)
+ if(p[pixel[5]] < c_b)
+ if(p[pixel[6]] < c_b)
+ if(p[pixel[8]] < c_b)
+ if(p[pixel[9]] < c_b)
+ if(p[pixel[10]] < c_b)
+ if(p[pixel[11]] < c_b)
+ if(p[pixel[12]] < c_b)
+ if(p[pixel[13]] < c_b)
+ if(p[pixel[4]] < c_b)
+ if(p[pixel[3]] < c_b)
+ {}
+ else
+ if(p[pixel[14]] < c_b)
+ {}
+ else
+ continue;
+ else
+ if(p[pixel[14]] < c_b)
+ if(p[pixel[15]] < c_b)
+ {}
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else if(p[pixel[1]] < c_b)
+ if(p[pixel[6]] > cb)
+ if(p[pixel[7]] > cb)
+ if(p[pixel[8]] > cb)
+ if(p[pixel[9]] > cb)
+ if(p[pixel[10]] > cb)
+ if(p[pixel[11]] > cb)
+ if(p[pixel[12]] > cb)
+ if(p[pixel[13]] > cb)
+ if(p[pixel[14]] > cb)
+ if(p[pixel[15]] > cb)
+ {}
+ else
+ if(p[pixel[4]] > cb)
+ if(p[pixel[5]] > cb)
+ {}
+ else
+ continue;
+ else
+ continue;
+ else
+ if(p[pixel[3]] > cb)
+ if(p[pixel[4]] > cb)
+ if(p[pixel[5]] > cb)
+ {}
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ if(p[pixel[2]] > cb)
+ if(p[pixel[3]] > cb)
+ if(p[pixel[4]] > cb)
+ if(p[pixel[5]] > cb)
+ {}
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else if(p[pixel[6]] < c_b)
+ if(p[pixel[5]] < c_b)
+ if(p[pixel[7]] < c_b)
+ if(p[pixel[8]] < c_b)
+ if(p[pixel[9]] < c_b)
+ if(p[pixel[10]] < c_b)
+ if(p[pixel[11]] < c_b)
+ if(p[pixel[4]] < c_b)
+ if(p[pixel[3]] < c_b)
+ if(p[pixel[2]] < c_b)
+ {}
+ else
+ if(p[pixel[12]] < c_b)
+ if(p[pixel[13]] < c_b)
+ {}
+ else
+ continue;
+ else
+ continue;
+ else
+ if(p[pixel[12]] < c_b)
+ if(p[pixel[13]] < c_b)
+ if(p[pixel[14]] < c_b)
+ {}
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ if(p[pixel[12]] < c_b)
+ if(p[pixel[13]] < c_b)
+ if(p[pixel[14]] < c_b)
+ if(p[pixel[15]] < c_b)
+ {}
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ if(p[pixel[6]] > cb)
+ if(p[pixel[7]] > cb)
+ if(p[pixel[8]] > cb)
+ if(p[pixel[9]] > cb)
+ if(p[pixel[10]] > cb)
+ if(p[pixel[11]] > cb)
+ if(p[pixel[12]] > cb)
+ if(p[pixel[13]] > cb)
+ if(p[pixel[14]] > cb)
+ if(p[pixel[15]] > cb)
+ {}
+ else
+ if(p[pixel[4]] > cb)
+ if(p[pixel[5]] > cb)
+ {}
+ else
+ continue;
+ else
+ continue;
+ else
+ if(p[pixel[3]] > cb)
+ if(p[pixel[4]] > cb)
+ if(p[pixel[5]] > cb)
+ {}
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ if(p[pixel[2]] > cb)
+ if(p[pixel[3]] > cb)
+ if(p[pixel[4]] > cb)
+ if(p[pixel[5]] > cb)
+ {}
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else if(p[pixel[6]] < c_b)
+ if(p[pixel[5]] < c_b)
+ if(p[pixel[7]] < c_b)
+ if(p[pixel[8]] < c_b)
+ if(p[pixel[9]] < c_b)
+ if(p[pixel[10]] < c_b)
+ if(p[pixel[11]] < c_b)
+ if(p[pixel[12]] < c_b)
+ if(p[pixel[4]] < c_b)
+ if(p[pixel[3]] < c_b)
+ if(p[pixel[2]] < c_b)
+ {}
+ else
+ if(p[pixel[13]] < c_b)
+ {}
+ else
+ continue;
+ else
+ if(p[pixel[13]] < c_b)
+ if(p[pixel[14]] < c_b)
+ {}
+ else
+ continue;
+ else
+ continue;
+ else
+ if(p[pixel[13]] < c_b)
+ if(p[pixel[14]] < c_b)
+ if(p[pixel[15]] < c_b)
+ {}
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else if(p[pixel[0]] < c_b)
+ if(p[pixel[1]] > cb)
+ if(p[pixel[6]] > cb)
+ if(p[pixel[5]] > cb)
+ if(p[pixel[7]] > cb)
+ if(p[pixel[8]] > cb)
+ if(p[pixel[9]] > cb)
+ if(p[pixel[10]] > cb)
+ if(p[pixel[11]] > cb)
+ if(p[pixel[4]] > cb)
+ if(p[pixel[3]] > cb)
+ if(p[pixel[2]] > cb)
+ {}
+ else
+ if(p[pixel[12]] > cb)
+ if(p[pixel[13]] > cb)
+ {}
+ else
+ continue;
+ else
+ continue;
+ else
+ if(p[pixel[12]] > cb)
+ if(p[pixel[13]] > cb)
+ if(p[pixel[14]] > cb)
+ {}
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ if(p[pixel[12]] > cb)
+ if(p[pixel[13]] > cb)
+ if(p[pixel[14]] > cb)
+ if(p[pixel[15]] > cb)
+ {}
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else if(p[pixel[6]] < c_b)
+ if(p[pixel[7]] < c_b)
+ if(p[pixel[8]] < c_b)
+ if(p[pixel[9]] < c_b)
+ if(p[pixel[10]] < c_b)
+ if(p[pixel[11]] < c_b)
+ if(p[pixel[12]] < c_b)
+ if(p[pixel[13]] < c_b)
+ if(p[pixel[14]] < c_b)
+ if(p[pixel[15]] < c_b)
+ {}
+ else
+ if(p[pixel[4]] < c_b)
+ if(p[pixel[5]] < c_b)
+ {}
+ else
+ continue;
+ else
+ continue;
+ else
+ if(p[pixel[3]] < c_b)
+ if(p[pixel[4]] < c_b)
+ if(p[pixel[5]] < c_b)
+ {}
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ if(p[pixel[2]] < c_b)
+ if(p[pixel[3]] < c_b)
+ if(p[pixel[4]] < c_b)
+ if(p[pixel[5]] < c_b)
+ {}
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else if(p[pixel[1]] < c_b)
+ if(p[pixel[2]] > cb)
+ if(p[pixel[7]] > cb)
+ if(p[pixel[5]] > cb)
+ if(p[pixel[6]] > cb)
+ if(p[pixel[8]] > cb)
+ if(p[pixel[9]] > cb)
+ if(p[pixel[10]] > cb)
+ if(p[pixel[11]] > cb)
+ if(p[pixel[12]] > cb)
+ if(p[pixel[4]] > cb)
+ if(p[pixel[3]] > cb)
+ {}
+ else
+ if(p[pixel[13]] > cb)
+ if(p[pixel[14]] > cb)
+ {}
+ else
+ continue;
+ else
+ continue;
+ else
+ if(p[pixel[13]] > cb)
+ if(p[pixel[14]] > cb)
+ if(p[pixel[15]] > cb)
+ {}
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else if(p[pixel[7]] < c_b)
+ if(p[pixel[8]] < c_b)
+ if(p[pixel[9]] < c_b)
+ if(p[pixel[10]] < c_b)
+ if(p[pixel[11]] < c_b)
+ if(p[pixel[12]] < c_b)
+ if(p[pixel[13]] < c_b)
+ if(p[pixel[14]] < c_b)
+ if(p[pixel[15]] < c_b)
+ {}
+ else
+ if(p[pixel[4]] < c_b)
+ if(p[pixel[5]] < c_b)
+ if(p[pixel[6]] < c_b)
+ {}
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ if(p[pixel[3]] < c_b)
+ if(p[pixel[4]] < c_b)
+ if(p[pixel[5]] < c_b)
+ if(p[pixel[6]] < c_b)
+ {}
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else if(p[pixel[2]] < c_b)
+ if(p[pixel[3]] > cb)
+ if(p[pixel[14]] > cb)
+ if(p[pixel[5]] > cb)
+ if(p[pixel[6]] > cb)
+ if(p[pixel[7]] > cb)
+ if(p[pixel[8]] > cb)
+ if(p[pixel[9]] > cb)
+ if(p[pixel[10]] > cb)
+ if(p[pixel[11]] > cb)
+ if(p[pixel[12]] > cb)
+ if(p[pixel[13]] > cb)
+ if(p[pixel[4]] > cb)
+ {}
+ else
+ if(p[pixel[15]] > cb)
+ {}
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else if(p[pixel[14]] < c_b)
+ if(p[pixel[8]] > cb)
+ if(p[pixel[4]] > cb)
+ if(p[pixel[5]] > cb)
+ if(p[pixel[6]] > cb)
+ if(p[pixel[7]] > cb)
+ if(p[pixel[9]] > cb)
+ if(p[pixel[10]] > cb)
+ if(p[pixel[11]] > cb)
+ if(p[pixel[12]] > cb)
+ if(p[pixel[13]] > cb)
+ {}
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else if(p[pixel[8]] < c_b)
+ if(p[pixel[9]] < c_b)
+ if(p[pixel[10]] < c_b)
+ if(p[pixel[11]] < c_b)
+ if(p[pixel[12]] < c_b)
+ if(p[pixel[13]] < c_b)
+ if(p[pixel[15]] < c_b)
+ {}
+ else
+ if(p[pixel[4]] < c_b)
+ if(p[pixel[5]] < c_b)
+ if(p[pixel[6]] < c_b)
+ if(p[pixel[7]] < c_b)
+ {}
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ if(p[pixel[4]] > cb)
+ if(p[pixel[5]] > cb)
+ if(p[pixel[6]] > cb)
+ if(p[pixel[7]] > cb)
+ if(p[pixel[8]] > cb)
+ if(p[pixel[9]] > cb)
+ if(p[pixel[10]] > cb)
+ if(p[pixel[11]] > cb)
+ if(p[pixel[12]] > cb)
+ if(p[pixel[13]] > cb)
+ {}
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else if(p[pixel[3]] < c_b)
+ if(p[pixel[4]] > cb)
+ if(p[pixel[15]] < c_b)
+ if(p[pixel[9]] > cb)
+ if(p[pixel[5]] > cb)
+ if(p[pixel[6]] > cb)
+ if(p[pixel[7]] > cb)
+ if(p[pixel[8]] > cb)
+ if(p[pixel[10]] > cb)
+ if(p[pixel[11]] > cb)
+ if(p[pixel[12]] > cb)
+ if(p[pixel[13]] > cb)
+ if(p[pixel[14]] > cb)
+ {}
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else if(p[pixel[9]] < c_b)
+ if(p[pixel[10]] < c_b)
+ if(p[pixel[11]] < c_b)
+ if(p[pixel[12]] < c_b)
+ if(p[pixel[13]] < c_b)
+ if(p[pixel[14]] < c_b)
+ {}
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ if(p[pixel[5]] > cb)
+ if(p[pixel[6]] > cb)
+ if(p[pixel[7]] > cb)
+ if(p[pixel[8]] > cb)
+ if(p[pixel[9]] > cb)
+ if(p[pixel[10]] > cb)
+ if(p[pixel[11]] > cb)
+ if(p[pixel[12]] > cb)
+ if(p[pixel[13]] > cb)
+ if(p[pixel[14]] > cb)
+ {}
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else if(p[pixel[4]] < c_b)
+ if(p[pixel[5]] > cb)
+ if(p[pixel[10]] > cb)
+ if(p[pixel[6]] > cb)
+ if(p[pixel[7]] > cb)
+ if(p[pixel[8]] > cb)
+ if(p[pixel[9]] > cb)
+ if(p[pixel[11]] > cb)
+ if(p[pixel[12]] > cb)
+ if(p[pixel[13]] > cb)
+ if(p[pixel[14]] > cb)
+ if(p[pixel[15]] > cb)
+ {}
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else if(p[pixel[10]] < c_b)
+ if(p[pixel[11]] < c_b)
+ if(p[pixel[12]] < c_b)
+ if(p[pixel[13]] < c_b)
+ if(p[pixel[14]] < c_b)
+ if(p[pixel[15]] < c_b)
+ {}
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else if(p[pixel[5]] < c_b)
+ if(p[pixel[6]] < c_b)
+ if(p[pixel[7]] < c_b)
+ if(p[pixel[8]] < c_b)
+ if(p[pixel[9]] < c_b)
+ if(p[pixel[10]] < c_b)
+ {}
+ else
+ if(p[pixel[15]] < c_b)
+ {}
+ else
+ continue;
+ else
+ if(p[pixel[14]] < c_b)
+ if(p[pixel[15]] < c_b)
+ {}
+ else
+ continue;
+ else
+ continue;
+ else
+ if(p[pixel[13]] < c_b)
+ if(p[pixel[14]] < c_b)
+ if(p[pixel[15]] < c_b)
+ {}
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ if(p[pixel[12]] < c_b)
+ if(p[pixel[13]] < c_b)
+ if(p[pixel[14]] < c_b)
+ if(p[pixel[15]] < c_b)
+ {}
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ if(p[pixel[11]] < c_b)
+ if(p[pixel[12]] < c_b)
+ if(p[pixel[13]] < c_b)
+ if(p[pixel[14]] < c_b)
+ if(p[pixel[15]] < c_b)
+ {}
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ if(p[pixel[10]] < c_b)
+ if(p[pixel[11]] < c_b)
+ if(p[pixel[12]] < c_b)
+ if(p[pixel[13]] < c_b)
+ if(p[pixel[14]] < c_b)
+ if(p[pixel[15]] < c_b)
+ {}
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ if(p[pixel[9]] > cb)
+ if(p[pixel[5]] > cb)
+ if(p[pixel[6]] > cb)
+ if(p[pixel[7]] > cb)
+ if(p[pixel[8]] > cb)
+ if(p[pixel[10]] > cb)
+ if(p[pixel[11]] > cb)
+ if(p[pixel[12]] > cb)
+ if(p[pixel[13]] > cb)
+ if(p[pixel[14]] > cb)
+ if(p[pixel[15]] > cb)
+ {}
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else if(p[pixel[9]] < c_b)
+ if(p[pixel[10]] < c_b)
+ if(p[pixel[11]] < c_b)
+ if(p[pixel[12]] < c_b)
+ if(p[pixel[13]] < c_b)
+ if(p[pixel[14]] < c_b)
+ if(p[pixel[15]] < c_b)
+ {}
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ if(p[pixel[8]] > cb)
+ if(p[pixel[5]] > cb)
+ if(p[pixel[6]] > cb)
+ if(p[pixel[7]] > cb)
+ if(p[pixel[9]] > cb)
+ if(p[pixel[10]] > cb)
+ if(p[pixel[11]] > cb)
+ if(p[pixel[12]] > cb)
+ if(p[pixel[13]] > cb)
+ if(p[pixel[14]] > cb)
+ if(p[pixel[4]] > cb)
+ {}
+ else
+ if(p[pixel[15]] > cb)
+ {}
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else if(p[pixel[8]] < c_b)
+ if(p[pixel[9]] < c_b)
+ if(p[pixel[10]] < c_b)
+ if(p[pixel[11]] < c_b)
+ if(p[pixel[12]] < c_b)
+ if(p[pixel[13]] < c_b)
+ if(p[pixel[14]] < c_b)
+ if(p[pixel[15]] < c_b)
+ {}
+ else
+ if(p[pixel[4]] < c_b)
+ if(p[pixel[5]] < c_b)
+ if(p[pixel[6]] < c_b)
+ if(p[pixel[7]] < c_b)
+ {}
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ if(p[pixel[7]] > cb)
+ if(p[pixel[5]] > cb)
+ if(p[pixel[6]] > cb)
+ if(p[pixel[8]] > cb)
+ if(p[pixel[9]] > cb)
+ if(p[pixel[10]] > cb)
+ if(p[pixel[11]] > cb)
+ if(p[pixel[12]] > cb)
+ if(p[pixel[13]] > cb)
+ if(p[pixel[4]] > cb)
+ if(p[pixel[3]] > cb)
+ {}
+ else
+ if(p[pixel[14]] > cb)
+ {}
+ else
+ continue;
+ else
+ if(p[pixel[14]] > cb)
+ if(p[pixel[15]] > cb)
+ {}
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else if(p[pixel[7]] < c_b)
+ if(p[pixel[8]] < c_b)
+ if(p[pixel[9]] < c_b)
+ if(p[pixel[10]] < c_b)
+ if(p[pixel[11]] < c_b)
+ if(p[pixel[12]] < c_b)
+ if(p[pixel[13]] < c_b)
+ if(p[pixel[14]] < c_b)
+ if(p[pixel[15]] < c_b)
+ {}
+ else
+ if(p[pixel[4]] < c_b)
+ if(p[pixel[5]] < c_b)
+ if(p[pixel[6]] < c_b)
+ {}
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ if(p[pixel[3]] < c_b)
+ if(p[pixel[4]] < c_b)
+ if(p[pixel[5]] < c_b)
+ if(p[pixel[6]] < c_b)
+ {}
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ if(p[pixel[6]] > cb)
+ if(p[pixel[5]] > cb)
+ if(p[pixel[7]] > cb)
+ if(p[pixel[8]] > cb)
+ if(p[pixel[9]] > cb)
+ if(p[pixel[10]] > cb)
+ if(p[pixel[11]] > cb)
+ if(p[pixel[12]] > cb)
+ if(p[pixel[4]] > cb)
+ if(p[pixel[3]] > cb)
+ if(p[pixel[2]] > cb)
+ {}
+ else
+ if(p[pixel[13]] > cb)
+ {}
+ else
+ continue;
+ else
+ if(p[pixel[13]] > cb)
+ if(p[pixel[14]] > cb)
+ {}
+ else
+ continue;
+ else
+ continue;
+ else
+ if(p[pixel[13]] > cb)
+ if(p[pixel[14]] > cb)
+ if(p[pixel[15]] > cb)
+ {}
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else if(p[pixel[6]] < c_b)
+ if(p[pixel[7]] < c_b)
+ if(p[pixel[8]] < c_b)
+ if(p[pixel[9]] < c_b)
+ if(p[pixel[10]] < c_b)
+ if(p[pixel[11]] < c_b)
+ if(p[pixel[12]] < c_b)
+ if(p[pixel[13]] < c_b)
+ if(p[pixel[14]] < c_b)
+ if(p[pixel[15]] < c_b)
+ {}
+ else
+ if(p[pixel[4]] < c_b)
+ if(p[pixel[5]] < c_b)
+ {}
+ else
+ continue;
+ else
+ continue;
+ else
+ if(p[pixel[3]] < c_b)
+ if(p[pixel[4]] < c_b)
+ if(p[pixel[5]] < c_b)
+ {}
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ if(p[pixel[2]] < c_b)
+ if(p[pixel[3]] < c_b)
+ if(p[pixel[4]] < c_b)
+ if(p[pixel[5]] < c_b)
+ {}
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ if(p[pixel[5]] > cb)
+ if(p[pixel[6]] > cb)
+ if(p[pixel[7]] > cb)
+ if(p[pixel[8]] > cb)
+ if(p[pixel[9]] > cb)
+ if(p[pixel[10]] > cb)
+ if(p[pixel[11]] > cb)
+ if(p[pixel[4]] > cb)
+ if(p[pixel[3]] > cb)
+ if(p[pixel[2]] > cb)
+ if(p[pixel[1]] > cb)
+ {}
+ else
+ if(p[pixel[12]] > cb)
+ {}
+ else
+ continue;
+ else
+ if(p[pixel[12]] > cb)
+ if(p[pixel[13]] > cb)
+ {}
+ else
+ continue;
+ else
+ continue;
+ else
+ if(p[pixel[12]] > cb)
+ if(p[pixel[13]] > cb)
+ if(p[pixel[14]] > cb)
+ {}
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ if(p[pixel[12]] > cb)
+ if(p[pixel[13]] > cb)
+ if(p[pixel[14]] > cb)
+ if(p[pixel[15]] > cb)
+ {}
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else if(p[pixel[5]] < c_b)
+ if(p[pixel[6]] < c_b)
+ if(p[pixel[7]] < c_b)
+ if(p[pixel[8]] < c_b)
+ if(p[pixel[9]] < c_b)
+ if(p[pixel[10]] < c_b)
+ if(p[pixel[11]] < c_b)
+ if(p[pixel[4]] < c_b)
+ if(p[pixel[3]] < c_b)
+ if(p[pixel[2]] < c_b)
+ if(p[pixel[1]] < c_b)
+ {}
+ else
+ if(p[pixel[12]] < c_b)
+ {}
+ else
+ continue;
+ else
+ if(p[pixel[12]] < c_b)
+ if(p[pixel[13]] < c_b)
+ {}
+ else
+ continue;
+ else
+ continue;
+ else
+ if(p[pixel[12]] < c_b)
+ if(p[pixel[13]] < c_b)
+ if(p[pixel[14]] < c_b)
+ {}
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ if(p[pixel[12]] < c_b)
+ if(p[pixel[13]] < c_b)
+ if(p[pixel[14]] < c_b)
+ if(p[pixel[15]] < c_b)
+ {}
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ if(num_corners == rsize)
+ {
+ rsize*=2;
+ ret_corners = (xy*)realloc(ret_corners, sizeof(xy)*rsize);
+ }
+
+ ret_corners[num_corners].x = x;
+ ret_corners[num_corners].y = y;
+ num_corners++;
+ }
+
+ *ret_num_corners = num_corners;
+ return ret_corners;
+
+}
+
+
diff --git a/extern/libmv/third_party/fast/fast_12.c b/extern/libmv/third_party/fast/fast_12.c
new file mode 100644
index 00000000000..f73f68dd043
--- /dev/null
+++ b/extern/libmv/third_party/fast/fast_12.c
@@ -0,0 +1,3134 @@
+/*This is mechanically generated code*/
+#include <stdlib.h>
+
+typedef struct { int x, y; } xy;
+typedef unsigned char byte;
+
+int fast12_corner_score(const byte* p, const int pixel[], int bstart)
+{
+ int bmin = bstart;
+ int bmax = 255;
+ int b = (bmax + bmin)/2;
+
+ /*Compute the score using binary search*/
+ for(;;)
+ {
+ int cb = *p + b;
+ int c_b= *p - b;
+
+
+ if( p[pixel[0]] > cb)
+ if( p[pixel[1]] > cb)
+ if( p[pixel[2]] > cb)
+ if( p[pixel[3]] > cb)
+ if( p[pixel[4]] > cb)
+ if( p[pixel[5]] > cb)
+ if( p[pixel[6]] > cb)
+ if( p[pixel[7]] > cb)
+ if( p[pixel[8]] > cb)
+ if( p[pixel[9]] > cb)
+ if( p[pixel[10]] > cb)
+ if( p[pixel[11]] > cb)
+ goto is_a_corner;
+ else
+ if( p[pixel[15]] > cb)
+ goto is_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ if( p[pixel[14]] > cb)
+ if( p[pixel[15]] > cb)
+ goto is_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ if( p[pixel[13]] > cb)
+ if( p[pixel[14]] > cb)
+ if( p[pixel[15]] > cb)
+ goto is_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ if( p[pixel[12]] > cb)
+ if( p[pixel[13]] > cb)
+ if( p[pixel[14]] > cb)
+ if( p[pixel[15]] > cb)
+ goto is_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ if( p[pixel[11]] > cb)
+ if( p[pixel[12]] > cb)
+ if( p[pixel[13]] > cb)
+ if( p[pixel[14]] > cb)
+ if( p[pixel[15]] > cb)
+ goto is_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ if( p[pixel[10]] > cb)
+ if( p[pixel[11]] > cb)
+ if( p[pixel[12]] > cb)
+ if( p[pixel[13]] > cb)
+ if( p[pixel[14]] > cb)
+ if( p[pixel[15]] > cb)
+ goto is_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ if( p[pixel[9]] > cb)
+ if( p[pixel[10]] > cb)
+ if( p[pixel[11]] > cb)
+ if( p[pixel[12]] > cb)
+ if( p[pixel[13]] > cb)
+ if( p[pixel[14]] > cb)
+ if( p[pixel[15]] > cb)
+ goto is_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else if( p[pixel[4]] < c_b)
+ if( p[pixel[8]] > cb)
+ if( p[pixel[9]] > cb)
+ if( p[pixel[10]] > cb)
+ if( p[pixel[11]] > cb)
+ if( p[pixel[12]] > cb)
+ if( p[pixel[13]] > cb)
+ if( p[pixel[14]] > cb)
+ if( p[pixel[15]] > cb)
+ goto is_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else if( p[pixel[8]] < c_b)
+ if( p[pixel[5]] < c_b)
+ if( p[pixel[6]] < c_b)
+ if( p[pixel[7]] < c_b)
+ if( p[pixel[9]] < c_b)
+ if( p[pixel[10]] < c_b)
+ if( p[pixel[11]] < c_b)
+ if( p[pixel[12]] < c_b)
+ if( p[pixel[13]] < c_b)
+ if( p[pixel[14]] < c_b)
+ if( p[pixel[15]] < c_b)
+ goto is_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ if( p[pixel[8]] > cb)
+ if( p[pixel[9]] > cb)
+ if( p[pixel[10]] > cb)
+ if( p[pixel[11]] > cb)
+ if( p[pixel[12]] > cb)
+ if( p[pixel[13]] > cb)
+ if( p[pixel[14]] > cb)
+ if( p[pixel[15]] > cb)
+ goto is_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else if( p[pixel[3]] < c_b)
+ if( p[pixel[15]] > cb)
+ if( p[pixel[7]] > cb)
+ if( p[pixel[8]] > cb)
+ if( p[pixel[9]] > cb)
+ if( p[pixel[10]] > cb)
+ if( p[pixel[11]] > cb)
+ if( p[pixel[12]] > cb)
+ if( p[pixel[13]] > cb)
+ if( p[pixel[14]] > cb)
+ goto is_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else if( p[pixel[7]] < c_b)
+ if( p[pixel[4]] < c_b)
+ if( p[pixel[5]] < c_b)
+ if( p[pixel[6]] < c_b)
+ if( p[pixel[8]] < c_b)
+ if( p[pixel[9]] < c_b)
+ if( p[pixel[10]] < c_b)
+ if( p[pixel[11]] < c_b)
+ if( p[pixel[12]] < c_b)
+ if( p[pixel[13]] < c_b)
+ if( p[pixel[14]] < c_b)
+ goto is_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ if( p[pixel[4]] < c_b)
+ if( p[pixel[5]] < c_b)
+ if( p[pixel[6]] < c_b)
+ if( p[pixel[7]] < c_b)
+ if( p[pixel[8]] < c_b)
+ if( p[pixel[9]] < c_b)
+ if( p[pixel[10]] < c_b)
+ if( p[pixel[11]] < c_b)
+ if( p[pixel[12]] < c_b)
+ if( p[pixel[13]] < c_b)
+ if( p[pixel[14]] < c_b)
+ goto is_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ if( p[pixel[7]] > cb)
+ if( p[pixel[8]] > cb)
+ if( p[pixel[9]] > cb)
+ if( p[pixel[10]] > cb)
+ if( p[pixel[11]] > cb)
+ if( p[pixel[12]] > cb)
+ if( p[pixel[13]] > cb)
+ if( p[pixel[14]] > cb)
+ if( p[pixel[15]] > cb)
+ goto is_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else if( p[pixel[7]] < c_b)
+ if( p[pixel[4]] < c_b)
+ if( p[pixel[5]] < c_b)
+ if( p[pixel[6]] < c_b)
+ if( p[pixel[8]] < c_b)
+ if( p[pixel[9]] < c_b)
+ if( p[pixel[10]] < c_b)
+ if( p[pixel[11]] < c_b)
+ if( p[pixel[12]] < c_b)
+ if( p[pixel[13]] < c_b)
+ if( p[pixel[14]] < c_b)
+ if( p[pixel[15]] < c_b)
+ goto is_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else if( p[pixel[2]] < c_b)
+ if( p[pixel[6]] > cb)
+ if( p[pixel[7]] > cb)
+ if( p[pixel[8]] > cb)
+ if( p[pixel[9]] > cb)
+ if( p[pixel[10]] > cb)
+ if( p[pixel[11]] > cb)
+ if( p[pixel[12]] > cb)
+ if( p[pixel[13]] > cb)
+ if( p[pixel[14]] > cb)
+ if( p[pixel[15]] > cb)
+ goto is_a_corner;
+ else
+ if( p[pixel[3]] > cb)
+ if( p[pixel[4]] > cb)
+ if( p[pixel[5]] > cb)
+ goto is_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else if( p[pixel[6]] < c_b)
+ if( p[pixel[4]] < c_b)
+ if( p[pixel[5]] < c_b)
+ if( p[pixel[7]] < c_b)
+ if( p[pixel[8]] < c_b)
+ if( p[pixel[9]] < c_b)
+ if( p[pixel[10]] < c_b)
+ if( p[pixel[11]] < c_b)
+ if( p[pixel[12]] < c_b)
+ if( p[pixel[13]] < c_b)
+ if( p[pixel[3]] < c_b)
+ goto is_a_corner;
+ else
+ if( p[pixel[14]] < c_b)
+ if( p[pixel[15]] < c_b)
+ goto is_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ if( p[pixel[6]] > cb)
+ if( p[pixel[7]] > cb)
+ if( p[pixel[8]] > cb)
+ if( p[pixel[9]] > cb)
+ if( p[pixel[10]] > cb)
+ if( p[pixel[11]] > cb)
+ if( p[pixel[12]] > cb)
+ if( p[pixel[13]] > cb)
+ if( p[pixel[14]] > cb)
+ if( p[pixel[15]] > cb)
+ goto is_a_corner;
+ else
+ if( p[pixel[3]] > cb)
+ if( p[pixel[4]] > cb)
+ if( p[pixel[5]] > cb)
+ goto is_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else if( p[pixel[6]] < c_b)
+ if( p[pixel[4]] < c_b)
+ if( p[pixel[5]] < c_b)
+ if( p[pixel[7]] < c_b)
+ if( p[pixel[8]] < c_b)
+ if( p[pixel[9]] < c_b)
+ if( p[pixel[10]] < c_b)
+ if( p[pixel[11]] < c_b)
+ if( p[pixel[12]] < c_b)
+ if( p[pixel[13]] < c_b)
+ if( p[pixel[14]] < c_b)
+ if( p[pixel[3]] < c_b)
+ goto is_a_corner;
+ else
+ if( p[pixel[15]] < c_b)
+ goto is_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else if( p[pixel[1]] < c_b)
+ if( p[pixel[5]] > cb)
+ if( p[pixel[6]] > cb)
+ if( p[pixel[7]] > cb)
+ if( p[pixel[8]] > cb)
+ if( p[pixel[9]] > cb)
+ if( p[pixel[10]] > cb)
+ if( p[pixel[11]] > cb)
+ if( p[pixel[12]] > cb)
+ if( p[pixel[13]] > cb)
+ if( p[pixel[14]] > cb)
+ if( p[pixel[15]] > cb)
+ goto is_a_corner;
+ else
+ if( p[pixel[3]] > cb)
+ if( p[pixel[4]] > cb)
+ goto is_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ if( p[pixel[2]] > cb)
+ if( p[pixel[3]] > cb)
+ if( p[pixel[4]] > cb)
+ goto is_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else if( p[pixel[5]] < c_b)
+ if( p[pixel[4]] < c_b)
+ if( p[pixel[6]] < c_b)
+ if( p[pixel[7]] < c_b)
+ if( p[pixel[8]] < c_b)
+ if( p[pixel[9]] < c_b)
+ if( p[pixel[10]] < c_b)
+ if( p[pixel[11]] < c_b)
+ if( p[pixel[12]] < c_b)
+ if( p[pixel[3]] < c_b)
+ if( p[pixel[2]] < c_b)
+ goto is_a_corner;
+ else
+ if( p[pixel[13]] < c_b)
+ if( p[pixel[14]] < c_b)
+ goto is_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ if( p[pixel[13]] < c_b)
+ if( p[pixel[14]] < c_b)
+ if( p[pixel[15]] < c_b)
+ goto is_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ if( p[pixel[5]] > cb)
+ if( p[pixel[6]] > cb)
+ if( p[pixel[7]] > cb)
+ if( p[pixel[8]] > cb)
+ if( p[pixel[9]] > cb)
+ if( p[pixel[10]] > cb)
+ if( p[pixel[11]] > cb)
+ if( p[pixel[12]] > cb)
+ if( p[pixel[13]] > cb)
+ if( p[pixel[14]] > cb)
+ if( p[pixel[15]] > cb)
+ goto is_a_corner;
+ else
+ if( p[pixel[3]] > cb)
+ if( p[pixel[4]] > cb)
+ goto is_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ if( p[pixel[2]] > cb)
+ if( p[pixel[3]] > cb)
+ if( p[pixel[4]] > cb)
+ goto is_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else if( p[pixel[5]] < c_b)
+ if( p[pixel[4]] < c_b)
+ if( p[pixel[6]] < c_b)
+ if( p[pixel[7]] < c_b)
+ if( p[pixel[8]] < c_b)
+ if( p[pixel[9]] < c_b)
+ if( p[pixel[10]] < c_b)
+ if( p[pixel[11]] < c_b)
+ if( p[pixel[12]] < c_b)
+ if( p[pixel[13]] < c_b)
+ if( p[pixel[3]] < c_b)
+ if( p[pixel[2]] < c_b)
+ goto is_a_corner;
+ else
+ if( p[pixel[14]] < c_b)
+ goto is_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ if( p[pixel[14]] < c_b)
+ if( p[pixel[15]] < c_b)
+ goto is_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else if( p[pixel[0]] < c_b)
+ if( p[pixel[1]] > cb)
+ if( p[pixel[5]] > cb)
+ if( p[pixel[4]] > cb)
+ if( p[pixel[6]] > cb)
+ if( p[pixel[7]] > cb)
+ if( p[pixel[8]] > cb)
+ if( p[pixel[9]] > cb)
+ if( p[pixel[10]] > cb)
+ if( p[pixel[11]] > cb)
+ if( p[pixel[12]] > cb)
+ if( p[pixel[3]] > cb)
+ if( p[pixel[2]] > cb)
+ goto is_a_corner;
+ else
+ if( p[pixel[13]] > cb)
+ if( p[pixel[14]] > cb)
+ goto is_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ if( p[pixel[13]] > cb)
+ if( p[pixel[14]] > cb)
+ if( p[pixel[15]] > cb)
+ goto is_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else if( p[pixel[5]] < c_b)
+ if( p[pixel[6]] < c_b)
+ if( p[pixel[7]] < c_b)
+ if( p[pixel[8]] < c_b)
+ if( p[pixel[9]] < c_b)
+ if( p[pixel[10]] < c_b)
+ if( p[pixel[11]] < c_b)
+ if( p[pixel[12]] < c_b)
+ if( p[pixel[13]] < c_b)
+ if( p[pixel[14]] < c_b)
+ if( p[pixel[15]] < c_b)
+ goto is_a_corner;
+ else
+ if( p[pixel[3]] < c_b)
+ if( p[pixel[4]] < c_b)
+ goto is_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ if( p[pixel[2]] < c_b)
+ if( p[pixel[3]] < c_b)
+ if( p[pixel[4]] < c_b)
+ goto is_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else if( p[pixel[1]] < c_b)
+ if( p[pixel[2]] > cb)
+ if( p[pixel[6]] > cb)
+ if( p[pixel[4]] > cb)
+ if( p[pixel[5]] > cb)
+ if( p[pixel[7]] > cb)
+ if( p[pixel[8]] > cb)
+ if( p[pixel[9]] > cb)
+ if( p[pixel[10]] > cb)
+ if( p[pixel[11]] > cb)
+ if( p[pixel[12]] > cb)
+ if( p[pixel[13]] > cb)
+ if( p[pixel[3]] > cb)
+ goto is_a_corner;
+ else
+ if( p[pixel[14]] > cb)
+ if( p[pixel[15]] > cb)
+ goto is_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else if( p[pixel[6]] < c_b)
+ if( p[pixel[7]] < c_b)
+ if( p[pixel[8]] < c_b)
+ if( p[pixel[9]] < c_b)
+ if( p[pixel[10]] < c_b)
+ if( p[pixel[11]] < c_b)
+ if( p[pixel[12]] < c_b)
+ if( p[pixel[13]] < c_b)
+ if( p[pixel[14]] < c_b)
+ if( p[pixel[15]] < c_b)
+ goto is_a_corner;
+ else
+ if( p[pixel[3]] < c_b)
+ if( p[pixel[4]] < c_b)
+ if( p[pixel[5]] < c_b)
+ goto is_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else if( p[pixel[2]] < c_b)
+ if( p[pixel[3]] > cb)
+ if( p[pixel[15]] < c_b)
+ if( p[pixel[7]] > cb)
+ if( p[pixel[4]] > cb)
+ if( p[pixel[5]] > cb)
+ if( p[pixel[6]] > cb)
+ if( p[pixel[8]] > cb)
+ if( p[pixel[9]] > cb)
+ if( p[pixel[10]] > cb)
+ if( p[pixel[11]] > cb)
+ if( p[pixel[12]] > cb)
+ if( p[pixel[13]] > cb)
+ if( p[pixel[14]] > cb)
+ goto is_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else if( p[pixel[7]] < c_b)
+ if( p[pixel[8]] < c_b)
+ if( p[pixel[9]] < c_b)
+ if( p[pixel[10]] < c_b)
+ if( p[pixel[11]] < c_b)
+ if( p[pixel[12]] < c_b)
+ if( p[pixel[13]] < c_b)
+ if( p[pixel[14]] < c_b)
+ goto is_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ if( p[pixel[4]] > cb)
+ if( p[pixel[5]] > cb)
+ if( p[pixel[6]] > cb)
+ if( p[pixel[7]] > cb)
+ if( p[pixel[8]] > cb)
+ if( p[pixel[9]] > cb)
+ if( p[pixel[10]] > cb)
+ if( p[pixel[11]] > cb)
+ if( p[pixel[12]] > cb)
+ if( p[pixel[13]] > cb)
+ if( p[pixel[14]] > cb)
+ goto is_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else if( p[pixel[3]] < c_b)
+ if( p[pixel[4]] > cb)
+ if( p[pixel[8]] > cb)
+ if( p[pixel[5]] > cb)
+ if( p[pixel[6]] > cb)
+ if( p[pixel[7]] > cb)
+ if( p[pixel[9]] > cb)
+ if( p[pixel[10]] > cb)
+ if( p[pixel[11]] > cb)
+ if( p[pixel[12]] > cb)
+ if( p[pixel[13]] > cb)
+ if( p[pixel[14]] > cb)
+ if( p[pixel[15]] > cb)
+ goto is_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else if( p[pixel[8]] < c_b)
+ if( p[pixel[9]] < c_b)
+ if( p[pixel[10]] < c_b)
+ if( p[pixel[11]] < c_b)
+ if( p[pixel[12]] < c_b)
+ if( p[pixel[13]] < c_b)
+ if( p[pixel[14]] < c_b)
+ if( p[pixel[15]] < c_b)
+ goto is_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else if( p[pixel[4]] < c_b)
+ if( p[pixel[5]] < c_b)
+ if( p[pixel[6]] < c_b)
+ if( p[pixel[7]] < c_b)
+ if( p[pixel[8]] < c_b)
+ if( p[pixel[9]] < c_b)
+ if( p[pixel[10]] < c_b)
+ if( p[pixel[11]] < c_b)
+ goto is_a_corner;
+ else
+ if( p[pixel[15]] < c_b)
+ goto is_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ if( p[pixel[14]] < c_b)
+ if( p[pixel[15]] < c_b)
+ goto is_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ if( p[pixel[13]] < c_b)
+ if( p[pixel[14]] < c_b)
+ if( p[pixel[15]] < c_b)
+ goto is_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ if( p[pixel[12]] < c_b)
+ if( p[pixel[13]] < c_b)
+ if( p[pixel[14]] < c_b)
+ if( p[pixel[15]] < c_b)
+ goto is_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ if( p[pixel[11]] < c_b)
+ if( p[pixel[12]] < c_b)
+ if( p[pixel[13]] < c_b)
+ if( p[pixel[14]] < c_b)
+ if( p[pixel[15]] < c_b)
+ goto is_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ if( p[pixel[10]] < c_b)
+ if( p[pixel[11]] < c_b)
+ if( p[pixel[12]] < c_b)
+ if( p[pixel[13]] < c_b)
+ if( p[pixel[14]] < c_b)
+ if( p[pixel[15]] < c_b)
+ goto is_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ if( p[pixel[9]] < c_b)
+ if( p[pixel[10]] < c_b)
+ if( p[pixel[11]] < c_b)
+ if( p[pixel[12]] < c_b)
+ if( p[pixel[13]] < c_b)
+ if( p[pixel[14]] < c_b)
+ if( p[pixel[15]] < c_b)
+ goto is_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ if( p[pixel[8]] < c_b)
+ if( p[pixel[9]] < c_b)
+ if( p[pixel[10]] < c_b)
+ if( p[pixel[11]] < c_b)
+ if( p[pixel[12]] < c_b)
+ if( p[pixel[13]] < c_b)
+ if( p[pixel[14]] < c_b)
+ if( p[pixel[15]] < c_b)
+ goto is_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ if( p[pixel[7]] > cb)
+ if( p[pixel[4]] > cb)
+ if( p[pixel[5]] > cb)
+ if( p[pixel[6]] > cb)
+ if( p[pixel[8]] > cb)
+ if( p[pixel[9]] > cb)
+ if( p[pixel[10]] > cb)
+ if( p[pixel[11]] > cb)
+ if( p[pixel[12]] > cb)
+ if( p[pixel[13]] > cb)
+ if( p[pixel[14]] > cb)
+ if( p[pixel[15]] > cb)
+ goto is_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else if( p[pixel[7]] < c_b)
+ if( p[pixel[8]] < c_b)
+ if( p[pixel[9]] < c_b)
+ if( p[pixel[10]] < c_b)
+ if( p[pixel[11]] < c_b)
+ if( p[pixel[12]] < c_b)
+ if( p[pixel[13]] < c_b)
+ if( p[pixel[14]] < c_b)
+ if( p[pixel[15]] < c_b)
+ goto is_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ if( p[pixel[6]] > cb)
+ if( p[pixel[4]] > cb)
+ if( p[pixel[5]] > cb)
+ if( p[pixel[7]] > cb)
+ if( p[pixel[8]] > cb)
+ if( p[pixel[9]] > cb)
+ if( p[pixel[10]] > cb)
+ if( p[pixel[11]] > cb)
+ if( p[pixel[12]] > cb)
+ if( p[pixel[13]] > cb)
+ if( p[pixel[14]] > cb)
+ if( p[pixel[3]] > cb)
+ goto is_a_corner;
+ else
+ if( p[pixel[15]] > cb)
+ goto is_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else if( p[pixel[6]] < c_b)
+ if( p[pixel[7]] < c_b)
+ if( p[pixel[8]] < c_b)
+ if( p[pixel[9]] < c_b)
+ if( p[pixel[10]] < c_b)
+ if( p[pixel[11]] < c_b)
+ if( p[pixel[12]] < c_b)
+ if( p[pixel[13]] < c_b)
+ if( p[pixel[14]] < c_b)
+ if( p[pixel[15]] < c_b)
+ goto is_a_corner;
+ else
+ if( p[pixel[3]] < c_b)
+ if( p[pixel[4]] < c_b)
+ if( p[pixel[5]] < c_b)
+ goto is_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ if( p[pixel[5]] > cb)
+ if( p[pixel[4]] > cb)
+ if( p[pixel[6]] > cb)
+ if( p[pixel[7]] > cb)
+ if( p[pixel[8]] > cb)
+ if( p[pixel[9]] > cb)
+ if( p[pixel[10]] > cb)
+ if( p[pixel[11]] > cb)
+ if( p[pixel[12]] > cb)
+ if( p[pixel[13]] > cb)
+ if( p[pixel[3]] > cb)
+ if( p[pixel[2]] > cb)
+ goto is_a_corner;
+ else
+ if( p[pixel[14]] > cb)
+ goto is_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ if( p[pixel[14]] > cb)
+ if( p[pixel[15]] > cb)
+ goto is_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else if( p[pixel[5]] < c_b)
+ if( p[pixel[6]] < c_b)
+ if( p[pixel[7]] < c_b)
+ if( p[pixel[8]] < c_b)
+ if( p[pixel[9]] < c_b)
+ if( p[pixel[10]] < c_b)
+ if( p[pixel[11]] < c_b)
+ if( p[pixel[12]] < c_b)
+ if( p[pixel[13]] < c_b)
+ if( p[pixel[14]] < c_b)
+ if( p[pixel[15]] < c_b)
+ goto is_a_corner;
+ else
+ if( p[pixel[3]] < c_b)
+ if( p[pixel[4]] < c_b)
+ goto is_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ if( p[pixel[2]] < c_b)
+ if( p[pixel[3]] < c_b)
+ if( p[pixel[4]] < c_b)
+ goto is_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ if( p[pixel[4]] > cb)
+ if( p[pixel[5]] > cb)
+ if( p[pixel[6]] > cb)
+ if( p[pixel[7]] > cb)
+ if( p[pixel[8]] > cb)
+ if( p[pixel[9]] > cb)
+ if( p[pixel[10]] > cb)
+ if( p[pixel[11]] > cb)
+ if( p[pixel[12]] > cb)
+ if( p[pixel[3]] > cb)
+ if( p[pixel[2]] > cb)
+ if( p[pixel[1]] > cb)
+ goto is_a_corner;
+ else
+ if( p[pixel[13]] > cb)
+ goto is_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ if( p[pixel[13]] > cb)
+ if( p[pixel[14]] > cb)
+ goto is_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ if( p[pixel[13]] > cb)
+ if( p[pixel[14]] > cb)
+ if( p[pixel[15]] > cb)
+ goto is_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else if( p[pixel[4]] < c_b)
+ if( p[pixel[5]] < c_b)
+ if( p[pixel[6]] < c_b)
+ if( p[pixel[7]] < c_b)
+ if( p[pixel[8]] < c_b)
+ if( p[pixel[9]] < c_b)
+ if( p[pixel[10]] < c_b)
+ if( p[pixel[11]] < c_b)
+ if( p[pixel[12]] < c_b)
+ if( p[pixel[3]] < c_b)
+ if( p[pixel[2]] < c_b)
+ if( p[pixel[1]] < c_b)
+ goto is_a_corner;
+ else
+ if( p[pixel[13]] < c_b)
+ goto is_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ if( p[pixel[13]] < c_b)
+ if( p[pixel[14]] < c_b)
+ goto is_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ if( p[pixel[13]] < c_b)
+ if( p[pixel[14]] < c_b)
+ if( p[pixel[15]] < c_b)
+ goto is_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+
+ is_a_corner:
+ bmin=b;
+ goto end_if;
+
+ is_not_a_corner:
+ bmax=b;
+ goto end_if;
+
+ end_if:
+
+ if(bmin == bmax - 1 || bmin == bmax)
+ return bmin;
+ b = (bmin + bmax) / 2;
+ }
+}
+
+static void make_offsets(int pixel[], int row_stride)
+{
+ pixel[0] = 0 + row_stride * 3;
+ pixel[1] = 1 + row_stride * 3;
+ pixel[2] = 2 + row_stride * 2;
+ pixel[3] = 3 + row_stride * 1;
+ pixel[4] = 3 + row_stride * 0;
+ pixel[5] = 3 + row_stride * -1;
+ pixel[6] = 2 + row_stride * -2;
+ pixel[7] = 1 + row_stride * -3;
+ pixel[8] = 0 + row_stride * -3;
+ pixel[9] = -1 + row_stride * -3;
+ pixel[10] = -2 + row_stride * -2;
+ pixel[11] = -3 + row_stride * -1;
+ pixel[12] = -3 + row_stride * 0;
+ pixel[13] = -3 + row_stride * 1;
+ pixel[14] = -2 + row_stride * 2;
+ pixel[15] = -1 + row_stride * 3;
+}
+
+
+
+int* fast12_score(const byte* i, int stride, xy* corners, int num_corners, int b)
+{
+ int* scores = (int*)malloc(sizeof(int)* num_corners);
+ int n;
+
+ int pixel[16];
+ make_offsets(pixel, stride);
+
+ for(n=0; n < num_corners; n++)
+ scores[n] = fast12_corner_score(i + corners[n].y*stride + corners[n].x, pixel, b);
+
+ return scores;
+}
+
+
+xy* fast12_detect(const byte* im, int xsize, int ysize, int stride, int b, int* ret_num_corners)
+{
+ int num_corners=0;
+ xy* ret_corners;
+ int rsize=512;
+ int pixel[16];
+ int x, y;
+
+ ret_corners = (xy*)malloc(sizeof(xy)*rsize);
+ make_offsets(pixel, stride);
+
+ for(y=3; y < ysize - 3; y++)
+ for(x=3; x < xsize - 3; x++)
+ {
+ const byte* p = im + y*stride + x;
+
+ int cb = *p + b;
+ int c_b= *p - b;
+ if(p[pixel[0]] > cb)
+ if(p[pixel[1]] > cb)
+ if(p[pixel[2]] > cb)
+ if(p[pixel[3]] > cb)
+ if(p[pixel[4]] > cb)
+ if(p[pixel[5]] > cb)
+ if(p[pixel[6]] > cb)
+ if(p[pixel[7]] > cb)
+ if(p[pixel[8]] > cb)
+ if(p[pixel[9]] > cb)
+ if(p[pixel[10]] > cb)
+ if(p[pixel[11]] > cb)
+ {}
+ else
+ if(p[pixel[15]] > cb)
+ {}
+ else
+ continue;
+ else
+ if(p[pixel[14]] > cb)
+ if(p[pixel[15]] > cb)
+ {}
+ else
+ continue;
+ else
+ continue;
+ else
+ if(p[pixel[13]] > cb)
+ if(p[pixel[14]] > cb)
+ if(p[pixel[15]] > cb)
+ {}
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ if(p[pixel[12]] > cb)
+ if(p[pixel[13]] > cb)
+ if(p[pixel[14]] > cb)
+ if(p[pixel[15]] > cb)
+ {}
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ if(p[pixel[11]] > cb)
+ if(p[pixel[12]] > cb)
+ if(p[pixel[13]] > cb)
+ if(p[pixel[14]] > cb)
+ if(p[pixel[15]] > cb)
+ {}
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ if(p[pixel[10]] > cb)
+ if(p[pixel[11]] > cb)
+ if(p[pixel[12]] > cb)
+ if(p[pixel[13]] > cb)
+ if(p[pixel[14]] > cb)
+ if(p[pixel[15]] > cb)
+ {}
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ if(p[pixel[9]] > cb)
+ if(p[pixel[10]] > cb)
+ if(p[pixel[11]] > cb)
+ if(p[pixel[12]] > cb)
+ if(p[pixel[13]] > cb)
+ if(p[pixel[14]] > cb)
+ if(p[pixel[15]] > cb)
+ {}
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else if(p[pixel[4]] < c_b)
+ if(p[pixel[8]] > cb)
+ if(p[pixel[9]] > cb)
+ if(p[pixel[10]] > cb)
+ if(p[pixel[11]] > cb)
+ if(p[pixel[12]] > cb)
+ if(p[pixel[13]] > cb)
+ if(p[pixel[14]] > cb)
+ if(p[pixel[15]] > cb)
+ {}
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else if(p[pixel[8]] < c_b)
+ if(p[pixel[5]] < c_b)
+ if(p[pixel[6]] < c_b)
+ if(p[pixel[7]] < c_b)
+ if(p[pixel[9]] < c_b)
+ if(p[pixel[10]] < c_b)
+ if(p[pixel[11]] < c_b)
+ if(p[pixel[12]] < c_b)
+ if(p[pixel[13]] < c_b)
+ if(p[pixel[14]] < c_b)
+ if(p[pixel[15]] < c_b)
+ {}
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ if(p[pixel[8]] > cb)
+ if(p[pixel[9]] > cb)
+ if(p[pixel[10]] > cb)
+ if(p[pixel[11]] > cb)
+ if(p[pixel[12]] > cb)
+ if(p[pixel[13]] > cb)
+ if(p[pixel[14]] > cb)
+ if(p[pixel[15]] > cb)
+ {}
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else if(p[pixel[3]] < c_b)
+ if(p[pixel[15]] > cb)
+ if(p[pixel[7]] > cb)
+ if(p[pixel[8]] > cb)
+ if(p[pixel[9]] > cb)
+ if(p[pixel[10]] > cb)
+ if(p[pixel[11]] > cb)
+ if(p[pixel[12]] > cb)
+ if(p[pixel[13]] > cb)
+ if(p[pixel[14]] > cb)
+ {}
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else if(p[pixel[7]] < c_b)
+ if(p[pixel[4]] < c_b)
+ if(p[pixel[5]] < c_b)
+ if(p[pixel[6]] < c_b)
+ if(p[pixel[8]] < c_b)
+ if(p[pixel[9]] < c_b)
+ if(p[pixel[10]] < c_b)
+ if(p[pixel[11]] < c_b)
+ if(p[pixel[12]] < c_b)
+ if(p[pixel[13]] < c_b)
+ if(p[pixel[14]] < c_b)
+ {}
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ if(p[pixel[4]] < c_b)
+ if(p[pixel[5]] < c_b)
+ if(p[pixel[6]] < c_b)
+ if(p[pixel[7]] < c_b)
+ if(p[pixel[8]] < c_b)
+ if(p[pixel[9]] < c_b)
+ if(p[pixel[10]] < c_b)
+ if(p[pixel[11]] < c_b)
+ if(p[pixel[12]] < c_b)
+ if(p[pixel[13]] < c_b)
+ if(p[pixel[14]] < c_b)
+ {}
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ if(p[pixel[7]] > cb)
+ if(p[pixel[8]] > cb)
+ if(p[pixel[9]] > cb)
+ if(p[pixel[10]] > cb)
+ if(p[pixel[11]] > cb)
+ if(p[pixel[12]] > cb)
+ if(p[pixel[13]] > cb)
+ if(p[pixel[14]] > cb)
+ if(p[pixel[15]] > cb)
+ {}
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else if(p[pixel[7]] < c_b)
+ if(p[pixel[4]] < c_b)
+ if(p[pixel[5]] < c_b)
+ if(p[pixel[6]] < c_b)
+ if(p[pixel[8]] < c_b)
+ if(p[pixel[9]] < c_b)
+ if(p[pixel[10]] < c_b)
+ if(p[pixel[11]] < c_b)
+ if(p[pixel[12]] < c_b)
+ if(p[pixel[13]] < c_b)
+ if(p[pixel[14]] < c_b)
+ if(p[pixel[15]] < c_b)
+ {}
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else if(p[pixel[2]] < c_b)
+ if(p[pixel[6]] > cb)
+ if(p[pixel[7]] > cb)
+ if(p[pixel[8]] > cb)
+ if(p[pixel[9]] > cb)
+ if(p[pixel[10]] > cb)
+ if(p[pixel[11]] > cb)
+ if(p[pixel[12]] > cb)
+ if(p[pixel[13]] > cb)
+ if(p[pixel[14]] > cb)
+ if(p[pixel[15]] > cb)
+ {}
+ else
+ if(p[pixel[3]] > cb)
+ if(p[pixel[4]] > cb)
+ if(p[pixel[5]] > cb)
+ {}
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else if(p[pixel[6]] < c_b)
+ if(p[pixel[4]] < c_b)
+ if(p[pixel[5]] < c_b)
+ if(p[pixel[7]] < c_b)
+ if(p[pixel[8]] < c_b)
+ if(p[pixel[9]] < c_b)
+ if(p[pixel[10]] < c_b)
+ if(p[pixel[11]] < c_b)
+ if(p[pixel[12]] < c_b)
+ if(p[pixel[13]] < c_b)
+ if(p[pixel[3]] < c_b)
+ {}
+ else
+ if(p[pixel[14]] < c_b)
+ if(p[pixel[15]] < c_b)
+ {}
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ if(p[pixel[6]] > cb)
+ if(p[pixel[7]] > cb)
+ if(p[pixel[8]] > cb)
+ if(p[pixel[9]] > cb)
+ if(p[pixel[10]] > cb)
+ if(p[pixel[11]] > cb)
+ if(p[pixel[12]] > cb)
+ if(p[pixel[13]] > cb)
+ if(p[pixel[14]] > cb)
+ if(p[pixel[15]] > cb)
+ {}
+ else
+ if(p[pixel[3]] > cb)
+ if(p[pixel[4]] > cb)
+ if(p[pixel[5]] > cb)
+ {}
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else if(p[pixel[6]] < c_b)
+ if(p[pixel[4]] < c_b)
+ if(p[pixel[5]] < c_b)
+ if(p[pixel[7]] < c_b)
+ if(p[pixel[8]] < c_b)
+ if(p[pixel[9]] < c_b)
+ if(p[pixel[10]] < c_b)
+ if(p[pixel[11]] < c_b)
+ if(p[pixel[12]] < c_b)
+ if(p[pixel[13]] < c_b)
+ if(p[pixel[14]] < c_b)
+ if(p[pixel[3]] < c_b)
+ {}
+ else
+ if(p[pixel[15]] < c_b)
+ {}
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else if(p[pixel[1]] < c_b)
+ if(p[pixel[5]] > cb)
+ if(p[pixel[6]] > cb)
+ if(p[pixel[7]] > cb)
+ if(p[pixel[8]] > cb)
+ if(p[pixel[9]] > cb)
+ if(p[pixel[10]] > cb)
+ if(p[pixel[11]] > cb)
+ if(p[pixel[12]] > cb)
+ if(p[pixel[13]] > cb)
+ if(p[pixel[14]] > cb)
+ if(p[pixel[15]] > cb)
+ {}
+ else
+ if(p[pixel[3]] > cb)
+ if(p[pixel[4]] > cb)
+ {}
+ else
+ continue;
+ else
+ continue;
+ else
+ if(p[pixel[2]] > cb)
+ if(p[pixel[3]] > cb)
+ if(p[pixel[4]] > cb)
+ {}
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else if(p[pixel[5]] < c_b)
+ if(p[pixel[4]] < c_b)
+ if(p[pixel[6]] < c_b)
+ if(p[pixel[7]] < c_b)
+ if(p[pixel[8]] < c_b)
+ if(p[pixel[9]] < c_b)
+ if(p[pixel[10]] < c_b)
+ if(p[pixel[11]] < c_b)
+ if(p[pixel[12]] < c_b)
+ if(p[pixel[3]] < c_b)
+ if(p[pixel[2]] < c_b)
+ {}
+ else
+ if(p[pixel[13]] < c_b)
+ if(p[pixel[14]] < c_b)
+ {}
+ else
+ continue;
+ else
+ continue;
+ else
+ if(p[pixel[13]] < c_b)
+ if(p[pixel[14]] < c_b)
+ if(p[pixel[15]] < c_b)
+ {}
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ if(p[pixel[5]] > cb)
+ if(p[pixel[6]] > cb)
+ if(p[pixel[7]] > cb)
+ if(p[pixel[8]] > cb)
+ if(p[pixel[9]] > cb)
+ if(p[pixel[10]] > cb)
+ if(p[pixel[11]] > cb)
+ if(p[pixel[12]] > cb)
+ if(p[pixel[13]] > cb)
+ if(p[pixel[14]] > cb)
+ if(p[pixel[15]] > cb)
+ {}
+ else
+ if(p[pixel[3]] > cb)
+ if(p[pixel[4]] > cb)
+ {}
+ else
+ continue;
+ else
+ continue;
+ else
+ if(p[pixel[2]] > cb)
+ if(p[pixel[3]] > cb)
+ if(p[pixel[4]] > cb)
+ {}
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else if(p[pixel[5]] < c_b)
+ if(p[pixel[4]] < c_b)
+ if(p[pixel[6]] < c_b)
+ if(p[pixel[7]] < c_b)
+ if(p[pixel[8]] < c_b)
+ if(p[pixel[9]] < c_b)
+ if(p[pixel[10]] < c_b)
+ if(p[pixel[11]] < c_b)
+ if(p[pixel[12]] < c_b)
+ if(p[pixel[13]] < c_b)
+ if(p[pixel[3]] < c_b)
+ if(p[pixel[2]] < c_b)
+ {}
+ else
+ if(p[pixel[14]] < c_b)
+ {}
+ else
+ continue;
+ else
+ if(p[pixel[14]] < c_b)
+ if(p[pixel[15]] < c_b)
+ {}
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else if(p[pixel[0]] < c_b)
+ if(p[pixel[1]] > cb)
+ if(p[pixel[5]] > cb)
+ if(p[pixel[4]] > cb)
+ if(p[pixel[6]] > cb)
+ if(p[pixel[7]] > cb)
+ if(p[pixel[8]] > cb)
+ if(p[pixel[9]] > cb)
+ if(p[pixel[10]] > cb)
+ if(p[pixel[11]] > cb)
+ if(p[pixel[12]] > cb)
+ if(p[pixel[3]] > cb)
+ if(p[pixel[2]] > cb)
+ {}
+ else
+ if(p[pixel[13]] > cb)
+ if(p[pixel[14]] > cb)
+ {}
+ else
+ continue;
+ else
+ continue;
+ else
+ if(p[pixel[13]] > cb)
+ if(p[pixel[14]] > cb)
+ if(p[pixel[15]] > cb)
+ {}
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else if(p[pixel[5]] < c_b)
+ if(p[pixel[6]] < c_b)
+ if(p[pixel[7]] < c_b)
+ if(p[pixel[8]] < c_b)
+ if(p[pixel[9]] < c_b)
+ if(p[pixel[10]] < c_b)
+ if(p[pixel[11]] < c_b)
+ if(p[pixel[12]] < c_b)
+ if(p[pixel[13]] < c_b)
+ if(p[pixel[14]] < c_b)
+ if(p[pixel[15]] < c_b)
+ {}
+ else
+ if(p[pixel[3]] < c_b)
+ if(p[pixel[4]] < c_b)
+ {}
+ else
+ continue;
+ else
+ continue;
+ else
+ if(p[pixel[2]] < c_b)
+ if(p[pixel[3]] < c_b)
+ if(p[pixel[4]] < c_b)
+ {}
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else if(p[pixel[1]] < c_b)
+ if(p[pixel[2]] > cb)
+ if(p[pixel[6]] > cb)
+ if(p[pixel[4]] > cb)
+ if(p[pixel[5]] > cb)
+ if(p[pixel[7]] > cb)
+ if(p[pixel[8]] > cb)
+ if(p[pixel[9]] > cb)
+ if(p[pixel[10]] > cb)
+ if(p[pixel[11]] > cb)
+ if(p[pixel[12]] > cb)
+ if(p[pixel[13]] > cb)
+ if(p[pixel[3]] > cb)
+ {}
+ else
+ if(p[pixel[14]] > cb)
+ if(p[pixel[15]] > cb)
+ {}
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else if(p[pixel[6]] < c_b)
+ if(p[pixel[7]] < c_b)
+ if(p[pixel[8]] < c_b)
+ if(p[pixel[9]] < c_b)
+ if(p[pixel[10]] < c_b)
+ if(p[pixel[11]] < c_b)
+ if(p[pixel[12]] < c_b)
+ if(p[pixel[13]] < c_b)
+ if(p[pixel[14]] < c_b)
+ if(p[pixel[15]] < c_b)
+ {}
+ else
+ if(p[pixel[3]] < c_b)
+ if(p[pixel[4]] < c_b)
+ if(p[pixel[5]] < c_b)
+ {}
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else if(p[pixel[2]] < c_b)
+ if(p[pixel[3]] > cb)
+ if(p[pixel[15]] < c_b)
+ if(p[pixel[7]] > cb)
+ if(p[pixel[4]] > cb)
+ if(p[pixel[5]] > cb)
+ if(p[pixel[6]] > cb)
+ if(p[pixel[8]] > cb)
+ if(p[pixel[9]] > cb)
+ if(p[pixel[10]] > cb)
+ if(p[pixel[11]] > cb)
+ if(p[pixel[12]] > cb)
+ if(p[pixel[13]] > cb)
+ if(p[pixel[14]] > cb)
+ {}
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else if(p[pixel[7]] < c_b)
+ if(p[pixel[8]] < c_b)
+ if(p[pixel[9]] < c_b)
+ if(p[pixel[10]] < c_b)
+ if(p[pixel[11]] < c_b)
+ if(p[pixel[12]] < c_b)
+ if(p[pixel[13]] < c_b)
+ if(p[pixel[14]] < c_b)
+ {}
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ if(p[pixel[4]] > cb)
+ if(p[pixel[5]] > cb)
+ if(p[pixel[6]] > cb)
+ if(p[pixel[7]] > cb)
+ if(p[pixel[8]] > cb)
+ if(p[pixel[9]] > cb)
+ if(p[pixel[10]] > cb)
+ if(p[pixel[11]] > cb)
+ if(p[pixel[12]] > cb)
+ if(p[pixel[13]] > cb)
+ if(p[pixel[14]] > cb)
+ {}
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else if(p[pixel[3]] < c_b)
+ if(p[pixel[4]] > cb)
+ if(p[pixel[8]] > cb)
+ if(p[pixel[5]] > cb)
+ if(p[pixel[6]] > cb)
+ if(p[pixel[7]] > cb)
+ if(p[pixel[9]] > cb)
+ if(p[pixel[10]] > cb)
+ if(p[pixel[11]] > cb)
+ if(p[pixel[12]] > cb)
+ if(p[pixel[13]] > cb)
+ if(p[pixel[14]] > cb)
+ if(p[pixel[15]] > cb)
+ {}
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else if(p[pixel[8]] < c_b)
+ if(p[pixel[9]] < c_b)
+ if(p[pixel[10]] < c_b)
+ if(p[pixel[11]] < c_b)
+ if(p[pixel[12]] < c_b)
+ if(p[pixel[13]] < c_b)
+ if(p[pixel[14]] < c_b)
+ if(p[pixel[15]] < c_b)
+ {}
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else if(p[pixel[4]] < c_b)
+ if(p[pixel[5]] < c_b)
+ if(p[pixel[6]] < c_b)
+ if(p[pixel[7]] < c_b)
+ if(p[pixel[8]] < c_b)
+ if(p[pixel[9]] < c_b)
+ if(p[pixel[10]] < c_b)
+ if(p[pixel[11]] < c_b)
+ {}
+ else
+ if(p[pixel[15]] < c_b)
+ {}
+ else
+ continue;
+ else
+ if(p[pixel[14]] < c_b)
+ if(p[pixel[15]] < c_b)
+ {}
+ else
+ continue;
+ else
+ continue;
+ else
+ if(p[pixel[13]] < c_b)
+ if(p[pixel[14]] < c_b)
+ if(p[pixel[15]] < c_b)
+ {}
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ if(p[pixel[12]] < c_b)
+ if(p[pixel[13]] < c_b)
+ if(p[pixel[14]] < c_b)
+ if(p[pixel[15]] < c_b)
+ {}
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ if(p[pixel[11]] < c_b)
+ if(p[pixel[12]] < c_b)
+ if(p[pixel[13]] < c_b)
+ if(p[pixel[14]] < c_b)
+ if(p[pixel[15]] < c_b)
+ {}
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ if(p[pixel[10]] < c_b)
+ if(p[pixel[11]] < c_b)
+ if(p[pixel[12]] < c_b)
+ if(p[pixel[13]] < c_b)
+ if(p[pixel[14]] < c_b)
+ if(p[pixel[15]] < c_b)
+ {}
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ if(p[pixel[9]] < c_b)
+ if(p[pixel[10]] < c_b)
+ if(p[pixel[11]] < c_b)
+ if(p[pixel[12]] < c_b)
+ if(p[pixel[13]] < c_b)
+ if(p[pixel[14]] < c_b)
+ if(p[pixel[15]] < c_b)
+ {}
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ if(p[pixel[8]] < c_b)
+ if(p[pixel[9]] < c_b)
+ if(p[pixel[10]] < c_b)
+ if(p[pixel[11]] < c_b)
+ if(p[pixel[12]] < c_b)
+ if(p[pixel[13]] < c_b)
+ if(p[pixel[14]] < c_b)
+ if(p[pixel[15]] < c_b)
+ {}
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ if(p[pixel[7]] > cb)
+ if(p[pixel[4]] > cb)
+ if(p[pixel[5]] > cb)
+ if(p[pixel[6]] > cb)
+ if(p[pixel[8]] > cb)
+ if(p[pixel[9]] > cb)
+ if(p[pixel[10]] > cb)
+ if(p[pixel[11]] > cb)
+ if(p[pixel[12]] > cb)
+ if(p[pixel[13]] > cb)
+ if(p[pixel[14]] > cb)
+ if(p[pixel[15]] > cb)
+ {}
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else if(p[pixel[7]] < c_b)
+ if(p[pixel[8]] < c_b)
+ if(p[pixel[9]] < c_b)
+ if(p[pixel[10]] < c_b)
+ if(p[pixel[11]] < c_b)
+ if(p[pixel[12]] < c_b)
+ if(p[pixel[13]] < c_b)
+ if(p[pixel[14]] < c_b)
+ if(p[pixel[15]] < c_b)
+ {}
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ if(p[pixel[6]] > cb)
+ if(p[pixel[4]] > cb)
+ if(p[pixel[5]] > cb)
+ if(p[pixel[7]] > cb)
+ if(p[pixel[8]] > cb)
+ if(p[pixel[9]] > cb)
+ if(p[pixel[10]] > cb)
+ if(p[pixel[11]] > cb)
+ if(p[pixel[12]] > cb)
+ if(p[pixel[13]] > cb)
+ if(p[pixel[14]] > cb)
+ if(p[pixel[3]] > cb)
+ {}
+ else
+ if(p[pixel[15]] > cb)
+ {}
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else if(p[pixel[6]] < c_b)
+ if(p[pixel[7]] < c_b)
+ if(p[pixel[8]] < c_b)
+ if(p[pixel[9]] < c_b)
+ if(p[pixel[10]] < c_b)
+ if(p[pixel[11]] < c_b)
+ if(p[pixel[12]] < c_b)
+ if(p[pixel[13]] < c_b)
+ if(p[pixel[14]] < c_b)
+ if(p[pixel[15]] < c_b)
+ {}
+ else
+ if(p[pixel[3]] < c_b)
+ if(p[pixel[4]] < c_b)
+ if(p[pixel[5]] < c_b)
+ {}
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ if(p[pixel[5]] > cb)
+ if(p[pixel[4]] > cb)
+ if(p[pixel[6]] > cb)
+ if(p[pixel[7]] > cb)
+ if(p[pixel[8]] > cb)
+ if(p[pixel[9]] > cb)
+ if(p[pixel[10]] > cb)
+ if(p[pixel[11]] > cb)
+ if(p[pixel[12]] > cb)
+ if(p[pixel[13]] > cb)
+ if(p[pixel[3]] > cb)
+ if(p[pixel[2]] > cb)
+ {}
+ else
+ if(p[pixel[14]] > cb)
+ {}
+ else
+ continue;
+ else
+ if(p[pixel[14]] > cb)
+ if(p[pixel[15]] > cb)
+ {}
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else if(p[pixel[5]] < c_b)
+ if(p[pixel[6]] < c_b)
+ if(p[pixel[7]] < c_b)
+ if(p[pixel[8]] < c_b)
+ if(p[pixel[9]] < c_b)
+ if(p[pixel[10]] < c_b)
+ if(p[pixel[11]] < c_b)
+ if(p[pixel[12]] < c_b)
+ if(p[pixel[13]] < c_b)
+ if(p[pixel[14]] < c_b)
+ if(p[pixel[15]] < c_b)
+ {}
+ else
+ if(p[pixel[3]] < c_b)
+ if(p[pixel[4]] < c_b)
+ {}
+ else
+ continue;
+ else
+ continue;
+ else
+ if(p[pixel[2]] < c_b)
+ if(p[pixel[3]] < c_b)
+ if(p[pixel[4]] < c_b)
+ {}
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ if(p[pixel[4]] > cb)
+ if(p[pixel[5]] > cb)
+ if(p[pixel[6]] > cb)
+ if(p[pixel[7]] > cb)
+ if(p[pixel[8]] > cb)
+ if(p[pixel[9]] > cb)
+ if(p[pixel[10]] > cb)
+ if(p[pixel[11]] > cb)
+ if(p[pixel[12]] > cb)
+ if(p[pixel[3]] > cb)
+ if(p[pixel[2]] > cb)
+ if(p[pixel[1]] > cb)
+ {}
+ else
+ if(p[pixel[13]] > cb)
+ {}
+ else
+ continue;
+ else
+ if(p[pixel[13]] > cb)
+ if(p[pixel[14]] > cb)
+ {}
+ else
+ continue;
+ else
+ continue;
+ else
+ if(p[pixel[13]] > cb)
+ if(p[pixel[14]] > cb)
+ if(p[pixel[15]] > cb)
+ {}
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else if(p[pixel[4]] < c_b)
+ if(p[pixel[5]] < c_b)
+ if(p[pixel[6]] < c_b)
+ if(p[pixel[7]] < c_b)
+ if(p[pixel[8]] < c_b)
+ if(p[pixel[9]] < c_b)
+ if(p[pixel[10]] < c_b)
+ if(p[pixel[11]] < c_b)
+ if(p[pixel[12]] < c_b)
+ if(p[pixel[3]] < c_b)
+ if(p[pixel[2]] < c_b)
+ if(p[pixel[1]] < c_b)
+ {}
+ else
+ if(p[pixel[13]] < c_b)
+ {}
+ else
+ continue;
+ else
+ if(p[pixel[13]] < c_b)
+ if(p[pixel[14]] < c_b)
+ {}
+ else
+ continue;
+ else
+ continue;
+ else
+ if(p[pixel[13]] < c_b)
+ if(p[pixel[14]] < c_b)
+ if(p[pixel[15]] < c_b)
+ {}
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ if(num_corners == rsize)
+ {
+ rsize*=2;
+ ret_corners = (xy*)realloc(ret_corners, sizeof(xy)*rsize);
+ }
+
+ ret_corners[num_corners].x = x;
+ ret_corners[num_corners].y = y;
+ num_corners++;
+ }
+
+ *ret_num_corners = num_corners;
+ return ret_corners;
+
+}
+
+
diff --git a/extern/libmv/third_party/fast/fast_9.c b/extern/libmv/third_party/fast/fast_9.c
new file mode 100644
index 00000000000..6d33daeffbb
--- /dev/null
+++ b/extern/libmv/third_party/fast/fast_9.c
@@ -0,0 +1,5910 @@
+/*This is mechanically generated code*/
+#include <stdlib.h>
+
+typedef struct { int x, y; } xy;
+typedef unsigned char byte;
+
+int fast9_corner_score(const byte* p, const int pixel[], int bstart)
+{
+ int bmin = bstart;
+ int bmax = 255;
+ int b = (bmax + bmin)/2;
+
+ /*Compute the score using binary search*/
+ for(;;)
+ {
+ int cb = *p + b;
+ int c_b= *p - b;
+
+
+ if( p[pixel[0]] > cb)
+ if( p[pixel[1]] > cb)
+ if( p[pixel[2]] > cb)
+ if( p[pixel[3]] > cb)
+ if( p[pixel[4]] > cb)
+ if( p[pixel[5]] > cb)
+ if( p[pixel[6]] > cb)
+ if( p[pixel[7]] > cb)
+ if( p[pixel[8]] > cb)
+ goto is_a_corner;
+ else
+ if( p[pixel[15]] > cb)
+ goto is_a_corner;
+ else
+ goto is_not_a_corner;
+ else if( p[pixel[7]] < c_b)
+ if( p[pixel[14]] > cb)
+ if( p[pixel[15]] > cb)
+ goto is_a_corner;
+ else
+ goto is_not_a_corner;
+ else if( p[pixel[14]] < c_b)
+ if( p[pixel[8]] < c_b)
+ if( p[pixel[9]] < c_b)
+ if( p[pixel[10]] < c_b)
+ if( p[pixel[11]] < c_b)
+ if( p[pixel[12]] < c_b)
+ if( p[pixel[13]] < c_b)
+ if( p[pixel[15]] < c_b)
+ goto is_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ if( p[pixel[14]] > cb)
+ if( p[pixel[15]] > cb)
+ goto is_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else if( p[pixel[6]] < c_b)
+ if( p[pixel[15]] > cb)
+ if( p[pixel[13]] > cb)
+ if( p[pixel[14]] > cb)
+ goto is_a_corner;
+ else
+ goto is_not_a_corner;
+ else if( p[pixel[13]] < c_b)
+ if( p[pixel[7]] < c_b)
+ if( p[pixel[8]] < c_b)
+ if( p[pixel[9]] < c_b)
+ if( p[pixel[10]] < c_b)
+ if( p[pixel[11]] < c_b)
+ if( p[pixel[12]] < c_b)
+ if( p[pixel[14]] < c_b)
+ goto is_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ if( p[pixel[7]] < c_b)
+ if( p[pixel[8]] < c_b)
+ if( p[pixel[9]] < c_b)
+ if( p[pixel[10]] < c_b)
+ if( p[pixel[11]] < c_b)
+ if( p[pixel[12]] < c_b)
+ if( p[pixel[13]] < c_b)
+ if( p[pixel[14]] < c_b)
+ goto is_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ if( p[pixel[13]] > cb)
+ if( p[pixel[14]] > cb)
+ if( p[pixel[15]] > cb)
+ goto is_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else if( p[pixel[13]] < c_b)
+ if( p[pixel[7]] < c_b)
+ if( p[pixel[8]] < c_b)
+ if( p[pixel[9]] < c_b)
+ if( p[pixel[10]] < c_b)
+ if( p[pixel[11]] < c_b)
+ if( p[pixel[12]] < c_b)
+ if( p[pixel[14]] < c_b)
+ if( p[pixel[15]] < c_b)
+ goto is_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else if( p[pixel[5]] < c_b)
+ if( p[pixel[14]] > cb)
+ if( p[pixel[12]] > cb)
+ if( p[pixel[13]] > cb)
+ if( p[pixel[15]] > cb)
+ goto is_a_corner;
+ else
+ if( p[pixel[6]] > cb)
+ if( p[pixel[7]] > cb)
+ if( p[pixel[8]] > cb)
+ if( p[pixel[9]] > cb)
+ if( p[pixel[10]] > cb)
+ if( p[pixel[11]] > cb)
+ goto is_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else if( p[pixel[12]] < c_b)
+ if( p[pixel[6]] < c_b)
+ if( p[pixel[7]] < c_b)
+ if( p[pixel[8]] < c_b)
+ if( p[pixel[9]] < c_b)
+ if( p[pixel[10]] < c_b)
+ if( p[pixel[11]] < c_b)
+ if( p[pixel[13]] < c_b)
+ goto is_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else if( p[pixel[14]] < c_b)
+ if( p[pixel[7]] < c_b)
+ if( p[pixel[8]] < c_b)
+ if( p[pixel[9]] < c_b)
+ if( p[pixel[10]] < c_b)
+ if( p[pixel[11]] < c_b)
+ if( p[pixel[12]] < c_b)
+ if( p[pixel[13]] < c_b)
+ if( p[pixel[6]] < c_b)
+ goto is_a_corner;
+ else
+ if( p[pixel[15]] < c_b)
+ goto is_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ if( p[pixel[6]] < c_b)
+ if( p[pixel[7]] < c_b)
+ if( p[pixel[8]] < c_b)
+ if( p[pixel[9]] < c_b)
+ if( p[pixel[10]] < c_b)
+ if( p[pixel[11]] < c_b)
+ if( p[pixel[12]] < c_b)
+ if( p[pixel[13]] < c_b)
+ goto is_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ if( p[pixel[12]] > cb)
+ if( p[pixel[13]] > cb)
+ if( p[pixel[14]] > cb)
+ if( p[pixel[15]] > cb)
+ goto is_a_corner;
+ else
+ if( p[pixel[6]] > cb)
+ if( p[pixel[7]] > cb)
+ if( p[pixel[8]] > cb)
+ if( p[pixel[9]] > cb)
+ if( p[pixel[10]] > cb)
+ if( p[pixel[11]] > cb)
+ goto is_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else if( p[pixel[12]] < c_b)
+ if( p[pixel[7]] < c_b)
+ if( p[pixel[8]] < c_b)
+ if( p[pixel[9]] < c_b)
+ if( p[pixel[10]] < c_b)
+ if( p[pixel[11]] < c_b)
+ if( p[pixel[13]] < c_b)
+ if( p[pixel[14]] < c_b)
+ if( p[pixel[6]] < c_b)
+ goto is_a_corner;
+ else
+ if( p[pixel[15]] < c_b)
+ goto is_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else if( p[pixel[4]] < c_b)
+ if( p[pixel[13]] > cb)
+ if( p[pixel[11]] > cb)
+ if( p[pixel[12]] > cb)
+ if( p[pixel[14]] > cb)
+ if( p[pixel[15]] > cb)
+ goto is_a_corner;
+ else
+ if( p[pixel[6]] > cb)
+ if( p[pixel[7]] > cb)
+ if( p[pixel[8]] > cb)
+ if( p[pixel[9]] > cb)
+ if( p[pixel[10]] > cb)
+ goto is_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ if( p[pixel[5]] > cb)
+ if( p[pixel[6]] > cb)
+ if( p[pixel[7]] > cb)
+ if( p[pixel[8]] > cb)
+ if( p[pixel[9]] > cb)
+ if( p[pixel[10]] > cb)
+ goto is_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else if( p[pixel[11]] < c_b)
+ if( p[pixel[5]] < c_b)
+ if( p[pixel[6]] < c_b)
+ if( p[pixel[7]] < c_b)
+ if( p[pixel[8]] < c_b)
+ if( p[pixel[9]] < c_b)
+ if( p[pixel[10]] < c_b)
+ if( p[pixel[12]] < c_b)
+ goto is_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else if( p[pixel[13]] < c_b)
+ if( p[pixel[7]] < c_b)
+ if( p[pixel[8]] < c_b)
+ if( p[pixel[9]] < c_b)
+ if( p[pixel[10]] < c_b)
+ if( p[pixel[11]] < c_b)
+ if( p[pixel[12]] < c_b)
+ if( p[pixel[6]] < c_b)
+ if( p[pixel[5]] < c_b)
+ goto is_a_corner;
+ else
+ if( p[pixel[14]] < c_b)
+ goto is_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ if( p[pixel[14]] < c_b)
+ if( p[pixel[15]] < c_b)
+ goto is_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ if( p[pixel[5]] < c_b)
+ if( p[pixel[6]] < c_b)
+ if( p[pixel[7]] < c_b)
+ if( p[pixel[8]] < c_b)
+ if( p[pixel[9]] < c_b)
+ if( p[pixel[10]] < c_b)
+ if( p[pixel[11]] < c_b)
+ if( p[pixel[12]] < c_b)
+ goto is_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ if( p[pixel[11]] > cb)
+ if( p[pixel[12]] > cb)
+ if( p[pixel[13]] > cb)
+ if( p[pixel[14]] > cb)
+ if( p[pixel[15]] > cb)
+ goto is_a_corner;
+ else
+ if( p[pixel[6]] > cb)
+ if( p[pixel[7]] > cb)
+ if( p[pixel[8]] > cb)
+ if( p[pixel[9]] > cb)
+ if( p[pixel[10]] > cb)
+ goto is_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ if( p[pixel[5]] > cb)
+ if( p[pixel[6]] > cb)
+ if( p[pixel[7]] > cb)
+ if( p[pixel[8]] > cb)
+ if( p[pixel[9]] > cb)
+ if( p[pixel[10]] > cb)
+ goto is_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else if( p[pixel[11]] < c_b)
+ if( p[pixel[7]] < c_b)
+ if( p[pixel[8]] < c_b)
+ if( p[pixel[9]] < c_b)
+ if( p[pixel[10]] < c_b)
+ if( p[pixel[12]] < c_b)
+ if( p[pixel[13]] < c_b)
+ if( p[pixel[6]] < c_b)
+ if( p[pixel[5]] < c_b)
+ goto is_a_corner;
+ else
+ if( p[pixel[14]] < c_b)
+ goto is_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ if( p[pixel[14]] < c_b)
+ if( p[pixel[15]] < c_b)
+ goto is_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else if( p[pixel[3]] < c_b)
+ if( p[pixel[10]] > cb)
+ if( p[pixel[11]] > cb)
+ if( p[pixel[12]] > cb)
+ if( p[pixel[13]] > cb)
+ if( p[pixel[14]] > cb)
+ if( p[pixel[15]] > cb)
+ goto is_a_corner;
+ else
+ if( p[pixel[6]] > cb)
+ if( p[pixel[7]] > cb)
+ if( p[pixel[8]] > cb)
+ if( p[pixel[9]] > cb)
+ goto is_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ if( p[pixel[5]] > cb)
+ if( p[pixel[6]] > cb)
+ if( p[pixel[7]] > cb)
+ if( p[pixel[8]] > cb)
+ if( p[pixel[9]] > cb)
+ goto is_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ if( p[pixel[4]] > cb)
+ if( p[pixel[5]] > cb)
+ if( p[pixel[6]] > cb)
+ if( p[pixel[7]] > cb)
+ if( p[pixel[8]] > cb)
+ if( p[pixel[9]] > cb)
+ goto is_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else if( p[pixel[10]] < c_b)
+ if( p[pixel[7]] < c_b)
+ if( p[pixel[8]] < c_b)
+ if( p[pixel[9]] < c_b)
+ if( p[pixel[11]] < c_b)
+ if( p[pixel[6]] < c_b)
+ if( p[pixel[5]] < c_b)
+ if( p[pixel[4]] < c_b)
+ goto is_a_corner;
+ else
+ if( p[pixel[12]] < c_b)
+ if( p[pixel[13]] < c_b)
+ goto is_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ if( p[pixel[12]] < c_b)
+ if( p[pixel[13]] < c_b)
+ if( p[pixel[14]] < c_b)
+ goto is_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ if( p[pixel[12]] < c_b)
+ if( p[pixel[13]] < c_b)
+ if( p[pixel[14]] < c_b)
+ if( p[pixel[15]] < c_b)
+ goto is_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ if( p[pixel[10]] > cb)
+ if( p[pixel[11]] > cb)
+ if( p[pixel[12]] > cb)
+ if( p[pixel[13]] > cb)
+ if( p[pixel[14]] > cb)
+ if( p[pixel[15]] > cb)
+ goto is_a_corner;
+ else
+ if( p[pixel[6]] > cb)
+ if( p[pixel[7]] > cb)
+ if( p[pixel[8]] > cb)
+ if( p[pixel[9]] > cb)
+ goto is_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ if( p[pixel[5]] > cb)
+ if( p[pixel[6]] > cb)
+ if( p[pixel[7]] > cb)
+ if( p[pixel[8]] > cb)
+ if( p[pixel[9]] > cb)
+ goto is_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ if( p[pixel[4]] > cb)
+ if( p[pixel[5]] > cb)
+ if( p[pixel[6]] > cb)
+ if( p[pixel[7]] > cb)
+ if( p[pixel[8]] > cb)
+ if( p[pixel[9]] > cb)
+ goto is_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else if( p[pixel[10]] < c_b)
+ if( p[pixel[7]] < c_b)
+ if( p[pixel[8]] < c_b)
+ if( p[pixel[9]] < c_b)
+ if( p[pixel[11]] < c_b)
+ if( p[pixel[12]] < c_b)
+ if( p[pixel[6]] < c_b)
+ if( p[pixel[5]] < c_b)
+ if( p[pixel[4]] < c_b)
+ goto is_a_corner;
+ else
+ if( p[pixel[13]] < c_b)
+ goto is_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ if( p[pixel[13]] < c_b)
+ if( p[pixel[14]] < c_b)
+ goto is_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ if( p[pixel[13]] < c_b)
+ if( p[pixel[14]] < c_b)
+ if( p[pixel[15]] < c_b)
+ goto is_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else if( p[pixel[2]] < c_b)
+ if( p[pixel[9]] > cb)
+ if( p[pixel[10]] > cb)
+ if( p[pixel[11]] > cb)
+ if( p[pixel[12]] > cb)
+ if( p[pixel[13]] > cb)
+ if( p[pixel[14]] > cb)
+ if( p[pixel[15]] > cb)
+ goto is_a_corner;
+ else
+ if( p[pixel[6]] > cb)
+ if( p[pixel[7]] > cb)
+ if( p[pixel[8]] > cb)
+ goto is_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ if( p[pixel[5]] > cb)
+ if( p[pixel[6]] > cb)
+ if( p[pixel[7]] > cb)
+ if( p[pixel[8]] > cb)
+ goto is_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ if( p[pixel[4]] > cb)
+ if( p[pixel[5]] > cb)
+ if( p[pixel[6]] > cb)
+ if( p[pixel[7]] > cb)
+ if( p[pixel[8]] > cb)
+ goto is_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ if( p[pixel[3]] > cb)
+ if( p[pixel[4]] > cb)
+ if( p[pixel[5]] > cb)
+ if( p[pixel[6]] > cb)
+ if( p[pixel[7]] > cb)
+ if( p[pixel[8]] > cb)
+ goto is_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else if( p[pixel[9]] < c_b)
+ if( p[pixel[7]] < c_b)
+ if( p[pixel[8]] < c_b)
+ if( p[pixel[10]] < c_b)
+ if( p[pixel[6]] < c_b)
+ if( p[pixel[5]] < c_b)
+ if( p[pixel[4]] < c_b)
+ if( p[pixel[3]] < c_b)
+ goto is_a_corner;
+ else
+ if( p[pixel[11]] < c_b)
+ if( p[pixel[12]] < c_b)
+ goto is_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ if( p[pixel[11]] < c_b)
+ if( p[pixel[12]] < c_b)
+ if( p[pixel[13]] < c_b)
+ goto is_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ if( p[pixel[11]] < c_b)
+ if( p[pixel[12]] < c_b)
+ if( p[pixel[13]] < c_b)
+ if( p[pixel[14]] < c_b)
+ goto is_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ if( p[pixel[11]] < c_b)
+ if( p[pixel[12]] < c_b)
+ if( p[pixel[13]] < c_b)
+ if( p[pixel[14]] < c_b)
+ if( p[pixel[15]] < c_b)
+ goto is_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ if( p[pixel[9]] > cb)
+ if( p[pixel[10]] > cb)
+ if( p[pixel[11]] > cb)
+ if( p[pixel[12]] > cb)
+ if( p[pixel[13]] > cb)
+ if( p[pixel[14]] > cb)
+ if( p[pixel[15]] > cb)
+ goto is_a_corner;
+ else
+ if( p[pixel[6]] > cb)
+ if( p[pixel[7]] > cb)
+ if( p[pixel[8]] > cb)
+ goto is_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ if( p[pixel[5]] > cb)
+ if( p[pixel[6]] > cb)
+ if( p[pixel[7]] > cb)
+ if( p[pixel[8]] > cb)
+ goto is_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ if( p[pixel[4]] > cb)
+ if( p[pixel[5]] > cb)
+ if( p[pixel[6]] > cb)
+ if( p[pixel[7]] > cb)
+ if( p[pixel[8]] > cb)
+ goto is_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ if( p[pixel[3]] > cb)
+ if( p[pixel[4]] > cb)
+ if( p[pixel[5]] > cb)
+ if( p[pixel[6]] > cb)
+ if( p[pixel[7]] > cb)
+ if( p[pixel[8]] > cb)
+ goto is_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else if( p[pixel[9]] < c_b)
+ if( p[pixel[7]] < c_b)
+ if( p[pixel[8]] < c_b)
+ if( p[pixel[10]] < c_b)
+ if( p[pixel[11]] < c_b)
+ if( p[pixel[6]] < c_b)
+ if( p[pixel[5]] < c_b)
+ if( p[pixel[4]] < c_b)
+ if( p[pixel[3]] < c_b)
+ goto is_a_corner;
+ else
+ if( p[pixel[12]] < c_b)
+ goto is_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ if( p[pixel[12]] < c_b)
+ if( p[pixel[13]] < c_b)
+ goto is_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ if( p[pixel[12]] < c_b)
+ if( p[pixel[13]] < c_b)
+ if( p[pixel[14]] < c_b)
+ goto is_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ if( p[pixel[12]] < c_b)
+ if( p[pixel[13]] < c_b)
+ if( p[pixel[14]] < c_b)
+ if( p[pixel[15]] < c_b)
+ goto is_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else if( p[pixel[1]] < c_b)
+ if( p[pixel[8]] > cb)
+ if( p[pixel[9]] > cb)
+ if( p[pixel[10]] > cb)
+ if( p[pixel[11]] > cb)
+ if( p[pixel[12]] > cb)
+ if( p[pixel[13]] > cb)
+ if( p[pixel[14]] > cb)
+ if( p[pixel[15]] > cb)
+ goto is_a_corner;
+ else
+ if( p[pixel[6]] > cb)
+ if( p[pixel[7]] > cb)
+ goto is_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ if( p[pixel[5]] > cb)
+ if( p[pixel[6]] > cb)
+ if( p[pixel[7]] > cb)
+ goto is_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ if( p[pixel[4]] > cb)
+ if( p[pixel[5]] > cb)
+ if( p[pixel[6]] > cb)
+ if( p[pixel[7]] > cb)
+ goto is_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ if( p[pixel[3]] > cb)
+ if( p[pixel[4]] > cb)
+ if( p[pixel[5]] > cb)
+ if( p[pixel[6]] > cb)
+ if( p[pixel[7]] > cb)
+ goto is_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ if( p[pixel[2]] > cb)
+ if( p[pixel[3]] > cb)
+ if( p[pixel[4]] > cb)
+ if( p[pixel[5]] > cb)
+ if( p[pixel[6]] > cb)
+ if( p[pixel[7]] > cb)
+ goto is_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else if( p[pixel[8]] < c_b)
+ if( p[pixel[7]] < c_b)
+ if( p[pixel[9]] < c_b)
+ if( p[pixel[6]] < c_b)
+ if( p[pixel[5]] < c_b)
+ if( p[pixel[4]] < c_b)
+ if( p[pixel[3]] < c_b)
+ if( p[pixel[2]] < c_b)
+ goto is_a_corner;
+ else
+ if( p[pixel[10]] < c_b)
+ if( p[pixel[11]] < c_b)
+ goto is_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ if( p[pixel[10]] < c_b)
+ if( p[pixel[11]] < c_b)
+ if( p[pixel[12]] < c_b)
+ goto is_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ if( p[pixel[10]] < c_b)
+ if( p[pixel[11]] < c_b)
+ if( p[pixel[12]] < c_b)
+ if( p[pixel[13]] < c_b)
+ goto is_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ if( p[pixel[10]] < c_b)
+ if( p[pixel[11]] < c_b)
+ if( p[pixel[12]] < c_b)
+ if( p[pixel[13]] < c_b)
+ if( p[pixel[14]] < c_b)
+ goto is_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ if( p[pixel[10]] < c_b)
+ if( p[pixel[11]] < c_b)
+ if( p[pixel[12]] < c_b)
+ if( p[pixel[13]] < c_b)
+ if( p[pixel[14]] < c_b)
+ if( p[pixel[15]] < c_b)
+ goto is_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ if( p[pixel[8]] > cb)
+ if( p[pixel[9]] > cb)
+ if( p[pixel[10]] > cb)
+ if( p[pixel[11]] > cb)
+ if( p[pixel[12]] > cb)
+ if( p[pixel[13]] > cb)
+ if( p[pixel[14]] > cb)
+ if( p[pixel[15]] > cb)
+ goto is_a_corner;
+ else
+ if( p[pixel[6]] > cb)
+ if( p[pixel[7]] > cb)
+ goto is_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ if( p[pixel[5]] > cb)
+ if( p[pixel[6]] > cb)
+ if( p[pixel[7]] > cb)
+ goto is_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ if( p[pixel[4]] > cb)
+ if( p[pixel[5]] > cb)
+ if( p[pixel[6]] > cb)
+ if( p[pixel[7]] > cb)
+ goto is_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ if( p[pixel[3]] > cb)
+ if( p[pixel[4]] > cb)
+ if( p[pixel[5]] > cb)
+ if( p[pixel[6]] > cb)
+ if( p[pixel[7]] > cb)
+ goto is_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ if( p[pixel[2]] > cb)
+ if( p[pixel[3]] > cb)
+ if( p[pixel[4]] > cb)
+ if( p[pixel[5]] > cb)
+ if( p[pixel[6]] > cb)
+ if( p[pixel[7]] > cb)
+ goto is_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else if( p[pixel[8]] < c_b)
+ if( p[pixel[7]] < c_b)
+ if( p[pixel[9]] < c_b)
+ if( p[pixel[10]] < c_b)
+ if( p[pixel[6]] < c_b)
+ if( p[pixel[5]] < c_b)
+ if( p[pixel[4]] < c_b)
+ if( p[pixel[3]] < c_b)
+ if( p[pixel[2]] < c_b)
+ goto is_a_corner;
+ else
+ if( p[pixel[11]] < c_b)
+ goto is_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ if( p[pixel[11]] < c_b)
+ if( p[pixel[12]] < c_b)
+ goto is_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ if( p[pixel[11]] < c_b)
+ if( p[pixel[12]] < c_b)
+ if( p[pixel[13]] < c_b)
+ goto is_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ if( p[pixel[11]] < c_b)
+ if( p[pixel[12]] < c_b)
+ if( p[pixel[13]] < c_b)
+ if( p[pixel[14]] < c_b)
+ goto is_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ if( p[pixel[11]] < c_b)
+ if( p[pixel[12]] < c_b)
+ if( p[pixel[13]] < c_b)
+ if( p[pixel[14]] < c_b)
+ if( p[pixel[15]] < c_b)
+ goto is_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else if( p[pixel[0]] < c_b)
+ if( p[pixel[1]] > cb)
+ if( p[pixel[8]] > cb)
+ if( p[pixel[7]] > cb)
+ if( p[pixel[9]] > cb)
+ if( p[pixel[6]] > cb)
+ if( p[pixel[5]] > cb)
+ if( p[pixel[4]] > cb)
+ if( p[pixel[3]] > cb)
+ if( p[pixel[2]] > cb)
+ goto is_a_corner;
+ else
+ if( p[pixel[10]] > cb)
+ if( p[pixel[11]] > cb)
+ goto is_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ if( p[pixel[10]] > cb)
+ if( p[pixel[11]] > cb)
+ if( p[pixel[12]] > cb)
+ goto is_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ if( p[pixel[10]] > cb)
+ if( p[pixel[11]] > cb)
+ if( p[pixel[12]] > cb)
+ if( p[pixel[13]] > cb)
+ goto is_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ if( p[pixel[10]] > cb)
+ if( p[pixel[11]] > cb)
+ if( p[pixel[12]] > cb)
+ if( p[pixel[13]] > cb)
+ if( p[pixel[14]] > cb)
+ goto is_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ if( p[pixel[10]] > cb)
+ if( p[pixel[11]] > cb)
+ if( p[pixel[12]] > cb)
+ if( p[pixel[13]] > cb)
+ if( p[pixel[14]] > cb)
+ if( p[pixel[15]] > cb)
+ goto is_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else if( p[pixel[8]] < c_b)
+ if( p[pixel[9]] < c_b)
+ if( p[pixel[10]] < c_b)
+ if( p[pixel[11]] < c_b)
+ if( p[pixel[12]] < c_b)
+ if( p[pixel[13]] < c_b)
+ if( p[pixel[14]] < c_b)
+ if( p[pixel[15]] < c_b)
+ goto is_a_corner;
+ else
+ if( p[pixel[6]] < c_b)
+ if( p[pixel[7]] < c_b)
+ goto is_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ if( p[pixel[5]] < c_b)
+ if( p[pixel[6]] < c_b)
+ if( p[pixel[7]] < c_b)
+ goto is_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ if( p[pixel[4]] < c_b)
+ if( p[pixel[5]] < c_b)
+ if( p[pixel[6]] < c_b)
+ if( p[pixel[7]] < c_b)
+ goto is_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ if( p[pixel[3]] < c_b)
+ if( p[pixel[4]] < c_b)
+ if( p[pixel[5]] < c_b)
+ if( p[pixel[6]] < c_b)
+ if( p[pixel[7]] < c_b)
+ goto is_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ if( p[pixel[2]] < c_b)
+ if( p[pixel[3]] < c_b)
+ if( p[pixel[4]] < c_b)
+ if( p[pixel[5]] < c_b)
+ if( p[pixel[6]] < c_b)
+ if( p[pixel[7]] < c_b)
+ goto is_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else if( p[pixel[1]] < c_b)
+ if( p[pixel[2]] > cb)
+ if( p[pixel[9]] > cb)
+ if( p[pixel[7]] > cb)
+ if( p[pixel[8]] > cb)
+ if( p[pixel[10]] > cb)
+ if( p[pixel[6]] > cb)
+ if( p[pixel[5]] > cb)
+ if( p[pixel[4]] > cb)
+ if( p[pixel[3]] > cb)
+ goto is_a_corner;
+ else
+ if( p[pixel[11]] > cb)
+ if( p[pixel[12]] > cb)
+ goto is_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ if( p[pixel[11]] > cb)
+ if( p[pixel[12]] > cb)
+ if( p[pixel[13]] > cb)
+ goto is_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ if( p[pixel[11]] > cb)
+ if( p[pixel[12]] > cb)
+ if( p[pixel[13]] > cb)
+ if( p[pixel[14]] > cb)
+ goto is_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ if( p[pixel[11]] > cb)
+ if( p[pixel[12]] > cb)
+ if( p[pixel[13]] > cb)
+ if( p[pixel[14]] > cb)
+ if( p[pixel[15]] > cb)
+ goto is_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else if( p[pixel[9]] < c_b)
+ if( p[pixel[10]] < c_b)
+ if( p[pixel[11]] < c_b)
+ if( p[pixel[12]] < c_b)
+ if( p[pixel[13]] < c_b)
+ if( p[pixel[14]] < c_b)
+ if( p[pixel[15]] < c_b)
+ goto is_a_corner;
+ else
+ if( p[pixel[6]] < c_b)
+ if( p[pixel[7]] < c_b)
+ if( p[pixel[8]] < c_b)
+ goto is_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ if( p[pixel[5]] < c_b)
+ if( p[pixel[6]] < c_b)
+ if( p[pixel[7]] < c_b)
+ if( p[pixel[8]] < c_b)
+ goto is_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ if( p[pixel[4]] < c_b)
+ if( p[pixel[5]] < c_b)
+ if( p[pixel[6]] < c_b)
+ if( p[pixel[7]] < c_b)
+ if( p[pixel[8]] < c_b)
+ goto is_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ if( p[pixel[3]] < c_b)
+ if( p[pixel[4]] < c_b)
+ if( p[pixel[5]] < c_b)
+ if( p[pixel[6]] < c_b)
+ if( p[pixel[7]] < c_b)
+ if( p[pixel[8]] < c_b)
+ goto is_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else if( p[pixel[2]] < c_b)
+ if( p[pixel[3]] > cb)
+ if( p[pixel[10]] > cb)
+ if( p[pixel[7]] > cb)
+ if( p[pixel[8]] > cb)
+ if( p[pixel[9]] > cb)
+ if( p[pixel[11]] > cb)
+ if( p[pixel[6]] > cb)
+ if( p[pixel[5]] > cb)
+ if( p[pixel[4]] > cb)
+ goto is_a_corner;
+ else
+ if( p[pixel[12]] > cb)
+ if( p[pixel[13]] > cb)
+ goto is_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ if( p[pixel[12]] > cb)
+ if( p[pixel[13]] > cb)
+ if( p[pixel[14]] > cb)
+ goto is_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ if( p[pixel[12]] > cb)
+ if( p[pixel[13]] > cb)
+ if( p[pixel[14]] > cb)
+ if( p[pixel[15]] > cb)
+ goto is_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else if( p[pixel[10]] < c_b)
+ if( p[pixel[11]] < c_b)
+ if( p[pixel[12]] < c_b)
+ if( p[pixel[13]] < c_b)
+ if( p[pixel[14]] < c_b)
+ if( p[pixel[15]] < c_b)
+ goto is_a_corner;
+ else
+ if( p[pixel[6]] < c_b)
+ if( p[pixel[7]] < c_b)
+ if( p[pixel[8]] < c_b)
+ if( p[pixel[9]] < c_b)
+ goto is_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ if( p[pixel[5]] < c_b)
+ if( p[pixel[6]] < c_b)
+ if( p[pixel[7]] < c_b)
+ if( p[pixel[8]] < c_b)
+ if( p[pixel[9]] < c_b)
+ goto is_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ if( p[pixel[4]] < c_b)
+ if( p[pixel[5]] < c_b)
+ if( p[pixel[6]] < c_b)
+ if( p[pixel[7]] < c_b)
+ if( p[pixel[8]] < c_b)
+ if( p[pixel[9]] < c_b)
+ goto is_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else if( p[pixel[3]] < c_b)
+ if( p[pixel[4]] > cb)
+ if( p[pixel[13]] > cb)
+ if( p[pixel[7]] > cb)
+ if( p[pixel[8]] > cb)
+ if( p[pixel[9]] > cb)
+ if( p[pixel[10]] > cb)
+ if( p[pixel[11]] > cb)
+ if( p[pixel[12]] > cb)
+ if( p[pixel[6]] > cb)
+ if( p[pixel[5]] > cb)
+ goto is_a_corner;
+ else
+ if( p[pixel[14]] > cb)
+ goto is_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ if( p[pixel[14]] > cb)
+ if( p[pixel[15]] > cb)
+ goto is_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else if( p[pixel[13]] < c_b)
+ if( p[pixel[11]] > cb)
+ if( p[pixel[5]] > cb)
+ if( p[pixel[6]] > cb)
+ if( p[pixel[7]] > cb)
+ if( p[pixel[8]] > cb)
+ if( p[pixel[9]] > cb)
+ if( p[pixel[10]] > cb)
+ if( p[pixel[12]] > cb)
+ goto is_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else if( p[pixel[11]] < c_b)
+ if( p[pixel[12]] < c_b)
+ if( p[pixel[14]] < c_b)
+ if( p[pixel[15]] < c_b)
+ goto is_a_corner;
+ else
+ if( p[pixel[6]] < c_b)
+ if( p[pixel[7]] < c_b)
+ if( p[pixel[8]] < c_b)
+ if( p[pixel[9]] < c_b)
+ if( p[pixel[10]] < c_b)
+ goto is_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ if( p[pixel[5]] < c_b)
+ if( p[pixel[6]] < c_b)
+ if( p[pixel[7]] < c_b)
+ if( p[pixel[8]] < c_b)
+ if( p[pixel[9]] < c_b)
+ if( p[pixel[10]] < c_b)
+ goto is_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ if( p[pixel[5]] > cb)
+ if( p[pixel[6]] > cb)
+ if( p[pixel[7]] > cb)
+ if( p[pixel[8]] > cb)
+ if( p[pixel[9]] > cb)
+ if( p[pixel[10]] > cb)
+ if( p[pixel[11]] > cb)
+ if( p[pixel[12]] > cb)
+ goto is_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else if( p[pixel[4]] < c_b)
+ if( p[pixel[5]] > cb)
+ if( p[pixel[14]] > cb)
+ if( p[pixel[7]] > cb)
+ if( p[pixel[8]] > cb)
+ if( p[pixel[9]] > cb)
+ if( p[pixel[10]] > cb)
+ if( p[pixel[11]] > cb)
+ if( p[pixel[12]] > cb)
+ if( p[pixel[13]] > cb)
+ if( p[pixel[6]] > cb)
+ goto is_a_corner;
+ else
+ if( p[pixel[15]] > cb)
+ goto is_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else if( p[pixel[14]] < c_b)
+ if( p[pixel[12]] > cb)
+ if( p[pixel[6]] > cb)
+ if( p[pixel[7]] > cb)
+ if( p[pixel[8]] > cb)
+ if( p[pixel[9]] > cb)
+ if( p[pixel[10]] > cb)
+ if( p[pixel[11]] > cb)
+ if( p[pixel[13]] > cb)
+ goto is_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else if( p[pixel[12]] < c_b)
+ if( p[pixel[13]] < c_b)
+ if( p[pixel[15]] < c_b)
+ goto is_a_corner;
+ else
+ if( p[pixel[6]] < c_b)
+ if( p[pixel[7]] < c_b)
+ if( p[pixel[8]] < c_b)
+ if( p[pixel[9]] < c_b)
+ if( p[pixel[10]] < c_b)
+ if( p[pixel[11]] < c_b)
+ goto is_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ if( p[pixel[6]] > cb)
+ if( p[pixel[7]] > cb)
+ if( p[pixel[8]] > cb)
+ if( p[pixel[9]] > cb)
+ if( p[pixel[10]] > cb)
+ if( p[pixel[11]] > cb)
+ if( p[pixel[12]] > cb)
+ if( p[pixel[13]] > cb)
+ goto is_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else if( p[pixel[5]] < c_b)
+ if( p[pixel[6]] > cb)
+ if( p[pixel[15]] < c_b)
+ if( p[pixel[13]] > cb)
+ if( p[pixel[7]] > cb)
+ if( p[pixel[8]] > cb)
+ if( p[pixel[9]] > cb)
+ if( p[pixel[10]] > cb)
+ if( p[pixel[11]] > cb)
+ if( p[pixel[12]] > cb)
+ if( p[pixel[14]] > cb)
+ goto is_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else if( p[pixel[13]] < c_b)
+ if( p[pixel[14]] < c_b)
+ goto is_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ if( p[pixel[7]] > cb)
+ if( p[pixel[8]] > cb)
+ if( p[pixel[9]] > cb)
+ if( p[pixel[10]] > cb)
+ if( p[pixel[11]] > cb)
+ if( p[pixel[12]] > cb)
+ if( p[pixel[13]] > cb)
+ if( p[pixel[14]] > cb)
+ goto is_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else if( p[pixel[6]] < c_b)
+ if( p[pixel[7]] > cb)
+ if( p[pixel[14]] > cb)
+ if( p[pixel[8]] > cb)
+ if( p[pixel[9]] > cb)
+ if( p[pixel[10]] > cb)
+ if( p[pixel[11]] > cb)
+ if( p[pixel[12]] > cb)
+ if( p[pixel[13]] > cb)
+ if( p[pixel[15]] > cb)
+ goto is_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else if( p[pixel[14]] < c_b)
+ if( p[pixel[15]] < c_b)
+ goto is_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else if( p[pixel[7]] < c_b)
+ if( p[pixel[8]] < c_b)
+ goto is_a_corner;
+ else
+ if( p[pixel[15]] < c_b)
+ goto is_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ if( p[pixel[14]] < c_b)
+ if( p[pixel[15]] < c_b)
+ goto is_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ if( p[pixel[13]] > cb)
+ if( p[pixel[7]] > cb)
+ if( p[pixel[8]] > cb)
+ if( p[pixel[9]] > cb)
+ if( p[pixel[10]] > cb)
+ if( p[pixel[11]] > cb)
+ if( p[pixel[12]] > cb)
+ if( p[pixel[14]] > cb)
+ if( p[pixel[15]] > cb)
+ goto is_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else if( p[pixel[13]] < c_b)
+ if( p[pixel[14]] < c_b)
+ if( p[pixel[15]] < c_b)
+ goto is_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ if( p[pixel[12]] > cb)
+ if( p[pixel[7]] > cb)
+ if( p[pixel[8]] > cb)
+ if( p[pixel[9]] > cb)
+ if( p[pixel[10]] > cb)
+ if( p[pixel[11]] > cb)
+ if( p[pixel[13]] > cb)
+ if( p[pixel[14]] > cb)
+ if( p[pixel[6]] > cb)
+ goto is_a_corner;
+ else
+ if( p[pixel[15]] > cb)
+ goto is_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else if( p[pixel[12]] < c_b)
+ if( p[pixel[13]] < c_b)
+ if( p[pixel[14]] < c_b)
+ if( p[pixel[15]] < c_b)
+ goto is_a_corner;
+ else
+ if( p[pixel[6]] < c_b)
+ if( p[pixel[7]] < c_b)
+ if( p[pixel[8]] < c_b)
+ if( p[pixel[9]] < c_b)
+ if( p[pixel[10]] < c_b)
+ if( p[pixel[11]] < c_b)
+ goto is_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ if( p[pixel[11]] > cb)
+ if( p[pixel[7]] > cb)
+ if( p[pixel[8]] > cb)
+ if( p[pixel[9]] > cb)
+ if( p[pixel[10]] > cb)
+ if( p[pixel[12]] > cb)
+ if( p[pixel[13]] > cb)
+ if( p[pixel[6]] > cb)
+ if( p[pixel[5]] > cb)
+ goto is_a_corner;
+ else
+ if( p[pixel[14]] > cb)
+ goto is_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ if( p[pixel[14]] > cb)
+ if( p[pixel[15]] > cb)
+ goto is_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else if( p[pixel[11]] < c_b)
+ if( p[pixel[12]] < c_b)
+ if( p[pixel[13]] < c_b)
+ if( p[pixel[14]] < c_b)
+ if( p[pixel[15]] < c_b)
+ goto is_a_corner;
+ else
+ if( p[pixel[6]] < c_b)
+ if( p[pixel[7]] < c_b)
+ if( p[pixel[8]] < c_b)
+ if( p[pixel[9]] < c_b)
+ if( p[pixel[10]] < c_b)
+ goto is_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ if( p[pixel[5]] < c_b)
+ if( p[pixel[6]] < c_b)
+ if( p[pixel[7]] < c_b)
+ if( p[pixel[8]] < c_b)
+ if( p[pixel[9]] < c_b)
+ if( p[pixel[10]] < c_b)
+ goto is_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ if( p[pixel[10]] > cb)
+ if( p[pixel[7]] > cb)
+ if( p[pixel[8]] > cb)
+ if( p[pixel[9]] > cb)
+ if( p[pixel[11]] > cb)
+ if( p[pixel[12]] > cb)
+ if( p[pixel[6]] > cb)
+ if( p[pixel[5]] > cb)
+ if( p[pixel[4]] > cb)
+ goto is_a_corner;
+ else
+ if( p[pixel[13]] > cb)
+ goto is_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ if( p[pixel[13]] > cb)
+ if( p[pixel[14]] > cb)
+ goto is_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ if( p[pixel[13]] > cb)
+ if( p[pixel[14]] > cb)
+ if( p[pixel[15]] > cb)
+ goto is_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else if( p[pixel[10]] < c_b)
+ if( p[pixel[11]] < c_b)
+ if( p[pixel[12]] < c_b)
+ if( p[pixel[13]] < c_b)
+ if( p[pixel[14]] < c_b)
+ if( p[pixel[15]] < c_b)
+ goto is_a_corner;
+ else
+ if( p[pixel[6]] < c_b)
+ if( p[pixel[7]] < c_b)
+ if( p[pixel[8]] < c_b)
+ if( p[pixel[9]] < c_b)
+ goto is_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ if( p[pixel[5]] < c_b)
+ if( p[pixel[6]] < c_b)
+ if( p[pixel[7]] < c_b)
+ if( p[pixel[8]] < c_b)
+ if( p[pixel[9]] < c_b)
+ goto is_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ if( p[pixel[4]] < c_b)
+ if( p[pixel[5]] < c_b)
+ if( p[pixel[6]] < c_b)
+ if( p[pixel[7]] < c_b)
+ if( p[pixel[8]] < c_b)
+ if( p[pixel[9]] < c_b)
+ goto is_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ if( p[pixel[9]] > cb)
+ if( p[pixel[7]] > cb)
+ if( p[pixel[8]] > cb)
+ if( p[pixel[10]] > cb)
+ if( p[pixel[11]] > cb)
+ if( p[pixel[6]] > cb)
+ if( p[pixel[5]] > cb)
+ if( p[pixel[4]] > cb)
+ if( p[pixel[3]] > cb)
+ goto is_a_corner;
+ else
+ if( p[pixel[12]] > cb)
+ goto is_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ if( p[pixel[12]] > cb)
+ if( p[pixel[13]] > cb)
+ goto is_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ if( p[pixel[12]] > cb)
+ if( p[pixel[13]] > cb)
+ if( p[pixel[14]] > cb)
+ goto is_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ if( p[pixel[12]] > cb)
+ if( p[pixel[13]] > cb)
+ if( p[pixel[14]] > cb)
+ if( p[pixel[15]] > cb)
+ goto is_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else if( p[pixel[9]] < c_b)
+ if( p[pixel[10]] < c_b)
+ if( p[pixel[11]] < c_b)
+ if( p[pixel[12]] < c_b)
+ if( p[pixel[13]] < c_b)
+ if( p[pixel[14]] < c_b)
+ if( p[pixel[15]] < c_b)
+ goto is_a_corner;
+ else
+ if( p[pixel[6]] < c_b)
+ if( p[pixel[7]] < c_b)
+ if( p[pixel[8]] < c_b)
+ goto is_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ if( p[pixel[5]] < c_b)
+ if( p[pixel[6]] < c_b)
+ if( p[pixel[7]] < c_b)
+ if( p[pixel[8]] < c_b)
+ goto is_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ if( p[pixel[4]] < c_b)
+ if( p[pixel[5]] < c_b)
+ if( p[pixel[6]] < c_b)
+ if( p[pixel[7]] < c_b)
+ if( p[pixel[8]] < c_b)
+ goto is_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ if( p[pixel[3]] < c_b)
+ if( p[pixel[4]] < c_b)
+ if( p[pixel[5]] < c_b)
+ if( p[pixel[6]] < c_b)
+ if( p[pixel[7]] < c_b)
+ if( p[pixel[8]] < c_b)
+ goto is_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ if( p[pixel[8]] > cb)
+ if( p[pixel[7]] > cb)
+ if( p[pixel[9]] > cb)
+ if( p[pixel[10]] > cb)
+ if( p[pixel[6]] > cb)
+ if( p[pixel[5]] > cb)
+ if( p[pixel[4]] > cb)
+ if( p[pixel[3]] > cb)
+ if( p[pixel[2]] > cb)
+ goto is_a_corner;
+ else
+ if( p[pixel[11]] > cb)
+ goto is_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ if( p[pixel[11]] > cb)
+ if( p[pixel[12]] > cb)
+ goto is_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ if( p[pixel[11]] > cb)
+ if( p[pixel[12]] > cb)
+ if( p[pixel[13]] > cb)
+ goto is_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ if( p[pixel[11]] > cb)
+ if( p[pixel[12]] > cb)
+ if( p[pixel[13]] > cb)
+ if( p[pixel[14]] > cb)
+ goto is_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ if( p[pixel[11]] > cb)
+ if( p[pixel[12]] > cb)
+ if( p[pixel[13]] > cb)
+ if( p[pixel[14]] > cb)
+ if( p[pixel[15]] > cb)
+ goto is_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else if( p[pixel[8]] < c_b)
+ if( p[pixel[9]] < c_b)
+ if( p[pixel[10]] < c_b)
+ if( p[pixel[11]] < c_b)
+ if( p[pixel[12]] < c_b)
+ if( p[pixel[13]] < c_b)
+ if( p[pixel[14]] < c_b)
+ if( p[pixel[15]] < c_b)
+ goto is_a_corner;
+ else
+ if( p[pixel[6]] < c_b)
+ if( p[pixel[7]] < c_b)
+ goto is_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ if( p[pixel[5]] < c_b)
+ if( p[pixel[6]] < c_b)
+ if( p[pixel[7]] < c_b)
+ goto is_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ if( p[pixel[4]] < c_b)
+ if( p[pixel[5]] < c_b)
+ if( p[pixel[6]] < c_b)
+ if( p[pixel[7]] < c_b)
+ goto is_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ if( p[pixel[3]] < c_b)
+ if( p[pixel[4]] < c_b)
+ if( p[pixel[5]] < c_b)
+ if( p[pixel[6]] < c_b)
+ if( p[pixel[7]] < c_b)
+ goto is_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ if( p[pixel[2]] < c_b)
+ if( p[pixel[3]] < c_b)
+ if( p[pixel[4]] < c_b)
+ if( p[pixel[5]] < c_b)
+ if( p[pixel[6]] < c_b)
+ if( p[pixel[7]] < c_b)
+ goto is_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ if( p[pixel[7]] > cb)
+ if( p[pixel[8]] > cb)
+ if( p[pixel[9]] > cb)
+ if( p[pixel[6]] > cb)
+ if( p[pixel[5]] > cb)
+ if( p[pixel[4]] > cb)
+ if( p[pixel[3]] > cb)
+ if( p[pixel[2]] > cb)
+ if( p[pixel[1]] > cb)
+ goto is_a_corner;
+ else
+ if( p[pixel[10]] > cb)
+ goto is_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ if( p[pixel[10]] > cb)
+ if( p[pixel[11]] > cb)
+ goto is_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ if( p[pixel[10]] > cb)
+ if( p[pixel[11]] > cb)
+ if( p[pixel[12]] > cb)
+ goto is_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ if( p[pixel[10]] > cb)
+ if( p[pixel[11]] > cb)
+ if( p[pixel[12]] > cb)
+ if( p[pixel[13]] > cb)
+ goto is_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ if( p[pixel[10]] > cb)
+ if( p[pixel[11]] > cb)
+ if( p[pixel[12]] > cb)
+ if( p[pixel[13]] > cb)
+ if( p[pixel[14]] > cb)
+ goto is_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ if( p[pixel[10]] > cb)
+ if( p[pixel[11]] > cb)
+ if( p[pixel[12]] > cb)
+ if( p[pixel[13]] > cb)
+ if( p[pixel[14]] > cb)
+ if( p[pixel[15]] > cb)
+ goto is_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else if( p[pixel[7]] < c_b)
+ if( p[pixel[8]] < c_b)
+ if( p[pixel[9]] < c_b)
+ if( p[pixel[6]] < c_b)
+ if( p[pixel[5]] < c_b)
+ if( p[pixel[4]] < c_b)
+ if( p[pixel[3]] < c_b)
+ if( p[pixel[2]] < c_b)
+ if( p[pixel[1]] < c_b)
+ goto is_a_corner;
+ else
+ if( p[pixel[10]] < c_b)
+ goto is_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ if( p[pixel[10]] < c_b)
+ if( p[pixel[11]] < c_b)
+ goto is_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ if( p[pixel[10]] < c_b)
+ if( p[pixel[11]] < c_b)
+ if( p[pixel[12]] < c_b)
+ goto is_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ if( p[pixel[10]] < c_b)
+ if( p[pixel[11]] < c_b)
+ if( p[pixel[12]] < c_b)
+ if( p[pixel[13]] < c_b)
+ goto is_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ if( p[pixel[10]] < c_b)
+ if( p[pixel[11]] < c_b)
+ if( p[pixel[12]] < c_b)
+ if( p[pixel[13]] < c_b)
+ if( p[pixel[14]] < c_b)
+ goto is_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ if( p[pixel[10]] < c_b)
+ if( p[pixel[11]] < c_b)
+ if( p[pixel[12]] < c_b)
+ if( p[pixel[13]] < c_b)
+ if( p[pixel[14]] < c_b)
+ if( p[pixel[15]] < c_b)
+ goto is_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+ else
+ goto is_not_a_corner;
+
+ is_a_corner:
+ bmin=b;
+ goto end_if;
+
+ is_not_a_corner:
+ bmax=b;
+ goto end_if;
+
+ end_if:
+
+ if(bmin == bmax - 1 || bmin == bmax)
+ return bmin;
+ b = (bmin + bmax) / 2;
+ }
+}
+
+static void make_offsets(int pixel[], int row_stride)
+{
+ pixel[0] = 0 + row_stride * 3;
+ pixel[1] = 1 + row_stride * 3;
+ pixel[2] = 2 + row_stride * 2;
+ pixel[3] = 3 + row_stride * 1;
+ pixel[4] = 3 + row_stride * 0;
+ pixel[5] = 3 + row_stride * -1;
+ pixel[6] = 2 + row_stride * -2;
+ pixel[7] = 1 + row_stride * -3;
+ pixel[8] = 0 + row_stride * -3;
+ pixel[9] = -1 + row_stride * -3;
+ pixel[10] = -2 + row_stride * -2;
+ pixel[11] = -3 + row_stride * -1;
+ pixel[12] = -3 + row_stride * 0;
+ pixel[13] = -3 + row_stride * 1;
+ pixel[14] = -2 + row_stride * 2;
+ pixel[15] = -1 + row_stride * 3;
+}
+
+
+
+int* fast9_score(const byte* i, int stride, xy* corners, int num_corners, int b)
+{
+ int* scores = (int*)malloc(sizeof(int)* num_corners);
+ int n;
+
+ int pixel[16];
+ make_offsets(pixel, stride);
+
+ for(n=0; n < num_corners; n++)
+ scores[n] = fast9_corner_score(i + corners[n].y*stride + corners[n].x, pixel, b);
+
+ return scores;
+}
+
+
+xy* fast9_detect(const byte* im, int xsize, int ysize, int stride, int b, int* ret_num_corners)
+{
+ int num_corners=0;
+ xy* ret_corners;
+ int rsize=512;
+ int pixel[16];
+ int x, y;
+
+ ret_corners = (xy*)malloc(sizeof(xy)*rsize);
+ make_offsets(pixel, stride);
+
+ for(y=3; y < ysize - 3; y++)
+ for(x=3; x < xsize - 3; x++)
+ {
+ const byte* p = im + y*stride + x;
+
+ int cb = *p + b;
+ int c_b= *p - b;
+ if(p[pixel[0]] > cb)
+ if(p[pixel[1]] > cb)
+ if(p[pixel[2]] > cb)
+ if(p[pixel[3]] > cb)
+ if(p[pixel[4]] > cb)
+ if(p[pixel[5]] > cb)
+ if(p[pixel[6]] > cb)
+ if(p[pixel[7]] > cb)
+ if(p[pixel[8]] > cb)
+ {}
+ else
+ if(p[pixel[15]] > cb)
+ {}
+ else
+ continue;
+ else if(p[pixel[7]] < c_b)
+ if(p[pixel[14]] > cb)
+ if(p[pixel[15]] > cb)
+ {}
+ else
+ continue;
+ else if(p[pixel[14]] < c_b)
+ if(p[pixel[8]] < c_b)
+ if(p[pixel[9]] < c_b)
+ if(p[pixel[10]] < c_b)
+ if(p[pixel[11]] < c_b)
+ if(p[pixel[12]] < c_b)
+ if(p[pixel[13]] < c_b)
+ if(p[pixel[15]] < c_b)
+ {}
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ if(p[pixel[14]] > cb)
+ if(p[pixel[15]] > cb)
+ {}
+ else
+ continue;
+ else
+ continue;
+ else if(p[pixel[6]] < c_b)
+ if(p[pixel[15]] > cb)
+ if(p[pixel[13]] > cb)
+ if(p[pixel[14]] > cb)
+ {}
+ else
+ continue;
+ else if(p[pixel[13]] < c_b)
+ if(p[pixel[7]] < c_b)
+ if(p[pixel[8]] < c_b)
+ if(p[pixel[9]] < c_b)
+ if(p[pixel[10]] < c_b)
+ if(p[pixel[11]] < c_b)
+ if(p[pixel[12]] < c_b)
+ if(p[pixel[14]] < c_b)
+ {}
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ if(p[pixel[7]] < c_b)
+ if(p[pixel[8]] < c_b)
+ if(p[pixel[9]] < c_b)
+ if(p[pixel[10]] < c_b)
+ if(p[pixel[11]] < c_b)
+ if(p[pixel[12]] < c_b)
+ if(p[pixel[13]] < c_b)
+ if(p[pixel[14]] < c_b)
+ {}
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ if(p[pixel[13]] > cb)
+ if(p[pixel[14]] > cb)
+ if(p[pixel[15]] > cb)
+ {}
+ else
+ continue;
+ else
+ continue;
+ else if(p[pixel[13]] < c_b)
+ if(p[pixel[7]] < c_b)
+ if(p[pixel[8]] < c_b)
+ if(p[pixel[9]] < c_b)
+ if(p[pixel[10]] < c_b)
+ if(p[pixel[11]] < c_b)
+ if(p[pixel[12]] < c_b)
+ if(p[pixel[14]] < c_b)
+ if(p[pixel[15]] < c_b)
+ {}
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else if(p[pixel[5]] < c_b)
+ if(p[pixel[14]] > cb)
+ if(p[pixel[12]] > cb)
+ if(p[pixel[13]] > cb)
+ if(p[pixel[15]] > cb)
+ {}
+ else
+ if(p[pixel[6]] > cb)
+ if(p[pixel[7]] > cb)
+ if(p[pixel[8]] > cb)
+ if(p[pixel[9]] > cb)
+ if(p[pixel[10]] > cb)
+ if(p[pixel[11]] > cb)
+ {}
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else if(p[pixel[12]] < c_b)
+ if(p[pixel[6]] < c_b)
+ if(p[pixel[7]] < c_b)
+ if(p[pixel[8]] < c_b)
+ if(p[pixel[9]] < c_b)
+ if(p[pixel[10]] < c_b)
+ if(p[pixel[11]] < c_b)
+ if(p[pixel[13]] < c_b)
+ {}
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else if(p[pixel[14]] < c_b)
+ if(p[pixel[7]] < c_b)
+ if(p[pixel[8]] < c_b)
+ if(p[pixel[9]] < c_b)
+ if(p[pixel[10]] < c_b)
+ if(p[pixel[11]] < c_b)
+ if(p[pixel[12]] < c_b)
+ if(p[pixel[13]] < c_b)
+ if(p[pixel[6]] < c_b)
+ {}
+ else
+ if(p[pixel[15]] < c_b)
+ {}
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ if(p[pixel[6]] < c_b)
+ if(p[pixel[7]] < c_b)
+ if(p[pixel[8]] < c_b)
+ if(p[pixel[9]] < c_b)
+ if(p[pixel[10]] < c_b)
+ if(p[pixel[11]] < c_b)
+ if(p[pixel[12]] < c_b)
+ if(p[pixel[13]] < c_b)
+ {}
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ if(p[pixel[12]] > cb)
+ if(p[pixel[13]] > cb)
+ if(p[pixel[14]] > cb)
+ if(p[pixel[15]] > cb)
+ {}
+ else
+ if(p[pixel[6]] > cb)
+ if(p[pixel[7]] > cb)
+ if(p[pixel[8]] > cb)
+ if(p[pixel[9]] > cb)
+ if(p[pixel[10]] > cb)
+ if(p[pixel[11]] > cb)
+ {}
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else if(p[pixel[12]] < c_b)
+ if(p[pixel[7]] < c_b)
+ if(p[pixel[8]] < c_b)
+ if(p[pixel[9]] < c_b)
+ if(p[pixel[10]] < c_b)
+ if(p[pixel[11]] < c_b)
+ if(p[pixel[13]] < c_b)
+ if(p[pixel[14]] < c_b)
+ if(p[pixel[6]] < c_b)
+ {}
+ else
+ if(p[pixel[15]] < c_b)
+ {}
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else if(p[pixel[4]] < c_b)
+ if(p[pixel[13]] > cb)
+ if(p[pixel[11]] > cb)
+ if(p[pixel[12]] > cb)
+ if(p[pixel[14]] > cb)
+ if(p[pixel[15]] > cb)
+ {}
+ else
+ if(p[pixel[6]] > cb)
+ if(p[pixel[7]] > cb)
+ if(p[pixel[8]] > cb)
+ if(p[pixel[9]] > cb)
+ if(p[pixel[10]] > cb)
+ {}
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ if(p[pixel[5]] > cb)
+ if(p[pixel[6]] > cb)
+ if(p[pixel[7]] > cb)
+ if(p[pixel[8]] > cb)
+ if(p[pixel[9]] > cb)
+ if(p[pixel[10]] > cb)
+ {}
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else if(p[pixel[11]] < c_b)
+ if(p[pixel[5]] < c_b)
+ if(p[pixel[6]] < c_b)
+ if(p[pixel[7]] < c_b)
+ if(p[pixel[8]] < c_b)
+ if(p[pixel[9]] < c_b)
+ if(p[pixel[10]] < c_b)
+ if(p[pixel[12]] < c_b)
+ {}
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else if(p[pixel[13]] < c_b)
+ if(p[pixel[7]] < c_b)
+ if(p[pixel[8]] < c_b)
+ if(p[pixel[9]] < c_b)
+ if(p[pixel[10]] < c_b)
+ if(p[pixel[11]] < c_b)
+ if(p[pixel[12]] < c_b)
+ if(p[pixel[6]] < c_b)
+ if(p[pixel[5]] < c_b)
+ {}
+ else
+ if(p[pixel[14]] < c_b)
+ {}
+ else
+ continue;
+ else
+ if(p[pixel[14]] < c_b)
+ if(p[pixel[15]] < c_b)
+ {}
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ if(p[pixel[5]] < c_b)
+ if(p[pixel[6]] < c_b)
+ if(p[pixel[7]] < c_b)
+ if(p[pixel[8]] < c_b)
+ if(p[pixel[9]] < c_b)
+ if(p[pixel[10]] < c_b)
+ if(p[pixel[11]] < c_b)
+ if(p[pixel[12]] < c_b)
+ {}
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ if(p[pixel[11]] > cb)
+ if(p[pixel[12]] > cb)
+ if(p[pixel[13]] > cb)
+ if(p[pixel[14]] > cb)
+ if(p[pixel[15]] > cb)
+ {}
+ else
+ if(p[pixel[6]] > cb)
+ if(p[pixel[7]] > cb)
+ if(p[pixel[8]] > cb)
+ if(p[pixel[9]] > cb)
+ if(p[pixel[10]] > cb)
+ {}
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ if(p[pixel[5]] > cb)
+ if(p[pixel[6]] > cb)
+ if(p[pixel[7]] > cb)
+ if(p[pixel[8]] > cb)
+ if(p[pixel[9]] > cb)
+ if(p[pixel[10]] > cb)
+ {}
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else if(p[pixel[11]] < c_b)
+ if(p[pixel[7]] < c_b)
+ if(p[pixel[8]] < c_b)
+ if(p[pixel[9]] < c_b)
+ if(p[pixel[10]] < c_b)
+ if(p[pixel[12]] < c_b)
+ if(p[pixel[13]] < c_b)
+ if(p[pixel[6]] < c_b)
+ if(p[pixel[5]] < c_b)
+ {}
+ else
+ if(p[pixel[14]] < c_b)
+ {}
+ else
+ continue;
+ else
+ if(p[pixel[14]] < c_b)
+ if(p[pixel[15]] < c_b)
+ {}
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else if(p[pixel[3]] < c_b)
+ if(p[pixel[10]] > cb)
+ if(p[pixel[11]] > cb)
+ if(p[pixel[12]] > cb)
+ if(p[pixel[13]] > cb)
+ if(p[pixel[14]] > cb)
+ if(p[pixel[15]] > cb)
+ {}
+ else
+ if(p[pixel[6]] > cb)
+ if(p[pixel[7]] > cb)
+ if(p[pixel[8]] > cb)
+ if(p[pixel[9]] > cb)
+ {}
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ if(p[pixel[5]] > cb)
+ if(p[pixel[6]] > cb)
+ if(p[pixel[7]] > cb)
+ if(p[pixel[8]] > cb)
+ if(p[pixel[9]] > cb)
+ {}
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ if(p[pixel[4]] > cb)
+ if(p[pixel[5]] > cb)
+ if(p[pixel[6]] > cb)
+ if(p[pixel[7]] > cb)
+ if(p[pixel[8]] > cb)
+ if(p[pixel[9]] > cb)
+ {}
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else if(p[pixel[10]] < c_b)
+ if(p[pixel[7]] < c_b)
+ if(p[pixel[8]] < c_b)
+ if(p[pixel[9]] < c_b)
+ if(p[pixel[11]] < c_b)
+ if(p[pixel[6]] < c_b)
+ if(p[pixel[5]] < c_b)
+ if(p[pixel[4]] < c_b)
+ {}
+ else
+ if(p[pixel[12]] < c_b)
+ if(p[pixel[13]] < c_b)
+ {}
+ else
+ continue;
+ else
+ continue;
+ else
+ if(p[pixel[12]] < c_b)
+ if(p[pixel[13]] < c_b)
+ if(p[pixel[14]] < c_b)
+ {}
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ if(p[pixel[12]] < c_b)
+ if(p[pixel[13]] < c_b)
+ if(p[pixel[14]] < c_b)
+ if(p[pixel[15]] < c_b)
+ {}
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ if(p[pixel[10]] > cb)
+ if(p[pixel[11]] > cb)
+ if(p[pixel[12]] > cb)
+ if(p[pixel[13]] > cb)
+ if(p[pixel[14]] > cb)
+ if(p[pixel[15]] > cb)
+ {}
+ else
+ if(p[pixel[6]] > cb)
+ if(p[pixel[7]] > cb)
+ if(p[pixel[8]] > cb)
+ if(p[pixel[9]] > cb)
+ {}
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ if(p[pixel[5]] > cb)
+ if(p[pixel[6]] > cb)
+ if(p[pixel[7]] > cb)
+ if(p[pixel[8]] > cb)
+ if(p[pixel[9]] > cb)
+ {}
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ if(p[pixel[4]] > cb)
+ if(p[pixel[5]] > cb)
+ if(p[pixel[6]] > cb)
+ if(p[pixel[7]] > cb)
+ if(p[pixel[8]] > cb)
+ if(p[pixel[9]] > cb)
+ {}
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else if(p[pixel[10]] < c_b)
+ if(p[pixel[7]] < c_b)
+ if(p[pixel[8]] < c_b)
+ if(p[pixel[9]] < c_b)
+ if(p[pixel[11]] < c_b)
+ if(p[pixel[12]] < c_b)
+ if(p[pixel[6]] < c_b)
+ if(p[pixel[5]] < c_b)
+ if(p[pixel[4]] < c_b)
+ {}
+ else
+ if(p[pixel[13]] < c_b)
+ {}
+ else
+ continue;
+ else
+ if(p[pixel[13]] < c_b)
+ if(p[pixel[14]] < c_b)
+ {}
+ else
+ continue;
+ else
+ continue;
+ else
+ if(p[pixel[13]] < c_b)
+ if(p[pixel[14]] < c_b)
+ if(p[pixel[15]] < c_b)
+ {}
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else if(p[pixel[2]] < c_b)
+ if(p[pixel[9]] > cb)
+ if(p[pixel[10]] > cb)
+ if(p[pixel[11]] > cb)
+ if(p[pixel[12]] > cb)
+ if(p[pixel[13]] > cb)
+ if(p[pixel[14]] > cb)
+ if(p[pixel[15]] > cb)
+ {}
+ else
+ if(p[pixel[6]] > cb)
+ if(p[pixel[7]] > cb)
+ if(p[pixel[8]] > cb)
+ {}
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ if(p[pixel[5]] > cb)
+ if(p[pixel[6]] > cb)
+ if(p[pixel[7]] > cb)
+ if(p[pixel[8]] > cb)
+ {}
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ if(p[pixel[4]] > cb)
+ if(p[pixel[5]] > cb)
+ if(p[pixel[6]] > cb)
+ if(p[pixel[7]] > cb)
+ if(p[pixel[8]] > cb)
+ {}
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ if(p[pixel[3]] > cb)
+ if(p[pixel[4]] > cb)
+ if(p[pixel[5]] > cb)
+ if(p[pixel[6]] > cb)
+ if(p[pixel[7]] > cb)
+ if(p[pixel[8]] > cb)
+ {}
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else if(p[pixel[9]] < c_b)
+ if(p[pixel[7]] < c_b)
+ if(p[pixel[8]] < c_b)
+ if(p[pixel[10]] < c_b)
+ if(p[pixel[6]] < c_b)
+ if(p[pixel[5]] < c_b)
+ if(p[pixel[4]] < c_b)
+ if(p[pixel[3]] < c_b)
+ {}
+ else
+ if(p[pixel[11]] < c_b)
+ if(p[pixel[12]] < c_b)
+ {}
+ else
+ continue;
+ else
+ continue;
+ else
+ if(p[pixel[11]] < c_b)
+ if(p[pixel[12]] < c_b)
+ if(p[pixel[13]] < c_b)
+ {}
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ if(p[pixel[11]] < c_b)
+ if(p[pixel[12]] < c_b)
+ if(p[pixel[13]] < c_b)
+ if(p[pixel[14]] < c_b)
+ {}
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ if(p[pixel[11]] < c_b)
+ if(p[pixel[12]] < c_b)
+ if(p[pixel[13]] < c_b)
+ if(p[pixel[14]] < c_b)
+ if(p[pixel[15]] < c_b)
+ {}
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ if(p[pixel[9]] > cb)
+ if(p[pixel[10]] > cb)
+ if(p[pixel[11]] > cb)
+ if(p[pixel[12]] > cb)
+ if(p[pixel[13]] > cb)
+ if(p[pixel[14]] > cb)
+ if(p[pixel[15]] > cb)
+ {}
+ else
+ if(p[pixel[6]] > cb)
+ if(p[pixel[7]] > cb)
+ if(p[pixel[8]] > cb)
+ {}
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ if(p[pixel[5]] > cb)
+ if(p[pixel[6]] > cb)
+ if(p[pixel[7]] > cb)
+ if(p[pixel[8]] > cb)
+ {}
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ if(p[pixel[4]] > cb)
+ if(p[pixel[5]] > cb)
+ if(p[pixel[6]] > cb)
+ if(p[pixel[7]] > cb)
+ if(p[pixel[8]] > cb)
+ {}
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ if(p[pixel[3]] > cb)
+ if(p[pixel[4]] > cb)
+ if(p[pixel[5]] > cb)
+ if(p[pixel[6]] > cb)
+ if(p[pixel[7]] > cb)
+ if(p[pixel[8]] > cb)
+ {}
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else if(p[pixel[9]] < c_b)
+ if(p[pixel[7]] < c_b)
+ if(p[pixel[8]] < c_b)
+ if(p[pixel[10]] < c_b)
+ if(p[pixel[11]] < c_b)
+ if(p[pixel[6]] < c_b)
+ if(p[pixel[5]] < c_b)
+ if(p[pixel[4]] < c_b)
+ if(p[pixel[3]] < c_b)
+ {}
+ else
+ if(p[pixel[12]] < c_b)
+ {}
+ else
+ continue;
+ else
+ if(p[pixel[12]] < c_b)
+ if(p[pixel[13]] < c_b)
+ {}
+ else
+ continue;
+ else
+ continue;
+ else
+ if(p[pixel[12]] < c_b)
+ if(p[pixel[13]] < c_b)
+ if(p[pixel[14]] < c_b)
+ {}
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ if(p[pixel[12]] < c_b)
+ if(p[pixel[13]] < c_b)
+ if(p[pixel[14]] < c_b)
+ if(p[pixel[15]] < c_b)
+ {}
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else if(p[pixel[1]] < c_b)
+ if(p[pixel[8]] > cb)
+ if(p[pixel[9]] > cb)
+ if(p[pixel[10]] > cb)
+ if(p[pixel[11]] > cb)
+ if(p[pixel[12]] > cb)
+ if(p[pixel[13]] > cb)
+ if(p[pixel[14]] > cb)
+ if(p[pixel[15]] > cb)
+ {}
+ else
+ if(p[pixel[6]] > cb)
+ if(p[pixel[7]] > cb)
+ {}
+ else
+ continue;
+ else
+ continue;
+ else
+ if(p[pixel[5]] > cb)
+ if(p[pixel[6]] > cb)
+ if(p[pixel[7]] > cb)
+ {}
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ if(p[pixel[4]] > cb)
+ if(p[pixel[5]] > cb)
+ if(p[pixel[6]] > cb)
+ if(p[pixel[7]] > cb)
+ {}
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ if(p[pixel[3]] > cb)
+ if(p[pixel[4]] > cb)
+ if(p[pixel[5]] > cb)
+ if(p[pixel[6]] > cb)
+ if(p[pixel[7]] > cb)
+ {}
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ if(p[pixel[2]] > cb)
+ if(p[pixel[3]] > cb)
+ if(p[pixel[4]] > cb)
+ if(p[pixel[5]] > cb)
+ if(p[pixel[6]] > cb)
+ if(p[pixel[7]] > cb)
+ {}
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else if(p[pixel[8]] < c_b)
+ if(p[pixel[7]] < c_b)
+ if(p[pixel[9]] < c_b)
+ if(p[pixel[6]] < c_b)
+ if(p[pixel[5]] < c_b)
+ if(p[pixel[4]] < c_b)
+ if(p[pixel[3]] < c_b)
+ if(p[pixel[2]] < c_b)
+ {}
+ else
+ if(p[pixel[10]] < c_b)
+ if(p[pixel[11]] < c_b)
+ {}
+ else
+ continue;
+ else
+ continue;
+ else
+ if(p[pixel[10]] < c_b)
+ if(p[pixel[11]] < c_b)
+ if(p[pixel[12]] < c_b)
+ {}
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ if(p[pixel[10]] < c_b)
+ if(p[pixel[11]] < c_b)
+ if(p[pixel[12]] < c_b)
+ if(p[pixel[13]] < c_b)
+ {}
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ if(p[pixel[10]] < c_b)
+ if(p[pixel[11]] < c_b)
+ if(p[pixel[12]] < c_b)
+ if(p[pixel[13]] < c_b)
+ if(p[pixel[14]] < c_b)
+ {}
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ if(p[pixel[10]] < c_b)
+ if(p[pixel[11]] < c_b)
+ if(p[pixel[12]] < c_b)
+ if(p[pixel[13]] < c_b)
+ if(p[pixel[14]] < c_b)
+ if(p[pixel[15]] < c_b)
+ {}
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ if(p[pixel[8]] > cb)
+ if(p[pixel[9]] > cb)
+ if(p[pixel[10]] > cb)
+ if(p[pixel[11]] > cb)
+ if(p[pixel[12]] > cb)
+ if(p[pixel[13]] > cb)
+ if(p[pixel[14]] > cb)
+ if(p[pixel[15]] > cb)
+ {}
+ else
+ if(p[pixel[6]] > cb)
+ if(p[pixel[7]] > cb)
+ {}
+ else
+ continue;
+ else
+ continue;
+ else
+ if(p[pixel[5]] > cb)
+ if(p[pixel[6]] > cb)
+ if(p[pixel[7]] > cb)
+ {}
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ if(p[pixel[4]] > cb)
+ if(p[pixel[5]] > cb)
+ if(p[pixel[6]] > cb)
+ if(p[pixel[7]] > cb)
+ {}
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ if(p[pixel[3]] > cb)
+ if(p[pixel[4]] > cb)
+ if(p[pixel[5]] > cb)
+ if(p[pixel[6]] > cb)
+ if(p[pixel[7]] > cb)
+ {}
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ if(p[pixel[2]] > cb)
+ if(p[pixel[3]] > cb)
+ if(p[pixel[4]] > cb)
+ if(p[pixel[5]] > cb)
+ if(p[pixel[6]] > cb)
+ if(p[pixel[7]] > cb)
+ {}
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else if(p[pixel[8]] < c_b)
+ if(p[pixel[7]] < c_b)
+ if(p[pixel[9]] < c_b)
+ if(p[pixel[10]] < c_b)
+ if(p[pixel[6]] < c_b)
+ if(p[pixel[5]] < c_b)
+ if(p[pixel[4]] < c_b)
+ if(p[pixel[3]] < c_b)
+ if(p[pixel[2]] < c_b)
+ {}
+ else
+ if(p[pixel[11]] < c_b)
+ {}
+ else
+ continue;
+ else
+ if(p[pixel[11]] < c_b)
+ if(p[pixel[12]] < c_b)
+ {}
+ else
+ continue;
+ else
+ continue;
+ else
+ if(p[pixel[11]] < c_b)
+ if(p[pixel[12]] < c_b)
+ if(p[pixel[13]] < c_b)
+ {}
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ if(p[pixel[11]] < c_b)
+ if(p[pixel[12]] < c_b)
+ if(p[pixel[13]] < c_b)
+ if(p[pixel[14]] < c_b)
+ {}
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ if(p[pixel[11]] < c_b)
+ if(p[pixel[12]] < c_b)
+ if(p[pixel[13]] < c_b)
+ if(p[pixel[14]] < c_b)
+ if(p[pixel[15]] < c_b)
+ {}
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else if(p[pixel[0]] < c_b)
+ if(p[pixel[1]] > cb)
+ if(p[pixel[8]] > cb)
+ if(p[pixel[7]] > cb)
+ if(p[pixel[9]] > cb)
+ if(p[pixel[6]] > cb)
+ if(p[pixel[5]] > cb)
+ if(p[pixel[4]] > cb)
+ if(p[pixel[3]] > cb)
+ if(p[pixel[2]] > cb)
+ {}
+ else
+ if(p[pixel[10]] > cb)
+ if(p[pixel[11]] > cb)
+ {}
+ else
+ continue;
+ else
+ continue;
+ else
+ if(p[pixel[10]] > cb)
+ if(p[pixel[11]] > cb)
+ if(p[pixel[12]] > cb)
+ {}
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ if(p[pixel[10]] > cb)
+ if(p[pixel[11]] > cb)
+ if(p[pixel[12]] > cb)
+ if(p[pixel[13]] > cb)
+ {}
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ if(p[pixel[10]] > cb)
+ if(p[pixel[11]] > cb)
+ if(p[pixel[12]] > cb)
+ if(p[pixel[13]] > cb)
+ if(p[pixel[14]] > cb)
+ {}
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ if(p[pixel[10]] > cb)
+ if(p[pixel[11]] > cb)
+ if(p[pixel[12]] > cb)
+ if(p[pixel[13]] > cb)
+ if(p[pixel[14]] > cb)
+ if(p[pixel[15]] > cb)
+ {}
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else if(p[pixel[8]] < c_b)
+ if(p[pixel[9]] < c_b)
+ if(p[pixel[10]] < c_b)
+ if(p[pixel[11]] < c_b)
+ if(p[pixel[12]] < c_b)
+ if(p[pixel[13]] < c_b)
+ if(p[pixel[14]] < c_b)
+ if(p[pixel[15]] < c_b)
+ {}
+ else
+ if(p[pixel[6]] < c_b)
+ if(p[pixel[7]] < c_b)
+ {}
+ else
+ continue;
+ else
+ continue;
+ else
+ if(p[pixel[5]] < c_b)
+ if(p[pixel[6]] < c_b)
+ if(p[pixel[7]] < c_b)
+ {}
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ if(p[pixel[4]] < c_b)
+ if(p[pixel[5]] < c_b)
+ if(p[pixel[6]] < c_b)
+ if(p[pixel[7]] < c_b)
+ {}
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ if(p[pixel[3]] < c_b)
+ if(p[pixel[4]] < c_b)
+ if(p[pixel[5]] < c_b)
+ if(p[pixel[6]] < c_b)
+ if(p[pixel[7]] < c_b)
+ {}
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ if(p[pixel[2]] < c_b)
+ if(p[pixel[3]] < c_b)
+ if(p[pixel[4]] < c_b)
+ if(p[pixel[5]] < c_b)
+ if(p[pixel[6]] < c_b)
+ if(p[pixel[7]] < c_b)
+ {}
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else if(p[pixel[1]] < c_b)
+ if(p[pixel[2]] > cb)
+ if(p[pixel[9]] > cb)
+ if(p[pixel[7]] > cb)
+ if(p[pixel[8]] > cb)
+ if(p[pixel[10]] > cb)
+ if(p[pixel[6]] > cb)
+ if(p[pixel[5]] > cb)
+ if(p[pixel[4]] > cb)
+ if(p[pixel[3]] > cb)
+ {}
+ else
+ if(p[pixel[11]] > cb)
+ if(p[pixel[12]] > cb)
+ {}
+ else
+ continue;
+ else
+ continue;
+ else
+ if(p[pixel[11]] > cb)
+ if(p[pixel[12]] > cb)
+ if(p[pixel[13]] > cb)
+ {}
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ if(p[pixel[11]] > cb)
+ if(p[pixel[12]] > cb)
+ if(p[pixel[13]] > cb)
+ if(p[pixel[14]] > cb)
+ {}
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ if(p[pixel[11]] > cb)
+ if(p[pixel[12]] > cb)
+ if(p[pixel[13]] > cb)
+ if(p[pixel[14]] > cb)
+ if(p[pixel[15]] > cb)
+ {}
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else if(p[pixel[9]] < c_b)
+ if(p[pixel[10]] < c_b)
+ if(p[pixel[11]] < c_b)
+ if(p[pixel[12]] < c_b)
+ if(p[pixel[13]] < c_b)
+ if(p[pixel[14]] < c_b)
+ if(p[pixel[15]] < c_b)
+ {}
+ else
+ if(p[pixel[6]] < c_b)
+ if(p[pixel[7]] < c_b)
+ if(p[pixel[8]] < c_b)
+ {}
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ if(p[pixel[5]] < c_b)
+ if(p[pixel[6]] < c_b)
+ if(p[pixel[7]] < c_b)
+ if(p[pixel[8]] < c_b)
+ {}
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ if(p[pixel[4]] < c_b)
+ if(p[pixel[5]] < c_b)
+ if(p[pixel[6]] < c_b)
+ if(p[pixel[7]] < c_b)
+ if(p[pixel[8]] < c_b)
+ {}
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ if(p[pixel[3]] < c_b)
+ if(p[pixel[4]] < c_b)
+ if(p[pixel[5]] < c_b)
+ if(p[pixel[6]] < c_b)
+ if(p[pixel[7]] < c_b)
+ if(p[pixel[8]] < c_b)
+ {}
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else if(p[pixel[2]] < c_b)
+ if(p[pixel[3]] > cb)
+ if(p[pixel[10]] > cb)
+ if(p[pixel[7]] > cb)
+ if(p[pixel[8]] > cb)
+ if(p[pixel[9]] > cb)
+ if(p[pixel[11]] > cb)
+ if(p[pixel[6]] > cb)
+ if(p[pixel[5]] > cb)
+ if(p[pixel[4]] > cb)
+ {}
+ else
+ if(p[pixel[12]] > cb)
+ if(p[pixel[13]] > cb)
+ {}
+ else
+ continue;
+ else
+ continue;
+ else
+ if(p[pixel[12]] > cb)
+ if(p[pixel[13]] > cb)
+ if(p[pixel[14]] > cb)
+ {}
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ if(p[pixel[12]] > cb)
+ if(p[pixel[13]] > cb)
+ if(p[pixel[14]] > cb)
+ if(p[pixel[15]] > cb)
+ {}
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else if(p[pixel[10]] < c_b)
+ if(p[pixel[11]] < c_b)
+ if(p[pixel[12]] < c_b)
+ if(p[pixel[13]] < c_b)
+ if(p[pixel[14]] < c_b)
+ if(p[pixel[15]] < c_b)
+ {}
+ else
+ if(p[pixel[6]] < c_b)
+ if(p[pixel[7]] < c_b)
+ if(p[pixel[8]] < c_b)
+ if(p[pixel[9]] < c_b)
+ {}
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ if(p[pixel[5]] < c_b)
+ if(p[pixel[6]] < c_b)
+ if(p[pixel[7]] < c_b)
+ if(p[pixel[8]] < c_b)
+ if(p[pixel[9]] < c_b)
+ {}
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ if(p[pixel[4]] < c_b)
+ if(p[pixel[5]] < c_b)
+ if(p[pixel[6]] < c_b)
+ if(p[pixel[7]] < c_b)
+ if(p[pixel[8]] < c_b)
+ if(p[pixel[9]] < c_b)
+ {}
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else if(p[pixel[3]] < c_b)
+ if(p[pixel[4]] > cb)
+ if(p[pixel[13]] > cb)
+ if(p[pixel[7]] > cb)
+ if(p[pixel[8]] > cb)
+ if(p[pixel[9]] > cb)
+ if(p[pixel[10]] > cb)
+ if(p[pixel[11]] > cb)
+ if(p[pixel[12]] > cb)
+ if(p[pixel[6]] > cb)
+ if(p[pixel[5]] > cb)
+ {}
+ else
+ if(p[pixel[14]] > cb)
+ {}
+ else
+ continue;
+ else
+ if(p[pixel[14]] > cb)
+ if(p[pixel[15]] > cb)
+ {}
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else if(p[pixel[13]] < c_b)
+ if(p[pixel[11]] > cb)
+ if(p[pixel[5]] > cb)
+ if(p[pixel[6]] > cb)
+ if(p[pixel[7]] > cb)
+ if(p[pixel[8]] > cb)
+ if(p[pixel[9]] > cb)
+ if(p[pixel[10]] > cb)
+ if(p[pixel[12]] > cb)
+ {}
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else if(p[pixel[11]] < c_b)
+ if(p[pixel[12]] < c_b)
+ if(p[pixel[14]] < c_b)
+ if(p[pixel[15]] < c_b)
+ {}
+ else
+ if(p[pixel[6]] < c_b)
+ if(p[pixel[7]] < c_b)
+ if(p[pixel[8]] < c_b)
+ if(p[pixel[9]] < c_b)
+ if(p[pixel[10]] < c_b)
+ {}
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ if(p[pixel[5]] < c_b)
+ if(p[pixel[6]] < c_b)
+ if(p[pixel[7]] < c_b)
+ if(p[pixel[8]] < c_b)
+ if(p[pixel[9]] < c_b)
+ if(p[pixel[10]] < c_b)
+ {}
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ if(p[pixel[5]] > cb)
+ if(p[pixel[6]] > cb)
+ if(p[pixel[7]] > cb)
+ if(p[pixel[8]] > cb)
+ if(p[pixel[9]] > cb)
+ if(p[pixel[10]] > cb)
+ if(p[pixel[11]] > cb)
+ if(p[pixel[12]] > cb)
+ {}
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else if(p[pixel[4]] < c_b)
+ if(p[pixel[5]] > cb)
+ if(p[pixel[14]] > cb)
+ if(p[pixel[7]] > cb)
+ if(p[pixel[8]] > cb)
+ if(p[pixel[9]] > cb)
+ if(p[pixel[10]] > cb)
+ if(p[pixel[11]] > cb)
+ if(p[pixel[12]] > cb)
+ if(p[pixel[13]] > cb)
+ if(p[pixel[6]] > cb)
+ {}
+ else
+ if(p[pixel[15]] > cb)
+ {}
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else if(p[pixel[14]] < c_b)
+ if(p[pixel[12]] > cb)
+ if(p[pixel[6]] > cb)
+ if(p[pixel[7]] > cb)
+ if(p[pixel[8]] > cb)
+ if(p[pixel[9]] > cb)
+ if(p[pixel[10]] > cb)
+ if(p[pixel[11]] > cb)
+ if(p[pixel[13]] > cb)
+ {}
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else if(p[pixel[12]] < c_b)
+ if(p[pixel[13]] < c_b)
+ if(p[pixel[15]] < c_b)
+ {}
+ else
+ if(p[pixel[6]] < c_b)
+ if(p[pixel[7]] < c_b)
+ if(p[pixel[8]] < c_b)
+ if(p[pixel[9]] < c_b)
+ if(p[pixel[10]] < c_b)
+ if(p[pixel[11]] < c_b)
+ {}
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ if(p[pixel[6]] > cb)
+ if(p[pixel[7]] > cb)
+ if(p[pixel[8]] > cb)
+ if(p[pixel[9]] > cb)
+ if(p[pixel[10]] > cb)
+ if(p[pixel[11]] > cb)
+ if(p[pixel[12]] > cb)
+ if(p[pixel[13]] > cb)
+ {}
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else if(p[pixel[5]] < c_b)
+ if(p[pixel[6]] > cb)
+ if(p[pixel[15]] < c_b)
+ if(p[pixel[13]] > cb)
+ if(p[pixel[7]] > cb)
+ if(p[pixel[8]] > cb)
+ if(p[pixel[9]] > cb)
+ if(p[pixel[10]] > cb)
+ if(p[pixel[11]] > cb)
+ if(p[pixel[12]] > cb)
+ if(p[pixel[14]] > cb)
+ {}
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else if(p[pixel[13]] < c_b)
+ if(p[pixel[14]] < c_b)
+ {}
+ else
+ continue;
+ else
+ continue;
+ else
+ if(p[pixel[7]] > cb)
+ if(p[pixel[8]] > cb)
+ if(p[pixel[9]] > cb)
+ if(p[pixel[10]] > cb)
+ if(p[pixel[11]] > cb)
+ if(p[pixel[12]] > cb)
+ if(p[pixel[13]] > cb)
+ if(p[pixel[14]] > cb)
+ {}
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else if(p[pixel[6]] < c_b)
+ if(p[pixel[7]] > cb)
+ if(p[pixel[14]] > cb)
+ if(p[pixel[8]] > cb)
+ if(p[pixel[9]] > cb)
+ if(p[pixel[10]] > cb)
+ if(p[pixel[11]] > cb)
+ if(p[pixel[12]] > cb)
+ if(p[pixel[13]] > cb)
+ if(p[pixel[15]] > cb)
+ {}
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else if(p[pixel[14]] < c_b)
+ if(p[pixel[15]] < c_b)
+ {}
+ else
+ continue;
+ else
+ continue;
+ else if(p[pixel[7]] < c_b)
+ if(p[pixel[8]] < c_b)
+ {}
+ else
+ if(p[pixel[15]] < c_b)
+ {}
+ else
+ continue;
+ else
+ if(p[pixel[14]] < c_b)
+ if(p[pixel[15]] < c_b)
+ {}
+ else
+ continue;
+ else
+ continue;
+ else
+ if(p[pixel[13]] > cb)
+ if(p[pixel[7]] > cb)
+ if(p[pixel[8]] > cb)
+ if(p[pixel[9]] > cb)
+ if(p[pixel[10]] > cb)
+ if(p[pixel[11]] > cb)
+ if(p[pixel[12]] > cb)
+ if(p[pixel[14]] > cb)
+ if(p[pixel[15]] > cb)
+ {}
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else if(p[pixel[13]] < c_b)
+ if(p[pixel[14]] < c_b)
+ if(p[pixel[15]] < c_b)
+ {}
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ if(p[pixel[12]] > cb)
+ if(p[pixel[7]] > cb)
+ if(p[pixel[8]] > cb)
+ if(p[pixel[9]] > cb)
+ if(p[pixel[10]] > cb)
+ if(p[pixel[11]] > cb)
+ if(p[pixel[13]] > cb)
+ if(p[pixel[14]] > cb)
+ if(p[pixel[6]] > cb)
+ {}
+ else
+ if(p[pixel[15]] > cb)
+ {}
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else if(p[pixel[12]] < c_b)
+ if(p[pixel[13]] < c_b)
+ if(p[pixel[14]] < c_b)
+ if(p[pixel[15]] < c_b)
+ {}
+ else
+ if(p[pixel[6]] < c_b)
+ if(p[pixel[7]] < c_b)
+ if(p[pixel[8]] < c_b)
+ if(p[pixel[9]] < c_b)
+ if(p[pixel[10]] < c_b)
+ if(p[pixel[11]] < c_b)
+ {}
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ if(p[pixel[11]] > cb)
+ if(p[pixel[7]] > cb)
+ if(p[pixel[8]] > cb)
+ if(p[pixel[9]] > cb)
+ if(p[pixel[10]] > cb)
+ if(p[pixel[12]] > cb)
+ if(p[pixel[13]] > cb)
+ if(p[pixel[6]] > cb)
+ if(p[pixel[5]] > cb)
+ {}
+ else
+ if(p[pixel[14]] > cb)
+ {}
+ else
+ continue;
+ else
+ if(p[pixel[14]] > cb)
+ if(p[pixel[15]] > cb)
+ {}
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else if(p[pixel[11]] < c_b)
+ if(p[pixel[12]] < c_b)
+ if(p[pixel[13]] < c_b)
+ if(p[pixel[14]] < c_b)
+ if(p[pixel[15]] < c_b)
+ {}
+ else
+ if(p[pixel[6]] < c_b)
+ if(p[pixel[7]] < c_b)
+ if(p[pixel[8]] < c_b)
+ if(p[pixel[9]] < c_b)
+ if(p[pixel[10]] < c_b)
+ {}
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ if(p[pixel[5]] < c_b)
+ if(p[pixel[6]] < c_b)
+ if(p[pixel[7]] < c_b)
+ if(p[pixel[8]] < c_b)
+ if(p[pixel[9]] < c_b)
+ if(p[pixel[10]] < c_b)
+ {}
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ if(p[pixel[10]] > cb)
+ if(p[pixel[7]] > cb)
+ if(p[pixel[8]] > cb)
+ if(p[pixel[9]] > cb)
+ if(p[pixel[11]] > cb)
+ if(p[pixel[12]] > cb)
+ if(p[pixel[6]] > cb)
+ if(p[pixel[5]] > cb)
+ if(p[pixel[4]] > cb)
+ {}
+ else
+ if(p[pixel[13]] > cb)
+ {}
+ else
+ continue;
+ else
+ if(p[pixel[13]] > cb)
+ if(p[pixel[14]] > cb)
+ {}
+ else
+ continue;
+ else
+ continue;
+ else
+ if(p[pixel[13]] > cb)
+ if(p[pixel[14]] > cb)
+ if(p[pixel[15]] > cb)
+ {}
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else if(p[pixel[10]] < c_b)
+ if(p[pixel[11]] < c_b)
+ if(p[pixel[12]] < c_b)
+ if(p[pixel[13]] < c_b)
+ if(p[pixel[14]] < c_b)
+ if(p[pixel[15]] < c_b)
+ {}
+ else
+ if(p[pixel[6]] < c_b)
+ if(p[pixel[7]] < c_b)
+ if(p[pixel[8]] < c_b)
+ if(p[pixel[9]] < c_b)
+ {}
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ if(p[pixel[5]] < c_b)
+ if(p[pixel[6]] < c_b)
+ if(p[pixel[7]] < c_b)
+ if(p[pixel[8]] < c_b)
+ if(p[pixel[9]] < c_b)
+ {}
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ if(p[pixel[4]] < c_b)
+ if(p[pixel[5]] < c_b)
+ if(p[pixel[6]] < c_b)
+ if(p[pixel[7]] < c_b)
+ if(p[pixel[8]] < c_b)
+ if(p[pixel[9]] < c_b)
+ {}
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ if(p[pixel[9]] > cb)
+ if(p[pixel[7]] > cb)
+ if(p[pixel[8]] > cb)
+ if(p[pixel[10]] > cb)
+ if(p[pixel[11]] > cb)
+ if(p[pixel[6]] > cb)
+ if(p[pixel[5]] > cb)
+ if(p[pixel[4]] > cb)
+ if(p[pixel[3]] > cb)
+ {}
+ else
+ if(p[pixel[12]] > cb)
+ {}
+ else
+ continue;
+ else
+ if(p[pixel[12]] > cb)
+ if(p[pixel[13]] > cb)
+ {}
+ else
+ continue;
+ else
+ continue;
+ else
+ if(p[pixel[12]] > cb)
+ if(p[pixel[13]] > cb)
+ if(p[pixel[14]] > cb)
+ {}
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ if(p[pixel[12]] > cb)
+ if(p[pixel[13]] > cb)
+ if(p[pixel[14]] > cb)
+ if(p[pixel[15]] > cb)
+ {}
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else if(p[pixel[9]] < c_b)
+ if(p[pixel[10]] < c_b)
+ if(p[pixel[11]] < c_b)
+ if(p[pixel[12]] < c_b)
+ if(p[pixel[13]] < c_b)
+ if(p[pixel[14]] < c_b)
+ if(p[pixel[15]] < c_b)
+ {}
+ else
+ if(p[pixel[6]] < c_b)
+ if(p[pixel[7]] < c_b)
+ if(p[pixel[8]] < c_b)
+ {}
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ if(p[pixel[5]] < c_b)
+ if(p[pixel[6]] < c_b)
+ if(p[pixel[7]] < c_b)
+ if(p[pixel[8]] < c_b)
+ {}
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ if(p[pixel[4]] < c_b)
+ if(p[pixel[5]] < c_b)
+ if(p[pixel[6]] < c_b)
+ if(p[pixel[7]] < c_b)
+ if(p[pixel[8]] < c_b)
+ {}
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ if(p[pixel[3]] < c_b)
+ if(p[pixel[4]] < c_b)
+ if(p[pixel[5]] < c_b)
+ if(p[pixel[6]] < c_b)
+ if(p[pixel[7]] < c_b)
+ if(p[pixel[8]] < c_b)
+ {}
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ if(p[pixel[8]] > cb)
+ if(p[pixel[7]] > cb)
+ if(p[pixel[9]] > cb)
+ if(p[pixel[10]] > cb)
+ if(p[pixel[6]] > cb)
+ if(p[pixel[5]] > cb)
+ if(p[pixel[4]] > cb)
+ if(p[pixel[3]] > cb)
+ if(p[pixel[2]] > cb)
+ {}
+ else
+ if(p[pixel[11]] > cb)
+ {}
+ else
+ continue;
+ else
+ if(p[pixel[11]] > cb)
+ if(p[pixel[12]] > cb)
+ {}
+ else
+ continue;
+ else
+ continue;
+ else
+ if(p[pixel[11]] > cb)
+ if(p[pixel[12]] > cb)
+ if(p[pixel[13]] > cb)
+ {}
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ if(p[pixel[11]] > cb)
+ if(p[pixel[12]] > cb)
+ if(p[pixel[13]] > cb)
+ if(p[pixel[14]] > cb)
+ {}
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ if(p[pixel[11]] > cb)
+ if(p[pixel[12]] > cb)
+ if(p[pixel[13]] > cb)
+ if(p[pixel[14]] > cb)
+ if(p[pixel[15]] > cb)
+ {}
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else if(p[pixel[8]] < c_b)
+ if(p[pixel[9]] < c_b)
+ if(p[pixel[10]] < c_b)
+ if(p[pixel[11]] < c_b)
+ if(p[pixel[12]] < c_b)
+ if(p[pixel[13]] < c_b)
+ if(p[pixel[14]] < c_b)
+ if(p[pixel[15]] < c_b)
+ {}
+ else
+ if(p[pixel[6]] < c_b)
+ if(p[pixel[7]] < c_b)
+ {}
+ else
+ continue;
+ else
+ continue;
+ else
+ if(p[pixel[5]] < c_b)
+ if(p[pixel[6]] < c_b)
+ if(p[pixel[7]] < c_b)
+ {}
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ if(p[pixel[4]] < c_b)
+ if(p[pixel[5]] < c_b)
+ if(p[pixel[6]] < c_b)
+ if(p[pixel[7]] < c_b)
+ {}
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ if(p[pixel[3]] < c_b)
+ if(p[pixel[4]] < c_b)
+ if(p[pixel[5]] < c_b)
+ if(p[pixel[6]] < c_b)
+ if(p[pixel[7]] < c_b)
+ {}
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ if(p[pixel[2]] < c_b)
+ if(p[pixel[3]] < c_b)
+ if(p[pixel[4]] < c_b)
+ if(p[pixel[5]] < c_b)
+ if(p[pixel[6]] < c_b)
+ if(p[pixel[7]] < c_b)
+ {}
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ if(p[pixel[7]] > cb)
+ if(p[pixel[8]] > cb)
+ if(p[pixel[9]] > cb)
+ if(p[pixel[6]] > cb)
+ if(p[pixel[5]] > cb)
+ if(p[pixel[4]] > cb)
+ if(p[pixel[3]] > cb)
+ if(p[pixel[2]] > cb)
+ if(p[pixel[1]] > cb)
+ {}
+ else
+ if(p[pixel[10]] > cb)
+ {}
+ else
+ continue;
+ else
+ if(p[pixel[10]] > cb)
+ if(p[pixel[11]] > cb)
+ {}
+ else
+ continue;
+ else
+ continue;
+ else
+ if(p[pixel[10]] > cb)
+ if(p[pixel[11]] > cb)
+ if(p[pixel[12]] > cb)
+ {}
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ if(p[pixel[10]] > cb)
+ if(p[pixel[11]] > cb)
+ if(p[pixel[12]] > cb)
+ if(p[pixel[13]] > cb)
+ {}
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ if(p[pixel[10]] > cb)
+ if(p[pixel[11]] > cb)
+ if(p[pixel[12]] > cb)
+ if(p[pixel[13]] > cb)
+ if(p[pixel[14]] > cb)
+ {}
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ if(p[pixel[10]] > cb)
+ if(p[pixel[11]] > cb)
+ if(p[pixel[12]] > cb)
+ if(p[pixel[13]] > cb)
+ if(p[pixel[14]] > cb)
+ if(p[pixel[15]] > cb)
+ {}
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else if(p[pixel[7]] < c_b)
+ if(p[pixel[8]] < c_b)
+ if(p[pixel[9]] < c_b)
+ if(p[pixel[6]] < c_b)
+ if(p[pixel[5]] < c_b)
+ if(p[pixel[4]] < c_b)
+ if(p[pixel[3]] < c_b)
+ if(p[pixel[2]] < c_b)
+ if(p[pixel[1]] < c_b)
+ {}
+ else
+ if(p[pixel[10]] < c_b)
+ {}
+ else
+ continue;
+ else
+ if(p[pixel[10]] < c_b)
+ if(p[pixel[11]] < c_b)
+ {}
+ else
+ continue;
+ else
+ continue;
+ else
+ if(p[pixel[10]] < c_b)
+ if(p[pixel[11]] < c_b)
+ if(p[pixel[12]] < c_b)
+ {}
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ if(p[pixel[10]] < c_b)
+ if(p[pixel[11]] < c_b)
+ if(p[pixel[12]] < c_b)
+ if(p[pixel[13]] < c_b)
+ {}
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ if(p[pixel[10]] < c_b)
+ if(p[pixel[11]] < c_b)
+ if(p[pixel[12]] < c_b)
+ if(p[pixel[13]] < c_b)
+ if(p[pixel[14]] < c_b)
+ {}
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ if(p[pixel[10]] < c_b)
+ if(p[pixel[11]] < c_b)
+ if(p[pixel[12]] < c_b)
+ if(p[pixel[13]] < c_b)
+ if(p[pixel[14]] < c_b)
+ if(p[pixel[15]] < c_b)
+ {}
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ else
+ continue;
+ if(num_corners == rsize)
+ {
+ rsize*=2;
+ ret_corners = (xy*)realloc(ret_corners, sizeof(xy)*rsize);
+ }
+ ret_corners[num_corners].x = x;
+ ret_corners[num_corners].y = y;
+ num_corners++;
+
+ }
+
+ *ret_num_corners = num_corners;
+ return ret_corners;
+
+}
+
+
diff --git a/extern/libmv/third_party/fast/nonmax.c b/extern/libmv/third_party/fast/nonmax.c
new file mode 100644
index 00000000000..6ed0f580906
--- /dev/null
+++ b/extern/libmv/third_party/fast/nonmax.c
@@ -0,0 +1,117 @@
+#include <stdlib.h>
+#include "fast.h"
+
+
+#define Compare(X, Y) ((X)>=(Y))
+
+xy* nonmax_suppression(const xy* corners, const int* scores, int num_corners, int* ret_num_nonmax)
+{
+ int num_nonmax=0;
+ int last_row;
+ int* row_start;
+ int i, j;
+ xy* ret_nonmax;
+ const int sz = (int)num_corners;
+
+ /*Point above points (roughly) to the pixel above the one of interest, if there
+ is a feature there.*/
+ int point_above = 0;
+ int point_below = 0;
+
+
+ if(num_corners < 1)
+ {
+ *ret_num_nonmax = 0;
+ return 0;
+ }
+
+ ret_nonmax = (xy*)malloc(num_corners * sizeof(xy));
+
+ /* Find where each row begins
+ (the corners are output in raster scan order). A beginning of -1 signifies
+ that there are no corners on that row. */
+ last_row = corners[num_corners-1].y;
+ row_start = (int*)malloc((last_row+1)*sizeof(int));
+
+ for(i=0; i < last_row+1; i++)
+ row_start[i] = -1;
+
+ {
+ int prev_row = -1;
+ for(i=0; i< num_corners; i++)
+ if(corners[i].y != prev_row)
+ {
+ row_start[corners[i].y] = i;
+ prev_row = corners[i].y;
+ }
+ }
+
+
+
+ for(i=0; i < sz; i++)
+ {
+ int score = scores[i];
+ xy pos = corners[i];
+
+ /*Check left */
+ if(i > 0)
+ if(corners[i-1].x == pos.x-1 && corners[i-1].y == pos.y && Compare(scores[i-1], score))
+ continue;
+
+ /*Check right*/
+ if(i < (sz - 1))
+ if(corners[i+1].x == pos.x+1 && corners[i+1].y == pos.y && Compare(scores[i+1], score))
+ continue;
+
+ /*Check above (if there is a valid row above)*/
+ if(pos.y != 0 && row_start[pos.y - 1] != -1)
+ {
+ /*Make sure that current point_above is one
+ row above.*/
+ if(corners[point_above].y < pos.y - 1)
+ point_above = row_start[pos.y-1];
+
+ /*Make point_above point to the first of the pixels above the current point,
+ if it exists.*/
+ for(; corners[point_above].y < pos.y && corners[point_above].x < pos.x - 1; point_above++)
+ {}
+
+
+ for(j=point_above; corners[j].y < pos.y && corners[j].x <= pos.x + 1; j++)
+ {
+ int x = corners[j].x;
+ if( (x == pos.x - 1 || x ==pos.x || x == pos.x+1) && Compare(scores[j], score))
+ goto cont;
+ }
+
+ }
+
+ /*Check below (if there is anything below)*/
+ if(pos.y != last_row && row_start[pos.y + 1] != -1 && point_below < sz) /*Nothing below*/
+ {
+ if(corners[point_below].y < pos.y + 1)
+ point_below = row_start[pos.y+1];
+
+ /* Make point below point to one of the pixels belowthe current point, if it
+ exists.*/
+ for(; point_below < sz && corners[point_below].y == pos.y+1 && corners[point_below].x < pos.x - 1; point_below++)
+ {}
+
+ for(j=point_below; j < sz && corners[j].y == pos.y+1 && corners[j].x <= pos.x + 1; j++)
+ {
+ int x = corners[j].x;
+ if( (x == pos.x - 1 || x ==pos.x || x == pos.x+1) && Compare(scores[j],score))
+ goto cont;
+ }
+ }
+
+ ret_nonmax[num_nonmax++] = corners[i];
+ cont:
+ ;
+ }
+
+ free(row_start);
+ *ret_num_nonmax = num_nonmax;
+ return ret_nonmax;
+}
+
diff --git a/extern/libmv/third_party/gflags/README.libmv b/extern/libmv/third_party/gflags/README.libmv
new file mode 100644
index 00000000000..f2bdef6563e
--- /dev/null
+++ b/extern/libmv/third_party/gflags/README.libmv
@@ -0,0 +1,14 @@
+Project: Google Flags
+URL: http://code.google.com/p/google-gflags/
+License: New BSD
+Upstream version: 1.5
+Local modifications:
+
+- Flattened the tree and only included files needed for libmv. This involved
+ changing some of the includes to point to the current directory instead of a
+ nested gflags directory.
+
+- Added a poor-man's version of upstream's port.cc/h to make gflags compile on
+ windows. This isn't sufficient but is a stopgap for now.
+
+ TODO(keir): Import and use gflags for Windows from upstream.
diff --git a/extern/libmv/third_party/gflags/config.h b/extern/libmv/third_party/gflags/config.h
new file mode 100644
index 00000000000..ca2c1276c44
--- /dev/null
+++ b/extern/libmv/third_party/gflags/config.h
@@ -0,0 +1,110 @@
+/* src/config.h. Generated from config.h.in by configure. */
+/* src/config.h.in. Generated from configure.ac by autoheader. */
+
+/* Always the empty-string on non-windows systems. On windows, should be
+ "__declspec(dllexport)". This way, when we compile the dll, we export our
+ functions/classes. It's safe to define this here because config.h is only
+ used internally, to compile the DLL, and every DLL source file #includes
+ "config.h" before anything else. */
+#define GFLAGS_DLL_DECL /**/
+
+/* Namespace for Google classes */
+#define GOOGLE_NAMESPACE ::google
+
+/* Define to 1 if you have the <dlfcn.h> header file. */
+#define HAVE_DLFCN_H 1
+
+/* Define to 1 if you have the <fnmatch.h> header file. */
+#undef HAVE_FNMATCH_H
+
+/* Define to 1 if you have the <inttypes.h> header file. */
+#define HAVE_INTTYPES_H 1
+
+/* Define to 1 if you have the <memory.h> header file. */
+#define HAVE_MEMORY_H 1
+
+/* define if the compiler implements namespaces */
+#define HAVE_NAMESPACES 1
+
+/* Define if you have POSIX threads libraries and header files. */
+#define HAVE_PTHREAD 1
+
+/* Define to 1 if you have the `putenv' function. */
+#define HAVE_PUTENV 1
+
+/* Define to 1 if you have the `setenv' function. */
+#define HAVE_SETENV 1
+
+/* Define to 1 if you have the <stdint.h> header file. */
+#define HAVE_STDINT_H 1
+
+/* Define to 1 if you have the <stdlib.h> header file. */
+#define HAVE_STDLIB_H 1
+
+/* Define to 1 if you have the <strings.h> header file. */
+#define HAVE_STRINGS_H 1
+
+/* Define to 1 if you have the <string.h> header file. */
+#define HAVE_STRING_H 1
+
+/* Define to 1 if you have the `strtoll' function. */
+#define HAVE_STRTOLL 1
+
+/* Define to 1 if you have the `strtoq' function. */
+#define HAVE_STRTOQ 1
+
+/* Define to 1 if you have the <sys/stat.h> header file. */
+#define HAVE_SYS_STAT_H 1
+
+/* Define to 1 if you have the <sys/types.h> header file. */
+#define HAVE_SYS_TYPES_H 1
+
+/* Define to 1 if you have the <unistd.h> header file. */
+#define HAVE_UNISTD_H 1
+
+/* define if your compiler has __attribute__ */
+#define HAVE___ATTRIBUTE__ 1
+
+/* Define to the sub-directory in which libtool stores uninstalled libraries.
+ */
+#define LT_OBJDIR ".libs/"
+
+/* Name of package */
+#define PACKAGE "gflags"
+
+/* Define to the address where bug reports for this package should be sent. */
+#define PACKAGE_BUGREPORT "opensource@google.com"
+
+/* Define to the full name of this package. */
+#define PACKAGE_NAME "gflags"
+
+/* Define to the full name and version of this package. */
+#define PACKAGE_STRING "gflags 1.5"
+
+/* Define to the one symbol short name of this package. */
+#define PACKAGE_TARNAME "gflags"
+
+/* Define to the home page for this package. */
+#define PACKAGE_URL ""
+
+/* Define to the version of this package. */
+#define PACKAGE_VERSION "1.5"
+
+/* Define to necessary symbol if this constant uses a non-standard name on
+ your system. */
+/* #undef PTHREAD_CREATE_JOINABLE */
+
+/* Define to 1 if you have the ANSI C header files. */
+#define STDC_HEADERS 1
+
+/* the namespace where STL code like vector<> is defined */
+#define STL_NAMESPACE std
+
+/* Version number of package */
+#define VERSION "1.5"
+
+/* Stops putting the code inside the Google namespace */
+#define _END_GOOGLE_NAMESPACE_ }
+
+/* Puts following code inside the Google namespace */
+#define _START_GOOGLE_NAMESPACE_ namespace google {
diff --git a/extern/libmv/third_party/gflags/gflags.cc b/extern/libmv/third_party/gflags/gflags.cc
new file mode 100644
index 00000000000..34fe95dac59
--- /dev/null
+++ b/extern/libmv/third_party/gflags/gflags.cc
@@ -0,0 +1,1971 @@
+// Copyright (c) 2006, Google Inc.
+// 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.
+
+// ---
+// Author: Ray Sidney
+// Revamped and reorganized by Craig Silverstein
+//
+// This file contains the implementation of all our command line flags
+// stuff. Here's how everything fits together
+//
+// * FlagRegistry owns CommandLineFlags owns FlagValue.
+// * FlagSaver holds a FlagRegistry (saves it at construct time,
+// restores it at destroy time).
+// * CommandLineFlagParser lives outside that hierarchy, but works on
+// CommandLineFlags (modifying the FlagValues).
+// * Free functions like SetCommandLineOption() work via one of the
+// above (such as CommandLineFlagParser).
+//
+// In more detail:
+//
+// -- The main classes that hold flag data:
+//
+// FlagValue holds the current value of a flag. It's
+// pseudo-templatized: every operation on a FlagValue is typed. It
+// also deals with storage-lifetime issues (so flag values don't go
+// away in a destructor), which is why we need a whole class to hold a
+// variable's value.
+//
+// CommandLineFlag is all the information about a single command-line
+// flag. It has a FlagValue for the flag's current value, but also
+// the flag's name, type, etc.
+//
+// FlagRegistry is a collection of CommandLineFlags. There's the
+// global registry, which is where flags defined via DEFINE_foo()
+// live. But it's possible to define your own flag, manually, in a
+// different registry you create. (In practice, multiple registries
+// are used only by FlagSaver).
+//
+// A given FlagValue is owned by exactly one CommandLineFlag. A given
+// CommandLineFlag is owned by exactly one FlagRegistry. FlagRegistry
+// has a lock; any operation that writes to a FlagValue or
+// CommandLineFlag owned by that registry must acquire the
+// FlagRegistry lock before doing so.
+//
+// --- Some other classes and free functions:
+//
+// CommandLineFlagInfo is a client-exposed version of CommandLineFlag.
+// Once it's instantiated, it has no dependencies or relationships
+// with any other part of this file.
+//
+// FlagRegisterer is the helper class used by the DEFINE_* macros to
+// allow work to be done at global initialization time.
+//
+// CommandLineFlagParser is the class that reads from the commandline
+// and instantiates flag values based on that. It needs to poke into
+// the innards of the FlagValue->CommandLineFlag->FlagRegistry class
+// hierarchy to do that. It's careful to acquire the FlagRegistry
+// lock before doing any writing or other non-const actions.
+//
+// GetCommandLineOption is just a hook into registry routines to
+// retrieve a flag based on its name. SetCommandLineOption, on the
+// other hand, hooks into CommandLineFlagParser. Other API functions
+// are, similarly, mostly hooks into the functionality described above.
+
+#include "config.h"
+// This comes first to ensure we define __STDC_FORMAT_MACROS in time.
+#ifdef HAVE_INTTYPES_H
+#ifndef __STDC_FORMAT_MACROS
+# define __STDC_FORMAT_MACROS 1 // gcc requires this to get PRId64, etc.
+#endif
+#include <inttypes.h>
+#endif // HAVE_INTTYPES_H
+#include <stdio.h> // for snprintf
+#include <ctype.h>
+#include <errno.h>
+#include <stdio.h>
+#include <stdarg.h> // For va_list and related operations
+#include <string.h>
+#include <assert.h>
+#ifdef HAVE_FNMATCH_H
+#include <fnmatch.h>
+#endif // HAVE_FNMATCH_H
+#include <string>
+#include <map>
+#include <vector>
+#include <utility> // for pair<>
+#include <algorithm>
+#include "gflags.h"
+#include "mutex.h"
+
+#ifndef PATH_SEPARATOR
+#define PATH_SEPARATOR '/'
+#endif
+
+// Work properly if either strtoll or strtoq is on this system
+#ifdef HAVE_STRTOLL
+# define strtoint64 strtoll
+# define strtouint64 strtoull
+#elif HAVE_STRTOQ
+# define strtoint64 strtoq
+# define strtouint64 strtouq
+#else
+// Neither strtoll nor strtoq are defined. I hope strtol works!
+# define strtoint64 strtol
+# define strtouint64 strtoul
+#endif
+
+// If we have inttypes.h, it will have defined PRId32/etc for us. If
+// not, take our best guess.
+#ifndef PRId32
+# define PRId32 "d"
+#endif
+#ifndef PRId64
+# define PRId64 "lld"
+#endif
+#ifndef PRIu64
+# define PRIu64 "llu"
+#endif
+
+// Windows is missing random bits like strcasecmp, strtoll, strtoull, and
+// snprintf in the usual locations. Put them somewhere sensible.
+//
+// TODO(keir): Get the upstream Windows port and use that instead.
+#ifdef _MSC_VER
+# define snprintf _snprintf
+# undef strtoint64
+# define strtoint64 _strtoi64
+# undef strtouint64
+# define strtouint64 _strtoui64
+# define strcasecmp _stricmp
+#endif
+
+typedef signed char int8;
+typedef unsigned char uint8;
+
+// Special flags, type 1: the 'recursive' flags. They set another flag's val.
+DEFINE_string(flagfile, "",
+ "load flags from file");
+DEFINE_string(fromenv, "",
+ "set flags from the environment"
+ " [use 'export FLAGS_flag1=value']");
+DEFINE_string(tryfromenv, "",
+ "set flags from the environment if present");
+
+// Special flags, type 2: the 'parsing' flags. They modify how we parse.
+DEFINE_string(undefok, "",
+ "comma-separated list of flag names that it is okay to specify "
+ "on the command line even if the program does not define a flag "
+ "with that name. IMPORTANT: flags in this list that have "
+ "arguments MUST use the flag=value format");
+
+_START_GOOGLE_NAMESPACE_
+
+using std::map;
+using std::pair;
+using std::sort;
+using std::string;
+using std::vector;
+
+// The help message indicating that the commandline flag has been
+// 'stripped'. It will not show up when doing "-help" and its
+// variants. The flag is stripped if STRIP_FLAG_HELP is set to 1
+// before including gflags/gflags.h.
+
+// This is used by this file, and also in commandlineflags_reporting.cc
+const char kStrippedFlagHelp[] = "\001\002\003\004 (unknown) \004\003\002\001";
+
+// This is used by the unittest to test error-exit code
+void GFLAGS_DLL_DECL (*commandlineflags_exitfunc)(int) = &exit; // from stdlib.h
+
+namespace {
+
+// There are also 'reporting' flags, in commandlineflags_reporting.cc.
+
+static const char kError[] = "ERROR: ";
+
+// Indicates that undefined options are to be ignored.
+// Enables deferred processing of flags in dynamically loaded libraries.
+static bool allow_command_line_reparsing = false;
+
+static bool logging_is_probably_set_up = false;
+
+// This is a 'prototype' validate-function. 'Real' validate
+// functions, take a flag-value as an argument: ValidateFn(bool) or
+// ValidateFn(uint64). However, for easier storage, we strip off this
+// argument and then restore it when actually calling the function on
+// a flag value.
+typedef bool (*ValidateFnProto)();
+
+// Whether we should die when reporting an error.
+enum DieWhenReporting { DIE, DO_NOT_DIE };
+
+// Report Error and exit if requested.
+static void ReportError(DieWhenReporting should_die, const char* format, ...) {
+ va_list ap;
+ va_start(ap, format);
+ vfprintf(stderr, format, ap);
+ va_end(ap);
+ if (should_die == DIE)
+ commandlineflags_exitfunc(1); // almost certainly exit()
+}
+
+
+// --------------------------------------------------------------------
+// FlagValue
+// This represent the value a single flag might have. The major
+// functionality is to convert from a string to an object of a
+// given type, and back. Thread-compatible.
+// --------------------------------------------------------------------
+
+class CommandLineFlag;
+class FlagValue {
+ public:
+ FlagValue(void* valbuf, const char* type, bool transfer_ownership_of_value);
+ ~FlagValue();
+
+ bool ParseFrom(const char* spec);
+ string ToString() const;
+
+ private:
+ friend class CommandLineFlag; // for many things, including Validate()
+ friend class GOOGLE_NAMESPACE::FlagSaverImpl; // calls New()
+ friend class FlagRegistry; // checks value_buffer_ for flags_by_ptr_ map
+ template <typename T> friend T GetFromEnv(const char*, const char*, T);
+ friend bool TryParseLocked(const CommandLineFlag*, FlagValue*,
+ const char*, string*); // for New(), CopyFrom()
+
+ enum ValueType {
+ FV_BOOL = 0,
+ FV_INT32 = 1,
+ FV_INT64 = 2,
+ FV_UINT64 = 3,
+ FV_DOUBLE = 4,
+ FV_STRING = 5,
+ FV_MAX_INDEX = 5,
+ };
+ const char* TypeName() const;
+ bool Equal(const FlagValue& x) const;
+ FlagValue* New() const; // creates a new one with default value
+ void CopyFrom(const FlagValue& x);
+ int ValueSize() const;
+
+ // Calls the given validate-fn on value_buffer_, and returns
+ // whatever it returns. But first casts validate_fn_proto to a
+ // function that takes our value as an argument (eg void
+ // (*validate_fn)(bool) for a bool flag).
+ bool Validate(const char* flagname, ValidateFnProto validate_fn_proto) const;
+
+ void* value_buffer_; // points to the buffer holding our data
+ int8 type_; // how to interpret value_
+ bool owns_value_; // whether to free value on destruct
+
+ FlagValue(const FlagValue&); // no copying!
+ void operator=(const FlagValue&);
+};
+
+
+// This could be a templated method of FlagValue, but doing so adds to the
+// size of the .o. Since there's no type-safety here anyway, macro is ok.
+#define VALUE_AS(type) *reinterpret_cast<type*>(value_buffer_)
+#define OTHER_VALUE_AS(fv, type) *reinterpret_cast<type*>(fv.value_buffer_)
+#define SET_VALUE_AS(type, value) VALUE_AS(type) = (value)
+
+FlagValue::FlagValue(void* valbuf, const char* type,
+ bool transfer_ownership_of_value)
+ : value_buffer_(valbuf),
+ owns_value_(transfer_ownership_of_value) {
+ for (type_ = 0; type_ <= FV_MAX_INDEX; ++type_) {
+ if (!strcmp(type, TypeName())) {
+ break;
+ }
+ }
+ assert(type_ <= FV_MAX_INDEX); // Unknown typename
+}
+
+FlagValue::~FlagValue() {
+ if (!owns_value_) {
+ return;
+ }
+ switch (type_) {
+ case FV_BOOL: delete reinterpret_cast<bool*>(value_buffer_); break;
+ case FV_INT32: delete reinterpret_cast<int32*>(value_buffer_); break;
+ case FV_INT64: delete reinterpret_cast<int64*>(value_buffer_); break;
+ case FV_UINT64: delete reinterpret_cast<uint64*>(value_buffer_); break;
+ case FV_DOUBLE: delete reinterpret_cast<double*>(value_buffer_); break;
+ case FV_STRING: delete reinterpret_cast<string*>(value_buffer_); break;
+ }
+}
+
+bool FlagValue::ParseFrom(const char* value) {
+ if (type_ == FV_BOOL) {
+ const char* kTrue[] = { "1", "t", "true", "y", "yes" };
+ const char* kFalse[] = { "0", "f", "false", "n", "no" };
+ for (size_t i = 0; i < sizeof(kTrue)/sizeof(*kTrue); ++i) {
+ if (strcasecmp(value, kTrue[i]) == 0) {
+ SET_VALUE_AS(bool, true);
+ return true;
+ } else if (strcasecmp(value, kFalse[i]) == 0) {
+ SET_VALUE_AS(bool, false);
+ return true;
+ }
+ }
+ return false; // didn't match a legal input
+
+ } else if (type_ == FV_STRING) {
+ SET_VALUE_AS(string, value);
+ return true;
+ }
+
+ // OK, it's likely to be numeric, and we'll be using a strtoXXX method.
+ if (value[0] == '\0') // empty-string is only allowed for string type.
+ return false;
+ char* end;
+ // Leading 0x puts us in base 16. But leading 0 does not put us in base 8!
+ // It caused too many bugs when we had that behavior.
+ int base = 10; // by default
+ if (value[0] == '0' && (value[1] == 'x' || value[1] == 'X'))
+ base = 16;
+ errno = 0;
+
+ switch (type_) {
+ case FV_INT32: {
+ const int64 r = strtoint64(value, &end, base);
+ if (errno || end != value + strlen(value)) return false; // bad parse
+ if (static_cast<int32>(r) != r) // worked, but number out of range
+ return false;
+ SET_VALUE_AS(int32, static_cast<int32>(r));
+ return true;
+ }
+ case FV_INT64: {
+ const int64 r = strtoint64(value, &end, base);
+ if (errno || end != value + strlen(value)) return false; // bad parse
+ SET_VALUE_AS(int64, r);
+ return true;
+ }
+ case FV_UINT64: {
+ while (*value == ' ') value++;
+ if (*value == '-') return false; // negative number
+ const uint64 r = strtouint64(value, &end, base);
+ if (errno || end != value + strlen(value)) return false; // bad parse
+ SET_VALUE_AS(uint64, r);
+ return true;
+ }
+ case FV_DOUBLE: {
+ const double r = strtod(value, &end);
+ if (errno || end != value + strlen(value)) return false; // bad parse
+ SET_VALUE_AS(double, r);
+ return true;
+ }
+ default: {
+ assert(false); // unknown type
+ return false;
+ }
+ }
+}
+
+string FlagValue::ToString() const {
+ char intbuf[64]; // enough to hold even the biggest number
+ switch (type_) {
+ case FV_BOOL:
+ return VALUE_AS(bool) ? "true" : "false";
+ case FV_INT32:
+ snprintf(intbuf, sizeof(intbuf), "%"PRId32, VALUE_AS(int32));
+ return intbuf;
+ case FV_INT64:
+ snprintf(intbuf, sizeof(intbuf), "%"PRId64, VALUE_AS(int64));
+ return intbuf;
+ case FV_UINT64:
+ snprintf(intbuf, sizeof(intbuf), "%"PRIu64, VALUE_AS(uint64));
+ return intbuf;
+ case FV_DOUBLE:
+ snprintf(intbuf, sizeof(intbuf), "%.17g", VALUE_AS(double));
+ return intbuf;
+ case FV_STRING:
+ return VALUE_AS(string);
+ default:
+ assert(false);
+ return ""; // unknown type
+ }
+}
+
+bool FlagValue::Validate(const char* flagname,
+ ValidateFnProto validate_fn_proto) const {
+ switch (type_) {
+ case FV_BOOL:
+ return reinterpret_cast<bool (*)(const char*, bool)>(
+ validate_fn_proto)(flagname, VALUE_AS(bool));
+ case FV_INT32:
+ return reinterpret_cast<bool (*)(const char*, int32)>(
+ validate_fn_proto)(flagname, VALUE_AS(int32));
+ case FV_INT64:
+ return reinterpret_cast<bool (*)(const char*, int64)>(
+ validate_fn_proto)(flagname, VALUE_AS(int64));
+ case FV_UINT64:
+ return reinterpret_cast<bool (*)(const char*, uint64)>(
+ validate_fn_proto)(flagname, VALUE_AS(uint64));
+ case FV_DOUBLE:
+ return reinterpret_cast<bool (*)(const char*, double)>(
+ validate_fn_proto)(flagname, VALUE_AS(double));
+ case FV_STRING:
+ return reinterpret_cast<bool (*)(const char*, const string&)>(
+ validate_fn_proto)(flagname, VALUE_AS(string));
+ default:
+ assert(false); // unknown type
+ return false;
+ }
+}
+
+const char* FlagValue::TypeName() const {
+ static const char types[] =
+ "bool\0xx"
+ "int32\0x"
+ "int64\0x"
+ "uint64\0"
+ "double\0"
+ "string";
+ if (type_ > FV_MAX_INDEX) {
+ assert(false);
+ return "";
+ }
+ // Directly indexing the strigns in the 'types' string, each of them
+ // is 7 bytes long.
+ return &types[type_ * 7];
+}
+
+bool FlagValue::Equal(const FlagValue& x) const {
+ if (type_ != x.type_)
+ return false;
+ switch (type_) {
+ case FV_BOOL: return VALUE_AS(bool) == OTHER_VALUE_AS(x, bool);
+ case FV_INT32: return VALUE_AS(int32) == OTHER_VALUE_AS(x, int32);
+ case FV_INT64: return VALUE_AS(int64) == OTHER_VALUE_AS(x, int64);
+ case FV_UINT64: return VALUE_AS(uint64) == OTHER_VALUE_AS(x, uint64);
+ case FV_DOUBLE: return VALUE_AS(double) == OTHER_VALUE_AS(x, double);
+ case FV_STRING: return VALUE_AS(string) == OTHER_VALUE_AS(x, string);
+ default: assert(false); return false; // unknown type
+ }
+}
+
+FlagValue* FlagValue::New() const {
+ const char *type = TypeName();
+ switch (type_) {
+ case FV_BOOL: return new FlagValue(new bool(false), type, true);
+ case FV_INT32: return new FlagValue(new int32(0), type, true);
+ case FV_INT64: return new FlagValue(new int64(0), type, true);
+ case FV_UINT64: return new FlagValue(new uint64(0), type, true);
+ case FV_DOUBLE: return new FlagValue(new double(0.0), type, true);
+ case FV_STRING: return new FlagValue(new string, type, true);
+ default: assert(false); return NULL; // unknown type
+ }
+}
+
+void FlagValue::CopyFrom(const FlagValue& x) {
+ assert(type_ == x.type_);
+ switch (type_) {
+ case FV_BOOL: SET_VALUE_AS(bool, OTHER_VALUE_AS(x, bool)); break;
+ case FV_INT32: SET_VALUE_AS(int32, OTHER_VALUE_AS(x, int32)); break;
+ case FV_INT64: SET_VALUE_AS(int64, OTHER_VALUE_AS(x, int64)); break;
+ case FV_UINT64: SET_VALUE_AS(uint64, OTHER_VALUE_AS(x, uint64)); break;
+ case FV_DOUBLE: SET_VALUE_AS(double, OTHER_VALUE_AS(x, double)); break;
+ case FV_STRING: SET_VALUE_AS(string, OTHER_VALUE_AS(x, string)); break;
+ default: assert(false); // unknown type
+ }
+}
+
+int FlagValue::ValueSize() const {
+ if (type_ > FV_MAX_INDEX) {
+ assert(false); // unknown type
+ return 0;
+ }
+ static const uint8 valuesize[] = {
+ sizeof(bool),
+ sizeof(int32),
+ sizeof(int64),
+ sizeof(uint64),
+ sizeof(double),
+ sizeof(string),
+ };
+ return valuesize[type_];
+}
+
+// --------------------------------------------------------------------
+// CommandLineFlag
+// This represents a single flag, including its name, description,
+// default value, and current value. Mostly this serves as a
+// struct, though it also knows how to register itself.
+// All CommandLineFlags are owned by a (exactly one)
+// FlagRegistry. If you wish to modify fields in this class, you
+// should acquire the FlagRegistry lock for the registry that owns
+// this flag.
+// --------------------------------------------------------------------
+
+class CommandLineFlag {
+ public:
+ // Note: we take over memory-ownership of current_val and default_val.
+ CommandLineFlag(const char* name, const char* help, const char* filename,
+ FlagValue* current_val, FlagValue* default_val);
+ ~CommandLineFlag();
+
+ const char* name() const { return name_; }
+ const char* help() const { return help_; }
+ const char* filename() const { return file_; }
+ const char* CleanFileName() const; // nixes irrelevant prefix such as homedir
+ string current_value() const { return current_->ToString(); }
+ string default_value() const { return defvalue_->ToString(); }
+ const char* type_name() const { return defvalue_->TypeName(); }
+ ValidateFnProto validate_function() const { return validate_fn_proto_; }
+
+ void FillCommandLineFlagInfo(struct CommandLineFlagInfo* result);
+
+ // If validate_fn_proto_ is non-NULL, calls it on value, returns result.
+ bool Validate(const FlagValue& value) const;
+ bool ValidateCurrent() const { return Validate(*current_); }
+
+ private:
+ // for SetFlagLocked() and setting flags_by_ptr_
+ friend class FlagRegistry;
+ friend class GOOGLE_NAMESPACE::FlagSaverImpl; // for cloning the values
+ // set validate_fn
+ friend bool AddFlagValidator(const void*, ValidateFnProto);
+
+ // This copies all the non-const members: modified, processed, defvalue, etc.
+ void CopyFrom(const CommandLineFlag& src);
+
+ void UpdateModifiedBit();
+
+ const char* const name_; // Flag name
+ const char* const help_; // Help message
+ const char* const file_; // Which file did this come from?
+ bool modified_; // Set after default assignment?
+ FlagValue* defvalue_; // Default value for flag
+ FlagValue* current_; // Current value for flag
+ // This is a casted, 'generic' version of validate_fn, which actually
+ // takes a flag-value as an arg (void (*validate_fn)(bool), say).
+ // When we pass this to current_->Validate(), it will cast it back to
+ // the proper type. This may be NULL to mean we have no validate_fn.
+ ValidateFnProto validate_fn_proto_;
+
+ CommandLineFlag(const CommandLineFlag&); // no copying!
+ void operator=(const CommandLineFlag&);
+};
+
+CommandLineFlag::CommandLineFlag(const char* name, const char* help,
+ const char* filename,
+ FlagValue* current_val, FlagValue* default_val)
+ : name_(name), help_(help), file_(filename), modified_(false),
+ defvalue_(default_val), current_(current_val), validate_fn_proto_(NULL) {
+}
+
+CommandLineFlag::~CommandLineFlag() {
+ delete current_;
+ delete defvalue_;
+}
+
+const char* CommandLineFlag::CleanFileName() const {
+ // Compute top-level directory & file that this appears in
+ // search full path backwards.
+ // Stop going backwards at kRootDir; and skip by the first slash.
+ static const char kRootDir[] = ""; // can set this to root directory,
+ // e.g. "myproject"
+
+ if (sizeof(kRootDir)-1 == 0) // no prefix to strip
+ return filename();
+
+ const char* clean_name = filename() + strlen(filename()) - 1;
+ while ( clean_name > filename() ) {
+ if (*clean_name == PATH_SEPARATOR) {
+ if (strncmp(clean_name, kRootDir, sizeof(kRootDir)-1) == 0) {
+ // ".../myproject/base/logging.cc" ==> "base/logging.cc"
+ clean_name += sizeof(kRootDir)-1; // past "/myproject/"
+ break;
+ }
+ }
+ --clean_name;
+ }
+ while ( *clean_name == PATH_SEPARATOR ) ++clean_name; // Skip any slashes
+ return clean_name;
+}
+
+void CommandLineFlag::FillCommandLineFlagInfo(
+ CommandLineFlagInfo* result) {
+ result->name = name();
+ result->type = type_name();
+ result->description = help();
+ result->current_value = current_value();
+ result->default_value = default_value();
+ result->filename = CleanFileName();
+ UpdateModifiedBit();
+ result->is_default = !modified_;
+ result->has_validator_fn = validate_function() != NULL;
+}
+
+void CommandLineFlag::UpdateModifiedBit() {
+ // Update the "modified" bit in case somebody bypassed the
+ // Flags API and wrote directly through the FLAGS_name variable.
+ if (!modified_ && !current_->Equal(*defvalue_)) {
+ modified_ = true;
+ }
+}
+
+void CommandLineFlag::CopyFrom(const CommandLineFlag& src) {
+ // Note we only copy the non-const members; others are fixed at construct time
+ if (modified_ != src.modified_) modified_ = src.modified_;
+ if (!current_->Equal(*src.current_)) current_->CopyFrom(*src.current_);
+ if (!defvalue_->Equal(*src.defvalue_)) defvalue_->CopyFrom(*src.defvalue_);
+ if (validate_fn_proto_ != src.validate_fn_proto_)
+ validate_fn_proto_ = src.validate_fn_proto_;
+}
+
+bool CommandLineFlag::Validate(const FlagValue& value) const {
+ if (validate_function() == NULL)
+ return true;
+ else
+ return value.Validate(name(), validate_function());
+}
+
+
+// --------------------------------------------------------------------
+// FlagRegistry
+// A FlagRegistry singleton object holds all flag objects indexed
+// by their names so that if you know a flag's name (as a C
+// string), you can access or set it. If the function is named
+// FooLocked(), you must own the registry lock before calling
+// the function; otherwise, you should *not* hold the lock, and
+// the function will acquire it itself if needed.
+// --------------------------------------------------------------------
+
+struct StringCmp { // Used by the FlagRegistry map class to compare char*'s
+ bool operator() (const char* s1, const char* s2) const {
+ return (strcmp(s1, s2) < 0);
+ }
+};
+
+class FlagRegistry {
+ public:
+ FlagRegistry() { }
+ ~FlagRegistry() {
+ for (FlagMap::iterator p = flags_.begin(), e = flags_.end(); p != e; ++p) {
+ CommandLineFlag* flag = p->second;
+ delete flag;
+ }
+ }
+
+ static void DeleteGlobalRegistry() {
+ delete global_registry_;
+ global_registry_ = NULL;
+ }
+
+ void Lock() { lock_.Lock(); }
+ void Unlock() { lock_.Unlock(); }
+
+ // Store a flag in this registry. Takes ownership of the given pointer.
+ void RegisterFlag(CommandLineFlag* flag);
+
+ // Returns the flag object for the specified name, or NULL if not found.
+ CommandLineFlag* FindFlagLocked(const char* name);
+
+ // Returns the flag object whose current-value is stored at flag_ptr.
+ // That is, for whom current_->value_buffer_ == flag_ptr
+ CommandLineFlag* FindFlagViaPtrLocked(const void* flag_ptr);
+
+ // A fancier form of FindFlag that works correctly if name is of the
+ // form flag=value. In that case, we set key to point to flag, and
+ // modify v to point to the value (if present), and return the flag
+ // with the given name. If the flag does not exist, returns NULL
+ // and sets error_message.
+ CommandLineFlag* SplitArgumentLocked(const char* argument,
+ string* key, const char** v,
+ string* error_message);
+
+ // Set the value of a flag. If the flag was successfully set to
+ // value, set msg to indicate the new flag-value, and return true.
+ // Otherwise, set msg to indicate the error, leave flag unchanged,
+ // and return false. msg can be NULL.
+ bool SetFlagLocked(CommandLineFlag* flag, const char* value,
+ FlagSettingMode set_mode, string* msg);
+
+ static FlagRegistry* GlobalRegistry(); // returns a singleton registry
+
+ private:
+ friend class GOOGLE_NAMESPACE::FlagSaverImpl; // reads all the flags in order to copy them
+ friend class CommandLineFlagParser; // for ValidateAllFlags
+ friend void GOOGLE_NAMESPACE::GetAllFlags(vector<CommandLineFlagInfo>*);
+
+ // The map from name to flag, for FindFlagLocked().
+ typedef map<const char*, CommandLineFlag*, StringCmp> FlagMap;
+ typedef FlagMap::iterator FlagIterator;
+ typedef FlagMap::const_iterator FlagConstIterator;
+ FlagMap flags_;
+
+ // The map from current-value pointer to flag, fo FindFlagViaPtrLocked().
+ typedef map<const void*, CommandLineFlag*> FlagPtrMap;
+ FlagPtrMap flags_by_ptr_;
+
+ Mutex lock_;
+
+ static FlagRegistry* global_registry_; // a singleton registry
+ static Mutex global_registry_lock_; // guards creation of global_registry_
+
+ // Disallow
+ FlagRegistry(const FlagRegistry&);
+ FlagRegistry& operator=(const FlagRegistry&);
+};
+
+FlagRegistry* FlagRegistry::global_registry_ = NULL;
+Mutex FlagRegistry::global_registry_lock_(Mutex::LINKER_INITIALIZED);
+
+FlagRegistry* FlagRegistry::GlobalRegistry() {
+ MutexLock acquire_lock(&global_registry_lock_);
+ if (!global_registry_) {
+ global_registry_ = new FlagRegistry;
+ }
+ return global_registry_;
+}
+
+void FlagRegistry::RegisterFlag(CommandLineFlag* flag) {
+ Lock();
+ pair<FlagIterator, bool> ins =
+ flags_.insert(pair<const char*, CommandLineFlag*>(flag->name(), flag));
+ if (ins.second == false) { // means the name was already in the map
+ if (strcmp(ins.first->second->filename(), flag->filename()) != 0) {
+ ReportError(DIE, "ERROR: flag '%s' was defined more than once "
+ "(in files '%s' and '%s').\n",
+ flag->name(),
+ ins.first->second->filename(),
+ flag->filename());
+ } else {
+ ReportError(DIE, "ERROR: something wrong with flag '%s' in file '%s'. "
+ "One possibility: file '%s' is being linked both statically "
+ "and dynamically into this executable.\n",
+ flag->name(),
+ flag->filename(), flag->filename());
+ }
+ }
+ // Also add to the flags_by_ptr_ map.
+ flags_by_ptr_[flag->current_->value_buffer_] = flag;
+ Unlock();
+}
+
+CommandLineFlag* FlagRegistry::FindFlagLocked(const char* name) {
+ FlagConstIterator i = flags_.find(name);
+ if (i == flags_.end()) {
+ return NULL;
+ } else {
+ return i->second;
+ }
+}
+
+CommandLineFlag* FlagRegistry::FindFlagViaPtrLocked(const void* flag_ptr) {
+ FlagPtrMap::const_iterator i = flags_by_ptr_.find(flag_ptr);
+ if (i == flags_by_ptr_.end()) {
+ return NULL;
+ } else {
+ return i->second;
+ }
+}
+
+CommandLineFlag* FlagRegistry::SplitArgumentLocked(const char* arg,
+ string* key,
+ const char** v,
+ string* error_message) {
+ // Find the flag object for this option
+ const char* flag_name;
+ const char* value = strchr(arg, '=');
+ if (value == NULL) {
+ key->assign(arg);
+ *v = NULL;
+ } else {
+ // Strip out the "=value" portion from arg
+ key->assign(arg, value-arg);
+ *v = ++value; // advance past the '='
+ }
+ flag_name = key->c_str();
+
+ CommandLineFlag* flag = FindFlagLocked(flag_name);
+
+ if (flag == NULL) {
+ // If we can't find the flag-name, then we should return an error.
+ // The one exception is if 1) the flag-name is 'nox', 2) there
+ // exists a flag named 'x', and 3) 'x' is a boolean flag.
+ // In that case, we want to return flag 'x'.
+ if (!(flag_name[0] == 'n' && flag_name[1] == 'o')) {
+ // flag-name is not 'nox', so we're not in the exception case.
+ *error_message = (string(kError) +
+ "unknown command line flag '" + *key + "'\n");
+ return NULL;
+ }
+ flag = FindFlagLocked(flag_name+2);
+ if (flag == NULL) {
+ // No flag named 'x' exists, so we're not in the exception case.
+ *error_message = (string(kError) +
+ "unknown command line flag '" + *key + "'\n");
+ return NULL;
+ }
+ if (strcmp(flag->type_name(), "bool") != 0) {
+ // 'x' exists but is not boolean, so we're not in the exception case.
+ *error_message = (string(kError) +
+ "boolean value (" + *key + ") specified for " +
+ flag->type_name() + " command line flag\n");
+ return NULL;
+ }
+ // We're in the exception case!
+ // Make up a fake value to replace the "no" we stripped out
+ key->assign(flag_name+2); // the name without the "no"
+ *v = "0";
+ }
+
+ // Assign a value if this is a boolean flag
+ if (*v == NULL && strcmp(flag->type_name(), "bool") == 0) {
+ *v = "1"; // the --nox case was already handled, so this is the --x case
+ }
+
+ return flag;
+}
+
+bool TryParseLocked(const CommandLineFlag* flag, FlagValue* flag_value,
+ const char* value, string* msg) {
+ // Use tenative_value, not flag_value, until we know value is valid.
+ FlagValue* tentative_value = flag_value->New();
+ if (!tentative_value->ParseFrom(value)) {
+ if (msg) {
+ *msg += (string(kError) + "illegal value '" + value +
+ + "' specified for " + flag->type_name() + " flag '"
+ + flag->name() + "'\n");
+ }
+ delete tentative_value;
+ return false;
+ } else if (!flag->Validate(*tentative_value)) {
+ if (msg) {
+ *msg += (string(kError) + "failed validation of new value "
+ + "'" + tentative_value->ToString() + "' for flag '" +
+ + flag->name() + "'\n");
+ }
+ delete tentative_value;
+ return false;
+ } else {
+ flag_value->CopyFrom(*tentative_value);
+ if (msg) {
+ *msg += (string(flag->name()) + " set to " + flag_value->ToString()
+ + "\n");
+ }
+ delete tentative_value;
+ return true;
+ }
+}
+
+bool FlagRegistry::SetFlagLocked(CommandLineFlag* flag,
+ const char* value,
+ FlagSettingMode set_mode,
+ string* msg) {
+ flag->UpdateModifiedBit();
+ switch (set_mode) {
+ case SET_FLAGS_VALUE: {
+ // set or modify the flag's value
+ if (!TryParseLocked(flag, flag->current_, value, msg))
+ return false;
+ flag->modified_ = true;
+ break;
+ }
+ case SET_FLAG_IF_DEFAULT: {
+ // set the flag's value, but only if it hasn't been set by someone else
+ if (!flag->modified_) {
+ if (!TryParseLocked(flag, flag->current_, value, msg))
+ return false;
+ flag->modified_ = true;
+ } else {
+ *msg = string(flag->name()) + " set to " + flag->current_value();
+ }
+ break;
+ }
+ case SET_FLAGS_DEFAULT: {
+ // modify the flag's default-value
+ if (!TryParseLocked(flag, flag->defvalue_, value, msg))
+ return false;
+ if (!flag->modified_) {
+ // Need to set both defvalue *and* current, in this case
+ TryParseLocked(flag, flag->current_, value, NULL);
+ }
+ break;
+ }
+ default: {
+ // unknown set_mode
+ assert(false);
+ return false;
+ }
+ }
+
+ return true;
+}
+
+class FlagRegistryLock {
+ public:
+ explicit FlagRegistryLock(FlagRegistry* fr) : fr_(fr) { fr_->Lock(); }
+ ~FlagRegistryLock() { fr_->Unlock(); }
+ private:
+ FlagRegistry *const fr_;
+};
+
+// --------------------------------------------------------------------
+// CommandLineFlagParser
+// Parsing is done in two stages. In the first, we go through
+// argv. For every flag-like arg we can make sense of, we parse
+// it and set the appropriate FLAGS_* variable. For every flag-
+// like arg we can't make sense of, we store it in a vector,
+// along with an explanation of the trouble. In stage 2, we
+// handle the 'reporting' flags like --help and --mpm_version.
+// (This is via a call to HandleCommandLineHelpFlags(), in
+// gflags_reporting.cc.)
+// An optional stage 3 prints out the error messages.
+// This is a bit of a simplification. For instance, --flagfile
+// is handled as soon as it's seen in stage 1, not in stage 2.
+// --------------------------------------------------------------------
+
+class CommandLineFlagParser {
+ public:
+ // The argument is the flag-registry to register the parsed flags in
+ explicit CommandLineFlagParser(FlagRegistry* reg) : registry_(reg) {}
+ ~CommandLineFlagParser() {}
+
+ // Stage 1: Every time this is called, it reads all flags in argv.
+ // However, it ignores all flags that have been successfully set
+ // before. Typically this is only called once, so this 'reparsing'
+ // behavior isn't important. It can be useful when trying to
+ // reparse after loading a dll, though.
+ uint32 ParseNewCommandLineFlags(int* argc, char*** argv, bool remove_flags);
+
+ // Stage 2: print reporting info and exit, if requested.
+ // In gflags_reporting.cc:HandleCommandLineHelpFlags().
+
+ // Stage 3: validate all the commandline flags that have validators
+ // registered.
+ void ValidateAllFlags();
+
+ // Stage 4: report any errors and return true if any were found.
+ bool ReportErrors();
+
+ // Set a particular command line option. "newval" is a string
+ // describing the new value that the option has been set to. If
+ // option_name does not specify a valid option name, or value is not
+ // a valid value for option_name, newval is empty. Does recursive
+ // processing for --flagfile and --fromenv. Returns the new value
+ // if everything went ok, or empty-string if not. (Actually, the
+ // return-string could hold many flag/value pairs due to --flagfile.)
+ // NB: Must have called registry_->Lock() before calling this function.
+ string ProcessSingleOptionLocked(CommandLineFlag* flag,
+ const char* value,
+ FlagSettingMode set_mode);
+
+ // Set a whole batch of command line options as specified by contentdata,
+ // which is in flagfile format (and probably has been read from a flagfile).
+ // Returns the new value if everything went ok, or empty-string if
+ // not. (Actually, the return-string could hold many flag/value
+ // pairs due to --flagfile.)
+ // NB: Must have called registry_->Lock() before calling this function.
+ string ProcessOptionsFromStringLocked(const string& contentdata,
+ FlagSettingMode set_mode);
+
+ // These are the 'recursive' flags, defined at the top of this file.
+ // Whenever we see these flags on the commandline, we must take action.
+ // These are called by ProcessSingleOptionLocked and, similarly, return
+ // new values if everything went ok, or the empty-string if not.
+ string ProcessFlagfileLocked(const string& flagval, FlagSettingMode set_mode);
+ // diff fromenv/tryfromenv
+ string ProcessFromenvLocked(const string& flagval, FlagSettingMode set_mode,
+ bool errors_are_fatal);
+
+ private:
+ FlagRegistry* const registry_;
+ map<string, string> error_flags_; // map from name to error message
+ // This could be a set<string>, but we reuse the map to minimize the .o size
+ map<string, string> undefined_names_; // --[flag] name was not registered
+};
+
+
+// Parse a list of (comma-separated) flags.
+static void ParseFlagList(const char* value, vector<string>* flags) {
+ for (const char *p = value; p && *p; value = p) {
+ p = strchr(value, ',');
+ int len;
+ if (p) {
+ len = static_cast<int>(p - value);
+ p++;
+ } else {
+ len = static_cast<int>(strlen(value));
+ }
+
+ if (len == 0)
+ ReportError(DIE, "ERROR: empty flaglist entry\n");
+ if (value[0] == '-')
+ ReportError(DIE, "ERROR: flag \"%*s\" begins with '-'\n", len, value);
+
+ flags->push_back(string(value, len));
+ }
+}
+
+// Snarf an entire file into a C++ string. This is just so that we
+// can do all the I/O in one place and not worry about it everywhere.
+// Plus, it's convenient to have the whole file contents at hand.
+// Adds a newline at the end of the file.
+#define PFATAL(s) do { perror(s); commandlineflags_exitfunc(1); } while (0)
+
+static string ReadFileIntoString(const char* filename) {
+ const int kBufSize = 8092;
+ char buffer[kBufSize];
+ string s;
+ FILE* fp = fopen(filename, "r");
+ if (!fp) PFATAL(filename);
+ size_t n;
+ while ( (n=fread(buffer, 1, kBufSize, fp)) > 0 ) {
+ if (ferror(fp)) PFATAL(filename);
+ s.append(buffer, n);
+ }
+ fclose(fp);
+ return s;
+}
+
+uint32 CommandLineFlagParser::ParseNewCommandLineFlags(int* argc, char*** argv,
+ bool remove_flags) {
+ const char *program_name = strrchr((*argv)[0], PATH_SEPARATOR); // nix path
+ program_name = (program_name == NULL ? (*argv)[0] : program_name+1);
+
+ int first_nonopt = *argc; // for non-options moved to the end
+
+ registry_->Lock();
+ for (int i = 1; i < first_nonopt; i++) {
+ char* arg = (*argv)[i];
+
+ // Like getopt(), we permute non-option flags to be at the end.
+ if (arg[0] != '-' || // must be a program argument
+ (arg[0] == '-' && arg[1] == '\0')) { // "-" is an argument, not a flag
+ memmove((*argv) + i, (*argv) + i+1, (*argc - (i+1)) * sizeof((*argv)[i]));
+ (*argv)[*argc-1] = arg; // we go last
+ first_nonopt--; // we've been pushed onto the stack
+ i--; // to undo the i++ in the loop
+ continue;
+ }
+
+ if (arg[0] == '-') arg++; // allow leading '-'
+ if (arg[0] == '-') arg++; // or leading '--'
+
+ // -- alone means what it does for GNU: stop options parsing
+ if (*arg == '\0') {
+ first_nonopt = i+1;
+ break;
+ }
+
+ // Find the flag object for this option
+ string key;
+ const char* value;
+ string error_message;
+ CommandLineFlag* flag = registry_->SplitArgumentLocked(arg, &key, &value,
+ &error_message);
+ if (flag == NULL) {
+ undefined_names_[key] = ""; // value isn't actually used
+ error_flags_[key] = error_message;
+ continue;
+ }
+
+ if (value == NULL) {
+ // Boolean options are always assigned a value by SplitArgumentLocked()
+ assert(strcmp(flag->type_name(), "bool") != 0);
+ if (i+1 >= first_nonopt) {
+ // This flag needs a value, but there is nothing available
+ error_flags_[key] = (string(kError) + "flag '" + (*argv)[i] + "'"
+ + " is missing its argument");
+ if (flag->help() && flag->help()[0] > '\001') {
+ // Be useful in case we have a non-stripped description.
+ error_flags_[key] += string("; flag description: ") + flag->help();
+ }
+ error_flags_[key] += "\n";
+ break; // we treat this as an unrecoverable error
+ } else {
+ value = (*argv)[++i]; // read next arg for value
+
+ // Heuristic to detect the case where someone treats a string arg
+ // like a bool:
+ // --my_string_var --foo=bar
+ // We look for a flag of string type, whose value begins with a
+ // dash, and where the flag-name and value are separated by a
+ // space rather than an '='.
+ // To avoid false positives, we also require the word "true"
+ // or "false" in the help string. Without this, a valid usage
+ // "-lat -30.5" would trigger the warning. The common cases we
+ // want to solve talk about true and false as values.
+ if (value[0] == '-'
+ && strcmp(flag->type_name(), "string") == 0
+ && (strstr(flag->help(), "true")
+ || strstr(flag->help(), "false"))) {
+ fprintf(stderr, "Did you really mean to set flag '%s'"
+ " to the value '%s'?\n",
+ flag->name(), value);
+ }
+ }
+ }
+
+ // TODO(csilvers): only set a flag if we hadn't set it before here
+ ProcessSingleOptionLocked(flag, value, SET_FLAGS_VALUE);
+ }
+ registry_->Unlock();
+
+ if (remove_flags) { // Fix up argc and argv by removing command line flags
+ (*argv)[first_nonopt-1] = (*argv)[0];
+ (*argv) += (first_nonopt-1);
+ (*argc) -= (first_nonopt-1);
+ first_nonopt = 1; // because we still don't count argv[0]
+ }
+
+ logging_is_probably_set_up = true; // because we've parsed --logdir, etc.
+
+ return first_nonopt;
+}
+
+string CommandLineFlagParser::ProcessFlagfileLocked(const string& flagval,
+ FlagSettingMode set_mode) {
+ if (flagval.empty())
+ return "";
+
+ string msg;
+ vector<string> filename_list;
+ ParseFlagList(flagval.c_str(), &filename_list); // take a list of filenames
+ for (size_t i = 0; i < filename_list.size(); ++i) {
+ const char* file = filename_list[i].c_str();
+ msg += ProcessOptionsFromStringLocked(ReadFileIntoString(file), set_mode);
+ }
+ return msg;
+}
+
+string CommandLineFlagParser::ProcessFromenvLocked(const string& flagval,
+ FlagSettingMode set_mode,
+ bool errors_are_fatal) {
+ if (flagval.empty())
+ return "";
+
+ string msg;
+ vector<string> flaglist;
+ ParseFlagList(flagval.c_str(), &flaglist);
+
+ for (size_t i = 0; i < flaglist.size(); ++i) {
+ const char* flagname = flaglist[i].c_str();
+ CommandLineFlag* flag = registry_->FindFlagLocked(flagname);
+ if (flag == NULL) {
+ error_flags_[flagname] = (string(kError) + "unknown command line flag"
+ + " '" + flagname + "'"
+ + " (via --fromenv or --tryfromenv)\n");
+ undefined_names_[flagname] = "";
+ continue;
+ }
+
+ const string envname = string("FLAGS_") + string(flagname);
+ const char* envval = getenv(envname.c_str());
+ if (!envval) {
+ if (errors_are_fatal) {
+ error_flags_[flagname] = (string(kError) + envname +
+ " not found in environment\n");
+ }
+ continue;
+ }
+
+ // Avoid infinite recursion.
+ if ((strcmp(envval, "fromenv") == 0) ||
+ (strcmp(envval, "tryfromenv") == 0)) {
+ error_flags_[flagname] = (string(kError) + "infinite recursion on " +
+ "environment flag '" + envval + "'\n");
+ continue;
+ }
+
+ msg += ProcessSingleOptionLocked(flag, envval, set_mode);
+ }
+ return msg;
+}
+
+string CommandLineFlagParser::ProcessSingleOptionLocked(
+ CommandLineFlag* flag, const char* value, FlagSettingMode set_mode) {
+ string msg;
+ if (value && !registry_->SetFlagLocked(flag, value, set_mode, &msg)) {
+ error_flags_[flag->name()] = msg;
+ return "";
+ }
+
+ // The recursive flags, --flagfile and --fromenv and --tryfromenv,
+ // must be dealt with as soon as they're seen. They will emit
+ // messages of their own.
+ if (strcmp(flag->name(), "flagfile") == 0) {
+ msg += ProcessFlagfileLocked(FLAGS_flagfile, set_mode);
+
+ } else if (strcmp(flag->name(), "fromenv") == 0) {
+ // last arg indicates envval-not-found is fatal (unlike in --tryfromenv)
+ msg += ProcessFromenvLocked(FLAGS_fromenv, set_mode, true);
+
+ } else if (strcmp(flag->name(), "tryfromenv") == 0) {
+ msg += ProcessFromenvLocked(FLAGS_tryfromenv, set_mode, false);
+ }
+
+ return msg;
+}
+
+void CommandLineFlagParser::ValidateAllFlags() {
+ FlagRegistryLock frl(registry_);
+ for (FlagRegistry::FlagConstIterator i = registry_->flags_.begin();
+ i != registry_->flags_.end(); ++i) {
+ if (!i->second->ValidateCurrent()) {
+ // only set a message if one isn't already there. (If there's
+ // an error message, our job is done, even if it's not exactly
+ // the same error.)
+ if (error_flags_[i->second->name()].empty())
+ error_flags_[i->second->name()] =
+ string(kError) + "--" + i->second->name() +
+ " must be set on the commandline"
+ " (default value fails validation)\n";
+ }
+ }
+}
+
+bool CommandLineFlagParser::ReportErrors() {
+ // error_flags_ indicates errors we saw while parsing.
+ // But we ignore undefined-names if ok'ed by --undef_ok
+ if (!FLAGS_undefok.empty()) {
+ vector<string> flaglist;
+ ParseFlagList(FLAGS_undefok.c_str(), &flaglist);
+ for (size_t i = 0; i < flaglist.size(); ++i) {
+ // We also deal with --no<flag>, in case the flagname was boolean
+ const string no_version = string("no") + flaglist[i];
+ if (undefined_names_.find(flaglist[i]) != undefined_names_.end()) {
+ error_flags_[flaglist[i]] = ""; // clear the error message
+ } else if (undefined_names_.find(no_version) != undefined_names_.end()) {
+ error_flags_[no_version] = "";
+ }
+ }
+ }
+ // Likewise, if they decided to allow reparsing, all undefined-names
+ // are ok; we just silently ignore them now, and hope that a future
+ // parse will pick them up somehow.
+ if (allow_command_line_reparsing) {
+ for (map<string, string>::const_iterator it = undefined_names_.begin();
+ it != undefined_names_.end(); ++it)
+ error_flags_[it->first] = ""; // clear the error message
+ }
+
+ bool found_error = false;
+ string error_message;
+ for (map<string, string>::const_iterator it = error_flags_.begin();
+ it != error_flags_.end(); ++it) {
+ if (!it->second.empty()) {
+ error_message.append(it->second.data(), it->second.size());
+ found_error = true;
+ }
+ }
+ if (found_error)
+ ReportError(DO_NOT_DIE, "%s", error_message.c_str());
+ return found_error;
+}
+
+string CommandLineFlagParser::ProcessOptionsFromStringLocked(
+ const string& contentdata, FlagSettingMode set_mode) {
+ string retval;
+ const char* flagfile_contents = contentdata.c_str();
+ bool flags_are_relevant = true; // set to false when filenames don't match
+ bool in_filename_section = false;
+
+ const char* line_end = flagfile_contents;
+ // We read this file a line at a time.
+ for (; line_end; flagfile_contents = line_end + 1) {
+ while (*flagfile_contents && isspace(*flagfile_contents))
+ ++flagfile_contents;
+ line_end = strchr(flagfile_contents, '\n');
+ size_t len = line_end ? static_cast<size_t>(line_end - flagfile_contents)
+ : strlen(flagfile_contents);
+ string line(flagfile_contents, len);
+
+ // Each line can be one of four things:
+ // 1) A comment line -- we skip it
+ // 2) An empty line -- we skip it
+ // 3) A list of filenames -- starts a new filenames+flags section
+ // 4) A --flag=value line -- apply if previous filenames match
+ if (line.empty() || line[0] == '#') {
+ // comment or empty line; just ignore
+
+ } else if (line[0] == '-') { // flag
+ in_filename_section = false; // instead, it was a flag-line
+ if (!flags_are_relevant) // skip this flag; applies to someone else
+ continue;
+
+ const char* name_and_val = line.c_str() + 1; // skip the leading -
+ if (*name_and_val == '-')
+ name_and_val++; // skip second - too
+ string key;
+ const char* value;
+ string error_message;
+ CommandLineFlag* flag = registry_->SplitArgumentLocked(name_and_val,
+ &key, &value,
+ &error_message);
+ // By API, errors parsing flagfile lines are silently ignored.
+ if (flag == NULL) {
+ // "WARNING: flagname '" + key + "' not found\n"
+ } else if (value == NULL) {
+ // "WARNING: flagname '" + key + "' missing a value\n"
+ } else {
+ retval += ProcessSingleOptionLocked(flag, value, set_mode);
+ }
+
+ } else { // a filename!
+ if (!in_filename_section) { // start over: assume filenames don't match
+ in_filename_section = true;
+ flags_are_relevant = false;
+ }
+
+ // Split the line up at spaces into glob-patterns
+ const char* space = line.c_str(); // just has to be non-NULL
+ for (const char* word = line.c_str(); *space; word = space+1) {
+ if (flags_are_relevant) // we can stop as soon as we match
+ break;
+ space = strchr(word, ' ');
+ if (space == NULL)
+ space = word + strlen(word);
+ const string glob(word, space - word);
+ // We try matching both against the full argv0 and basename(argv0)
+#ifdef HAVE_FNMATCH_H
+ if (fnmatch(glob.c_str(),
+ ProgramInvocationName(),
+ FNM_PATHNAME) == 0 ||
+ fnmatch(glob.c_str(),
+ ProgramInvocationShortName(),
+ FNM_PATHNAME) == 0) {
+#else // !HAVE_FNMATCH_H
+ if ((glob == ProgramInvocationName()) ||
+ (glob == ProgramInvocationShortName())) {
+#endif // HAVE_FNMATCH_H
+ flags_are_relevant = true;
+ }
+ }
+ }
+ }
+ return retval;
+}
+
+// --------------------------------------------------------------------
+// GetFromEnv()
+// AddFlagValidator()
+// These are helper functions for routines like BoolFromEnv() and
+// RegisterFlagValidator, defined below. They're defined here so
+// they can live in the unnamed namespace (which makes friendship
+// declarations for these classes possible).
+// --------------------------------------------------------------------
+
+template<typename T>
+T GetFromEnv(const char *varname, const char* type, T dflt) {
+ const char* const valstr = getenv(varname);
+ if (!valstr)
+ return dflt;
+ FlagValue ifv(new T, type, true);
+ if (!ifv.ParseFrom(valstr))
+ ReportError(DIE, "ERROR: error parsing env variable '%s' with value '%s'\n",
+ varname, valstr);
+ return OTHER_VALUE_AS(ifv, T);
+}
+
+bool AddFlagValidator(const void* flag_ptr, ValidateFnProto validate_fn_proto) {
+ // We want a lock around this routine, in case two threads try to
+ // add a validator (hopefully the same one!) at once. We could use
+ // our own thread, but we need to loook at the registry anyway, so
+ // we just steal that one.
+ FlagRegistry* const registry = FlagRegistry::GlobalRegistry();
+ FlagRegistryLock frl(registry);
+ // First, find the flag whose current-flag storage is 'flag'.
+ // This is the CommandLineFlag whose current_->value_buffer_ == flag
+ CommandLineFlag* flag = registry->FindFlagViaPtrLocked(flag_ptr);
+ if (!flag) {
+ // WARNING << "Ignoring RegisterValidateFunction() for flag pointer "
+ // << flag_ptr << ": no flag found at that address";
+ return false;
+ } else if (validate_fn_proto == flag->validate_function()) {
+ return true; // ok to register the same function over and over again
+ } else if (validate_fn_proto != NULL && flag->validate_function() != NULL) {
+ // WARNING << "Ignoring RegisterValidateFunction() for flag '"
+ // << flag->name() << "': validate-fn already registered";
+ return false;
+ } else {
+ flag->validate_fn_proto_ = validate_fn_proto;
+ return true;
+ }
+}
+
+} // end unnamed namespaces
+
+
+// Now define the functions that are exported via the .h file
+
+// --------------------------------------------------------------------
+// FlagRegisterer
+// This class exists merely to have a global constructor (the
+// kind that runs before main(), that goes an initializes each
+// flag that's been declared. Note that it's very important we
+// don't have a destructor that deletes flag_, because that would
+// cause us to delete current_storage/defvalue_storage as well,
+// which can cause a crash if anything tries to access the flag
+// values in a global destructor.
+// --------------------------------------------------------------------
+
+FlagRegisterer::FlagRegisterer(const char* name, const char* type,
+ const char* help, const char* filename,
+ void* current_storage, void* defvalue_storage) {
+ if (help == NULL)
+ help = "";
+ // FlagValue expects the type-name to not include any namespace
+ // components, so we get rid of those, if any.
+ if (strchr(type, ':'))
+ type = strrchr(type, ':') + 1;
+ FlagValue* current = new FlagValue(current_storage, type, false);
+ FlagValue* defvalue = new FlagValue(defvalue_storage, type, false);
+ // Importantly, flag_ will never be deleted, so storage is always good.
+ CommandLineFlag* flag = new CommandLineFlag(name, help, filename,
+ current, defvalue);
+ FlagRegistry::GlobalRegistry()->RegisterFlag(flag); // default registry
+}
+
+// --------------------------------------------------------------------
+// GetAllFlags()
+// The main way the FlagRegistry class exposes its data. This
+// returns, as strings, all the info about all the flags in
+// the main registry, sorted first by filename they are defined
+// in, and then by flagname.
+// --------------------------------------------------------------------
+
+struct FilenameFlagnameCmp {
+ bool operator()(const CommandLineFlagInfo& a,
+ const CommandLineFlagInfo& b) const {
+ int cmp = strcmp(a.filename.c_str(), b.filename.c_str());
+ if (cmp == 0)
+ cmp = strcmp(a.name.c_str(), b.name.c_str()); // secondary sort key
+ return cmp < 0;
+ }
+};
+
+void GetAllFlags(vector<CommandLineFlagInfo>* OUTPUT) {
+ FlagRegistry* const registry = FlagRegistry::GlobalRegistry();
+ registry->Lock();
+ for (FlagRegistry::FlagConstIterator i = registry->flags_.begin();
+ i != registry->flags_.end(); ++i) {
+ CommandLineFlagInfo fi;
+ i->second->FillCommandLineFlagInfo(&fi);
+ OUTPUT->push_back(fi);
+ }
+ registry->Unlock();
+ // Now sort the flags, first by filename they occur in, then alphabetically
+ sort(OUTPUT->begin(), OUTPUT->end(), FilenameFlagnameCmp());
+}
+
+// --------------------------------------------------------------------
+// SetArgv()
+// GetArgvs()
+// GetArgv()
+// GetArgv0()
+// ProgramInvocationName()
+// ProgramInvocationShortName()
+// SetUsageMessage()
+// ProgramUsage()
+// Functions to set and get argv. Typically the setter is called
+// by ParseCommandLineFlags. Also can get the ProgramUsage string,
+// set by SetUsageMessage.
+// --------------------------------------------------------------------
+
+// These values are not protected by a Mutex because they are normally
+// set only once during program startup.
+static const char* argv0 = "UNKNOWN"; // just the program name
+static const char* cmdline = ""; // the entire command-line
+static vector<string> argvs;
+static uint32 argv_sum = 0;
+static const char* program_usage = NULL;
+
+void SetArgv(int argc, const char** argv) {
+ static bool called_set_argv = false;
+ if (called_set_argv) // we already have an argv for you
+ return;
+
+ called_set_argv = true;
+
+ assert(argc > 0); // every program has at least a progname
+ argv0 = strdup(argv[0]); // small memory leak, but fn only called once
+ assert(argv0);
+
+ string cmdline_string; // easier than doing strcats
+ for (int i = 0; i < argc; i++) {
+ if (i != 0) {
+ cmdline_string += " ";
+ }
+ cmdline_string += argv[i];
+ argvs.push_back(argv[i]);
+ }
+ cmdline = strdup(cmdline_string.c_str()); // another small memory leak
+ assert(cmdline);
+
+ // Compute a simple sum of all the chars in argv
+ for (const char* c = cmdline; *c; c++)
+ argv_sum += *c;
+}
+
+const vector<string>& GetArgvs() { return argvs; }
+const char* GetArgv() { return cmdline; }
+const char* GetArgv0() { return argv0; }
+uint32 GetArgvSum() { return argv_sum; }
+const char* ProgramInvocationName() { // like the GNU libc fn
+ return GetArgv0();
+}
+const char* ProgramInvocationShortName() { // like the GNU libc fn
+ const char* slash = strrchr(argv0, '/');
+#ifdef OS_WINDOWS
+ if (!slash) slash = strrchr(argv0, '\\');
+#endif
+ return slash ? slash + 1 : argv0;
+}
+
+void SetUsageMessage(const string& usage) {
+ if (program_usage != NULL)
+ ReportError(DIE, "ERROR: SetUsageMessage() called twice\n");
+ program_usage = strdup(usage.c_str()); // small memory leak
+}
+
+const char* ProgramUsage() {
+ if (program_usage) {
+ return program_usage;
+ }
+ return "Warning: SetUsageMessage() never called";
+}
+
+// --------------------------------------------------------------------
+// GetCommandLineOption()
+// GetCommandLineFlagInfo()
+// GetCommandLineFlagInfoOrDie()
+// SetCommandLineOption()
+// SetCommandLineOptionWithMode()
+// The programmatic way to set a flag's value, using a string
+// for its name rather than the variable itself (that is,
+// SetCommandLineOption("foo", x) rather than FLAGS_foo = x).
+// There's also a bit more flexibility here due to the various
+// set-modes, but typically these are used when you only have
+// that flag's name as a string, perhaps at runtime.
+// All of these work on the default, global registry.
+// For GetCommandLineOption, return false if no such flag
+// is known, true otherwise. We clear "value" if a suitable
+// flag is found.
+// --------------------------------------------------------------------
+
+
+bool GetCommandLineOption(const char* name, string* value) {
+ if (NULL == name)
+ return false;
+ assert(value);
+
+ FlagRegistry* const registry = FlagRegistry::GlobalRegistry();
+ FlagRegistryLock frl(registry);
+ CommandLineFlag* flag = registry->FindFlagLocked(name);
+ if (flag == NULL) {
+ return false;
+ } else {
+ *value = flag->current_value();
+ return true;
+ }
+}
+
+bool GetCommandLineFlagInfo(const char* name, CommandLineFlagInfo* OUTPUT) {
+ if (NULL == name) return false;
+ FlagRegistry* const registry = FlagRegistry::GlobalRegistry();
+ FlagRegistryLock frl(registry);
+ CommandLineFlag* flag = registry->FindFlagLocked(name);
+ if (flag == NULL) {
+ return false;
+ } else {
+ assert(OUTPUT);
+ flag->FillCommandLineFlagInfo(OUTPUT);
+ return true;
+ }
+}
+
+CommandLineFlagInfo GetCommandLineFlagInfoOrDie(const char* name) {
+ CommandLineFlagInfo info;
+ if (!GetCommandLineFlagInfo(name, &info)) {
+ fprintf(stderr, "FATAL ERROR: flag name '%s' doesn't exist\n", name);
+ commandlineflags_exitfunc(1); // almost certainly exit()
+ }
+ return info;
+}
+
+string SetCommandLineOptionWithMode(const char* name, const char* value,
+ FlagSettingMode set_mode) {
+ string result;
+ FlagRegistry* const registry = FlagRegistry::GlobalRegistry();
+ FlagRegistryLock frl(registry);
+ CommandLineFlag* flag = registry->FindFlagLocked(name);
+ if (flag) {
+ CommandLineFlagParser parser(registry);
+ result = parser.ProcessSingleOptionLocked(flag, value, set_mode);
+ if (!result.empty()) { // in the error case, we've already logged
+ // You could consider logging this change, if you wanted to know it:
+ //fprintf(stderr, "%sFLAGS_%s\n",
+ // (set_mode == SET_FLAGS_DEFAULT ? "default value of " : ""),
+ // result);
+ }
+ }
+ // The API of this function is that we return empty string on error
+ return result;
+}
+
+string SetCommandLineOption(const char* name, const char* value) {
+ return SetCommandLineOptionWithMode(name, value, SET_FLAGS_VALUE);
+}
+
+// --------------------------------------------------------------------
+// FlagSaver
+// FlagSaverImpl
+// This class stores the states of all flags at construct time,
+// and restores all flags to that state at destruct time.
+// Its major implementation challenge is that it never modifies
+// pointers in the 'main' registry, so global FLAG_* vars always
+// point to the right place.
+// --------------------------------------------------------------------
+
+class FlagSaverImpl {
+ public:
+ // Constructs an empty FlagSaverImpl object.
+ explicit FlagSaverImpl(FlagRegistry* main_registry)
+ : main_registry_(main_registry) { }
+ ~FlagSaverImpl() {
+ // reclaim memory from each of our CommandLineFlags
+ vector<CommandLineFlag*>::const_iterator it;
+ for (it = backup_registry_.begin(); it != backup_registry_.end(); ++it)
+ delete *it;
+ }
+
+ // Saves the flag states from the flag registry into this object.
+ // It's an error to call this more than once.
+ // Must be called when the registry mutex is not held.
+ void SaveFromRegistry() {
+ FlagRegistryLock frl(main_registry_);
+ assert(backup_registry_.empty()); // call only once!
+ for (FlagRegistry::FlagConstIterator it = main_registry_->flags_.begin();
+ it != main_registry_->flags_.end();
+ ++it) {
+ const CommandLineFlag* main = it->second;
+ // Sets up all the const variables in backup correctly
+ CommandLineFlag* backup = new CommandLineFlag(
+ main->name(), main->help(), main->filename(),
+ main->current_->New(), main->defvalue_->New());
+ // Sets up all the non-const variables in backup correctly
+ backup->CopyFrom(*main);
+ backup_registry_.push_back(backup); // add it to a convenient list
+ }
+ }
+
+ // Restores the saved flag states into the flag registry. We
+ // assume no flags were added or deleted from the registry since
+ // the SaveFromRegistry; if they were, that's trouble! Must be
+ // called when the registry mutex is not held.
+ void RestoreToRegistry() {
+ FlagRegistryLock frl(main_registry_);
+ vector<CommandLineFlag*>::const_iterator it;
+ for (it = backup_registry_.begin(); it != backup_registry_.end(); ++it) {
+ CommandLineFlag* main = main_registry_->FindFlagLocked((*it)->name());
+ if (main != NULL) { // if NULL, flag got deleted from registry(!)
+ main->CopyFrom(**it);
+ }
+ }
+ }
+
+ private:
+ FlagRegistry* const main_registry_;
+ vector<CommandLineFlag*> backup_registry_;
+
+ FlagSaverImpl(const FlagSaverImpl&); // no copying!
+ void operator=(const FlagSaverImpl&);
+};
+
+FlagSaver::FlagSaver()
+ : impl_(new FlagSaverImpl(FlagRegistry::GlobalRegistry())) {
+ impl_->SaveFromRegistry();
+}
+
+FlagSaver::~FlagSaver() {
+ impl_->RestoreToRegistry();
+ delete impl_;
+}
+
+
+// --------------------------------------------------------------------
+// CommandlineFlagsIntoString()
+// ReadFlagsFromString()
+// AppendFlagsIntoFile()
+// ReadFromFlagsFile()
+// These are mostly-deprecated routines that stick the
+// commandline flags into a file/string and read them back
+// out again. I can see a use for CommandlineFlagsIntoString,
+// for creating a flagfile, but the rest don't seem that useful
+// -- some, I think, are a poor-man's attempt at FlagSaver --
+// and are included only until we can delete them from callers.
+// Note they don't save --flagfile flags (though they do save
+// the result of having called the flagfile, of course).
+// --------------------------------------------------------------------
+
+static string TheseCommandlineFlagsIntoString(
+ const vector<CommandLineFlagInfo>& flags) {
+ vector<CommandLineFlagInfo>::const_iterator i;
+
+ size_t retval_space = 0;
+ for (i = flags.begin(); i != flags.end(); ++i) {
+ // An (over)estimate of how much space it will take to print this flag
+ retval_space += i->name.length() + i->current_value.length() + 5;
+ }
+
+ string retval;
+ retval.reserve(retval_space);
+ for (i = flags.begin(); i != flags.end(); ++i) {
+ retval += "--";
+ retval += i->name;
+ retval += "=";
+ retval += i->current_value;
+ retval += "\n";
+ }
+ return retval;
+}
+
+string CommandlineFlagsIntoString() {
+ vector<CommandLineFlagInfo> sorted_flags;
+ GetAllFlags(&sorted_flags);
+ return TheseCommandlineFlagsIntoString(sorted_flags);
+}
+
+bool ReadFlagsFromString(const string& flagfilecontents,
+ const char* /*prog_name*/, // TODO(csilvers): nix this
+ bool errors_are_fatal) {
+ FlagRegistry* const registry = FlagRegistry::GlobalRegistry();
+ FlagSaverImpl saved_states(registry);
+ saved_states.SaveFromRegistry();
+
+ CommandLineFlagParser parser(registry);
+ registry->Lock();
+ parser.ProcessOptionsFromStringLocked(flagfilecontents, SET_FLAGS_VALUE);
+ registry->Unlock();
+ // Should we handle --help and such when reading flags from a string? Sure.
+ HandleCommandLineHelpFlags();
+ if (parser.ReportErrors()) {
+ // Error. Restore all global flags to their previous values.
+ if (errors_are_fatal)
+ commandlineflags_exitfunc(1); // almost certainly exit()
+ saved_states.RestoreToRegistry();
+ return false;
+ }
+ return true;
+}
+
+// TODO(csilvers): nix prog_name in favor of ProgramInvocationShortName()
+bool AppendFlagsIntoFile(const string& filename, const char *prog_name) {
+ FILE *fp = fopen(filename.c_str(), "a");
+ if (!fp) {
+ return false;
+ }
+
+ if (prog_name)
+ fprintf(fp, "%s\n", prog_name);
+
+ vector<CommandLineFlagInfo> flags;
+ GetAllFlags(&flags);
+ // But we don't want --flagfile, which leads to weird recursion issues
+ vector<CommandLineFlagInfo>::iterator i;
+ for (i = flags.begin(); i != flags.end(); ++i) {
+ if (strcmp(i->name.c_str(), "flagfile") == 0) {
+ flags.erase(i);
+ break;
+ }
+ }
+ fprintf(fp, "%s", TheseCommandlineFlagsIntoString(flags).c_str());
+
+ fclose(fp);
+ return true;
+}
+
+bool ReadFromFlagsFile(const string& filename, const char* prog_name,
+ bool errors_are_fatal) {
+ return ReadFlagsFromString(ReadFileIntoString(filename.c_str()),
+ prog_name, errors_are_fatal);
+}
+
+
+// --------------------------------------------------------------------
+// BoolFromEnv()
+// Int32FromEnv()
+// Int64FromEnv()
+// Uint64FromEnv()
+// DoubleFromEnv()
+// StringFromEnv()
+// Reads the value from the environment and returns it.
+// We use an FlagValue to make the parsing easy.
+// Example usage:
+// DEFINE_bool(myflag, BoolFromEnv("MYFLAG_DEFAULT", false), "whatever");
+// --------------------------------------------------------------------
+
+bool BoolFromEnv(const char *v, bool dflt) {
+ return GetFromEnv(v, "bool", dflt);
+}
+int32 Int32FromEnv(const char *v, int32 dflt) {
+ return GetFromEnv(v, "int32", dflt);
+}
+int64 Int64FromEnv(const char *v, int64 dflt) {
+ return GetFromEnv(v, "int64", dflt);
+}
+uint64 Uint64FromEnv(const char *v, uint64 dflt) {
+ return GetFromEnv(v, "uint64", dflt);
+}
+double DoubleFromEnv(const char *v, double dflt) {
+ return GetFromEnv(v, "double", dflt);
+}
+const char *StringFromEnv(const char *varname, const char *dflt) {
+ const char* const val = getenv(varname);
+ return val ? val : dflt;
+}
+
+
+// --------------------------------------------------------------------
+// RegisterFlagValidator()
+// RegisterFlagValidator() is the function that clients use to
+// 'decorate' a flag with a validation function. Once this is
+// done, every time the flag is set (including when the flag
+// is parsed from argv), the validator-function is called.
+// These functions return true if the validator was added
+// successfully, or false if not: the flag already has a validator,
+// (only one allowed per flag), the 1st arg isn't a flag, etc.
+// This function is not thread-safe.
+// --------------------------------------------------------------------
+
+bool RegisterFlagValidator(const bool* flag,
+ bool (*validate_fn)(const char*, bool)) {
+ return AddFlagValidator(flag, reinterpret_cast<ValidateFnProto>(validate_fn));
+}
+bool RegisterFlagValidator(const int32* flag,
+ bool (*validate_fn)(const char*, int32)) {
+ return AddFlagValidator(flag, reinterpret_cast<ValidateFnProto>(validate_fn));
+}
+bool RegisterFlagValidator(const int64* flag,
+ bool (*validate_fn)(const char*, int64)) {
+ return AddFlagValidator(flag, reinterpret_cast<ValidateFnProto>(validate_fn));
+}
+bool RegisterFlagValidator(const uint64* flag,
+ bool (*validate_fn)(const char*, uint64)) {
+ return AddFlagValidator(flag, reinterpret_cast<ValidateFnProto>(validate_fn));
+}
+bool RegisterFlagValidator(const double* flag,
+ bool (*validate_fn)(const char*, double)) {
+ return AddFlagValidator(flag, reinterpret_cast<ValidateFnProto>(validate_fn));
+}
+bool RegisterFlagValidator(const string* flag,
+ bool (*validate_fn)(const char*, const string&)) {
+ return AddFlagValidator(flag, reinterpret_cast<ValidateFnProto>(validate_fn));
+}
+
+
+// --------------------------------------------------------------------
+// ParseCommandLineFlags()
+// ParseCommandLineNonHelpFlags()
+// HandleCommandLineHelpFlags()
+// This is the main function called from main(), to actually
+// parse the commandline. It modifies argc and argv as described
+// at the top of gflags.h. You can also divide this
+// function into two parts, if you want to do work between
+// the parsing of the flags and the printing of any help output.
+// --------------------------------------------------------------------
+
+static uint32 ParseCommandLineFlagsInternal(int* argc, char*** argv,
+ bool remove_flags, bool do_report) {
+ SetArgv(*argc, const_cast<const char**>(*argv)); // save it for later
+
+ FlagRegistry* const registry = FlagRegistry::GlobalRegistry();
+ CommandLineFlagParser parser(registry);
+
+ // When we parse the commandline flags, we'll handle --flagfile,
+ // --tryfromenv, etc. as we see them (since flag-evaluation order
+ // may be important). But sometimes apps set FLAGS_tryfromenv/etc.
+ // manually before calling ParseCommandLineFlags. We want to evaluate
+ // those too, as if they were the first flags on the commandline.
+ registry->Lock();
+ parser.ProcessFlagfileLocked(FLAGS_flagfile, SET_FLAGS_VALUE);
+ // Last arg here indicates whether flag-not-found is a fatal error or not
+ parser.ProcessFromenvLocked(FLAGS_fromenv, SET_FLAGS_VALUE, true);
+ parser.ProcessFromenvLocked(FLAGS_tryfromenv, SET_FLAGS_VALUE, false);
+ registry->Unlock();
+
+ // Now get the flags specified on the commandline
+ const int r = parser.ParseNewCommandLineFlags(argc, argv, remove_flags);
+
+ if (do_report)
+ HandleCommandLineHelpFlags(); // may cause us to exit on --help, etc.
+
+ // See if any of the unset flags fail their validation checks
+ parser.ValidateAllFlags();
+
+ if (parser.ReportErrors()) // may cause us to exit on illegal flags
+ commandlineflags_exitfunc(1); // almost certainly exit()
+ return r;
+}
+
+uint32 ParseCommandLineFlags(int* argc, char*** argv, bool remove_flags) {
+ return ParseCommandLineFlagsInternal(argc, argv, remove_flags, true);
+}
+
+uint32 ParseCommandLineNonHelpFlags(int* argc, char*** argv,
+ bool remove_flags) {
+ return ParseCommandLineFlagsInternal(argc, argv, remove_flags, false);
+}
+
+// --------------------------------------------------------------------
+// AllowCommandLineReparsing()
+// ReparseCommandLineNonHelpFlags()
+// This is most useful for shared libraries. The idea is if
+// a flag is defined in a shared library that is dlopen'ed
+// sometime after main(), you can ParseCommandLineFlags before
+// the dlopen, then ReparseCommandLineNonHelpFlags() after the
+// dlopen, to get the new flags. But you have to explicitly
+// Allow() it; otherwise, you get the normal default behavior
+// of unrecognized flags calling a fatal error.
+// TODO(csilvers): this isn't used. Just delete it?
+// --------------------------------------------------------------------
+
+void AllowCommandLineReparsing() {
+ allow_command_line_reparsing = true;
+}
+
+uint32 ReparseCommandLineNonHelpFlags() {
+ // We make a copy of argc and argv to pass in
+ const vector<string>& argvs = GetArgvs();
+ int tmp_argc = static_cast<int>(argvs.size());
+ char** tmp_argv = new char* [tmp_argc + 1];
+ for (int i = 0; i < tmp_argc; ++i)
+ tmp_argv[i] = strdup(argvs[i].c_str()); // TODO(csilvers): don't dup
+
+ const int retval = ParseCommandLineNonHelpFlags(&tmp_argc, &tmp_argv, false);
+
+ for (int i = 0; i < tmp_argc; ++i)
+ free(tmp_argv[i]);
+ delete[] tmp_argv;
+
+ return retval;
+}
+
+void ShutDownCommandLineFlags() {
+ FlagRegistry::DeleteGlobalRegistry();
+}
+
+_END_GOOGLE_NAMESPACE_
diff --git a/extern/libmv/third_party/gflags/gflags.h b/extern/libmv/third_party/gflags/gflags.h
new file mode 100644
index 00000000000..cefbd62ae51
--- /dev/null
+++ b/extern/libmv/third_party/gflags/gflags.h
@@ -0,0 +1,589 @@
+// Copyright (c) 2006, Google Inc.
+// 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.
+
+// ---
+// Author: Ray Sidney
+// Revamped and reorganized by Craig Silverstein
+//
+// This is the file that should be included by any file which declares
+// or defines a command line flag or wants to parse command line flags
+// or print a program usage message (which will include information about
+// flags). Executive summary, in the form of an example foo.cc file:
+//
+// #include "foo.h" // foo.h has a line "DECLARE_int32(start);"
+// #include "validators.h" // hypothetical file defining ValidateIsFile()
+//
+// DEFINE_int32(end, 1000, "The last record to read");
+//
+// DEFINE_string(filename, "my_file.txt", "The file to read");
+// // Crash if the specified file does not exist.
+// static bool dummy = RegisterFlagValidator(&FLAGS_filename,
+// &ValidateIsFile);
+//
+// DECLARE_bool(verbose); // some other file has a DEFINE_bool(verbose, ...)
+//
+// void MyFunc() {
+// if (FLAGS_verbose) printf("Records %d-%d\n", FLAGS_start, FLAGS_end);
+// }
+//
+// Then, at the command-line:
+// ./foo --noverbose --start=5 --end=100
+//
+// For more details, see
+// doc/gflags.html
+//
+// --- A note about thread-safety:
+//
+// We describe many functions in this routine as being thread-hostile,
+// thread-compatible, or thread-safe. Here are the meanings we use:
+//
+// thread-safe: it is safe for multiple threads to call this routine
+// (or, when referring to a class, methods of this class)
+// concurrently.
+// thread-hostile: it is not safe for multiple threads to call this
+// routine (or methods of this class) concurrently. In gflags,
+// most thread-hostile routines are intended to be called early in,
+// or even before, main() -- that is, before threads are spawned.
+// thread-compatible: it is safe for multiple threads to read from
+// this variable (when applied to variables), or to call const
+// methods of this class (when applied to classes), as long as no
+// other thread is writing to the variable or calling non-const
+// methods of this class.
+
+#ifndef GOOGLE_GFLAGS_H_
+#define GOOGLE_GFLAGS_H_
+
+#include <string>
+#include <vector>
+
+// We care a lot about number of bits things take up. Unfortunately,
+// systems define their bit-specific ints in a lot of different ways.
+// We use our own way, and have a typedef to get there.
+// Note: these commands below may look like "#if 1" or "#if 0", but
+// that's because they were constructed that way at ./configure time.
+// Look at gflags.h.in to see how they're calculated (based on your config).
+#if 1
+#include <stdint.h> // the normal place uint16_t is defined
+#endif
+#if 1
+#include <sys/types.h> // the normal place u_int16_t is defined
+#endif
+#if 1
+#include <inttypes.h> // a third place for uint16_t or u_int16_t
+#endif
+
+namespace google {
+
+#if 1 // the C99 format
+typedef int32_t int32;
+typedef uint32_t uint32;
+typedef int64_t int64;
+typedef uint64_t uint64;
+#elif 1 // the BSD format
+typedef int32_t int32;
+typedef u_int32_t uint32;
+typedef int64_t int64;
+typedef u_int64_t uint64;
+#elif 0 // the windows (vc7) format
+typedef __int32 int32;
+typedef unsigned __int32 uint32;
+typedef __int64 int64;
+typedef unsigned __int64 uint64;
+#else
+#error Do not know how to define a 32-bit integer quantity on your system
+#endif
+
+// --------------------------------------------------------------------
+// To actually define a flag in a file, use DEFINE_bool,
+// DEFINE_string, etc. at the bottom of this file. You may also find
+// it useful to register a validator with the flag. This ensures that
+// when the flag is parsed from the commandline, or is later set via
+// SetCommandLineOption, we call the validation function. It is _not_
+// called when you assign the value to the flag directly using the = operator.
+//
+// The validation function should return true if the flag value is valid, and
+// false otherwise. If the function returns false for the new setting of the
+// flag, the flag will retain its current value. If it returns false for the
+// default value, ParseCommandLineFlags() will die.
+//
+// This function is safe to call at global construct time (as in the
+// example below).
+//
+// Example use:
+// static bool ValidatePort(const char* flagname, int32 value) {
+// if (value > 0 && value < 32768) // value is ok
+// return true;
+// printf("Invalid value for --%s: %d\n", flagname, (int)value);
+// return false;
+// }
+// DEFINE_int32(port, 0, "What port to listen on");
+// static bool dummy = RegisterFlagValidator(&FLAGS_port, &ValidatePort);
+
+// Returns true if successfully registered, false if not (because the
+// first argument doesn't point to a command-line flag, or because a
+// validator is already registered for this flag).
+bool RegisterFlagValidator(const bool* flag,
+ bool (*validate_fn)(const char*, bool));
+bool RegisterFlagValidator(const int32* flag,
+ bool (*validate_fn)(const char*, int32));
+bool RegisterFlagValidator(const int64* flag,
+ bool (*validate_fn)(const char*, int64));
+bool RegisterFlagValidator(const uint64* flag,
+ bool (*validate_fn)(const char*, uint64));
+bool RegisterFlagValidator(const double* flag,
+ bool (*validate_fn)(const char*, double));
+bool RegisterFlagValidator(const std::string* flag,
+ bool (*validate_fn)(const char*, const std::string&));
+
+
+// --------------------------------------------------------------------
+// These methods are the best way to get access to info about the
+// list of commandline flags. Note that these routines are pretty slow.
+// GetAllFlags: mostly-complete info about the list, sorted by file.
+// ShowUsageWithFlags: pretty-prints the list to stdout (what --help does)
+// ShowUsageWithFlagsRestrict: limit to filenames with restrict as a substr
+//
+// In addition to accessing flags, you can also access argv[0] (the program
+// name) and argv (the entire commandline), which we sock away a copy of.
+// These variables are static, so you should only set them once.
+
+struct CommandLineFlagInfo {
+ std::string name; // the name of the flag
+ std::string type; // the type of the flag: int32, etc
+ std::string description; // the "help text" associated with the flag
+ std::string current_value; // the current value, as a string
+ std::string default_value; // the default value, as a string
+ std::string filename; // 'cleaned' version of filename holding the flag
+ bool has_validator_fn; // true if RegisterFlagValidator called on flag
+ bool is_default; // true if the flag has the default value and
+ // has not been set explicitly from the cmdline
+ // or via SetCommandLineOption
+};
+
+// Using this inside of a validator is a recipe for a deadlock.
+// TODO(wojtekm) Fix locking when validators are running, to make it safe to
+// call validators during ParseAllFlags.
+// Also make sure then to uncomment the corresponding unit test in
+// commandlineflags_unittest.sh
+extern void GetAllFlags(std::vector<CommandLineFlagInfo>* OUTPUT);
+// These two are actually defined in commandlineflags_reporting.cc.
+extern void ShowUsageWithFlags(const char *argv0); // what --help does
+extern void ShowUsageWithFlagsRestrict(const char *argv0, const char *restrict);
+
+// Create a descriptive string for a flag.
+// Goes to some trouble to make pretty line breaks.
+extern std::string DescribeOneFlag(const CommandLineFlagInfo& flag);
+
+// Thread-hostile; meant to be called before any threads are spawned.
+extern void SetArgv(int argc, const char** argv);
+// The following functions are thread-safe as long as SetArgv() is
+// only called before any threads start.
+extern const std::vector<std::string>& GetArgvs(); // all of argv as a vector
+extern const char* GetArgv(); // all of argv as a string
+extern const char* GetArgv0(); // only argv0
+extern uint32 GetArgvSum(); // simple checksum of argv
+extern const char* ProgramInvocationName(); // argv0, or "UNKNOWN" if not set
+extern const char* ProgramInvocationShortName(); // basename(argv0)
+// ProgramUsage() is thread-safe as long as SetUsageMessage() is only
+// called before any threads start.
+extern const char* ProgramUsage(); // string set by SetUsageMessage()
+
+
+// --------------------------------------------------------------------
+// Normally you access commandline flags by just saying "if (FLAGS_foo)"
+// or whatever, and set them by calling "FLAGS_foo = bar" (or, more
+// commonly, via the DEFINE_foo macro). But if you need a bit more
+// control, we have programmatic ways to get/set the flags as well.
+// These programmatic ways to access flags are thread-safe, but direct
+// access is only thread-compatible.
+
+// Return true iff the flagname was found.
+// OUTPUT is set to the flag's value, or unchanged if we return false.
+extern bool GetCommandLineOption(const char* name, std::string* OUTPUT);
+
+// Return true iff the flagname was found. OUTPUT is set to the flag's
+// CommandLineFlagInfo or unchanged if we return false.
+extern bool GetCommandLineFlagInfo(const char* name,
+ CommandLineFlagInfo* OUTPUT);
+
+// Return the CommandLineFlagInfo of the flagname. exit() if name not found.
+// Example usage, to check if a flag's value is currently the default value:
+// if (GetCommandLineFlagInfoOrDie("foo").is_default) ...
+extern CommandLineFlagInfo GetCommandLineFlagInfoOrDie(const char* name);
+
+enum FlagSettingMode {
+ // update the flag's value (can call this multiple times).
+ SET_FLAGS_VALUE,
+ // update the flag's value, but *only if* it has not yet been updated
+ // with SET_FLAGS_VALUE, SET_FLAG_IF_DEFAULT, or "FLAGS_xxx = nondef".
+ SET_FLAG_IF_DEFAULT,
+ // set the flag's default value to this. If the flag has not yet updated
+ // yet (via SET_FLAGS_VALUE, SET_FLAG_IF_DEFAULT, or "FLAGS_xxx = nondef")
+ // change the flag's current value to the new default value as well.
+ SET_FLAGS_DEFAULT
+};
+
+// Set a particular flag ("command line option"). Returns a string
+// describing the new value that the option has been set to. The
+// return value API is not well-specified, so basically just depend on
+// it to be empty if the setting failed for some reason -- the name is
+// not a valid flag name, or the value is not a valid value -- and
+// non-empty else.
+
+// SetCommandLineOption uses set_mode == SET_FLAGS_VALUE (the common case)
+extern std::string SetCommandLineOption(const char* name, const char* value);
+extern std::string SetCommandLineOptionWithMode(const char* name, const char* value,
+ FlagSettingMode set_mode);
+
+
+// --------------------------------------------------------------------
+// Saves the states (value, default value, whether the user has set
+// the flag, registered validators, etc) of all flags, and restores
+// them when the FlagSaver is destroyed. This is very useful in
+// tests, say, when you want to let your tests change the flags, but
+// make sure that they get reverted to the original states when your
+// test is complete.
+//
+// Example usage:
+// void TestFoo() {
+// FlagSaver s1;
+// FLAG_foo = false;
+// FLAG_bar = "some value";
+//
+// // test happens here. You can return at any time
+// // without worrying about restoring the FLAG values.
+// }
+//
+// Note: This class is marked with __attribute__((unused)) because all the
+// work is done in the constructor and destructor, so in the standard
+// usage example above, the compiler would complain that it's an
+// unused variable.
+//
+// This class is thread-safe.
+
+class FlagSaver {
+ public:
+ FlagSaver();
+ ~FlagSaver();
+
+ private:
+ class FlagSaverImpl* impl_; // we use pimpl here to keep API steady
+
+ FlagSaver(const FlagSaver&); // no copying!
+ void operator=(const FlagSaver&);
+}
+#ifndef _MSC_VER
+__attribute__ ((unused))
+#endif
+;
+
+// --------------------------------------------------------------------
+// Some deprecated or hopefully-soon-to-be-deprecated functions.
+
+// This is often used for logging. TODO(csilvers): figure out a better way
+extern std::string CommandlineFlagsIntoString();
+// Usually where this is used, a FlagSaver should be used instead.
+extern bool ReadFlagsFromString(const std::string& flagfilecontents,
+ const char* prog_name,
+ bool errors_are_fatal); // uses SET_FLAGS_VALUE
+
+// These let you manually implement --flagfile functionality.
+// DEPRECATED.
+extern bool AppendFlagsIntoFile(const std::string& filename, const char* prog_name);
+extern bool SaveCommandFlags(); // actually defined in google.cc !
+extern bool ReadFromFlagsFile(const std::string& filename, const char* prog_name,
+ bool errors_are_fatal); // uses SET_FLAGS_VALUE
+
+
+// --------------------------------------------------------------------
+// Useful routines for initializing flags from the environment.
+// In each case, if 'varname' does not exist in the environment
+// return defval. If 'varname' does exist but is not valid
+// (e.g., not a number for an int32 flag), abort with an error.
+// Otherwise, return the value. NOTE: for booleans, for true use
+// 't' or 'T' or 'true' or '1', for false 'f' or 'F' or 'false' or '0'.
+
+extern bool BoolFromEnv(const char *varname, bool defval);
+extern int32 Int32FromEnv(const char *varname, int32 defval);
+extern int64 Int64FromEnv(const char *varname, int64 defval);
+extern uint64 Uint64FromEnv(const char *varname, uint64 defval);
+extern double DoubleFromEnv(const char *varname, double defval);
+extern const char *StringFromEnv(const char *varname, const char *defval);
+
+
+// --------------------------------------------------------------------
+// The next two functions parse commandlineflags from main():
+
+// Set the "usage" message for this program. For example:
+// string usage("This program does nothing. Sample usage:\n");
+// usage += argv[0] + " <uselessarg1> <uselessarg2>";
+// SetUsageMessage(usage);
+// Do not include commandline flags in the usage: we do that for you!
+// Thread-hostile; meant to be called before any threads are spawned.
+extern void SetUsageMessage(const std::string& usage);
+
+// Looks for flags in argv and parses them. Rearranges argv to put
+// flags first, or removes them entirely if remove_flags is true.
+// If a flag is defined more than once in the command line or flag
+// file, the last definition is used. Returns the index (into argv)
+// of the first non-flag argument.
+// See top-of-file for more details on this function.
+#ifndef SWIG // In swig, use ParseCommandLineFlagsScript() instead.
+extern uint32 ParseCommandLineFlags(int *argc, char*** argv,
+ bool remove_flags);
+#endif
+
+
+// Calls to ParseCommandLineNonHelpFlags and then to
+// HandleCommandLineHelpFlags can be used instead of a call to
+// ParseCommandLineFlags during initialization, in order to allow for
+// changing default values for some FLAGS (via
+// e.g. SetCommandLineOptionWithMode calls) between the time of
+// command line parsing and the time of dumping help information for
+// the flags as a result of command line parsing. If a flag is
+// defined more than once in the command line or flag file, the last
+// definition is used. Returns the index (into argv) of the first
+// non-flag argument. (If remove_flags is true, will always return 1.)
+extern uint32 ParseCommandLineNonHelpFlags(int *argc, char*** argv,
+ bool remove_flags);
+// This is actually defined in commandlineflags_reporting.cc.
+// This function is misnamed (it also handles --version, etc.), but
+// it's too late to change that now. :-(
+extern void HandleCommandLineHelpFlags(); // in commandlineflags_reporting.cc
+
+// Allow command line reparsing. Disables the error normally
+// generated when an unknown flag is found, since it may be found in a
+// later parse. Thread-hostile; meant to be called before any threads
+// are spawned.
+extern void AllowCommandLineReparsing();
+
+// Reparse the flags that have not yet been recognized. Only flags
+// registered since the last parse will be recognized. Any flag value
+// must be provided as part of the argument using "=", not as a
+// separate command line argument that follows the flag argument.
+// Intended for handling flags from dynamically loaded libraries,
+// since their flags are not registered until they are loaded.
+// Returns the index (into the original argv) of the first non-flag
+// argument. (If remove_flags is true, will always return 1.)
+extern uint32 ReparseCommandLineNonHelpFlags();
+
+// Clean up memory allocated by flags. This is only needed to reduce
+// the quantity of "potentially leaked" reports emitted by memory
+// debugging tools such as valgrind. It is not required for normal
+// operation, or for the perftools heap-checker. It must only be called
+// when the process is about to exit, and all threads that might
+// access flags are quiescent. Referencing flags after this is called
+// will have unexpected consequences. This is not safe to run when
+// multiple threads might be running: the function is thread-hostile.
+extern void ShutDownCommandLineFlags();
+
+
+// --------------------------------------------------------------------
+// Now come the command line flag declaration/definition macros that
+// will actually be used. They're kind of hairy. A major reason
+// for this is initialization: we want people to be able to access
+// variables in global constructors and have that not crash, even if
+// their global constructor runs before the global constructor here.
+// (Obviously, we can't guarantee the flags will have the correct
+// default value in that case, but at least accessing them is safe.)
+// The only way to do that is have flags point to a static buffer.
+// So we make one, using a union to ensure proper alignment, and
+// then use placement-new to actually set up the flag with the
+// correct default value. In the same vein, we have to worry about
+// flag access in global destructors, so FlagRegisterer has to be
+// careful never to destroy the flag-values it constructs.
+//
+// Note that when we define a flag variable FLAGS_<name>, we also
+// preemptively define a junk variable, FLAGS_no<name>. This is to
+// cause a link-time error if someone tries to define 2 flags with
+// names like "logging" and "nologging". We do this because a bool
+// flag FLAG can be set from the command line to true with a "-FLAG"
+// argument, and to false with a "-noFLAG" argument, and so this can
+// potentially avert confusion.
+//
+// We also put flags into their own namespace. It is purposefully
+// named in an opaque way that people should have trouble typing
+// directly. The idea is that DEFINE puts the flag in the weird
+// namespace, and DECLARE imports the flag from there into the current
+// namespace. The net result is to force people to use DECLARE to get
+// access to a flag, rather than saying "extern bool FLAGS_whatever;"
+// or some such instead. We want this so we can put extra
+// functionality (like sanity-checking) in DECLARE if we want, and
+// make sure it is picked up everywhere.
+//
+// We also put the type of the variable in the namespace, so that
+// people can't DECLARE_int32 something that they DEFINE_bool'd
+// elsewhere.
+
+class FlagRegisterer {
+ public:
+ FlagRegisterer(const char* name, const char* type,
+ const char* help, const char* filename,
+ void* current_storage, void* defvalue_storage);
+};
+
+extern bool FlagsTypeWarn(const char *name);
+
+// If your application #defines STRIP_FLAG_HELP to a non-zero value
+// before #including this file, we remove the help message from the
+// binary file. This can reduce the size of the resulting binary
+// somewhat, and may also be useful for security reasons.
+
+extern const char kStrippedFlagHelp[];
+
+}
+
+#ifndef SWIG // In swig, ignore the main flag declarations
+
+#if defined(STRIP_FLAG_HELP) && STRIP_FLAG_HELP > 0
+// Need this construct to avoid the 'defined but not used' warning.
+#define MAYBE_STRIPPED_HELP(txt) (false ? (txt) : ::google::kStrippedFlagHelp)
+#else
+#define MAYBE_STRIPPED_HELP(txt) txt
+#endif
+
+// Each command-line flag has two variables associated with it: one
+// with the current value, and one with the default value. However,
+// we have a third variable, which is where value is assigned; it's a
+// constant. This guarantees that FLAG_##value is initialized at
+// static initialization time (e.g. before program-start) rather than
+// than global construction time (which is after program-start but
+// before main), at least when 'value' is a compile-time constant. We
+// use a small trick for the "default value" variable, and call it
+// FLAGS_no<name>. This serves the second purpose of assuring a
+// compile error if someone tries to define a flag named no<name>
+// which is illegal (--foo and --nofoo both affect the "foo" flag).
+#define DEFINE_VARIABLE(type, shorttype, name, value, help) \
+ namespace fL##shorttype { \
+ static const type FLAGS_nono##name = value; \
+ type FLAGS_##name = FLAGS_nono##name; \
+ type FLAGS_no##name = FLAGS_nono##name; \
+ static ::google::FlagRegisterer o_##name( \
+ #name, #type, MAYBE_STRIPPED_HELP(help), __FILE__, \
+ &FLAGS_##name, &FLAGS_no##name); \
+ } \
+ using fL##shorttype::FLAGS_##name
+
+#define DECLARE_VARIABLE(type, shorttype, name) \
+ namespace fL##shorttype { \
+ extern type FLAGS_##name; \
+ } \
+ using fL##shorttype::FLAGS_##name
+
+// For DEFINE_bool, we want to do the extra check that the passed-in
+// value is actually a bool, and not a string or something that can be
+// coerced to a bool. These declarations (no definition needed!) will
+// help us do that, and never evaluate From, which is important.
+// We'll use 'sizeof(IsBool(val))' to distinguish. This code requires
+// that the compiler have different sizes for bool & double. Since
+// this is not guaranteed by the standard, we check it with a
+// compile-time assert (msg[-1] will give a compile-time error).
+namespace fLB {
+struct CompileAssert {};
+typedef CompileAssert expected_sizeof_double_neq_sizeof_bool[
+ (sizeof(double) != sizeof(bool)) ? 1 : -1];
+template<typename From> double IsBoolFlag(const From& from);
+bool IsBoolFlag(bool from);
+} // namespace fLB
+
+#define DECLARE_bool(name) DECLARE_VARIABLE(bool, B, name)
+#define DEFINE_bool(name, val, txt) \
+ namespace fLB { \
+ typedef ::fLB::CompileAssert FLAG_##name##_value_is_not_a_bool[ \
+ (sizeof(::fLB::IsBoolFlag(val)) != sizeof(double)) ? 1 : -1]; \
+ } \
+ DEFINE_VARIABLE(bool, B, name, val, txt)
+
+#define DECLARE_int32(name) DECLARE_VARIABLE(::google::int32, I, name)
+#define DEFINE_int32(name,val,txt) DEFINE_VARIABLE(::google::int32, I, name, val, txt)
+
+#define DECLARE_int64(name) DECLARE_VARIABLE(::google::int64, I64, name)
+#define DEFINE_int64(name,val,txt) DEFINE_VARIABLE(::google::int64, I64, name, val, txt)
+
+#define DECLARE_uint64(name) DECLARE_VARIABLE(::google::uint64, U64, name)
+#define DEFINE_uint64(name,val,txt) DEFINE_VARIABLE(::google::uint64, U64, name, val, txt)
+
+#define DECLARE_double(name) DECLARE_VARIABLE(double, D, name)
+#define DEFINE_double(name, val, txt) DEFINE_VARIABLE(double, D, name, val, txt)
+
+// Strings are trickier, because they're not a POD, so we can't
+// construct them at static-initialization time (instead they get
+// constructed at global-constructor time, which is much later). To
+// try to avoid crashes in that case, we use a char buffer to store
+// the string, which we can static-initialize, and then placement-new
+// into it later. It's not perfect, but the best we can do.
+
+namespace fLS {
+// The meaning of "string" might be different between now and when the
+// macros below get invoked (e.g., if someone is experimenting with
+// other string implementations that get defined after this file is
+// included). Save the current meaning now and use it in the macros.
+typedef std::string clstring;
+
+inline clstring* dont_pass0toDEFINE_string(char *stringspot,
+ const char *value) {
+ return new(stringspot) clstring(value);
+}
+inline clstring* dont_pass0toDEFINE_string(char *stringspot,
+ const clstring &value) {
+ return new(stringspot) clstring(value);
+}
+inline clstring* dont_pass0toDEFINE_string(char *stringspot,
+ int value);
+} // namespace fLS
+
+#define DECLARE_string(name) namespace fLS { extern ::fLS::clstring& FLAGS_##name; } \
+ using fLS::FLAGS_##name
+
+// We need to define a var named FLAGS_no##name so people don't define
+// --string and --nostring. And we need a temporary place to put val
+// so we don't have to evaluate it twice. Two great needs that go
+// great together!
+// The weird 'using' + 'extern' inside the fLS namespace is to work around
+// an unknown compiler bug/issue with the gcc 4.2.1 on SUSE 10. See
+// http://code.google.com/p/google-gflags/issues/detail?id=20
+#define DEFINE_string(name, val, txt) \
+ namespace fLS { \
+ using ::fLS::clstring; \
+ static union { void* align; char s[sizeof(clstring)]; } s_##name[2]; \
+ clstring* const FLAGS_no##name = ::fLS:: \
+ dont_pass0toDEFINE_string(s_##name[0].s, \
+ val); \
+ static ::google::FlagRegisterer o_##name( \
+ #name, "string", MAYBE_STRIPPED_HELP(txt), __FILE__, \
+ s_##name[0].s, new (s_##name[1].s) clstring(*FLAGS_no##name)); \
+ extern clstring& FLAGS_##name; \
+ using fLS::FLAGS_##name; \
+ clstring& FLAGS_##name = *FLAGS_no##name; \
+ } \
+ using fLS::FLAGS_##name
+
+#endif // SWIG
+
+#endif // GOOGLE_GFLAGS_H_
diff --git a/extern/libmv/third_party/gflags/gflags_completions.cc b/extern/libmv/third_party/gflags/gflags_completions.cc
new file mode 100644
index 00000000000..a129611d8a1
--- /dev/null
+++ b/extern/libmv/third_party/gflags/gflags_completions.cc
@@ -0,0 +1,765 @@
+// Copyright (c) 2008, Google Inc.
+// 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.
+//
+// ---
+// Author: Dave Nicponski
+//
+// Bash-style command line flag completion for C++ binaries
+//
+// This module implements bash-style completions. It achieves this
+// goal in the following broad chunks:
+//
+// 1) Take a to-be-completed word, and examine it for search hints
+// 2) Identify all potentially matching flags
+// 2a) If there are no matching flags, do nothing.
+// 2b) If all matching flags share a common prefix longer than the
+// completion word, output just that matching prefix
+// 3) Categorize those flags to produce a rough ordering of relevence.
+// 4) Potentially trim the set of flags returned to a smaller number
+// that bash is happier with
+// 5) Output the matching flags in groups ordered by relevence.
+// 5a) Force bash to place most-relevent groups at the top of the list
+// 5b) Trim most flag's descriptions to fit on a single terminal line
+
+
+#include "config.h"
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h> // for strlen
+
+#include <set>
+#include <string>
+#include <utility>
+#include <vector>
+
+#include "gflags.h"
+
+#ifndef PATH_SEPARATOR
+#define PATH_SEPARATOR '/'
+#endif
+
+DEFINE_string(tab_completion_word, "",
+ "If non-empty, HandleCommandLineCompletions() will hijack the "
+ "process and attempt to do bash-style command line flag "
+ "completion on this value.");
+DEFINE_int32(tab_completion_columns, 80,
+ "Number of columns to use in output for tab completion");
+
+_START_GOOGLE_NAMESPACE_
+
+namespace {
+
+using std::set;
+using std::string;
+using std::vector;
+
+// Function prototypes and Type forward declarations. Code may be
+// more easily understood if it is roughly ordered according to
+// control flow, rather than by C's "declare before use" ordering
+struct CompletionOptions;
+struct NotableFlags;
+
+// The entry point if flag completion is to be used.
+static void PrintFlagCompletionInfo(void);
+
+
+// 1) Examine search word
+static void CanonicalizeCursorWordAndSearchOptions(
+ const string &cursor_word,
+ string *canonical_search_token,
+ CompletionOptions *options);
+
+static bool RemoveTrailingChar(string *str, char c);
+
+
+// 2) Find all matches
+static void FindMatchingFlags(
+ const vector<CommandLineFlagInfo> &all_flags,
+ const CompletionOptions &options,
+ const string &match_token,
+ set<const CommandLineFlagInfo *> *all_matches,
+ string *longest_common_prefix);
+
+static bool DoesSingleFlagMatch(
+ const CommandLineFlagInfo &flag,
+ const CompletionOptions &options,
+ const string &match_token);
+
+
+// 3) Categorize matches
+static void CategorizeAllMatchingFlags(
+ const set<const CommandLineFlagInfo *> &all_matches,
+ const string &search_token,
+ const string &module,
+ const string &package_dir,
+ NotableFlags *notable_flags);
+
+static void TryFindModuleAndPackageDir(
+ const vector<CommandLineFlagInfo> all_flags,
+ string *module,
+ string *package_dir);
+
+
+// 4) Decide which flags to use
+static void FinalizeCompletionOutput(
+ const set<const CommandLineFlagInfo *> &matching_flags,
+ CompletionOptions *options,
+ NotableFlags *notable_flags,
+ vector<string> *completions);
+
+static void RetrieveUnusedFlags(
+ const set<const CommandLineFlagInfo *> &matching_flags,
+ const NotableFlags &notable_flags,
+ set<const CommandLineFlagInfo *> *unused_flags);
+
+
+// 5) Output matches
+static void OutputSingleGroupWithLimit(
+ const set<const CommandLineFlagInfo *> &group,
+ const string &line_indentation,
+ const string &header,
+ const string &footer,
+ bool long_output_format,
+ int *remaining_line_limit,
+ size_t *completion_elements_added,
+ vector<string> *completions);
+
+// (helpers for #5)
+static string GetShortFlagLine(
+ const string &line_indentation,
+ const CommandLineFlagInfo &info);
+
+static string GetLongFlagLine(
+ const string &line_indentation,
+ const CommandLineFlagInfo &info);
+
+
+//
+// Useful types
+
+// Try to deduce the intentions behind this completion attempt. Return the
+// canonical search term in 'canonical_search_token'. Binary search options
+// are returned in the various booleans, which should all have intuitive
+// semantics, possibly except:
+// - return_all_matching_flags: Generally, we'll trim the number of
+// returned candidates to some small number, showing those that are
+// most likely to be useful first. If this is set, however, the user
+// really does want us to return every single flag as an option.
+// - force_no_update: Any time we output lines, all of which share a
+// common prefix, bash will 'helpfully' not even bother to show the
+// output, instead changing the current word to be that common prefix.
+// If it's clear this shouldn't happen, we'll set this boolean
+struct CompletionOptions {
+ bool flag_name_substring_search;
+ bool flag_location_substring_search;
+ bool flag_description_substring_search;
+ bool return_all_matching_flags;
+ bool force_no_update;
+};
+
+// Notable flags are flags that are special or preferred for some
+// reason. For example, flags that are defined in the binary's module
+// are expected to be much more relevent than flags defined in some
+// other random location. These sets are specified roughly in precedence
+// order. Once a flag is placed in one of these 'higher' sets, it won't
+// be placed in any of the 'lower' sets.
+struct NotableFlags {
+ typedef set<const CommandLineFlagInfo *> FlagSet;
+ FlagSet perfect_match_flag;
+ FlagSet module_flags; // Found in module file
+ FlagSet package_flags; // Found in same directory as module file
+ FlagSet most_common_flags; // One of the XXX most commonly supplied flags
+ FlagSet subpackage_flags; // Found in subdirectories of package
+};
+
+
+//
+// Tab completion implementation - entry point
+static void PrintFlagCompletionInfo(void) {
+ string cursor_word = FLAGS_tab_completion_word;
+ string canonical_token;
+ CompletionOptions options = { };
+ CanonicalizeCursorWordAndSearchOptions(
+ cursor_word,
+ &canonical_token,
+ &options);
+
+ //VLOG(1) << "Identified canonical_token: '" << canonical_token << "'";
+
+ vector<CommandLineFlagInfo> all_flags;
+ set<const CommandLineFlagInfo *> matching_flags;
+ GetAllFlags(&all_flags);
+ //VLOG(2) << "Found " << all_flags.size() << " flags overall";
+
+ string longest_common_prefix;
+ FindMatchingFlags(
+ all_flags,
+ options,
+ canonical_token,
+ &matching_flags,
+ &longest_common_prefix);
+ //VLOG(1) << "Identified " << matching_flags.size() << " matching flags";
+ //VLOG(1) << "Identified " << longest_common_prefix
+ // << " as longest common prefix.";
+ if (longest_common_prefix.size() > canonical_token.size()) {
+ // There's actually a shared common prefix to all matching flags,
+ // so may as well output that and quit quickly.
+ //VLOG(1) << "The common prefix '" << longest_common_prefix
+ // << "' was longer than the token '" << canonical_token
+ // << "'. Returning just this prefix for completion.";
+ fprintf(stdout, "--%s", longest_common_prefix.c_str());
+ return;
+ }
+ if (matching_flags.empty()) {
+ //VLOG(1) << "There were no matching flags, returning nothing.";
+ return;
+ }
+
+ string module;
+ string package_dir;
+ TryFindModuleAndPackageDir(all_flags, &module, &package_dir);
+ //VLOG(1) << "Identified module: '" << module << "'";
+ //VLOG(1) << "Identified package_dir: '" << package_dir << "'";
+
+ NotableFlags notable_flags;
+ CategorizeAllMatchingFlags(
+ matching_flags,
+ canonical_token,
+ module,
+ package_dir,
+ &notable_flags);
+ //VLOG(2) << "Categorized matching flags:";
+ //VLOG(2) << " perfect_match: " << notable_flags.perfect_match_flag.size();
+ //VLOG(2) << " module: " << notable_flags.module_flags.size();
+ //VLOG(2) << " package: " << notable_flags.package_flags.size();
+ //VLOG(2) << " most common: " << notable_flags.most_common_flags.size();
+ //VLOG(2) << " subpackage: " << notable_flags.subpackage_flags.size();
+
+ vector<string> completions;
+ FinalizeCompletionOutput(
+ matching_flags,
+ &options,
+ &notable_flags,
+ &completions);
+
+ if (options.force_no_update)
+ completions.push_back("~");
+
+ //VLOG(1) << "Finalized with " << completions.size()
+ // << " chosen completions";
+
+ for (vector<string>::const_iterator it = completions.begin();
+ it != completions.end();
+ ++it) {
+ //VLOG(9) << " Completion entry: '" << *it << "'";
+ fprintf(stdout, "%s\n", it->c_str());
+ }
+}
+
+
+// 1) Examine search word (and helper method)
+static void CanonicalizeCursorWordAndSearchOptions(
+ const string &cursor_word,
+ string *canonical_search_token,
+ CompletionOptions *options) {
+ *canonical_search_token = cursor_word;
+ if (canonical_search_token->empty()) return;
+
+ // Get rid of leading quotes and dashes in the search term
+ if ((*canonical_search_token)[0] == '"')
+ *canonical_search_token = canonical_search_token->substr(1);
+ while ((*canonical_search_token)[0] == '-')
+ *canonical_search_token = canonical_search_token->substr(1);
+
+ options->flag_name_substring_search = false;
+ options->flag_location_substring_search = false;
+ options->flag_description_substring_search = false;
+ options->return_all_matching_flags = false;
+ options->force_no_update = false;
+
+ // Look for all search options we can deduce now. Do this by walking
+ // backwards through the term, looking for up to three '?' and up to
+ // one '+' as suffixed characters. Consume them if found, and remove
+ // them from the canonical search token.
+ int found_question_marks = 0;
+ int found_plusses = 0;
+ while (true) {
+ if (found_question_marks < 3 &&
+ RemoveTrailingChar(canonical_search_token, '?')) {
+ ++found_question_marks;
+ continue;
+ }
+ if (found_plusses < 1 &&
+ RemoveTrailingChar(canonical_search_token, '+')) {
+ ++found_plusses;
+ continue;
+ }
+ break;
+ }
+
+ switch (found_question_marks) { // all fallthroughs
+ case 3: options->flag_description_substring_search = true;
+ case 2: options->flag_location_substring_search = true;
+ case 1: options->flag_name_substring_search = true;
+ };
+
+ options->return_all_matching_flags = (found_plusses > 0);
+}
+
+// Returns true if a char was removed
+static bool RemoveTrailingChar(string *str, char c) {
+ if (str->empty()) return false;
+ if ((*str)[str->size() - 1] == c) {
+ *str = str->substr(0, str->size() - 1);
+ return true;
+ }
+ return false;
+}
+
+
+// 2) Find all matches (and helper methods)
+static void FindMatchingFlags(
+ const vector<CommandLineFlagInfo> &all_flags,
+ const CompletionOptions &options,
+ const string &match_token,
+ set<const CommandLineFlagInfo *> *all_matches,
+ string *longest_common_prefix) {
+ all_matches->clear();
+ bool first_match = true;
+ for (vector<CommandLineFlagInfo>::const_iterator it = all_flags.begin();
+ it != all_flags.end();
+ ++it) {
+ if (DoesSingleFlagMatch(*it, options, match_token)) {
+ all_matches->insert(&*it);
+ if (first_match) {
+ first_match = false;
+ *longest_common_prefix = it->name;
+ } else {
+ if (longest_common_prefix->empty() || it->name.empty()) {
+ longest_common_prefix->clear();
+ continue;
+ }
+ string::size_type pos = 0;
+ while (pos < longest_common_prefix->size() &&
+ pos < it->name.size() &&
+ (*longest_common_prefix)[pos] == it->name[pos])
+ ++pos;
+ longest_common_prefix->erase(pos);
+ }
+ }
+ }
+}
+
+// Given the set of all flags, the parsed match options, and the
+// canonical search token, produce the set of all candidate matching
+// flags for subsequent analysis or filtering.
+static bool DoesSingleFlagMatch(
+ const CommandLineFlagInfo &flag,
+ const CompletionOptions &options,
+ const string &match_token) {
+ // Is there a prefix match?
+ string::size_type pos = flag.name.find(match_token);
+ if (pos == 0) return true;
+
+ // Is there a substring match if we want it?
+ if (options.flag_name_substring_search &&
+ pos != string::npos)
+ return true;
+
+ // Is there a location match if we want it?
+ if (options.flag_location_substring_search &&
+ flag.filename.find(match_token) != string::npos)
+ return true;
+
+ // TODO(daven): All searches should probably be case-insensitive
+ // (especially this one...)
+ if (options.flag_description_substring_search &&
+ flag.description.find(match_token) != string::npos)
+ return true;
+
+ return false;
+}
+
+// 3) Categorize matches (and helper method)
+
+// Given a set of matching flags, categorize them by
+// likely relevence to this specific binary
+static void CategorizeAllMatchingFlags(
+ const set<const CommandLineFlagInfo *> &all_matches,
+ const string &search_token,
+ const string &module, // empty if we couldn't find any
+ const string &package_dir, // empty if we couldn't find any
+ NotableFlags *notable_flags) {
+ notable_flags->perfect_match_flag.clear();
+ notable_flags->module_flags.clear();
+ notable_flags->package_flags.clear();
+ notable_flags->most_common_flags.clear();
+ notable_flags->subpackage_flags.clear();
+
+ for (set<const CommandLineFlagInfo *>::const_iterator it =
+ all_matches.begin();
+ it != all_matches.end();
+ ++it) {
+ //VLOG(2) << "Examining match '" << (*it)->name << "'";
+ //VLOG(7) << " filename: '" << (*it)->filename << "'";
+ string::size_type pos = string::npos;
+ if (!package_dir.empty())
+ pos = (*it)->filename.find(package_dir);
+ string::size_type slash = string::npos;
+ if (pos != string::npos) // candidate for package or subpackage match
+ slash = (*it)->filename.find(
+ PATH_SEPARATOR,
+ pos + package_dir.size() + 1);
+
+ if ((*it)->name == search_token) {
+ // Exact match on some flag's name
+ notable_flags->perfect_match_flag.insert(*it);
+ //VLOG(3) << "Result: perfect match";
+ } else if (!module.empty() && (*it)->filename == module) {
+ // Exact match on module filename
+ notable_flags->module_flags.insert(*it);
+ //VLOG(3) << "Result: module match";
+ } else if (!package_dir.empty() &&
+ pos != string::npos && slash == string::npos) {
+ // In the package, since there was no slash after the package portion
+ notable_flags->package_flags.insert(*it);
+ //VLOG(3) << "Result: package match";
+ } else if (false) {
+ // In the list of the XXX most commonly supplied flags overall
+ // TODO(daven): Compile this list.
+ //VLOG(3) << "Result: most-common match";
+ } else if (!package_dir.empty() &&
+ pos != string::npos && slash != string::npos) {
+ // In a subdirectory of the package
+ notable_flags->subpackage_flags.insert(*it);
+ //VLOG(3) << "Result: subpackage match";
+ }
+
+ //VLOG(3) << "Result: not special match";
+ }
+}
+
+static void PushNameWithSuffix(vector<string>* suffixes, const char* suffix) {
+ string s("/");
+ s += ProgramInvocationShortName();
+ s += suffix;
+ suffixes->push_back(s);
+}
+
+static void TryFindModuleAndPackageDir(
+ const vector<CommandLineFlagInfo> all_flags,
+ string *module,
+ string *package_dir) {
+ module->clear();
+ package_dir->clear();
+
+ vector<string> suffixes;
+ // TODO(daven): There's some inherant ambiguity here - multiple directories
+ // could share the same trailing folder and file structure (and even worse,
+ // same file names), causing us to be unsure as to which of the two is the
+ // actual package for this binary. In this case, we'll arbitrarily choose.
+ PushNameWithSuffix(&suffixes, ".");
+ PushNameWithSuffix(&suffixes, "-main.");
+ PushNameWithSuffix(&suffixes, "_main.");
+ // These four are new but probably merited?
+ PushNameWithSuffix(&suffixes, "-test.");
+ PushNameWithSuffix(&suffixes, "_test.");
+ PushNameWithSuffix(&suffixes, "-unittest.");
+ PushNameWithSuffix(&suffixes, "_unittest.");
+
+ for (vector<CommandLineFlagInfo>::const_iterator it = all_flags.begin();
+ it != all_flags.end();
+ ++it) {
+ for (vector<string>::const_iterator suffix = suffixes.begin();
+ suffix != suffixes.end();
+ ++suffix) {
+ // TODO(daven): Make sure the match is near the end of the string
+ if (it->filename.find(*suffix) != string::npos) {
+ *module = it->filename;
+ string::size_type sep = it->filename.rfind(PATH_SEPARATOR);
+ *package_dir = it->filename.substr(0, (sep == string::npos) ? 0 : sep);
+ return;
+ }
+ }
+ }
+}
+
+// Can't specialize template type on a locally defined type. Silly C++...
+struct DisplayInfoGroup {
+ const char* header;
+ const char* footer;
+ set<const CommandLineFlagInfo *> *group;
+
+ int SizeInLines() const {
+ int size_in_lines = static_cast<int>(group->size()) + 1;
+ if (strlen(header) > 0) {
+ size_in_lines++;
+ }
+ if (strlen(footer) > 0) {
+ size_in_lines++;
+ }
+ return size_in_lines;
+ }
+};
+
+// 4) Finalize and trim output flag set
+static void FinalizeCompletionOutput(
+ const set<const CommandLineFlagInfo *> &matching_flags,
+ CompletionOptions *options,
+ NotableFlags *notable_flags,
+ vector<string> *completions) {
+
+ // We want to output lines in groups. Each group needs to be indented
+ // the same to keep its lines together. Unless otherwise required,
+ // only 99 lines should be output to prevent bash from harassing the
+ // user.
+
+ // First, figure out which output groups we'll actually use. For each
+ // nonempty group, there will be ~3 lines of header & footer, plus all
+ // output lines themselves.
+ int max_desired_lines = // "999999 flags should be enough for anyone. -dave"
+ (options->return_all_matching_flags ? 999999 : 98);
+ int lines_so_far = 0;
+
+ vector<DisplayInfoGroup> output_groups;
+ bool perfect_match_found = false;
+ if (lines_so_far < max_desired_lines &&
+ !notable_flags->perfect_match_flag.empty()) {
+ perfect_match_found = true;
+ DisplayInfoGroup group =
+ { "",
+ "==========",
+ &notable_flags->perfect_match_flag };
+ lines_so_far += group.SizeInLines();
+ output_groups.push_back(group);
+ }
+ if (lines_so_far < max_desired_lines &&
+ !notable_flags->module_flags.empty()) {
+ DisplayInfoGroup group = {
+ "-* Matching module flags *-",
+ "===========================",
+ &notable_flags->module_flags };
+ lines_so_far += group.SizeInLines();
+ output_groups.push_back(group);
+ }
+ if (lines_so_far < max_desired_lines &&
+ !notable_flags->package_flags.empty()) {
+ DisplayInfoGroup group = {
+ "-* Matching package flags *-",
+ "============================",
+ &notable_flags->package_flags };
+ lines_so_far += group.SizeInLines();
+ output_groups.push_back(group);
+ }
+ if (lines_so_far < max_desired_lines &&
+ !notable_flags->most_common_flags.empty()) {
+ DisplayInfoGroup group = {
+ "-* Commonly used flags *-",
+ "=========================",
+ &notable_flags->most_common_flags };
+ lines_so_far += group.SizeInLines();
+ output_groups.push_back(group);
+ }
+ if (lines_so_far < max_desired_lines &&
+ !notable_flags->subpackage_flags.empty()) {
+ DisplayInfoGroup group = {
+ "-* Matching sub-package flags *-",
+ "================================",
+ &notable_flags->subpackage_flags };
+ lines_so_far += group.SizeInLines();
+ output_groups.push_back(group);
+ }
+
+ set<const CommandLineFlagInfo *> obscure_flags; // flags not notable
+ if (lines_so_far < max_desired_lines) {
+ RetrieveUnusedFlags(matching_flags, *notable_flags, &obscure_flags);
+ if (!obscure_flags.empty()) {
+ DisplayInfoGroup group = {
+ "-* Other flags *-",
+ "",
+ &obscure_flags };
+ lines_so_far += group.SizeInLines();
+ output_groups.push_back(group);
+ }
+ }
+
+ // Second, go through each of the chosen output groups and output
+ // as many of those flags as we can, while remaining below our limit
+ int remaining_lines = max_desired_lines;
+ size_t completions_output = 0;
+ int indent = static_cast<int>(output_groups.size()) - 1;
+ for (vector<DisplayInfoGroup>::const_iterator it =
+ output_groups.begin();
+ it != output_groups.end();
+ ++it, --indent) {
+ OutputSingleGroupWithLimit(
+ *it->group, // group
+ string(indent, ' '), // line indentation
+ string(it->header), // header
+ string(it->footer), // footer
+ perfect_match_found, // long format
+ &remaining_lines, // line limit - reduces this by number printed
+ &completions_output, // completions (not lines) added
+ completions); // produced completions
+ perfect_match_found = false;
+ }
+
+ if (completions_output != matching_flags.size()) {
+ options->force_no_update = false;
+ completions->push_back("~ (Remaining flags hidden) ~");
+ } else {
+ options->force_no_update = true;
+ }
+}
+
+static void RetrieveUnusedFlags(
+ const set<const CommandLineFlagInfo *> &matching_flags,
+ const NotableFlags &notable_flags,
+ set<const CommandLineFlagInfo *> *unused_flags) {
+ // Remove from 'matching_flags' set all members of the sets of
+ // flags we've already printed (specifically, those in notable_flags)
+ for (set<const CommandLineFlagInfo *>::const_iterator it =
+ matching_flags.begin();
+ it != matching_flags.end();
+ ++it) {
+ if (notable_flags.perfect_match_flag.count(*it) ||
+ notable_flags.module_flags.count(*it) ||
+ notable_flags.package_flags.count(*it) ||
+ notable_flags.most_common_flags.count(*it) ||
+ notable_flags.subpackage_flags.count(*it))
+ continue;
+ unused_flags->insert(*it);
+ }
+}
+
+// 5) Output matches (and helper methods)
+
+static void OutputSingleGroupWithLimit(
+ const set<const CommandLineFlagInfo *> &group,
+ const string &line_indentation,
+ const string &header,
+ const string &footer,
+ bool long_output_format,
+ int *remaining_line_limit,
+ size_t *completion_elements_output,
+ vector<string> *completions) {
+ if (group.empty()) return;
+ if (!header.empty()) {
+ if (*remaining_line_limit < 2) return;
+ *remaining_line_limit -= 2;
+ completions->push_back(line_indentation + header);
+ completions->push_back(line_indentation + string(header.size(), '-'));
+ }
+ for (set<const CommandLineFlagInfo *>::const_iterator it = group.begin();
+ it != group.end() && *remaining_line_limit > 0;
+ ++it) {
+ --*remaining_line_limit;
+ ++*completion_elements_output;
+ completions->push_back(
+ (long_output_format
+ ? GetLongFlagLine(line_indentation, **it)
+ : GetShortFlagLine(line_indentation, **it)));
+ }
+ if (!footer.empty()) {
+ if (*remaining_line_limit < 1) return;
+ --*remaining_line_limit;
+ completions->push_back(line_indentation + footer);
+ }
+}
+
+static string GetShortFlagLine(
+ const string &line_indentation,
+ const CommandLineFlagInfo &info) {
+ string prefix =
+ line_indentation + "--" + info.name + " [" +
+ (info.type == "string" ?
+ ("'" + info.default_value + "'") :
+ info.default_value)
+ + "] ";
+ int remainder =
+ FLAGS_tab_completion_columns - static_cast<int>(prefix.size());
+ string suffix;
+ if (remainder > 0)
+ suffix =
+ (static_cast<int>(info.description.size()) > remainder ?
+ (info.description.substr(0, remainder - 3) + "...").c_str() :
+ info.description.c_str());
+ return prefix + suffix;
+}
+
+static string GetLongFlagLine(
+ const string &line_indentation,
+ const CommandLineFlagInfo &info) {
+
+ string output = DescribeOneFlag(info);
+
+ // Replace '-' with '--', and remove trailing newline before appending
+ // the module definition location.
+ string old_flagname = "-" + info.name;
+ output.replace(
+ output.find(old_flagname),
+ old_flagname.size(),
+ "-" + old_flagname);
+ // Stick a newline and indentation in front of the type and default
+ // portions of DescribeOneFlag()s description
+ static const char kNewlineWithIndent[] = "\n ";
+ output.replace(output.find(" type:"), 1, string(kNewlineWithIndent));
+ output.replace(output.find(" default:"), 1, string(kNewlineWithIndent));
+ output = line_indentation + " Details for '--" + info.name + "':\n" +
+ output + " defined: " + info.filename;
+
+ // Eliminate any doubled newlines that crept in. Specifically, if
+ // DescribeOneFlag() decided to break the line just before "type"
+ // or "default", we don't want to introduce an extra blank line
+ static const string line_of_spaces(FLAGS_tab_completion_columns, ' ');
+ static const char kDoubledNewlines[] = "\n \n";
+ for (string::size_type newlines = output.find(kDoubledNewlines);
+ newlines != string::npos;
+ newlines = output.find(kDoubledNewlines))
+ // Replace each 'doubled newline' with a single newline
+ output.replace(newlines, sizeof(kDoubledNewlines) - 1, string("\n"));
+
+ for (string::size_type newline = output.find('\n');
+ newline != string::npos;
+ newline = output.find('\n')) {
+ int newline_pos = static_cast<int>(newline) % FLAGS_tab_completion_columns;
+ int missing_spaces = FLAGS_tab_completion_columns - newline_pos;
+ output.replace(newline, 1, line_of_spaces, 1, missing_spaces);
+ }
+ return output;
+}
+} // anonymous
+
+void HandleCommandLineCompletions(void) {
+ if (FLAGS_tab_completion_word.empty()) return;
+ PrintFlagCompletionInfo();
+ exit(0);
+}
+
+_END_GOOGLE_NAMESPACE_
diff --git a/extern/libmv/third_party/gflags/gflags_completions.h b/extern/libmv/third_party/gflags/gflags_completions.h
new file mode 100644
index 00000000000..9d9ce7a5f75
--- /dev/null
+++ b/extern/libmv/third_party/gflags/gflags_completions.h
@@ -0,0 +1,121 @@
+// Copyright (c) 2008, Google Inc.
+// 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.
+//
+// ---
+// Author: Dave Nicponski
+//
+// Implement helpful bash-style command line flag completions
+//
+// ** Functional API:
+// HandleCommandLineCompletions() should be called early during
+// program startup, but after command line flag code has been
+// initialized, such as the beginning of HandleCommandLineHelpFlags().
+// It checks the value of the flag --tab_completion_word. If this
+// flag is empty, nothing happens here. If it contains a string,
+// however, then HandleCommandLineCompletions() will hijack the
+// process, attempting to identify the intention behind this
+// completion. Regardless of the outcome of this deduction, the
+// process will be terminated, similar to --helpshort flag
+// handling.
+//
+// ** Overview of Bash completions:
+// Bash can be told to programatically determine completions for the
+// current 'cursor word'. It does this by (in this case) invoking a
+// command with some additional arguments identifying the command
+// being executed, the word being completed, and the previous word
+// (if any). Bash then expects a sequence of output lines to be
+// printed to stdout. If these lines all contain a common prefix
+// longer than the cursor word, bash will replace the cursor word
+// with that common prefix, and display nothing. If there isn't such
+// a common prefix, bash will display the lines in pages using 'more'.
+//
+// ** Strategy taken for command line completions:
+// If we can deduce either the exact flag intended, or a common flag
+// prefix, we'll output exactly that. Otherwise, if information
+// must be displayed to the user, we'll take the opportunity to add
+// some helpful information beyond just the flag name (specifically,
+// we'll include the default flag value and as much of the flag's
+// description as can fit on a single terminal line width, as specified
+// by the flag --tab_completion_columns). Furthermore, we'll try to
+// make bash order the output such that the most useful or relevent
+// flags are the most likely to be shown at the top.
+//
+// ** Additional features:
+// To assist in finding that one really useful flag, substring matching
+// was implemented. Before pressing a <TAB> to get completion for the
+// current word, you can append one or more '?' to the flag to do
+// substring matching. Here's the semantics:
+// --foo<TAB> Show me all flags with names prefixed by 'foo'
+// --foo?<TAB> Show me all flags with 'foo' somewhere in the name
+// --foo??<TAB> Same as prior case, but also search in module
+// definition path for 'foo'
+// --foo???<TAB> Same as prior case, but also search in flag
+// descriptions for 'foo'
+// Finally, we'll trim the output to a relatively small number of
+// flags to keep bash quiet about the verbosity of output. If one
+// really wanted to see all possible matches, appending a '+' to the
+// search word will force the exhaustive list of matches to be printed.
+//
+// ** How to have bash accept completions from a binary:
+// Bash requires that it be informed about each command that programmatic
+// completion should be enabled for. Example addition to a .bashrc
+// file would be (your path to gflags_completions.sh file may differ):
+
+/*
+$ complete -o bashdefault -o default -o nospace -C \
+ '/usr/local/bin/gflags_completions.sh --tab_completion_columns $COLUMNS' \
+ time env binary_name another_binary [...]
+*/
+
+// This would allow the following to work:
+// $ /path/to/binary_name --vmodule<TAB>
+// Or:
+// $ ./bin/path/another_binary --gfs_u<TAB>
+// (etc)
+//
+// Sadly, it appears that bash gives no easy way to force this behavior for
+// all commands. That's where the "time" in the above example comes in.
+// If you haven't specifically added a command to the list of completion
+// supported commands, you can still get completions by prefixing the
+// entire command with "env".
+// $ env /some/brand/new/binary --vmod<TAB>
+// Assuming that "binary" is a newly compiled binary, this should still
+// produce the expected completion output.
+
+
+#ifndef GOOGLE_GFLAGS_COMPLETIONS_H_
+#define GOOGLE_GFLAGS_COMPLETIONS_H_
+
+namespace google {
+
+void HandleCommandLineCompletions(void);
+
+}
+
+#endif // GOOGLE_GFLAGS_COMPLETIONS_H_
diff --git a/extern/libmv/third_party/gflags/gflags_reporting.cc b/extern/libmv/third_party/gflags/gflags_reporting.cc
new file mode 100644
index 00000000000..fa3024d974e
--- /dev/null
+++ b/extern/libmv/third_party/gflags/gflags_reporting.cc
@@ -0,0 +1,446 @@
+// Copyright (c) 2006, Google Inc.
+// 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.
+
+// ---
+// Author: Ray Sidney
+// Revamped and reorganized by Craig Silverstein
+//
+// This file contains code for handling the 'reporting' flags. These
+// are flags that, when present, cause the program to report some
+// information and then exit. --help and --version are the canonical
+// reporting flags, but we also have flags like --helpxml, etc.
+//
+// There's only one function that's meant to be called externally:
+// HandleCommandLineHelpFlags(). (Well, actually, ShowUsageWithFlags(),
+// ShowUsageWithFlagsRestrict(), and DescribeOneFlag() can be called
+// externally too, but there's little need for it.) These are all
+// declared in the main commandlineflags.h header file.
+//
+// HandleCommandLineHelpFlags() will check what 'reporting' flags have
+// been defined, if any -- the "help" part of the function name is a
+// bit misleading -- and do the relevant reporting. It should be
+// called after all flag-values have been assigned, that is, after
+// parsing the command-line.
+
+#include "config.h"
+#include <stdio.h>
+#include <string.h>
+#include <ctype.h>
+#include <assert.h>
+#include <string>
+#include <vector>
+#include "gflags.h"
+#include "gflags_completions.h"
+
+#ifndef PATH_SEPARATOR
+#define PATH_SEPARATOR '/'
+#endif
+
+// The 'reporting' flags. They all call exit().
+DEFINE_bool(help, false,
+ "show help on all flags [tip: all flags can have two dashes]");
+DEFINE_bool(helpfull, false,
+ "show help on all flags -- same as -help");
+DEFINE_bool(helpshort, false,
+ "show help on only the main module for this program");
+DEFINE_string(helpon, "",
+ "show help on the modules named by this flag value");
+DEFINE_string(helpmatch, "",
+ "show help on modules whose name contains the specified substr");
+DEFINE_bool(helppackage, false,
+ "show help on all modules in the main package");
+DEFINE_bool(helpxml, false,
+ "produce an xml version of help");
+DEFINE_bool(version, false,
+ "show version and build info and exit");
+
+_START_GOOGLE_NAMESPACE_
+
+using std::string;
+using std::vector;
+
+// --------------------------------------------------------------------
+// DescribeOneFlag()
+// DescribeOneFlagInXML()
+// Routines that pretty-print info about a flag. These use
+// a CommandLineFlagInfo, which is the way the commandlineflags
+// API exposes static info about a flag.
+// --------------------------------------------------------------------
+
+static const int kLineLength = 80;
+
+static void AddString(const string& s,
+ string* final_string, int* chars_in_line) {
+ const int slen = static_cast<int>(s.length());
+ if (*chars_in_line + 1 + slen >= kLineLength) { // < 80 chars/line
+ *final_string += "\n ";
+ *chars_in_line = 6;
+ } else {
+ *final_string += " ";
+ *chars_in_line += 1;
+ }
+ *final_string += s;
+ *chars_in_line += slen;
+}
+
+static string PrintStringFlagsWithQuotes(const CommandLineFlagInfo& flag,
+ const string& text, bool current) {
+ const char* c_string = (current ? flag.current_value.c_str() :
+ flag.default_value.c_str());
+ if (strcmp(flag.type.c_str(), "string") == 0) { // add quotes for strings
+ return text + ": \"" + c_string + "\"";
+ } else {
+ return text + ": " + c_string;
+ }
+}
+
+// Create a descriptive string for a flag.
+// Goes to some trouble to make pretty line breaks.
+string DescribeOneFlag(const CommandLineFlagInfo& flag) {
+ string main_part = (string(" -") + flag.name +
+ " (" + flag.description + ')');
+ const char* c_string = main_part.c_str();
+ int chars_left = static_cast<int>(main_part.length());
+ string final_string = "";
+ int chars_in_line = 0; // how many chars in current line so far?
+ while (1) {
+ assert(chars_left == strlen(c_string)); // Unless there's a \0 in there?
+ const char* newline = strchr(c_string, '\n');
+ if (newline == NULL && chars_in_line+chars_left < kLineLength) {
+ // The whole remainder of the string fits on this line
+ final_string += c_string;
+ chars_in_line += chars_left;
+ break;
+ }
+ if (newline != NULL && newline - c_string < kLineLength - chars_in_line) {
+ int n = static_cast<int>(newline - c_string);
+ final_string.append(c_string, n);
+ chars_left -= n + 1;
+ c_string += n + 1;
+ } else {
+ // Find the last whitespace on this 80-char line
+ int whitespace = kLineLength-chars_in_line-1; // < 80 chars/line
+ while ( whitespace > 0 && !isspace(c_string[whitespace]) ) {
+ --whitespace;
+ }
+ if (whitespace <= 0) {
+ // Couldn't find any whitespace to make a line break. Just dump the
+ // rest out!
+ final_string += c_string;
+ chars_in_line = kLineLength; // next part gets its own line for sure!
+ break;
+ }
+ final_string += string(c_string, whitespace);
+ chars_in_line += whitespace;
+ while (isspace(c_string[whitespace])) ++whitespace;
+ c_string += whitespace;
+ chars_left -= whitespace;
+ }
+ if (*c_string == '\0')
+ break;
+ final_string += "\n ";
+ chars_in_line = 6;
+ }
+
+ // Append data type
+ AddString(string("type: ") + flag.type, &final_string, &chars_in_line);
+ // The listed default value will be the actual default from the flag
+ // definition in the originating source file, unless the value has
+ // subsequently been modified using SetCommandLineOptionWithMode() with mode
+ // SET_FLAGS_DEFAULT, or by setting FLAGS_foo = bar before initializing.
+ AddString(PrintStringFlagsWithQuotes(flag, "default", false), &final_string,
+ &chars_in_line);
+ if (!flag.is_default) {
+ AddString(PrintStringFlagsWithQuotes(flag, "currently", true),
+ &final_string, &chars_in_line);
+ }
+
+ final_string += '\n';
+ return final_string;
+}
+
+// Simple routine to xml-escape a string: escape & and < only.
+static string XMLText(const string& txt) {
+ string ans = txt;
+ for (string::size_type pos = 0; (pos = ans.find("&", pos)) != string::npos; )
+ ans.replace(pos++, 1, "&amp;");
+ for (string::size_type pos = 0; (pos = ans.find("<", pos)) != string::npos; )
+ ans.replace(pos++, 1, "&lt;");
+ return ans;
+}
+
+static void AddXMLTag(string* r, const char* tag, const string& txt) {
+ *r += ('<');
+ *r += (tag);
+ *r += ('>');
+ *r += (XMLText(txt));
+ *r += ("</");
+ *r += (tag);
+ *r += ('>');
+}
+
+static string DescribeOneFlagInXML(const CommandLineFlagInfo& flag) {
+ // The file and flagname could have been attributes, but default
+ // and meaning need to avoid attribute normalization. This way it
+ // can be parsed by simple programs, in addition to xml parsers.
+ string r("<flag>");
+ AddXMLTag(&r, "file", flag.filename);
+ AddXMLTag(&r, "name", flag.name);
+ AddXMLTag(&r, "meaning", flag.description);
+ AddXMLTag(&r, "default", flag.default_value);
+ AddXMLTag(&r, "current", flag.current_value);
+ AddXMLTag(&r, "type", flag.type);
+ r += "</flag>";
+ return r;
+}
+
+// --------------------------------------------------------------------
+// ShowUsageWithFlags()
+// ShowUsageWithFlagsRestrict()
+// ShowXMLOfFlags()
+// These routines variously expose the registry's list of flag
+// values. ShowUsage*() prints the flag-value information
+// to stdout in a user-readable format (that's what --help uses).
+// The Restrict() version limits what flags are shown.
+// ShowXMLOfFlags() prints the flag-value information to stdout
+// in a machine-readable format. In all cases, the flags are
+// sorted: first by filename they are defined in, then by flagname.
+// --------------------------------------------------------------------
+
+static const char* Basename(const char* filename) {
+ const char* sep = strrchr(filename, PATH_SEPARATOR);
+ return sep ? sep + 1 : filename;
+}
+
+static string Dirname(const string& filename) {
+ string::size_type sep = filename.rfind(PATH_SEPARATOR);
+ return filename.substr(0, (sep == string::npos) ? 0 : sep);
+}
+
+// Test whether a filename contains at least one of the substrings.
+static bool FileMatchesSubstring(const string& filename,
+ const vector<string>& substrings) {
+ for (vector<string>::const_iterator target = substrings.begin();
+ target != substrings.end();
+ ++target) {
+ if (strstr(filename.c_str(), target->c_str()) != NULL)
+ return true;
+ // If the substring starts with a '/', that means that we want
+ // the string to be at the beginning of a directory component.
+ // That should match the first directory component as well, so
+ // we allow '/foo' to match a filename of 'foo'.
+ if (!target->empty() && (*target)[0] == '/' &&
+ strncmp(filename.c_str(), target->c_str() + 1,
+ strlen(target->c_str() + 1)) == 0)
+ return true;
+ }
+ return false;
+}
+
+// Show help for every filename which matches any of the target substrings.
+// If substrings is empty, shows help for every file. If a flag's help message
+// has been stripped (e.g. by adding '#define STRIP_FLAG_HELP 1' before
+// including gflags/gflags.h), then this flag will not be displayed by
+// '--help' and its variants.
+static void ShowUsageWithFlagsMatching(const char *argv0,
+ const vector<string> &substrings) {
+ fprintf(stdout, "%s: %s\n", Basename(argv0), ProgramUsage());
+
+ vector<CommandLineFlagInfo> flags;
+ GetAllFlags(&flags); // flags are sorted by filename, then flagname
+
+ string last_filename; // so we know when we're at a new file
+ bool first_directory = true; // controls blank lines between dirs
+ bool found_match = false; // stays false iff no dir matches restrict
+ for (vector<CommandLineFlagInfo>::const_iterator flag = flags.begin();
+ flag != flags.end();
+ ++flag) {
+ if (substrings.empty() ||
+ FileMatchesSubstring(flag->filename, substrings)) {
+ // If the flag has been stripped, pretend that it doesn't exist.
+ if (flag->description == kStrippedFlagHelp) continue;
+ found_match = true; // this flag passed the match!
+ if (flag->filename != last_filename) { // new file
+ if (Dirname(flag->filename) != Dirname(last_filename)) { // new dir!
+ if (!first_directory)
+ fprintf(stdout, "\n\n"); // put blank lines between directories
+ first_directory = false;
+ }
+ fprintf(stdout, "\n Flags from %s:\n", flag->filename.c_str());
+ last_filename = flag->filename;
+ }
+ // Now print this flag
+ fprintf(stdout, "%s", DescribeOneFlag(*flag).c_str());
+ }
+ }
+ if (!found_match && !substrings.empty()) {
+ fprintf(stdout, "\n No modules matched: use -help\n");
+ }
+}
+
+void ShowUsageWithFlagsRestrict(const char *argv0, const char *restrict) {
+ vector<string> substrings;
+ if (restrict != NULL && *restrict != '\0') {
+ substrings.push_back(restrict);
+ }
+ ShowUsageWithFlagsMatching(argv0, substrings);
+}
+
+void ShowUsageWithFlags(const char *argv0) {
+ ShowUsageWithFlagsRestrict(argv0, "");
+}
+
+// Convert the help, program, and usage to xml.
+static void ShowXMLOfFlags(const char *prog_name) {
+ vector<CommandLineFlagInfo> flags;
+ GetAllFlags(&flags); // flags are sorted: by filename, then flagname
+
+ // XML. There is no corresponding schema yet
+ fprintf(stdout, "<?xml version=\"1.0\"?>\n");
+ // The document
+ fprintf(stdout, "<AllFlags>\n");
+ // the program name and usage
+ fprintf(stdout, "<program>%s</program>\n",
+ XMLText(Basename(prog_name)).c_str());
+ fprintf(stdout, "<usage>%s</usage>\n",
+ XMLText(ProgramUsage()).c_str());
+ // All the flags
+ for (vector<CommandLineFlagInfo>::const_iterator flag = flags.begin();
+ flag != flags.end();
+ ++flag) {
+ if (flag->description != kStrippedFlagHelp)
+ fprintf(stdout, "%s\n", DescribeOneFlagInXML(*flag).c_str());
+ }
+ // The end of the document
+ fprintf(stdout, "</AllFlags>\n");
+}
+
+// --------------------------------------------------------------------
+// ShowVersion()
+// Called upon --version. Prints build-related info.
+// --------------------------------------------------------------------
+
+static void ShowVersion() {
+ fprintf(stdout, "%s\n", ProgramInvocationShortName());
+ // TODO: add other stuff, like a timestamp, who built it, what
+ // target they built, etc.
+
+# if !defined(NDEBUG)
+ fprintf(stdout, "Debug build (NDEBUG not #defined)\n");
+# endif
+}
+
+static void AppendPrognameStrings(vector<string>* substrings,
+ const char* progname) {
+ string r("/");
+ r += progname;
+ substrings->push_back(r + ".");
+ substrings->push_back(r + "-main.");
+ substrings->push_back(r + "_main.");
+}
+
+// --------------------------------------------------------------------
+// HandleCommandLineHelpFlags()
+// Checks all the 'reporting' commandline flags to see if any
+// have been set. If so, handles them appropriately. Note
+// that all of them, by definition, cause the program to exit
+// if they trigger.
+// --------------------------------------------------------------------
+
+void HandleCommandLineHelpFlags() {
+ const char* progname = ProgramInvocationShortName();
+ extern void (*commandlineflags_exitfunc)(int); // in gflags.cc
+
+ HandleCommandLineCompletions();
+
+ vector<string> substrings;
+ AppendPrognameStrings(&substrings, progname);
+
+ if (FLAGS_helpshort) {
+ // show only flags related to this binary:
+ // E.g. for fileutil.cc, want flags containing ... "/fileutil." cc
+ ShowUsageWithFlagsMatching(progname, substrings);
+ commandlineflags_exitfunc(1); // almost certainly exit()
+
+ } else if (FLAGS_help || FLAGS_helpfull) {
+ // show all options
+ ShowUsageWithFlagsRestrict(progname, ""); // empty restrict
+ commandlineflags_exitfunc(1);
+
+ } else if (!FLAGS_helpon.empty()) {
+ string restrict = "/" + FLAGS_helpon + ".";
+ ShowUsageWithFlagsRestrict(progname, restrict.c_str());
+ commandlineflags_exitfunc(1);
+
+ } else if (!FLAGS_helpmatch.empty()) {
+ ShowUsageWithFlagsRestrict(progname, FLAGS_helpmatch.c_str());
+ commandlineflags_exitfunc(1);
+
+ } else if (FLAGS_helppackage) {
+ // Shows help for all files in the same directory as main(). We
+ // don't want to resort to looking at dirname(progname), because
+ // the user can pick progname, and it may not relate to the file
+ // where main() resides. So instead, we search the flags for a
+ // filename like "/progname.cc", and take the dirname of that.
+ vector<CommandLineFlagInfo> flags;
+ GetAllFlags(&flags);
+ string last_package;
+ for (vector<CommandLineFlagInfo>::const_iterator flag = flags.begin();
+ flag != flags.end();
+ ++flag) {
+ if (!FileMatchesSubstring(flag->filename, substrings))
+ continue;
+ const string package = Dirname(flag->filename) + "/";
+ if (package != last_package) {
+ ShowUsageWithFlagsRestrict(progname, package.c_str());
+ if (!last_package.empty()) { // means this isn't our first pkg
+ fprintf(stderr, "WARNING: Multiple packages contain a file=%s\n",
+ progname);
+ }
+ last_package = package;
+ }
+ }
+ if (last_package.empty()) { // never found a package to print
+ fprintf(stderr, "WARNING: Unable to find a package for file=%s\n",
+ progname);
+ }
+ commandlineflags_exitfunc(1);
+
+ } else if (FLAGS_helpxml) {
+ ShowXMLOfFlags(progname);
+ commandlineflags_exitfunc(1);
+
+ } else if (FLAGS_version) {
+ ShowVersion();
+ // Unlike help, we may be asking for version in a script, so return 0
+ commandlineflags_exitfunc(0);
+ }
+}
+
+_END_GOOGLE_NAMESPACE_
diff --git a/extern/libmv/third_party/gflags/mutex.h b/extern/libmv/third_party/gflags/mutex.h
new file mode 100644
index 00000000000..6e1e8976b6d
--- /dev/null
+++ b/extern/libmv/third_party/gflags/mutex.h
@@ -0,0 +1,349 @@
+// Copyright (c) 2007, Google Inc.
+// 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.
+//
+// ---
+// Author: Craig Silverstein.
+//
+// A simple mutex wrapper, supporting locks and read-write locks.
+// You should assume the locks are *not* re-entrant.
+//
+// To use: you should define the following macros in your configure.ac:
+// ACX_PTHREAD
+// AC_RWLOCK
+// The latter is defined in ../autoconf.
+//
+// This class is meant to be internal-only and should be wrapped by an
+// internal namespace. Before you use this module, please give the
+// name of your internal namespace for this module. Or, if you want
+// to expose it, you'll want to move it to the Google namespace. We
+// cannot put this class in global namespace because there can be some
+// problems when we have multiple versions of Mutex in each shared object.
+//
+// NOTE: by default, we have #ifdef'ed out the TryLock() method.
+// This is for two reasons:
+// 1) TryLock() under Windows is a bit annoying (it requires a
+// #define to be defined very early).
+// 2) TryLock() is broken for NO_THREADS mode, at least in NDEBUG
+// mode.
+// If you need TryLock(), and either these two caveats are not a
+// problem for you, or you're willing to work around them, then
+// feel free to #define GMUTEX_TRYLOCK, or to remove the #ifdefs
+// in the code below.
+//
+// CYGWIN NOTE: Cygwin support for rwlock seems to be buggy:
+// http://www.cygwin.com/ml/cygwin/2008-12/msg00017.html
+// Because of that, we might as well use windows locks for
+// cygwin. They seem to be more reliable than the cygwin pthreads layer.
+//
+// TRICKY IMPLEMENTATION NOTE:
+// This class is designed to be safe to use during
+// dynamic-initialization -- that is, by global constructors that are
+// run before main() starts. The issue in this case is that
+// dynamic-initialization happens in an unpredictable order, and it
+// could be that someone else's dynamic initializer could call a
+// function that tries to acquire this mutex -- but that all happens
+// before this mutex's constructor has run. (This can happen even if
+// the mutex and the function that uses the mutex are in the same .cc
+// file.) Basically, because Mutex does non-trivial work in its
+// constructor, it's not, in the naive implementation, safe to use
+// before dynamic initialization has run on it.
+//
+// The solution used here is to pair the actual mutex primitive with a
+// bool that is set to true when the mutex is dynamically initialized.
+// (Before that it's false.) Then we modify all mutex routines to
+// look at the bool, and not try to lock/unlock until the bool makes
+// it to true (which happens after the Mutex constructor has run.)
+//
+// This works because before main() starts -- particularly, during
+// dynamic initialization -- there are no threads, so a) it's ok that
+// the mutex operations are a no-op, since we don't need locking then
+// anyway; and b) we can be quite confident our bool won't change
+// state between a call to Lock() and a call to Unlock() (that would
+// require a global constructor in one translation unit to call Lock()
+// and another global constructor in another translation unit to call
+// Unlock() later, which is pretty perverse).
+//
+// That said, it's tricky, and can conceivably fail; it's safest to
+// avoid trying to acquire a mutex in a global constructor, if you
+// can. One way it can fail is that a really smart compiler might
+// initialize the bool to true at static-initialization time (too
+// early) rather than at dynamic-initialization time. To discourage
+// that, we set is_safe_ to true in code (not the constructor
+// colon-initializer) and set it to true via a function that always
+// evaluates to true, but that the compiler can't know always
+// evaluates to true. This should be good enough.
+//
+// A related issue is code that could try to access the mutex
+// after it's been destroyed in the global destructors (because
+// the Mutex global destructor runs before some other global
+// destructor, that tries to acquire the mutex). The way we
+// deal with this is by taking a constructor arg that global
+// mutexes should pass in, that causes the destructor to do no
+// work. We still depend on the compiler not doing anything
+// weird to a Mutex's memory after it is destroyed, but for a
+// static global variable, that's pretty safe.
+
+#ifndef GOOGLE_MUTEX_H_
+#define GOOGLE_MUTEX_H_
+
+#include "config.h" // to figure out pthreads support
+
+#if defined(NO_THREADS)
+ typedef int MutexType; // to keep a lock-count
+#elif defined(_WIN32) || defined(__CYGWIN32__) || defined(__CYGWIN64__)
+# define WIN32_LEAN_AND_MEAN // We only need minimal includes
+# ifdef GMUTEX_TRYLOCK
+ // We need Windows NT or later for TryEnterCriticalSection(). If you
+ // don't need that functionality, you can remove these _WIN32_WINNT
+ // lines, and change TryLock() to assert(0) or something.
+# ifndef _WIN32_WINNT
+# define _WIN32_WINNT 0x0400
+# endif
+# endif
+# include <windows.h>
+ typedef CRITICAL_SECTION MutexType;
+#elif defined(HAVE_PTHREAD) && defined(HAVE_RWLOCK)
+ // Needed for pthread_rwlock_*. If it causes problems, you could take it
+ // out, but then you'd have to unset HAVE_RWLOCK (at least on linux -- it
+ // *does* cause problems for FreeBSD, or MacOSX, but isn't needed
+ // for locking there.)
+# ifdef __linux__
+# define _XOPEN_SOURCE 500 // may be needed to get the rwlock calls
+# endif
+# include <pthread.h>
+ typedef pthread_rwlock_t MutexType;
+#elif defined(HAVE_PTHREAD)
+# include <pthread.h>
+ typedef pthread_mutex_t MutexType;
+#else
+# error Need to implement mutex.h for your architecture, or #define NO_THREADS
+#endif
+
+#include <assert.h>
+#include <stdlib.h> // for abort()
+
+#define MUTEX_NAMESPACE gflags_mutex_namespace
+
+namespace MUTEX_NAMESPACE {
+
+class Mutex {
+ public:
+ // This is used for the single-arg constructor
+ enum LinkerInitialized { LINKER_INITIALIZED };
+
+ // Create a Mutex that is not held by anybody. This constructor is
+ // typically used for Mutexes allocated on the heap or the stack.
+ inline Mutex();
+ // This constructor should be used for global, static Mutex objects.
+ // It inhibits work being done by the destructor, which makes it
+ // safer for code that tries to acqiure this mutex in their global
+ // destructor.
+ inline Mutex(LinkerInitialized);
+
+ // Destructor
+ inline ~Mutex();
+
+ inline void Lock(); // Block if needed until free then acquire exclusively
+ inline void Unlock(); // Release a lock acquired via Lock()
+#ifdef GMUTEX_TRYLOCK
+ inline bool TryLock(); // If free, Lock() and return true, else return false
+#endif
+ // Note that on systems that don't support read-write locks, these may
+ // be implemented as synonyms to Lock() and Unlock(). So you can use
+ // these for efficiency, but don't use them anyplace where being able
+ // to do shared reads is necessary to avoid deadlock.
+ inline void ReaderLock(); // Block until free or shared then acquire a share
+ inline void ReaderUnlock(); // Release a read share of this Mutex
+ inline void WriterLock() { Lock(); } // Acquire an exclusive lock
+ inline void WriterUnlock() { Unlock(); } // Release a lock from WriterLock()
+
+ private:
+ MutexType mutex_;
+ // We want to make sure that the compiler sets is_safe_ to true only
+ // when we tell it to, and never makes assumptions is_safe_ is
+ // always true. volatile is the most reliable way to do that.
+ volatile bool is_safe_;
+ // This indicates which constructor was called.
+ bool destroy_;
+
+ inline void SetIsSafe() { is_safe_ = true; }
+
+ // Catch the error of writing Mutex when intending MutexLock.
+ Mutex(Mutex* /*ignored*/) {}
+ // Disallow "evil" constructors
+ Mutex(const Mutex&);
+ void operator=(const Mutex&);
+};
+
+// Now the implementation of Mutex for various systems
+#if defined(NO_THREADS)
+
+// When we don't have threads, we can be either reading or writing,
+// but not both. We can have lots of readers at once (in no-threads
+// mode, that's most likely to happen in recursive function calls),
+// but only one writer. We represent this by having mutex_ be -1 when
+// writing and a number > 0 when reading (and 0 when no lock is held).
+//
+// In debug mode, we assert these invariants, while in non-debug mode
+// we do nothing, for efficiency. That's why everything is in an
+// assert.
+
+Mutex::Mutex() : mutex_(0) { }
+Mutex::Mutex(Mutex::LinkerInitialized) : mutex_(0) { }
+Mutex::~Mutex() { assert(mutex_ == 0); }
+void Mutex::Lock() { assert(--mutex_ == -1); }
+void Mutex::Unlock() { assert(mutex_++ == -1); }
+#ifdef GMUTEX_TRYLOCK
+bool Mutex::TryLock() { if (mutex_) return false; Lock(); return true; }
+#endif
+void Mutex::ReaderLock() { assert(++mutex_ > 0); }
+void Mutex::ReaderUnlock() { assert(mutex_-- > 0); }
+
+#elif defined(_WIN32) || defined(__CYGWIN32__) || defined(__CYGWIN64__)
+
+Mutex::Mutex() : destroy_(true) {
+ InitializeCriticalSection(&mutex_);
+ SetIsSafe();
+}
+Mutex::Mutex(LinkerInitialized) : destroy_(false) {
+ InitializeCriticalSection(&mutex_);
+ SetIsSafe();
+}
+Mutex::~Mutex() { if (destroy_) DeleteCriticalSection(&mutex_); }
+void Mutex::Lock() { if (is_safe_) EnterCriticalSection(&mutex_); }
+void Mutex::Unlock() { if (is_safe_) LeaveCriticalSection(&mutex_); }
+#ifdef GMUTEX_TRYLOCK
+bool Mutex::TryLock() { return is_safe_ ?
+ TryEnterCriticalSection(&mutex_) != 0 : true; }
+#endif
+void Mutex::ReaderLock() { Lock(); } // we don't have read-write locks
+void Mutex::ReaderUnlock() { Unlock(); }
+
+#elif defined(HAVE_PTHREAD) && defined(HAVE_RWLOCK)
+
+#define SAFE_PTHREAD(fncall) do { /* run fncall if is_safe_ is true */ \
+ if (is_safe_ && fncall(&mutex_) != 0) abort(); \
+} while (0)
+
+Mutex::Mutex() : destroy_(true) {
+ SetIsSafe();
+ if (is_safe_ && pthread_rwlock_init(&mutex_, NULL) != 0) abort();
+}
+Mutex::Mutex(Mutex::LinkerInitialized) : destroy_(false) {
+ SetIsSafe();
+ if (is_safe_ && pthread_rwlock_init(&mutex_, NULL) != 0) abort();
+}
+Mutex::~Mutex() { if (destroy_) SAFE_PTHREAD(pthread_rwlock_destroy); }
+void Mutex::Lock() { SAFE_PTHREAD(pthread_rwlock_wrlock); }
+void Mutex::Unlock() { SAFE_PTHREAD(pthread_rwlock_unlock); }
+#ifdef GMUTEX_TRYLOCK
+bool Mutex::TryLock() { return is_safe_ ?
+ pthread_rwlock_trywrlock(&mutex_) == 0 : true; }
+#endif
+void Mutex::ReaderLock() { SAFE_PTHREAD(pthread_rwlock_rdlock); }
+void Mutex::ReaderUnlock() { SAFE_PTHREAD(pthread_rwlock_unlock); }
+#undef SAFE_PTHREAD
+
+#elif defined(HAVE_PTHREAD)
+
+#define SAFE_PTHREAD(fncall) do { /* run fncall if is_safe_ is true */ \
+ if (is_safe_ && fncall(&mutex_) != 0) abort(); \
+} while (0)
+
+Mutex::Mutex() : destroy_(true) {
+ SetIsSafe();
+ if (is_safe_ && pthread_mutex_init(&mutex_, NULL) != 0) abort();
+}
+Mutex::Mutex(Mutex::LinkerInitialized) : destroy_(false) {
+ SetIsSafe();
+ if (is_safe_ && pthread_mutex_init(&mutex_, NULL) != 0) abort();
+}
+Mutex::~Mutex() { if (destroy_) SAFE_PTHREAD(pthread_mutex_destroy); }
+void Mutex::Lock() { SAFE_PTHREAD(pthread_mutex_lock); }
+void Mutex::Unlock() { SAFE_PTHREAD(pthread_mutex_unlock); }
+#ifdef GMUTEX_TRYLOCK
+bool Mutex::TryLock() { return is_safe_ ?
+ pthread_mutex_trylock(&mutex_) == 0 : true; }
+#endif
+void Mutex::ReaderLock() { Lock(); }
+void Mutex::ReaderUnlock() { Unlock(); }
+#undef SAFE_PTHREAD
+
+#endif
+
+// --------------------------------------------------------------------------
+// Some helper classes
+
+// MutexLock(mu) acquires mu when constructed and releases it when destroyed.
+class MutexLock {
+ public:
+ explicit MutexLock(Mutex *mu) : mu_(mu) { mu_->Lock(); }
+ ~MutexLock() { mu_->Unlock(); }
+ private:
+ Mutex * const mu_;
+ // Disallow "evil" constructors
+ MutexLock(const MutexLock&);
+ void operator=(const MutexLock&);
+};
+
+// ReaderMutexLock and WriterMutexLock do the same, for rwlocks
+class ReaderMutexLock {
+ public:
+ explicit ReaderMutexLock(Mutex *mu) : mu_(mu) { mu_->ReaderLock(); }
+ ~ReaderMutexLock() { mu_->ReaderUnlock(); }
+ private:
+ Mutex * const mu_;
+ // Disallow "evil" constructors
+ ReaderMutexLock(const ReaderMutexLock&);
+ void operator=(const ReaderMutexLock&);
+};
+
+class WriterMutexLock {
+ public:
+ explicit WriterMutexLock(Mutex *mu) : mu_(mu) { mu_->WriterLock(); }
+ ~WriterMutexLock() { mu_->WriterUnlock(); }
+ private:
+ Mutex * const mu_;
+ // Disallow "evil" constructors
+ WriterMutexLock(const WriterMutexLock&);
+ void operator=(const WriterMutexLock&);
+};
+
+// Catch bug where variable name is omitted, e.g. MutexLock (&mu);
+#define MutexLock(x) COMPILE_ASSERT(0, mutex_lock_decl_missing_var_name)
+#define ReaderMutexLock(x) COMPILE_ASSERT(0, rmutex_lock_decl_missing_var_name)
+#define WriterMutexLock(x) COMPILE_ASSERT(0, wmutex_lock_decl_missing_var_name)
+
+} // namespace MUTEX_NAMESPACE
+
+using namespace MUTEX_NAMESPACE;
+
+#undef MUTEX_NAMESPACE
+
+#endif /* #define GOOGLE_MUTEX_H__ */
diff --git a/extern/libmv/third_party/glog/AUTHORS b/extern/libmv/third_party/glog/AUTHORS
new file mode 100644
index 00000000000..ee92be88dcf
--- /dev/null
+++ b/extern/libmv/third_party/glog/AUTHORS
@@ -0,0 +1,2 @@
+opensource@google.com
+
diff --git a/extern/libmv/third_party/glog/COPYING b/extern/libmv/third_party/glog/COPYING
new file mode 100644
index 00000000000..38396b580b3
--- /dev/null
+++ b/extern/libmv/third_party/glog/COPYING
@@ -0,0 +1,65 @@
+Copyright (c) 2008, Google Inc.
+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.
+
+
+A function gettimeofday in utilities.cc is based on
+
+http://www.google.com/codesearch/p?hl=en#dR3YEbitojA/COPYING&q=GetSystemTimeAsFileTime%20license:bsd
+
+The license of this code is:
+
+Copyright (c) 2003-2008, Jouni Malinen <j@w1.fi> and contributors
+All Rights Reserved.
+
+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(s) of the above-listed copyright holder(s) 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.
diff --git a/extern/libmv/third_party/glog/ChangeLog b/extern/libmv/third_party/glog/ChangeLog
new file mode 100644
index 00000000000..350fee921e3
--- /dev/null
+++ b/extern/libmv/third_party/glog/ChangeLog
@@ -0,0 +1,59 @@
+2010-06-15 Google Inc. <opensource@google.com>
+
+ * google-glog: version 0.3.1
+ * GLOG_* environment variables now work even when gflags is installed.
+ * Snow leopard support.
+ * Now we can build and test from out side tree.
+ * Add DCHECK_NOTNULL.
+ * Add ShutdownGoogleLogging to close syslog (thanks DGunchev)
+ * Fix --enable-frame-pointers option (thanks kazuki.ohta)
+ * Fix libunwind detection (thanks giantchen)
+
+2009-07-30 Google Inc. <opensource@google.com>
+
+ * google-glog: version 0.3.0
+ * Fix a deadlock happened when user uses glog with recent gflags.
+ * Suppress several unnecessary warnings (thanks keir).
+ * NetBSD and OpenBSD support.
+ * Use Win32API GetComputeNameA properly (thanks magila).
+ * Fix user name detection for Windows (thanks ademin).
+ * Fix several minor bugs.
+
+2009-04-10 Google Inc. <opensource@google.com>
+ * google-glog: version 0.2.1
+ * Fix timestamps of VC++ version.
+ * Add pkg-config support (thanks Tomasz)
+ * Fix build problem when building with gtest (thanks Michael)
+ * Add --with-gflags option for configure (thanks Michael)
+ * Fixes for GCC 4.4 (thanks John)
+
+2009-01-23 Google Inc. <opensource@google.com>
+ * google-glog: version 0.2
+ * Add initial Windows VC++ support.
+ * Google testing/mocking frameworks integration.
+ * Link pthread library automatically.
+ * Flush logs in signal handlers.
+ * Add macros LOG_TO_STRING, LOG_AT_LEVEL, DVLOG, and LOG_TO_SINK_ONLY.
+ * Log microseconds.
+ * Add --log_backtrace_at option.
+ * Fix some minor bugs.
+
+2008-11-18 Google Inc. <opensource@google.com>
+ * google-glog: version 0.1.2
+ * Add InstallFailureSignalHandler(). (satorux)
+ * Re-organize the way to produce stacktraces.
+ * Don't define unnecessary macro DISALLOW_EVIL_CONSTRUCTORS.
+
+2008-10-15 Google Inc. <opensource@google.com>
+ * google-glog: version 0.1.1
+ * Support symbolize for MacOSX 10.5.
+ * BUG FIX: --vmodule didn't work with gflags.
+ * BUG FIX: symbolize_unittest failed with GCC 4.3.
+ * Several fixes on the document.
+
+2008-10-07 Google Inc. <opensource@google.com>
+
+ * google-glog: initial release:
+ The glog package contains a library that implements application-level
+ logging. This library provides logging APIs based on C++-style
+ streams and various helper macros.
diff --git a/extern/libmv/third_party/glog/NEWS b/extern/libmv/third_party/glog/NEWS
new file mode 100644
index 00000000000..e69de29bb2d
--- /dev/null
+++ b/extern/libmv/third_party/glog/NEWS
diff --git a/extern/libmv/third_party/glog/README b/extern/libmv/third_party/glog/README
new file mode 100644
index 00000000000..77efd37505a
--- /dev/null
+++ b/extern/libmv/third_party/glog/README
@@ -0,0 +1,5 @@
+This repository contains a C++ implementation of the Google logging
+module. Documentation for the implementation is in doc/.
+
+See INSTALL for (generic) installation instructions for C++: basically
+ ./configure && make && make install
diff --git a/extern/libmv/third_party/glog/README.libmv b/extern/libmv/third_party/glog/README.libmv
new file mode 100644
index 00000000000..8f1243b2430
--- /dev/null
+++ b/extern/libmv/third_party/glog/README.libmv
@@ -0,0 +1,38 @@
+Project: Google Logging
+URL: http://code.google.com/p/google-glog/
+License: New BSD
+Upstream version: 0.3.1
+Local modifications:
+
+Upgrading Notes
+* Had to change #include <gflags/gflags.h> to #include "gflags/gflags.h"
+* Make sure to copy over a config_YOUR_PLATFORM.h and put it in config.h
+
+Old changes which got obsoleted (maybe?) by 0.3.1 merge:
+* The config_linux.h is generated by configure on Keir's Ubuntu 9.04 desktop.
+* Commented out some struct ::tm weirdness causing compile failures on
+ ubuntu 8.10 and 9.04.
+* Switched several initializers to memset instead of = {}.
+* Changed some includes pointing to gflags. Not sure why the regular inclusion
+ didn't work.
+* Added some compile flags to silence various warnings, allowing us to keep the
+ differences between upstream small.
+* Don't redefine _XOPEN_SOURCE.
+* Added "google::" to GetReferenceableValue in CHECK_OP_LOG.
+* Add virtual destructor to Thread in googletest.h.
+* Update windows/glog/log_severity to build with QT library that include WinGDI
+ (It cause a double definition of ERROR variable).
+
+Old changes which got obsoleted (maybe?) by 0.2.1 merge:
+* Added #ifndef / def REG_EIP; not sure what that is.
+* Added (void) arg stuff to prevent unused variable warnings.
+* Added google:: namespace prefix to GetReferencableValue
+* Added assignments for several functions marked with no_ignore_return, where
+ the return value was ignored.
+* Commented out the unused function DumpPCAndSymbol() in utilities.cc to silent
+ gcc on the mac
+
+TODO(keir): Remove any obsoleted changes above if they are not necessary after
+testing on more platforms.
+
+WARNING: Mac port not updated for 0.2.1
diff --git a/extern/libmv/third_party/glog/src/base/commandlineflags.h b/extern/libmv/third_party/glog/src/base/commandlineflags.h
new file mode 100644
index 00000000000..6c529ccd847
--- /dev/null
+++ b/extern/libmv/third_party/glog/src/base/commandlineflags.h
@@ -0,0 +1,132 @@
+// Copyright (c) 2008, Google Inc.
+// 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.
+
+// ---
+// This file is a compatibility layer that defines Google's version of
+// command line flags that are used for configuration.
+//
+// We put flags into their own namespace. It is purposefully
+// named in an opaque way that people should have trouble typing
+// directly. The idea is that DEFINE puts the flag in the weird
+// namespace, and DECLARE imports the flag from there into the
+// current namespace. The net result is to force people to use
+// DECLARE to get access to a flag, rather than saying
+// extern bool FLAGS_logtostderr;
+// or some such instead. We want this so we can put extra
+// functionality (like sanity-checking) in DECLARE if we want,
+// and make sure it is picked up everywhere.
+//
+// We also put the type of the variable in the namespace, so that
+// people can't DECLARE_int32 something that they DEFINE_bool'd
+// elsewhere.
+#ifndef BASE_COMMANDLINEFLAGS_H__
+#define BASE_COMMANDLINEFLAGS_H__
+
+#include "config.h"
+#include <string>
+#include <string.h> // for memchr
+#include <stdlib.h> // for getenv
+
+#ifdef HAVE_LIB_GFLAGS
+
+#include "third_party/gflags/gflags.h"
+
+#else
+
+#include "glog/logging.h"
+
+#define DECLARE_VARIABLE(type, name, tn) \
+ namespace FLAG__namespace_do_not_use_directly_use_DECLARE_##tn##_instead { \
+ extern GOOGLE_GLOG_DLL_DECL type FLAGS_##name; \
+ } \
+ using FLAG__namespace_do_not_use_directly_use_DECLARE_##tn##_instead::FLAGS_##name
+#define DEFINE_VARIABLE(type, name, value, meaning, tn) \
+ namespace FLAG__namespace_do_not_use_directly_use_DECLARE_##tn##_instead { \
+ GOOGLE_GLOG_DLL_DECL type FLAGS_##name(value); \
+ char FLAGS_no##name; \
+ } \
+ using FLAG__namespace_do_not_use_directly_use_DECLARE_##tn##_instead::FLAGS_##name
+
+// bool specialization
+#define DECLARE_bool(name) \
+ DECLARE_VARIABLE(bool, name, bool)
+#define DEFINE_bool(name, value, meaning) \
+ DEFINE_VARIABLE(bool, name, value, meaning, bool)
+
+// int32 specialization
+#define DECLARE_int32(name) \
+ DECLARE_VARIABLE(GOOGLE_NAMESPACE::int32, name, int32)
+#define DEFINE_int32(name, value, meaning) \
+ DEFINE_VARIABLE(GOOGLE_NAMESPACE::int32, name, value, meaning, int32)
+
+// Special case for string, because we have to specify the namespace
+// std::string, which doesn't play nicely with our FLAG__namespace hackery.
+#define DECLARE_string(name) \
+ namespace FLAG__namespace_do_not_use_directly_use_DECLARE_string_instead { \
+ extern GOOGLE_GLOG_DLL_DECL std::string FLAGS_##name; \
+ } \
+ using FLAG__namespace_do_not_use_directly_use_DECLARE_string_instead::FLAGS_##name
+#define DEFINE_string(name, value, meaning) \
+ namespace FLAG__namespace_do_not_use_directly_use_DECLARE_string_instead { \
+ GOOGLE_GLOG_DLL_DECL std::string FLAGS_##name(value); \
+ char FLAGS_no##name; \
+ } \
+ using FLAG__namespace_do_not_use_directly_use_DECLARE_string_instead::FLAGS_##name
+
+#endif // HAVE_LIB_GFLAGS
+
+// Define GLOG_DEFINE_* using DEFINE_* . By using these macros, we
+// have GLOG_* environ variables even if we have gflags installed.
+//
+// If both an environment variable and a flag are specified, the value
+// specified by a flag wins. E.g., if GLOG_v=0 and --v=1, the
+// verbosity will be 1, not 0.
+
+#define GLOG_DEFINE_bool(name, value, meaning) \
+ DEFINE_bool(name, EnvToBool("GLOG_" #name, value), meaning)
+
+#define GLOG_DEFINE_int32(name, value, meaning) \
+ DEFINE_int32(name, EnvToInt("GLOG_" #name, value), meaning)
+
+#define GLOG_DEFINE_string(name, value, meaning) \
+ DEFINE_string(name, EnvToString("GLOG_" #name, value), meaning)
+
+// These macros (could be functions, but I don't want to bother with a .cc
+// file), make it easier to initialize flags from the environment.
+
+#define EnvToString(envname, dflt) \
+ (!getenv(envname) ? (dflt) : getenv(envname))
+
+#define EnvToBool(envname, dflt) \
+ (!getenv(envname) ? (dflt) : memchr("tTyY1\0", getenv(envname)[0], 6) != NULL)
+
+#define EnvToInt(envname, dflt) \
+ (!getenv(envname) ? (dflt) : strtol(getenv(envname), NULL, 10))
+
+#endif // BASE_COMMANDLINEFLAGS_H__
diff --git a/extern/libmv/third_party/glog/src/base/googleinit.h b/extern/libmv/third_party/glog/src/base/googleinit.h
new file mode 100644
index 00000000000..c907308e852
--- /dev/null
+++ b/extern/libmv/third_party/glog/src/base/googleinit.h
@@ -0,0 +1,51 @@
+// Copyright (c) 2008, Google Inc.
+// 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.
+
+// ---
+// Author: Jacob Hoffman-Andrews
+
+#ifndef _GOOGLEINIT_H
+#define _GOOGLEINIT_H
+
+class GoogleInitializer {
+ public:
+ typedef void (*void_function)(void);
+ GoogleInitializer(const char* name, void_function f) {
+ f();
+ }
+};
+
+#define REGISTER_MODULE_INITIALIZER(name, body) \
+ namespace { \
+ static void google_init_module_##name () { body; } \
+ GoogleInitializer google_initializer_module_##name(#name, \
+ google_init_module_##name); \
+ }
+
+#endif /* _GOOGLEINIT_H */
diff --git a/extern/libmv/third_party/glog/src/base/mutex.h b/extern/libmv/third_party/glog/src/base/mutex.h
new file mode 100644
index 00000000000..7ba88cb5a63
--- /dev/null
+++ b/extern/libmv/third_party/glog/src/base/mutex.h
@@ -0,0 +1,325 @@
+// Copyright (c) 2007, Google Inc.
+// 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.
+//
+// ---
+// Author: Craig Silverstein.
+//
+// A simple mutex wrapper, supporting locks and read-write locks.
+// You should assume the locks are *not* re-entrant.
+//
+// To use: you should define the following macros in your configure.ac:
+// ACX_PTHREAD
+// AC_RWLOCK
+// The latter is defined in ../autoconf.
+//
+// This class is meant to be internal-only and should be wrapped by an
+// internal namespace. Before you use this module, please give the
+// name of your internal namespace for this module. Or, if you want
+// to expose it, you'll want to move it to the Google namespace. We
+// cannot put this class in global namespace because there can be some
+// problems when we have multiple versions of Mutex in each shared object.
+//
+// NOTE: by default, we have #ifdef'ed out the TryLock() method.
+// This is for two reasons:
+// 1) TryLock() under Windows is a bit annoying (it requires a
+// #define to be defined very early).
+// 2) TryLock() is broken for NO_THREADS mode, at least in NDEBUG
+// mode.
+// If you need TryLock(), and either these two caveats are not a
+// problem for you, or you're willing to work around them, then
+// feel free to #define GMUTEX_TRYLOCK, or to remove the #ifdefs
+// in the code below.
+//
+// CYGWIN NOTE: Cygwin support for rwlock seems to be buggy:
+// http://www.cygwin.com/ml/cygwin/2008-12/msg00017.html
+// Because of that, we might as well use windows locks for
+// cygwin. They seem to be more reliable than the cygwin pthreads layer.
+//
+// TRICKY IMPLEMENTATION NOTE:
+// This class is designed to be safe to use during
+// dynamic-initialization -- that is, by global constructors that are
+// run before main() starts. The issue in this case is that
+// dynamic-initialization happens in an unpredictable order, and it
+// could be that someone else's dynamic initializer could call a
+// function that tries to acquire this mutex -- but that all happens
+// before this mutex's constructor has run. (This can happen even if
+// the mutex and the function that uses the mutex are in the same .cc
+// file.) Basically, because Mutex does non-trivial work in its
+// constructor, it's not, in the naive implementation, safe to use
+// before dynamic initialization has run on it.
+//
+// The solution used here is to pair the actual mutex primitive with a
+// bool that is set to true when the mutex is dynamically initialized.
+// (Before that it's false.) Then we modify all mutex routines to
+// look at the bool, and not try to lock/unlock until the bool makes
+// it to true (which happens after the Mutex constructor has run.)
+//
+// This works because before main() starts -- particularly, during
+// dynamic initialization -- there are no threads, so a) it's ok that
+// the mutex operations are a no-op, since we don't need locking then
+// anyway; and b) we can be quite confident our bool won't change
+// state between a call to Lock() and a call to Unlock() (that would
+// require a global constructor in one translation unit to call Lock()
+// and another global constructor in another translation unit to call
+// Unlock() later, which is pretty perverse).
+//
+// That said, it's tricky, and can conceivably fail; it's safest to
+// avoid trying to acquire a mutex in a global constructor, if you
+// can. One way it can fail is that a really smart compiler might
+// initialize the bool to true at static-initialization time (too
+// early) rather than at dynamic-initialization time. To discourage
+// that, we set is_safe_ to true in code (not the constructor
+// colon-initializer) and set it to true via a function that always
+// evaluates to true, but that the compiler can't know always
+// evaluates to true. This should be good enough.
+
+#ifndef GOOGLE_MUTEX_H_
+#define GOOGLE_MUTEX_H_
+
+#include "config.h" // to figure out pthreads support
+
+#if defined(NO_THREADS)
+ typedef int MutexType; // to keep a lock-count
+#elif defined(_WIN32) || defined(__CYGWIN32__) || defined(__CYGWIN64__)
+# define WIN32_LEAN_AND_MEAN // We only need minimal includes
+# ifdef GMUTEX_TRYLOCK
+ // We need Windows NT or later for TryEnterCriticalSection(). If you
+ // don't need that functionality, you can remove these _WIN32_WINNT
+ // lines, and change TryLock() to assert(0) or something.
+# ifndef _WIN32_WINNT
+# define _WIN32_WINNT 0x0400
+# endif
+# endif
+// To avoid macro definition of ERROR.
+# define NOGDI
+// To avoid macro definition of min/max.
+# define NOMINMAX
+# include <windows.h>
+ typedef CRITICAL_SECTION MutexType;
+#elif defined(HAVE_PTHREAD) && defined(HAVE_RWLOCK)
+ // Needed for pthread_rwlock_*. If it causes problems, you could take it
+ // out, but then you'd have to unset HAVE_RWLOCK (at least on linux -- it
+ // *does* cause problems for FreeBSD, or MacOSX, but isn't needed
+ // for locking there.)
+# ifdef __linux__
+# define _XOPEN_SOURCE 500 // may be needed to get the rwlock calls
+# endif
+# include <pthread.h>
+ typedef pthread_rwlock_t MutexType;
+#elif defined(HAVE_PTHREAD)
+# include <pthread.h>
+ typedef pthread_mutex_t MutexType;
+#else
+# error Need to implement mutex.h for your architecture, or #define NO_THREADS
+#endif
+
+// We need to include these header files after defining _XOPEN_SOURCE
+// as they may define the _XOPEN_SOURCE macro.
+#include <assert.h>
+#include <stdlib.h> // for abort()
+
+#define MUTEX_NAMESPACE glog_internal_namespace_
+
+namespace MUTEX_NAMESPACE {
+
+class Mutex {
+ public:
+ // Create a Mutex that is not held by anybody. This constructor is
+ // typically used for Mutexes allocated on the heap or the stack.
+ // See below for a recommendation for constructing global Mutex
+ // objects.
+ inline Mutex();
+
+ // Destructor
+ inline ~Mutex();
+
+ inline void Lock(); // Block if needed until free then acquire exclusively
+ inline void Unlock(); // Release a lock acquired via Lock()
+#ifdef GMUTEX_TRYLOCK
+ inline bool TryLock(); // If free, Lock() and return true, else return false
+#endif
+ // Note that on systems that don't support read-write locks, these may
+ // be implemented as synonyms to Lock() and Unlock(). So you can use
+ // these for efficiency, but don't use them anyplace where being able
+ // to do shared reads is necessary to avoid deadlock.
+ inline void ReaderLock(); // Block until free or shared then acquire a share
+ inline void ReaderUnlock(); // Release a read share of this Mutex
+ inline void WriterLock() { Lock(); } // Acquire an exclusive lock
+ inline void WriterUnlock() { Unlock(); } // Release a lock from WriterLock()
+
+ // TODO(hamaji): Do nothing, implement correctly.
+ inline void AssertHeld() {}
+
+ private:
+ MutexType mutex_;
+ // We want to make sure that the compiler sets is_safe_ to true only
+ // when we tell it to, and never makes assumptions is_safe_ is
+ // always true. volatile is the most reliable way to do that.
+ volatile bool is_safe_;
+
+ inline void SetIsSafe() { is_safe_ = true; }
+
+ // Catch the error of writing Mutex when intending MutexLock.
+ Mutex(Mutex* /*ignored*/) {}
+ // Disallow "evil" constructors
+ Mutex(const Mutex&);
+ void operator=(const Mutex&);
+};
+
+// Now the implementation of Mutex for various systems
+#if defined(NO_THREADS)
+
+// When we don't have threads, we can be either reading or writing,
+// but not both. We can have lots of readers at once (in no-threads
+// mode, that's most likely to happen in recursive function calls),
+// but only one writer. We represent this by having mutex_ be -1 when
+// writing and a number > 0 when reading (and 0 when no lock is held).
+//
+// In debug mode, we assert these invariants, while in non-debug mode
+// we do nothing, for efficiency. That's why everything is in an
+// assert.
+
+Mutex::Mutex() : mutex_(0) { }
+Mutex::~Mutex() { assert(mutex_ == 0); }
+void Mutex::Lock() { assert(--mutex_ == -1); }
+void Mutex::Unlock() { assert(mutex_++ == -1); }
+#ifdef GMUTEX_TRYLOCK
+bool Mutex::TryLock() { if (mutex_) return false; Lock(); return true; }
+#endif
+void Mutex::ReaderLock() { assert(++mutex_ > 0); }
+void Mutex::ReaderUnlock() { assert(mutex_-- > 0); }
+
+#elif defined(_WIN32) || defined(__CYGWIN32__) || defined(__CYGWIN64__)
+
+Mutex::Mutex() { InitializeCriticalSection(&mutex_); SetIsSafe(); }
+Mutex::~Mutex() { DeleteCriticalSection(&mutex_); }
+void Mutex::Lock() { if (is_safe_) EnterCriticalSection(&mutex_); }
+void Mutex::Unlock() { if (is_safe_) LeaveCriticalSection(&mutex_); }
+#ifdef GMUTEX_TRYLOCK
+bool Mutex::TryLock() { return is_safe_ ?
+ TryEnterCriticalSection(&mutex_) != 0 : true; }
+#endif
+void Mutex::ReaderLock() { Lock(); } // we don't have read-write locks
+void Mutex::ReaderUnlock() { Unlock(); }
+
+#elif defined(HAVE_PTHREAD) && defined(HAVE_RWLOCK)
+
+#define SAFE_PTHREAD(fncall) do { /* run fncall if is_safe_ is true */ \
+ if (is_safe_ && fncall(&mutex_) != 0) abort(); \
+} while (0)
+
+Mutex::Mutex() {
+ SetIsSafe();
+ if (is_safe_ && pthread_rwlock_init(&mutex_, NULL) != 0) abort();
+}
+Mutex::~Mutex() { SAFE_PTHREAD(pthread_rwlock_destroy); }
+void Mutex::Lock() { SAFE_PTHREAD(pthread_rwlock_wrlock); }
+void Mutex::Unlock() { SAFE_PTHREAD(pthread_rwlock_unlock); }
+#ifdef GMUTEX_TRYLOCK
+bool Mutex::TryLock() { return is_safe_ ?
+ pthread_rwlock_trywrlock(&mutex_) == 0 :
+ true; }
+#endif
+void Mutex::ReaderLock() { SAFE_PTHREAD(pthread_rwlock_rdlock); }
+void Mutex::ReaderUnlock() { SAFE_PTHREAD(pthread_rwlock_unlock); }
+#undef SAFE_PTHREAD
+
+#elif defined(HAVE_PTHREAD)
+
+#define SAFE_PTHREAD(fncall) do { /* run fncall if is_safe_ is true */ \
+ if (is_safe_ && fncall(&mutex_) != 0) abort(); \
+} while (0)
+
+Mutex::Mutex() {
+ SetIsSafe();
+ if (is_safe_ && pthread_mutex_init(&mutex_, NULL) != 0) abort();
+}
+Mutex::~Mutex() { SAFE_PTHREAD(pthread_mutex_destroy); }
+void Mutex::Lock() { SAFE_PTHREAD(pthread_mutex_lock); }
+void Mutex::Unlock() { SAFE_PTHREAD(pthread_mutex_unlock); }
+#ifdef GMUTEX_TRYLOCK
+bool Mutex::TryLock() { return is_safe_ ?
+ pthread_mutex_trylock(&mutex_) == 0 : true; }
+#endif
+void Mutex::ReaderLock() { Lock(); }
+void Mutex::ReaderUnlock() { Unlock(); }
+#undef SAFE_PTHREAD
+
+#endif
+
+// --------------------------------------------------------------------------
+// Some helper classes
+
+// MutexLock(mu) acquires mu when constructed and releases it when destroyed.
+class MutexLock {
+ public:
+ explicit MutexLock(Mutex *mu) : mu_(mu) { mu_->Lock(); }
+ ~MutexLock() { mu_->Unlock(); }
+ private:
+ Mutex * const mu_;
+ // Disallow "evil" constructors
+ MutexLock(const MutexLock&);
+ void operator=(const MutexLock&);
+};
+
+// ReaderMutexLock and WriterMutexLock do the same, for rwlocks
+class ReaderMutexLock {
+ public:
+ explicit ReaderMutexLock(Mutex *mu) : mu_(mu) { mu_->ReaderLock(); }
+ ~ReaderMutexLock() { mu_->ReaderUnlock(); }
+ private:
+ Mutex * const mu_;
+ // Disallow "evil" constructors
+ ReaderMutexLock(const ReaderMutexLock&);
+ void operator=(const ReaderMutexLock&);
+};
+
+class WriterMutexLock {
+ public:
+ explicit WriterMutexLock(Mutex *mu) : mu_(mu) { mu_->WriterLock(); }
+ ~WriterMutexLock() { mu_->WriterUnlock(); }
+ private:
+ Mutex * const mu_;
+ // Disallow "evil" constructors
+ WriterMutexLock(const WriterMutexLock&);
+ void operator=(const WriterMutexLock&);
+};
+
+// Catch bug where variable name is omitted, e.g. MutexLock (&mu);
+#define MutexLock(x) COMPILE_ASSERT(0, mutex_lock_decl_missing_var_name)
+#define ReaderMutexLock(x) COMPILE_ASSERT(0, rmutex_lock_decl_missing_var_name)
+#define WriterMutexLock(x) COMPILE_ASSERT(0, wmutex_lock_decl_missing_var_name)
+
+} // namespace MUTEX_NAMESPACE
+
+using namespace MUTEX_NAMESPACE;
+
+#undef MUTEX_NAMESPACE
+
+#endif /* #define GOOGLE_MUTEX_H__ */
diff --git a/extern/libmv/third_party/glog/src/config.h b/extern/libmv/third_party/glog/src/config.h
new file mode 100644
index 00000000000..ed8d56e7799
--- /dev/null
+++ b/extern/libmv/third_party/glog/src/config.h
@@ -0,0 +1,11 @@
+/* src/config.h. Generated from config.h.in by configure. */
+/* src/config.h.in. Generated from configure.ac by autoheader. */
+
+/* Namespace for Google classes */
+#ifdef __APPLE__
+ #include "config_mac.h"
+#elif __GNUC__
+ #include "config_linux.h"
+#elif _MSC_VER
+ #include "windows/config.h"
+#endif
diff --git a/extern/libmv/third_party/glog/src/config_linux.h b/extern/libmv/third_party/glog/src/config_linux.h
new file mode 100644
index 00000000000..df6956c9ecf
--- /dev/null
+++ b/extern/libmv/third_party/glog/src/config_linux.h
@@ -0,0 +1,164 @@
+/* src/config.h. Generated from config.h.in by configure. */
+/* src/config.h.in. Generated from configure.ac by autoheader. */
+
+/* Namespace for Google classes */
+#define GOOGLE_NAMESPACE google
+
+/* Define if you have the `dladdr' function */
+/* #undef HAVE_DLADDR */
+
+/* Define to 1 if you have the <dlfcn.h> header file. */
+#define HAVE_DLFCN_H 1
+
+/* Define to 1 if you have the <execinfo.h> header file. */
+#define HAVE_EXECINFO_H 1
+
+/* Define if you have the `fcntl' function */
+#define HAVE_FCNTL 1
+
+/* Define to 1 if you have the <glob.h> header file. */
+#define HAVE_GLOB_H 1
+
+/* Define to 1 if you have the <inttypes.h> header file. */
+#define HAVE_INTTYPES_H 1
+
+/* Define to 1 if you have the `pthread' library (-lpthread). */
+#define HAVE_LIBPTHREAD 1
+
+/* Define to 1 if you have the <libunwind.h> header file. */
+/* #undef HAVE_LIBUNWIND_H */
+
+/* define if you have google gflags library */
+#define HAVE_LIB_GFLAGS 1
+
+/* define if you have google gmock library */
+/* #undef HAVE_LIB_GMOCK */
+
+/* define if you have google gtest library */
+/* #undef HAVE_LIB_GTEST */
+
+/* define if you have libunwind */
+/* #undef HAVE_LIB_UNWIND */
+
+/* Define to 1 if you have the <memory.h> header file. */
+#define HAVE_MEMORY_H 1
+
+/* define if the compiler implements namespaces */
+#define HAVE_NAMESPACES 1
+
+/* Define if you have POSIX threads libraries and header files. */
+#define HAVE_PTHREAD 1
+
+/* Define to 1 if you have the <pwd.h> header file. */
+#define HAVE_PWD_H 1
+
+/* define if the compiler implements pthread_rwlock_* */
+#define HAVE_RWLOCK 1
+
+/* Define if you have the `sigaltstack' function */
+#define HAVE_SIGALTSTACK 1
+
+/* Define to 1 if you have the <stdint.h> header file. */
+#define HAVE_STDINT_H 1
+
+/* Define to 1 if you have the <stdlib.h> header file. */
+#define HAVE_STDLIB_H 1
+
+/* Define to 1 if you have the <strings.h> header file. */
+#define HAVE_STRINGS_H 1
+
+/* Define to 1 if you have the <string.h> header file. */
+#define HAVE_STRING_H 1
+
+/* Define to 1 if you have the <syscall.h> header file. */
+#define HAVE_SYSCALL_H 1
+
+/* Define to 1 if you have the <syslog.h> header file. */
+#define HAVE_SYSLOG_H 1
+
+/* Define to 1 if you have the <sys/stat.h> header file. */
+#define HAVE_SYS_STAT_H 1
+
+/* Define to 1 if you have the <sys/syscall.h> header file. */
+#define HAVE_SYS_SYSCALL_H 1
+
+/* Define to 1 if you have the <sys/time.h> header file. */
+#define HAVE_SYS_TIME_H 1
+
+/* Define to 1 if you have the <sys/types.h> header file. */
+#define HAVE_SYS_TYPES_H 1
+
+/* Define to 1 if you have the <sys/ucontext.h> header file. */
+#define HAVE_SYS_UCONTEXT_H 1
+
+/* Define to 1 if you have the <sys/utsname.h> header file. */
+#define HAVE_SYS_UTSNAME_H 1
+
+/* Define to 1 if you have the <ucontext.h> header file. */
+#define HAVE_UCONTEXT_H 1
+
+/* Define to 1 if you have the <unistd.h> header file. */
+#define HAVE_UNISTD_H 1
+
+/* define if the compiler supports using expression for operator */
+#define HAVE_USING_OPERATOR 1
+
+/* define if your compiler has __attribute__ */
+#define HAVE___ATTRIBUTE__ 1
+
+/* define if your compiler has __builtin_expect */
+#define HAVE___BUILTIN_EXPECT 1
+
+/* define if your compiler has __sync_val_compare_and_swap */
+/* #undef HAVE___SYNC_VAL_COMPARE_AND_SWAP */
+
+/* Name of package */
+#define PACKAGE "glog"
+
+/* Define to the address where bug reports for this package should be sent. */
+#define PACKAGE_BUGREPORT "opensource@google.com"
+
+/* Define to the full name of this package. */
+#define PACKAGE_NAME "glog"
+
+/* Define to the full name and version of this package. */
+#define PACKAGE_STRING "glog 0.3.1"
+
+/* Define to the one symbol short name of this package. */
+#define PACKAGE_TARNAME "glog"
+
+/* Define to the version of this package. */
+#define PACKAGE_VERSION "0.3.1"
+
+/* How to access the PC from a struct ucontext */
+#if defined(_M_X64) || defined(__amd64__)
+ #define PC_FROM_UCONTEXT uc_mcontext.gregs[REG_RIP]
+#else
+ #define PC_FROM_UCONTEXT uc_mcontext.gregs[REG_EIP]
+#endif
+
+/* Define to necessary symbol if this constant uses a non-standard name on
+ your system. */
+/* #undef PTHREAD_CREATE_JOINABLE */
+
+/* The size of `void *', as computed by sizeof. */
+#define SIZEOF_VOID_P 8
+
+/* Define to 1 if you have the ANSI C header files. */
+/* #undef STDC_HEADERS */
+
+#define STDC_HEADERS 1
+/* the namespace where STL code like vector<> is defined */
+#define STL_NAMESPACE std
+
+/* location of source code */
+#define TEST_SRC_DIR "."
+
+/* Version number of package */
+#define VERSION "0.3.1"
+
+/* Stops putting the code inside the Google namespace */
+#define _END_GOOGLE_NAMESPACE_ }
+
+/* Puts following code inside the Google namespace */
+#define _START_GOOGLE_NAMESPACE_ namespace google {
diff --git a/extern/libmv/third_party/glog/src/config_mac.h b/extern/libmv/third_party/glog/src/config_mac.h
new file mode 100644
index 00000000000..5f953d17ba9
--- /dev/null
+++ b/extern/libmv/third_party/glog/src/config_mac.h
@@ -0,0 +1,159 @@
+/* src/config.h. Generated from config.h.in by configure. */
+/* src/config.h.in. Generated from configure.ac by autoheader. */
+
+/* Namespace for Google classes */
+#define GOOGLE_NAMESPACE google
+
+/* Define if you have the `dladdr' function */
+#define HAVE_DLADDR 1
+
+/* Define to 1 if you have the <dlfcn.h> header file. */
+#define HAVE_DLFCN_H 1
+
+/* Define to 1 if you have the <execinfo.h> header file. */
+#define HAVE_EXECINFO_H 1
+
+/* Define if you have the `fcntl' function */
+#define HAVE_FCNTL 1
+
+/* Define to 1 if you have the <glob.h> header file. */
+#define HAVE_GLOB_H 1
+
+/* Define to 1 if you have the <inttypes.h> header file. */
+#define HAVE_INTTYPES_H 1
+
+/* Define to 1 if you have the `pthread' library (-lpthread). */
+#define HAVE_LIBPTHREAD 1
+
+/* Define to 1 if you have the <libunwind.h> header file. */
+#define HAVE_LIBUNWIND_H 1
+
+/* define if you have google gflags library */
+#define HAVE_LIB_GFLAGS 1
+
+/* define if you have google gmock library */
+/* #undef HAVE_LIB_GMOCK */
+
+/* define if you have google gtest library */
+//#define HAVE_LIB_GTEST 1
+
+/* define if you have libunwind */
+/* #undef HAVE_LIB_UNWIND */
+
+/* Define to 1 if you have the <memory.h> header file. */
+#define HAVE_MEMORY_H 1
+
+/* define if the compiler implements namespaces */
+#define HAVE_NAMESPACES 1
+
+/* Define if you have POSIX threads libraries and header files. */
+#define HAVE_PTHREAD 1
+
+/* Define to 1 if you have the <pwd.h> header file. */
+#define HAVE_PWD_H 1
+
+/* define if the compiler implements pthread_rwlock_* */
+#define HAVE_RWLOCK 1
+
+/* Define if you have the `sigaltstack' function */
+#define HAVE_SIGALTSTACK 1
+
+/* Define to 1 if you have the <stdint.h> header file. */
+#define HAVE_STDINT_H 1
+
+/* Define to 1 if you have the <stdlib.h> header file. */
+#define HAVE_STDLIB_H 1
+
+/* Define to 1 if you have the <strings.h> header file. */
+#define HAVE_STRINGS_H 1
+
+/* Define to 1 if you have the <string.h> header file. */
+#define HAVE_STRING_H 1
+
+/* Define to 1 if you have the <syscall.h> header file. */
+/* #undef HAVE_SYSCALL_H */
+
+/* Define to 1 if you have the <syslog.h> header file. */
+#define HAVE_SYSLOG_H 1
+
+/* Define to 1 if you have the <sys/stat.h> header file. */
+#define HAVE_SYS_STAT_H 1
+
+/* Define to 1 if you have the <sys/syscall.h> header file. */
+#define HAVE_SYS_SYSCALL_H 1
+
+/* Define to 1 if you have the <sys/time.h> header file. */
+#define HAVE_SYS_TIME_H 1
+
+/* Define to 1 if you have the <sys/types.h> header file. */
+#define HAVE_SYS_TYPES_H 1
+
+/* Define to 1 if you have the <sys/ucontext.h> header file. */
+#define HAVE_SYS_UCONTEXT_H 1
+
+/* Define to 1 if you have the <sys/utsname.h> header file. */
+#define HAVE_SYS_UTSNAME_H 1
+
+/* Define to 1 if you have the <ucontext.h> header file. */
+/* #undef HAVE_UCONTEXT_H */
+
+/* Define to 1 if you have the <unistd.h> header file. */
+#define HAVE_UNISTD_H 1
+
+/* define if the compiler supports using expression for operator */
+#define HAVE_USING_OPERATOR 1
+
+/* define if your compiler has __attribute__ */
+#define HAVE___ATTRIBUTE__ 1
+
+/* define if your compiler has __builtin_expect */
+#define HAVE___BUILTIN_EXPECT 1
+
+/* define if your compiler has __sync_val_compare_and_swap */
+/* #undef HAVE___SYNC_VAL_COMPARE_AND_SWAP */
+
+/* Name of package */
+#define PACKAGE "glog"
+
+/* Define to the address where bug reports for this package should be sent. */
+#define PACKAGE_BUGREPORT "opensource@google.com"
+
+/* Define to the full name of this package. */
+#define PACKAGE_NAME "glog"
+
+/* Define to the full name and version of this package. */
+#define PACKAGE_STRING "glog 0.3.1"
+
+/* Define to the one symbol short name of this package. */
+#define PACKAGE_TARNAME "glog"
+
+/* Define to the version of this package. */
+#define PACKAGE_VERSION "0.3.1"
+
+/* How to access the PC from a struct ucontext */
+#undef PC_FROM_UCONTEXT
+
+/* Define to necessary symbol if this constant uses a non-standard name on
+ your system. */
+/* #undef PTHREAD_CREATE_JOINABLE */
+
+/* The size of `void *', as computed by sizeof. */
+#define SIZEOF_VOID_P 8
+
+/* Define to 1 if you have the ANSI C header files. */
+/* #undef STDC_HEADERS */
+
+/* the namespace where STL code like vector<> is defined */
+#define STL_NAMESPACE std
+
+/* location of source code */
+#define TEST_SRC_DIR "."
+
+/* Version number of package */
+#define VERSION "0.3.1"
+
+/* Stops putting the code inside the Google namespace */
+#define _END_GOOGLE_NAMESPACE_ }
+
+/* Puts following code inside the Google namespace */
+#define _START_GOOGLE_NAMESPACE_ namespace google {
diff --git a/extern/libmv/third_party/glog/src/demangle.cc b/extern/libmv/third_party/glog/src/demangle.cc
new file mode 100644
index 00000000000..46556bf3c13
--- /dev/null
+++ b/extern/libmv/third_party/glog/src/demangle.cc
@@ -0,0 +1,1231 @@
+// Copyright (c) 2006, Google Inc.
+// 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.
+//
+// Author: Satoru Takabayashi
+
+#include <stdio.h> // for NULL
+#include "demangle.h"
+
+_START_GOOGLE_NAMESPACE_
+
+typedef struct {
+ const char *abbrev;
+ const char *real_name;
+} AbbrevPair;
+
+// List of operators from Itanium C++ ABI.
+static const AbbrevPair kOperatorList[] = {
+ { "nw", "new" },
+ { "na", "new[]" },
+ { "dl", "delete" },
+ { "da", "delete[]" },
+ { "ps", "+" },
+ { "ng", "-" },
+ { "ad", "&" },
+ { "de", "*" },
+ { "co", "~" },
+ { "pl", "+" },
+ { "mi", "-" },
+ { "ml", "*" },
+ { "dv", "/" },
+ { "rm", "%" },
+ { "an", "&" },
+ { "or", "|" },
+ { "eo", "^" },
+ { "aS", "=" },
+ { "pL", "+=" },
+ { "mI", "-=" },
+ { "mL", "*=" },
+ { "dV", "/=" },
+ { "rM", "%=" },
+ { "aN", "&=" },
+ { "oR", "|=" },
+ { "eO", "^=" },
+ { "ls", "<<" },
+ { "rs", ">>" },
+ { "lS", "<<=" },
+ { "rS", ">>=" },
+ { "eq", "==" },
+ { "ne", "!=" },
+ { "lt", "<" },
+ { "gt", ">" },
+ { "le", "<=" },
+ { "ge", ">=" },
+ { "nt", "!" },
+ { "aa", "&&" },
+ { "oo", "||" },
+ { "pp", "++" },
+ { "mm", "--" },
+ { "cm", "," },
+ { "pm", "->*" },
+ { "pt", "->" },
+ { "cl", "()" },
+ { "ix", "[]" },
+ { "qu", "?" },
+ { "st", "sizeof" },
+ { "sz", "sizeof" },
+ { NULL, NULL },
+};
+
+// List of builtin types from Itanium C++ ABI.
+static const AbbrevPair kBuiltinTypeList[] = {
+ { "v", "void" },
+ { "w", "wchar_t" },
+ { "b", "bool" },
+ { "c", "char" },
+ { "a", "signed char" },
+ { "h", "unsigned char" },
+ { "s", "short" },
+ { "t", "unsigned short" },
+ { "i", "int" },
+ { "j", "unsigned int" },
+ { "l", "long" },
+ { "m", "unsigned long" },
+ { "x", "long long" },
+ { "y", "unsigned long long" },
+ { "n", "__int128" },
+ { "o", "unsigned __int128" },
+ { "f", "float" },
+ { "d", "double" },
+ { "e", "long double" },
+ { "g", "__float128" },
+ { "z", "ellipsis" },
+ { NULL, NULL }
+};
+
+// List of substitutions Itanium C++ ABI.
+static const AbbrevPair kSubstitutionList[] = {
+ { "St", "" },
+ { "Sa", "allocator" },
+ { "Sb", "basic_string" },
+ // std::basic_string<char, std::char_traits<char>,std::allocator<char> >
+ { "Ss", "string"},
+ // std::basic_istream<char, std::char_traits<char> >
+ { "Si", "istream" },
+ // std::basic_ostream<char, std::char_traits<char> >
+ { "So", "ostream" },
+ // std::basic_iostream<char, std::char_traits<char> >
+ { "Sd", "iostream" },
+ { NULL, NULL }
+};
+
+// State needed for demangling.
+typedef struct {
+ const char *mangled_cur; // Cursor of mangled name.
+ const char *mangled_end; // End of mangled name.
+ char *out_cur; // Cursor of output string.
+ const char *out_begin; // Beginning of output string.
+ const char *out_end; // End of output string.
+ const char *prev_name; // For constructors/destructors.
+ int prev_name_length; // For constructors/destructors.
+ int nest_level; // For nested names.
+ int number; // Remember the previous number.
+ bool append; // Append flag.
+ bool overflowed; // True if output gets overflowed.
+} State;
+
+// We don't use strlen() in libc since it's not guaranteed to be async
+// signal safe.
+static size_t StrLen(const char *str) {
+ size_t len = 0;
+ while (*str != '\0') {
+ ++str;
+ ++len;
+ }
+ return len;
+}
+
+// Returns true if "str" has "prefix" as a prefix.
+static bool StrPrefix(const char *str, const char *prefix) {
+ size_t i = 0;
+ while (str[i] != '\0' && prefix[i] != '\0' &&
+ str[i] == prefix[i]) {
+ ++i;
+ }
+ return prefix[i] == '\0'; // Consumed everything in "prefix".
+}
+
+static void InitState(State *state, const char *mangled,
+ char *out, int out_size) {
+ state->mangled_cur = mangled;
+ state->mangled_end = mangled + StrLen(mangled);
+ state->out_cur = out;
+ state->out_begin = out;
+ state->out_end = out + out_size;
+ state->prev_name = NULL;
+ state->prev_name_length = -1;
+ state->nest_level = -1;
+ state->number = -1;
+ state->append = true;
+ state->overflowed = false;
+}
+
+// Calculates the remaining length of the mangled name.
+static int RemainingLength(State *state) {
+ return state->mangled_end - state->mangled_cur;
+}
+
+// Returns true and advances "mangled_cur" if we find "c" at
+// "mangled_cur" position.
+static bool ParseChar(State *state, const char c) {
+ if (RemainingLength(state) >= 1 && *state->mangled_cur == c) {
+ ++state->mangled_cur;
+ return true;
+ }
+ return false;
+}
+
+// Returns true and advances "mangled_cur" if we find "two_chars" at
+// "mangled_cur" position.
+static bool ParseTwoChar(State *state, const char *two_chars) {
+ if (RemainingLength(state) >= 2 &&
+ state->mangled_cur[0] == two_chars[0] &&
+ state->mangled_cur[1] == two_chars[1]) {
+ state->mangled_cur += 2;
+ return true;
+ }
+ return false;
+}
+
+// Returns true and advances "mangled_cur" if we find any character in
+// "char_class" at "mangled_cur" position.
+static bool ParseCharClass(State *state, const char *char_class) {
+ if (state->mangled_cur == state->mangled_end) {
+ return false;
+ }
+ const char *p = char_class;
+ for (; *p != '\0'; ++p) {
+ if (*state->mangled_cur == *p) {
+ state->mangled_cur += 1;
+ return true;
+ }
+ }
+ return false;
+}
+
+// This function is used for handling an optional non-terminal.
+static bool Optional(bool status) {
+ return true;
+}
+
+// This function is used for handling <non-terminal>+ syntax.
+typedef bool (*ParseFunc)(State *);
+static bool OneOrMore(ParseFunc parse_func, State *state) {
+ if (parse_func(state)) {
+ while (parse_func(state)) {
+ }
+ return true;
+ }
+ return false;
+}
+
+// Append "str" at "out_cur". If there is an overflow, "overflowed"
+// is set to true for later use. The output string is ensured to
+// always terminate with '\0' as long as there is no overflow.
+static void Append(State *state, const char * const str, const int length) {
+ int i;
+ for (i = 0; i < length; ++i) {
+ if (state->out_cur + 1 < state->out_end) { // +1 for '\0'
+ *state->out_cur = str[i];
+ ++state->out_cur;
+ } else {
+ state->overflowed = true;
+ break;
+ }
+ }
+ if (!state->overflowed) {
+ *state->out_cur = '\0'; // Terminate it with '\0'
+ }
+}
+
+// We don't use equivalents in libc to avoid locale issues.
+static bool IsLower(char c) {
+ return c >= 'a' && c <= 'z';
+}
+
+static bool IsAlpha(char c) {
+ return ((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z'));
+}
+
+// Append "str" with some tweaks, iff "append" state is true.
+// Returns true so that it can be placed in "if" conditions.
+static void MaybeAppendWithLength(State *state, const char * const str,
+ const int length) {
+ if (state->append && length > 0) {
+ // Append a space if the output buffer ends with '<' and "str"
+ // starts with '<' to avoid <<<.
+ if (str[0] == '<' && state->out_begin < state->out_cur &&
+ state->out_cur[-1] == '<') {
+ Append(state, " ", 1);
+ }
+ // Remember the last identifier name for ctors/dtors.
+ if (IsAlpha(str[0]) || str[0] == '_') {
+ state->prev_name = state->out_cur;
+ state->prev_name_length = length;
+ }
+ Append(state, str, length);
+ }
+}
+
+// A convenient wrapper arount MaybeAppendWithLength().
+static bool MaybeAppend(State *state, const char * const str) {
+ if (state->append) {
+ int length = StrLen(str);
+ MaybeAppendWithLength(state, str, length);
+ }
+ return true;
+}
+
+// This function is used for handling nested names.
+static bool EnterNestedName(State *state) {
+ state->nest_level = 0;
+ return true;
+}
+
+// This function is used for handling nested names.
+static bool LeaveNestedName(State *state, int prev_value) {
+ state->nest_level = prev_value;
+ return true;
+}
+
+// Disable the append mode not to print function parameters, etc.
+static bool DisableAppend(State *state) {
+ state->append = false;
+ return true;
+}
+
+// Restore the append mode to the previous state.
+static bool RestoreAppend(State *state, bool prev_value) {
+ state->append = prev_value;
+ return true;
+}
+
+// Increase the nest level for nested names.
+static void MaybeIncreaseNestLevel(State *state) {
+ if (state->nest_level > -1) {
+ ++state->nest_level;
+ }
+}
+
+// Appends :: for nested names if necessary.
+static void MaybeAppendSeparator(State *state) {
+ if (state->nest_level >= 1) {
+ MaybeAppend(state, "::");
+ }
+}
+
+// Cancel the last separator if necessary.
+static void MaybeCancelLastSeparator(State *state) {
+ if (state->nest_level >= 1 && state->append &&
+ state->out_begin <= state->out_cur - 2) {
+ state->out_cur -= 2;
+ *state->out_cur = '\0';
+ }
+}
+
+// Returns true if identifier pointed by "mangled_cur" is anonymous
+// namespace.
+static bool IdentifierIsAnonymousNamespace(State *state) {
+ const char anon_prefix[] = "_GLOBAL__N_";
+ return (state->number > sizeof(anon_prefix) - 1 && // Should be longer.
+ StrPrefix(state->mangled_cur, anon_prefix));
+}
+
+// Forward declarations of our parsing functions.
+static bool ParseMangledName(State *state);
+static bool ParseEncoding(State *state);
+static bool ParseName(State *state);
+static bool ParseUnscopedName(State *state);
+static bool ParseUnscopedTemplateName(State *state);
+static bool ParseNestedName(State *state);
+static bool ParsePrefix(State *state);
+static bool ParseUnqualifiedName(State *state);
+static bool ParseSourceName(State *state);
+static bool ParseLocalSourceName(State *state);
+static bool ParseNumber(State *state);
+static bool ParseFloatNumber(State *state);
+static bool ParseSeqId(State *state);
+static bool ParseIdentifier(State *state);
+static bool ParseOperatorName(State *state);
+static bool ParseSpecialName(State *state);
+static bool ParseCallOffset(State *state);
+static bool ParseNVOffset(State *state);
+static bool ParseVOffset(State *state);
+static bool ParseCtorDtorName(State *state);
+static bool ParseType(State *state);
+static bool ParseCVQualifiers(State *state);
+static bool ParseBuiltinType(State *state);
+static bool ParseFunctionType(State *state);
+static bool ParseBareFunctionType(State *state);
+static bool ParseClassEnumType(State *state);
+static bool ParseArrayType(State *state);
+static bool ParsePointerToMemberType(State *state);
+static bool ParseTemplateParam(State *state);
+static bool ParseTemplateTemplateParam(State *state);
+static bool ParseTemplateArgs(State *state);
+static bool ParseTemplateArg(State *state);
+static bool ParseExpression(State *state);
+static bool ParseExprPrimary(State *state);
+static bool ParseLocalName(State *state);
+static bool ParseDiscriminator(State *state);
+static bool ParseSubstitution(State *state);
+
+// Implementation note: the following code is a straightforward
+// translation of the Itanium C++ ABI defined in BNF with a couple of
+// exceptions.
+//
+// - Support GNU extensions not defined in the Itanium C++ ABI
+// - <prefix> and <template-prefix> are combined to avoid infinite loop
+// - Reorder patterns to shorten the code
+// - Reorder patterns to give greedier functions precedence
+// We'll mark "Less greedy than" for these cases in the code
+//
+// Each parsing function changes the state and returns true on
+// success. Otherwise, don't change the state and returns false. To
+// ensure that the state isn't changed in the latter case, we save the
+// original state before we call more than one parsing functions
+// consecutively with &&, and restore the state if unsuccessful. See
+// ParseEncoding() as an example of this convention. We follow the
+// convention throughout the code.
+//
+// Originally we tried to do demangling without following the full ABI
+// syntax but it turned out we needed to follow the full syntax to
+// parse complicated cases like nested template arguments. Note that
+// implementing a full-fledged demangler isn't trivial (libiberty's
+// cp-demangle.c has +4300 lines).
+//
+// Note that (foo) in <(foo) ...> is a modifier to be ignored.
+//
+// Reference:
+// - Itanium C++ ABI
+// <http://www.codesourcery.com/cxx-abi/abi.html#mangling>
+
+// <mangled-name> ::= _Z <encoding>
+static bool ParseMangledName(State *state) {
+ if (ParseTwoChar(state, "_Z") && ParseEncoding(state)) {
+ // Append trailing version suffix if any.
+ // ex. _Z3foo@@GLIBCXX_3.4
+ if (state->mangled_cur < state->mangled_end &&
+ state->mangled_cur[0] == '@') {
+ MaybeAppend(state, state->mangled_cur);
+ state->mangled_cur = state->mangled_end;
+ }
+ return true;
+ }
+ return false;
+}
+
+// <encoding> ::= <(function) name> <bare-function-type>
+// ::= <(data) name>
+// ::= <special-name>
+static bool ParseEncoding(State *state) {
+ State copy = *state;
+ if (ParseName(state) && ParseBareFunctionType(state)) {
+ return true;
+ }
+ *state = copy;
+
+ if (ParseName(state) || ParseSpecialName(state)) {
+ return true;
+ }
+ return false;
+}
+
+// <name> ::= <nested-name>
+// ::= <unscoped-template-name> <template-args>
+// ::= <unscoped-name>
+// ::= <local-name>
+static bool ParseName(State *state) {
+ if (ParseNestedName(state) || ParseLocalName(state)) {
+ return true;
+ }
+
+ State copy = *state;
+ if (ParseUnscopedTemplateName(state) &&
+ ParseTemplateArgs(state)) {
+ return true;
+ }
+ *state = copy;
+
+ // Less greedy than <unscoped-template-name> <template-args>.
+ if (ParseUnscopedName(state)) {
+ return true;
+ }
+ return false;
+}
+
+// <unscoped-name> ::= <unqualified-name>
+// ::= St <unqualified-name>
+static bool ParseUnscopedName(State *state) {
+ if (ParseUnqualifiedName(state)) {
+ return true;
+ }
+
+ State copy = *state;
+ if (ParseTwoChar(state, "St") &&
+ MaybeAppend(state, "std::") &&
+ ParseUnqualifiedName(state)) {
+ return true;
+ }
+ *state = copy;
+ return false;
+}
+
+// <unscoped-template-name> ::= <unscoped-name>
+// ::= <substitution>
+static bool ParseUnscopedTemplateName(State *state) {
+ return ParseUnscopedName(state) || ParseSubstitution(state);
+}
+
+// <nested-name> ::= N [<CV-qualifiers>] <prefix> <unqualified-name> E
+// ::= N [<CV-qualifiers>] <template-prefix> <template-args> E
+static bool ParseNestedName(State *state) {
+ State copy = *state;
+ if (ParseChar(state, 'N') &&
+ EnterNestedName(state) &&
+ Optional(ParseCVQualifiers(state)) &&
+ ParsePrefix(state) &&
+ LeaveNestedName(state, copy.nest_level) &&
+ ParseChar(state, 'E')) {
+ return true;
+ }
+ *state = copy;
+ return false;
+}
+
+// This part is tricky. If we literally translate them to code, we'll
+// end up infinite loop. Hence we merge them to avoid the case.
+//
+// <prefix> ::= <prefix> <unqualified-name>
+// ::= <template-prefix> <template-args>
+// ::= <template-param>
+// ::= <substitution>
+// ::= # empty
+// <template-prefix> ::= <prefix> <(template) unqualified-name>
+// ::= <template-param>
+// ::= <substitution>
+static bool ParsePrefix(State *state) {
+ bool has_something = false;
+ while (true) {
+ MaybeAppendSeparator(state);
+ if (ParseTemplateParam(state) ||
+ ParseSubstitution(state) ||
+ ParseUnscopedName(state)) {
+ has_something = true;
+ MaybeIncreaseNestLevel(state);
+ continue;
+ }
+ MaybeCancelLastSeparator(state);
+ if (has_something && ParseTemplateArgs(state)) {
+ return ParsePrefix(state);
+ } else {
+ break;
+ }
+ }
+ return true;
+}
+
+// <unqualified-name> ::= <operator-name>
+// ::= <ctor-dtor-name>
+// ::= <source-name>
+// ::= <local-source-name>
+static bool ParseUnqualifiedName(State *state) {
+ return (ParseOperatorName(state) ||
+ ParseCtorDtorName(state) ||
+ ParseSourceName(state) ||
+ ParseLocalSourceName(state));
+}
+
+// <source-name> ::= <positive length number> <identifier>
+static bool ParseSourceName(State *state) {
+ State copy = *state;
+ if (ParseNumber(state) && ParseIdentifier(state)) {
+ return true;
+ }
+ *state = copy;
+ return false;
+}
+
+// <local-source-name> ::= L <source-name> [<discriminator>]
+//
+// References:
+// http://gcc.gnu.org/bugzilla/show_bug.cgi?id=31775
+// http://gcc.gnu.org/viewcvs?view=rev&revision=124467
+static bool ParseLocalSourceName(State *state) {
+ State copy = *state;
+ if (ParseChar(state, 'L') && ParseSourceName(state) &&
+ Optional(ParseDiscriminator(state))) {
+ return true;
+ }
+ *state = copy;
+ return false;
+}
+
+// <number> ::= [n] <non-negative decimal integer>
+static bool ParseNumber(State *state) {
+ int sign = 1;
+ if (ParseChar(state, 'n')) {
+ sign = -1;
+ }
+ const char *p = state->mangled_cur;
+ int number = 0;
+ for (;p < state->mangled_end; ++p) {
+ if ((*p >= '0' && *p <= '9')) {
+ number = number * 10 + (*p - '0');
+ } else {
+ break;
+ }
+ }
+ if (p != state->mangled_cur) { // Conversion succeeded.
+ state->mangled_cur = p;
+ state->number = number * sign;
+ return true;
+ }
+ return false;
+}
+
+// Floating-point literals are encoded using a fixed-length lowercase
+// hexadecimal string.
+static bool ParseFloatNumber(State *state) {
+ const char *p = state->mangled_cur;
+ int number = 0;
+ for (;p < state->mangled_end; ++p) {
+ if ((*p >= '0' && *p <= '9')) {
+ number = number * 16 + (*p - '0');
+ } else if (*p >= 'a' && *p <= 'f') {
+ number = number * 16 + (*p - 'a' + 10);
+ } else {
+ break;
+ }
+ }
+ if (p != state->mangled_cur) { // Conversion succeeded.
+ state->mangled_cur = p;
+ state->number = number;
+ return true;
+ }
+ return false;
+}
+
+// The <seq-id> is a sequence number in base 36,
+// using digits and upper case letters
+static bool ParseSeqId(State *state) {
+ const char *p = state->mangled_cur;
+ int number = 0;
+ for (;p < state->mangled_end; ++p) {
+ if ((*p >= '0' && *p <= '9')) {
+ number = number * 36 + (*p - '0');
+ } else if (*p >= 'A' && *p <= 'Z') {
+ number = number * 36 + (*p - 'A' + 10);
+ } else {
+ break;
+ }
+ }
+ if (p != state->mangled_cur) { // Conversion succeeded.
+ state->mangled_cur = p;
+ state->number = number;
+ return true;
+ }
+ return false;
+}
+
+// <identifier> ::= <unqualified source code identifier>
+static bool ParseIdentifier(State *state) {
+ if (state->number == -1 ||
+ RemainingLength(state) < state->number) {
+ return false;
+ }
+ if (IdentifierIsAnonymousNamespace(state)) {
+ MaybeAppend(state, "(anonymous namespace)");
+ } else {
+ MaybeAppendWithLength(state, state->mangled_cur, state->number);
+ }
+ state->mangled_cur += state->number;
+ state->number = -1; // Reset the number.
+ return true;
+}
+
+// <operator-name> ::= nw, and other two letters cases
+// ::= cv <type> # (cast)
+// ::= v <digit> <source-name> # vendor extended operator
+static bool ParseOperatorName(State *state) {
+ if (RemainingLength(state) < 2) {
+ return false;
+ }
+ // First check with "cv" (cast) case.
+ State copy = *state;
+ if (ParseTwoChar(state, "cv") &&
+ MaybeAppend(state, "operator ") &&
+ EnterNestedName(state) &&
+ ParseType(state) &&
+ LeaveNestedName(state, copy.nest_level)) {
+ return true;
+ }
+ *state = copy;
+
+ // Then vendor extended operators.
+ if (ParseChar(state, 'v') && ParseCharClass(state, "0123456789") &&
+ ParseSourceName(state)) {
+ return true;
+ }
+ *state = copy;
+
+ // Other operator names should start with a lower alphabet followed
+ // by a lower/upper alphabet.
+ if (!(IsLower(state->mangled_cur[0]) &&
+ IsAlpha(state->mangled_cur[1]))) {
+ return false;
+ }
+ // We may want to perform a binary search if we really need speed.
+ const AbbrevPair *p;
+ for (p = kOperatorList; p->abbrev != NULL; ++p) {
+ if (state->mangled_cur[0] == p->abbrev[0] &&
+ state->mangled_cur[1] == p->abbrev[1]) {
+ MaybeAppend(state, "operator");
+ if (IsLower(*p->real_name)) { // new, delete, etc.
+ MaybeAppend(state, " ");
+ }
+ MaybeAppend(state, p->real_name);
+ state->mangled_cur += 2;
+ return true;
+ }
+ }
+ return false;
+}
+
+// <special-name> ::= TV <type>
+// ::= TT <type>
+// ::= TI <type>
+// ::= TS <type>
+// ::= Tc <call-offset> <call-offset> <(base) encoding>
+// ::= GV <(object) name>
+// ::= T <call-offset> <(base) encoding>
+// G++ extensions:
+// ::= TC <type> <(offset) number> _ <(base) type>
+// ::= TF <type>
+// ::= TJ <type>
+// ::= GR <name>
+// ::= GA <encoding>
+// ::= Th <call-offset> <(base) encoding>
+// ::= Tv <call-offset> <(base) encoding>
+//
+// Note: we don't care much about them since they don't appear in
+// stack traces. The are special data.
+static bool ParseSpecialName(State *state) {
+ State copy = *state;
+ if (ParseChar(state, 'T') &&
+ ParseCharClass(state, "VTIS") &&
+ ParseType(state)) {
+ return true;
+ }
+ *state = copy;
+
+ if (ParseTwoChar(state, "Tc") && ParseCallOffset(state) &&
+ ParseCallOffset(state) && ParseEncoding(state)) {
+ return true;
+ }
+ *state = copy;
+
+ if (ParseTwoChar(state, "GV") &&
+ ParseName(state)) {
+ return true;
+ }
+ *state = copy;
+
+ if (ParseChar(state, 'T') && ParseCallOffset(state) &&
+ ParseEncoding(state)) {
+ return true;
+ }
+ *state = copy;
+
+ // G++ extensions
+ if (ParseTwoChar(state, "TC") && ParseType(state) &&
+ ParseNumber(state) && ParseChar(state, '_') &&
+ DisableAppend(state) &&
+ ParseType(state)) {
+ RestoreAppend(state, copy.append);
+ return true;
+ }
+ *state = copy;
+
+ if (ParseChar(state, 'T') && ParseCharClass(state, "FJ") &&
+ ParseType(state)) {
+ return true;
+ }
+ *state = copy;
+
+ if (ParseTwoChar(state, "GR") && ParseName(state)) {
+ return true;
+ }
+ *state = copy;
+
+ if (ParseTwoChar(state, "GA") && ParseEncoding(state)) {
+ return true;
+ }
+ *state = copy;
+
+ if (ParseChar(state, 'T') && ParseCharClass(state, "hv") &&
+ ParseCallOffset(state) && ParseEncoding(state)) {
+ return true;
+ }
+ *state = copy;
+ return false;
+}
+
+// <call-offset> ::= h <nv-offset> _
+// ::= v <v-offset> _
+static bool ParseCallOffset(State *state) {
+ State copy = *state;
+ if (ParseChar(state, 'h') &&
+ ParseNVOffset(state) && ParseChar(state, '_')) {
+ return true;
+ }
+ *state = copy;
+
+ if (ParseChar(state, 'v') &&
+ ParseVOffset(state) && ParseChar(state, '_')) {
+ return true;
+ }
+ *state = copy;
+
+ return false;
+}
+
+// <nv-offset> ::= <(offset) number>
+static bool ParseNVOffset(State *state) {
+ return ParseNumber(state);
+}
+
+// <v-offset> ::= <(offset) number> _ <(virtual offset) number>
+static bool ParseVOffset(State *state) {
+ State copy = *state;
+ if (ParseNumber(state) && ParseChar(state, '_') &&
+ ParseNumber(state)) {
+ return true;
+ }
+ *state = copy;
+ return false;
+}
+
+// <ctor-dtor-name> ::= C1 | C2 | C3
+// ::= D0 | D1 | D2
+static bool ParseCtorDtorName(State *state) {
+ State copy = *state;
+ if (ParseChar(state, 'C') &&
+ ParseCharClass(state, "123")) {
+ const char * const prev_name = state->prev_name;
+ const int prev_name_length = state->prev_name_length;
+ MaybeAppendWithLength(state, prev_name, prev_name_length);
+ return true;
+ }
+ *state = copy;
+
+ if (ParseChar(state, 'D') &&
+ ParseCharClass(state, "012")) {
+ const char * const prev_name = state->prev_name;
+ const int prev_name_length = state->prev_name_length;
+ MaybeAppend(state, "~");
+ MaybeAppendWithLength(state, prev_name, prev_name_length);
+ return true;
+ }
+ *state = copy;
+ return false;
+}
+
+// <type> ::= <CV-qualifiers> <type>
+// ::= P <type>
+// ::= R <type>
+// ::= C <type>
+// ::= G <type>
+// ::= U <source-name> <type>
+// ::= <builtin-type>
+// ::= <function-type>
+// ::= <class-enum-type>
+// ::= <array-type>
+// ::= <pointer-to-member-type>
+// ::= <template-template-param> <template-args>
+// ::= <template-param>
+// ::= <substitution>
+static bool ParseType(State *state) {
+ // We should check CV-qualifers, and PRGC things first.
+ State copy = *state;
+ if (ParseCVQualifiers(state) && ParseType(state)) {
+ return true;
+ }
+ *state = copy;
+
+ if (ParseCharClass(state, "PRCG") && ParseType(state)) {
+ return true;
+ }
+ *state = copy;
+
+ if (ParseChar(state, 'U') && ParseSourceName(state) &&
+ ParseType(state)) {
+ return true;
+ }
+ *state = copy;
+
+ if (ParseBuiltinType(state) ||
+ ParseFunctionType(state) ||
+ ParseClassEnumType(state) ||
+ ParseArrayType(state) ||
+ ParsePointerToMemberType(state) ||
+ ParseSubstitution(state)) {
+ return true;
+ }
+
+ if (ParseTemplateTemplateParam(state) &&
+ ParseTemplateArgs(state)) {
+ return true;
+ }
+ *state = copy;
+
+ // Less greedy than <template-template-param> <template-args>.
+ if (ParseTemplateParam(state)) {
+ return true;
+ }
+
+ return false;
+}
+
+// <CV-qualifiers> ::= [r] [V] [K]
+// We don't allow empty <CV-qualifiers> to avoid infinite loop in
+// ParseType().
+static bool ParseCVQualifiers(State *state) {
+ int num_cv_qualifiers = 0;
+ num_cv_qualifiers += ParseChar(state, 'r');
+ num_cv_qualifiers += ParseChar(state, 'V');
+ num_cv_qualifiers += ParseChar(state, 'K');
+ return num_cv_qualifiers > 0;
+}
+
+// <builtin-type> ::= v, etc.
+// ::= u <source-name>
+static bool ParseBuiltinType(State *state) {
+ const AbbrevPair *p;
+ for (p = kBuiltinTypeList; p->abbrev != NULL; ++p) {
+ if (state->mangled_cur[0] == p->abbrev[0]) {
+ MaybeAppend(state, p->real_name);
+ ++state->mangled_cur;
+ return true;
+ }
+ }
+
+ State copy = *state;
+ if (ParseChar(state, 'u') && ParseSourceName(state)) {
+ return true;
+ }
+ *state = copy;
+ return false;
+}
+
+// <function-type> ::= F [Y] <bare-function-type> E
+static bool ParseFunctionType(State *state) {
+ State copy = *state;
+ if (ParseChar(state, 'F') && Optional(ParseChar(state, 'Y')) &&
+ ParseBareFunctionType(state) && ParseChar(state, 'E')) {
+ return true;
+ }
+ *state = copy;
+ return false;
+}
+
+// <bare-function-type> ::= <(signature) type>+
+static bool ParseBareFunctionType(State *state) {
+ State copy = *state;
+ DisableAppend(state);
+ if (OneOrMore(ParseType, state)) {
+ RestoreAppend(state, copy.append);
+ MaybeAppend(state, "()");
+ return true;
+ }
+ *state = copy;
+ return false;
+}
+
+// <class-enum-type> ::= <name>
+static bool ParseClassEnumType(State *state) {
+ return ParseName(state);
+}
+
+// <array-type> ::= A <(positive dimension) number> _ <(element) type>
+// ::= A [<(dimension) expression>] _ <(element) type>
+static bool ParseArrayType(State *state) {
+ State copy = *state;
+ if (ParseChar(state, 'A') && ParseNumber(state) &&
+ ParseChar(state, '_') && ParseType(state)) {
+ return true;
+ }
+ *state = copy;
+
+ if (ParseChar(state, 'A') && Optional(ParseExpression(state)) &&
+ ParseChar(state, '_') && ParseType(state)) {
+ return true;
+ }
+ *state = copy;
+ return false;
+}
+
+// <pointer-to-member-type> ::= M <(class) type> <(member) type>
+static bool ParsePointerToMemberType(State *state) {
+ State copy = *state;
+ if (ParseChar(state, 'M') && ParseType(state) &&
+ ParseType(state)) {
+ return true;
+ }
+ *state = copy;
+ return false;
+}
+
+// <template-param> ::= T_
+// ::= T <parameter-2 non-negative number> _
+static bool ParseTemplateParam(State *state) {
+ if (ParseTwoChar(state, "T_")) {
+ MaybeAppend(state, "?"); // We don't support template substitutions.
+ return true;
+ }
+
+ State copy = *state;
+ if (ParseChar(state, 'T') && ParseNumber(state) &&
+ ParseChar(state, '_')) {
+ MaybeAppend(state, "?"); // We don't support template substitutions.
+ return true;
+ }
+ *state = copy;
+ return false;
+}
+
+
+// <template-template-param> ::= <template-param>
+// ::= <substitution>
+static bool ParseTemplateTemplateParam(State *state) {
+ return (ParseTemplateParam(state) ||
+ ParseSubstitution(state));
+}
+
+// <template-args> ::= I <template-arg>+ E
+static bool ParseTemplateArgs(State *state) {
+ State copy = *state;
+ DisableAppend(state);
+ if (ParseChar(state, 'I') &&
+ OneOrMore(ParseTemplateArg, state) &&
+ ParseChar(state, 'E')) {
+ RestoreAppend(state, copy.append);
+ MaybeAppend(state, "<>");
+ return true;
+ }
+ *state = copy;
+ return false;
+}
+
+// <template-arg> ::= <type>
+// ::= <expr-primary>
+// ::= X <expression> E
+static bool ParseTemplateArg(State *state) {
+ if (ParseType(state) ||
+ ParseExprPrimary(state)) {
+ return true;
+ }
+
+ State copy = *state;
+ if (ParseChar(state, 'X') && ParseExpression(state) &&
+ ParseChar(state, 'E')) {
+ return true;
+ }
+ *state = copy;
+ return false;
+}
+
+// <expression> ::= <template-param>
+// ::= <expr-primary>
+// ::= <unary operator-name> <expression>
+// ::= <binary operator-name> <expression> <expression>
+// ::= <trinary operator-name> <expression> <expression>
+// <expression>
+// ::= st <type>
+// ::= sr <type> <unqualified-name> <template-args>
+// ::= sr <type> <unqualified-name>
+static bool ParseExpression(State *state) {
+ if (ParseTemplateParam(state) || ParseExprPrimary(state)) {
+ return true;
+ }
+
+ State copy = *state;
+ if (ParseOperatorName(state) &&
+ ParseExpression(state) &&
+ ParseExpression(state) &&
+ ParseExpression(state)) {
+ return true;
+ }
+ *state = copy;
+
+ if (ParseOperatorName(state) &&
+ ParseExpression(state) &&
+ ParseExpression(state)) {
+ return true;
+ }
+ *state = copy;
+
+ if (ParseOperatorName(state) &&
+ ParseExpression(state)) {
+ return true;
+ }
+ *state = copy;
+
+ if (ParseTwoChar(state, "st") && ParseType(state)) {
+ return true;
+ }
+ *state = copy;
+
+ if (ParseTwoChar(state, "sr") && ParseType(state) &&
+ ParseUnqualifiedName(state) &&
+ ParseTemplateArgs(state)) {
+ return true;
+ }
+ *state = copy;
+
+ if (ParseTwoChar(state, "sr") && ParseType(state) &&
+ ParseUnqualifiedName(state)) {
+ return true;
+ }
+ *state = copy;
+ return false;
+}
+
+// <expr-primary> ::= L <type> <(value) number> E
+// ::= L <type> <(value) float> E
+// ::= L <mangled-name> E
+// // A bug in g++'s C++ ABI version 2 (-fabi-version=2).
+// ::= LZ <encoding> E
+static bool ParseExprPrimary(State *state) {
+ State copy = *state;
+ if (ParseChar(state, 'L') && ParseType(state) &&
+ ParseNumber(state) &&
+ ParseChar(state, 'E')) {
+ return true;
+ }
+ *state = copy;
+
+ if (ParseChar(state, 'L') && ParseType(state) &&
+ ParseFloatNumber(state) &&
+ ParseChar(state, 'E')) {
+ return true;
+ }
+ *state = copy;
+
+ if (ParseChar(state, 'L') && ParseMangledName(state) &&
+ ParseChar(state, 'E')) {
+ return true;
+ }
+ *state = copy;
+
+ if (ParseTwoChar(state, "LZ") && ParseEncoding(state) &&
+ ParseChar(state, 'E')) {
+ return true;
+ }
+ *state = copy;
+
+ return false;
+}
+
+// <local-name> := Z <(function) encoding> E <(entity) name>
+// [<discriminator>]
+// := Z <(function) encoding> E s [<discriminator>]
+static bool ParseLocalName(State *state) {
+ State copy = *state;
+ if (ParseChar(state, 'Z') && ParseEncoding(state) &&
+ ParseChar(state, 'E') && MaybeAppend(state, "::") &&
+ ParseName(state) && Optional(ParseDiscriminator(state))) {
+ return true;
+ }
+ *state = copy;
+
+ if (ParseChar(state, 'Z') && ParseEncoding(state) &&
+ ParseTwoChar(state, "Es") && Optional(ParseDiscriminator(state))) {
+ return true;
+ }
+ *state = copy;
+ return false;
+}
+
+// <discriminator> := _ <(non-negative) number>
+static bool ParseDiscriminator(State *state) {
+ State copy = *state;
+ if (ParseChar(state, '_') && ParseNumber(state)) {
+ return true;
+ }
+ *state = copy;
+ return false;
+}
+
+// <substitution> ::= S_
+// ::= S <seq-id> _
+// ::= St, etc.
+static bool ParseSubstitution(State *state) {
+ if (ParseTwoChar(state, "S_")) {
+ MaybeAppend(state, "?"); // We don't support substitutions.
+ return true;
+ }
+
+ State copy = *state;
+ if (ParseChar(state, 'S') && ParseSeqId(state) &&
+ ParseChar(state, '_')) {
+ MaybeAppend(state, "?"); // We don't support substitutions.
+ return true;
+ }
+ *state = copy;
+
+ // Expand abbreviations like "St" => "std".
+ if (ParseChar(state, 'S')) {
+ const AbbrevPair *p;
+ for (p = kSubstitutionList; p->abbrev != NULL; ++p) {
+ if (state->mangled_cur[0] == p->abbrev[1]) {
+ MaybeAppend(state, "std");
+ if (p->real_name[0] != '\0') {
+ MaybeAppend(state, "::");
+ MaybeAppend(state, p->real_name);
+ }
+ state->mangled_cur += 1;
+ return true;
+ }
+ }
+ }
+ *state = copy;
+ return false;
+}
+
+// The demangler entry point.
+bool Demangle(const char *mangled, char *out, int out_size) {
+ State state;
+ InitState(&state, mangled, out, out_size);
+ return (ParseMangledName(&state) &&
+ state.overflowed == false &&
+ RemainingLength(&state) == 0);
+}
+
+_END_GOOGLE_NAMESPACE_
diff --git a/extern/libmv/third_party/glog/src/demangle.h b/extern/libmv/third_party/glog/src/demangle.h
new file mode 100644
index 00000000000..9c7591527c0
--- /dev/null
+++ b/extern/libmv/third_party/glog/src/demangle.h
@@ -0,0 +1,84 @@
+// Copyright (c) 2006, Google Inc.
+// 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.
+//
+// Author: Satoru Takabayashi
+//
+// An async-signal-safe and thread-safe demangler for Itanium C++ ABI
+// (aka G++ V3 ABI).
+
+// The demangler is implemented to be used in async signal handlers to
+// symbolize stack traces. We cannot use libstdc++'s
+// abi::__cxa_demangle() in such signal handlers since it's not async
+// signal safe (it uses malloc() internally).
+//
+// Note that this demangler doesn't support full demangling. More
+// specifically, it doesn't print types of function parameters and
+// types of template arguments. It just skips them. However, it's
+// still very useful to extract basic information such as class,
+// function, constructor, destructor, and operator names.
+//
+// See the implementation note in demangle.cc if you are interested.
+//
+// Example:
+//
+// | Mangled Name | The Demangler | abi::__cxa_demangle()
+// |---------------|---------------|-----------------------
+// | _Z1fv | f() | f()
+// | _Z1fi | f() | f(int)
+// | _Z3foo3bar | foo() | foo(bar)
+// | _Z1fIiEvi | f<>() | void f<int>(int)
+// | _ZN1N1fE | N::f | N::f
+// | _ZN3Foo3BarEv | Foo::Bar() | Foo::Bar()
+// | _Zrm1XS_" | operator%() | operator%(X, X)
+// | _ZN3FooC1Ev | Foo::Foo() | Foo::Foo()
+// | _Z1fSs | f() | f(std::basic_string<char,
+// | | | std::char_traits<char>,
+// | | | std::allocator<char> >)
+//
+// See the unit test for more examples.
+//
+// Note: we might want to write demanglers for ABIs other than Itanium
+// C++ ABI in the future.
+//
+
+#ifndef BASE_DEMANGLE_H_
+#define BASE_DEMANGLE_H_
+
+#include "config.h"
+
+_START_GOOGLE_NAMESPACE_
+
+// Demangle "mangled". On success, return true and write the
+// demangled symbol name to "out". Otherwise, return false.
+// "out" is modified even if demangling is unsuccessful.
+bool Demangle(const char *mangled, char *out, int out_size);
+
+_END_GOOGLE_NAMESPACE_
+
+#endif // BASE_DEMANGLE_H_
diff --git a/extern/libmv/third_party/glog/src/glog/log_severity.h b/extern/libmv/third_party/glog/src/glog/log_severity.h
new file mode 100644
index 00000000000..17805fbadd4
--- /dev/null
+++ b/extern/libmv/third_party/glog/src/glog/log_severity.h
@@ -0,0 +1,84 @@
+// Copyright (c) 2007, Google Inc.
+// 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.
+
+#ifndef BASE_LOG_SEVERITY_H__
+#define BASE_LOG_SEVERITY_H__
+
+// Annoying stuff for windows -- makes sure clients can import these functions
+#ifndef GOOGLE_GLOG_DLL_DECL
+# if defined(_WIN32) && !defined(__CYGWIN__)
+# define GOOGLE_GLOG_DLL_DECL __declspec(dllimport)
+# else
+# define GOOGLE_GLOG_DLL_DECL
+# endif
+#endif
+
+// Variables of type LogSeverity are widely taken to lie in the range
+// [0, NUM_SEVERITIES-1]. Be careful to preserve this assumption if
+// you ever need to change their values or add a new severity.
+typedef int LogSeverity;
+
+const int INFO = 0, WARNING = 1, ERROR = 2, FATAL = 3, NUM_SEVERITIES = 4;
+
+// DFATAL is FATAL in debug mode, ERROR in normal mode
+#ifdef NDEBUG
+#define DFATAL_LEVEL ERROR
+#else
+#define DFATAL_LEVEL FATAL
+#endif
+
+extern GOOGLE_GLOG_DLL_DECL const char* const LogSeverityNames[NUM_SEVERITIES];
+
+// NDEBUG usage helpers related to (RAW_)DCHECK:
+//
+// DEBUG_MODE is for small !NDEBUG uses like
+// if (DEBUG_MODE) foo.CheckThatFoo();
+// instead of substantially more verbose
+// #ifndef NDEBUG
+// foo.CheckThatFoo();
+// #endif
+//
+// IF_DEBUG_MODE is for small !NDEBUG uses like
+// IF_DEBUG_MODE( string error; )
+// DCHECK(Foo(&error)) << error;
+// instead of substantially more verbose
+// #ifndef NDEBUG
+// string error;
+// DCHECK(Foo(&error)) << error;
+// #endif
+//
+#ifdef NDEBUG
+enum { DEBUG_MODE = 0 };
+#define IF_DEBUG_MODE(x)
+#else
+enum { DEBUG_MODE = 1 };
+#define IF_DEBUG_MODE(x) x
+#endif
+
+#endif // BASE_LOG_SEVERITY_H__
diff --git a/extern/libmv/third_party/glog/src/glog/logging.h b/extern/libmv/third_party/glog/src/glog/logging.h
new file mode 100644
index 00000000000..a58d478ab17
--- /dev/null
+++ b/extern/libmv/third_party/glog/src/glog/logging.h
@@ -0,0 +1,1507 @@
+// Copyright (c) 1999, Google Inc.
+// 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.
+//
+// Author: Ray Sidney
+//
+// This file contains #include information about logging-related stuff.
+// Pretty much everybody needs to #include this file so that they can
+// log various happenings.
+//
+
+#ifndef _LOGGING_H_
+#define _LOGGING_H_
+
+#include <errno.h>
+#include <string.h>
+#include <time.h>
+#include <string>
+#if 1
+# include <unistd.h>
+#endif
+#ifdef __DEPRECATED
+// Make GCC quiet.
+# undef __DEPRECATED
+# include <strstream>
+# define __DEPRECATED
+#else
+# include <strstream>
+#endif
+#include <vector>
+
+// Annoying stuff for windows -- makes sure clients can import these functions
+#ifndef GOOGLE_GLOG_DLL_DECL
+# if defined(_WIN32) && !defined(__CYGWIN__)
+# define GOOGLE_GLOG_DLL_DECL __declspec(dllimport)
+# else
+# define GOOGLE_GLOG_DLL_DECL
+# endif
+#endif
+
+// We care a lot about number of bits things take up. Unfortunately,
+// systems define their bit-specific ints in a lot of different ways.
+// We use our own way, and have a typedef to get there.
+// Note: these commands below may look like "#if 1" or "#if 0", but
+// that's because they were constructed that way at ./configure time.
+// Look at logging.h.in to see how they're calculated (based on your config).
+#if 1
+#include <stdint.h> // the normal place uint16_t is defined
+#endif
+#if 1
+#include <sys/types.h> // the normal place u_int16_t is defined
+#endif
+#if 1
+#include <inttypes.h> // a third place for uint16_t or u_int16_t
+#endif
+
+#if 1
+#include "third_party/gflags/gflags.h"
+#endif
+
+namespace google {
+
+#if 1 // the C99 format
+typedef int32_t int32;
+typedef uint32_t uint32;
+typedef int64_t int64;
+typedef uint64_t uint64;
+#elif 1 // the BSD format
+typedef int32_t int32;
+typedef u_int32_t uint32;
+typedef int64_t int64;
+typedef u_int64_t uint64;
+#elif 0 // the windows (vc7) format
+typedef __int32 int32;
+typedef unsigned __int32 uint32;
+typedef __int64 int64;
+typedef unsigned __int64 uint64;
+#else
+#error Do not know how to define a 32-bit integer quantity on your system
+#endif
+
+}
+
+// The global value of GOOGLE_STRIP_LOG. All the messages logged to
+// LOG(XXX) with severity less than GOOGLE_STRIP_LOG will not be displayed.
+// If it can be determined at compile time that the message will not be
+// printed, the statement will be compiled out.
+//
+// Example: to strip out all INFO and WARNING messages, use the value
+// of 2 below. To make an exception for WARNING messages from a single
+// file, add "#define GOOGLE_STRIP_LOG 1" to that file _before_ including
+// base/logging.h
+#ifndef GOOGLE_STRIP_LOG
+#define GOOGLE_STRIP_LOG 0
+#endif
+
+// GCC can be told that a certain branch is not likely to be taken (for
+// instance, a CHECK failure), and use that information in static analysis.
+// Giving it this information can help it optimize for the common case in
+// the absence of better information (ie. -fprofile-arcs).
+//
+#ifndef GOOGLE_PREDICT_BRANCH_NOT_TAKEN
+#if 1
+#define GOOGLE_PREDICT_BRANCH_NOT_TAKEN(x) (__builtin_expect(x, 0))
+#else
+#define GOOGLE_PREDICT_BRANCH_NOT_TAKEN(x) x
+#endif
+#endif
+
+// Make a bunch of macros for logging. The way to log things is to stream
+// things to LOG(<a particular severity level>). E.g.,
+//
+// LOG(INFO) << "Found " << num_cookies << " cookies";
+//
+// You can capture log messages in a string, rather than reporting them
+// immediately:
+//
+// vector<string> errors;
+// LOG_STRING(ERROR, &errors) << "Couldn't parse cookie #" << cookie_num;
+//
+// This pushes back the new error onto 'errors'; if given a NULL pointer,
+// it reports the error via LOG(ERROR).
+//
+// You can also do conditional logging:
+//
+// LOG_IF(INFO, num_cookies > 10) << "Got lots of cookies";
+//
+// You can also do occasional logging (log every n'th occurrence of an
+// event):
+//
+// LOG_EVERY_N(INFO, 10) << "Got the " << COUNTER << "th cookie";
+//
+// The above will cause log messages to be output on the 1st, 11th, 21st, ...
+// times it is executed. Note that the special COUNTER value is used to
+// identify which repetition is happening.
+//
+// You can also do occasional conditional logging (log every n'th
+// occurrence of an event, when condition is satisfied):
+//
+// LOG_IF_EVERY_N(INFO, (size > 1024), 10) << "Got the " << COUNTER
+// << "th big cookie";
+//
+// You can log messages the first N times your code executes a line. E.g.
+//
+// LOG_FIRST_N(INFO, 20) << "Got the " << COUNTER << "th cookie";
+//
+// Outputs log messages for the first 20 times it is executed.
+//
+// Analogous SYSLOG, SYSLOG_IF, and SYSLOG_EVERY_N macros are available.
+// These log to syslog as well as to the normal logs. If you use these at
+// all, you need to be aware that syslog can drastically reduce performance,
+// especially if it is configured for remote logging! Don't use these
+// unless you fully understand this and have a concrete need to use them.
+// Even then, try to minimize your use of them.
+//
+// There are also "debug mode" logging macros like the ones above:
+//
+// DLOG(INFO) << "Found cookies";
+//
+// DLOG_IF(INFO, num_cookies > 10) << "Got lots of cookies";
+//
+// DLOG_EVERY_N(INFO, 10) << "Got the " << COUNTER << "th cookie";
+//
+// All "debug mode" logging is compiled away to nothing for non-debug mode
+// compiles.
+//
+// We also have
+//
+// LOG_ASSERT(assertion);
+// DLOG_ASSERT(assertion);
+//
+// which is syntactic sugar for {,D}LOG_IF(FATAL, assert fails) << assertion;
+//
+// There are "verbose level" logging macros. They look like
+//
+// VLOG(1) << "I'm printed when you run the program with --v=1 or more";
+// VLOG(2) << "I'm printed when you run the program with --v=2 or more";
+//
+// These always log at the INFO log level (when they log at all).
+// The verbose logging can also be turned on module-by-module. For instance,
+// --vmodule=mapreduce=2,file=1,gfs*=3 --v=0
+// will cause:
+// a. VLOG(2) and lower messages to be printed from mapreduce.{h,cc}
+// b. VLOG(1) and lower messages to be printed from file.{h,cc}
+// c. VLOG(3) and lower messages to be printed from files prefixed with "gfs"
+// d. VLOG(0) and lower messages to be printed from elsewhere
+//
+// The wildcarding functionality shown by (c) supports both '*' (match
+// 0 or more characters) and '?' (match any single character) wildcards.
+//
+// There's also VLOG_IS_ON(n) "verbose level" condition macro. To be used as
+//
+// if (VLOG_IS_ON(2)) {
+// // do some logging preparation and logging
+// // that can't be accomplished with just VLOG(2) << ...;
+// }
+//
+// There are also VLOG_IF, VLOG_EVERY_N and VLOG_IF_EVERY_N "verbose level"
+// condition macros for sample cases, when some extra computation and
+// preparation for logs is not needed.
+// VLOG_IF(1, (size > 1024))
+// << "I'm printed when size is more than 1024 and when you run the "
+// "program with --v=1 or more";
+// VLOG_EVERY_N(1, 10)
+// << "I'm printed every 10th occurrence, and when you run the program "
+// "with --v=1 or more. Present occurence is " << COUNTER;
+// VLOG_IF_EVERY_N(1, (size > 1024), 10)
+// << "I'm printed on every 10th occurence of case when size is more "
+// " than 1024, when you run the program with --v=1 or more. ";
+// "Present occurence is " << COUNTER;
+//
+// The supported severity levels for macros that allow you to specify one
+// are (in increasing order of severity) INFO, WARNING, ERROR, and FATAL.
+// Note that messages of a given severity are logged not only in the
+// logfile for that severity, but also in all logfiles of lower severity.
+// E.g., a message of severity FATAL will be logged to the logfiles of
+// severity FATAL, ERROR, WARNING, and INFO.
+//
+// There is also the special severity of DFATAL, which logs FATAL in
+// debug mode, ERROR in normal mode.
+//
+// Very important: logging a message at the FATAL severity level causes
+// the program to terminate (after the message is logged).
+//
+// Unless otherwise specified, logs will be written to the filename
+// "<program name>.<hostname>.<user name>.log.<severity level>.", followed
+// by the date, time, and pid (you can't prevent the date, time, and pid
+// from being in the filename).
+//
+// The logging code takes two flags:
+// --v=# set the verbose level
+// --logtostderr log all the messages to stderr instead of to logfiles
+
+// LOG LINE PREFIX FORMAT
+//
+// Log lines have this form:
+//
+// Lmmdd hh:mm:ss.uuuuuu threadid file:line] msg...
+//
+// where the fields are defined as follows:
+//
+// L A single character, representing the log level
+// (eg 'I' for INFO)
+// mm The month (zero padded; ie May is '05')
+// dd The day (zero padded)
+// hh:mm:ss.uuuuuu Time in hours, minutes and fractional seconds
+// threadid The space-padded thread ID as returned by GetTID()
+// (this matches the PID on Linux)
+// file The file name
+// line The line number
+// msg The user-supplied message
+//
+// Example:
+//
+// I1103 11:57:31.739339 24395 google.cc:2341] Command line: ./some_prog
+// I1103 11:57:31.739403 24395 google.cc:2342] Process id 24395
+//
+// NOTE: although the microseconds are useful for comparing events on
+// a single machine, clocks on different machines may not be well
+// synchronized. Hence, use caution when comparing the low bits of
+// timestamps from different machines.
+
+#ifndef DECLARE_VARIABLE
+#define MUST_UNDEF_GFLAGS_DECLARE_MACROS
+#define DECLARE_VARIABLE(type, name, tn) \
+ namespace FLAG__namespace_do_not_use_directly_use_DECLARE_##tn##_instead { \
+ extern GOOGLE_GLOG_DLL_DECL type FLAGS_##name; \
+ } \
+ using FLAG__namespace_do_not_use_directly_use_DECLARE_##tn##_instead::FLAGS_##name
+
+// bool specialization
+#define DECLARE_bool(name) \
+ DECLARE_VARIABLE(bool, name, bool)
+
+// int32 specialization
+#define DECLARE_int32(name) \
+ DECLARE_VARIABLE(google::int32, name, int32)
+
+// Special case for string, because we have to specify the namespace
+// std::string, which doesn't play nicely with our FLAG__namespace hackery.
+#define DECLARE_string(name) \
+ namespace FLAG__namespace_do_not_use_directly_use_DECLARE_string_instead { \
+ extern GOOGLE_GLOG_DLL_DECL std::string FLAGS_##name; \
+ } \
+ using FLAG__namespace_do_not_use_directly_use_DECLARE_string_instead::FLAGS_##name
+#endif
+
+// Set whether log messages go to stderr instead of logfiles
+DECLARE_bool(logtostderr);
+
+// Set whether log messages go to stderr in addition to logfiles.
+DECLARE_bool(alsologtostderr);
+
+// Log messages at a level >= this flag are automatically sent to
+// stderr in addition to log files.
+DECLARE_int32(stderrthreshold);
+
+// Set whether the log prefix should be prepended to each line of output.
+DECLARE_bool(log_prefix);
+
+// Log messages at a level <= this flag are buffered.
+// Log messages at a higher level are flushed immediately.
+DECLARE_int32(logbuflevel);
+
+// Sets the maximum number of seconds which logs may be buffered for.
+DECLARE_int32(logbufsecs);
+
+// Log suppression level: messages logged at a lower level than this
+// are suppressed.
+DECLARE_int32(minloglevel);
+
+// If specified, logfiles are written into this directory instead of the
+// default logging directory.
+DECLARE_string(log_dir);
+
+// Sets the path of the directory into which to put additional links
+// to the log files.
+DECLARE_string(log_link);
+
+DECLARE_int32(v); // in vlog_is_on.cc
+
+// Sets the maximum log file size (in MB).
+DECLARE_int32(max_log_size);
+
+// Sets whether to avoid logging to the disk if the disk is full.
+DECLARE_bool(stop_logging_if_full_disk);
+
+#ifdef MUST_UNDEF_GFLAGS_DECLARE_MACROS
+#undef MUST_UNDEF_GFLAGS_DECLARE_MACROS
+#undef DECLARE_VARIABLE
+#undef DECLARE_bool
+#undef DECLARE_int32
+#undef DECLARE_string
+#endif
+
+// Log messages below the GOOGLE_STRIP_LOG level will be compiled away for
+// security reasons. See LOG(severtiy) below.
+
+// A few definitions of macros that don't generate much code. Since
+// LOG(INFO) and its ilk are used all over our code, it's
+// better to have compact code for these operations.
+
+#if GOOGLE_STRIP_LOG == 0
+#define COMPACT_GOOGLE_LOG_INFO google::LogMessage( \
+ __FILE__, __LINE__)
+#define LOG_TO_STRING_INFO(message) google::LogMessage( \
+ __FILE__, __LINE__, google::INFO, message)
+#else
+#define COMPACT_GOOGLE_LOG_INFO google::NullStream()
+#define LOG_TO_STRING_INFO(message) google::NullStream()
+#endif
+
+#if GOOGLE_STRIP_LOG <= 1
+#define COMPACT_GOOGLE_LOG_WARNING google::LogMessage( \
+ __FILE__, __LINE__, google::WARNING)
+#define LOG_TO_STRING_WARNING(message) google::LogMessage( \
+ __FILE__, __LINE__, google::WARNING, message)
+#else
+#define COMPACT_GOOGLE_LOG_WARNING google::NullStream()
+#define LOG_TO_STRING_WARNING(message) google::NullStream()
+#endif
+
+#if GOOGLE_STRIP_LOG <= 2
+#define COMPACT_GOOGLE_LOG_ERROR google::LogMessage( \
+ __FILE__, __LINE__, google::ERROR)
+#define LOG_TO_STRING_ERROR(message) google::LogMessage( \
+ __FILE__, __LINE__, google::ERROR, message)
+#else
+#define COMPACT_GOOGLE_LOG_ERROR google::NullStream()
+#define LOG_TO_STRING_ERROR(message) google::NullStream()
+#endif
+
+#if GOOGLE_STRIP_LOG <= 3
+#define COMPACT_GOOGLE_LOG_FATAL google::LogMessageFatal( \
+ __FILE__, __LINE__)
+#define LOG_TO_STRING_FATAL(message) google::LogMessage( \
+ __FILE__, __LINE__, google::FATAL, message)
+#else
+#define COMPACT_GOOGLE_LOG_FATAL google::NullStreamFatal()
+#define LOG_TO_STRING_FATAL(message) google::NullStreamFatal()
+#endif
+
+// For DFATAL, we want to use LogMessage (as opposed to
+// LogMessageFatal), to be consistent with the original behavior.
+#ifdef NDEBUG
+#define COMPACT_GOOGLE_LOG_DFATAL COMPACT_GOOGLE_LOG_ERROR
+#elif GOOGLE_STRIP_LOG <= 3
+#define COMPACT_GOOGLE_LOG_DFATAL google::LogMessage( \
+ __FILE__, __LINE__, google::FATAL)
+#else
+#define COMPACT_GOOGLE_LOG_DFATAL google::NullStreamFatal()
+#endif
+
+#define GOOGLE_LOG_INFO(counter) google::LogMessage(__FILE__, __LINE__, google::INFO, counter, &google::LogMessage::SendToLog)
+#define SYSLOG_INFO(counter) \
+ google::LogMessage(__FILE__, __LINE__, google::INFO, counter, \
+ &google::LogMessage::SendToSyslogAndLog)
+#define GOOGLE_LOG_WARNING(counter) \
+ google::LogMessage(__FILE__, __LINE__, google::WARNING, counter, \
+ &google::LogMessage::SendToLog)
+#define SYSLOG_WARNING(counter) \
+ google::LogMessage(__FILE__, __LINE__, google::WARNING, counter, \
+ &google::LogMessage::SendToSyslogAndLog)
+#define GOOGLE_LOG_ERROR(counter) \
+ google::LogMessage(__FILE__, __LINE__, google::ERROR, counter, \
+ &google::LogMessage::SendToLog)
+#define SYSLOG_ERROR(counter) \
+ google::LogMessage(__FILE__, __LINE__, google::ERROR, counter, \
+ &google::LogMessage::SendToSyslogAndLog)
+#define GOOGLE_LOG_FATAL(counter) \
+ google::LogMessage(__FILE__, __LINE__, google::FATAL, counter, \
+ &google::LogMessage::SendToLog)
+#define SYSLOG_FATAL(counter) \
+ google::LogMessage(__FILE__, __LINE__, google::FATAL, counter, \
+ &google::LogMessage::SendToSyslogAndLog)
+#define GOOGLE_LOG_DFATAL(counter) \
+ google::LogMessage(__FILE__, __LINE__, google::DFATAL_LEVEL, counter, \
+ &google::LogMessage::SendToLog)
+#define SYSLOG_DFATAL(counter) \
+ google::LogMessage(__FILE__, __LINE__, google::DFATAL_LEVEL, counter, \
+ &google::LogMessage::SendToSyslogAndLog)
+
+#if defined(WIN32) || defined(_WIN32) || defined(__WIN32__) || defined(__CYGWIN__) || defined(__CYGWIN32__)
+// A very useful logging macro to log windows errors:
+#define LOG_SYSRESULT(result) \
+ if (FAILED(result)) { \
+ LPTSTR message = NULL; \
+ LPTSTR msg = reinterpret_cast<LPTSTR>(&message); \
+ DWORD message_length = FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | \
+ FORMAT_MESSAGE_FROM_SYSTEM, \
+ 0, result, 0, msg, 100, NULL); \
+ if (message_length > 0) { \
+ google::LogMessage(__FILE__, __LINE__, ERROR, 0, \
+ &google::LogMessage::SendToLog).stream() << message; \
+ LocalFree(message); \
+ } \
+ }
+#endif
+
+// We use the preprocessor's merging operator, "##", so that, e.g.,
+// LOG(INFO) becomes the token GOOGLE_LOG_INFO. There's some funny
+// subtle difference between ostream member streaming functions (e.g.,
+// ostream::operator<<(int) and ostream non-member streaming functions
+// (e.g., ::operator<<(ostream&, string&): it turns out that it's
+// impossible to stream something like a string directly to an unnamed
+// ostream. We employ a neat hack by calling the stream() member
+// function of LogMessage which seems to avoid the problem.
+#define LOG(severity) COMPACT_GOOGLE_LOG_ ## severity.stream()
+#define SYSLOG(severity) SYSLOG_ ## severity(0).stream()
+
+namespace google {
+
+// They need the definitions of integer types.
+#include "glog/log_severity.h"
+#include "glog/vlog_is_on.h"
+
+// Initialize google's logging library. You will see the program name
+// specified by argv0 in log outputs.
+GOOGLE_GLOG_DLL_DECL void InitGoogleLogging(const char* argv0);
+
+// Shutdown google's logging library.
+GOOGLE_GLOG_DLL_DECL void ShutdownGoogleLogging();
+
+// Install a function which will be called after LOG(FATAL).
+GOOGLE_GLOG_DLL_DECL void InstallFailureFunction(void (*fail_func)());
+
+class LogSink; // defined below
+
+// If a non-NULL sink pointer is given, we push this message to that sink.
+// For LOG_TO_SINK we then do normal LOG(severity) logging as well.
+// This is useful for capturing messages and passing/storing them
+// somewhere more specific than the global log of the process.
+// Argument types:
+// LogSink* sink;
+// LogSeverity severity;
+// The cast is to disambiguate NULL arguments.
+#define LOG_TO_SINK(sink, severity) \
+ google::LogMessage( \
+ __FILE__, __LINE__, \
+ google::severity, \
+ static_cast<google::LogSink*>(sink), true).stream()
+#define LOG_TO_SINK_BUT_NOT_TO_LOGFILE(sink, severity) \
+ google::LogMessage( \
+ __FILE__, __LINE__, \
+ google::severity, \
+ static_cast<google::LogSink*>(sink), false).stream()
+
+// If a non-NULL string pointer is given, we write this message to that string.
+// We then do normal LOG(severity) logging as well.
+// This is useful for capturing messages and storing them somewhere more
+// specific than the global log of the process.
+// Argument types:
+// string* message;
+// LogSeverity severity;
+// The cast is to disambiguate NULL arguments.
+// NOTE: LOG(severity) expands to LogMessage().stream() for the specified
+// severity.
+#define LOG_TO_STRING(severity, message) \
+ LOG_TO_STRING_##severity(static_cast<string*>(message)).stream()
+
+// If a non-NULL pointer is given, we push the message onto the end
+// of a vector of strings; otherwise, we report it with LOG(severity).
+// This is handy for capturing messages and perhaps passing them back
+// to the caller, rather than reporting them immediately.
+// Argument types:
+// LogSeverity severity;
+// vector<string> *outvec;
+// The cast is to disambiguate NULL arguments.
+#define LOG_STRING(severity, outvec) \
+ LOG_TO_STRING_##severity(static_cast<vector<string>*>(outvec)).stream()
+
+#define LOG_IF(severity, condition) \
+ !(condition) ? (void) 0 : google::LogMessageVoidify() & LOG(severity)
+#define SYSLOG_IF(severity, condition) \
+ !(condition) ? (void) 0 : google::LogMessageVoidify() & SYSLOG(severity)
+
+#define LOG_ASSERT(condition) \
+ LOG_IF(FATAL, !(condition)) << "Assert failed: " #condition
+#define SYSLOG_ASSERT(condition) \
+ SYSLOG_IF(FATAL, !(condition)) << "Assert failed: " #condition
+
+// CHECK dies with a fatal error if condition is not true. It is *not*
+// controlled by NDEBUG, so the check will be executed regardless of
+// compilation mode. Therefore, it is safe to do things like:
+// CHECK(fp->Write(x) == 4)
+#define CHECK(condition) \
+ LOG_IF(FATAL, GOOGLE_PREDICT_BRANCH_NOT_TAKEN(!(condition))) \
+ << "Check failed: " #condition " "
+
+// A container for a string pointer which can be evaluated to a bool -
+// true iff the pointer is NULL.
+struct CheckOpString {
+ CheckOpString(std::string* str) : str_(str) { }
+ // No destructor: if str_ is non-NULL, we're about to LOG(FATAL),
+ // so there's no point in cleaning up str_.
+ operator bool() const {
+ return GOOGLE_PREDICT_BRANCH_NOT_TAKEN(str_ != NULL);
+ }
+ std::string* str_;
+};
+
+// Function is overloaded for integral types to allow static const
+// integrals declared in classes and not defined to be used as arguments to
+// CHECK* macros. It's not encouraged though.
+template <class T>
+inline const T& GetReferenceableValue(const T& t) { return t; }
+inline char GetReferenceableValue(char t) { return t; }
+inline unsigned char GetReferenceableValue(unsigned char t) { return t; }
+inline signed char GetReferenceableValue(signed char t) { return t; }
+inline short GetReferenceableValue(short t) { return t; }
+inline unsigned short GetReferenceableValue(unsigned short t) { return t; }
+inline int GetReferenceableValue(int t) { return t; }
+inline unsigned int GetReferenceableValue(unsigned int t) { return t; }
+inline long GetReferenceableValue(long t) { return t; }
+inline unsigned long GetReferenceableValue(unsigned long t) { return t; }
+inline long long GetReferenceableValue(long long t) { return t; }
+inline unsigned long long GetReferenceableValue(unsigned long long t) {
+ return t;
+}
+
+// This is a dummy class to define the following operator.
+struct DummyClassToDefineOperator {};
+
+}
+
+// Define global operator<< to declare using ::operator<<.
+// This declaration will allow use to use CHECK macros for user
+// defined classes which have operator<< (e.g., stl_logging.h).
+inline std::ostream& operator<<(
+ std::ostream& out, const google::DummyClassToDefineOperator&) {
+ return out;
+}
+
+namespace google {
+
+// Build the error message string.
+template<class t1, class t2>
+std::string* MakeCheckOpString(const t1& v1, const t2& v2, const char* names) {
+ // It means that we cannot use stl_logging if compiler doesn't
+ // support using expression for operator.
+ // TODO(hamaji): Figure out a way to fix.
+#if 1
+ using ::operator<<;
+#endif
+ std::strstream ss;
+ ss << names << " (" << v1 << " vs. " << v2 << ")";
+ return new std::string(ss.str(), ss.pcount());
+}
+
+// Helper functions for CHECK_OP macro.
+// The (int, int) specialization works around the issue that the compiler
+// will not instantiate the template version of the function on values of
+// unnamed enum type - see comment below.
+#define DEFINE_CHECK_OP_IMPL(name, op) \
+ template <class t1, class t2> \
+ inline std::string* Check##name##Impl(const t1& v1, const t2& v2, \
+ const char* names) { \
+ if (v1 op v2) return NULL; \
+ else return MakeCheckOpString(v1, v2, names); \
+ } \
+ inline std::string* Check##name##Impl(int v1, int v2, const char* names) { \
+ return Check##name##Impl<int, int>(v1, v2, names); \
+ }
+
+// Use _EQ, _NE, _LE, etc. in case the file including base/logging.h
+// provides its own #defines for the simpler names EQ, NE, LE, etc.
+// This happens if, for example, those are used as token names in a
+// yacc grammar.
+DEFINE_CHECK_OP_IMPL(_EQ, ==)
+DEFINE_CHECK_OP_IMPL(_NE, !=)
+DEFINE_CHECK_OP_IMPL(_LE, <=)
+DEFINE_CHECK_OP_IMPL(_LT, < )
+DEFINE_CHECK_OP_IMPL(_GE, >=)
+DEFINE_CHECK_OP_IMPL(_GT, > )
+#undef DEFINE_CHECK_OP_IMPL
+
+// Helper macro for binary operators.
+// Don't use this macro directly in your code, use CHECK_EQ et al below.
+
+#if defined(STATIC_ANALYSIS)
+// Only for static analysis tool to know that it is equivalent to assert
+#define CHECK_OP_LOG(name, op, val1, val2, log) CHECK((val1) op (val2))
+#elif !defined(NDEBUG)
+// In debug mode, avoid constructing CheckOpStrings if possible,
+// to reduce the overhead of CHECK statments by 2x.
+// Real DCHECK-heavy tests have seen 1.5x speedups.
+
+// The meaning of "string" might be different between now and
+// when this macro gets invoked (e.g., if someone is experimenting
+// with other string implementations that get defined after this
+// file is included). Save the current meaning now and use it
+// in the macro.
+typedef std::string _Check_string;
+#define CHECK_OP_LOG(name, op, val1, val2, log) \
+ while (google::_Check_string* _result = \
+ google::Check##name##Impl( \
+ google::GetReferenceableValue(val1), \
+ google::GetReferenceableValue(val2), \
+ #val1 " " #op " " #val2)) \
+ log(__FILE__, __LINE__, \
+ google::CheckOpString(_result)).stream()
+#else
+// In optimized mode, use CheckOpString to hint to compiler that
+// the while condition is unlikely.
+#define CHECK_OP_LOG(name, op, val1, val2, log) \
+ while (google::CheckOpString _result = \
+ google::Check##name##Impl( \
+ google::GetReferenceableValue(val1), \
+ google::GetReferenceableValue(val2), \
+ #val1 " " #op " " #val2)) \
+ log(__FILE__, __LINE__, _result).stream()
+#endif // STATIC_ANALYSIS, !NDEBUG
+
+#if GOOGLE_STRIP_LOG <= 3
+#define CHECK_OP(name, op, val1, val2) \
+ CHECK_OP_LOG(name, op, val1, val2, google::LogMessageFatal)
+#else
+#define CHECK_OP(name, op, val1, val2) \
+ CHECK_OP_LOG(name, op, val1, val2, google::NullStreamFatal)
+#endif // STRIP_LOG <= 3
+
+// Equality/Inequality checks - compare two values, and log a FATAL message
+// including the two values when the result is not as expected. The values
+// must have operator<<(ostream, ...) defined.
+//
+// You may append to the error message like so:
+// CHECK_NE(1, 2) << ": The world must be ending!";
+//
+// We are very careful to ensure that each argument is evaluated exactly
+// once, and that anything which is legal to pass as a function argument is
+// legal here. In particular, the arguments may be temporary expressions
+// which will end up being destroyed at the end of the apparent statement,
+// for example:
+// CHECK_EQ(string("abc")[1], 'b');
+//
+// WARNING: These don't compile correctly if one of the arguments is a pointer
+// and the other is NULL. To work around this, simply static_cast NULL to the
+// type of the desired pointer.
+
+#define CHECK_EQ(val1, val2) CHECK_OP(_EQ, ==, val1, val2)
+#define CHECK_NE(val1, val2) CHECK_OP(_NE, !=, val1, val2)
+#define CHECK_LE(val1, val2) CHECK_OP(_LE, <=, val1, val2)
+#define CHECK_LT(val1, val2) CHECK_OP(_LT, < , val1, val2)
+#define CHECK_GE(val1, val2) CHECK_OP(_GE, >=, val1, val2)
+#define CHECK_GT(val1, val2) CHECK_OP(_GT, > , val1, val2)
+
+// Check that the input is non NULL. This very useful in constructor
+// initializer lists.
+
+#define CHECK_NOTNULL(val) \
+ google::CheckNotNull(__FILE__, __LINE__, "'" #val "' Must be non NULL", (val))
+
+// Helper functions for string comparisons.
+// To avoid bloat, the definitions are in logging.cc.
+#define DECLARE_CHECK_STROP_IMPL(func, expected) \
+ GOOGLE_GLOG_DLL_DECL std::string* Check##func##expected##Impl( \
+ const char* s1, const char* s2, const char* names);
+DECLARE_CHECK_STROP_IMPL(strcmp, true)
+DECLARE_CHECK_STROP_IMPL(strcmp, false)
+DECLARE_CHECK_STROP_IMPL(strcasecmp, true)
+DECLARE_CHECK_STROP_IMPL(strcasecmp, false)
+#undef DECLARE_CHECK_STROP_IMPL
+
+// Helper macro for string comparisons.
+// Don't use this macro directly in your code, use CHECK_STREQ et al below.
+#define CHECK_STROP(func, op, expected, s1, s2) \
+ while (google::CheckOpString _result = \
+ google::Check##func##expected##Impl((s1), (s2), \
+ #s1 " " #op " " #s2)) \
+ LOG(FATAL) << *_result.str_
+
+
+// String (char*) equality/inequality checks.
+// CASE versions are case-insensitive.
+//
+// Note that "s1" and "s2" may be temporary strings which are destroyed
+// by the compiler at the end of the current "full expression"
+// (e.g. CHECK_STREQ(Foo().c_str(), Bar().c_str())).
+
+#define CHECK_STREQ(s1, s2) CHECK_STROP(strcmp, ==, true, s1, s2)
+#define CHECK_STRNE(s1, s2) CHECK_STROP(strcmp, !=, false, s1, s2)
+#define CHECK_STRCASEEQ(s1, s2) CHECK_STROP(strcasecmp, ==, true, s1, s2)
+#define CHECK_STRCASENE(s1, s2) CHECK_STROP(strcasecmp, !=, false, s1, s2)
+
+#define CHECK_INDEX(I,A) CHECK(I < (sizeof(A)/sizeof(A[0])))
+#define CHECK_BOUND(B,A) CHECK(B <= (sizeof(A)/sizeof(A[0])))
+
+#define CHECK_DOUBLE_EQ(val1, val2) \
+ do { \
+ CHECK_LE((val1), (val2)+0.000000000000001L); \
+ CHECK_GE((val1), (val2)-0.000000000000001L); \
+ } while (0)
+
+#define CHECK_NEAR(val1, val2, margin) \
+ do { \
+ CHECK_LE((val1), (val2)+(margin)); \
+ CHECK_GE((val1), (val2)-(margin)); \
+ } while (0)
+
+// perror()..googly style!
+//
+// PLOG() and PLOG_IF() and PCHECK() behave exactly like their LOG* and
+// CHECK equivalents with the addition that they postpend a description
+// of the current state of errno to their output lines.
+
+#define PLOG(severity) GOOGLE_PLOG(severity, 0).stream()
+
+#define GOOGLE_PLOG(severity, counter) \
+ google::ErrnoLogMessage( \
+ __FILE__, __LINE__, google::severity, counter, \
+ &google::LogMessage::SendToLog)
+
+#define PLOG_IF(severity, condition) \
+ !(condition) ? (void) 0 : google::LogMessageVoidify() & PLOG(severity)
+
+// A CHECK() macro that postpends errno if the condition is false. E.g.
+//
+// if (poll(fds, nfds, timeout) == -1) { PCHECK(errno == EINTR); ... }
+#define PCHECK(condition) \
+ PLOG_IF(FATAL, GOOGLE_PREDICT_BRANCH_NOT_TAKEN(!(condition))) \
+ << "Check failed: " #condition " "
+
+// A CHECK() macro that lets you assert the success of a function that
+// returns -1 and sets errno in case of an error. E.g.
+//
+// CHECK_ERR(mkdir(path, 0700));
+//
+// or
+//
+// int fd = open(filename, flags); CHECK_ERR(fd) << ": open " << filename;
+#define CHECK_ERR(invocation) \
+PLOG_IF(FATAL, GOOGLE_PREDICT_BRANCH_NOT_TAKEN((invocation) == -1)) \
+ << #invocation
+
+// Use macro expansion to create, for each use of LOG_EVERY_N(), static
+// variables with the __LINE__ expansion as part of the variable name.
+#define LOG_EVERY_N_VARNAME(base, line) LOG_EVERY_N_VARNAME_CONCAT(base, line)
+#define LOG_EVERY_N_VARNAME_CONCAT(base, line) base ## line
+
+#define LOG_OCCURRENCES LOG_EVERY_N_VARNAME(occurrences_, __LINE__)
+#define LOG_OCCURRENCES_MOD_N LOG_EVERY_N_VARNAME(occurrences_mod_n_, __LINE__)
+
+#define SOME_KIND_OF_LOG_EVERY_N(severity, n, what_to_do) \
+ static int LOG_OCCURRENCES = 0, LOG_OCCURRENCES_MOD_N = 0; \
+ ++LOG_OCCURRENCES; \
+ if (++LOG_OCCURRENCES_MOD_N > n) LOG_OCCURRENCES_MOD_N -= n; \
+ if (LOG_OCCURRENCES_MOD_N == 1) \
+ google::LogMessage( \
+ __FILE__, __LINE__, google::severity, LOG_OCCURRENCES, \
+ &what_to_do).stream()
+
+#define SOME_KIND_OF_LOG_IF_EVERY_N(severity, condition, n, what_to_do) \
+ static int LOG_OCCURRENCES = 0, LOG_OCCURRENCES_MOD_N = 0; \
+ ++LOG_OCCURRENCES; \
+ if (condition && \
+ ((LOG_OCCURRENCES_MOD_N=(LOG_OCCURRENCES_MOD_N + 1) % n) == (1 % n))) \
+ google::LogMessage( \
+ __FILE__, __LINE__, google::severity, LOG_OCCURRENCES, \
+ &what_to_do).stream()
+
+#define SOME_KIND_OF_PLOG_EVERY_N(severity, n, what_to_do) \
+ static int LOG_OCCURRENCES = 0, LOG_OCCURRENCES_MOD_N = 0; \
+ ++LOG_OCCURRENCES; \
+ if (++LOG_OCCURRENCES_MOD_N > n) LOG_OCCURRENCES_MOD_N -= n; \
+ if (LOG_OCCURRENCES_MOD_N == 1) \
+ google::ErrnoLogMessage( \
+ __FILE__, __LINE__, google::severity, LOG_OCCURRENCES, \
+ &what_to_do).stream()
+
+#define SOME_KIND_OF_LOG_FIRST_N(severity, n, what_to_do) \
+ static int LOG_OCCURRENCES = 0; \
+ if (LOG_OCCURRENCES <= n) \
+ ++LOG_OCCURRENCES; \
+ if (LOG_OCCURRENCES <= n) \
+ google::LogMessage( \
+ __FILE__, __LINE__, google::severity, LOG_OCCURRENCES, \
+ &what_to_do).stream()
+
+namespace glog_internal_namespace_ {
+template <bool>
+struct CompileAssert {
+};
+struct CrashReason;
+} // namespace glog_internal_namespace_
+
+#define GOOGLE_GLOG_COMPILE_ASSERT(expr, msg) \
+ typedef google::glog_internal_namespace_::CompileAssert<(bool(expr))> msg[bool(expr) ? 1 : -1]
+
+#define LOG_EVERY_N(severity, n) \
+ GOOGLE_GLOG_COMPILE_ASSERT(google::severity < \
+ google::NUM_SEVERITIES, \
+ INVALID_REQUESTED_LOG_SEVERITY); \
+ SOME_KIND_OF_LOG_EVERY_N(severity, (n), google::LogMessage::SendToLog)
+
+#define SYSLOG_EVERY_N(severity, n) \
+ SOME_KIND_OF_LOG_EVERY_N(severity, (n), google::LogMessage::SendToSyslogAndLog)
+
+#define PLOG_EVERY_N(severity, n) \
+ SOME_KIND_OF_PLOG_EVERY_N(severity, (n), google::LogMessage::SendToLog)
+
+#define LOG_FIRST_N(severity, n) \
+ SOME_KIND_OF_LOG_FIRST_N(severity, (n), google::LogMessage::SendToLog)
+
+#define LOG_IF_EVERY_N(severity, condition, n) \
+ SOME_KIND_OF_LOG_IF_EVERY_N(severity, (condition), (n), google::LogMessage::SendToLog)
+
+// We want the special COUNTER value available for LOG_EVERY_X()'ed messages
+enum PRIVATE_Counter {COUNTER};
+
+
+// Plus some debug-logging macros that get compiled to nothing for production
+
+#ifndef NDEBUG
+
+#define DLOG(severity) LOG(severity)
+#define DVLOG(verboselevel) VLOG(verboselevel)
+#define DLOG_IF(severity, condition) LOG_IF(severity, condition)
+#define DLOG_EVERY_N(severity, n) LOG_EVERY_N(severity, n)
+#define DLOG_IF_EVERY_N(severity, condition, n) \
+ LOG_IF_EVERY_N(severity, condition, n)
+#define DLOG_ASSERT(condition) LOG_ASSERT(condition)
+
+// debug-only checking. not executed in NDEBUG mode.
+#define DCHECK(condition) CHECK(condition)
+#define DCHECK_EQ(val1, val2) CHECK_EQ(val1, val2)
+#define DCHECK_NE(val1, val2) CHECK_NE(val1, val2)
+#define DCHECK_LE(val1, val2) CHECK_LE(val1, val2)
+#define DCHECK_LT(val1, val2) CHECK_LT(val1, val2)
+#define DCHECK_GE(val1, val2) CHECK_GE(val1, val2)
+#define DCHECK_GT(val1, val2) CHECK_GT(val1, val2)
+#define DCHECK_NOTNULL(val) CHECK_NOTNULL(val)
+#define DCHECK_STREQ(str1, str2) CHECK_STREQ(str1, str2)
+#define DCHECK_STRCASEEQ(str1, str2) CHECK_STRCASEEQ(str1, str2)
+#define DCHECK_STRNE(str1, str2) CHECK_STRNE(str1, str2)
+#define DCHECK_STRCASENE(str1, str2) CHECK_STRCASENE(str1, str2)
+
+#else // NDEBUG
+
+#define DLOG(severity) \
+ true ? (void) 0 : google::LogMessageVoidify() & LOG(severity)
+
+#define DVLOG(verboselevel) \
+ (true || !VLOG_IS_ON(verboselevel)) ?\
+ (void) 0 : google::LogMessageVoidify() & LOG(INFO)
+
+#define DLOG_IF(severity, condition) \
+ (true || !(condition)) ? (void) 0 : google::LogMessageVoidify() & LOG(severity)
+
+#define DLOG_EVERY_N(severity, n) \
+ true ? (void) 0 : google::LogMessageVoidify() & LOG(severity)
+
+#define DLOG_IF_EVERY_N(severity, condition, n) \
+ (true || !(condition))? (void) 0 : google::LogMessageVoidify() & LOG(severity)
+
+#define DLOG_ASSERT(condition) \
+ true ? (void) 0 : LOG_ASSERT(condition)
+
+#define DCHECK(condition) \
+ while (false) \
+ CHECK(condition)
+
+#define DCHECK_EQ(val1, val2) \
+ while (false) \
+ CHECK_EQ(val1, val2)
+
+#define DCHECK_NE(val1, val2) \
+ while (false) \
+ CHECK_NE(val1, val2)
+
+#define DCHECK_LE(val1, val2) \
+ while (false) \
+ CHECK_LE(val1, val2)
+
+#define DCHECK_LT(val1, val2) \
+ while (false) \
+ CHECK_LT(val1, val2)
+
+#define DCHECK_GE(val1, val2) \
+ while (false) \
+ CHECK_GE(val1, val2)
+
+#define DCHECK_GT(val1, val2) \
+ while (false) \
+ CHECK_GT(val1, val2)
+
+#define DCHECK_NOTNULL(val) (val)
+
+#define DCHECK_STREQ(str1, str2) \
+ while (false) \
+ CHECK_STREQ(str1, str2)
+
+#define DCHECK_STRCASEEQ(str1, str2) \
+ while (false) \
+ CHECK_STRCASEEQ(str1, str2)
+
+#define DCHECK_STRNE(str1, str2) \
+ while (false) \
+ CHECK_STRNE(str1, str2)
+
+#define DCHECK_STRCASENE(str1, str2) \
+ while (false) \
+ CHECK_STRCASENE(str1, str2)
+
+
+#endif // NDEBUG
+
+// Log only in verbose mode.
+
+#define VLOG(verboselevel) LOG_IF(INFO, VLOG_IS_ON(verboselevel))
+
+#define VLOG_IF(verboselevel, condition) \
+ LOG_IF(INFO, (condition) && VLOG_IS_ON(verboselevel))
+
+#define VLOG_EVERY_N(verboselevel, n) \
+ LOG_IF_EVERY_N(INFO, VLOG_IS_ON(verboselevel), n)
+
+#define VLOG_IF_EVERY_N(verboselevel, condition, n) \
+ LOG_IF_EVERY_N(INFO, (condition) && VLOG_IS_ON(verboselevel), n)
+
+//
+// This class more or less represents a particular log message. You
+// create an instance of LogMessage and then stream stuff to it.
+// When you finish streaming to it, ~LogMessage is called and the
+// full message gets streamed to the appropriate destination.
+//
+// You shouldn't actually use LogMessage's constructor to log things,
+// though. You should use the LOG() macro (and variants thereof)
+// above.
+class GOOGLE_GLOG_DLL_DECL LogMessage {
+public:
+ enum {
+ // Passing kNoLogPrefix for the line number disables the
+ // log-message prefix. Useful for using the LogMessage
+ // infrastructure as a printing utility. See also the --log_prefix
+ // flag for controlling the log-message prefix on an
+ // application-wide basis.
+ kNoLogPrefix = -1
+ };
+
+ // LogStream inherit from non-DLL-exported class (std::ostrstream)
+ // and VC++ produces a warning for this situation.
+ // However, MSDN says "C4275 can be ignored in Microsoft Visual C++
+ // 2005 if you are deriving from a type in the Standard C++ Library"
+ // http://msdn.microsoft.com/en-us/library/3tdb471s(VS.80).aspx
+ // Let's just ignore the warning.
+#ifdef _MSC_VER
+# pragma warning(disable: 4275)
+#endif
+ class GOOGLE_GLOG_DLL_DECL LogStream : public std::ostrstream {
+#ifdef _MSC_VER
+# pragma warning(default: 4275)
+#endif
+ public:
+ LogStream(char *buf, int len, int ctr)
+ : ostrstream(buf, len),
+ ctr_(ctr) {
+ self_ = this;
+ }
+
+ int ctr() const { return ctr_; }
+ void set_ctr(int ctr) { ctr_ = ctr; }
+ LogStream* self() const { return self_; }
+
+ private:
+ int ctr_; // Counter hack (for the LOG_EVERY_X() macro)
+ LogStream *self_; // Consistency check hack
+ };
+
+public:
+ // icc 8 requires this typedef to avoid an internal compiler error.
+ typedef void (LogMessage::*SendMethod)();
+
+ LogMessage(const char* file, int line, LogSeverity severity, int ctr,
+ SendMethod send_method);
+
+ // Two special constructors that generate reduced amounts of code at
+ // LOG call sites for common cases.
+
+ // Used for LOG(INFO): Implied are:
+ // severity = INFO, ctr = 0, send_method = &LogMessage::SendToLog.
+ //
+ // Using this constructor instead of the more complex constructor above
+ // saves 19 bytes per call site.
+ LogMessage(const char* file, int line);
+
+ // Used for LOG(severity) where severity != INFO. Implied
+ // are: ctr = 0, send_method = &LogMessage::SendToLog
+ //
+ // Using this constructor instead of the more complex constructor above
+ // saves 17 bytes per call site.
+ LogMessage(const char* file, int line, LogSeverity severity);
+
+ // Constructor to log this message to a specified sink (if not NULL).
+ // Implied are: ctr = 0, send_method = &LogMessage::SendToSinkAndLog if
+ // also_send_to_log is true, send_method = &LogMessage::SendToSink otherwise.
+ LogMessage(const char* file, int line, LogSeverity severity, LogSink* sink,
+ bool also_send_to_log);
+
+ // Constructor where we also give a vector<string> pointer
+ // for storing the messages (if the pointer is not NULL).
+ // Implied are: ctr = 0, send_method = &LogMessage::SaveOrSendToLog.
+ LogMessage(const char* file, int line, LogSeverity severity,
+ std::vector<std::string>* outvec);
+
+ // Constructor where we also give a string pointer for storing the
+ // message (if the pointer is not NULL). Implied are: ctr = 0,
+ // send_method = &LogMessage::WriteToStringAndLog.
+ LogMessage(const char* file, int line, LogSeverity severity,
+ std::string* message);
+
+ // A special constructor used for check failures
+ LogMessage(const char* file, int line, const CheckOpString& result);
+
+ ~LogMessage();
+
+ // Flush a buffered message to the sink set in the constructor. Always
+ // called by the destructor, it may also be called from elsewhere if
+ // needed. Only the first call is actioned; any later ones are ignored.
+ void Flush();
+
+ // An arbitrary limit on the length of a single log message. This
+ // is so that streaming can be done more efficiently.
+ static const size_t kMaxLogMessageLen;
+
+ // Theses should not be called directly outside of logging.*,
+ // only passed as SendMethod arguments to other LogMessage methods:
+ void SendToLog(); // Actually dispatch to the logs
+ void SendToSyslogAndLog(); // Actually dispatch to syslog and the logs
+
+ // Call abort() or similar to perform LOG(FATAL) crash.
+ static void Fail() __attribute__ ((noreturn));
+
+ std::ostream& stream() { return *(data_->stream_); }
+
+ int preserved_errno() const { return data_->preserved_errno_; }
+
+ // Must be called without the log_mutex held. (L < log_mutex)
+ static int64 num_messages(int severity);
+
+private:
+ // Fully internal SendMethod cases:
+ void SendToSinkAndLog(); // Send to sink if provided and dispatch to the logs
+ void SendToSink(); // Send to sink if provided, do nothing otherwise.
+
+ // Write to string if provided and dispatch to the logs.
+ void WriteToStringAndLog();
+
+ void SaveOrSendToLog(); // Save to stringvec if provided, else to logs
+
+ void Init(const char* file, int line, LogSeverity severity,
+ void (LogMessage::*send_method)());
+
+ // Used to fill in crash information during LOG(FATAL) failures.
+ void RecordCrashReason(glog_internal_namespace_::CrashReason* reason);
+
+ // Counts of messages sent at each priority:
+ static int64 num_messages_[NUM_SEVERITIES]; // under log_mutex
+
+ // We keep the data in a separate struct so that each instance of
+ // LogMessage uses less stack space.
+ struct GOOGLE_GLOG_DLL_DECL LogMessageData {
+ LogMessageData() {};
+
+ int preserved_errno_; // preserved errno
+ char* buf_;
+ char* message_text_; // Complete message text (points to selected buffer)
+ LogStream* stream_alloc_;
+ LogStream* stream_;
+ char severity_; // What level is this LogMessage logged at?
+ int line_; // line number where logging call is.
+ void (LogMessage::*send_method_)(); // Call this in destructor to send
+ union { // At most one of these is used: union to keep the size low.
+ LogSink* sink_; // NULL or sink to send message to
+ std::vector<std::string>* outvec_; // NULL or vector to push message onto
+ std::string* message_; // NULL or string to write message into
+ };
+ time_t timestamp_; // Time of creation of LogMessage
+ struct ::tm tm_time_; // Time of creation of LogMessage
+ size_t num_prefix_chars_; // # of chars of prefix in this message
+ size_t num_chars_to_log_; // # of chars of msg to send to log
+ size_t num_chars_to_syslog_; // # of chars of msg to send to syslog
+ const char* basename_; // basename of file that called LOG
+ const char* fullname_; // fullname of file that called LOG
+ bool has_been_flushed_; // false => data has not been flushed
+ bool first_fatal_; // true => this was first fatal msg
+
+ ~LogMessageData();
+ private:
+ LogMessageData(const LogMessageData&);
+ void operator=(const LogMessageData&);
+ };
+
+ static LogMessageData fatal_msg_data_exclusive_;
+ static LogMessageData fatal_msg_data_shared_;
+
+ LogMessageData* allocated_;
+ LogMessageData* data_;
+
+ friend class LogDestination;
+
+ LogMessage(const LogMessage&);
+ void operator=(const LogMessage&);
+};
+
+// This class happens to be thread-hostile because all instances share
+// a single data buffer, but since it can only be created just before
+// the process dies, we don't worry so much.
+class GOOGLE_GLOG_DLL_DECL LogMessageFatal : public LogMessage {
+ public:
+ LogMessageFatal(const char* file, int line);
+ LogMessageFatal(const char* file, int line, const CheckOpString& result);
+ ~LogMessageFatal() __attribute__ ((noreturn));
+};
+
+// A non-macro interface to the log facility; (useful
+// when the logging level is not a compile-time constant).
+inline void LogAtLevel(int const severity, std::string const &msg) {
+ LogMessage(__FILE__, __LINE__, severity).stream() << msg;
+}
+
+// A macro alternative of LogAtLevel. New code may want to use this
+// version since there are two advantages: 1. this version outputs the
+// file name and the line number where this macro is put like other
+// LOG macros, 2. this macro can be used as C++ stream.
+#define LOG_AT_LEVEL(severity) google::LogMessage(__FILE__, __LINE__, severity).stream()
+
+// A small helper for CHECK_NOTNULL().
+template <typename T>
+T* CheckNotNull(const char *file, int line, const char *names, T* t) {
+ if (t == NULL) {
+ LogMessageFatal(file, line, new std::string(names));
+ }
+ return t;
+}
+
+// Allow folks to put a counter in the LOG_EVERY_X()'ed messages. This
+// only works if ostream is a LogStream. If the ostream is not a
+// LogStream you'll get an assert saying as much at runtime.
+GOOGLE_GLOG_DLL_DECL std::ostream& operator<<(std::ostream &os,
+ const PRIVATE_Counter&);
+
+
+// Derived class for PLOG*() above.
+class GOOGLE_GLOG_DLL_DECL ErrnoLogMessage : public LogMessage {
+ public:
+
+ ErrnoLogMessage(const char* file, int line, LogSeverity severity, int ctr,
+ void (LogMessage::*send_method)());
+
+ // Postpends ": strerror(errno) [errno]".
+ ~ErrnoLogMessage();
+
+ private:
+ ErrnoLogMessage(const ErrnoLogMessage&);
+ void operator=(const ErrnoLogMessage&);
+};
+
+
+// This class is used to explicitly ignore values in the conditional
+// logging macros. This avoids compiler warnings like "value computed
+// is not used" and "statement has no effect".
+
+class GOOGLE_GLOG_DLL_DECL LogMessageVoidify {
+ public:
+ LogMessageVoidify() { }
+ // This has to be an operator with a precedence lower than << but
+ // higher than ?:
+ void operator&(std::ostream&) { }
+};
+
+
+// Flushes all log files that contains messages that are at least of
+// the specified severity level. Thread-safe.
+GOOGLE_GLOG_DLL_DECL void FlushLogFiles(LogSeverity min_severity);
+
+// Flushes all log files that contains messages that are at least of
+// the specified severity level. Thread-hostile because it ignores
+// locking -- used for catastrophic failures.
+GOOGLE_GLOG_DLL_DECL void FlushLogFilesUnsafe(LogSeverity min_severity);
+
+//
+// Set the destination to which a particular severity level of log
+// messages is sent. If base_filename is "", it means "don't log this
+// severity". Thread-safe.
+//
+GOOGLE_GLOG_DLL_DECL void SetLogDestination(LogSeverity severity,
+ const char* base_filename);
+
+//
+// Set the basename of the symlink to the latest log file at a given
+// severity. If symlink_basename is empty, do not make a symlink. If
+// you don't call this function, the symlink basename is the
+// invocation name of the program. Thread-safe.
+//
+GOOGLE_GLOG_DLL_DECL void SetLogSymlink(LogSeverity severity,
+ const char* symlink_basename);
+
+//
+// Used to send logs to some other kind of destination
+// Users should subclass LogSink and override send to do whatever they want.
+// Implementations must be thread-safe because a shared instance will
+// be called from whichever thread ran the LOG(XXX) line.
+class GOOGLE_GLOG_DLL_DECL LogSink {
+ public:
+ virtual ~LogSink();
+
+ // Sink's logging logic (message_len is such as to exclude '\n' at the end).
+ // This method can't use LOG() or CHECK() as logging system mutex(s) are held
+ // during this call.
+ virtual void send(LogSeverity severity, const char* full_filename,
+ const char* base_filename, int line,
+ const struct ::tm* tm_time,
+ const char* message, size_t message_len) = 0;
+
+ // Redefine this to implement waiting for
+ // the sink's logging logic to complete.
+ // It will be called after each send() returns,
+ // but before that LogMessage exits or crashes.
+ // By default this function does nothing.
+ // Using this function one can implement complex logic for send()
+ // that itself involves logging; and do all this w/o causing deadlocks and
+ // inconsistent rearrangement of log messages.
+ // E.g. if a LogSink has thread-specific actions, the send() method
+ // can simply add the message to a queue and wake up another thread that
+ // handles real logging while itself making some LOG() calls;
+ // WaitTillSent() can be implemented to wait for that logic to complete.
+ // See our unittest for an example.
+ virtual void WaitTillSent();
+
+ // Returns the normal text output of the log message.
+ // Can be useful to implement send().
+ static std::string ToString(LogSeverity severity, const char* file, int line,
+ const struct ::tm* tm_time,
+ const char* message, size_t message_len);
+};
+
+// Add or remove a LogSink as a consumer of logging data. Thread-safe.
+GOOGLE_GLOG_DLL_DECL void AddLogSink(LogSink *destination);
+GOOGLE_GLOG_DLL_DECL void RemoveLogSink(LogSink *destination);
+
+//
+// Specify an "extension" added to the filename specified via
+// SetLogDestination. This applies to all severity levels. It's
+// often used to append the port we're listening on to the logfile
+// name. Thread-safe.
+//
+GOOGLE_GLOG_DLL_DECL void SetLogFilenameExtension(
+ const char* filename_extension);
+
+//
+// Make it so that all log messages of at least a particular severity
+// are logged to stderr (in addition to logging to the usual log
+// file(s)). Thread-safe.
+//
+GOOGLE_GLOG_DLL_DECL void SetStderrLogging(LogSeverity min_severity);
+
+//
+// Make it so that all log messages go only to stderr. Thread-safe.
+//
+GOOGLE_GLOG_DLL_DECL void LogToStderr();
+
+//
+// Make it so that all log messages of at least a particular severity are
+// logged via email to a list of addresses (in addition to logging to the
+// usual log file(s)). The list of addresses is just a string containing
+// the email addresses to send to (separated by spaces, say). Thread-safe.
+//
+GOOGLE_GLOG_DLL_DECL void SetEmailLogging(LogSeverity min_severity,
+ const char* addresses);
+
+// A simple function that sends email. dest is a commma-separated
+// list of addressess. Thread-safe.
+GOOGLE_GLOG_DLL_DECL bool SendEmail(const char *dest,
+ const char *subject, const char *body);
+
+GOOGLE_GLOG_DLL_DECL const std::vector<std::string>& GetLoggingDirectories();
+
+// For tests only: Clear the internal [cached] list of logging directories to
+// force a refresh the next time GetLoggingDirectories is called.
+// Thread-hostile.
+void TestOnly_ClearLoggingDirectoriesList();
+
+// Returns a set of existing temporary directories, which will be a
+// subset of the directories returned by GetLogginDirectories().
+// Thread-safe.
+GOOGLE_GLOG_DLL_DECL void GetExistingTempDirectories(
+ std::vector<std::string>* list);
+
+// Print any fatal message again -- useful to call from signal handler
+// so that the last thing in the output is the fatal message.
+// Thread-hostile, but a race is unlikely.
+GOOGLE_GLOG_DLL_DECL void ReprintFatalMessage();
+
+// Truncate a log file that may be the append-only output of multiple
+// processes and hence can't simply be renamed/reopened (typically a
+// stdout/stderr). If the file "path" is > "limit" bytes, copy the
+// last "keep" bytes to offset 0 and truncate the rest. Since we could
+// be racing with other writers, this approach has the potential to
+// lose very small amounts of data. For security, only follow symlinks
+// if the path is /proc/self/fd/*
+GOOGLE_GLOG_DLL_DECL void TruncateLogFile(const char *path,
+ int64 limit, int64 keep);
+
+// Truncate stdout and stderr if they are over the value specified by
+// --max_log_size; keep the final 1MB. This function has the same
+// race condition as TruncateLogFile.
+GOOGLE_GLOG_DLL_DECL void TruncateStdoutStderr();
+
+// Return the string representation of the provided LogSeverity level.
+// Thread-safe.
+GOOGLE_GLOG_DLL_DECL const char* GetLogSeverityName(LogSeverity severity);
+
+// ---------------------------------------------------------------------
+// Implementation details that are not useful to most clients
+// ---------------------------------------------------------------------
+
+// A Logger is the interface used by logging modules to emit entries
+// to a log. A typical implementation will dump formatted data to a
+// sequence of files. We also provide interfaces that will forward
+// the data to another thread so that the invoker never blocks.
+// Implementations should be thread-safe since the logging system
+// will write to them from multiple threads.
+
+namespace base {
+
+class GOOGLE_GLOG_DLL_DECL Logger {
+ public:
+ virtual ~Logger();
+
+ // Writes "message[0,message_len-1]" corresponding to an event that
+ // occurred at "timestamp". If "force_flush" is true, the log file
+ // is flushed immediately.
+ //
+ // The input message has already been formatted as deemed
+ // appropriate by the higher level logging facility. For example,
+ // textual log messages already contain timestamps, and the
+ // file:linenumber header.
+ virtual void Write(bool force_flush,
+ time_t timestamp,
+ const char* message,
+ int message_len) = 0;
+
+ // Flush any buffered messages
+ virtual void Flush() = 0;
+
+ // Get the current LOG file size.
+ // The returned value is approximate since some
+ // logged data may not have been flushed to disk yet.
+ virtual uint32 LogSize() = 0;
+};
+
+// Get the logger for the specified severity level. The logger
+// remains the property of the logging module and should not be
+// deleted by the caller. Thread-safe.
+extern GOOGLE_GLOG_DLL_DECL Logger* GetLogger(LogSeverity level);
+
+// Set the logger for the specified severity level. The logger
+// becomes the property of the logging module and should not
+// be deleted by the caller. Thread-safe.
+extern GOOGLE_GLOG_DLL_DECL void SetLogger(LogSeverity level, Logger* logger);
+
+}
+
+// glibc has traditionally implemented two incompatible versions of
+// strerror_r(). There is a poorly defined convention for picking the
+// version that we want, but it is not clear whether it even works with
+// all versions of glibc.
+// So, instead, we provide this wrapper that automatically detects the
+// version that is in use, and then implements POSIX semantics.
+// N.B. In addition to what POSIX says, we also guarantee that "buf" will
+// be set to an empty string, if this function failed. This means, in most
+// cases, you do not need to check the error code and you can directly
+// use the value of "buf". It will never have an undefined value.
+GOOGLE_GLOG_DLL_DECL int posix_strerror_r(int err, char *buf, size_t len);
+
+
+// A class for which we define operator<<, which does nothing.
+class GOOGLE_GLOG_DLL_DECL NullStream : public LogMessage::LogStream {
+ public:
+ // Initialize the LogStream so the messages can be written somewhere
+ // (they'll never be actually displayed). This will be needed if a
+ // NullStream& is implicitly converted to LogStream&, in which case
+ // the overloaded NullStream::operator<< will not be invoked.
+ NullStream() : LogMessage::LogStream(message_buffer_, 1, 0) { }
+ NullStream(const char* /*file*/, int /*line*/,
+ const CheckOpString& /*result*/) :
+ LogMessage::LogStream(message_buffer_, 1, 0) { }
+ NullStream &stream() { return *this; }
+ private:
+ // A very short buffer for messages (which we discard anyway). This
+ // will be needed if NullStream& converted to LogStream& (e.g. as a
+ // result of a conditional expression).
+ char message_buffer_[2];
+};
+
+// Do nothing. This operator is inline, allowing the message to be
+// compiled away. The message will not be compiled away if we do
+// something like (flag ? LOG(INFO) : LOG(ERROR)) << message; when
+// SKIP_LOG=WARNING. In those cases, NullStream will be implicitly
+// converted to LogStream and the message will be computed and then
+// quietly discarded.
+template<class T>
+inline NullStream& operator<<(NullStream &str, const T &value) { return str; }
+
+// Similar to NullStream, but aborts the program (without stack
+// trace), like LogMessageFatal.
+class GOOGLE_GLOG_DLL_DECL NullStreamFatal : public NullStream {
+ public:
+ NullStreamFatal() { }
+ NullStreamFatal(const char* file, int line, const CheckOpString& result) :
+ NullStream(file, line, result) { }
+ __attribute__ ((noreturn)) ~NullStreamFatal() { _exit(1); }
+};
+
+// Install a signal handler that will dump signal information and a stack
+// trace when the program crashes on certain signals. We'll install the
+// signal handler for the following signals.
+//
+// SIGSEGV, SIGILL, SIGFPE, SIGABRT, SIGBUS, and SIGTERM.
+//
+// By default, the signal handler will write the failure dump to the
+// standard error. You can customize the destination by installing your
+// own writer function by InstallFailureWriter() below.
+//
+// Note on threading:
+//
+// The function should be called before threads are created, if you want
+// to use the failure signal handler for all threads. The stack trace
+// will be shown only for the thread that receives the signal. In other
+// words, stack traces of other threads won't be shown.
+GOOGLE_GLOG_DLL_DECL void InstallFailureSignalHandler();
+
+// Installs a function that is used for writing the failure dump. "data"
+// is the pointer to the beginning of a message to be written, and "size"
+// is the size of the message. You should not expect the data is
+// terminated with '\0'.
+GOOGLE_GLOG_DLL_DECL void InstallFailureWriter(
+ void (*writer)(const char* data, int size));
+
+}
+
+#endif // _LOGGING_H_
diff --git a/extern/libmv/third_party/glog/src/glog/raw_logging.h b/extern/libmv/third_party/glog/src/glog/raw_logging.h
new file mode 100644
index 00000000000..9e9b3772f3b
--- /dev/null
+++ b/extern/libmv/third_party/glog/src/glog/raw_logging.h
@@ -0,0 +1,185 @@
+// Copyright (c) 2006, Google Inc.
+// 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.
+//
+// Author: Maxim Lifantsev
+//
+// Thread-safe logging routines that do not allocate any memory or
+// acquire any locks, and can therefore be used by low-level memory
+// allocation and synchronization code.
+
+#ifndef BASE_RAW_LOGGING_H_
+#define BASE_RAW_LOGGING_H_
+
+#include <time.h>
+
+namespace google {
+
+#include "glog/log_severity.h"
+#include "glog/vlog_is_on.h"
+
+// Annoying stuff for windows -- makes sure clients can import these functions
+#ifndef GOOGLE_GLOG_DLL_DECL
+# if defined(_WIN32) && !defined(__CYGWIN__)
+# define GOOGLE_GLOG_DLL_DECL __declspec(dllimport)
+# else
+# define GOOGLE_GLOG_DLL_DECL
+# endif
+#endif
+
+// This is similar to LOG(severity) << format... and VLOG(level) << format..,
+// but
+// * it is to be used ONLY by low-level modules that can't use normal LOG()
+// * it is desiged to be a low-level logger that does not allocate any
+// memory and does not need any locks, hence:
+// * it logs straight and ONLY to STDERR w/o buffering
+// * it uses an explicit format and arguments list
+// * it will silently chop off really long message strings
+// Usage example:
+// RAW_LOG(ERROR, "Failed foo with %i: %s", status, error);
+// RAW_VLOG(3, "status is %i", status);
+// These will print an almost standard log lines like this to stderr only:
+// E0821 211317 file.cc:123] RAW: Failed foo with 22: bad_file
+// I0821 211317 file.cc:142] RAW: status is 20
+#define RAW_LOG(severity, ...) \
+ do { \
+ switch (google::severity) { \
+ case 0: \
+ RAW_LOG_INFO(__VA_ARGS__); \
+ break; \
+ case 1: \
+ RAW_LOG_WARNING(__VA_ARGS__); \
+ break; \
+ case 2: \
+ RAW_LOG_ERROR(__VA_ARGS__); \
+ break; \
+ case 3: \
+ RAW_LOG_FATAL(__VA_ARGS__); \
+ break; \
+ default: \
+ break; \
+ } \
+ } while (0)
+
+// The following STRIP_LOG testing is performed in the header file so that it's
+// possible to completely compile out the logging code and the log messages.
+#if STRIP_LOG == 0
+#define RAW_VLOG(verboselevel, ...) \
+ do { \
+ if (VLOG_IS_ON(verboselevel)) { \
+ RAW_LOG_INFO(__VA_ARGS__); \
+ } \
+ } while (0)
+#else
+#define RAW_VLOG(verboselevel, ...) RawLogStub__(0, __VA_ARGS__)
+#endif // STRIP_LOG == 0
+
+#if STRIP_LOG == 0
+#define RAW_LOG_INFO(...) google::RawLog__(google::INFO, \
+ __FILE__, __LINE__, __VA_ARGS__)
+#else
+#define RAW_LOG_INFO(...) google::RawLogStub__(0, __VA_ARGS__)
+#endif // STRIP_LOG == 0
+
+#if STRIP_LOG <= 1
+#define RAW_LOG_WARNING(...) google::RawLog__(google::WARNING, \
+ __FILE__, __LINE__, __VA_ARGS__)
+#else
+#define RAW_LOG_WARNING(...) google::RawLogStub__(0, __VA_ARGS__)
+#endif // STRIP_LOG <= 1
+
+#if STRIP_LOG <= 2
+#define RAW_LOG_ERROR(...) google::RawLog__(google::ERROR, \
+ __FILE__, __LINE__, __VA_ARGS__)
+#else
+#define RAW_LOG_ERROR(...) google::RawLogStub__(0, __VA_ARGS__)
+#endif // STRIP_LOG <= 2
+
+#if STRIP_LOG <= 3
+#define RAW_LOG_FATAL(...) google::RawLog__(google::FATAL, \
+ __FILE__, __LINE__, __VA_ARGS__)
+#else
+#define RAW_LOG_FATAL(...) \
+ do { \
+ google::RawLogStub__(0, __VA_ARGS__); \
+ exit(1); \
+ } while (0)
+#endif // STRIP_LOG <= 3
+
+// Similar to CHECK(condition) << message,
+// but for low-level modules: we use only RAW_LOG that does not allocate memory.
+// We do not want to provide args list here to encourage this usage:
+// if (!cond) RAW_LOG(FATAL, "foo ...", hard_to_compute_args);
+// so that the args are not computed when not needed.
+#define RAW_CHECK(condition, message) \
+ do { \
+ if (!(condition)) { \
+ RAW_LOG(FATAL, "Check %s failed: %s", #condition, message); \
+ } \
+ } while (0)
+
+// Debug versions of RAW_LOG and RAW_CHECK
+#ifndef NDEBUG
+
+#define RAW_DLOG(severity, ...) RAW_LOG(severity, __VA_ARGS__)
+#define RAW_DCHECK(condition, message) RAW_CHECK(condition, message)
+
+#else // NDEBUG
+
+#define RAW_DLOG(severity, ...) \
+ while (false) \
+ RAW_LOG(severity, __VA_ARGS__)
+#define RAW_DCHECK(condition, message) \
+ while (false) \
+ RAW_CHECK(condition, message)
+
+#endif // NDEBUG
+
+// Stub log function used to work around for unused variable warnings when
+// building with STRIP_LOG > 0.
+static inline void RawLogStub__(int ignored, ...) {
+}
+
+// Helper function to implement RAW_LOG and RAW_VLOG
+// Logs format... at "severity" level, reporting it
+// as called from file:line.
+// This does not allocate memory or acquire locks.
+GOOGLE_GLOG_DLL_DECL void RawLog__(LogSeverity severity,
+ const char* file,
+ int line,
+ const char* format, ...)
+ __attribute__((__format__ (__printf__, 4, 5)));
+
+// Hack to propagate time information into this module so that
+// this module does not have to directly call localtime_r(),
+// which could allocate memory.
+GOOGLE_GLOG_DLL_DECL void RawLog__SetLastTime(const struct tm& t, int usecs);
+
+}
+
+#endif // BASE_RAW_LOGGING_H_
diff --git a/extern/libmv/third_party/glog/src/glog/vlog_is_on.h b/extern/libmv/third_party/glog/src/glog/vlog_is_on.h
new file mode 100644
index 00000000000..02b0b867097
--- /dev/null
+++ b/extern/libmv/third_party/glog/src/glog/vlog_is_on.h
@@ -0,0 +1,129 @@
+// Copyright (c) 1999, 2007, Google Inc.
+// 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.
+//
+// Author: Ray Sidney and many others
+//
+// Defines the VLOG_IS_ON macro that controls the variable-verbosity
+// conditional logging.
+//
+// It's used by VLOG and VLOG_IF in logging.h
+// and by RAW_VLOG in raw_logging.h to trigger the logging.
+//
+// It can also be used directly e.g. like this:
+// if (VLOG_IS_ON(2)) {
+// // do some logging preparation and logging
+// // that can't be accomplished e.g. via just VLOG(2) << ...;
+// }
+//
+// The truth value that VLOG_IS_ON(level) returns is determined by
+// the three verbosity level flags:
+// --v=<n> Gives the default maximal active V-logging level;
+// 0 is the default.
+// Normally positive values are used for V-logging levels.
+// --vmodule=<str> Gives the per-module maximal V-logging levels to override
+// the value given by --v.
+// E.g. "my_module=2,foo*=3" would change the logging level
+// for all code in source files "my_module.*" and "foo*.*"
+// ("-inl" suffixes are also disregarded for this matching).
+//
+// SetVLOGLevel helper function is provided to do limited dynamic control over
+// V-logging by overriding the per-module settings given via --vmodule flag.
+//
+// CAVEAT: --vmodule functionality is not available in non gcc compilers.
+//
+
+#ifndef BASE_VLOG_IS_ON_H_
+#define BASE_VLOG_IS_ON_H_
+
+#include "glog/log_severity.h"
+
+// Annoying stuff for windows -- makes sure clients can import these functions
+#ifndef GOOGLE_GLOG_DLL_DECL
+# if defined(_WIN32) && !defined(__CYGWIN__)
+# define GOOGLE_GLOG_DLL_DECL __declspec(dllimport)
+# else
+# define GOOGLE_GLOG_DLL_DECL
+# endif
+#endif
+
+#if defined(__GNUC__)
+// We emit an anonymous static int* variable at every VLOG_IS_ON(n) site.
+// (Normally) the first time every VLOG_IS_ON(n) site is hit,
+// we determine what variable will dynamically control logging at this site:
+// it's either FLAGS_v or an appropriate internal variable
+// matching the current source file that represents results of
+// parsing of --vmodule flag and/or SetVLOGLevel calls.
+#define VLOG_IS_ON(verboselevel) \
+ __extension__ \
+ ({ static google::int32* vlocal__ = &google::kLogSiteUninitialized; \
+ google::int32 verbose_level__ = (verboselevel); \
+ (*vlocal__ >= verbose_level__) && \
+ ((vlocal__ != &google::kLogSiteUninitialized) || \
+ (google::InitVLOG3__(&vlocal__, &FLAGS_v, \
+ __FILE__, verbose_level__))); })
+#else
+// GNU extensions not available, so we do not support --vmodule.
+// Dynamic value of FLAGS_v always controls the logging level.
+#define VLOG_IS_ON(verboselevel) (FLAGS_v >= (verboselevel))
+#endif
+
+// Set VLOG(_IS_ON) level for module_pattern to log_level.
+// This lets us dynamically control what is normally set by the --vmodule flag.
+// Returns the level that previously applied to module_pattern.
+// NOTE: To change the log level for VLOG(_IS_ON) sites
+// that have already executed after/during InitGoogleLogging,
+// one needs to supply the exact --vmodule pattern that applied to them.
+// (If no --vmodule pattern applied to them
+// the value of FLAGS_v will continue to control them.)
+extern GOOGLE_GLOG_DLL_DECL int SetVLOGLevel(const char* module_pattern,
+ int log_level);
+
+// Various declarations needed for VLOG_IS_ON above: =========================
+
+// Special value used to indicate that a VLOG_IS_ON site has not been
+// initialized. We make this a large value, so the common-case check
+// of "*vlocal__ >= verbose_level__" in VLOG_IS_ON definition
+// passes in such cases and InitVLOG3__ is then triggered.
+extern google::int32 kLogSiteUninitialized;
+
+// Helper routine which determines the logging info for a particalur VLOG site.
+// site_flag is the address of the site-local pointer to the controlling
+// verbosity level
+// site_default is the default to use for *site_flag
+// fname is the current source file name
+// verbose_level is the argument to VLOG_IS_ON
+// We will return the return value for VLOG_IS_ON
+// and if possible set *site_flag appropriately.
+extern GOOGLE_GLOG_DLL_DECL bool InitVLOG3__(
+ google::int32** site_flag,
+ google::int32* site_default,
+ const char* fname,
+ google::int32 verbose_level);
+
+#endif // BASE_VLOG_IS_ON_H_
diff --git a/extern/libmv/third_party/glog/src/logging.cc b/extern/libmv/third_party/glog/src/logging.cc
new file mode 100644
index 00000000000..1bb3867aa10
--- /dev/null
+++ b/extern/libmv/third_party/glog/src/logging.cc
@@ -0,0 +1,1783 @@
+// Copyright (c) 1999, Google Inc.
+// 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.
+
+#define _GNU_SOURCE 1 // needed for O_NOFOLLOW and pread()/pwrite()
+
+#include "utilities.h"
+
+#include <assert.h>
+#include <iomanip>
+#include <string>
+#ifdef HAVE_UNISTD_H
+# include <unistd.h> // For _exit.
+#endif
+#include <climits>
+#include <sys/types.h>
+#include <sys/stat.h>
+#ifdef HAVE_SYS_UTSNAME_H
+# include <sys/utsname.h> // For uname.
+#endif
+#include <fcntl.h>
+#include <cstdio>
+#include <iostream>
+#include <stdarg.h>
+#include <stdlib.h>
+#ifdef HAVE_PWD_H
+# include <pwd.h>
+#endif
+#ifdef HAVE_SYSLOG_H
+# include <syslog.h>
+#endif
+#include <vector>
+#include <errno.h> // for errno
+#include <sstream>
+#include "base/commandlineflags.h" // to get the program name
+#include <glog/logging.h>
+#include <glog/raw_logging.h>
+#include "base/googleinit.h"
+
+#ifdef HAVE_STACKTRACE
+# include "stacktrace.h"
+#endif
+
+using std::string;
+using std::vector;
+using std::ostrstream;
+using std::setw;
+using std::setfill;
+using std::hex;
+using std::dec;
+using std::min;
+using std::ostream;
+using std::ostringstream;
+using std::strstream;
+
+// There is no thread annotation support.
+#define EXCLUSIVE_LOCKS_REQUIRED(mu)
+
+static bool BoolFromEnv(const char *varname, bool defval) {
+ const char* const valstr = getenv(varname);
+ if (!valstr) {
+ return defval;
+ }
+ return memchr("tTyY1\0", valstr[0], 6) != NULL;
+}
+
+GLOG_DEFINE_bool(logtostderr, BoolFromEnv("GOOGLE_LOGTOSTDERR", false),
+ "log messages go to stderr instead of logfiles");
+GLOG_DEFINE_bool(alsologtostderr, BoolFromEnv("GOOGLE_ALSOLOGTOSTDERR", false),
+ "log messages go to stderr in addition to logfiles");
+#ifdef OS_LINUX
+GLOG_DEFINE_bool(drop_log_memory, true, "Drop in-memory buffers of log contents. "
+ "Logs can grow very quickly and they are rarely read before they "
+ "need to be evicted from memory. Instead, drop them from memory "
+ "as soon as they are flushed to disk.");
+_START_GOOGLE_NAMESPACE_
+namespace logging {
+static const int64 kPageSize = getpagesize();
+}
+_END_GOOGLE_NAMESPACE_
+#endif
+
+// By default, errors (including fatal errors) get logged to stderr as
+// well as the file.
+//
+// The default is ERROR instead of FATAL so that users can see problems
+// when they run a program without having to look in another file.
+DEFINE_int32(stderrthreshold,
+ GOOGLE_NAMESPACE::ERROR,
+ "log messages at or above this level are copied to stderr in "
+ "addition to logfiles. This flag obsoletes --alsologtostderr.");
+
+GLOG_DEFINE_string(alsologtoemail, "",
+ "log messages go to these email addresses "
+ "in addition to logfiles");
+GLOG_DEFINE_bool(log_prefix, true,
+ "Prepend the log prefix to the start of each log line");
+GLOG_DEFINE_int32(minloglevel, 0, "Messages logged at a lower level than this don't "
+ "actually get logged anywhere");
+GLOG_DEFINE_int32(logbuflevel, 0,
+ "Buffer log messages logged at this level or lower"
+ " (-1 means don't buffer; 0 means buffer INFO only;"
+ " ...)");
+GLOG_DEFINE_int32(logbufsecs, 30,
+ "Buffer log messages for at most this many seconds");
+GLOG_DEFINE_int32(logemaillevel, 999,
+ "Email log messages logged at this level or higher"
+ " (0 means email all; 3 means email FATAL only;"
+ " ...)");
+GLOG_DEFINE_string(logmailer, "/bin/mail",
+ "Mailer used to send logging email");
+
+// Compute the default value for --log_dir
+static const char* DefaultLogDir() {
+ const char* env;
+ env = getenv("GOOGLE_LOG_DIR");
+ if (env != NULL && env[0] != '\0') {
+ return env;
+ }
+ env = getenv("TEST_TMPDIR");
+ if (env != NULL && env[0] != '\0') {
+ return env;
+ }
+ return "";
+}
+
+GLOG_DEFINE_string(log_dir, DefaultLogDir(),
+ "If specified, logfiles are written into this directory instead "
+ "of the default logging directory.");
+GLOG_DEFINE_string(log_link, "", "Put additional links to the log "
+ "files in this directory");
+
+GLOG_DEFINE_int32(max_log_size, 1800,
+ "approx. maximum log file size (in MB). A value of 0 will "
+ "be silently overridden to 1.");
+
+GLOG_DEFINE_bool(stop_logging_if_full_disk, false,
+ "Stop attempting to log to disk if the disk is full.");
+
+GLOG_DEFINE_string(log_backtrace_at, "",
+ "Emit a backtrace when logging at file:linenum.");
+
+// TODO(hamaji): consider windows
+#define PATH_SEPARATOR '/'
+
+static void GetHostName(string* hostname) {
+#if defined(HAVE_SYS_UTSNAME_H)
+ struct utsname buf;
+ if (0 != uname(&buf)) {
+ // ensure null termination on failure
+ *buf.nodename = '\0';
+ }
+ *hostname = buf.nodename;
+#elif defined(OS_WINDOWS)
+ char buf[MAX_COMPUTERNAME_LENGTH + 1];
+ DWORD len = MAX_COMPUTERNAME_LENGTH + 1;
+ if (GetComputerNameA(buf, &len)) {
+ *hostname = buf;
+ } else {
+ hostname->clear();
+ }
+#else
+# warning There is no way to retrieve the host name.
+ *hostname = "(unknown)";
+#endif
+}
+
+_START_GOOGLE_NAMESPACE_
+
+// Safely get max_log_size, overriding to 1 if it somehow gets defined as 0
+static int32 MaxLogSize() {
+ return (FLAGS_max_log_size > 0 ? FLAGS_max_log_size : 1);
+}
+
+// A mutex that allows only one thread to log at a time, to keep things from
+// getting jumbled. Some other very uncommon logging operations (like
+// changing the destination file for log messages of a given severity) also
+// lock this mutex. Please be sure that anybody who might possibly need to
+// lock it does so.
+static Mutex log_mutex;
+
+// Number of messages sent at each severity. Under log_mutex.
+int64 LogMessage::num_messages_[NUM_SEVERITIES] = {0, 0, 0, 0};
+
+// Globally disable log writing (if disk is full)
+static bool stop_writing = false;
+
+const char*const LogSeverityNames[NUM_SEVERITIES] = {
+ "INFO", "WARNING", "ERROR", "FATAL"
+};
+
+// Has the user called SetExitOnDFatal(true)?
+static bool exit_on_dfatal = true;
+
+const char* GetLogSeverityName(LogSeverity severity) {
+ return LogSeverityNames[severity];
+}
+
+static bool SendEmailInternal(const char*dest, const char *subject,
+ const char*body, bool use_logging);
+
+base::Logger::~Logger() {
+}
+
+namespace {
+
+// Encapsulates all file-system related state
+class LogFileObject : public base::Logger {
+ public:
+ LogFileObject(LogSeverity severity, const char* base_filename);
+ ~LogFileObject();
+
+ virtual void Write(bool force_flush, // Should we force a flush here?
+ time_t timestamp, // Timestamp for this entry
+ const char* message,
+ int message_len);
+
+ // Configuration options
+ void SetBasename(const char* basename);
+ void SetExtension(const char* ext);
+ void SetSymlinkBasename(const char* symlink_basename);
+
+ // Normal flushing routine
+ virtual void Flush();
+
+ // It is the actual file length for the system loggers,
+ // i.e., INFO, ERROR, etc.
+ virtual uint32 LogSize() {
+ MutexLock l(&lock_);
+ return file_length_;
+ }
+
+ // Internal flush routine. Exposed so that FlushLogFilesUnsafe()
+ // can avoid grabbing a lock. Usually Flush() calls it after
+ // acquiring lock_.
+ void FlushUnlocked();
+
+ private:
+ static const uint32 kRolloverAttemptFrequency = 0x20;
+
+ Mutex lock_;
+ bool base_filename_selected_;
+ string base_filename_;
+ string symlink_basename_;
+ string filename_extension_; // option users can specify (eg to add port#)
+ FILE* file_;
+ LogSeverity severity_;
+ uint32 bytes_since_flush_;
+ uint32 file_length_;
+ unsigned int rollover_attempt_;
+ int64 next_flush_time_; // cycle count at which to flush log
+
+ // Actually create a logfile using the value of base_filename_ and the
+ // supplied argument time_pid_string
+ // REQUIRES: lock_ is held
+ bool CreateLogfile(const char* time_pid_string);
+};
+
+} // namespace
+
+class LogDestination {
+ public:
+ friend class LogMessage;
+ friend void ReprintFatalMessage();
+ friend base::Logger* base::GetLogger(LogSeverity);
+ friend void base::SetLogger(LogSeverity, base::Logger*);
+
+ // These methods are just forwarded to by their global versions.
+ static void SetLogDestination(LogSeverity severity,
+ const char* base_filename);
+ static void SetLogSymlink(LogSeverity severity,
+ const char* symlink_basename);
+ static void AddLogSink(LogSink *destination);
+ static void RemoveLogSink(LogSink *destination);
+ static void SetLogFilenameExtension(const char* filename_extension);
+ static void SetStderrLogging(LogSeverity min_severity);
+ static void SetEmailLogging(LogSeverity min_severity, const char* addresses);
+ static void LogToStderr();
+ // Flush all log files that are at least at the given severity level
+ static void FlushLogFiles(int min_severity);
+ static void FlushLogFilesUnsafe(int min_severity);
+
+ // we set the maximum size of our packet to be 1400, the logic being
+ // to prevent fragmentation.
+ // Really this number is arbitrary.
+ static const int kNetworkBytes = 1400;
+
+ static const string& hostname();
+ private:
+
+ LogDestination(LogSeverity severity, const char* base_filename);
+ ~LogDestination() { }
+
+ // Take a log message of a particular severity and log it to stderr
+ // iff it's of a high enough severity to deserve it.
+ static void MaybeLogToStderr(LogSeverity severity, const char* message,
+ size_t len);
+
+ // Take a log message of a particular severity and log it to email
+ // iff it's of a high enough severity to deserve it.
+ static void MaybeLogToEmail(LogSeverity severity, const char* message,
+ size_t len);
+ // Take a log message of a particular severity and log it to a file
+ // iff the base filename is not "" (which means "don't log to me")
+ static void MaybeLogToLogfile(LogSeverity severity,
+ time_t timestamp,
+ const char* message, size_t len);
+ // Take a log message of a particular severity and log it to the file
+ // for that severity and also for all files with severity less than
+ // this severity.
+ static void LogToAllLogfiles(LogSeverity severity,
+ time_t timestamp,
+ const char* message, size_t len);
+
+ // Send logging info to all registered sinks.
+ static void LogToSinks(LogSeverity severity,
+ const char *full_filename,
+ const char *base_filename,
+ int line,
+ const struct ::tm* tm_time,
+ const char* message,
+ size_t message_len);
+
+ // Wait for all registered sinks via WaitTillSent
+ // including the optional one in "data".
+ static void WaitForSinks(LogMessage::LogMessageData* data);
+
+ static LogDestination* log_destination(LogSeverity severity);
+
+ LogFileObject fileobject_;
+ base::Logger* logger_; // Either &fileobject_, or wrapper around it
+
+ static LogDestination* log_destinations_[NUM_SEVERITIES];
+ static LogSeverity email_logging_severity_;
+ static string addresses_;
+ static string hostname_;
+
+ // arbitrary global logging destinations.
+ static vector<LogSink*>* sinks_;
+
+ // Protects the vector sinks_,
+ // but not the LogSink objects its elements reference.
+ static Mutex sink_mutex_;
+
+ // Disallow
+ LogDestination(const LogDestination&);
+ LogDestination& operator=(const LogDestination&);
+};
+
+// Errors do not get logged to email by default.
+LogSeverity LogDestination::email_logging_severity_ = 99999;
+
+string LogDestination::addresses_;
+string LogDestination::hostname_;
+
+vector<LogSink*>* LogDestination::sinks_ = NULL;
+Mutex LogDestination::sink_mutex_;
+
+/* static */
+const string& LogDestination::hostname() {
+ if (hostname_.empty()) {
+ GetHostName(&hostname_);
+ if (hostname_.empty()) {
+ hostname_ = "(unknown)";
+ }
+ }
+ return hostname_;
+}
+
+LogDestination::LogDestination(LogSeverity severity,
+ const char* base_filename)
+ : fileobject_(severity, base_filename),
+ logger_(&fileobject_) {
+}
+
+inline void LogDestination::FlushLogFilesUnsafe(int min_severity) {
+ // assume we have the log_mutex or we simply don't care
+ // about it
+ for (int i = min_severity; i < NUM_SEVERITIES; i++) {
+ LogDestination* log = log_destination(i);
+ if (log != NULL) {
+ // Flush the base fileobject_ logger directly instead of going
+ // through any wrappers to reduce chance of deadlock.
+ log->fileobject_.FlushUnlocked();
+ }
+ }
+}
+
+inline void LogDestination::FlushLogFiles(int min_severity) {
+ // Prevent any subtle race conditions by wrapping a mutex lock around
+ // all this stuff.
+ MutexLock l(&log_mutex);
+ for (int i = min_severity; i < NUM_SEVERITIES; i++) {
+ LogDestination* log = log_destination(i);
+ if (log != NULL) {
+ log->logger_->Flush();
+ }
+ }
+}
+
+inline void LogDestination::SetLogDestination(LogSeverity severity,
+ const char* base_filename) {
+ assert(severity >= 0 && severity < NUM_SEVERITIES);
+ // Prevent any subtle race conditions by wrapping a mutex lock around
+ // all this stuff.
+ MutexLock l(&log_mutex);
+ log_destination(severity)->fileobject_.SetBasename(base_filename);
+}
+
+inline void LogDestination::SetLogSymlink(LogSeverity severity,
+ const char* symlink_basename) {
+ CHECK_GE(severity, 0);
+ CHECK_LT(severity, NUM_SEVERITIES);
+ MutexLock l(&log_mutex);
+ log_destination(severity)->fileobject_.SetSymlinkBasename(symlink_basename);
+}
+
+inline void LogDestination::AddLogSink(LogSink *destination) {
+ // Prevent any subtle race conditions by wrapping a mutex lock around
+ // all this stuff.
+ MutexLock l(&sink_mutex_);
+ if (!sinks_) sinks_ = new vector<LogSink*>;
+ sinks_->push_back(destination);
+}
+
+inline void LogDestination::RemoveLogSink(LogSink *destination) {
+ // Prevent any subtle race conditions by wrapping a mutex lock around
+ // all this stuff.
+ MutexLock l(&sink_mutex_);
+ // This doesn't keep the sinks in order, but who cares?
+ if (sinks_) {
+ for (int i = sinks_->size() - 1; i >= 0; i--) {
+ if ((*sinks_)[i] == destination) {
+ (*sinks_)[i] = (*sinks_)[sinks_->size() - 1];
+ sinks_->pop_back();
+ break;
+ }
+ }
+ }
+}
+
+inline void LogDestination::SetLogFilenameExtension(const char* ext) {
+ // Prevent any subtle race conditions by wrapping a mutex lock around
+ // all this stuff.
+ MutexLock l(&log_mutex);
+ for ( int severity = 0; severity < NUM_SEVERITIES; ++severity ) {
+ log_destination(severity)->fileobject_.SetExtension(ext);
+ }
+}
+
+inline void LogDestination::SetStderrLogging(LogSeverity min_severity) {
+ assert(min_severity >= 0 && min_severity < NUM_SEVERITIES);
+ // Prevent any subtle race conditions by wrapping a mutex lock around
+ // all this stuff.
+ MutexLock l(&log_mutex);
+ FLAGS_stderrthreshold = min_severity;
+}
+
+inline void LogDestination::LogToStderr() {
+ // *Don't* put this stuff in a mutex lock, since SetStderrLogging &
+ // SetLogDestination already do the locking!
+ SetStderrLogging(0); // thus everything is "also" logged to stderr
+ for ( int i = 0; i < NUM_SEVERITIES; ++i ) {
+ SetLogDestination(i, ""); // "" turns off logging to a logfile
+ }
+}
+
+inline void LogDestination::SetEmailLogging(LogSeverity min_severity,
+ const char* addresses) {
+ assert(min_severity >= 0 && min_severity < NUM_SEVERITIES);
+ // Prevent any subtle race conditions by wrapping a mutex lock around
+ // all this stuff.
+ MutexLock l(&log_mutex);
+ LogDestination::email_logging_severity_ = min_severity;
+ LogDestination::addresses_ = addresses;
+}
+
+static void WriteToStderr(const char* message, size_t len) {
+ // Avoid using cerr from this module since we may get called during
+ // exit code, and cerr may be partially or fully destroyed by then.
+ write(STDERR_FILENO, message, len);
+}
+
+inline void LogDestination::MaybeLogToStderr(LogSeverity severity,
+ const char* message, size_t len) {
+ if ((severity >= FLAGS_stderrthreshold) || FLAGS_alsologtostderr) {
+ WriteToStderr(message, len);
+#ifdef OS_WINDOWS
+ // On Windows, also output to the debugger
+ ::OutputDebugStringA(string(message,len).c_str());
+#endif
+ }
+}
+
+
+inline void LogDestination::MaybeLogToEmail(LogSeverity severity,
+ const char* message, size_t len) {
+ if (severity >= email_logging_severity_ ||
+ severity >= FLAGS_logemaillevel) {
+ string to(FLAGS_alsologtoemail);
+ if (!addresses_.empty()) {
+ if (!to.empty()) {
+ to += ",";
+ }
+ to += addresses_;
+ }
+ const string subject(string("[LOG] ") + LogSeverityNames[severity] + ": " +
+ glog_internal_namespace_::ProgramInvocationShortName());
+ string body(hostname());
+ body += "\n\n";
+ body.append(message, len);
+
+ // should NOT use SendEmail(). The caller of this function holds the
+ // log_mutex and SendEmail() calls LOG/VLOG which will block trying to
+ // acquire the log_mutex object. Use SendEmailInternal() and set
+ // use_logging to false.
+ SendEmailInternal(to.c_str(), subject.c_str(), body.c_str(), false);
+ }
+}
+
+
+inline void LogDestination::MaybeLogToLogfile(LogSeverity severity,
+ time_t timestamp,
+ const char* message,
+ size_t len) {
+ const bool should_flush = severity > FLAGS_logbuflevel;
+ LogDestination* destination = log_destination(severity);
+ destination->logger_->Write(should_flush, timestamp, message, len);
+}
+
+inline void LogDestination::LogToAllLogfiles(LogSeverity severity,
+ time_t timestamp,
+ const char* message,
+ size_t len) {
+
+ if ( FLAGS_logtostderr ) // global flag: never log to file
+ WriteToStderr(message, len);
+ else
+ for (int i = severity; i >= 0; --i)
+ LogDestination::MaybeLogToLogfile(i, timestamp, message, len);
+
+}
+
+inline void LogDestination::LogToSinks(LogSeverity severity,
+ const char *full_filename,
+ const char *base_filename,
+ int line,
+ const struct ::tm* tm_time,
+ const char* message,
+ size_t message_len) {
+ ReaderMutexLock l(&sink_mutex_);
+ if (sinks_) {
+ for (int i = sinks_->size() - 1; i >= 0; i--) {
+ (*sinks_)[i]->send(severity, full_filename, base_filename,
+ line, tm_time, message, message_len);
+ }
+ }
+}
+
+inline void LogDestination::WaitForSinks(LogMessage::LogMessageData* data) {
+ ReaderMutexLock l(&sink_mutex_);
+ if (sinks_) {
+ for (int i = sinks_->size() - 1; i >= 0; i--) {
+ (*sinks_)[i]->WaitTillSent();
+ }
+ }
+ const bool send_to_sink =
+ (data->send_method_ == &LogMessage::SendToSink) ||
+ (data->send_method_ == &LogMessage::SendToSinkAndLog);
+ if (send_to_sink && data->sink_ != NULL) {
+ data->sink_->WaitTillSent();
+ }
+}
+
+LogDestination* LogDestination::log_destinations_[NUM_SEVERITIES];
+
+inline LogDestination* LogDestination::log_destination(LogSeverity severity) {
+ assert(severity >=0 && severity < NUM_SEVERITIES);
+ if (!log_destinations_[severity]) {
+ log_destinations_[severity] = new LogDestination(severity, NULL);
+ }
+ return log_destinations_[severity];
+}
+
+namespace {
+
+LogFileObject::LogFileObject(LogSeverity severity,
+ const char* base_filename)
+ : base_filename_selected_(base_filename != NULL),
+ base_filename_((base_filename != NULL) ? base_filename : ""),
+ symlink_basename_(glog_internal_namespace_::ProgramInvocationShortName()),
+ filename_extension_(),
+ file_(NULL),
+ severity_(severity),
+ bytes_since_flush_(0),
+ file_length_(0),
+ rollover_attempt_(kRolloverAttemptFrequency-1),
+ next_flush_time_(0) {
+ assert(severity >= 0);
+ assert(severity < NUM_SEVERITIES);
+}
+
+LogFileObject::~LogFileObject() {
+ MutexLock l(&lock_);
+ if (file_ != NULL) {
+ fclose(file_);
+ file_ = NULL;
+ }
+}
+
+void LogFileObject::SetBasename(const char* basename) {
+ MutexLock l(&lock_);
+ base_filename_selected_ = true;
+ if (base_filename_ != basename) {
+ // Get rid of old log file since we are changing names
+ if (file_ != NULL) {
+ fclose(file_);
+ file_ = NULL;
+ rollover_attempt_ = kRolloverAttemptFrequency-1;
+ }
+ base_filename_ = basename;
+ }
+}
+
+void LogFileObject::SetExtension(const char* ext) {
+ MutexLock l(&lock_);
+ if (filename_extension_ != ext) {
+ // Get rid of old log file since we are changing names
+ if (file_ != NULL) {
+ fclose(file_);
+ file_ = NULL;
+ rollover_attempt_ = kRolloverAttemptFrequency-1;
+ }
+ filename_extension_ = ext;
+ }
+}
+
+void LogFileObject::SetSymlinkBasename(const char* symlink_basename) {
+ MutexLock l(&lock_);
+ symlink_basename_ = symlink_basename;
+}
+
+void LogFileObject::Flush() {
+ MutexLock l(&lock_);
+ FlushUnlocked();
+}
+
+void LogFileObject::FlushUnlocked(){
+ if (file_ != NULL) {
+ fflush(file_);
+ bytes_since_flush_ = 0;
+ }
+ // Figure out when we are due for another flush.
+ const int64 next = (FLAGS_logbufsecs
+ * static_cast<int64>(1000000)); // in usec
+ next_flush_time_ = CycleClock_Now() + UsecToCycles(next);
+}
+
+bool LogFileObject::CreateLogfile(const char* time_pid_string) {
+ string string_filename = base_filename_+filename_extension_+
+ time_pid_string;
+ const char* filename = string_filename.c_str();
+ int fd = open(filename, O_WRONLY | O_CREAT | O_EXCL, 0664);
+ if (fd == -1) return false;
+#ifdef HAVE_FCNTL
+ // Mark the file close-on-exec. We don't really care if this fails
+ fcntl(fd, F_SETFD, FD_CLOEXEC);
+#endif
+
+ file_ = fdopen(fd, "a"); // Make a FILE*.
+ if (file_ == NULL) { // Man, we're screwed!
+ close(fd);
+ unlink(filename); // Erase the half-baked evidence: an unusable log file
+ return false;
+ }
+
+ // We try to create a symlink called <program_name>.<severity>,
+ // which is easier to use. (Every time we create a new logfile,
+ // we destroy the old symlink and create a new one, so it always
+ // points to the latest logfile.) If it fails, we're sad but it's
+ // no error.
+ if (!symlink_basename_.empty()) {
+ // take directory from filename
+ const char* slash = strrchr(filename, PATH_SEPARATOR);
+ const string linkname =
+ symlink_basename_ + '.' + LogSeverityNames[severity_];
+ string linkpath;
+ if ( slash ) linkpath = string(filename, slash-filename+1); // get dirname
+ linkpath += linkname;
+ unlink(linkpath.c_str()); // delete old one if it exists
+
+ // We must have unistd.h.
+#ifdef HAVE_UNISTD_H
+ // Make the symlink be relative (in the same dir) so that if the
+ // entire log directory gets relocated the link is still valid.
+ const char *linkdest = slash ? (slash + 1) : filename;
+ symlink(linkdest, linkpath.c_str()); // silently ignore failures
+
+ // Make an additional link to the log file in a place specified by
+ // FLAGS_log_link, if indicated
+ if (!FLAGS_log_link.empty()) {
+ linkpath = FLAGS_log_link + "/" + linkname;
+ unlink(linkpath.c_str()); // delete old one if it exists
+ symlink(filename, linkpath.c_str()); // silently ignore failures
+ }
+#endif
+ }
+
+ return true; // Everything worked
+}
+
+void LogFileObject::Write(bool force_flush,
+ time_t timestamp,
+ const char* message,
+ int message_len) {
+ MutexLock l(&lock_);
+
+ // We don't log if the base_name_ is "" (which means "don't write")
+ if (base_filename_selected_ && base_filename_.empty()) {
+ return;
+ }
+
+ if (static_cast<int>(file_length_ >> 20) >= MaxLogSize()) {
+ if (file_ != NULL) fclose(file_);
+ file_ = NULL;
+ file_length_ = bytes_since_flush_ = 0;
+ rollover_attempt_ = kRolloverAttemptFrequency-1;
+ }
+
+ // If there's no destination file, make one before outputting
+ if (file_ == NULL) {
+ // Try to rollover the log file every 32 log messages. The only time
+ // this could matter would be when we have trouble creating the log
+ // file. If that happens, we'll lose lots of log messages, of course!
+ if (++rollover_attempt_ != kRolloverAttemptFrequency) return;
+ rollover_attempt_ = 0;
+
+ struct ::tm tm_time;
+ localtime_r(&timestamp, &tm_time);
+
+ // The logfile's filename will have the date/time & pid in it
+ char time_pid_string[256]; // More than enough chars for time, pid, \0
+ ostrstream time_pid_stream(time_pid_string, sizeof(time_pid_string));
+ time_pid_stream.fill('0');
+ time_pid_stream << 1900+tm_time.tm_year
+ << setw(2) << 1+tm_time.tm_mon
+ << setw(2) << tm_time.tm_mday
+ << '-'
+ << setw(2) << tm_time.tm_hour
+ << setw(2) << tm_time.tm_min
+ << setw(2) << tm_time.tm_sec
+ << '.'
+ << GetMainThreadPid()
+ << '\0';
+
+ if (base_filename_selected_) {
+ if (!CreateLogfile(time_pid_string)) {
+ perror("Could not create log file");
+ fprintf(stderr, "COULD NOT CREATE LOGFILE '%s'!\n", time_pid_string);
+ return;
+ }
+ } else {
+ // If no base filename for logs of this severity has been set, use a
+ // default base filename of
+ // "<program name>.<hostname>.<user name>.log.<severity level>.". So
+ // logfiles will have names like
+ // webserver.examplehost.root.log.INFO.19990817-150000.4354, where
+ // 19990817 is a date (1999 August 17), 150000 is a time (15:00:00),
+ // and 4354 is the pid of the logging process. The date & time reflect
+ // when the file was created for output.
+ //
+ // Where does the file get put? Successively try the directories
+ // "/tmp", and "."
+ string stripped_filename(
+ glog_internal_namespace_::ProgramInvocationShortName());
+ string hostname;
+ GetHostName(&hostname);
+
+ string uidname = MyUserName();
+ // We should not call CHECK() here because this function can be
+ // called after holding on to log_mutex. We don't want to
+ // attempt to hold on to the same mutex, and get into a
+ // deadlock. Simply use a name like invalid-user.
+ if (uidname.empty()) uidname = "invalid-user";
+
+ stripped_filename = stripped_filename+'.'+hostname+'.'
+ +uidname+".log."
+ +LogSeverityNames[severity_]+'.';
+ // We're going to (potentially) try to put logs in several different dirs
+ const vector<string> & log_dirs = GetLoggingDirectories();
+
+ // Go through the list of dirs, and try to create the log file in each
+ // until we succeed or run out of options
+ bool success = false;
+ for (vector<string>::const_iterator dir = log_dirs.begin();
+ dir != log_dirs.end();
+ ++dir) {
+ base_filename_ = *dir + "/" + stripped_filename;
+ if ( CreateLogfile(time_pid_string) ) {
+ success = true;
+ break;
+ }
+ }
+ // If we never succeeded, we have to give up
+ if ( success == false ) {
+ perror("Could not create logging file");
+ fprintf(stderr, "COULD NOT CREATE A LOGGINGFILE %s!", time_pid_string);
+ return;
+ }
+ }
+
+ // Write a header message into the log file
+ char file_header_string[512]; // Enough chars for time and binary info
+ ostrstream file_header_stream(file_header_string,
+ sizeof(file_header_string));
+ file_header_stream.fill('0');
+ file_header_stream << "Log file created at: "
+ << 1900+tm_time.tm_year << '/'
+ << setw(2) << 1+tm_time.tm_mon << '/'
+ << setw(2) << tm_time.tm_mday
+ << ' '
+ << setw(2) << tm_time.tm_hour << ':'
+ << setw(2) << tm_time.tm_min << ':'
+ << setw(2) << tm_time.tm_sec << '\n'
+ << "Running on machine: "
+ << LogDestination::hostname() << '\n'
+ << "Log line format: [IWEF]mmdd hh:mm:ss.uuuuuu "
+ << "threadid file:line] msg" << '\n'
+ << '\0';
+ int header_len = strlen(file_header_string);
+ fwrite(file_header_string, 1, header_len, file_);
+ file_length_ += header_len;
+ bytes_since_flush_ += header_len;
+ }
+
+ // Write to LOG file
+ if ( !stop_writing ) {
+ // fwrite() doesn't return an error when the disk is full, for
+ // messages that are less than 4096 bytes. When the disk is full,
+ // it returns the message length for messages that are less than
+ // 4096 bytes. fwrite() returns 4096 for message lengths that are
+ // greater than 4096, thereby indicating an error.
+ errno = 0;
+ fwrite(message, 1, message_len, file_);
+ if ( FLAGS_stop_logging_if_full_disk &&
+ errno == ENOSPC ) { // disk full, stop writing to disk
+ stop_writing = true; // until the disk is
+ return;
+ } else {
+ file_length_ += message_len;
+ bytes_since_flush_ += message_len;
+ }
+ } else {
+ if ( CycleClock_Now() >= next_flush_time_ )
+ stop_writing = false; // check to see if disk has free space.
+ return; // no need to flush
+ }
+
+ // See important msgs *now*. Also, flush logs at least every 10^6 chars,
+ // or every "FLAGS_logbufsecs" seconds.
+ if ( force_flush ||
+ (bytes_since_flush_ >= 1000000) ||
+ (CycleClock_Now() >= next_flush_time_) ) {
+ FlushUnlocked();
+#ifdef OS_LINUX
+ if (FLAGS_drop_log_memory) {
+ if (file_length_ >= logging::kPageSize) {
+ // don't evict the most recent page
+ uint32 len = file_length_ & ~(logging::kPageSize - 1);
+ posix_fadvise(fileno(file_), 0, len, POSIX_FADV_DONTNEED);
+ }
+ }
+#endif
+ }
+}
+
+} // namespace
+
+// An arbitrary limit on the length of a single log message. This
+// is so that streaming can be done more efficiently.
+const size_t LogMessage::kMaxLogMessageLen = 30000;
+
+// Static log data space to avoid alloc failures in a LOG(FATAL)
+//
+// Since multiple threads may call LOG(FATAL), and we want to preserve
+// the data from the first call, we allocate two sets of space. One
+// for exclusive use by the first thread, and one for shared use by
+// all other threads.
+static Mutex fatal_msg_lock;
+static CrashReason crash_reason;
+static bool fatal_msg_exclusive = true;
+static char fatal_msg_buf_exclusive[LogMessage::kMaxLogMessageLen+1];
+static char fatal_msg_buf_shared[LogMessage::kMaxLogMessageLen+1];
+static LogMessage::LogStream fatal_msg_stream_exclusive(
+ fatal_msg_buf_exclusive, LogMessage::kMaxLogMessageLen, 0);
+static LogMessage::LogStream fatal_msg_stream_shared(
+ fatal_msg_buf_shared, LogMessage::kMaxLogMessageLen, 0);
+LogMessage::LogMessageData LogMessage::fatal_msg_data_exclusive_;
+LogMessage::LogMessageData LogMessage::fatal_msg_data_shared_;
+
+LogMessage::LogMessageData::~LogMessageData() {
+ delete[] buf_;
+ delete stream_alloc_;
+}
+
+LogMessage::LogMessage(const char* file, int line, LogSeverity severity,
+ int ctr, void (LogMessage::*send_method)()) {
+ Init(file, line, severity, send_method);
+ data_->stream_->set_ctr(ctr);
+}
+
+LogMessage::LogMessage(const char* file, int line,
+ const CheckOpString& result) {
+ Init(file, line, FATAL, &LogMessage::SendToLog);
+ stream() << "Check failed: " << (*result.str_) << " ";
+}
+
+LogMessage::LogMessage(const char* file, int line) {
+ Init(file, line, INFO, &LogMessage::SendToLog);
+}
+
+LogMessage::LogMessage(const char* file, int line, LogSeverity severity) {
+ Init(file, line, severity, &LogMessage::SendToLog);
+}
+
+LogMessage::LogMessage(const char* file, int line, LogSeverity severity,
+ LogSink* sink, bool also_send_to_log) {
+ Init(file, line, severity, also_send_to_log ? &LogMessage::SendToSinkAndLog :
+ &LogMessage::SendToSink);
+ data_->sink_ = sink; // override Init()'s setting to NULL
+}
+
+LogMessage::LogMessage(const char* file, int line, LogSeverity severity,
+ vector<string> *outvec) {
+ Init(file, line, severity, &LogMessage::SaveOrSendToLog);
+ data_->outvec_ = outvec; // override Init()'s setting to NULL
+}
+
+LogMessage::LogMessage(const char* file, int line, LogSeverity severity,
+ string *message) {
+ Init(file, line, severity, &LogMessage::WriteToStringAndLog);
+ data_->message_ = message; // override Init()'s setting to NULL
+}
+
+void LogMessage::Init(const char* file,
+ int line,
+ LogSeverity severity,
+ void (LogMessage::*send_method)()) {
+ allocated_ = NULL;
+ if (severity != FATAL || !exit_on_dfatal) {
+ allocated_ = new LogMessageData();
+ data_ = allocated_;
+ data_->buf_ = new char[kMaxLogMessageLen+1];
+ data_->message_text_ = data_->buf_;
+ data_->stream_alloc_ =
+ new LogStream(data_->message_text_, kMaxLogMessageLen, 0);
+ data_->stream_ = data_->stream_alloc_;
+ data_->first_fatal_ = false;
+ } else {
+ MutexLock l(&fatal_msg_lock);
+ if (fatal_msg_exclusive) {
+ fatal_msg_exclusive = false;
+ data_ = &fatal_msg_data_exclusive_;
+ data_->message_text_ = fatal_msg_buf_exclusive;
+ data_->stream_ = &fatal_msg_stream_exclusive;
+ data_->first_fatal_ = true;
+ } else {
+ data_ = &fatal_msg_data_shared_;
+ data_->message_text_ = fatal_msg_buf_shared;
+ data_->stream_ = &fatal_msg_stream_shared;
+ data_->first_fatal_ = false;
+ }
+ data_->stream_alloc_ = NULL;
+ }
+
+ stream().fill('0');
+ data_->preserved_errno_ = errno;
+ data_->severity_ = severity;
+ data_->line_ = line;
+ data_->send_method_ = send_method;
+ data_->sink_ = NULL;
+ data_->outvec_ = NULL;
+ WallTime now = WallTime_Now();
+ data_->timestamp_ = static_cast<time_t>(now);
+ localtime_r(&data_->timestamp_, &data_->tm_time_);
+ int usecs = static_cast<int>((now - data_->timestamp_) * 1000000);
+ RawLog__SetLastTime(data_->tm_time_, usecs);
+
+ data_->num_chars_to_log_ = 0;
+ data_->num_chars_to_syslog_ = 0;
+ data_->basename_ = const_basename(file);
+ data_->fullname_ = file;
+ data_->has_been_flushed_ = false;
+
+ // If specified, prepend a prefix to each line. For example:
+ // I1018 160715 f5d4fbb0 logging.cc:1153]
+ // (log level, GMT month, date, time, thread_id, file basename, line)
+ // We exclude the thread_id for the default thread.
+ if (FLAGS_log_prefix && (line != kNoLogPrefix)) {
+ stream() << LogSeverityNames[severity][0]
+ << setw(2) << 1+data_->tm_time_.tm_mon
+ << setw(2) << data_->tm_time_.tm_mday
+ << ' '
+ << setw(2) << data_->tm_time_.tm_hour << ':'
+ << setw(2) << data_->tm_time_.tm_min << ':'
+ << setw(2) << data_->tm_time_.tm_sec << "."
+ << setw(6) << usecs
+ << ' '
+ << setfill(' ') << setw(5)
+ << static_cast<unsigned int>(GetTID()) << setfill('0')
+ << ' '
+ << data_->basename_ << ':' << data_->line_ << "] ";
+ }
+ data_->num_prefix_chars_ = data_->stream_->pcount();
+
+ if (!FLAGS_log_backtrace_at.empty()) {
+ char fileline[128];
+ snprintf(fileline, sizeof(fileline), "%s:%d", data_->basename_, line);
+#ifdef HAVE_STACKTRACE
+ if (!strcmp(FLAGS_log_backtrace_at.c_str(), fileline)) {
+ string stacktrace;
+ DumpStackTraceToString(&stacktrace);
+ stream() << " (stacktrace:\n" << stacktrace << ") ";
+ }
+#endif
+ }
+}
+
+LogMessage::~LogMessage() {
+ Flush();
+ delete allocated_;
+}
+
+// Flush buffered message, called by the destructor, or any other function
+// that needs to synchronize the log.
+void LogMessage::Flush() {
+ if (data_->has_been_flushed_ || data_->severity_ < FLAGS_minloglevel)
+ return;
+
+ data_->num_chars_to_log_ = data_->stream_->pcount();
+ data_->num_chars_to_syslog_ =
+ data_->num_chars_to_log_ - data_->num_prefix_chars_;
+
+ // Do we need to add a \n to the end of this message?
+ bool append_newline =
+ (data_->message_text_[data_->num_chars_to_log_-1] != '\n');
+ char original_final_char = '\0';
+
+ // If we do need to add a \n, we'll do it by violating the memory of the
+ // ostrstream buffer. This is quick, and we'll make sure to undo our
+ // modification before anything else is done with the ostrstream. It
+ // would be preferable not to do things this way, but it seems to be
+ // the best way to deal with this.
+ if (append_newline) {
+ original_final_char = data_->message_text_[data_->num_chars_to_log_];
+ data_->message_text_[data_->num_chars_to_log_++] = '\n';
+ }
+
+ // Prevent any subtle race conditions by wrapping a mutex lock around
+ // the actual logging action per se.
+ {
+ MutexLock l(&log_mutex);
+ (this->*(data_->send_method_))();
+ ++num_messages_[static_cast<int>(data_->severity_)];
+ }
+ LogDestination::WaitForSinks(data_);
+
+ if (append_newline) {
+ // Fix the ostrstream back how it was before we screwed with it.
+ // It's 99.44% certain that we don't need to worry about doing this.
+ data_->message_text_[data_->num_chars_to_log_-1] = original_final_char;
+ }
+
+ // If errno was already set before we enter the logging call, we'll
+ // set it back to that value when we return from the logging call.
+ // It happens often that we log an error message after a syscall
+ // failure, which can potentially set the errno to some other
+ // values. We would like to preserve the original errno.
+ if (data_->preserved_errno_ != 0) {
+ errno = data_->preserved_errno_;
+ }
+
+ // Note that this message is now safely logged. If we're asked to flush
+ // again, as a result of destruction, say, we'll do nothing on future calls.
+ data_->has_been_flushed_ = true;
+}
+
+// Copy of first FATAL log message so that we can print it out again
+// after all the stack traces. To preserve legacy behavior, we don't
+// use fatal_msg_buf_exclusive.
+static time_t fatal_time;
+static char fatal_message[256];
+
+void ReprintFatalMessage() {
+ if (fatal_message[0]) {
+ const int n = strlen(fatal_message);
+ if (!FLAGS_logtostderr) {
+ // Also write to stderr
+ WriteToStderr(fatal_message, n);
+ }
+ LogDestination::LogToAllLogfiles(ERROR, fatal_time, fatal_message, n);
+ }
+}
+
+// L >= log_mutex (callers must hold the log_mutex).
+void LogMessage::SendToLog() EXCLUSIVE_LOCKS_REQUIRED(log_mutex) {
+ static bool already_warned_before_initgoogle = false;
+
+ log_mutex.AssertHeld();
+
+ RAW_DCHECK(data_->num_chars_to_log_ > 0 &&
+ data_->message_text_[data_->num_chars_to_log_-1] == '\n', "");
+
+ // Messages of a given severity get logged to lower severity logs, too
+
+ if (!already_warned_before_initgoogle && !IsGoogleLoggingInitialized()) {
+ const char w[] = "WARNING: Logging before InitGoogleLogging() is "
+ "written to STDERR\n";
+ WriteToStderr(w, strlen(w));
+ already_warned_before_initgoogle = true;
+ }
+
+ // global flag: never log to file if set. Also -- don't log to a
+ // file if we haven't parsed the command line flags to get the
+ // program name.
+ if (FLAGS_logtostderr || !IsGoogleLoggingInitialized()) {
+ WriteToStderr(data_->message_text_, data_->num_chars_to_log_);
+
+ // this could be protected by a flag if necessary.
+ LogDestination::LogToSinks(data_->severity_,
+ data_->fullname_, data_->basename_,
+ data_->line_, &data_->tm_time_,
+ data_->message_text_ + data_->num_prefix_chars_,
+ (data_->num_chars_to_log_ -
+ data_->num_prefix_chars_ - 1));
+ } else {
+
+ // log this message to all log files of severity <= severity_
+ LogDestination::LogToAllLogfiles(data_->severity_, data_->timestamp_,
+ data_->message_text_,
+ data_->num_chars_to_log_);
+
+ LogDestination::MaybeLogToStderr(data_->severity_, data_->message_text_,
+ data_->num_chars_to_log_);
+ LogDestination::MaybeLogToEmail(data_->severity_, data_->message_text_,
+ data_->num_chars_to_log_);
+ LogDestination::LogToSinks(data_->severity_,
+ data_->fullname_, data_->basename_,
+ data_->line_, &data_->tm_time_,
+ data_->message_text_ + data_->num_prefix_chars_,
+ (data_->num_chars_to_log_
+ - data_->num_prefix_chars_ - 1));
+ // NOTE: -1 removes trailing \n
+ }
+
+ // If we log a FATAL message, flush all the log destinations, then toss
+ // a signal for others to catch. We leave the logs in a state that
+ // someone else can use them (as long as they flush afterwards)
+ if (data_->severity_ == FATAL && exit_on_dfatal) {
+ if (data_->first_fatal_) {
+ // Store crash information so that it is accessible from within signal
+ // handlers that may be invoked later.
+ RecordCrashReason(&crash_reason);
+ SetCrashReason(&crash_reason);
+
+ // Store shortened fatal message for other logs and GWQ status
+ const int copy = min<int>(data_->num_chars_to_log_,
+ sizeof(fatal_message)-1);
+ memcpy(fatal_message, data_->message_text_, copy);
+ fatal_message[copy] = '\0';
+ fatal_time = data_->timestamp_;
+ }
+
+ if (!FLAGS_logtostderr) {
+ for (int i = 0; i < NUM_SEVERITIES; ++i) {
+ if ( LogDestination::log_destinations_[i] )
+ LogDestination::log_destinations_[i]->logger_->Write(true, 0, "", 0);
+ }
+ }
+
+ // release the lock that our caller (directly or indirectly)
+ // LogMessage::~LogMessage() grabbed so that signal handlers
+ // can use the logging facility. Alternately, we could add
+ // an entire unsafe logging interface to bypass locking
+ // for signal handlers but this seems simpler.
+ log_mutex.Unlock();
+ LogDestination::WaitForSinks(data_);
+
+ const char* message = "*** Check failure stack trace: ***\n";
+ write(STDERR_FILENO, message, strlen(message));
+ Fail();
+ }
+}
+
+void LogMessage::RecordCrashReason(
+ glog_internal_namespace_::CrashReason* reason) {
+ reason->filename = fatal_msg_data_exclusive_.fullname_;
+ reason->line_number = fatal_msg_data_exclusive_.line_;
+ reason->message = fatal_msg_buf_exclusive +
+ fatal_msg_data_exclusive_.num_prefix_chars_;
+#ifdef HAVE_STACKTRACE
+ // Retrieve the stack trace, omitting the logging frames that got us here.
+ reason->depth = GetStackTrace(reason->stack, ARRAYSIZE(reason->stack), 4);
+#else
+ reason->depth = 0;
+#endif
+}
+
+static void logging_fail() {
+// #if defined(_DEBUG) && defined(_MSC_VER)
+// doesn't work for my laptop (sergey)
+#if 0
+ // When debugging on windows, avoid the obnoxious dialog and make
+ // it possible to continue past a LOG(FATAL) in the debugger
+ _asm int 3
+#else
+ abort();
+#endif
+}
+
+#ifdef HAVE___ATTRIBUTE__
+GOOGLE_GLOG_DLL_DECL
+void (*g_logging_fail_func)() __attribute__((noreturn)) = &logging_fail;
+#else
+GOOGLE_GLOG_DLL_DECL void (*g_logging_fail_func)() = &logging_fail;
+#endif
+
+void InstallFailureFunction(void (*fail_func)()) {
+ g_logging_fail_func = fail_func;
+}
+
+void LogMessage::Fail() {
+ g_logging_fail_func();
+}
+
+// L >= log_mutex (callers must hold the log_mutex).
+void LogMessage::SendToSink() EXCLUSIVE_LOCKS_REQUIRED(log_mutex) {
+ if (data_->sink_ != NULL) {
+ RAW_DCHECK(data_->num_chars_to_log_ > 0 &&
+ data_->message_text_[data_->num_chars_to_log_-1] == '\n', "");
+ data_->sink_->send(data_->severity_, data_->fullname_, data_->basename_,
+ data_->line_, &data_->tm_time_,
+ data_->message_text_ + data_->num_prefix_chars_,
+ (data_->num_chars_to_log_ -
+ data_->num_prefix_chars_ - 1));
+ }
+}
+
+// L >= log_mutex (callers must hold the log_mutex).
+void LogMessage::SendToSinkAndLog() EXCLUSIVE_LOCKS_REQUIRED(log_mutex) {
+ SendToSink();
+ SendToLog();
+}
+
+// L >= log_mutex (callers must hold the log_mutex).
+void LogMessage::SaveOrSendToLog() EXCLUSIVE_LOCKS_REQUIRED(log_mutex) {
+ if (data_->outvec_ != NULL) {
+ RAW_DCHECK(data_->num_chars_to_log_ > 0 &&
+ data_->message_text_[data_->num_chars_to_log_-1] == '\n', "");
+ // Omit prefix of message and trailing newline when recording in outvec_.
+ const char *start = data_->message_text_ + data_->num_prefix_chars_;
+ int len = data_->num_chars_to_log_ - data_->num_prefix_chars_ - 1;
+ data_->outvec_->push_back(string(start, len));
+ } else {
+ SendToLog();
+ }
+}
+
+void LogMessage::WriteToStringAndLog() EXCLUSIVE_LOCKS_REQUIRED(log_mutex) {
+ if (data_->message_ != NULL) {
+ RAW_DCHECK(data_->num_chars_to_log_ > 0 &&
+ data_->message_text_[data_->num_chars_to_log_-1] == '\n', "");
+ // Omit prefix of message and trailing newline when writing to message_.
+ const char *start = data_->message_text_ + data_->num_prefix_chars_;
+ int len = data_->num_chars_to_log_ - data_->num_prefix_chars_ - 1;
+ data_->message_->assign(start, len);
+ }
+ SendToLog();
+}
+
+// L >= log_mutex (callers must hold the log_mutex).
+void LogMessage::SendToSyslogAndLog() {
+#ifdef HAVE_SYSLOG_H
+ // Before any calls to syslog(), make a single call to openlog()
+ static bool openlog_already_called = false;
+ if (!openlog_already_called) {
+ openlog(glog_internal_namespace_::ProgramInvocationShortName(),
+ LOG_CONS | LOG_NDELAY | LOG_PID,
+ LOG_USER);
+ openlog_already_called = true;
+ }
+
+ // This array maps Google severity levels to syslog levels
+ const int SEVERITY_TO_LEVEL[] = { LOG_INFO, LOG_WARNING, LOG_ERR, LOG_EMERG };
+ syslog(LOG_USER | SEVERITY_TO_LEVEL[static_cast<int>(data_->severity_)], "%.*s",
+ int(data_->num_chars_to_syslog_),
+ data_->message_text_ + data_->num_prefix_chars_);
+ SendToLog();
+#else
+ LOG(ERROR) << "No syslog support: message=" << data_->message_text_;
+#endif
+}
+
+base::Logger* base::GetLogger(LogSeverity severity) {
+ MutexLock l(&log_mutex);
+ return LogDestination::log_destination(severity)->logger_;
+}
+
+void base::SetLogger(LogSeverity severity, base::Logger* logger) {
+ MutexLock l(&log_mutex);
+ LogDestination::log_destination(severity)->logger_ = logger;
+}
+
+// L < log_mutex. Acquires and releases mutex_.
+int64 LogMessage::num_messages(int severity) {
+ MutexLock l(&log_mutex);
+ return num_messages_[severity];
+}
+
+// Output the COUNTER value. This is only valid if ostream is a
+// LogStream.
+ostream& operator<<(ostream &os, const PRIVATE_Counter&) {
+ LogMessage::LogStream *log = dynamic_cast<LogMessage::LogStream*>(&os);
+ CHECK(log == log->self());
+ os << log->ctr();
+ return os;
+}
+
+ErrnoLogMessage::ErrnoLogMessage(const char* file, int line,
+ LogSeverity severity, int ctr,
+ void (LogMessage::*send_method)())
+ : LogMessage(file, line, severity, ctr, send_method) {
+}
+
+ErrnoLogMessage::~ErrnoLogMessage() {
+ // Don't access errno directly because it may have been altered
+ // while streaming the message.
+ char buf[100];
+ posix_strerror_r(preserved_errno(), buf, sizeof(buf));
+ stream() << ": " << buf << " [" << preserved_errno() << "]";
+}
+
+void FlushLogFiles(LogSeverity min_severity) {
+ LogDestination::FlushLogFiles(min_severity);
+}
+
+void FlushLogFilesUnsafe(LogSeverity min_severity) {
+ LogDestination::FlushLogFilesUnsafe(min_severity);
+}
+
+void SetLogDestination(LogSeverity severity, const char* base_filename) {
+ LogDestination::SetLogDestination(severity, base_filename);
+}
+
+void SetLogSymlink(LogSeverity severity, const char* symlink_basename) {
+ LogDestination::SetLogSymlink(severity, symlink_basename);
+}
+
+LogSink::~LogSink() {
+}
+
+void LogSink::WaitTillSent() {
+ // noop default
+}
+
+string LogSink::ToString(LogSeverity severity, const char* file, int line,
+ const struct ::tm* tm_time,
+ const char* message, size_t message_len) {
+ ostringstream stream(string(message, message_len));
+ stream.fill('0');
+
+ // FIXME(jrvb): Updating this to use the correct value for usecs
+ // requires changing the signature for both this method and
+ // LogSink::send(). This change needs to be done in a separate CL
+ // so subclasses of LogSink can be updated at the same time.
+ int usecs = 0;
+
+ stream << LogSeverityNames[severity][0]
+ << setw(2) << 1+tm_time->tm_mon
+ << setw(2) << tm_time->tm_mday
+ << ' '
+ << setw(2) << tm_time->tm_hour << ':'
+ << setw(2) << tm_time->tm_min << ':'
+ << setw(2) << tm_time->tm_sec << '.'
+ << setw(6) << usecs
+ << ' '
+ << setfill(' ') << setw(5) << GetTID() << setfill('0')
+ << ' '
+ << file << ':' << line << "] ";
+
+ stream << string(message, message_len);
+ return stream.str();
+}
+
+void AddLogSink(LogSink *destination) {
+ LogDestination::AddLogSink(destination);
+}
+
+void RemoveLogSink(LogSink *destination) {
+ LogDestination::RemoveLogSink(destination);
+}
+
+void SetLogFilenameExtension(const char* ext) {
+ LogDestination::SetLogFilenameExtension(ext);
+}
+
+void SetStderrLogging(LogSeverity min_severity) {
+ LogDestination::SetStderrLogging(min_severity);
+}
+
+void SetEmailLogging(LogSeverity min_severity, const char* addresses) {
+ LogDestination::SetEmailLogging(min_severity, addresses);
+}
+
+void LogToStderr() {
+ LogDestination::LogToStderr();
+}
+
+namespace base {
+namespace internal {
+
+bool GetExitOnDFatal() {
+ MutexLock l(&log_mutex);
+ return exit_on_dfatal;
+}
+
+// Determines whether we exit the program for a LOG(DFATAL) message in
+// debug mode. It does this by skipping the call to Fail/FailQuietly.
+// This is intended for testing only.
+//
+// This can have some effects on LOG(FATAL) as well. Failure messages
+// are always allocated (rather than sharing a buffer), the crash
+// reason is not recorded, the "gwq" status message is not updated,
+// and the stack trace is not recorded. The LOG(FATAL) *will* still
+// exit the program. Since this function is used only in testing,
+// these differences are acceptable.
+void SetExitOnDFatal(bool value) {
+ MutexLock l(&log_mutex);
+ exit_on_dfatal = value;
+}
+
+} // namespace internal
+} // namespace base
+
+// use_logging controls whether the logging functions LOG/VLOG are used
+// to log errors. It should be set to false when the caller holds the
+// log_mutex.
+static bool SendEmailInternal(const char*dest, const char *subject,
+ const char*body, bool use_logging) {
+ if (dest && *dest) {
+ if ( use_logging ) {
+ VLOG(1) << "Trying to send TITLE:" << subject
+ << " BODY:" << body << " to " << dest;
+ } else {
+ fprintf(stderr, "Trying to send TITLE: %s BODY: %s to %s\n",
+ subject, body, dest);
+ }
+
+ string cmd =
+ FLAGS_logmailer + " -s\"" + subject + "\" " + dest;
+ FILE* pipe = popen(cmd.c_str(), "w");
+ if (pipe != NULL) {
+ // Add the body if we have one
+ if (body)
+ fwrite(body, sizeof(char), strlen(body), pipe);
+ bool ok = pclose(pipe) != -1;
+ if ( !ok ) {
+ if ( use_logging ) {
+ char buf[100];
+ posix_strerror_r(errno, buf, sizeof(buf));
+ LOG(ERROR) << "Problems sending mail to " << dest << ": " << buf;
+ } else {
+ char buf[100];
+ posix_strerror_r(errno, buf, sizeof(buf));
+ fprintf(stderr, "Problems sending mail to %s: %s\n", dest, buf);
+ }
+ }
+ return ok;
+ } else {
+ if ( use_logging ) {
+ LOG(ERROR) << "Unable to send mail to " << dest;
+ } else {
+ fprintf(stderr, "Unable to send mail to %s\n", dest);
+ }
+ }
+ }
+ return false;
+}
+
+bool SendEmail(const char*dest, const char *subject, const char*body){
+ return SendEmailInternal(dest, subject, body, true);
+}
+
+static void GetTempDirectories(vector<string>* list) {
+ list->clear();
+#ifdef OS_WINDOWS
+ // On windows we'll try to find a directory in this order:
+ // C:/Documents & Settings/whomever/TEMP (or whatever GetTempPath() is)
+ // C:/TMP/
+ // C:/TEMP/
+ // C:/WINDOWS/ or C:/WINNT/
+ // .
+ char tmp[MAX_PATH];
+ if (GetTempPathA(MAX_PATH, tmp))
+ list->push_back(tmp);
+ list->push_back("C:\\tmp\\");
+ list->push_back("C:\\temp\\");
+#else
+ // Directories, in order of preference. If we find a dir that
+ // exists, we stop adding other less-preferred dirs
+ const char * candidates[] = {
+ // Non-null only during unittest/regtest
+ getenv("TEST_TMPDIR"),
+
+ // Explicitly-supplied temp dirs
+ getenv("TMPDIR"), getenv("TMP"),
+
+ // If all else fails
+ "/tmp",
+ };
+
+ for (int i = 0; i < ARRAYSIZE(candidates); i++) {
+ const char *d = candidates[i];
+ if (!d) continue; // Empty env var
+
+ // Make sure we don't surprise anyone who's expecting a '/'
+ string dstr = d;
+ if (dstr[dstr.size() - 1] != '/') {
+ dstr += "/";
+ }
+ list->push_back(dstr);
+
+ struct stat statbuf;
+ if (!stat(d, &statbuf) && S_ISDIR(statbuf.st_mode)) {
+ // We found a dir that exists - we're done.
+ return;
+ }
+ }
+
+#endif
+}
+
+static vector<string>* logging_directories_list;
+
+const vector<string>& GetLoggingDirectories() {
+ // Not strictly thread-safe but we're called early in InitGoogle().
+ if (logging_directories_list == NULL) {
+ logging_directories_list = new vector<string>;
+
+ if ( !FLAGS_log_dir.empty() ) {
+ // A dir was specified, we should use it
+ logging_directories_list->push_back(FLAGS_log_dir.c_str());
+ } else {
+ GetTempDirectories(logging_directories_list);
+#ifdef OS_WINDOWS
+ char tmp[MAX_PATH];
+ if (GetWindowsDirectoryA(tmp, MAX_PATH))
+ logging_directories_list->push_back(tmp);
+ logging_directories_list->push_back(".\\");
+#else
+ logging_directories_list->push_back("./");
+#endif
+ }
+ }
+ return *logging_directories_list;
+}
+
+void TestOnly_ClearLoggingDirectoriesList() {
+ fprintf(stderr, "TestOnly_ClearLoggingDirectoriesList should only be "
+ "called from test code.\n");
+ delete logging_directories_list;
+ logging_directories_list = NULL;
+}
+
+void GetExistingTempDirectories(vector<string>* list) {
+ GetTempDirectories(list);
+ vector<string>::iterator i_dir = list->begin();
+ while( i_dir != list->end() ) {
+ // zero arg to access means test for existence; no constant
+ // defined on windows
+ if ( access(i_dir->c_str(), 0) ) {
+ i_dir = list->erase(i_dir);
+ } else {
+ ++i_dir;
+ }
+ }
+}
+
+void TruncateLogFile(const char *path, int64 limit, int64 keep) {
+#ifdef HAVE_UNISTD_H
+ struct stat statbuf;
+ const int kCopyBlockSize = 8 << 10;
+ char copybuf[kCopyBlockSize];
+ int64 read_offset, write_offset;
+ // Don't follow symlinks unless they're our own fd symlinks in /proc
+ int flags = O_RDWR;
+ const char *procfd_prefix = "/proc/self/fd/";
+ if (strncmp(procfd_prefix, path, strlen(procfd_prefix))) flags |= O_NOFOLLOW;
+
+ int fd = open(path, flags);
+ if (fd == -1) {
+ if (errno == EFBIG) {
+ // The log file in question has got too big for us to open. The
+ // real fix for this would be to compile logging.cc (or probably
+ // all of base/...) with -D_FILE_OFFSET_BITS=64 but that's
+ // rather scary.
+ // Instead just truncate the file to something we can manage
+ if (truncate(path, 0) == -1) {
+ PLOG(ERROR) << "Unable to truncate " << path;
+ } else {
+ LOG(ERROR) << "Truncated " << path << " due to EFBIG error";
+ }
+ } else {
+ PLOG(ERROR) << "Unable to open " << path;
+ }
+ return;
+ }
+
+ if (fstat(fd, &statbuf) == -1) {
+ PLOG(ERROR) << "Unable to fstat()";
+ goto out_close_fd;
+ }
+
+ // See if the path refers to a regular file bigger than the
+ // specified limit
+ if (!S_ISREG(statbuf.st_mode)) goto out_close_fd;
+ if (statbuf.st_size <= limit) goto out_close_fd;
+ if (statbuf.st_size <= keep) goto out_close_fd;
+
+ // This log file is too large - we need to truncate it
+ LOG(INFO) << "Truncating " << path << " to " << keep << " bytes";
+
+ // Copy the last "keep" bytes of the file to the beginning of the file
+ read_offset = statbuf.st_size - keep;
+ write_offset = 0;
+ int bytesin, bytesout;
+ while ((bytesin = pread(fd, copybuf, sizeof(copybuf), read_offset)) > 0) {
+ bytesout = pwrite(fd, copybuf, bytesin, write_offset);
+ if (bytesout == -1) {
+ PLOG(ERROR) << "Unable to write to " << path;
+ break;
+ } else if (bytesout != bytesin) {
+ LOG(ERROR) << "Expected to write " << bytesin << ", wrote " << bytesout;
+ }
+ read_offset += bytesin;
+ write_offset += bytesout;
+ }
+ if (bytesin == -1) PLOG(ERROR) << "Unable to read from " << path;
+
+ // Truncate the remainder of the file. If someone else writes to the
+ // end of the file after our last read() above, we lose their latest
+ // data. Too bad ...
+ if (ftruncate(fd, write_offset) == -1) {
+ PLOG(ERROR) << "Unable to truncate " << path;
+ }
+
+ out_close_fd:
+ close(fd);
+#else
+ LOG(ERROR) << "No log truncation support.";
+#endif
+}
+
+void TruncateStdoutStderr() {
+#ifdef HAVE_UNISTD_H
+ int64 limit = MaxLogSize() << 20;
+ int64 keep = 1 << 20;
+ TruncateLogFile("/proc/self/fd/1", limit, keep);
+ TruncateLogFile("/proc/self/fd/2", limit, keep);
+#else
+ LOG(ERROR) << "No log truncation support.";
+#endif
+}
+
+
+// Helper functions for string comparisons.
+#define DEFINE_CHECK_STROP_IMPL(name, func, expected) \
+ string* Check##func##expected##Impl(const char* s1, const char* s2, \
+ const char* names) { \
+ bool equal = s1 == s2 || (s1 && s2 && !func(s1, s2)); \
+ if (equal == expected) return NULL; \
+ else { \
+ strstream ss; \
+ if (!s1) s1 = ""; \
+ if (!s2) s2 = ""; \
+ ss << #name " failed: " << names << " (" << s1 << " vs. " << s2 << ")"; \
+ return new string(ss.str(), ss.pcount()); \
+ } \
+ }
+DEFINE_CHECK_STROP_IMPL(CHECK_STREQ, strcmp, true)
+DEFINE_CHECK_STROP_IMPL(CHECK_STRNE, strcmp, false)
+DEFINE_CHECK_STROP_IMPL(CHECK_STRCASEEQ, strcasecmp, true)
+DEFINE_CHECK_STROP_IMPL(CHECK_STRCASENE, strcasecmp, false)
+#undef DEFINE_CHECK_STROP_IMPL
+
+int posix_strerror_r(int err, char *buf, size_t len) {
+ // Sanity check input parameters
+ if (buf == NULL || len <= 0) {
+ errno = EINVAL;
+ return -1;
+ }
+
+ // Reset buf and errno, and try calling whatever version of strerror_r()
+ // is implemented by glibc
+ buf[0] = '\000';
+ int old_errno = errno;
+ errno = 0;
+ char *rc = reinterpret_cast<char *>(strerror_r(err, buf, len));
+
+ // Both versions set errno on failure
+ if (errno) {
+ // Should already be there, but better safe than sorry
+ buf[0] = '\000';
+ return -1;
+ }
+ errno = old_errno;
+
+ // POSIX is vague about whether the string will be terminated, although
+ // is indirectly implies that typically ERANGE will be returned, instead
+ // of truncating the string. This is different from the GNU implementation.
+ // We play it safe by always terminating the string explicitly.
+ buf[len-1] = '\000';
+
+ // If the function succeeded, we can use its exit code to determine the
+ // semantics implemented by glibc
+ if (!rc) {
+ return 0;
+ } else {
+ // GNU semantics detected
+ if (rc == buf) {
+ return 0;
+ } else {
+ buf[0] = '\000';
+#if defined(OS_MACOSX) || defined(OS_FREEBSD) || defined(OS_OPENBSD)
+ if (reinterpret_cast<intptr_t>(rc) < sys_nerr) {
+ // This means an error on MacOSX or FreeBSD.
+ return -1;
+ }
+#endif
+ strncat(buf, rc, len-1);
+ return 0;
+ }
+ }
+}
+
+LogMessageFatal::LogMessageFatal(const char* file, int line) :
+ LogMessage(file, line, FATAL) {}
+
+LogMessageFatal::LogMessageFatal(const char* file, int line,
+ const CheckOpString& result) :
+ LogMessage(file, line, result) {}
+
+LogMessageFatal::~LogMessageFatal() {
+ Flush();
+ LogMessage::Fail();
+}
+
+_END_GOOGLE_NAMESPACE_
diff --git a/extern/libmv/third_party/glog/src/raw_logging.cc b/extern/libmv/third_party/glog/src/raw_logging.cc
new file mode 100644
index 00000000000..b179a1eded4
--- /dev/null
+++ b/extern/libmv/third_party/glog/src/raw_logging.cc
@@ -0,0 +1,172 @@
+// Copyright (c) 2006, Google Inc.
+// 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.
+//
+// Author: Maxim Lifantsev
+//
+// logging_unittest.cc covers the functionality herein
+
+#include "utilities.h"
+
+#include <stdarg.h>
+#include <stdio.h>
+#include <errno.h>
+#ifdef HAVE_UNISTD_H
+# include <unistd.h> // for close() and write()
+#endif
+#include <fcntl.h> // for open()
+#include <time.h>
+#include "config.h"
+#include <glog/logging.h> // To pick up flag settings etc.
+#include <glog/raw_logging.h>
+#include "base/commandlineflags.h"
+
+#ifdef HAVE_STACKTRACE
+# include "stacktrace.h"
+#endif
+
+#if defined(HAVE_SYSCALL_H)
+#include <syscall.h> // for syscall()
+#elif defined(HAVE_SYS_SYSCALL_H)
+#include <sys/syscall.h> // for syscall()
+#endif
+#ifdef HAVE_UNISTD_H
+# include <unistd.h>
+#endif
+
+#if defined(HAVE_SYSCALL_H) || defined(HAVE_SYS_SYSCALL_H)
+# define safe_write(fd, s, len) syscall(SYS_write, fd, s, len)
+#else
+ // Not so safe, but what can you do?
+# define safe_write(fd, s, len) write(fd, s, len)
+#endif
+
+_START_GOOGLE_NAMESPACE_
+
+// Data for RawLog__ below. We simply pick up the latest
+// time data created by a normal log message to avoid calling
+// localtime_r which can allocate memory.
+static struct ::tm last_tm_time_for_raw_log;
+static int last_usecs_for_raw_log;
+
+void RawLog__SetLastTime(const struct ::tm& t, int usecs) {
+ memcpy(&last_tm_time_for_raw_log, &t, sizeof(last_tm_time_for_raw_log));
+ last_usecs_for_raw_log = usecs;
+}
+
+// CAVEAT: vsnprintf called from *DoRawLog below has some (exotic) code paths
+// that invoke malloc() and getenv() that might acquire some locks.
+// If this becomes a problem we should reimplement a subset of vsnprintf
+// that does not need locks and malloc.
+
+// Helper for RawLog__ below.
+// *DoRawLog writes to *buf of *size and move them past the written portion.
+// It returns true iff there was no overflow or error.
+static bool DoRawLog(char** buf, int* size, const char* format, ...) {
+ va_list ap;
+ va_start(ap, format);
+ int n = vsnprintf(*buf, *size, format, ap);
+ va_end(ap);
+ if (n < 0 || n > *size) return false;
+ *size -= n;
+ *buf += n;
+ return true;
+}
+
+// Helper for RawLog__ below.
+inline static bool VADoRawLog(char** buf, int* size,
+ const char* format, va_list ap) {
+ int n = vsnprintf(*buf, *size, format, ap);
+ if (n < 0 || n > *size) return false;
+ *size -= n;
+ *buf += n;
+ return true;
+}
+
+static const int kLogBufSize = 3000;
+static bool crashed = false;
+static CrashReason crash_reason;
+static char crash_buf[kLogBufSize + 1] = { 0 }; // Will end in '\0'
+
+void RawLog__(LogSeverity severity, const char* file, int line,
+ const char* format, ...) {
+ if (!(FLAGS_logtostderr || severity >= FLAGS_stderrthreshold ||
+ FLAGS_alsologtostderr || !IsGoogleLoggingInitialized())) {
+ return; // this stderr log message is suppressed
+ }
+ // can't call localtime_r here: it can allocate
+ struct ::tm& t = last_tm_time_for_raw_log;
+ char buffer[kLogBufSize];
+ char* buf = buffer;
+ int size = sizeof(buffer);
+
+ // NOTE: this format should match the specification in base/logging.h
+ DoRawLog(&buf, &size, "%c%02d%02d %02d:%02d:%02d.%06d %5u %s:%d] RAW: ",
+ LogSeverityNames[severity][0],
+ 1 + t.tm_mon, t.tm_mday, t.tm_hour, t.tm_min, t.tm_sec,
+ last_usecs_for_raw_log,
+ static_cast<unsigned int>(GetTID()),
+ const_basename(const_cast<char *>(file)), line);
+
+ // Record the position and size of the buffer after the prefix
+ const char* msg_start = buf;
+ const int msg_size = size;
+
+ va_list ap;
+ va_start(ap, format);
+ bool no_chop = VADoRawLog(&buf, &size, format, ap);
+ va_end(ap);
+ if (no_chop) {
+ DoRawLog(&buf, &size, "\n");
+ } else {
+ DoRawLog(&buf, &size, "RAW_LOG ERROR: The Message was too long!\n");
+ }
+ // We make a raw syscall to write directly to the stderr file descriptor,
+ // avoiding FILE buffering (to avoid invoking malloc()), and bypassing
+ // libc (to side-step any libc interception).
+ // We write just once to avoid races with other invocations of RawLog__.
+ safe_write(STDERR_FILENO, buffer, strlen(buffer));
+ if (severity == FATAL) {
+ if (!sync_val_compare_and_swap(&crashed, false, true)) {
+ crash_reason.filename = file;
+ crash_reason.line_number = line;
+ memcpy(crash_buf, msg_start, msg_size); // Don't include prefix
+ crash_reason.message = crash_buf;
+#ifdef HAVE_STACKTRACE
+ crash_reason.depth =
+ GetStackTrace(crash_reason.stack, ARRAYSIZE(crash_reason.stack), 1);
+#else
+ crash_reason.depth = 0;
+#endif
+ SetCrashReason(&crash_reason);
+ }
+ LogMessage::Fail(); // abort()
+ }
+}
+
+_END_GOOGLE_NAMESPACE_
diff --git a/extern/libmv/third_party/glog/src/signalhandler.cc b/extern/libmv/third_party/glog/src/signalhandler.cc
new file mode 100644
index 00000000000..9fc91b3390d
--- /dev/null
+++ b/extern/libmv/third_party/glog/src/signalhandler.cc
@@ -0,0 +1,348 @@
+// Copyright (c) 2008, Google Inc.
+// 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.
+//
+// Author: Satoru Takabayashi
+//
+// Implementation of InstallFailureSignalHandler().
+
+#include "utilities.h"
+#include "stacktrace.h"
+#include "symbolize.h"
+#include "glog/logging.h"
+
+#include <signal.h>
+#include <time.h>
+#ifdef HAVE_UCONTEXT_H
+# include <ucontext.h>
+#endif
+#ifdef HAVE_SYS_UCONTEXT_H
+# include <sys/ucontext.h>
+#endif
+#include <algorithm>
+
+_START_GOOGLE_NAMESPACE_
+
+namespace {
+
+// We'll install the failure signal handler for these signals. We could
+// use strsignal() to get signal names, but we don't use it to avoid
+// introducing yet another #ifdef complication.
+//
+// The list should be synced with the comment in signalhandler.h.
+const struct {
+ int number;
+ const char *name;
+} kFailureSignals[] = {
+ { SIGSEGV, "SIGSEGV" },
+ { SIGILL, "SIGILL" },
+ { SIGFPE, "SIGFPE" },
+ { SIGABRT, "SIGABRT" },
+ { SIGBUS, "SIGBUS" },
+ { SIGTERM, "SIGTERM" },
+};
+
+// Returns the program counter from signal context, NULL if unknown.
+void* GetPC(void* ucontext_in_void) {
+#if (defined(HAVE_UCONTEXT_H) || defined(HAVE_SYS_UCONTEXT_H)) && defined(PC_FROM_UCONTEXT)
+ if (ucontext_in_void != NULL) {
+ ucontext_t *context = reinterpret_cast<ucontext_t *>(ucontext_in_void);
+ return (void*)context->PC_FROM_UCONTEXT;
+ }
+#endif
+ return NULL;
+}
+
+// The class is used for formatting error messages. We don't use printf()
+// as it's not async signal safe.
+class MinimalFormatter {
+ public:
+ MinimalFormatter(char *buffer, int size)
+ : buffer_(buffer),
+ cursor_(buffer),
+ end_(buffer + size) {
+ }
+
+ // Returns the number of bytes written in the buffer.
+ int num_bytes_written() const { return cursor_ - buffer_; }
+
+ // Appends string from "str" and updates the internal cursor.
+ void AppendString(const char* str) {
+ int i = 0;
+ while (str[i] != '\0' && cursor_ + i < end_) {
+ cursor_[i] = str[i];
+ ++i;
+ }
+ cursor_ += i;
+ }
+
+ // Formats "number" in "radix" and updates the internal cursor.
+ // Lowercase letters are used for 'a' - 'z'.
+ void AppendUint64(uint64 number, int radix) {
+ int i = 0;
+ while (cursor_ + i < end_) {
+ const int tmp = number % radix;
+ number /= radix;
+ cursor_[i] = (tmp < 10 ? '0' + tmp : 'a' + tmp - 10);
+ ++i;
+ if (number == 0) {
+ break;
+ }
+ }
+ // Reverse the bytes written.
+ std::reverse(cursor_, cursor_ + i);
+ cursor_ += i;
+ }
+
+ // Formats "number" as hexadecimal number, and updates the internal
+ // cursor. Padding will be added in front if needed.
+ void AppendHexWithPadding(uint64 number, int width) {
+ char* start = cursor_;
+ AppendString("0x");
+ AppendUint64(number, 16);
+ // Move to right and add padding in front if needed.
+ if (cursor_ < start + width) {
+ const int64 delta = start + width - cursor_;
+ std::copy(start, cursor_, start + delta);
+ std::fill(start, start + delta, ' ');
+ cursor_ = start + width;
+ }
+ }
+
+ private:
+ char *buffer_;
+ char *cursor_;
+ const char * const end_;
+};
+
+// Writes the given data with the size to the standard error.
+void WriteToStderr(const char* data, int size) {
+ write(STDERR_FILENO, data, size);
+}
+
+// The writer function can be changed by InstallFailureWriter().
+void (*g_failure_writer)(const char* data, int size) = WriteToStderr;
+
+// Dumps time information. We don't dump human-readable time information
+// as localtime() is not guaranteed to be async signal safe.
+void DumpTimeInfo() {
+ time_t time_in_sec = time(NULL);
+ char buf[256]; // Big enough for time info.
+ MinimalFormatter formatter(buf, sizeof(buf));
+ formatter.AppendString("*** Aborted at ");
+ formatter.AppendUint64(time_in_sec, 10);
+ formatter.AppendString(" (unix time)");
+ formatter.AppendString(" try \"date -d @");
+ formatter.AppendUint64(time_in_sec, 10);
+ formatter.AppendString("\" if you are using GNU date ***\n");
+ g_failure_writer(buf, formatter.num_bytes_written());
+}
+
+// Dumps information about the signal to STDERR.
+void DumpSignalInfo(int signal_number, siginfo_t *siginfo) {
+ // Get the signal name.
+ const char* signal_name = NULL;
+ for (int i = 0; i < ARRAYSIZE(kFailureSignals); ++i) {
+ if (signal_number == kFailureSignals[i].number) {
+ signal_name = kFailureSignals[i].name;
+ }
+ }
+
+ char buf[256]; // Big enough for signal info.
+ MinimalFormatter formatter(buf, sizeof(buf));
+
+ formatter.AppendString("*** ");
+ if (signal_name) {
+ formatter.AppendString(signal_name);
+ } else {
+ // Use the signal number if the name is unknown. The signal name
+ // should be known, but just in case.
+ formatter.AppendString("Signal ");
+ formatter.AppendUint64(signal_number, 10);
+ }
+ formatter.AppendString(" (@0x");
+ formatter.AppendUint64(reinterpret_cast<uintptr_t>(siginfo->si_addr), 16);
+ formatter.AppendString(")");
+ formatter.AppendString(" received by PID ");
+ formatter.AppendUint64(getpid(), 10);
+ formatter.AppendString(" (TID 0x");
+ // We assume pthread_t is an integral number or a pointer, rather
+ // than a complex struct. In some environments, pthread_self()
+ // returns an uint64 but in some other environments pthread_self()
+ // returns a pointer. Hence we use C-style cast here, rather than
+ // reinterpret/static_cast, to support both types of environments.
+ formatter.AppendUint64((uintptr_t)pthread_self(), 16);
+ formatter.AppendString(") ");
+ // Only linux has the PID of the signal sender in si_pid.
+#ifdef OS_LINUX
+ formatter.AppendString("from PID ");
+ formatter.AppendUint64(siginfo->si_pid, 10);
+ formatter.AppendString("; ");
+#endif
+ formatter.AppendString("stack trace: ***\n");
+ g_failure_writer(buf, formatter.num_bytes_written());
+}
+
+// Dumps information about the stack frame to STDERR.
+void DumpStackFrameInfo(const char* prefix, void* pc) {
+ // Get the symbol name.
+ const char *symbol = "(unknown)";
+ char symbolized[1024]; // Big enough for a sane symbol.
+ // Symbolizes the previous address of pc because pc may be in the
+ // next function.
+ if (Symbolize(reinterpret_cast<char *>(pc) - 1,
+ symbolized, sizeof(symbolized))) {
+ symbol = symbolized;
+ }
+
+ char buf[1024]; // Big enough for stack frame info.
+ MinimalFormatter formatter(buf, sizeof(buf));
+
+ formatter.AppendString(prefix);
+ formatter.AppendString("@ ");
+ const int width = 2 * sizeof(void*) + 2; // + 2 for "0x".
+ formatter.AppendHexWithPadding(reinterpret_cast<uintptr_t>(pc), width);
+ formatter.AppendString(" ");
+ formatter.AppendString(symbol);
+ formatter.AppendString("\n");
+ g_failure_writer(buf, formatter.num_bytes_written());
+}
+
+// Invoke the default signal handler.
+void InvokeDefaultSignalHandler(int signal_number) {
+ struct sigaction sig_action;
+ memset(&sig_action, 0, sizeof(sig_action));
+ sigemptyset(&sig_action.sa_mask);
+ sig_action.sa_handler = SIG_DFL;
+ sigaction(signal_number, &sig_action, NULL);
+ kill(getpid(), signal_number);
+}
+
+// This variable is used for protecting FailureSignalHandler() from
+// dumping stuff while another thread is doing it. Our policy is to let
+// the first thread dump stuff and let other threads wait.
+// See also comments in FailureSignalHandler().
+static pthread_t* g_entered_thread_id_pointer = NULL;
+
+// Dumps signal and stack frame information, and invokes the default
+// signal handler once our job is done.
+void FailureSignalHandler(int signal_number,
+ siginfo_t *signal_info,
+ void *ucontext) {
+ // First check if we've already entered the function. We use an atomic
+ // compare and swap operation for platforms that support it. For other
+ // platforms, we use a naive method that could lead to a subtle race.
+
+ // We assume pthread_self() is async signal safe, though it's not
+ // officially guaranteed.
+ pthread_t my_thread_id = pthread_self();
+ // NOTE: We could simply use pthread_t rather than pthread_t* for this,
+ // if pthread_self() is guaranteed to return non-zero value for thread
+ // ids, but there is no such guarantee. We need to distinguish if the
+ // old value (value returned from __sync_val_compare_and_swap) is
+ // different from the original value (in this case NULL).
+ pthread_t* old_thread_id_pointer =
+ glog_internal_namespace_::sync_val_compare_and_swap(
+ &g_entered_thread_id_pointer,
+ static_cast<pthread_t*>(NULL),
+ &my_thread_id);
+ if (old_thread_id_pointer != NULL) {
+ // We've already entered the signal handler. What should we do?
+ if (pthread_equal(my_thread_id, *g_entered_thread_id_pointer)) {
+ // It looks the current thread is reentering the signal handler.
+ // Something must be going wrong (maybe we are reentering by another
+ // type of signal?). Kill ourself by the default signal handler.
+ InvokeDefaultSignalHandler(signal_number);
+ }
+ // Another thread is dumping stuff. Let's wait until that thread
+ // finishes the job and kills the process.
+ while (true) {
+ sleep(1);
+ }
+ }
+ // This is the first time we enter the signal handler. We are going to
+ // do some interesting stuff from here.
+ // TODO(satorux): We might want to set timeout here using alarm(), but
+ // mixing alarm() and sleep() can be a bad idea.
+
+ // First dump time info.
+ DumpTimeInfo();
+
+ // Get the program counter from ucontext.
+ void *pc = GetPC(ucontext);
+ DumpStackFrameInfo("PC: ", pc);
+
+#ifdef HAVE_STACKTRACE
+ // Get the stack traces.
+ void *stack[32];
+ // +1 to exclude this function.
+ const int depth = GetStackTrace(stack, ARRAYSIZE(stack), 1);
+ DumpSignalInfo(signal_number, signal_info);
+ // Dump the stack traces.
+ for (int i = 0; i < depth; ++i) {
+ DumpStackFrameInfo(" ", stack[i]);
+ }
+#endif
+
+ // *** TRANSITION ***
+ //
+ // BEFORE this point, all code must be async-termination-safe!
+ // (See WARNING above.)
+ //
+ // AFTER this point, we do unsafe things, like using LOG()!
+ // The process could be terminated or hung at any time. We try to
+ // do more useful things first and riskier things later.
+
+ // Flush the logs before we do anything in case 'anything'
+ // causes problems.
+ FlushLogFilesUnsafe(0);
+
+ // Kill ourself by the default signal handler.
+ InvokeDefaultSignalHandler(signal_number);
+}
+
+} // namespace
+
+void InstallFailureSignalHandler() {
+ // Build the sigaction struct.
+ struct sigaction sig_action;
+ memset(&sig_action, 0, sizeof(sig_action));
+ sigemptyset(&sig_action.sa_mask);
+ sig_action.sa_flags |= SA_SIGINFO;
+ sig_action.sa_sigaction = &FailureSignalHandler;
+
+ for (int i = 0; i < ARRAYSIZE(kFailureSignals); ++i) {
+ CHECK_ERR(sigaction(kFailureSignals[i].number, &sig_action, NULL));
+ }
+}
+
+void InstallFailureWriter(void (*writer)(const char* data, int size)) {
+ g_failure_writer = writer;
+}
+
+_END_GOOGLE_NAMESPACE_
diff --git a/extern/libmv/third_party/glog/src/stacktrace.h b/extern/libmv/third_party/glog/src/stacktrace.h
new file mode 100644
index 00000000000..8c3e8fe8f8d
--- /dev/null
+++ b/extern/libmv/third_party/glog/src/stacktrace.h
@@ -0,0 +1,60 @@
+// Copyright (c) 2000 - 2007, Google Inc.
+// 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.
+//
+// Routines to extract the current stack trace. These functions are
+// thread-safe.
+
+#ifndef BASE_STACKTRACE_H_
+#define BASE_STACKTRACE_H_
+
+#include "config.h"
+
+_START_GOOGLE_NAMESPACE_
+
+// This is similar to the GetStackFrames routine, except that it returns
+// the stack trace only, and not the stack frame sizes as well.
+// Example:
+// main() { foo(); }
+// foo() { bar(); }
+// bar() {
+// void* result[10];
+// int depth = GetStackFrames(result, 10, 1);
+// }
+//
+// This produces:
+// result[0] foo
+// result[1] main
+// .... ...
+//
+// "result" must not be NULL.
+extern int GetStackTrace(void** result, int max_depth, int skip_count);
+
+_END_GOOGLE_NAMESPACE_
+
+#endif // BASE_STACKTRACE_H_
diff --git a/extern/libmv/third_party/glog/src/stacktrace_generic-inl.h b/extern/libmv/third_party/glog/src/stacktrace_generic-inl.h
new file mode 100644
index 00000000000..fad81d3e3f4
--- /dev/null
+++ b/extern/libmv/third_party/glog/src/stacktrace_generic-inl.h
@@ -0,0 +1,59 @@
+// Copyright (c) 2000 - 2007, Google Inc.
+// 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.
+//
+// Portable implementation - just use glibc
+//
+// Note: The glibc implementation may cause a call to malloc.
+// This can cause a deadlock in HeapProfiler.
+#include <execinfo.h>
+#include <string.h>
+#include "stacktrace.h"
+
+_START_GOOGLE_NAMESPACE_
+
+// If you change this function, also change GetStackFrames below.
+int GetStackTrace(void** result, int max_depth, int skip_count) {
+ static const int kStackLength = 64;
+ void * stack[kStackLength];
+ int size;
+
+ size = backtrace(stack, kStackLength);
+ skip_count++; // we want to skip the current frame as well
+ int result_count = size - skip_count;
+ if (result_count < 0)
+ result_count = 0;
+ if (result_count > max_depth)
+ result_count = max_depth;
+ for (int i = 0; i < result_count; i++)
+ result[i] = stack[i + skip_count];
+
+ return result_count;
+}
+
+_END_GOOGLE_NAMESPACE_
diff --git a/extern/libmv/third_party/glog/src/stacktrace_libunwind-inl.h b/extern/libmv/third_party/glog/src/stacktrace_libunwind-inl.h
new file mode 100644
index 00000000000..0dc14c6506e
--- /dev/null
+++ b/extern/libmv/third_party/glog/src/stacktrace_libunwind-inl.h
@@ -0,0 +1,87 @@
+// Copyright (c) 2005 - 2007, Google Inc.
+// 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.
+//
+// Author: Arun Sharma
+//
+// Produce stack trace using libunwind
+
+#include "utilities.h"
+
+extern "C" {
+#define UNW_LOCAL_ONLY
+#include <libunwind.h>
+}
+#include "glog/raw_logging.h"
+#include "stacktrace.h"
+
+_START_GOOGLE_NAMESPACE_
+
+// Sometimes, we can try to get a stack trace from within a stack
+// trace, because libunwind can call mmap (maybe indirectly via an
+// internal mmap based memory allocator), and that mmap gets trapped
+// and causes a stack-trace request. If were to try to honor that
+// recursive request, we'd end up with infinite recursion or deadlock.
+// Luckily, it's safe to ignore those subsequent traces. In such
+// cases, we return 0 to indicate the situation.
+static bool g_now_entering = false;
+
+// If you change this function, also change GetStackFrames below.
+int GetStackTrace(void** result, int max_depth, int skip_count) {
+ void *ip;
+ int n = 0;
+ unw_cursor_t cursor;
+ unw_context_t uc;
+
+ if (sync_val_compare_and_swap(&g_now_entering, false, true)) {
+ return 0;
+ }
+
+ unw_getcontext(&uc);
+ RAW_CHECK(unw_init_local(&cursor, &uc) >= 0, "unw_init_local failed");
+ skip_count++; // Do not include the "GetStackTrace" frame
+
+ while (n < max_depth) {
+ int ret = unw_get_reg(&cursor, UNW_REG_IP, (unw_word_t *) &ip);
+ if (ret < 0)
+ break;
+ if (skip_count > 0) {
+ skip_count--;
+ } else {
+ result[n++] = ip;
+ }
+ ret = unw_step(&cursor);
+ if (ret <= 0)
+ break;
+ }
+
+ g_now_entering = false;
+ return n;
+}
+
+_END_GOOGLE_NAMESPACE_
diff --git a/extern/libmv/third_party/glog/src/stacktrace_powerpc-inl.h b/extern/libmv/third_party/glog/src/stacktrace_powerpc-inl.h
new file mode 100644
index 00000000000..1090ddedbc7
--- /dev/null
+++ b/extern/libmv/third_party/glog/src/stacktrace_powerpc-inl.h
@@ -0,0 +1,130 @@
+// Copyright (c) 2007, Google Inc.
+// 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.
+//
+// Author: Craig Silverstein
+//
+// Produce stack trace. I'm guessing (hoping!) the code is much like
+// for x86. For apple machines, at least, it seems to be; see
+// http://developer.apple.com/documentation/mac/runtimehtml/RTArch-59.html
+// http://www.linux-foundation.org/spec/ELF/ppc64/PPC-elf64abi-1.9.html#STACK
+// Linux has similar code: http://patchwork.ozlabs.org/linuxppc/patch?id=8882
+
+#include <stdio.h>
+#include <stdint.h> // for uintptr_t
+#include "stacktrace.h"
+
+_START_GOOGLE_NAMESPACE_
+
+// Given a pointer to a stack frame, locate and return the calling
+// stackframe, or return NULL if no stackframe can be found. Perform sanity
+// checks (the strictness of which is controlled by the boolean parameter
+// "STRICT_UNWINDING") to reduce the chance that a bad pointer is returned.
+template<bool STRICT_UNWINDING>
+static void **NextStackFrame(void **old_sp) {
+ void **new_sp = (void **) *old_sp;
+
+ // Check that the transition from frame pointer old_sp to frame
+ // pointer new_sp isn't clearly bogus
+ if (STRICT_UNWINDING) {
+ // With the stack growing downwards, older stack frame must be
+ // at a greater address that the current one.
+ if (new_sp <= old_sp) return NULL;
+ // Assume stack frames larger than 100,000 bytes are bogus.
+ if ((uintptr_t)new_sp - (uintptr_t)old_sp > 100000) return NULL;
+ } else {
+ // In the non-strict mode, allow discontiguous stack frames.
+ // (alternate-signal-stacks for example).
+ if (new_sp == old_sp) return NULL;
+ // And allow frames upto about 1MB.
+ if ((new_sp > old_sp)
+ && ((uintptr_t)new_sp - (uintptr_t)old_sp > 1000000)) return NULL;
+ }
+ if ((uintptr_t)new_sp & (sizeof(void *) - 1)) return NULL;
+ return new_sp;
+}
+
+// This ensures that GetStackTrace stes up the Link Register properly.
+void StacktracePowerPCDummyFunction() __attribute__((noinline));
+void StacktracePowerPCDummyFunction() { __asm__ volatile(""); }
+
+// If you change this function, also change GetStackFrames below.
+int GetStackTrace(void** result, int max_depth, int skip_count) {
+ void **sp;
+ // Apple OS X uses an old version of gnu as -- both Darwin 7.9.0 (Panther)
+ // and Darwin 8.8.1 (Tiger) use as 1.38. This means we have to use a
+ // different asm syntax. I don't know quite the best way to discriminate
+ // systems using the old as from the new one; I've gone with __APPLE__.
+#ifdef __APPLE__
+ __asm__ volatile ("mr %0,r1" : "=r" (sp));
+#else
+ __asm__ volatile ("mr %0,1" : "=r" (sp));
+#endif
+
+ // On PowerPC, the "Link Register" or "Link Record" (LR), is a stack
+ // entry that holds the return address of the subroutine call (what
+ // instruction we run after our function finishes). This is the
+ // same as the stack-pointer of our parent routine, which is what we
+ // want here. While the compiler will always(?) set up LR for
+ // subroutine calls, it may not for leaf functions (such as this one).
+ // This routine forces the compiler (at least gcc) to push it anyway.
+ StacktracePowerPCDummyFunction();
+
+ // The LR save area is used by the callee, so the top entry is bogus.
+ skip_count++;
+
+ int n = 0;
+ while (sp && n < max_depth) {
+ if (skip_count > 0) {
+ skip_count--;
+ } else {
+ // PowerPC has 3 main ABIs, which say where in the stack the
+ // Link Register is. For DARWIN and AIX (used by apple and
+ // linux ppc64), it's in sp[2]. For SYSV (used by linux ppc),
+ // it's in sp[1].
+#if defined(_CALL_AIX) || defined(_CALL_DARWIN)
+ result[n++] = *(sp+2);
+#elif defined(_CALL_SYSV)
+ result[n++] = *(sp+1);
+#elif defined(__APPLE__) || (defined(__linux) && defined(__PPC64__))
+ // This check is in case the compiler doesn't define _CALL_AIX/etc.
+ result[n++] = *(sp+2);
+#elif defined(__linux)
+ // This check is in case the compiler doesn't define _CALL_SYSV.
+ result[n++] = *(sp+1);
+#else
+#error Need to specify the PPC ABI for your archiecture.
+#endif
+ }
+ // Use strict unwinding rules.
+ sp = NextStackFrame<true>(sp);
+ }
+ return n;
+}
+
+_END_GOOGLE_NAMESPACE_
diff --git a/extern/libmv/third_party/glog/src/stacktrace_x86-inl.h b/extern/libmv/third_party/glog/src/stacktrace_x86-inl.h
new file mode 100644
index 00000000000..cfd31f783e3
--- /dev/null
+++ b/extern/libmv/third_party/glog/src/stacktrace_x86-inl.h
@@ -0,0 +1,139 @@
+// Copyright (c) 2000 - 2007, Google Inc.
+// 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.
+//
+// Produce stack trace
+
+#include <stdint.h> // for uintptr_t
+
+#include "utilities.h" // for OS_* macros
+
+#if !defined(OS_WINDOWS)
+#include <unistd.h>
+#include <sys/mman.h>
+#endif
+
+#include <stdio.h> // for NULL
+#include "stacktrace.h"
+
+_START_GOOGLE_NAMESPACE_
+
+// Given a pointer to a stack frame, locate and return the calling
+// stackframe, or return NULL if no stackframe can be found. Perform sanity
+// checks (the strictness of which is controlled by the boolean parameter
+// "STRICT_UNWINDING") to reduce the chance that a bad pointer is returned.
+template<bool STRICT_UNWINDING>
+static void **NextStackFrame(void **old_sp) {
+ void **new_sp = (void **) *old_sp;
+
+ // Check that the transition from frame pointer old_sp to frame
+ // pointer new_sp isn't clearly bogus
+ if (STRICT_UNWINDING) {
+ // With the stack growing downwards, older stack frame must be
+ // at a greater address that the current one.
+ if (new_sp <= old_sp) return NULL;
+ // Assume stack frames larger than 100,000 bytes are bogus.
+ if ((uintptr_t)new_sp - (uintptr_t)old_sp > 100000) return NULL;
+ } else {
+ // In the non-strict mode, allow discontiguous stack frames.
+ // (alternate-signal-stacks for example).
+ if (new_sp == old_sp) return NULL;
+ // And allow frames upto about 1MB.
+ if ((new_sp > old_sp)
+ && ((uintptr_t)new_sp - (uintptr_t)old_sp > 1000000)) return NULL;
+ }
+ if ((uintptr_t)new_sp & (sizeof(void *) - 1)) return NULL;
+#ifdef __i386__
+ // On 64-bit machines, the stack pointer can be very close to
+ // 0xffffffff, so we explicitly check for a pointer into the
+ // last two pages in the address space
+ if ((uintptr_t)new_sp >= 0xffffe000) return NULL;
+#endif
+#if !defined(OS_WINDOWS)
+ if (!STRICT_UNWINDING) {
+ // Lax sanity checks cause a crash in 32-bit tcmalloc/crash_reason_test
+ // on AMD-based machines with VDSO-enabled kernels.
+ // Make an extra sanity check to insure new_sp is readable.
+ // Note: NextStackFrame<false>() is only called while the program
+ // is already on its last leg, so it's ok to be slow here.
+ static int page_size = getpagesize();
+ void *new_sp_aligned = (void *)((uintptr_t)new_sp & ~(page_size - 1));
+ if (msync(new_sp_aligned, page_size, MS_ASYNC) == -1)
+ return NULL;
+ }
+#endif
+ return new_sp;
+}
+
+// If you change this function, also change GetStackFrames below.
+int GetStackTrace(void** result, int max_depth, int skip_count) {
+ void **sp;
+#ifdef __i386__
+ // Stack frame format:
+ // sp[0] pointer to previous frame
+ // sp[1] caller address
+ // sp[2] first argument
+ // ...
+ sp = (void **)&result - 2;
+#endif
+
+#ifdef __x86_64__
+ // __builtin_frame_address(0) can return the wrong address on gcc-4.1.0-k8
+ unsigned long rbp;
+ // Move the value of the register %rbp into the local variable rbp.
+ // We need 'volatile' to prevent this instruction from getting moved
+ // around during optimization to before function prologue is done.
+ // An alternative way to achieve this
+ // would be (before this __asm__ instruction) to call Noop() defined as
+ // static void Noop() __attribute__ ((noinline)); // prevent inlining
+ // static void Noop() { asm(""); } // prevent optimizing-away
+ __asm__ volatile ("mov %%rbp, %0" : "=r" (rbp));
+ // Arguments are passed in registers on x86-64, so we can't just
+ // offset from &result
+ sp = (void **) rbp;
+#endif
+
+ int n = 0;
+ while (sp && n < max_depth) {
+ if (*(sp+1) == (void *)0) {
+ // In 64-bit code, we often see a frame that
+ // points to itself and has a return address of 0.
+ break;
+ }
+ if (skip_count > 0) {
+ skip_count--;
+ } else {
+ result[n++] = *(sp+1);
+ }
+ // Use strict unwinding rules.
+ sp = NextStackFrame<true>(sp);
+ }
+ return n;
+}
+
+_END_GOOGLE_NAMESPACE_
diff --git a/extern/libmv/third_party/glog/src/stacktrace_x86_64-inl.h b/extern/libmv/third_party/glog/src/stacktrace_x86_64-inl.h
new file mode 100644
index 00000000000..f7d1dca85bc
--- /dev/null
+++ b/extern/libmv/third_party/glog/src/stacktrace_x86_64-inl.h
@@ -0,0 +1,105 @@
+// Copyright (c) 2005 - 2007, Google Inc.
+// 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.
+//
+// Author: Arun Sharma
+//
+// Produce stack trace using libgcc
+
+extern "C" {
+#include <stdlib.h> // for NULL
+#include <unwind.h> // ABI defined unwinder
+}
+#include "stacktrace.h"
+
+_START_GOOGLE_NAMESPACE_
+
+typedef struct {
+ void **result;
+ int max_depth;
+ int skip_count;
+ int count;
+} trace_arg_t;
+
+
+// Workaround for the malloc() in _Unwind_Backtrace() issue.
+static _Unwind_Reason_Code nop_backtrace(struct _Unwind_Context *uc, void *opq) {
+ return _URC_NO_REASON;
+}
+
+
+// This code is not considered ready to run until
+// static initializers run so that we are guaranteed
+// that any malloc-related initialization is done.
+static bool ready_to_run = false;
+class StackTraceInit {
+ public:
+ StackTraceInit() {
+ // Extra call to force initialization
+ _Unwind_Backtrace(nop_backtrace, NULL);
+ ready_to_run = true;
+ }
+};
+
+static StackTraceInit module_initializer; // Force initialization
+
+static _Unwind_Reason_Code GetOneFrame(struct _Unwind_Context *uc, void *opq) {
+ trace_arg_t *targ = (trace_arg_t *) opq;
+
+ if (targ->skip_count > 0) {
+ targ->skip_count--;
+ } else {
+ targ->result[targ->count++] = (void *) _Unwind_GetIP(uc);
+ }
+
+ if (targ->count == targ->max_depth)
+ return _URC_END_OF_STACK;
+
+ return _URC_NO_REASON;
+}
+
+// If you change this function, also change GetStackFrames below.
+int GetStackTrace(void** result, int max_depth, int skip_count) {
+ if (!ready_to_run)
+ return 0;
+
+ trace_arg_t targ;
+
+ skip_count += 1; // Do not include the "GetStackTrace" frame
+
+ targ.result = result;
+ targ.max_depth = max_depth;
+ targ.skip_count = skip_count;
+ targ.count = 0;
+
+ _Unwind_Backtrace(GetOneFrame, &targ);
+
+ return targ.count;
+}
+
+_END_GOOGLE_NAMESPACE_
diff --git a/extern/libmv/third_party/glog/src/symbolize.cc b/extern/libmv/third_party/glog/src/symbolize.cc
new file mode 100644
index 00000000000..3465de6c6fe
--- /dev/null
+++ b/extern/libmv/third_party/glog/src/symbolize.cc
@@ -0,0 +1,681 @@
+// Copyright (c) 2006, Google Inc.
+// 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.
+//
+// Author: Satoru Takabayashi
+// Stack-footprint reduction work done by Raksit Ashok
+//
+// Implementation note:
+//
+// We don't use heaps but only use stacks. We want to reduce the
+// stack consumption so that the symbolizer can run on small stacks.
+//
+// Here are some numbers collected with GCC 4.1.0 on x86:
+// - sizeof(Elf32_Sym) = 16
+// - sizeof(Elf32_Shdr) = 40
+// - sizeof(Elf64_Sym) = 24
+// - sizeof(Elf64_Shdr) = 64
+//
+// This implementation is intended to be async-signal-safe but uses
+// some functions which are not guaranteed to be so, such as memchr()
+// and memmove(). We assume they are async-signal-safe.
+//
+
+#include "utilities.h"
+
+#if defined(HAVE_SYMBOLIZE)
+
+#include <limits>
+
+#include "symbolize.h"
+#include "demangle.h"
+
+_START_GOOGLE_NAMESPACE_
+
+// We don't use assert() since it's not guaranteed to be
+// async-signal-safe. Instead we define a minimal assertion
+// macro. So far, we don't need pretty printing for __FILE__, etc.
+
+// A wrapper for abort() to make it callable in ? :.
+static int AssertFail() {
+ abort();
+ return 0; // Should not reach.
+}
+
+#define SAFE_ASSERT(expr) ((expr) ? 0 : AssertFail())
+
+static SymbolizeCallback g_symbolize_callback = NULL;
+void InstallSymbolizeCallback(SymbolizeCallback callback) {
+ g_symbolize_callback = callback;
+}
+
+// This function wraps the Demangle function to provide an interface
+// where the input symbol is demangled in-place.
+// To keep stack consumption low, we would like this function to not
+// get inlined.
+static ATTRIBUTE_NOINLINE void DemangleInplace(char *out, int out_size) {
+ char demangled[256]; // Big enough for sane demangled symbols.
+ if (Demangle(out, demangled, sizeof(demangled))) {
+ // Demangling succeeded. Copy to out if the space allows.
+ int len = strlen(demangled);
+ if (len + 1 <= out_size) { // +1 for '\0'.
+ SAFE_ASSERT(len < sizeof(demangled));
+ memmove(out, demangled, len + 1);
+ }
+ }
+}
+
+_END_GOOGLE_NAMESPACE_
+
+#if defined(__ELF__)
+
+#include <dlfcn.h>
+#include <elf.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <limits.h>
+#include <link.h> // For ElfW() macro.
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <stddef.h>
+#include <string.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#include "symbolize.h"
+#include "config.h"
+#include "glog/raw_logging.h"
+
+// Re-runs fn until it doesn't cause EINTR.
+#define NO_INTR(fn) do {} while ((fn) < 0 && errno == EINTR)
+
+_START_GOOGLE_NAMESPACE_
+
+// Read up to "count" bytes from file descriptor "fd" into the buffer
+// starting at "buf" while handling short reads and EINTR. On
+// success, return the number of bytes read. Otherwise, return -1.
+static ssize_t ReadPersistent(const int fd, void *buf, const size_t count) {
+ SAFE_ASSERT(fd >= 0);
+ SAFE_ASSERT(count >= 0 && count <= std::numeric_limits<ssize_t>::max());
+ char *buf0 = reinterpret_cast<char *>(buf);
+ ssize_t num_bytes = 0;
+ while (num_bytes < count) {
+ ssize_t len;
+ NO_INTR(len = read(fd, buf0 + num_bytes, count - num_bytes));
+ if (len < 0) { // There was an error other than EINTR.
+ return -1;
+ }
+ if (len == 0) { // Reached EOF.
+ break;
+ }
+ num_bytes += len;
+ }
+ SAFE_ASSERT(num_bytes <= count);
+ return num_bytes;
+}
+
+// Read up to "count" bytes from "offset" in the file pointed by file
+// descriptor "fd" into the buffer starting at "buf". On success,
+// return the number of bytes read. Otherwise, return -1.
+static ssize_t ReadFromOffset(const int fd, void *buf,
+ const size_t count, const off_t offset) {
+ off_t off = lseek(fd, offset, SEEK_SET);
+ if (off == (off_t)-1) {
+ return -1;
+ }
+ return ReadPersistent(fd, buf, count);
+}
+
+// Try reading exactly "count" bytes from "offset" bytes in a file
+// pointed by "fd" into the buffer starting at "buf" while handling
+// short reads and EINTR. On success, return true. Otherwise, return
+// false.
+static bool ReadFromOffsetExact(const int fd, void *buf,
+ const size_t count, const off_t offset) {
+ ssize_t len = ReadFromOffset(fd, buf, count, offset);
+ return len == count;
+}
+
+// Returns elf_header.e_type if the file pointed by fd is an ELF binary.
+static int FileGetElfType(const int fd) {
+ ElfW(Ehdr) elf_header;
+ if (!ReadFromOffsetExact(fd, &elf_header, sizeof(elf_header), 0)) {
+ return -1;
+ }
+ if (memcmp(elf_header.e_ident, ELFMAG, SELFMAG) != 0) {
+ return -1;
+ }
+ return elf_header.e_type;
+}
+
+// Read the section headers in the given ELF binary, and if a section
+// of the specified type is found, set the output to this section header
+// and return true. Otherwise, return false.
+// To keep stack consumption low, we would like this function to not get
+// inlined.
+static ATTRIBUTE_NOINLINE bool
+GetSectionHeaderByType(const int fd, ElfW(Half) sh_num, const off_t sh_offset,
+ ElfW(Word) type, ElfW(Shdr) *out) {
+ // Read at most 16 section headers at a time to save read calls.
+ ElfW(Shdr) buf[16];
+ for (int i = 0; i < sh_num;) {
+ const ssize_t num_bytes_left = (sh_num - i) * sizeof(buf[0]);
+ const ssize_t num_bytes_to_read =
+ (sizeof(buf) > num_bytes_left) ? num_bytes_left : sizeof(buf);
+ const ssize_t len = ReadFromOffset(fd, buf, num_bytes_to_read,
+ sh_offset + i * sizeof(buf[0]));
+ SAFE_ASSERT(len % sizeof(buf[0]) == 0);
+ const ssize_t num_headers_in_buf = len / sizeof(buf[0]);
+ SAFE_ASSERT(num_headers_in_buf <= sizeof(buf) / sizeof(buf[0]));
+ for (int j = 0; j < num_headers_in_buf; ++j) {
+ if (buf[j].sh_type == type) {
+ *out = buf[j];
+ return true;
+ }
+ }
+ i += num_headers_in_buf;
+ }
+ return false;
+}
+
+// There is no particular reason to limit section name to 63 characters,
+// but there has (as yet) been no need for anything longer either.
+const int kMaxSectionNameLen = 64;
+
+// name_len should include terminating '\0'.
+bool GetSectionHeaderByName(int fd, const char *name, size_t name_len,
+ ElfW(Shdr) *out) {
+ ElfW(Ehdr) elf_header;
+ if (!ReadFromOffsetExact(fd, &elf_header, sizeof(elf_header), 0)) {
+ return false;
+ }
+
+ ElfW(Shdr) shstrtab;
+ off_t shstrtab_offset = (elf_header.e_shoff +
+ elf_header.e_shentsize * elf_header.e_shstrndx);
+ if (!ReadFromOffsetExact(fd, &shstrtab, sizeof(shstrtab), shstrtab_offset)) {
+ return false;
+ }
+
+ for (int i = 0; i < elf_header.e_shnum; ++i) {
+ off_t section_header_offset = (elf_header.e_shoff +
+ elf_header.e_shentsize * i);
+ if (!ReadFromOffsetExact(fd, out, sizeof(*out), section_header_offset)) {
+ return false;
+ }
+ char header_name[kMaxSectionNameLen];
+ if (sizeof(header_name) < name_len) {
+ RAW_LOG(WARNING, "Section name '%s' is too long (%"PRIuS"); "
+ "section will not be found (even if present).", name, name_len);
+ // No point in even trying.
+ return false;
+ }
+ off_t name_offset = shstrtab.sh_offset + out->sh_name;
+ ssize_t n_read = ReadFromOffset(fd, &header_name, name_len, name_offset);
+ if (n_read == -1) {
+ return false;
+ } else if (n_read != name_len) {
+ // Short read -- name could be at end of file.
+ continue;
+ }
+ if (memcmp(header_name, name, name_len) == 0) {
+ return true;
+ }
+ }
+ return false;
+}
+
+// Read a symbol table and look for the symbol containing the
+// pc. Iterate over symbols in a symbol table and look for the symbol
+// containing "pc". On success, return true and write the symbol name
+// to out. Otherwise, return false.
+// To keep stack consumption low, we would like this function to not get
+// inlined.
+static ATTRIBUTE_NOINLINE bool
+FindSymbol(uint64_t pc, const int fd, char *out, int out_size,
+ uint64_t symbol_offset, const ElfW(Shdr) *strtab,
+ const ElfW(Shdr) *symtab) {
+ if (symtab == NULL) {
+ return false;
+ }
+ const int num_symbols = symtab->sh_size / symtab->sh_entsize;
+ for (int i = 0; i < num_symbols;) {
+ off_t offset = symtab->sh_offset + i * symtab->sh_entsize;
+
+ // If we are reading Elf64_Sym's, we want to limit this array to
+ // 32 elements (to keep stack consumption low), otherwise we can
+ // have a 64 element Elf32_Sym array.
+#if __WORDSIZE == 64
+#define NUM_SYMBOLS 32
+#else
+#define NUM_SYMBOLS 64
+#endif
+
+ // Read at most NUM_SYMBOLS symbols at once to save read() calls.
+ ElfW(Sym) buf[NUM_SYMBOLS];
+ const ssize_t len = ReadFromOffset(fd, &buf, sizeof(buf), offset);
+ SAFE_ASSERT(len % sizeof(buf[0]) == 0);
+ const ssize_t num_symbols_in_buf = len / sizeof(buf[0]);
+ SAFE_ASSERT(num_symbols_in_buf <= sizeof(buf)/sizeof(buf[0]));
+ for (int j = 0; j < num_symbols_in_buf; ++j) {
+ const ElfW(Sym)& symbol = buf[j];
+ uint64_t start_address = symbol.st_value;
+ start_address += symbol_offset;
+ uint64_t end_address = start_address + symbol.st_size;
+ if (symbol.st_value != 0 && // Skip null value symbols.
+ symbol.st_shndx != 0 && // Skip undefined symbols.
+ start_address <= pc && pc < end_address) {
+ ssize_t len1 = ReadFromOffset(fd, out, out_size,
+ strtab->sh_offset + symbol.st_name);
+ if (len1 <= 0 || memchr(out, '\0', out_size) == NULL) {
+ return false;
+ }
+ return true; // Obtained the symbol name.
+ }
+ }
+ i += num_symbols_in_buf;
+ }
+ return false;
+}
+
+// Get the symbol name of "pc" from the file pointed by "fd". Process
+// both regular and dynamic symbol tables if necessary. On success,
+// write the symbol name to "out" and return true. Otherwise, return
+// false.
+static bool GetSymbolFromObjectFile(const int fd, uint64_t pc,
+ char *out, int out_size,
+ uint64_t map_start_address) {
+ // Read the ELF header.
+ ElfW(Ehdr) elf_header;
+ if (!ReadFromOffsetExact(fd, &elf_header, sizeof(elf_header), 0)) {
+ return false;
+ }
+
+ uint64_t symbol_offset = 0;
+ if (elf_header.e_type == ET_DYN) { // DSO needs offset adjustment.
+ symbol_offset = map_start_address;
+ }
+
+ ElfW(Shdr) symtab, strtab;
+
+ // Consult a regular symbol table first.
+ if (!GetSectionHeaderByType(fd, elf_header.e_shnum, elf_header.e_shoff,
+ SHT_SYMTAB, &symtab)) {
+ return false;
+ }
+ if (!ReadFromOffsetExact(fd, &strtab, sizeof(strtab), elf_header.e_shoff +
+ symtab.sh_link * sizeof(symtab))) {
+ return false;
+ }
+ if (FindSymbol(pc, fd, out, out_size, symbol_offset,
+ &strtab, &symtab)) {
+ return true; // Found the symbol in a regular symbol table.
+ }
+
+ // If the symbol is not found, then consult a dynamic symbol table.
+ if (!GetSectionHeaderByType(fd, elf_header.e_shnum, elf_header.e_shoff,
+ SHT_DYNSYM, &symtab)) {
+ return false;
+ }
+ if (!ReadFromOffsetExact(fd, &strtab, sizeof(strtab), elf_header.e_shoff +
+ symtab.sh_link * sizeof(symtab))) {
+ return false;
+ }
+ if (FindSymbol(pc, fd, out, out_size, symbol_offset,
+ &strtab, &symtab)) {
+ return true; // Found the symbol in a dynamic symbol table.
+ }
+
+ return false;
+}
+
+namespace {
+// Thin wrapper around a file descriptor so that the file descriptor
+// gets closed for sure.
+struct FileDescriptor {
+ const int fd_;
+ explicit FileDescriptor(int fd) : fd_(fd) {}
+ ~FileDescriptor() {
+ if (fd_ >= 0) {
+ NO_INTR(close(fd_));
+ }
+ }
+ int get() { return fd_; }
+
+ private:
+ explicit FileDescriptor(const FileDescriptor&);
+ void operator=(const FileDescriptor&);
+};
+
+// Helper class for reading lines from file.
+//
+// Note: we don't use ProcMapsIterator since the object is big (it has
+// a 5k array member) and uses async-unsafe functions such as sscanf()
+// and snprintf().
+class LineReader {
+ public:
+ explicit LineReader(int fd, char *buf, int buf_len) : fd_(fd),
+ buf_(buf), buf_len_(buf_len), bol_(buf), eol_(buf), eod_(buf) {
+ }
+
+ // Read '\n'-terminated line from file. On success, modify "bol"
+ // and "eol", then return true. Otherwise, return false.
+ //
+ // Note: if the last line doesn't end with '\n', the line will be
+ // dropped. It's an intentional behavior to make the code simple.
+ bool ReadLine(const char **bol, const char **eol) {
+ if (BufferIsEmpty()) { // First time.
+ const ssize_t num_bytes = ReadPersistent(fd_, buf_, buf_len_);
+ if (num_bytes <= 0) { // EOF or error.
+ return false;
+ }
+ eod_ = buf_ + num_bytes;
+ bol_ = buf_;
+ } else {
+ bol_ = eol_ + 1; // Advance to the next line in the buffer.
+ SAFE_ASSERT(bol_ <= eod_); // "bol_" can point to "eod_".
+ if (!HasCompleteLine()) {
+ const int incomplete_line_length = eod_ - bol_;
+ // Move the trailing incomplete line to the beginning.
+ memmove(buf_, bol_, incomplete_line_length);
+ // Read text from file and append it.
+ char * const append_pos = buf_ + incomplete_line_length;
+ const int capacity_left = buf_len_ - incomplete_line_length;
+ const ssize_t num_bytes = ReadPersistent(fd_, append_pos,
+ capacity_left);
+ if (num_bytes <= 0) { // EOF or error.
+ return false;
+ }
+ eod_ = append_pos + num_bytes;
+ bol_ = buf_;
+ }
+ }
+ eol_ = FindLineFeed();
+ if (eol_ == NULL) { // '\n' not found. Malformed line.
+ return false;
+ }
+ *eol_ = '\0'; // Replace '\n' with '\0'.
+
+ *bol = bol_;
+ *eol = eol_;
+ return true;
+ }
+
+ // Beginning of line.
+ const char *bol() {
+ return bol_;
+ }
+
+ // End of line.
+ const char *eol() {
+ return eol_;
+ }
+
+ private:
+ explicit LineReader(const LineReader&);
+ void operator=(const LineReader&);
+
+ char *FindLineFeed() {
+ return reinterpret_cast<char *>(memchr(bol_, '\n', eod_ - bol_));
+ }
+
+ bool BufferIsEmpty() {
+ return buf_ == eod_;
+ }
+
+ bool HasCompleteLine() {
+ return !BufferIsEmpty() && FindLineFeed() != NULL;
+ }
+
+ const int fd_;
+ char * const buf_;
+ const int buf_len_;
+ char *bol_;
+ char *eol_;
+ const char *eod_; // End of data in "buf_".
+};
+} // namespace
+
+// Place the hex number read from "start" into "*hex". The pointer to
+// the first non-hex character or "end" is returned.
+static char *GetHex(const char *start, const char *end, uint64_t *hex) {
+ *hex = 0;
+ const char *p;
+ for (p = start; p < end; ++p) {
+ int ch = *p;
+ if ((ch >= '0' && ch <= '9') ||
+ (ch >= 'A' && ch <= 'F') || (ch >= 'a' && ch <= 'f')) {
+ *hex = (*hex << 4) | (ch < 'A' ? ch - '0' : (ch & 0xF) + 9);
+ } else { // Encountered the first non-hex character.
+ break;
+ }
+ }
+ SAFE_ASSERT(p <= end);
+ return const_cast<char *>(p);
+}
+
+// Search for the object file (from /proc/self/maps) that contains
+// the specified pc. If found, open this file and return the file handle,
+// and also set start_address to the start address of where this object
+// file is mapped to in memory. Otherwise, return -1.
+static ATTRIBUTE_NOINLINE int
+OpenObjectFileContainingPcAndGetStartAddress(uint64_t pc,
+ uint64_t &start_address) {
+ int object_fd;
+
+ // Open /proc/self/maps.
+ int maps_fd;
+ NO_INTR(maps_fd = open("/proc/self/maps", O_RDONLY));
+ FileDescriptor wrapped_maps_fd(maps_fd);
+ if (wrapped_maps_fd.get() < 0) {
+ return -1;
+ }
+
+ // Iterate over maps and look for the map containing the pc. Then
+ // look into the symbol tables inside.
+ char buf[1024]; // Big enough for line of sane /proc/self/maps
+ LineReader reader(wrapped_maps_fd.get(), buf, sizeof(buf));
+ while (true) {
+ const char *cursor;
+ const char *eol;
+ if (!reader.ReadLine(&cursor, &eol)) { // EOF or malformed line.
+ return -1;
+ }
+
+ // Start parsing line in /proc/self/maps. Here is an example:
+ //
+ // 08048000-0804c000 r-xp 00000000 08:01 2142121 /bin/cat
+ //
+ // We want start address (08048000), end address (0804c000), flags
+ // (r-xp) and file name (/bin/cat).
+
+ // Read start address.
+ cursor = GetHex(cursor, eol, &start_address);
+ if (cursor == eol || *cursor != '-') {
+ return -1; // Malformed line.
+ }
+ ++cursor; // Skip '-'.
+
+ // Read end address.
+ uint64_t end_address;
+ cursor = GetHex(cursor, eol, &end_address);
+ if (cursor == eol || *cursor != ' ') {
+ return -1; // Malformed line.
+ }
+ ++cursor; // Skip ' '.
+
+ // Check start and end addresses.
+ if (!(start_address <= pc && pc < end_address)) {
+ continue; // We skip this map. PC isn't in this map.
+ }
+
+ // Read flags. Skip flags until we encounter a space or eol.
+ const char * const flags_start = cursor;
+ while (cursor < eol && *cursor != ' ') {
+ ++cursor;
+ }
+ // We expect at least four letters for flags (ex. "r-xp").
+ if (cursor == eol || cursor < flags_start + 4) {
+ return -1; // Malformed line.
+ }
+
+ // Check flags. We are only interested in "r-x" maps.
+ if (memcmp(flags_start, "r-x", 3) != 0) { // Not a "r-x" map.
+ continue; // We skip this map.
+ }
+ ++cursor; // Skip ' '.
+
+ // Skip to file name. "cursor" now points to file offset. We need to
+ // skip at least three spaces for file offset, dev, and inode.
+ int num_spaces = 0;
+ while (cursor < eol) {
+ if (*cursor == ' ') {
+ ++num_spaces;
+ } else if (num_spaces >= 3) {
+ // The first non-space character after skipping three spaces
+ // is the beginning of the file name.
+ break;
+ }
+ ++cursor;
+ }
+ if (cursor == eol) {
+ return -1; // Malformed line.
+ }
+
+ // Finally, "cursor" now points to file name of our interest.
+ NO_INTR(object_fd = open(cursor, O_RDONLY));
+ if (object_fd < 0) {
+ return -1;
+ }
+ return object_fd;
+ }
+}
+
+// The implementation of our symbolization routine. If it
+// successfully finds the symbol containing "pc" and obtains the
+// symbol name, returns true and write the symbol name to "out".
+// Otherwise, returns false. If Callback function is installed via
+// InstallSymbolizeCallback(), the function is also called in this function,
+// and "out" is used as its output.
+// To keep stack consumption low, we would like this function to not
+// get inlined.
+static ATTRIBUTE_NOINLINE bool SymbolizeAndDemangle(void *pc, char *out,
+ int out_size) {
+ uint64_t pc0 = reinterpret_cast<uintptr_t>(pc);
+ uint64_t start_address = 0;
+
+ int object_fd = OpenObjectFileContainingPcAndGetStartAddress(pc0,
+ start_address);
+ if (object_fd == -1) {
+ return false;
+ }
+ FileDescriptor wrapped_object_fd(object_fd);
+ int elf_type = FileGetElfType(wrapped_object_fd.get());
+ if (elf_type == -1) {
+ return false;
+ }
+ if (g_symbolize_callback) {
+ // Run the call back if it's installed.
+ // Note: relocation (and much of the rest of this code) will be
+ // wrong for prelinked shared libraries and PIE executables.
+ uint64 relocation = (elf_type == ET_DYN) ? start_address : 0;
+ int num_bytes_written = g_symbolize_callback(wrapped_object_fd.get(),
+ pc, out, out_size,
+ relocation);
+ if (num_bytes_written > 0) {
+ out += num_bytes_written;
+ out_size -= num_bytes_written;
+ }
+ }
+ if (!GetSymbolFromObjectFile(wrapped_object_fd.get(), pc0,
+ out, out_size, start_address)) {
+ return false;
+ }
+
+ // Symbolization succeeded. Now we try to demangle the symbol.
+ DemangleInplace(out, out_size);
+ return true;
+}
+
+_END_GOOGLE_NAMESPACE_
+
+#elif defined(OS_MACOSX) && defined(HAVE_DLADDR)
+
+#include <dlfcn.h>
+#include <string.h>
+
+_START_GOOGLE_NAMESPACE_
+
+static ATTRIBUTE_NOINLINE bool SymbolizeAndDemangle(void *pc, char *out,
+ int out_size) {
+ Dl_info info;
+ if (dladdr(pc, &info)) {
+ if (strlen(info.dli_sname) < out_size) {
+ strcpy(out, info.dli_sname);
+ // Symbolization succeeded. Now we try to demangle the symbol.
+ DemangleInplace(out, out_size);
+ return true;
+ }
+ }
+ return false;
+}
+
+_END_GOOGLE_NAMESPACE_
+
+#else
+# error BUG: HAVE_SYMBOLIZE was wrongly set
+#endif
+
+_START_GOOGLE_NAMESPACE_
+
+bool Symbolize(void *pc, char *out, int out_size) {
+ SAFE_ASSERT(out_size >= 0);
+ return SymbolizeAndDemangle(pc, out, out_size);
+}
+
+_END_GOOGLE_NAMESPACE_
+
+#else /* HAVE_SYMBOLIZE */
+
+#include <assert.h>
+
+#include "config.h"
+
+_START_GOOGLE_NAMESPACE_
+
+// TODO: Support other environments.
+bool Symbolize(void *pc, char *out, int out_size) {
+ assert(0);
+ return false;
+}
+
+_END_GOOGLE_NAMESPACE_
+
+#endif
diff --git a/extern/libmv/third_party/glog/src/symbolize.h b/extern/libmv/third_party/glog/src/symbolize.h
new file mode 100644
index 00000000000..1ebe4dd94a2
--- /dev/null
+++ b/extern/libmv/third_party/glog/src/symbolize.h
@@ -0,0 +1,116 @@
+// Copyright (c) 2006, Google Inc.
+// 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.
+//
+// Author: Satoru Takabayashi
+//
+// This library provides Symbolize() function that symbolizes program
+// counters to their corresponding symbol names on linux platforms.
+// This library has a minimal implementation of an ELF symbol table
+// reader (i.e. it doesn't depend on libelf, etc.).
+//
+// The algorithm used in Symbolize() is as follows.
+//
+// 1. Go through a list of maps in /proc/self/maps and find the map
+// containing the program counter.
+//
+// 2. Open the mapped file and find a regular symbol table inside.
+// Iterate over symbols in the symbol table and look for the symbol
+// containing the program counter. If such a symbol is found,
+// obtain the symbol name, and demangle the symbol if possible.
+// If the symbol isn't found in the regular symbol table (binary is
+// stripped), try the same thing with a dynamic symbol table.
+//
+// Note that Symbolize() is originally implemented to be used in
+// FailureSignalHandler() in base/google.cc. Hence it doesn't use
+// malloc() and other unsafe operations. It should be both
+// thread-safe and async-signal-safe.
+
+#ifndef BASE_SYMBOLIZE_H_
+#define BASE_SYMBOLIZE_H_
+
+#include "utilities.h"
+#include "config.h"
+#include "glog/logging.h"
+
+#ifdef HAVE_SYMBOLIZE
+
+#if defined(__ELF__) // defined by gcc on Linux
+#include <elf.h>
+#include <link.h> // For ElfW() macro.
+
+// If there is no ElfW macro, let's define it by ourself.
+#ifndef ElfW
+# if SIZEOF_VOID_P == 4
+# define ElfW(type) Elf32_##type
+# elif SIZEOF_VOID_P == 8
+# define ElfW(type) Elf64_##type
+# else
+# error "Unknown sizeof(void *)"
+# endif
+#endif
+
+_START_GOOGLE_NAMESPACE_
+
+// Gets the section header for the given name, if it exists. Returns true on
+// success. Otherwise, returns false.
+bool GetSectionHeaderByName(int fd, const char *name, size_t name_len,
+ ElfW(Shdr) *out);
+
+_END_GOOGLE_NAMESPACE_
+
+#endif /* __ELF__ */
+
+_START_GOOGLE_NAMESPACE_
+
+// Installs a callback function, which will be called right before a symbol name
+// is printed. The callback is intended to be used for showing a file name and a
+// line number preceding a symbol name.
+// "fd" is a file descriptor of the object file containing the program
+// counter "pc". The callback function should write output to "out"
+// and return the size of the output written. On error, the callback
+// function should return -1.
+typedef int (*SymbolizeCallback)(int fd, void *pc, char *out, size_t out_size,
+ uint64 relocation);
+void InstallSymbolizeCallback(SymbolizeCallback callback);
+
+_END_GOOGLE_NAMESPACE_
+
+#endif
+
+_START_GOOGLE_NAMESPACE_
+
+// Symbolizes a program counter. On success, returns true and write the
+// symbol name to "out". The symbol name is demangled if possible
+// (supports symbols generated by GCC 3.x or newer). Otherwise,
+// returns false.
+bool Symbolize(void *pc, char *out, int out_size);
+
+_END_GOOGLE_NAMESPACE_
+
+#endif // BASE_SYMBOLIZE_H_
diff --git a/extern/libmv/third_party/glog/src/utilities.cc b/extern/libmv/third_party/glog/src/utilities.cc
new file mode 100644
index 00000000000..e97d4f237ec
--- /dev/null
+++ b/extern/libmv/third_party/glog/src/utilities.cc
@@ -0,0 +1,335 @@
+// Copyright (c) 2008, Google Inc.
+// 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.
+//
+// Author: Shinichiro Hamaji
+
+#include "utilities.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include <signal.h>
+#ifdef HAVE_SYS_TIME_H
+# include <sys/time.h>
+#endif
+#include <time.h>
+#if defined(HAVE_SYSCALL_H)
+#include <syscall.h> // for syscall()
+#elif defined(HAVE_SYS_SYSCALL_H)
+#include <sys/syscall.h> // for syscall()
+#endif
+#ifdef HAVE_SYSLOG_H
+# include <syslog.h>
+#endif
+
+#include "base/googleinit.h"
+
+using std::string;
+
+_START_GOOGLE_NAMESPACE_
+
+static const char* g_program_invocation_short_name = NULL;
+static pthread_t g_main_thread_id;
+
+_END_GOOGLE_NAMESPACE_
+
+// The following APIs are all internal.
+#ifdef HAVE_STACKTRACE
+
+#include "stacktrace.h"
+#include "symbolize.h"
+#include "base/commandlineflags.h"
+
+GLOG_DEFINE_bool(symbolize_stacktrace, true,
+ "Symbolize the stack trace in the tombstone");
+
+_START_GOOGLE_NAMESPACE_
+
+typedef void DebugWriter(const char*, void*);
+
+// The %p field width for printf() functions is two characters per byte.
+// For some environments, add two extra bytes for the leading "0x".
+static const int kPrintfPointerFieldWidth = 2 + 2 * sizeof(void*);
+
+static void DebugWriteToStderr(const char* data, void *unused) {
+ // This one is signal-safe.
+ write(STDERR_FILENO, data, strlen(data));
+}
+
+void DebugWriteToString(const char* data, void *arg) {
+ reinterpret_cast<string*>(arg)->append(data);
+}
+
+#ifdef HAVE_SYMBOLIZE
+// Print a program counter and its symbol name.
+static void DumpPCAndSymbol(DebugWriter *writerfn, void *arg, void *pc,
+ const char * const prefix) {
+ char tmp[1024];
+ const char *symbol = "(unknown)";
+ // Symbolizes the previous address of pc because pc may be in the
+ // next function. The overrun happens when the function ends with
+ // a call to a function annotated noreturn (e.g. CHECK).
+ if (Symbolize(reinterpret_cast<char *>(pc) - 1, tmp, sizeof(tmp))) {
+ symbol = tmp;
+ }
+ char buf[1024];
+ snprintf(buf, sizeof(buf), "%s@ %*p %s\n",
+ prefix, kPrintfPointerFieldWidth, pc, symbol);
+ writerfn(buf, arg);
+}
+#endif
+
+static void DumpPC(DebugWriter *writerfn, void *arg, void *pc,
+ const char * const prefix) {
+ char buf[100];
+ snprintf(buf, sizeof(buf), "%s@ %*p\n",
+ prefix, kPrintfPointerFieldWidth, pc);
+ writerfn(buf, arg);
+}
+
+// Dump current stack trace as directed by writerfn
+static void DumpStackTrace(int skip_count, DebugWriter *writerfn, void *arg) {
+ // Print stack trace
+ void* stack[32];
+ int depth = GetStackTrace(stack, ARRAYSIZE(stack), skip_count+1);
+ for (int i = 0; i < depth; i++) {
+#if defined(HAVE_SYMBOLIZE)
+ if (FLAGS_symbolize_stacktrace) {
+ DumpPCAndSymbol(writerfn, arg, stack[i], " ");
+ } else {
+ DumpPC(writerfn, arg, stack[i], " ");
+ }
+#else
+ DumpPC(writerfn, arg, stack[i], " ");
+#endif
+ }
+}
+
+static void DumpStackTraceAndExit() {
+ DumpStackTrace(1, DebugWriteToStderr, NULL);
+
+ // Set the default signal handler for SIGABRT, to avoid invoking our
+ // own signal handler installed by InstallFailedSignalHandler().
+ struct sigaction sig_action;
+ memset(&sig_action, 0, sizeof(sig_action));
+ sigemptyset(&sig_action.sa_mask);
+ sig_action.sa_handler = SIG_DFL;
+ sigaction(SIGABRT, &sig_action, NULL);
+
+ abort();
+}
+
+_END_GOOGLE_NAMESPACE_
+
+#endif // HAVE_STACKTRACE
+
+_START_GOOGLE_NAMESPACE_
+
+namespace glog_internal_namespace_ {
+
+const char* ProgramInvocationShortName() {
+ if (g_program_invocation_short_name != NULL) {
+ return g_program_invocation_short_name;
+ } else {
+ // TODO(hamaji): Use /proc/self/cmdline and so?
+ return "UNKNOWN";
+ }
+}
+
+bool IsGoogleLoggingInitialized() {
+ return g_program_invocation_short_name != NULL;
+}
+
+bool is_default_thread() {
+ if (g_program_invocation_short_name == NULL) {
+ // InitGoogleLogging() not yet called, so unlikely to be in a different
+ // thread
+ return true;
+ } else {
+ return pthread_equal(pthread_self(), g_main_thread_id);
+ }
+}
+
+#ifdef OS_WINDOWS
+struct timeval {
+ long tv_sec, tv_usec;
+};
+
+// Based on: http://www.google.com/codesearch/p?hl=en#dR3YEbitojA/os_win32.c&q=GetSystemTimeAsFileTime%20license:bsd
+// See COPYING for copyright information.
+static int gettimeofday(struct timeval *tv, void* tz) {
+#define EPOCHFILETIME (116444736000000000ULL)
+ FILETIME ft;
+ LARGE_INTEGER li;
+ uint64 tt;
+
+ GetSystemTimeAsFileTime(&ft);
+ li.LowPart = ft.dwLowDateTime;
+ li.HighPart = ft.dwHighDateTime;
+ tt = (li.QuadPart - EPOCHFILETIME) / 10;
+ tv->tv_sec = tt / 1000000;
+ tv->tv_usec = tt % 1000000;
+
+ return 0;
+}
+#endif
+
+int64 CycleClock_Now() {
+ // TODO(hamaji): temporary impementation - it might be too slow.
+ struct timeval tv;
+ gettimeofday(&tv, NULL);
+ return static_cast<int64>(tv.tv_sec) * 1000000 + tv.tv_usec;
+}
+
+int64 UsecToCycles(int64 usec) {
+ return usec;
+}
+
+WallTime WallTime_Now() {
+ // Now, cycle clock is retuning microseconds since the epoch.
+ return CycleClock_Now() * 0.000001;
+}
+
+static int32 g_main_thread_pid = getpid();
+int32 GetMainThreadPid() {
+ return g_main_thread_pid;
+}
+
+pid_t GetTID() {
+ // On Linux and FreeBSD, we try to use gettid().
+#if defined OS_LINUX || defined OS_FREEBSD || defined OS_MACOSX
+#ifndef __NR_gettid
+#ifdef OS_MACOSX
+#define __NR_gettid SYS_gettid
+#elif ! defined __i386__
+#error "Must define __NR_gettid for non-x86 platforms"
+#else
+#define __NR_gettid 224
+#endif
+#endif
+ static bool lacks_gettid = false;
+ if (!lacks_gettid) {
+ pid_t tid = syscall(__NR_gettid);
+ if (tid != -1) {
+ return tid;
+ }
+ // Technically, this variable has to be volatile, but there is a small
+ // performance penalty in accessing volatile variables and there should
+ // not be any serious adverse effect if a thread does not immediately see
+ // the value change to "true".
+ lacks_gettid = true;
+ }
+#endif // OS_LINUX || OS_FREEBSD
+
+ // If gettid() could not be used, we use one of the following.
+#if defined OS_LINUX
+ return getpid(); // Linux: getpid returns thread ID when gettid is absent
+#elif defined OS_WINDOWS || defined OS_CYGWIN
+ return GetCurrentThreadId();
+#else
+ // If none of the techniques above worked, we use pthread_self().
+ return (pid_t)(uintptr_t)pthread_self();
+#endif
+}
+
+const char* const_basename(const char* filepath) {
+ const char* base = strrchr(filepath, '/');
+#ifdef OS_WINDOWS // Look for either path separator in Windows
+ if (!base)
+ base = strrchr(filepath, '\\');
+#endif
+ return base ? (base+1) : filepath;
+}
+
+static string g_my_user_name;
+const string& MyUserName() {
+ return g_my_user_name;
+}
+static void MyUserNameInitializer() {
+ // TODO(hamaji): Probably this is not portable.
+#if defined(OS_WINDOWS)
+ const char* user = getenv("USERNAME");
+#else
+ const char* user = getenv("USER");
+#endif
+ if (user != NULL) {
+ g_my_user_name = user;
+ } else {
+ g_my_user_name = "invalid-user";
+ }
+}
+REGISTER_MODULE_INITIALIZER(utilities, MyUserNameInitializer());
+
+#ifdef HAVE_STACKTRACE
+void DumpStackTraceToString(string* stacktrace) {
+ DumpStackTrace(1, DebugWriteToString, stacktrace);
+}
+#endif
+
+// We use an atomic operation to prevent problems with calling CrashReason
+// from inside the Mutex implementation (potentially through RAW_CHECK).
+static const CrashReason* g_reason = 0;
+
+void SetCrashReason(const CrashReason* r) {
+ sync_val_compare_and_swap(&g_reason,
+ reinterpret_cast<const CrashReason*>(0),
+ r);
+}
+
+} // namespace glog_internal_namespace_
+
+void InitGoogleLogging(const char* argv0) {
+ CHECK(!IsGoogleLoggingInitialized())
+ << "You called InitGoogleLogging() twice!";
+ const char* slash = strrchr(argv0, '/');
+#ifdef OS_WINDOWS
+ if (!slash) slash = strrchr(argv0, '\\');
+#endif
+ g_program_invocation_short_name = slash ? slash + 1 : argv0;
+ g_main_thread_id = pthread_self();
+
+#ifdef HAVE_STACKTRACE
+ InstallFailureFunction(&DumpStackTraceAndExit);
+#endif
+}
+
+void ShutdownGoogleLogging() {
+ CHECK(IsGoogleLoggingInitialized())
+ << "You called ShutdownGoogleLogging() without InitGoogleLogging() first!";
+#ifdef HAVE_SYSLOG_H
+ closelog();
+#endif
+}
+
+_END_GOOGLE_NAMESPACE_
+
+// Make an implementation of stacktrace compiled.
+#ifdef STACKTRACE_H
+# include STACKTRACE_H
+#endif
diff --git a/extern/libmv/third_party/glog/src/utilities.h b/extern/libmv/third_party/glog/src/utilities.h
new file mode 100644
index 00000000000..2d4e99e595e
--- /dev/null
+++ b/extern/libmv/third_party/glog/src/utilities.h
@@ -0,0 +1,222 @@
+// Copyright (c) 2008, Google Inc.
+// 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.
+//
+// Author: Shinichiro Hamaji
+//
+// Define utilties for glog internal usage.
+
+#ifndef UTILITIES_H__
+#define UTILITIES_H__
+
+#if defined(WIN32) || defined(_WIN32) || defined(__WIN32__)
+# define OS_WINDOWS
+#elif defined(__CYGWIN__) || defined(__CYGWIN32__)
+# define OS_CYGWIN
+#elif defined(linux) || defined(__linux) || defined(__linux__)
+# define OS_LINUX
+#elif defined(macintosh) || defined(__APPLE__) || defined(__APPLE_CC__)
+# define OS_MACOSX
+#elif defined(__FreeBSD__)
+# define OS_FREEBSD
+#elif defined(__NetBSD__)
+# define OS_NETBSD
+#elif defined(__OpenBSD__)
+# define OS_OPENBSD
+#else
+// TODO(hamaji): Add other platforms.
+#endif
+
+// printf macros for size_t, in the style of inttypes.h
+#ifdef _LP64
+#define __PRIS_PREFIX "z"
+#else
+#define __PRIS_PREFIX
+#endif
+
+// Use these macros after a % in a printf format string
+// to get correct 32/64 bit behavior, like this:
+// size_t size = records.size();
+// printf("%"PRIuS"\n", size);
+
+#define PRIdS __PRIS_PREFIX "d"
+#define PRIxS __PRIS_PREFIX "x"
+#define PRIuS __PRIS_PREFIX "u"
+#define PRIXS __PRIS_PREFIX "X"
+#define PRIoS __PRIS_PREFIX "o"
+
+#include "base/mutex.h" // This must go first so we get _XOPEN_SOURCE
+
+#include <string>
+
+#if defined(OS_WINDOWS)
+# include "port.h"
+#endif
+
+#include "config.h"
+#include <glog/logging.h>
+
+// There are three different ways we can try to get the stack trace:
+//
+// 1) The libunwind library. This is still in development, and as a
+// separate library adds a new dependency, but doesn't need a frame
+// pointer. It also doesn't call malloc.
+//
+// 2) Our hand-coded stack-unwinder. This depends on a certain stack
+// layout, which is used by gcc (and those systems using a
+// gcc-compatible ABI) on x86 systems, at least since gcc 2.95.
+// It uses the frame pointer to do its work.
+//
+// 3) The gdb unwinder -- also the one used by the c++ exception code.
+// It's obviously well-tested, but has a fatal flaw: it can call
+// malloc() from the unwinder. This is a problem because we're
+// trying to use the unwinder to instrument malloc().
+//
+// Note: if you add a new implementation here, make sure it works
+// correctly when GetStackTrace() is called with max_depth == 0.
+// Some code may do that.
+
+#if defined(HAVE_LIB_UNWIND)
+# define STACKTRACE_H "stacktrace_libunwind-inl.h"
+#elif !defined(NO_FRAME_POINTER)
+# if defined(__i386__) && __GNUC__ >= 2
+# define STACKTRACE_H "stacktrace_x86-inl.h"
+# elif defined(__x86_64__) && __GNUC__ >= 2
+# define STACKTRACE_H "stacktrace_x86_64-inl.h"
+# elif (defined(__ppc__) || defined(__PPC__)) && __GNUC__ >= 2
+# define STACKTRACE_H "stacktrace_powerpc-inl.h"
+# endif
+#endif
+
+#if !defined(STACKTRACE_H) && defined(HAVE_EXECINFO_H)
+# define STACKTRACE_H "stacktrace_generic-inl.h"
+#endif
+
+#if defined(STACKTRACE_H)
+# define HAVE_STACKTRACE
+#endif
+
+// defined by gcc
+#if defined(__ELF__) && defined(OS_LINUX)
+# define HAVE_SYMBOLIZE
+#elif defined(OS_MACOSX) && defined(HAVE_DLADDR)
+// Use dladdr to symbolize.
+# define HAVE_SYMBOLIZE
+#endif
+
+#ifndef ARRAYSIZE
+// There is a better way, but this is good enough for our purpose.
+# define ARRAYSIZE(a) (sizeof(a) / sizeof(*(a)))
+#endif
+
+_START_GOOGLE_NAMESPACE_
+
+namespace glog_internal_namespace_ {
+
+#ifdef HAVE___ATTRIBUTE__
+# define ATTRIBUTE_NOINLINE __attribute__ ((noinline))
+# define HAVE_ATTRIBUTE_NOINLINE
+#else
+# define ATTRIBUTE_NOINLINE
+#endif
+
+const char* ProgramInvocationShortName();
+
+bool IsGoogleLoggingInitialized();
+
+bool is_default_thread();
+
+int64 CycleClock_Now();
+
+int64 UsecToCycles(int64 usec);
+
+typedef double WallTime;
+WallTime WallTime_Now();
+
+int32 GetMainThreadPid();
+
+pid_t GetTID();
+
+const std::string& MyUserName();
+
+// Get the part of filepath after the last path separator.
+// (Doesn't modify filepath, contrary to basename() in libgen.h.)
+const char* const_basename(const char* filepath);
+
+// Wrapper of __sync_val_compare_and_swap. If the GCC extension isn't
+// defined, we try the CPU specific logics (we only support x86 and
+// x86_64 for now) first, then use a naive implementation, which has a
+// race condition.
+template<typename T>
+inline T sync_val_compare_and_swap(T* ptr, T oldval, T newval) {
+#if defined(HAVE___SYNC_VAL_COMPARE_AND_SWAP)
+ return __sync_val_compare_and_swap(ptr, oldval, newval);
+#elif defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__))
+ T ret;
+ __asm__ __volatile__("lock; cmpxchg %1, (%2);"
+ :"=a"(ret)
+ // GCC may produces %sil or %dil for
+ // constraint "r", but some of apple's gas
+ // dosn't know the 8 bit registers.
+ // We use "q" to avoid these registers.
+ :"q"(newval), "q"(ptr), "a"(oldval)
+ :"memory", "cc");
+ return ret;
+#else
+ T ret = *ptr;
+ if (ret == oldval) {
+ *ptr = newval;
+ }
+ return ret;
+#endif
+}
+
+void DumpStackTraceToString(std::string* stacktrace);
+
+struct CrashReason {
+ CrashReason() : filename(0), line_number(0), message(0), depth(0) {}
+
+ const char* filename;
+ int line_number;
+ const char* message;
+
+ // We'll also store a bit of stack trace context at the time of crash as
+ // it may not be available later on.
+ void* stack[32];
+ int depth;
+};
+
+void SetCrashReason(const CrashReason* r);
+
+} // namespace glog_internal_namespace_
+
+_END_GOOGLE_NAMESPACE_
+
+using namespace GOOGLE_NAMESPACE::glog_internal_namespace_;
+
+#endif // UTILITIES_H__
diff --git a/extern/libmv/third_party/glog/src/vlog_is_on.cc b/extern/libmv/third_party/glog/src/vlog_is_on.cc
new file mode 100644
index 00000000000..ed88514dce5
--- /dev/null
+++ b/extern/libmv/third_party/glog/src/vlog_is_on.cc
@@ -0,0 +1,249 @@
+// Copyright (c) 1999, 2007, Google Inc.
+// 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.
+//
+// Author: Ray Sidney and many others
+//
+// Broken out from logging.cc by Soren Lassen
+// logging_unittest.cc covers the functionality herein
+
+#include "utilities.h"
+
+#include <string.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <cstdio>
+#include <string>
+#include "base/commandlineflags.h"
+#include <glog/logging.h>
+#include <glog/raw_logging.h>
+#include "base/googleinit.h"
+
+// glog doesn't have annotation
+#define ANNOTATE_BENIGN_RACE(address, description)
+
+using std::string;
+
+GLOG_DEFINE_int32(v, 0, "Show all VLOG(m) messages for m <= this."
+" Overridable by --vmodule.");
+
+GLOG_DEFINE_string(vmodule, "", "per-module verbose level."
+" Argument is a comma-separated list of <module name>=<log level>."
+" <module name> is a glob pattern, matched against the filename base"
+" (that is, name ignoring .cc/.h./-inl.h)."
+" <log level> overrides any value given by --v.");
+
+_START_GOOGLE_NAMESPACE_
+
+namespace glog_internal_namespace_ {
+
+// Implementation of fnmatch that does not need 0-termination
+// of arguments and does not allocate any memory,
+// but we only support "*" and "?" wildcards, not the "[...]" patterns.
+// It's not a static function for the unittest.
+GOOGLE_GLOG_DLL_DECL bool SafeFNMatch_(const char* pattern,
+ size_t patt_len,
+ const char* str,
+ size_t str_len) {
+ int p = 0;
+ int s = 0;
+ while (1) {
+ if (p == patt_len && s == str_len) return true;
+ if (p == patt_len) return false;
+ if (s == str_len) return p+1 == patt_len && pattern[p] == '*';
+ if (pattern[p] == str[s] || pattern[p] == '?') {
+ p += 1;
+ s += 1;
+ continue;
+ }
+ if (pattern[p] == '*') {
+ if (p+1 == patt_len) return true;
+ do {
+ if (SafeFNMatch_(pattern+(p+1), patt_len-(p+1), str+s, str_len-s)) {
+ return true;
+ }
+ s += 1;
+ } while (s != str_len);
+ return false;
+ }
+ return false;
+ }
+}
+
+} // namespace glog_internal_namespace_
+
+using glog_internal_namespace_::SafeFNMatch_;
+
+int32 kLogSiteUninitialized = 1000;
+
+// List of per-module log levels from FLAGS_vmodule.
+// Once created each element is never deleted/modified
+// except for the vlog_level: other threads will read VModuleInfo blobs
+// w/o locks and we'll store pointers to vlog_level at VLOG locations
+// that will never go away.
+// We can't use an STL struct here as we wouldn't know
+// when it's safe to delete/update it: other threads need to use it w/o locks.
+struct VModuleInfo {
+ string module_pattern;
+ mutable int32 vlog_level; // Conceptually this is an AtomicWord, but it's
+ // too much work to use AtomicWord type here
+ // w/o much actual benefit.
+ const VModuleInfo* next;
+};
+
+// This protects the following global variables.
+static Mutex vmodule_lock;
+// Pointer to head of the VModuleInfo list.
+// It's a map from module pattern to logging level for those module(s).
+static VModuleInfo* vmodule_list = 0;
+// Boolean initialization flag.
+static bool inited_vmodule = false;
+
+// L >= vmodule_lock.
+static void VLOG2Initializer() {
+ vmodule_lock.AssertHeld();
+ // Can now parse --vmodule flag and initialize mapping of module-specific
+ // logging levels.
+ inited_vmodule = false;
+ const char* vmodule = FLAGS_vmodule.c_str();
+ const char* sep;
+ VModuleInfo* head = NULL;
+ VModuleInfo* tail = NULL;
+ while ((sep = strchr(vmodule, '=')) != NULL) {
+ string pattern(vmodule, sep - vmodule);
+ int module_level;
+ if (sscanf(sep, "=%d", &module_level) == 1) {
+ VModuleInfo* info = new VModuleInfo;
+ info->module_pattern = pattern;
+ info->vlog_level = module_level;
+ if (head) tail->next = info;
+ else head = info;
+ tail = info;
+ }
+ // Skip past this entry
+ vmodule = strchr(sep, ',');
+ if (vmodule == NULL) break;
+ vmodule++; // Skip past ","
+ }
+ if (head) { // Put them into the list at the head:
+ tail->next = vmodule_list;
+ vmodule_list = head;
+ }
+ inited_vmodule = true;
+}
+
+// This can be called very early, so we use SpinLock and RAW_VLOG here.
+int SetVLOGLevel(const char* module_pattern, int log_level) {
+ int result = FLAGS_v;
+ int const pattern_len = strlen(module_pattern);
+ bool found = false;
+ MutexLock l(&vmodule_lock); // protect whole read-modify-write
+ for (const VModuleInfo* info = vmodule_list;
+ info != NULL; info = info->next) {
+ if (info->module_pattern == module_pattern) {
+ if (!found) {
+ result = info->vlog_level;
+ found = true;
+ }
+ info->vlog_level = log_level;
+ } else if (!found &&
+ SafeFNMatch_(info->module_pattern.c_str(),
+ info->module_pattern.size(),
+ module_pattern, pattern_len)) {
+ result = info->vlog_level;
+ found = true;
+ }
+ }
+ if (!found) {
+ VModuleInfo* info = new VModuleInfo;
+ info->module_pattern = module_pattern;
+ info->vlog_level = log_level;
+ info->next = vmodule_list;
+ vmodule_list = info;
+ }
+ RAW_VLOG(1, "Set VLOG level for \"%s\" to %d", module_pattern, log_level);
+ return result;
+}
+
+// NOTE: Individual VLOG statements cache the integer log level pointers.
+// NOTE: This function must not allocate memory or require any locks.
+bool InitVLOG3__(int32** site_flag, int32* site_default,
+ const char* fname, int32 verbose_level) {
+ MutexLock l(&vmodule_lock);
+ bool read_vmodule_flag = inited_vmodule;
+ if (!read_vmodule_flag) {
+ VLOG2Initializer();
+ }
+
+ // protect the errno global in case someone writes:
+ // VLOG(..) << "The last error was " << strerror(errno)
+ int old_errno = errno;
+
+ // site_default normally points to FLAGS_v
+ int32* site_flag_value = site_default;
+
+ // Get basename for file
+ const char* base = strrchr(fname, '/');
+ base = base ? (base+1) : fname;
+ const char* base_end = strchr(base, '.');
+ size_t base_length = base_end ? (base_end - base) : strlen(base);
+
+ // Trim out trailing "-inl" if any
+ if (base_length >= 4 && (memcmp(base+base_length-4, "-inl", 4) == 0)) {
+ base_length -= 4;
+ }
+
+ // TODO: Trim out _unittest suffix? Perhaps it is better to have
+ // the extra control and just leave it there.
+
+ // find target in vector of modules, replace site_flag_value with
+ // a module-specific verbose level, if any.
+ for (const VModuleInfo* info = vmodule_list;
+ info != NULL; info = info->next) {
+ if (SafeFNMatch_(info->module_pattern.c_str(), info->module_pattern.size(),
+ base, base_length)) {
+ site_flag_value = &info->vlog_level;
+ // value at info->vlog_level is now what controls
+ // the VLOG at the caller site forever
+ break;
+ }
+ }
+
+ // Cache the vlog value pointer if --vmodule flag has been parsed.
+ ANNOTATE_BENIGN_RACE(site_flag,
+ "*site_flag may be written by several threads,"
+ " but the value will be the same");
+ if (read_vmodule_flag) *site_flag = site_flag_value;
+
+ // restore the errno in case something recoverable went wrong during
+ // the initialization of the VLOG mechanism (see above note "protect the..")
+ errno = old_errno;
+ return *site_flag_value >= verbose_level;
+}
+
+_END_GOOGLE_NAMESPACE_
diff --git a/extern/libmv/third_party/glog/src/windows/config.h b/extern/libmv/third_party/glog/src/windows/config.h
new file mode 100644
index 00000000000..682a1b9309d
--- /dev/null
+++ b/extern/libmv/third_party/glog/src/windows/config.h
@@ -0,0 +1,136 @@
+/* src/config.h.in. Generated from configure.ac by autoheader. */
+
+/* Namespace for Google classes */
+#define GOOGLE_NAMESPACE google
+
+/* Define if you have the `dladdr' function */
+#undef HAVE_DLADDR
+
+/* Define to 1 if you have the <dlfcn.h> header file. */
+#undef HAVE_DLFCN_H
+
+/* Define to 1 if you have the <execinfo.h> header file. */
+#undef HAVE_EXECINFO_H
+
+/* Define to 1 if you have the <inttypes.h> header file. */
+#undef HAVE_INTTYPES_H
+
+/* Define to 1 if you have the <libunwind.h> header file. */
+#undef HAVE_LIBUNWIND_H
+
+/* define if you have google gflags library */
+#define HAVE_LIB_GFLAGS 1
+
+/* define if you have libunwind */
+#undef HAVE_LIB_UNWIND
+
+/* Define to 1 if you have the <memory.h> header file. */
+#undef HAVE_MEMORY_H
+
+/* define if the compiler implements namespaces */
+#undef HAVE_NAMESPACES
+
+/* Define if you have POSIX threads libraries and header files. */
+#undef HAVE_PTHREAD
+
+/* define if the compiler implements pthread_rwlock_* */
+#undef HAVE_RWLOCK
+
+/* Define if you have the `sigaltstack' function */
+#undef HAVE_SIGALTSTACK
+
+/* Define to 1 if you have the <stdint.h> header file. */
+#undef HAVE_STDINT_H
+
+/* Define to 1 if you have the <stdlib.h> header file. */
+#undef HAVE_STDLIB_H
+
+/* Define to 1 if you have the <strings.h> header file. */
+#undef HAVE_STRINGS_H
+
+/* Define to 1 if you have the <string.h> header file. */
+#undef HAVE_STRING_H
+
+/* Define to 1 if you have the <syscall.h> header file. */
+#undef HAVE_SYSCALL_H
+
+/* Define to 1 if you have the <sys/stat.h> header file. */
+#undef HAVE_SYS_STAT_H
+
+/* Define to 1 if you have the <sys/syscall.h> header file. */
+#undef HAVE_SYS_SYSCALL_H
+
+/* Define to 1 if you have the <sys/types.h> header file. */
+#undef HAVE_SYS_TYPES_H
+
+/* Define to 1 if you have the <ucontext.h> header file. */
+#undef HAVE_UCONTEXT_H
+
+/* Define to 1 if you have the <unistd.h> header file. */
+#undef HAVE_UNISTD_H
+
+/* define if the compiler supports using expression for operator */
+#undef HAVE_USING_OPERATOR
+
+/* define if your compiler has __attribute__ */
+#undef HAVE___ATTRIBUTE__
+
+/* define if your compiler has __builtin_expect */
+#undef HAVE___BUILTIN_EXPECT
+
+/* define if your compiler has __sync_val_compare_and_swap */
+#undef HAVE___SYNC_VAL_COMPARE_AND_SWAP
+
+/* Name of package */
+#undef PACKAGE
+
+/* Define to the address where bug reports for this package should be sent. */
+#undef PACKAGE_BUGREPORT
+
+/* Define to the full name of this package. */
+#undef PACKAGE_NAME
+
+/* Define to the full name and version of this package. */
+#undef PACKAGE_STRING
+
+/* Define to the one symbol short name of this package. */
+#undef PACKAGE_TARNAME
+
+/* Define to the version of this package. */
+#undef PACKAGE_VERSION
+
+/* How to access the PC from a struct ucontext */
+#undef PC_FROM_UCONTEXT
+
+/* Define to necessary symbol if this constant uses a non-standard name on
+ your system. */
+#undef PTHREAD_CREATE_JOINABLE
+
+/* The size of `void *', as computed by sizeof. */
+#undef SIZEOF_VOID_P
+
+/* Define to 1 if you have the ANSI C header files. */
+#undef STDC_HEADERS
+
+/* the namespace where STL code like vector<> is defined */
+#undef STL_NAMESPACE
+
+/* Version number of package */
+#undef VERSION
+
+/* Stops putting the code inside the Google namespace */
+#define _END_GOOGLE_NAMESPACE_ }
+
+/* Puts following code inside the Google namespace */
+#define _START_GOOGLE_NAMESPACE_ namespace google {
+
+/* Always the empty-string on non-windows systems. On windows, should be
+ "__declspec(dllexport)". This way, when we compile the dll, we export our
+ functions/classes. It's safe to define this here because config.h is only
+ used internally, to compile the DLL, and every DLL source file #includes
+ "config.h" before anything else. */
+#ifndef GOOGLE_GLOG_DLL_DECL
+# define GOOGLE_GLOG_IS_A_DLL 1 /* not set if you're statically linking */
+# define GOOGLE_GLOG_DLL_DECL __declspec(dllexport)
+# define GOOGLE_GLOG_DLL_DECL_FOR_UNITTESTS __declspec(dllimport)
+#endif
diff --git a/extern/libmv/third_party/glog/src/windows/glog/log_severity.h b/extern/libmv/third_party/glog/src/windows/glog/log_severity.h
new file mode 100644
index 00000000000..5e7d09effb2
--- /dev/null
+++ b/extern/libmv/third_party/glog/src/windows/glog/log_severity.h
@@ -0,0 +1,88 @@
+// This file is automatically generated from src/glog/log_severity.h
+// using src/windows/preprocess.sh.
+// DO NOT EDIT!
+
+// Copyright (c) 2007, Google Inc.
+// 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.
+
+#ifndef BASE_LOG_SEVERITY_H__
+#define BASE_LOG_SEVERITY_H__
+
+// Annoying stuff for windows -- makes sure clients can import these functions
+#ifndef GOOGLE_GLOG_DLL_DECL
+# if defined(_WIN32) && !defined(__CYGWIN__)
+# define GOOGLE_GLOG_DLL_DECL __declspec(dllimport)
+# else
+# define GOOGLE_GLOG_DLL_DECL
+# endif
+#endif
+
+// Variables of type LogSeverity are widely taken to lie in the range
+// [0, NUM_SEVERITIES-1]. Be careful to preserve this assumption if
+// you ever need to change their values or add a new severity.
+typedef int LogSeverity;
+
+const int INFO = 0, WARNING = 1, ERROR = 2, FATAL = 3, NUM_SEVERITIES = 4;
+
+// DFATAL is FATAL in debug mode, ERROR in normal mode
+#ifdef NDEBUG
+#define DFATAL_LEVEL ERROR
+#else
+#define DFATAL_LEVEL FATAL
+#endif
+
+extern GOOGLE_GLOG_DLL_DECL const char* const LogSeverityNames[NUM_SEVERITIES];
+
+// NDEBUG usage helpers related to (RAW_)DCHECK:
+//
+// DEBUG_MODE is for small !NDEBUG uses like
+// if (DEBUG_MODE) foo.CheckThatFoo();
+// instead of substantially more verbose
+// #ifndef NDEBUG
+// foo.CheckThatFoo();
+// #endif
+//
+// IF_DEBUG_MODE is for small !NDEBUG uses like
+// IF_DEBUG_MODE( string error; )
+// DCHECK(Foo(&error)) << error;
+// instead of substantially more verbose
+// #ifndef NDEBUG
+// string error;
+// DCHECK(Foo(&error)) << error;
+// #endif
+//
+#ifdef NDEBUG
+enum { DEBUG_MODE = 0 };
+#define IF_DEBUG_MODE(x)
+#else
+enum { DEBUG_MODE = 1 };
+#define IF_DEBUG_MODE(x) x
+#endif
+
+#endif // BASE_LOG_SEVERITY_H__
diff --git a/extern/libmv/third_party/glog/src/windows/glog/logging.h b/extern/libmv/third_party/glog/src/windows/glog/logging.h
new file mode 100644
index 00000000000..de51586f8e3
--- /dev/null
+++ b/extern/libmv/third_party/glog/src/windows/glog/logging.h
@@ -0,0 +1,1510 @@
+// This file is automatically generated from src/glog/logging.h.in
+// using src/windows/preprocess.sh.
+// DO NOT EDIT!
+
+// Copyright (c) 1999, Google Inc.
+// 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.
+//
+// Author: Ray Sidney
+//
+// This file contains #include information about logging-related stuff.
+// Pretty much everybody needs to #include this file so that they can
+// log various happenings.
+//
+#ifndef _LOGGING_H_
+#define _LOGGING_H_
+
+#include <errno.h>
+#include <string.h>
+#include <time.h>
+#include <string>
+#if 0
+# include <unistd.h>
+#endif
+#ifdef __DEPRECATED
+// Make GCC quiet.
+# undef __DEPRECATED
+# include <strstream>
+# define __DEPRECATED
+#else
+# include <strstream>
+#endif
+#include <vector>
+
+// Annoying stuff for windows -- makes sure clients can import these functions
+#ifndef GOOGLE_GLOG_DLL_DECL
+# if defined(_WIN32) && !defined(__CYGWIN__)
+# define GOOGLE_GLOG_DLL_DECL __declspec(dllimport)
+# else
+# define GOOGLE_GLOG_DLL_DECL
+# endif
+#endif
+
+// We care a lot about number of bits things take up. Unfortunately,
+// systems define their bit-specific ints in a lot of different ways.
+// We use our own way, and have a typedef to get there.
+// Note: these commands below may look like "#if 1" or "#if 0", but
+// that's because they were constructed that way at ./configure time.
+// Look at logging.h.in to see how they're calculated (based on your config).
+#if 0
+#include <stdint.h> // the normal place uint16_t is defined
+#endif
+#if 0
+#include <sys/types.h> // the normal place u_int16_t is defined
+#endif
+#if 0
+#include <inttypes.h> // a third place for uint16_t or u_int16_t
+#endif
+
+#if 1
+#include "third_party/gflags/gflags.h"
+#endif
+
+namespace google {
+
+#if 0 // the C99 format
+typedef int32_t int32;
+typedef uint32_t uint32;
+typedef int64_t int64;
+typedef uint64_t uint64;
+#elif 0 // the BSD format
+typedef int32_t int32;
+typedef u_int32_t uint32;
+typedef int64_t int64;
+typedef u_int64_t uint64;
+#elif 1 // the windows (vc7) format
+typedef __int32 int32;
+typedef unsigned __int32 uint32;
+typedef __int64 int64;
+typedef unsigned __int64 uint64;
+#else
+#error Do not know how to define a 32-bit integer quantity on your system
+#endif
+
+}
+
+// The global value of GOOGLE_STRIP_LOG. All the messages logged to
+// LOG(XXX) with severity less than GOOGLE_STRIP_LOG will not be displayed.
+// If it can be determined at compile time that the message will not be
+// printed, the statement will be compiled out.
+//
+// Example: to strip out all INFO and WARNING messages, use the value
+// of 2 below. To make an exception for WARNING messages from a single
+// file, add "#define GOOGLE_STRIP_LOG 1" to that file _before_ including
+// base/logging.h
+#ifndef GOOGLE_STRIP_LOG
+#define GOOGLE_STRIP_LOG 0
+#endif
+
+// GCC can be told that a certain branch is not likely to be taken (for
+// instance, a CHECK failure), and use that information in static analysis.
+// Giving it this information can help it optimize for the common case in
+// the absence of better information (ie. -fprofile-arcs).
+//
+#ifndef GOOGLE_PREDICT_BRANCH_NOT_TAKEN
+#if 0
+#define GOOGLE_PREDICT_BRANCH_NOT_TAKEN(x) (__builtin_expect(x, 0))
+#else
+#define GOOGLE_PREDICT_BRANCH_NOT_TAKEN(x) x
+#endif
+#endif
+
+// Make a bunch of macros for logging. The way to log things is to stream
+// things to LOG(<a particular severity level>). E.g.,
+//
+// LOG(INFO) << "Found " << num_cookies << " cookies";
+//
+// You can capture log messages in a string, rather than reporting them
+// immediately:
+//
+// vector<string> errors;
+// LOG_STRING(ERROR, &errors) << "Couldn't parse cookie #" << cookie_num;
+//
+// This pushes back the new error onto 'errors'; if given a NULL pointer,
+// it reports the error via LOG(ERROR).
+//
+// You can also do conditional logging:
+//
+// LOG_IF(INFO, num_cookies > 10) << "Got lots of cookies";
+//
+// You can also do occasional logging (log every n'th occurrence of an
+// event):
+//
+// LOG_EVERY_N(INFO, 10) << "Got the " << COUNTER << "th cookie";
+//
+// The above will cause log messages to be output on the 1st, 11th, 21st, ...
+// times it is executed. Note that the special COUNTER value is used to
+// identify which repetition is happening.
+//
+// You can also do occasional conditional logging (log every n'th
+// occurrence of an event, when condition is satisfied):
+//
+// LOG_IF_EVERY_N(INFO, (size > 1024), 10) << "Got the " << COUNTER
+// << "th big cookie";
+//
+// You can log messages the first N times your code executes a line. E.g.
+//
+// LOG_FIRST_N(INFO, 20) << "Got the " << COUNTER << "th cookie";
+//
+// Outputs log messages for the first 20 times it is executed.
+//
+// Analogous SYSLOG, SYSLOG_IF, and SYSLOG_EVERY_N macros are available.
+// These log to syslog as well as to the normal logs. If you use these at
+// all, you need to be aware that syslog can drastically reduce performance,
+// especially if it is configured for remote logging! Don't use these
+// unless you fully understand this and have a concrete need to use them.
+// Even then, try to minimize your use of them.
+//
+// There are also "debug mode" logging macros like the ones above:
+//
+// DLOG(INFO) << "Found cookies";
+//
+// DLOG_IF(INFO, num_cookies > 10) << "Got lots of cookies";
+//
+// DLOG_EVERY_N(INFO, 10) << "Got the " << COUNTER << "th cookie";
+//
+// All "debug mode" logging is compiled away to nothing for non-debug mode
+// compiles.
+//
+// We also have
+//
+// LOG_ASSERT(assertion);
+// DLOG_ASSERT(assertion);
+//
+// which is syntactic sugar for {,D}LOG_IF(FATAL, assert fails) << assertion;
+//
+// There are "verbose level" logging macros. They look like
+//
+// VLOG(1) << "I'm printed when you run the program with --v=1 or more";
+// VLOG(2) << "I'm printed when you run the program with --v=2 or more";
+//
+// These always log at the INFO log level (when they log at all).
+// The verbose logging can also be turned on module-by-module. For instance,
+// --vmodule=mapreduce=2,file=1,gfs*=3 --v=0
+// will cause:
+// a. VLOG(2) and lower messages to be printed from mapreduce.{h,cc}
+// b. VLOG(1) and lower messages to be printed from file.{h,cc}
+// c. VLOG(3) and lower messages to be printed from files prefixed with "gfs"
+// d. VLOG(0) and lower messages to be printed from elsewhere
+//
+// The wildcarding functionality shown by (c) supports both '*' (match
+// 0 or more characters) and '?' (match any single character) wildcards.
+//
+// There's also VLOG_IS_ON(n) "verbose level" condition macro. To be used as
+//
+// if (VLOG_IS_ON(2)) {
+// // do some logging preparation and logging
+// // that can't be accomplished with just VLOG(2) << ...;
+// }
+//
+// There are also VLOG_IF, VLOG_EVERY_N and VLOG_IF_EVERY_N "verbose level"
+// condition macros for sample cases, when some extra computation and
+// preparation for logs is not needed.
+// VLOG_IF(1, (size > 1024))
+// << "I'm printed when size is more than 1024 and when you run the "
+// "program with --v=1 or more";
+// VLOG_EVERY_N(1, 10)
+// << "I'm printed every 10th occurrence, and when you run the program "
+// "with --v=1 or more. Present occurence is " << COUNTER;
+// VLOG_IF_EVERY_N(1, (size > 1024), 10)
+// << "I'm printed on every 10th occurence of case when size is more "
+// " than 1024, when you run the program with --v=1 or more. ";
+// "Present occurence is " << COUNTER;
+//
+// The supported severity levels for macros that allow you to specify one
+// are (in increasing order of severity) INFO, WARNING, ERROR, and FATAL.
+// Note that messages of a given severity are logged not only in the
+// logfile for that severity, but also in all logfiles of lower severity.
+// E.g., a message of severity FATAL will be logged to the logfiles of
+// severity FATAL, ERROR, WARNING, and INFO.
+//
+// There is also the special severity of DFATAL, which logs FATAL in
+// debug mode, ERROR in normal mode.
+//
+// Very important: logging a message at the FATAL severity level causes
+// the program to terminate (after the message is logged).
+//
+// Unless otherwise specified, logs will be written to the filename
+// "<program name>.<hostname>.<user name>.log.<severity level>.", followed
+// by the date, time, and pid (you can't prevent the date, time, and pid
+// from being in the filename).
+//
+// The logging code takes two flags:
+// --v=# set the verbose level
+// --logtostderr log all the messages to stderr instead of to logfiles
+
+// LOG LINE PREFIX FORMAT
+//
+// Log lines have this form:
+//
+// Lmmdd hh:mm:ss.uuuuuu threadid file:line] msg...
+//
+// where the fields are defined as follows:
+//
+// L A single character, representing the log level
+// (eg 'I' for INFO)
+// mm The month (zero padded; ie May is '05')
+// dd The day (zero padded)
+// hh:mm:ss.uuuuuu Time in hours, minutes and fractional seconds
+// threadid The space-padded thread ID as returned by GetTID()
+// (this matches the PID on Linux)
+// file The file name
+// line The line number
+// msg The user-supplied message
+//
+// Example:
+//
+// I1103 11:57:31.739339 24395 google.cc:2341] Command line: ./some_prog
+// I1103 11:57:31.739403 24395 google.cc:2342] Process id 24395
+//
+// NOTE: although the microseconds are useful for comparing events on
+// a single machine, clocks on different machines may not be well
+// synchronized. Hence, use caution when comparing the low bits of
+// timestamps from different machines.
+
+#ifndef DECLARE_VARIABLE
+#define MUST_UNDEF_GFLAGS_DECLARE_MACROS
+#define DECLARE_VARIABLE(type, name, tn) \
+ namespace FLAG__namespace_do_not_use_directly_use_DECLARE_##tn##_instead { \
+ extern GOOGLE_GLOG_DLL_DECL type FLAGS_##name; \
+ } \
+ using FLAG__namespace_do_not_use_directly_use_DECLARE_##tn##_instead::FLAGS_##name
+
+// bool specialization
+#define DECLARE_bool(name) \
+ DECLARE_VARIABLE(bool, name, bool)
+
+// int32 specialization
+#define DECLARE_int32(name) \
+ DECLARE_VARIABLE(google::int32, name, int32)
+
+// Special case for string, because we have to specify the namespace
+// std::string, which doesn't play nicely with our FLAG__namespace hackery.
+#define DECLARE_string(name) \
+ namespace FLAG__namespace_do_not_use_directly_use_DECLARE_string_instead { \
+ extern GOOGLE_GLOG_DLL_DECL std::string FLAGS_##name; \
+ } \
+ using FLAG__namespace_do_not_use_directly_use_DECLARE_string_instead::FLAGS_##name
+#endif
+
+// Set whether log messages go to stderr instead of logfiles
+DECLARE_bool(logtostderr);
+
+// Set whether log messages go to stderr in addition to logfiles.
+DECLARE_bool(alsologtostderr);
+
+// Log messages at a level >= this flag are automatically sent to
+// stderr in addition to log files.
+DECLARE_int32(stderrthreshold);
+
+// Set whether the log prefix should be prepended to each line of output.
+DECLARE_bool(log_prefix);
+
+// Log messages at a level <= this flag are buffered.
+// Log messages at a higher level are flushed immediately.
+DECLARE_int32(logbuflevel);
+
+// Sets the maximum number of seconds which logs may be buffered for.
+DECLARE_int32(logbufsecs);
+
+// Log suppression level: messages logged at a lower level than this
+// are suppressed.
+DECLARE_int32(minloglevel);
+
+// If specified, logfiles are written into this directory instead of the
+// default logging directory.
+DECLARE_string(log_dir);
+
+// Sets the path of the directory into which to put additional links
+// to the log files.
+DECLARE_string(log_link);
+
+DECLARE_int32(v); // in vlog_is_on.cc
+
+// Sets the maximum log file size (in MB).
+DECLARE_int32(max_log_size);
+
+// Sets whether to avoid logging to the disk if the disk is full.
+DECLARE_bool(stop_logging_if_full_disk);
+
+#ifdef MUST_UNDEF_GFLAGS_DECLARE_MACROS
+#undef MUST_UNDEF_GFLAGS_DECLARE_MACROS
+#undef DECLARE_VARIABLE
+#undef DECLARE_bool
+#undef DECLARE_int32
+#undef DECLARE_string
+#endif
+
+// Log messages below the GOOGLE_STRIP_LOG level will be compiled away for
+// security reasons. See LOG(severtiy) below.
+
+// A few definitions of macros that don't generate much code. Since
+// LOG(INFO) and its ilk are used all over our code, it's
+// better to have compact code for these operations.
+
+#if GOOGLE_STRIP_LOG == 0
+#define COMPACT_GOOGLE_LOG_INFO google::LogMessage( \
+ __FILE__, __LINE__)
+#define LOG_TO_STRING_INFO(message) google::LogMessage( \
+ __FILE__, __LINE__, google::INFO, message)
+#else
+#define COMPACT_GOOGLE_LOG_INFO google::NullStream()
+#define LOG_TO_STRING_INFO(message) google::NullStream()
+#endif
+
+#if GOOGLE_STRIP_LOG <= 1
+#define COMPACT_GOOGLE_LOG_WARNING google::LogMessage( \
+ __FILE__, __LINE__, google::WARNING)
+#define LOG_TO_STRING_WARNING(message) google::LogMessage( \
+ __FILE__, __LINE__, google::WARNING, message)
+#else
+#define COMPACT_GOOGLE_LOG_WARNING google::NullStream()
+#define LOG_TO_STRING_WARNING(message) google::NullStream()
+#endif
+
+#if GOOGLE_STRIP_LOG <= 2
+#define COMPACT_GOOGLE_LOG_ERROR google::LogMessage( \
+ __FILE__, __LINE__, google::ERROR)
+#define LOG_TO_STRING_ERROR(message) google::LogMessage( \
+ __FILE__, __LINE__, google::ERROR, message)
+#else
+#define COMPACT_GOOGLE_LOG_ERROR google::NullStream()
+#define LOG_TO_STRING_ERROR(message) google::NullStream()
+#endif
+
+#if GOOGLE_STRIP_LOG <= 3
+#define COMPACT_GOOGLE_LOG_FATAL google::LogMessageFatal( \
+ __FILE__, __LINE__)
+#define LOG_TO_STRING_FATAL(message) google::LogMessage( \
+ __FILE__, __LINE__, google::FATAL, message)
+#else
+#define COMPACT_GOOGLE_LOG_FATAL google::NullStreamFatal()
+#define LOG_TO_STRING_FATAL(message) google::NullStreamFatal()
+#endif
+
+// For DFATAL, we want to use LogMessage (as opposed to
+// LogMessageFatal), to be consistent with the original behavior.
+#ifdef NDEBUG
+#define COMPACT_GOOGLE_LOG_DFATAL COMPACT_GOOGLE_LOG_ERROR
+#elif GOOGLE_STRIP_LOG <= 3
+#define COMPACT_GOOGLE_LOG_DFATAL google::LogMessage( \
+ __FILE__, __LINE__, google::FATAL)
+#else
+#define COMPACT_GOOGLE_LOG_DFATAL google::NullStreamFatal()
+#endif
+
+#define GOOGLE_LOG_INFO(counter) google::LogMessage(__FILE__, __LINE__, google::INFO, counter, &google::LogMessage::SendToLog)
+#define SYSLOG_INFO(counter) \
+ google::LogMessage(__FILE__, __LINE__, google::INFO, counter, \
+ &google::LogMessage::SendToSyslogAndLog)
+#define GOOGLE_LOG_WARNING(counter) \
+ google::LogMessage(__FILE__, __LINE__, google::WARNING, counter, \
+ &google::LogMessage::SendToLog)
+#define SYSLOG_WARNING(counter) \
+ google::LogMessage(__FILE__, __LINE__, google::WARNING, counter, \
+ &google::LogMessage::SendToSyslogAndLog)
+#define GOOGLE_LOG_ERROR(counter) \
+ google::LogMessage(__FILE__, __LINE__, google::ERROR, counter, \
+ &google::LogMessage::SendToLog)
+#define SYSLOG_ERROR(counter) \
+ google::LogMessage(__FILE__, __LINE__, google::ERROR, counter, \
+ &google::LogMessage::SendToSyslogAndLog)
+#define GOOGLE_LOG_FATAL(counter) \
+ google::LogMessage(__FILE__, __LINE__, google::FATAL, counter, \
+ &google::LogMessage::SendToLog)
+#define SYSLOG_FATAL(counter) \
+ google::LogMessage(__FILE__, __LINE__, google::FATAL, counter, \
+ &google::LogMessage::SendToSyslogAndLog)
+#define GOOGLE_LOG_DFATAL(counter) \
+ google::LogMessage(__FILE__, __LINE__, google::DFATAL_LEVEL, counter, \
+ &google::LogMessage::SendToLog)
+#define SYSLOG_DFATAL(counter) \
+ google::LogMessage(__FILE__, __LINE__, google::DFATAL_LEVEL, counter, \
+ &google::LogMessage::SendToSyslogAndLog)
+
+#if defined(WIN32) || defined(_WIN32) || defined(__WIN32__) || defined(__CYGWIN__) || defined(__CYGWIN32__)
+// A very useful logging macro to log windows errors:
+#define LOG_SYSRESULT(result) \
+ if (FAILED(result)) { \
+ LPTSTR message = NULL; \
+ LPTSTR msg = reinterpret_cast<LPTSTR>(&message); \
+ DWORD message_length = FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | \
+ FORMAT_MESSAGE_FROM_SYSTEM, \
+ 0, result, 0, msg, 100, NULL); \
+ if (message_length > 0) { \
+ google::LogMessage(__FILE__, __LINE__, ERROR, 0, \
+ &google::LogMessage::SendToLog).stream() << message; \
+ LocalFree(message); \
+ } \
+ }
+#endif
+
+// We use the preprocessor's merging operator, "##", so that, e.g.,
+// LOG(INFO) becomes the token GOOGLE_LOG_INFO. There's some funny
+// subtle difference between ostream member streaming functions (e.g.,
+// ostream::operator<<(int) and ostream non-member streaming functions
+// (e.g., ::operator<<(ostream&, string&): it turns out that it's
+// impossible to stream something like a string directly to an unnamed
+// ostream. We employ a neat hack by calling the stream() member
+// function of LogMessage which seems to avoid the problem.
+#define LOG(severity) COMPACT_GOOGLE_LOG_ ## severity.stream()
+#define SYSLOG(severity) SYSLOG_ ## severity(0).stream()
+
+namespace google {
+
+// They need the definitions of integer types.
+#include "glog/log_severity.h"
+#include "glog/vlog_is_on.h"
+
+// Initialize google's logging library. You will see the program name
+// specified by argv0 in log outputs.
+GOOGLE_GLOG_DLL_DECL void InitGoogleLogging(const char* argv0);
+
+// Shutdown google's logging library.
+GOOGLE_GLOG_DLL_DECL void ShutdownGoogleLogging();
+
+// Install a function which will be called after LOG(FATAL).
+GOOGLE_GLOG_DLL_DECL void InstallFailureFunction(void (*fail_func)());
+
+class LogSink; // defined below
+
+// If a non-NULL sink pointer is given, we push this message to that sink.
+// For LOG_TO_SINK we then do normal LOG(severity) logging as well.
+// This is useful for capturing messages and passing/storing them
+// somewhere more specific than the global log of the process.
+// Argument types:
+// LogSink* sink;
+// LogSeverity severity;
+// The cast is to disambiguate NULL arguments.
+#define LOG_TO_SINK(sink, severity) \
+ google::LogMessage( \
+ __FILE__, __LINE__, \
+ google::severity, \
+ static_cast<google::LogSink*>(sink), true).stream()
+#define LOG_TO_SINK_BUT_NOT_TO_LOGFILE(sink, severity) \
+ google::LogMessage( \
+ __FILE__, __LINE__, \
+ google::severity, \
+ static_cast<google::LogSink*>(sink), false).stream()
+
+// If a non-NULL string pointer is given, we write this message to that string.
+// We then do normal LOG(severity) logging as well.
+// This is useful for capturing messages and storing them somewhere more
+// specific than the global log of the process.
+// Argument types:
+// string* message;
+// LogSeverity severity;
+// The cast is to disambiguate NULL arguments.
+// NOTE: LOG(severity) expands to LogMessage().stream() for the specified
+// severity.
+#define LOG_TO_STRING(severity, message) \
+ LOG_TO_STRING_##severity(static_cast<string*>(message)).stream()
+
+// If a non-NULL pointer is given, we push the message onto the end
+// of a vector of strings; otherwise, we report it with LOG(severity).
+// This is handy for capturing messages and perhaps passing them back
+// to the caller, rather than reporting them immediately.
+// Argument types:
+// LogSeverity severity;
+// vector<string> *outvec;
+// The cast is to disambiguate NULL arguments.
+#define LOG_STRING(severity, outvec) \
+ LOG_TO_STRING_##severity(static_cast<vector<string>*>(outvec)).stream()
+
+#define LOG_IF(severity, condition) \
+ !(condition) ? (void) 0 : google::LogMessageVoidify() & LOG(severity)
+#define SYSLOG_IF(severity, condition) \
+ !(condition) ? (void) 0 : google::LogMessageVoidify() & SYSLOG(severity)
+
+#define LOG_ASSERT(condition) \
+ LOG_IF(FATAL, !(condition)) << "Assert failed: " #condition
+#define SYSLOG_ASSERT(condition) \
+ SYSLOG_IF(FATAL, !(condition)) << "Assert failed: " #condition
+
+// CHECK dies with a fatal error if condition is not true. It is *not*
+// controlled by NDEBUG, so the check will be executed regardless of
+// compilation mode. Therefore, it is safe to do things like:
+// CHECK(fp->Write(x) == 4)
+#define CHECK(condition) \
+ LOG_IF(FATAL, GOOGLE_PREDICT_BRANCH_NOT_TAKEN(!(condition))) \
+ << "Check failed: " #condition " "
+
+// A container for a string pointer which can be evaluated to a bool -
+// true iff the pointer is NULL.
+struct CheckOpString {
+ CheckOpString(std::string* str) : str_(str) { }
+ // No destructor: if str_ is non-NULL, we're about to LOG(FATAL),
+ // so there's no point in cleaning up str_.
+ operator bool() const {
+ return GOOGLE_PREDICT_BRANCH_NOT_TAKEN(str_ != NULL);
+ }
+ std::string* str_;
+};
+
+// Function is overloaded for integral types to allow static const
+// integrals declared in classes and not defined to be used as arguments to
+// CHECK* macros. It's not encouraged though.
+template <class T>
+inline const T& GetReferenceableValue(const T& t) { return t; }
+inline char GetReferenceableValue(char t) { return t; }
+inline unsigned char GetReferenceableValue(unsigned char t) { return t; }
+inline signed char GetReferenceableValue(signed char t) { return t; }
+inline short GetReferenceableValue(short t) { return t; }
+inline unsigned short GetReferenceableValue(unsigned short t) { return t; }
+inline int GetReferenceableValue(int t) { return t; }
+inline unsigned int GetReferenceableValue(unsigned int t) { return t; }
+inline long GetReferenceableValue(long t) { return t; }
+inline unsigned long GetReferenceableValue(unsigned long t) { return t; }
+inline long long GetReferenceableValue(long long t) { return t; }
+inline unsigned long long GetReferenceableValue(unsigned long long t) {
+ return t;
+}
+
+// This is a dummy class to define the following operator.
+struct DummyClassToDefineOperator {};
+
+}
+
+// Define global operator<< to declare using ::operator<<.
+// This declaration will allow use to use CHECK macros for user
+// defined classes which have operator<< (e.g., stl_logging.h).
+inline std::ostream& operator<<(
+ std::ostream& out, const google::DummyClassToDefineOperator&) {
+ return out;
+}
+
+namespace google {
+
+// Build the error message string.
+template<class t1, class t2>
+std::string* MakeCheckOpString(const t1& v1, const t2& v2, const char* names) {
+ // It means that we cannot use stl_logging if compiler doesn't
+ // support using expression for operator.
+ // TODO(hamaji): Figure out a way to fix.
+#if 1
+ using ::operator<<;
+#endif
+ std::strstream ss;
+ ss << names << " (" << v1 << " vs. " << v2 << ")";
+ return new std::string(ss.str(), ss.pcount());
+}
+
+// Helper functions for CHECK_OP macro.
+// The (int, int) specialization works around the issue that the compiler
+// will not instantiate the template version of the function on values of
+// unnamed enum type - see comment below.
+#define DEFINE_CHECK_OP_IMPL(name, op) \
+ template <class t1, class t2> \
+ inline std::string* Check##name##Impl(const t1& v1, const t2& v2, \
+ const char* names) { \
+ if (v1 op v2) return NULL; \
+ else return MakeCheckOpString(v1, v2, names); \
+ } \
+ inline std::string* Check##name##Impl(int v1, int v2, const char* names) { \
+ return Check##name##Impl<int, int>(v1, v2, names); \
+ }
+
+// Use _EQ, _NE, _LE, etc. in case the file including base/logging.h
+// provides its own #defines for the simpler names EQ, NE, LE, etc.
+// This happens if, for example, those are used as token names in a
+// yacc grammar.
+DEFINE_CHECK_OP_IMPL(_EQ, ==)
+DEFINE_CHECK_OP_IMPL(_NE, !=)
+DEFINE_CHECK_OP_IMPL(_LE, <=)
+DEFINE_CHECK_OP_IMPL(_LT, < )
+DEFINE_CHECK_OP_IMPL(_GE, >=)
+DEFINE_CHECK_OP_IMPL(_GT, > )
+#undef DEFINE_CHECK_OP_IMPL
+
+// Helper macro for binary operators.
+// Don't use this macro directly in your code, use CHECK_EQ et al below.
+
+#if defined(STATIC_ANALYSIS)
+// Only for static analysis tool to know that it is equivalent to assert
+#define CHECK_OP_LOG(name, op, val1, val2, log) CHECK((val1) op (val2))
+#elif !defined(NDEBUG)
+// In debug mode, avoid constructing CheckOpStrings if possible,
+// to reduce the overhead of CHECK statments by 2x.
+// Real DCHECK-heavy tests have seen 1.5x speedups.
+
+// The meaning of "string" might be different between now and
+// when this macro gets invoked (e.g., if someone is experimenting
+// with other string implementations that get defined after this
+// file is included). Save the current meaning now and use it
+// in the macro.
+typedef std::string _Check_string;
+#define CHECK_OP_LOG(name, op, val1, val2, log) \
+ while (google::_Check_string* _result = \
+ google::Check##name##Impl( \
+ google::GetReferenceableValue(val1), \
+ google::GetReferenceableValue(val2), \
+ #val1 " " #op " " #val2)) \
+ log(__FILE__, __LINE__, \
+ google::CheckOpString(_result)).stream()
+#else
+// In optimized mode, use CheckOpString to hint to compiler that
+// the while condition is unlikely.
+#define CHECK_OP_LOG(name, op, val1, val2, log) \
+ while (google::CheckOpString _result = \
+ google::Check##name##Impl( \
+ google::GetReferenceableValue(val1), \
+ google::GetReferenceableValue(val2), \
+ #val1 " " #op " " #val2)) \
+ log(__FILE__, __LINE__, _result).stream()
+#endif // STATIC_ANALYSIS, !NDEBUG
+
+#if GOOGLE_STRIP_LOG <= 3
+#define CHECK_OP(name, op, val1, val2) \
+ CHECK_OP_LOG(name, op, val1, val2, google::LogMessageFatal)
+#else
+#define CHECK_OP(name, op, val1, val2) \
+ CHECK_OP_LOG(name, op, val1, val2, google::NullStreamFatal)
+#endif // STRIP_LOG <= 3
+
+// Equality/Inequality checks - compare two values, and log a FATAL message
+// including the two values when the result is not as expected. The values
+// must have operator<<(ostream, ...) defined.
+//
+// You may append to the error message like so:
+// CHECK_NE(1, 2) << ": The world must be ending!";
+//
+// We are very careful to ensure that each argument is evaluated exactly
+// once, and that anything which is legal to pass as a function argument is
+// legal here. In particular, the arguments may be temporary expressions
+// which will end up being destroyed at the end of the apparent statement,
+// for example:
+// CHECK_EQ(string("abc")[1], 'b');
+//
+// WARNING: These don't compile correctly if one of the arguments is a pointer
+// and the other is NULL. To work around this, simply static_cast NULL to the
+// type of the desired pointer.
+
+#define CHECK_EQ(val1, val2) CHECK_OP(_EQ, ==, val1, val2)
+#define CHECK_NE(val1, val2) CHECK_OP(_NE, !=, val1, val2)
+#define CHECK_LE(val1, val2) CHECK_OP(_LE, <=, val1, val2)
+#define CHECK_LT(val1, val2) CHECK_OP(_LT, < , val1, val2)
+#define CHECK_GE(val1, val2) CHECK_OP(_GE, >=, val1, val2)
+#define CHECK_GT(val1, val2) CHECK_OP(_GT, > , val1, val2)
+
+// Check that the input is non NULL. This very useful in constructor
+// initializer lists.
+
+#define CHECK_NOTNULL(val) \
+ google::CheckNotNull(__FILE__, __LINE__, "'" #val "' Must be non NULL", (val))
+
+// Helper functions for string comparisons.
+// To avoid bloat, the definitions are in logging.cc.
+#define DECLARE_CHECK_STROP_IMPL(func, expected) \
+ GOOGLE_GLOG_DLL_DECL std::string* Check##func##expected##Impl( \
+ const char* s1, const char* s2, const char* names);
+DECLARE_CHECK_STROP_IMPL(strcmp, true)
+DECLARE_CHECK_STROP_IMPL(strcmp, false)
+DECLARE_CHECK_STROP_IMPL(strcasecmp, true)
+DECLARE_CHECK_STROP_IMPL(strcasecmp, false)
+#undef DECLARE_CHECK_STROP_IMPL
+
+// Helper macro for string comparisons.
+// Don't use this macro directly in your code, use CHECK_STREQ et al below.
+#define CHECK_STROP(func, op, expected, s1, s2) \
+ while (google::CheckOpString _result = \
+ google::Check##func##expected##Impl((s1), (s2), \
+ #s1 " " #op " " #s2)) \
+ LOG(FATAL) << *_result.str_
+
+
+// String (char*) equality/inequality checks.
+// CASE versions are case-insensitive.
+//
+// Note that "s1" and "s2" may be temporary strings which are destroyed
+// by the compiler at the end of the current "full expression"
+// (e.g. CHECK_STREQ(Foo().c_str(), Bar().c_str())).
+
+#define CHECK_STREQ(s1, s2) CHECK_STROP(strcmp, ==, true, s1, s2)
+#define CHECK_STRNE(s1, s2) CHECK_STROP(strcmp, !=, false, s1, s2)
+#define CHECK_STRCASEEQ(s1, s2) CHECK_STROP(strcasecmp, ==, true, s1, s2)
+#define CHECK_STRCASENE(s1, s2) CHECK_STROP(strcasecmp, !=, false, s1, s2)
+
+#define CHECK_INDEX(I,A) CHECK(I < (sizeof(A)/sizeof(A[0])))
+#define CHECK_BOUND(B,A) CHECK(B <= (sizeof(A)/sizeof(A[0])))
+
+#define CHECK_DOUBLE_EQ(val1, val2) \
+ do { \
+ CHECK_LE((val1), (val2)+0.000000000000001L); \
+ CHECK_GE((val1), (val2)-0.000000000000001L); \
+ } while (0)
+
+#define CHECK_NEAR(val1, val2, margin) \
+ do { \
+ CHECK_LE((val1), (val2)+(margin)); \
+ CHECK_GE((val1), (val2)-(margin)); \
+ } while (0)
+
+// perror()..googly style!
+//
+// PLOG() and PLOG_IF() and PCHECK() behave exactly like their LOG* and
+// CHECK equivalents with the addition that they postpend a description
+// of the current state of errno to their output lines.
+
+#define PLOG(severity) GOOGLE_PLOG(severity, 0).stream()
+
+#define GOOGLE_PLOG(severity, counter) \
+ google::ErrnoLogMessage( \
+ __FILE__, __LINE__, google::severity, counter, \
+ &google::LogMessage::SendToLog)
+
+#define PLOG_IF(severity, condition) \
+ !(condition) ? (void) 0 : google::LogMessageVoidify() & PLOG(severity)
+
+// A CHECK() macro that postpends errno if the condition is false. E.g.
+//
+// if (poll(fds, nfds, timeout) == -1) { PCHECK(errno == EINTR); ... }
+#define PCHECK(condition) \
+ PLOG_IF(FATAL, GOOGLE_PREDICT_BRANCH_NOT_TAKEN(!(condition))) \
+ << "Check failed: " #condition " "
+
+// A CHECK() macro that lets you assert the success of a function that
+// returns -1 and sets errno in case of an error. E.g.
+//
+// CHECK_ERR(mkdir(path, 0700));
+//
+// or
+//
+// int fd = open(filename, flags); CHECK_ERR(fd) << ": open " << filename;
+#define CHECK_ERR(invocation) \
+PLOG_IF(FATAL, GOOGLE_PREDICT_BRANCH_NOT_TAKEN((invocation) == -1)) \
+ << #invocation
+
+// Use macro expansion to create, for each use of LOG_EVERY_N(), static
+// variables with the __LINE__ expansion as part of the variable name.
+#define LOG_EVERY_N_VARNAME(base, line) LOG_EVERY_N_VARNAME_CONCAT(base, line)
+#define LOG_EVERY_N_VARNAME_CONCAT(base, line) base ## line
+
+#define LOG_OCCURRENCES LOG_EVERY_N_VARNAME(occurrences_, __LINE__)
+#define LOG_OCCURRENCES_MOD_N LOG_EVERY_N_VARNAME(occurrences_mod_n_, __LINE__)
+
+#define SOME_KIND_OF_LOG_EVERY_N(severity, n, what_to_do) \
+ static int LOG_OCCURRENCES = 0, LOG_OCCURRENCES_MOD_N = 0; \
+ ++LOG_OCCURRENCES; \
+ if (++LOG_OCCURRENCES_MOD_N > n) LOG_OCCURRENCES_MOD_N -= n; \
+ if (LOG_OCCURRENCES_MOD_N == 1) \
+ google::LogMessage( \
+ __FILE__, __LINE__, google::severity, LOG_OCCURRENCES, \
+ &what_to_do).stream()
+
+#define SOME_KIND_OF_LOG_IF_EVERY_N(severity, condition, n, what_to_do) \
+ static int LOG_OCCURRENCES = 0, LOG_OCCURRENCES_MOD_N = 0; \
+ ++LOG_OCCURRENCES; \
+ if (condition && \
+ ((LOG_OCCURRENCES_MOD_N=(LOG_OCCURRENCES_MOD_N + 1) % n) == (1 % n))) \
+ google::LogMessage( \
+ __FILE__, __LINE__, google::severity, LOG_OCCURRENCES, \
+ &what_to_do).stream()
+
+#define SOME_KIND_OF_PLOG_EVERY_N(severity, n, what_to_do) \
+ static int LOG_OCCURRENCES = 0, LOG_OCCURRENCES_MOD_N = 0; \
+ ++LOG_OCCURRENCES; \
+ if (++LOG_OCCURRENCES_MOD_N > n) LOG_OCCURRENCES_MOD_N -= n; \
+ if (LOG_OCCURRENCES_MOD_N == 1) \
+ google::ErrnoLogMessage( \
+ __FILE__, __LINE__, google::severity, LOG_OCCURRENCES, \
+ &what_to_do).stream()
+
+#define SOME_KIND_OF_LOG_FIRST_N(severity, n, what_to_do) \
+ static int LOG_OCCURRENCES = 0; \
+ if (LOG_OCCURRENCES <= n) \
+ ++LOG_OCCURRENCES; \
+ if (LOG_OCCURRENCES <= n) \
+ google::LogMessage( \
+ __FILE__, __LINE__, google::severity, LOG_OCCURRENCES, \
+ &what_to_do).stream()
+
+namespace glog_internal_namespace_ {
+template <bool>
+struct CompileAssert {
+};
+struct CrashReason;
+} // namespace glog_internal_namespace_
+
+#define GOOGLE_GLOG_COMPILE_ASSERT(expr, msg) \
+ typedef google::glog_internal_namespace_::CompileAssert<(bool(expr))> msg[bool(expr) ? 1 : -1]
+
+#define LOG_EVERY_N(severity, n) \
+ GOOGLE_GLOG_COMPILE_ASSERT(google::severity < \
+ google::NUM_SEVERITIES, \
+ INVALID_REQUESTED_LOG_SEVERITY); \
+ SOME_KIND_OF_LOG_EVERY_N(severity, (n), google::LogMessage::SendToLog)
+
+#define SYSLOG_EVERY_N(severity, n) \
+ SOME_KIND_OF_LOG_EVERY_N(severity, (n), google::LogMessage::SendToSyslogAndLog)
+
+#define PLOG_EVERY_N(severity, n) \
+ SOME_KIND_OF_PLOG_EVERY_N(severity, (n), google::LogMessage::SendToLog)
+
+#define LOG_FIRST_N(severity, n) \
+ SOME_KIND_OF_LOG_FIRST_N(severity, (n), google::LogMessage::SendToLog)
+
+#define LOG_IF_EVERY_N(severity, condition, n) \
+ SOME_KIND_OF_LOG_IF_EVERY_N(severity, (condition), (n), google::LogMessage::SendToLog)
+
+// We want the special COUNTER value available for LOG_EVERY_X()'ed messages
+enum PRIVATE_Counter {COUNTER};
+
+
+// Plus some debug-logging macros that get compiled to nothing for production
+
+#ifndef NDEBUG
+
+#define DLOG(severity) LOG(severity)
+#define DVLOG(verboselevel) VLOG(verboselevel)
+#define DLOG_IF(severity, condition) LOG_IF(severity, condition)
+#define DLOG_EVERY_N(severity, n) LOG_EVERY_N(severity, n)
+#define DLOG_IF_EVERY_N(severity, condition, n) \
+ LOG_IF_EVERY_N(severity, condition, n)
+#define DLOG_ASSERT(condition) LOG_ASSERT(condition)
+
+// debug-only checking. not executed in NDEBUG mode.
+#define DCHECK(condition) CHECK(condition)
+#define DCHECK_EQ(val1, val2) CHECK_EQ(val1, val2)
+#define DCHECK_NE(val1, val2) CHECK_NE(val1, val2)
+#define DCHECK_LE(val1, val2) CHECK_LE(val1, val2)
+#define DCHECK_LT(val1, val2) CHECK_LT(val1, val2)
+#define DCHECK_GE(val1, val2) CHECK_GE(val1, val2)
+#define DCHECK_GT(val1, val2) CHECK_GT(val1, val2)
+#define DCHECK_NOTNULL(val) CHECK_NOTNULL(val)
+#define DCHECK_STREQ(str1, str2) CHECK_STREQ(str1, str2)
+#define DCHECK_STRCASEEQ(str1, str2) CHECK_STRCASEEQ(str1, str2)
+#define DCHECK_STRNE(str1, str2) CHECK_STRNE(str1, str2)
+#define DCHECK_STRCASENE(str1, str2) CHECK_STRCASENE(str1, str2)
+
+#else // NDEBUG
+
+#define DLOG(severity) \
+ true ? (void) 0 : google::LogMessageVoidify() & LOG(severity)
+
+#define DVLOG(verboselevel) \
+ (true || !VLOG_IS_ON(verboselevel)) ?\
+ (void) 0 : google::LogMessageVoidify() & LOG(INFO)
+
+#define DLOG_IF(severity, condition) \
+ (true || !(condition)) ? (void) 0 : google::LogMessageVoidify() & LOG(severity)
+
+#define DLOG_EVERY_N(severity, n) \
+ true ? (void) 0 : google::LogMessageVoidify() & LOG(severity)
+
+#define DLOG_IF_EVERY_N(severity, condition, n) \
+ (true || !(condition))? (void) 0 : google::LogMessageVoidify() & LOG(severity)
+
+#define DLOG_ASSERT(condition) \
+ true ? (void) 0 : LOG_ASSERT(condition)
+
+#define DCHECK(condition) \
+ while (false) \
+ CHECK(condition)
+
+#define DCHECK_EQ(val1, val2) \
+ while (false) \
+ CHECK_EQ(val1, val2)
+
+#define DCHECK_NE(val1, val2) \
+ while (false) \
+ CHECK_NE(val1, val2)
+
+#define DCHECK_LE(val1, val2) \
+ while (false) \
+ CHECK_LE(val1, val2)
+
+#define DCHECK_LT(val1, val2) \
+ while (false) \
+ CHECK_LT(val1, val2)
+
+#define DCHECK_GE(val1, val2) \
+ while (false) \
+ CHECK_GE(val1, val2)
+
+#define DCHECK_GT(val1, val2) \
+ while (false) \
+ CHECK_GT(val1, val2)
+
+#define DCHECK_NOTNULL(val) (val)
+
+#define DCHECK_STREQ(str1, str2) \
+ while (false) \
+ CHECK_STREQ(str1, str2)
+
+#define DCHECK_STRCASEEQ(str1, str2) \
+ while (false) \
+ CHECK_STRCASEEQ(str1, str2)
+
+#define DCHECK_STRNE(str1, str2) \
+ while (false) \
+ CHECK_STRNE(str1, str2)
+
+#define DCHECK_STRCASENE(str1, str2) \
+ while (false) \
+ CHECK_STRCASENE(str1, str2)
+
+
+#endif // NDEBUG
+
+// Log only in verbose mode.
+
+#define VLOG(verboselevel) LOG_IF(INFO, VLOG_IS_ON(verboselevel))
+
+#define VLOG_IF(verboselevel, condition) \
+ LOG_IF(INFO, (condition) && VLOG_IS_ON(verboselevel))
+
+#define VLOG_EVERY_N(verboselevel, n) \
+ LOG_IF_EVERY_N(INFO, VLOG_IS_ON(verboselevel), n)
+
+#define VLOG_IF_EVERY_N(verboselevel, condition, n) \
+ LOG_IF_EVERY_N(INFO, (condition) && VLOG_IS_ON(verboselevel), n)
+
+//
+// This class more or less represents a particular log message. You
+// create an instance of LogMessage and then stream stuff to it.
+// When you finish streaming to it, ~LogMessage is called and the
+// full message gets streamed to the appropriate destination.
+//
+// You shouldn't actually use LogMessage's constructor to log things,
+// though. You should use the LOG() macro (and variants thereof)
+// above.
+class GOOGLE_GLOG_DLL_DECL LogMessage {
+public:
+ enum {
+ // Passing kNoLogPrefix for the line number disables the
+ // log-message prefix. Useful for using the LogMessage
+ // infrastructure as a printing utility. See also the --log_prefix
+ // flag for controlling the log-message prefix on an
+ // application-wide basis.
+ kNoLogPrefix = -1
+ };
+
+ // LogStream inherit from non-DLL-exported class (std::ostrstream)
+ // and VC++ produces a warning for this situation.
+ // However, MSDN says "C4275 can be ignored in Microsoft Visual C++
+ // 2005 if you are deriving from a type in the Standard C++ Library"
+ // http://msdn.microsoft.com/en-us/library/3tdb471s(VS.80).aspx
+ // Let's just ignore the warning.
+#ifdef _MSC_VER
+# pragma warning(disable: 4275)
+#endif
+ class GOOGLE_GLOG_DLL_DECL LogStream : public std::ostrstream {
+#ifdef _MSC_VER
+# pragma warning(default: 4275)
+#endif
+ public:
+ LogStream(char *buf, int len, int ctr)
+ : ostrstream(buf, len),
+ ctr_(ctr) {
+ self_ = this;
+ }
+
+ int ctr() const { return ctr_; }
+ void set_ctr(int ctr) { ctr_ = ctr; }
+ LogStream* self() const { return self_; }
+
+ private:
+ int ctr_; // Counter hack (for the LOG_EVERY_X() macro)
+ LogStream *self_; // Consistency check hack
+ };
+
+public:
+ // icc 8 requires this typedef to avoid an internal compiler error.
+ typedef void (LogMessage::*SendMethod)();
+
+ LogMessage(const char* file, int line, LogSeverity severity, int ctr,
+ SendMethod send_method);
+
+ // Two special constructors that generate reduced amounts of code at
+ // LOG call sites for common cases.
+
+ // Used for LOG(INFO): Implied are:
+ // severity = INFO, ctr = 0, send_method = &LogMessage::SendToLog.
+ //
+ // Using this constructor instead of the more complex constructor above
+ // saves 19 bytes per call site.
+ LogMessage(const char* file, int line);
+
+ // Used for LOG(severity) where severity != INFO. Implied
+ // are: ctr = 0, send_method = &LogMessage::SendToLog
+ //
+ // Using this constructor instead of the more complex constructor above
+ // saves 17 bytes per call site.
+ LogMessage(const char* file, int line, LogSeverity severity);
+
+ // Constructor to log this message to a specified sink (if not NULL).
+ // Implied are: ctr = 0, send_method = &LogMessage::SendToSinkAndLog if
+ // also_send_to_log is true, send_method = &LogMessage::SendToSink otherwise.
+ LogMessage(const char* file, int line, LogSeverity severity, LogSink* sink,
+ bool also_send_to_log);
+
+ // Constructor where we also give a vector<string> pointer
+ // for storing the messages (if the pointer is not NULL).
+ // Implied are: ctr = 0, send_method = &LogMessage::SaveOrSendToLog.
+ LogMessage(const char* file, int line, LogSeverity severity,
+ std::vector<std::string>* outvec);
+
+ // Constructor where we also give a string pointer for storing the
+ // message (if the pointer is not NULL). Implied are: ctr = 0,
+ // send_method = &LogMessage::WriteToStringAndLog.
+ LogMessage(const char* file, int line, LogSeverity severity,
+ std::string* message);
+
+ // A special constructor used for check failures
+ LogMessage(const char* file, int line, const CheckOpString& result);
+
+ ~LogMessage();
+
+ // Flush a buffered message to the sink set in the constructor. Always
+ // called by the destructor, it may also be called from elsewhere if
+ // needed. Only the first call is actioned; any later ones are ignored.
+ void Flush();
+
+ // An arbitrary limit on the length of a single log message. This
+ // is so that streaming can be done more efficiently.
+ static const size_t kMaxLogMessageLen;
+
+ // Theses should not be called directly outside of logging.*,
+ // only passed as SendMethod arguments to other LogMessage methods:
+ void SendToLog(); // Actually dispatch to the logs
+ void SendToSyslogAndLog(); // Actually dispatch to syslog and the logs
+
+ // Call abort() or similar to perform LOG(FATAL) crash.
+ static void Fail() ;
+
+ std::ostream& stream() { return *(data_->stream_); }
+
+ int preserved_errno() const { return data_->preserved_errno_; }
+
+ // Must be called without the log_mutex held. (L < log_mutex)
+ static int64 num_messages(int severity);
+
+private:
+ // Fully internal SendMethod cases:
+ void SendToSinkAndLog(); // Send to sink if provided and dispatch to the logs
+ void SendToSink(); // Send to sink if provided, do nothing otherwise.
+
+ // Write to string if provided and dispatch to the logs.
+ void WriteToStringAndLog();
+
+ void SaveOrSendToLog(); // Save to stringvec if provided, else to logs
+
+ void Init(const char* file, int line, LogSeverity severity,
+ void (LogMessage::*send_method)());
+
+ // Used to fill in crash information during LOG(FATAL) failures.
+ void RecordCrashReason(glog_internal_namespace_::CrashReason* reason);
+
+ // Counts of messages sent at each priority:
+ static int64 num_messages_[NUM_SEVERITIES]; // under log_mutex
+
+ // We keep the data in a separate struct so that each instance of
+ // LogMessage uses less stack space.
+ struct GOOGLE_GLOG_DLL_DECL LogMessageData {
+ LogMessageData() {};
+
+ int preserved_errno_; // preserved errno
+ char* buf_;
+ char* message_text_; // Complete message text (points to selected buffer)
+ LogStream* stream_alloc_;
+ LogStream* stream_;
+ char severity_; // What level is this LogMessage logged at?
+ int line_; // line number where logging call is.
+ void (LogMessage::*send_method_)(); // Call this in destructor to send
+ union { // At most one of these is used: union to keep the size low.
+ LogSink* sink_; // NULL or sink to send message to
+ std::vector<std::string>* outvec_; // NULL or vector to push message onto
+ std::string* message_; // NULL or string to write message into
+ };
+ time_t timestamp_; // Time of creation of LogMessage
+ struct ::tm tm_time_; // Time of creation of LogMessage
+ size_t num_prefix_chars_; // # of chars of prefix in this message
+ size_t num_chars_to_log_; // # of chars of msg to send to log
+ size_t num_chars_to_syslog_; // # of chars of msg to send to syslog
+ const char* basename_; // basename of file that called LOG
+ const char* fullname_; // fullname of file that called LOG
+ bool has_been_flushed_; // false => data has not been flushed
+ bool first_fatal_; // true => this was first fatal msg
+
+ ~LogMessageData();
+ private:
+ LogMessageData(const LogMessageData&);
+ void operator=(const LogMessageData&);
+ };
+
+ static LogMessageData fatal_msg_data_exclusive_;
+ static LogMessageData fatal_msg_data_shared_;
+
+ LogMessageData* allocated_;
+ LogMessageData* data_;
+
+ friend class LogDestination;
+
+ LogMessage(const LogMessage&);
+ void operator=(const LogMessage&);
+};
+
+// This class happens to be thread-hostile because all instances share
+// a single data buffer, but since it can only be created just before
+// the process dies, we don't worry so much.
+class GOOGLE_GLOG_DLL_DECL LogMessageFatal : public LogMessage {
+ public:
+ LogMessageFatal(const char* file, int line);
+ LogMessageFatal(const char* file, int line, const CheckOpString& result);
+ ~LogMessageFatal() ;
+};
+
+// A non-macro interface to the log facility; (useful
+// when the logging level is not a compile-time constant).
+inline void LogAtLevel(int const severity, std::string const &msg) {
+ LogMessage(__FILE__, __LINE__, severity).stream() << msg;
+}
+
+// A macro alternative of LogAtLevel. New code may want to use this
+// version since there are two advantages: 1. this version outputs the
+// file name and the line number where this macro is put like other
+// LOG macros, 2. this macro can be used as C++ stream.
+#define LOG_AT_LEVEL(severity) google::LogMessage(__FILE__, __LINE__, severity).stream()
+
+// A small helper for CHECK_NOTNULL().
+template <typename T>
+T* CheckNotNull(const char *file, int line, const char *names, T* t) {
+ if (t == NULL) {
+ LogMessageFatal(file, line, new std::string(names));
+ }
+ return t;
+}
+
+// Allow folks to put a counter in the LOG_EVERY_X()'ed messages. This
+// only works if ostream is a LogStream. If the ostream is not a
+// LogStream you'll get an assert saying as much at runtime.
+GOOGLE_GLOG_DLL_DECL std::ostream& operator<<(std::ostream &os,
+ const PRIVATE_Counter&);
+
+
+// Derived class for PLOG*() above.
+class GOOGLE_GLOG_DLL_DECL ErrnoLogMessage : public LogMessage {
+ public:
+
+ ErrnoLogMessage(const char* file, int line, LogSeverity severity, int ctr,
+ void (LogMessage::*send_method)());
+
+ // Postpends ": strerror(errno) [errno]".
+ ~ErrnoLogMessage();
+
+ private:
+ ErrnoLogMessage(const ErrnoLogMessage&);
+ void operator=(const ErrnoLogMessage&);
+};
+
+
+// This class is used to explicitly ignore values in the conditional
+// logging macros. This avoids compiler warnings like "value computed
+// is not used" and "statement has no effect".
+
+class GOOGLE_GLOG_DLL_DECL LogMessageVoidify {
+ public:
+ LogMessageVoidify() { }
+ // This has to be an operator with a precedence lower than << but
+ // higher than ?:
+ void operator&(std::ostream&) { }
+};
+
+
+// Flushes all log files that contains messages that are at least of
+// the specified severity level. Thread-safe.
+GOOGLE_GLOG_DLL_DECL void FlushLogFiles(LogSeverity min_severity);
+
+// Flushes all log files that contains messages that are at least of
+// the specified severity level. Thread-hostile because it ignores
+// locking -- used for catastrophic failures.
+GOOGLE_GLOG_DLL_DECL void FlushLogFilesUnsafe(LogSeverity min_severity);
+
+//
+// Set the destination to which a particular severity level of log
+// messages is sent. If base_filename is "", it means "don't log this
+// severity". Thread-safe.
+//
+GOOGLE_GLOG_DLL_DECL void SetLogDestination(LogSeverity severity,
+ const char* base_filename);
+
+//
+// Set the basename of the symlink to the latest log file at a given
+// severity. If symlink_basename is empty, do not make a symlink. If
+// you don't call this function, the symlink basename is the
+// invocation name of the program. Thread-safe.
+//
+GOOGLE_GLOG_DLL_DECL void SetLogSymlink(LogSeverity severity,
+ const char* symlink_basename);
+
+//
+// Used to send logs to some other kind of destination
+// Users should subclass LogSink and override send to do whatever they want.
+// Implementations must be thread-safe because a shared instance will
+// be called from whichever thread ran the LOG(XXX) line.
+class GOOGLE_GLOG_DLL_DECL LogSink {
+ public:
+ virtual ~LogSink();
+
+ // Sink's logging logic (message_len is such as to exclude '\n' at the end).
+ // This method can't use LOG() or CHECK() as logging system mutex(s) are held
+ // during this call.
+ virtual void send(LogSeverity severity, const char* full_filename,
+ const char* base_filename, int line,
+ const struct ::tm* tm_time,
+ const char* message, size_t message_len) = 0;
+
+ // Redefine this to implement waiting for
+ // the sink's logging logic to complete.
+ // It will be called after each send() returns,
+ // but before that LogMessage exits or crashes.
+ // By default this function does nothing.
+ // Using this function one can implement complex logic for send()
+ // that itself involves logging; and do all this w/o causing deadlocks and
+ // inconsistent rearrangement of log messages.
+ // E.g. if a LogSink has thread-specific actions, the send() method
+ // can simply add the message to a queue and wake up another thread that
+ // handles real logging while itself making some LOG() calls;
+ // WaitTillSent() can be implemented to wait for that logic to complete.
+ // See our unittest for an example.
+ virtual void WaitTillSent();
+
+ // Returns the normal text output of the log message.
+ // Can be useful to implement send().
+ static std::string ToString(LogSeverity severity, const char* file, int line,
+ const struct ::tm* tm_time,
+ const char* message, size_t message_len);
+};
+
+// Add or remove a LogSink as a consumer of logging data. Thread-safe.
+GOOGLE_GLOG_DLL_DECL void AddLogSink(LogSink *destination);
+GOOGLE_GLOG_DLL_DECL void RemoveLogSink(LogSink *destination);
+
+//
+// Specify an "extension" added to the filename specified via
+// SetLogDestination. This applies to all severity levels. It's
+// often used to append the port we're listening on to the logfile
+// name. Thread-safe.
+//
+GOOGLE_GLOG_DLL_DECL void SetLogFilenameExtension(
+ const char* filename_extension);
+
+//
+// Make it so that all log messages of at least a particular severity
+// are logged to stderr (in addition to logging to the usual log
+// file(s)). Thread-safe.
+//
+GOOGLE_GLOG_DLL_DECL void SetStderrLogging(LogSeverity min_severity);
+
+//
+// Make it so that all log messages go only to stderr. Thread-safe.
+//
+GOOGLE_GLOG_DLL_DECL void LogToStderr();
+
+//
+// Make it so that all log messages of at least a particular severity are
+// logged via email to a list of addresses (in addition to logging to the
+// usual log file(s)). The list of addresses is just a string containing
+// the email addresses to send to (separated by spaces, say). Thread-safe.
+//
+GOOGLE_GLOG_DLL_DECL void SetEmailLogging(LogSeverity min_severity,
+ const char* addresses);
+
+// A simple function that sends email. dest is a commma-separated
+// list of addressess. Thread-safe.
+GOOGLE_GLOG_DLL_DECL bool SendEmail(const char *dest,
+ const char *subject, const char *body);
+
+GOOGLE_GLOG_DLL_DECL const std::vector<std::string>& GetLoggingDirectories();
+
+// For tests only: Clear the internal [cached] list of logging directories to
+// force a refresh the next time GetLoggingDirectories is called.
+// Thread-hostile.
+void TestOnly_ClearLoggingDirectoriesList();
+
+// Returns a set of existing temporary directories, which will be a
+// subset of the directories returned by GetLogginDirectories().
+// Thread-safe.
+GOOGLE_GLOG_DLL_DECL void GetExistingTempDirectories(
+ std::vector<std::string>* list);
+
+// Print any fatal message again -- useful to call from signal handler
+// so that the last thing in the output is the fatal message.
+// Thread-hostile, but a race is unlikely.
+GOOGLE_GLOG_DLL_DECL void ReprintFatalMessage();
+
+// Truncate a log file that may be the append-only output of multiple
+// processes and hence can't simply be renamed/reopened (typically a
+// stdout/stderr). If the file "path" is > "limit" bytes, copy the
+// last "keep" bytes to offset 0 and truncate the rest. Since we could
+// be racing with other writers, this approach has the potential to
+// lose very small amounts of data. For security, only follow symlinks
+// if the path is /proc/self/fd/*
+GOOGLE_GLOG_DLL_DECL void TruncateLogFile(const char *path,
+ int64 limit, int64 keep);
+
+// Truncate stdout and stderr if they are over the value specified by
+// --max_log_size; keep the final 1MB. This function has the same
+// race condition as TruncateLogFile.
+GOOGLE_GLOG_DLL_DECL void TruncateStdoutStderr();
+
+// Return the string representation of the provided LogSeverity level.
+// Thread-safe.
+GOOGLE_GLOG_DLL_DECL const char* GetLogSeverityName(LogSeverity severity);
+
+// ---------------------------------------------------------------------
+// Implementation details that are not useful to most clients
+// ---------------------------------------------------------------------
+
+// A Logger is the interface used by logging modules to emit entries
+// to a log. A typical implementation will dump formatted data to a
+// sequence of files. We also provide interfaces that will forward
+// the data to another thread so that the invoker never blocks.
+// Implementations should be thread-safe since the logging system
+// will write to them from multiple threads.
+
+namespace base {
+
+class GOOGLE_GLOG_DLL_DECL Logger {
+ public:
+ virtual ~Logger();
+
+ // Writes "message[0,message_len-1]" corresponding to an event that
+ // occurred at "timestamp". If "force_flush" is true, the log file
+ // is flushed immediately.
+ //
+ // The input message has already been formatted as deemed
+ // appropriate by the higher level logging facility. For example,
+ // textual log messages already contain timestamps, and the
+ // file:linenumber header.
+ virtual void Write(bool force_flush,
+ time_t timestamp,
+ const char* message,
+ int message_len) = 0;
+
+ // Flush any buffered messages
+ virtual void Flush() = 0;
+
+ // Get the current LOG file size.
+ // The returned value is approximate since some
+ // logged data may not have been flushed to disk yet.
+ virtual uint32 LogSize() = 0;
+};
+
+// Get the logger for the specified severity level. The logger
+// remains the property of the logging module and should not be
+// deleted by the caller. Thread-safe.
+extern GOOGLE_GLOG_DLL_DECL Logger* GetLogger(LogSeverity level);
+
+// Set the logger for the specified severity level. The logger
+// becomes the property of the logging module and should not
+// be deleted by the caller. Thread-safe.
+extern GOOGLE_GLOG_DLL_DECL void SetLogger(LogSeverity level, Logger* logger);
+
+}
+
+// glibc has traditionally implemented two incompatible versions of
+// strerror_r(). There is a poorly defined convention for picking the
+// version that we want, but it is not clear whether it even works with
+// all versions of glibc.
+// So, instead, we provide this wrapper that automatically detects the
+// version that is in use, and then implements POSIX semantics.
+// N.B. In addition to what POSIX says, we also guarantee that "buf" will
+// be set to an empty string, if this function failed. This means, in most
+// cases, you do not need to check the error code and you can directly
+// use the value of "buf". It will never have an undefined value.
+GOOGLE_GLOG_DLL_DECL int posix_strerror_r(int err, char *buf, size_t len);
+
+
+// A class for which we define operator<<, which does nothing.
+class GOOGLE_GLOG_DLL_DECL NullStream : public LogMessage::LogStream {
+ public:
+ // Initialize the LogStream so the messages can be written somewhere
+ // (they'll never be actually displayed). This will be needed if a
+ // NullStream& is implicitly converted to LogStream&, in which case
+ // the overloaded NullStream::operator<< will not be invoked.
+ NullStream() : LogMessage::LogStream(message_buffer_, 1, 0) { }
+ NullStream(const char* /*file*/, int /*line*/,
+ const CheckOpString& /*result*/) :
+ LogMessage::LogStream(message_buffer_, 1, 0) { }
+ NullStream &stream() { return *this; }
+ private:
+ // A very short buffer for messages (which we discard anyway). This
+ // will be needed if NullStream& converted to LogStream& (e.g. as a
+ // result of a conditional expression).
+ char message_buffer_[2];
+};
+
+// Do nothing. This operator is inline, allowing the message to be
+// compiled away. The message will not be compiled away if we do
+// something like (flag ? LOG(INFO) : LOG(ERROR)) << message; when
+// SKIP_LOG=WARNING. In those cases, NullStream will be implicitly
+// converted to LogStream and the message will be computed and then
+// quietly discarded.
+template<class T>
+inline NullStream& operator<<(NullStream &str, const T &value) { return str; }
+
+// Similar to NullStream, but aborts the program (without stack
+// trace), like LogMessageFatal.
+class GOOGLE_GLOG_DLL_DECL NullStreamFatal : public NullStream {
+ public:
+ NullStreamFatal() { }
+ NullStreamFatal(const char* file, int line, const CheckOpString& result) :
+ NullStream(file, line, result) { }
+ ~NullStreamFatal() { _exit(1); }
+};
+
+// Install a signal handler that will dump signal information and a stack
+// trace when the program crashes on certain signals. We'll install the
+// signal handler for the following signals.
+//
+// SIGSEGV, SIGILL, SIGFPE, SIGABRT, SIGBUS, and SIGTERM.
+//
+// By default, the signal handler will write the failure dump to the
+// standard error. You can customize the destination by installing your
+// own writer function by InstallFailureWriter() below.
+//
+// Note on threading:
+//
+// The function should be called before threads are created, if you want
+// to use the failure signal handler for all threads. The stack trace
+// will be shown only for the thread that receives the signal. In other
+// words, stack traces of other threads won't be shown.
+GOOGLE_GLOG_DLL_DECL void InstallFailureSignalHandler();
+
+// Installs a function that is used for writing the failure dump. "data"
+// is the pointer to the beginning of a message to be written, and "size"
+// is the size of the message. You should not expect the data is
+// terminated with '\0'.
+GOOGLE_GLOG_DLL_DECL void InstallFailureWriter(
+ void (*writer)(const char* data, int size));
+
+}
+
+#endif // _LOGGING_H_
diff --git a/extern/libmv/third_party/glog/src/windows/glog/raw_logging.h b/extern/libmv/third_party/glog/src/windows/glog/raw_logging.h
new file mode 100644
index 00000000000..c81e67bf99c
--- /dev/null
+++ b/extern/libmv/third_party/glog/src/windows/glog/raw_logging.h
@@ -0,0 +1,189 @@
+// This file is automatically generated from src/glog/raw_logging.h.in
+// using src/windows/preprocess.sh.
+// DO NOT EDIT!
+
+// Copyright (c) 2006, Google Inc.
+// 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.
+//
+// Author: Maxim Lifantsev
+//
+// Thread-safe logging routines that do not allocate any memory or
+// acquire any locks, and can therefore be used by low-level memory
+// allocation and synchronization code.
+
+#ifndef BASE_RAW_LOGGING_H_
+#define BASE_RAW_LOGGING_H_
+
+#include <time.h>
+
+namespace google {
+
+#include "glog/log_severity.h"
+#include "glog/vlog_is_on.h"
+
+// Annoying stuff for windows -- makes sure clients can import these functions
+#ifndef GOOGLE_GLOG_DLL_DECL
+# if defined(_WIN32) && !defined(__CYGWIN__)
+# define GOOGLE_GLOG_DLL_DECL __declspec(dllimport)
+# else
+# define GOOGLE_GLOG_DLL_DECL
+# endif
+#endif
+
+// This is similar to LOG(severity) << format... and VLOG(level) << format..,
+// but
+// * it is to be used ONLY by low-level modules that can't use normal LOG()
+// * it is desiged to be a low-level logger that does not allocate any
+// memory and does not need any locks, hence:
+// * it logs straight and ONLY to STDERR w/o buffering
+// * it uses an explicit format and arguments list
+// * it will silently chop off really long message strings
+// Usage example:
+// RAW_LOG(ERROR, "Failed foo with %i: %s", status, error);
+// RAW_VLOG(3, "status is %i", status);
+// These will print an almost standard log lines like this to stderr only:
+// E0821 211317 file.cc:123] RAW: Failed foo with 22: bad_file
+// I0821 211317 file.cc:142] RAW: status is 20
+#define RAW_LOG(severity, ...) \
+ do { \
+ switch (google::severity) { \
+ case 0: \
+ RAW_LOG_INFO(__VA_ARGS__); \
+ break; \
+ case 1: \
+ RAW_LOG_WARNING(__VA_ARGS__); \
+ break; \
+ case 2: \
+ RAW_LOG_ERROR(__VA_ARGS__); \
+ break; \
+ case 3: \
+ RAW_LOG_FATAL(__VA_ARGS__); \
+ break; \
+ default: \
+ break; \
+ } \
+ } while (0)
+
+// The following STRIP_LOG testing is performed in the header file so that it's
+// possible to completely compile out the logging code and the log messages.
+#if STRIP_LOG == 0
+#define RAW_VLOG(verboselevel, ...) \
+ do { \
+ if (VLOG_IS_ON(verboselevel)) { \
+ RAW_LOG_INFO(__VA_ARGS__); \
+ } \
+ } while (0)
+#else
+#define RAW_VLOG(verboselevel, ...) RawLogStub__(0, __VA_ARGS__)
+#endif // STRIP_LOG == 0
+
+#if STRIP_LOG == 0
+#define RAW_LOG_INFO(...) google::RawLog__(google::INFO, \
+ __FILE__, __LINE__, __VA_ARGS__)
+#else
+#define RAW_LOG_INFO(...) google::RawLogStub__(0, __VA_ARGS__)
+#endif // STRIP_LOG == 0
+
+#if STRIP_LOG <= 1
+#define RAW_LOG_WARNING(...) google::RawLog__(google::WARNING, \
+ __FILE__, __LINE__, __VA_ARGS__)
+#else
+#define RAW_LOG_WARNING(...) google::RawLogStub__(0, __VA_ARGS__)
+#endif // STRIP_LOG <= 1
+
+#if STRIP_LOG <= 2
+#define RAW_LOG_ERROR(...) google::RawLog__(google::ERROR, \
+ __FILE__, __LINE__, __VA_ARGS__)
+#else
+#define RAW_LOG_ERROR(...) google::RawLogStub__(0, __VA_ARGS__)
+#endif // STRIP_LOG <= 2
+
+#if STRIP_LOG <= 3
+#define RAW_LOG_FATAL(...) google::RawLog__(google::FATAL, \
+ __FILE__, __LINE__, __VA_ARGS__)
+#else
+#define RAW_LOG_FATAL(...) \
+ do { \
+ google::RawLogStub__(0, __VA_ARGS__); \
+ exit(1); \
+ } while (0)
+#endif // STRIP_LOG <= 3
+
+// Similar to CHECK(condition) << message,
+// but for low-level modules: we use only RAW_LOG that does not allocate memory.
+// We do not want to provide args list here to encourage this usage:
+// if (!cond) RAW_LOG(FATAL, "foo ...", hard_to_compute_args);
+// so that the args are not computed when not needed.
+#define RAW_CHECK(condition, message) \
+ do { \
+ if (!(condition)) { \
+ RAW_LOG(FATAL, "Check %s failed: %s", #condition, message); \
+ } \
+ } while (0)
+
+// Debug versions of RAW_LOG and RAW_CHECK
+#ifndef NDEBUG
+
+#define RAW_DLOG(severity, ...) RAW_LOG(severity, __VA_ARGS__)
+#define RAW_DCHECK(condition, message) RAW_CHECK(condition, message)
+
+#else // NDEBUG
+
+#define RAW_DLOG(severity, ...) \
+ while (false) \
+ RAW_LOG(severity, __VA_ARGS__)
+#define RAW_DCHECK(condition, message) \
+ while (false) \
+ RAW_CHECK(condition, message)
+
+#endif // NDEBUG
+
+// Stub log function used to work around for unused variable warnings when
+// building with STRIP_LOG > 0.
+static inline void RawLogStub__(int ignored, ...) {
+}
+
+// Helper function to implement RAW_LOG and RAW_VLOG
+// Logs format... at "severity" level, reporting it
+// as called from file:line.
+// This does not allocate memory or acquire locks.
+GOOGLE_GLOG_DLL_DECL void RawLog__(LogSeverity severity,
+ const char* file,
+ int line,
+ const char* format, ...)
+ ;
+
+// Hack to propagate time information into this module so that
+// this module does not have to directly call localtime_r(),
+// which could allocate memory.
+GOOGLE_GLOG_DLL_DECL void RawLog__SetLastTime(const struct tm& t, int usecs);
+
+}
+
+#endif // BASE_RAW_LOGGING_H_
diff --git a/extern/libmv/third_party/glog/src/windows/glog/vlog_is_on.h b/extern/libmv/third_party/glog/src/windows/glog/vlog_is_on.h
new file mode 100644
index 00000000000..409a4011b38
--- /dev/null
+++ b/extern/libmv/third_party/glog/src/windows/glog/vlog_is_on.h
@@ -0,0 +1,133 @@
+// This file is automatically generated from src/glog/vlog_is_on.h.in
+// using src/windows/preprocess.sh.
+// DO NOT EDIT!
+
+// Copyright (c) 1999, 2007, Google Inc.
+// 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.
+//
+// Author: Ray Sidney and many others
+//
+// Defines the VLOG_IS_ON macro that controls the variable-verbosity
+// conditional logging.
+//
+// It's used by VLOG and VLOG_IF in logging.h
+// and by RAW_VLOG in raw_logging.h to trigger the logging.
+//
+// It can also be used directly e.g. like this:
+// if (VLOG_IS_ON(2)) {
+// // do some logging preparation and logging
+// // that can't be accomplished e.g. via just VLOG(2) << ...;
+// }
+//
+// The truth value that VLOG_IS_ON(level) returns is determined by
+// the three verbosity level flags:
+// --v=<n> Gives the default maximal active V-logging level;
+// 0 is the default.
+// Normally positive values are used for V-logging levels.
+// --vmodule=<str> Gives the per-module maximal V-logging levels to override
+// the value given by --v.
+// E.g. "my_module=2,foo*=3" would change the logging level
+// for all code in source files "my_module.*" and "foo*.*"
+// ("-inl" suffixes are also disregarded for this matching).
+//
+// SetVLOGLevel helper function is provided to do limited dynamic control over
+// V-logging by overriding the per-module settings given via --vmodule flag.
+//
+// CAVEAT: --vmodule functionality is not available in non gcc compilers.
+//
+
+#ifndef BASE_VLOG_IS_ON_H_
+#define BASE_VLOG_IS_ON_H_
+
+#include "glog/log_severity.h"
+
+// Annoying stuff for windows -- makes sure clients can import these functions
+#ifndef GOOGLE_GLOG_DLL_DECL
+# if defined(_WIN32) && !defined(__CYGWIN__)
+# define GOOGLE_GLOG_DLL_DECL __declspec(dllimport)
+# else
+# define GOOGLE_GLOG_DLL_DECL
+# endif
+#endif
+
+#if defined(__GNUC__)
+// We emit an anonymous static int* variable at every VLOG_IS_ON(n) site.
+// (Normally) the first time every VLOG_IS_ON(n) site is hit,
+// we determine what variable will dynamically control logging at this site:
+// it's either FLAGS_v or an appropriate internal variable
+// matching the current source file that represents results of
+// parsing of --vmodule flag and/or SetVLOGLevel calls.
+#define VLOG_IS_ON(verboselevel) \
+ __extension__ \
+ ({ static google::int32* vlocal__ = &google::kLogSiteUninitialized; \
+ google::int32 verbose_level__ = (verboselevel); \
+ (*vlocal__ >= verbose_level__) && \
+ ((vlocal__ != &google::kLogSiteUninitialized) || \
+ (google::InitVLOG3__(&vlocal__, &FLAGS_v, \
+ __FILE__, verbose_level__))); })
+#else
+// GNU extensions not available, so we do not support --vmodule.
+// Dynamic value of FLAGS_v always controls the logging level.
+#define VLOG_IS_ON(verboselevel) (FLAGS_v >= (verboselevel))
+#endif
+
+// Set VLOG(_IS_ON) level for module_pattern to log_level.
+// This lets us dynamically control what is normally set by the --vmodule flag.
+// Returns the level that previously applied to module_pattern.
+// NOTE: To change the log level for VLOG(_IS_ON) sites
+// that have already executed after/during InitGoogleLogging,
+// one needs to supply the exact --vmodule pattern that applied to them.
+// (If no --vmodule pattern applied to them
+// the value of FLAGS_v will continue to control them.)
+extern GOOGLE_GLOG_DLL_DECL int SetVLOGLevel(const char* module_pattern,
+ int log_level);
+
+// Various declarations needed for VLOG_IS_ON above: =========================
+
+// Special value used to indicate that a VLOG_IS_ON site has not been
+// initialized. We make this a large value, so the common-case check
+// of "*vlocal__ >= verbose_level__" in VLOG_IS_ON definition
+// passes in such cases and InitVLOG3__ is then triggered.
+extern google::int32 kLogSiteUninitialized;
+
+// Helper routine which determines the logging info for a particalur VLOG site.
+// site_flag is the address of the site-local pointer to the controlling
+// verbosity level
+// site_default is the default to use for *site_flag
+// fname is the current source file name
+// verbose_level is the argument to VLOG_IS_ON
+// We will return the return value for VLOG_IS_ON
+// and if possible set *site_flag appropriately.
+extern GOOGLE_GLOG_DLL_DECL bool InitVLOG3__(
+ google::int32** site_flag,
+ google::int32* site_default,
+ const char* fname,
+ google::int32 verbose_level);
+
+#endif // BASE_VLOG_IS_ON_H_
diff --git a/extern/libmv/third_party/glog/src/windows/port.cc b/extern/libmv/third_party/glog/src/windows/port.cc
new file mode 100644
index 00000000000..bfa6e70afbb
--- /dev/null
+++ b/extern/libmv/third_party/glog/src/windows/port.cc
@@ -0,0 +1,64 @@
+/* Copyright (c) 2008, Google Inc.
+ * 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.
+ *
+ * ---
+ * Author: Craig Silverstein
+ * Copied from google-perftools and modified by Shinichiro Hamaji
+ */
+
+#ifndef _WIN32
+# error You should only be including windows/port.cc in a windows environment!
+#endif
+
+#include "config.h"
+#include <stdarg.h> // for va_list, va_start, va_end
+#include <string.h> // for strstr()
+#include <assert.h>
+#include <string>
+#include <vector>
+#include "port.h"
+
+using std::string;
+using std::vector;
+
+// These call the windows _vsnprintf, but always NUL-terminate.
+int safe_vsnprintf(char *str, size_t size, const char *format, va_list ap) {
+ if (size == 0) // not even room for a \0?
+ return -1; // not what C99 says to do, but what windows does
+ str[size-1] = '\0';
+ return _vsnprintf(str, size-1, format, ap);
+}
+
+int snprintf(char *str, size_t size, const char *format, ...) {
+ va_list ap;
+ va_start(ap, format);
+ const int r = vsnprintf(str, size, format, ap);
+ va_end(ap);
+ return r;
+}
diff --git a/extern/libmv/third_party/glog/src/windows/port.h b/extern/libmv/third_party/glog/src/windows/port.h
new file mode 100644
index 00000000000..d093bf5d34c
--- /dev/null
+++ b/extern/libmv/third_party/glog/src/windows/port.h
@@ -0,0 +1,149 @@
+/* Copyright (c) 2008, Google Inc.
+ * 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.
+ *
+ * ---
+ * Author: Craig Silverstein
+ * Copied from google-perftools and modified by Shinichiro Hamaji
+ *
+ * These are some portability typedefs and defines to make it a bit
+ * easier to compile this code under VC++.
+ *
+ * Several of these are taken from glib:
+ * http://developer.gnome.org/doc/API/glib/glib-windows-compatability-functions.html
+ */
+
+#ifndef CTEMPLATE_WINDOWS_PORT_H_
+#define CTEMPLATE_WINDOWS_PORT_H_
+
+#include "config.h"
+
+#ifdef _WIN32
+
+#define WIN32_LEAN_AND_MEAN /* We always want minimal includes */
+#include <windows.h>
+#include <winsock.h> /* for gethostname */
+#include <io.h> /* because we so often use open/close/etc */
+#include <direct.h> /* for _getcwd() */
+#include <process.h> /* for _getpid() */
+#include <stdio.h> /* read in vsnprintf decl. before redifining it */
+#include <stdarg.h> /* template_dictionary.cc uses va_copy */
+#include <string.h> /* for _strnicmp(), strerror_s() */
+#include <time.h> /* for localtime_s() */
+/* Note: the C++ #includes are all together at the bottom. This file is
+ * used by both C and C++ code, so we put all the C++ together.
+ */
+
+/* 4244: otherwise we get problems when substracting two size_t's to an int
+ * 4251: it's complaining about a private struct I've chosen not to dllexport
+ * 4355: we use this in a constructor, but we do it safely
+ * 4715: for some reason VC++ stopped realizing you can't return after abort()
+ * 4800: we know we're casting ints/char*'s to bools, and we're ok with that
+ * 4996: Yes, we're ok using "unsafe" functions like fopen() and strerror()
+ */
+#pragma warning(disable:4244 4251 4355 4715 4800 4996)
+
+/* file I/O */
+#define PATH_MAX 1024
+#define access _access
+#define getcwd _getcwd
+#define open _open
+#define read _read
+#define write _write
+#define lseek _lseek
+#define close _close
+#define popen _popen
+#define pclose _pclose
+#define R_OK 04 /* read-only (for access()) */
+#define S_ISDIR(m) (((m) & _S_IFMT) == _S_IFDIR)
+#ifndef __MINGW32__
+enum { STDIN_FILENO = 0, STDOUT_FILENO = 1, STDERR_FILENO = 2 };
+#endif
+#define S_IRUSR S_IREAD
+#define S_IWUSR S_IWRITE
+
+/* Not quite as lightweight as a hard-link, but more than good enough for us. */
+#define link(oldpath, newpath) CopyFileA(oldpath, newpath, false)
+
+#define strcasecmp _stricmp
+#define strncasecmp _strnicmp
+
+/* In windows-land, hash<> is called hash_compare<> (from xhash.h) */
+#define hash hash_compare
+
+/* Sleep is in ms, on windows */
+#define sleep(secs) Sleep((secs) * 1000)
+
+/* We can't just use _vsnprintf and _snprintf as drop-in-replacements,
+ * because they don't always NUL-terminate. :-( We also can't use the
+ * name vsnprintf, since windows defines that (but not snprintf (!)).
+ */
+extern int snprintf(char *str, size_t size,
+ const char *format, ...);
+extern int safe_vsnprintf(char *str, size_t size,
+ const char *format, va_list ap);
+#define vsnprintf(str, size, format, ap) safe_vsnprintf(str, size, format, ap)
+#define va_copy(dst, src) (dst) = (src)
+
+/* Windows doesn't support specifying the number of buckets as a
+ * hash_map constructor arg, so we leave this blank.
+ */
+#define CTEMPLATE_SMALL_HASHTABLE
+
+#define DEFAULT_TEMPLATE_ROOTDIR ".."
+
+// ----------------------------------- SYSTEM/PROCESS
+typedef int pid_t;
+#define getpid _getpid
+
+// ----------------------------------- THREADS
+typedef DWORD pthread_t;
+typedef DWORD pthread_key_t;
+typedef LONG pthread_once_t;
+enum { PTHREAD_ONCE_INIT = 0 }; // important that this be 0! for SpinLock
+#define pthread_self GetCurrentThreadId
+#define pthread_equal(pthread_t_1, pthread_t_2) ((pthread_t_1)==(pthread_t_2))
+
+inline struct tm* localtime_r(const time_t* timep, struct tm* result) {
+ localtime_s(result, timep);
+ return result;
+}
+
+inline char* strerror_r(int errnum, char* buf, size_t buflen) {
+ strerror_s(buf, buflen, errnum);
+ return buf;
+}
+
+#ifndef __cplusplus
+/* I don't see how to get inlining for C code in MSVC. Ah well. */
+#define inline
+#endif
+
+#endif /* _WIN32 */
+
+#endif /* CTEMPLATE_WINDOWS_PORT_H_ */
diff --git a/extern/libmv/third_party/glog/src/windows/preprocess.sh b/extern/libmv/third_party/glog/src/windows/preprocess.sh
new file mode 100755
index 00000000000..ea4352e8e3a
--- /dev/null
+++ b/extern/libmv/third_party/glog/src/windows/preprocess.sh
@@ -0,0 +1,118 @@
+#!/bin/sh
+
+# Copyright (c) 2008, Google Inc.
+# 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.
+
+# ---
+# Author: Craig Silverstein
+# Copied from google-perftools and modified by Shinichiro Hamaji
+#
+# This script is meant to be run at distribution-generation time, for
+# instance by autogen.sh. It does some of the work configure would
+# normally do, for windows systems. In particular, it expands all the
+# @...@ variables found in .in files, and puts them here, in the windows
+# directory.
+#
+# This script should be run before any new release.
+
+if [ -z "$1" ]; then
+ echo "USAGE: $0 <src/ directory>"
+ exit 1
+fi
+
+DLLDEF_MACRO_NAME="GLOG_DLL_DECL"
+
+# The text we put in every .h files we create. As a courtesy, we'll
+# include a helpful comment for windows users as to how to use
+# GLOG_DLL_DECL. Apparently sed expands \n into a newline. Good!
+DLLDEF_DEFINES="\
+// NOTE: if you are statically linking the template library into your binary\n\
+// (rather than using the template .dll), set '/D $DLLDEF_MACRO_NAME='\n\
+// as a compiler flag in your project file to turn off the dllimports.\n\
+#ifndef $DLLDEF_MACRO_NAME\n\
+# define $DLLDEF_MACRO_NAME __declspec(dllimport)\n\
+#endif"
+
+# Read all the windows config info into variables
+# In order for the 'set' to take, this requires putting all in a subshell.
+(
+ while read define varname value; do
+ [ "$define" != "#define" ] && continue
+ eval "$varname='$value'"
+ done
+
+ # Process all the .in files in the "glog" subdirectory
+ mkdir -p "$1/windows/glog"
+ for file in `echo "$1"/glog/*.in`; do
+ echo "Processing $file"
+ outfile="$1/windows/glog/`basename $file .in`"
+
+ echo "\
+// This file is automatically generated from $file
+// using src/windows/preprocess.sh.
+// DO NOT EDIT!
+" > "$outfile"
+ # Besides replacing @...@, we also need to turn on dllimport
+ # We also need to replace hash by hash_compare (annoying we hard-code :-( )
+ sed -e "s!@ac_windows_dllexport@!$DLLDEF_MACRO_NAME!g" \
+ -e "s!@ac_windows_dllexport_defines@!$DLLDEF_DEFINES!g" \
+ -e "s!@ac_cv_cxx_hash_map@!$HASH_MAP_H!g" \
+ -e "s!@ac_cv_cxx_hash_namespace@!$HASH_NAMESPACE!g" \
+ -e "s!@ac_cv_cxx_hash_set@!$HASH_SET_H!g" \
+ -e "s!@ac_cv_have_stdint_h@!0!g" \
+ -e "s!@ac_cv_have_systypes_h@!0!g" \
+ -e "s!@ac_cv_have_inttypes_h@!0!g" \
+ -e "s!@ac_cv_have_unistd_h@!0!g" \
+ -e "s!@ac_cv_have_uint16_t@!0!g" \
+ -e "s!@ac_cv_have_u_int16_t@!0!g" \
+ -e "s!@ac_cv_have___uint16@!1!g" \
+ -e "s!@ac_cv_have_libgflags@!0!g" \
+ -e "s!@ac_cv_have___builtin_expect@!0!g" \
+ -e "s!@ac_cv_cxx_using_operator@!1!g" \
+ -e "s!@ac_cv___attribute___noreturn@!!g" \
+ -e "s!@ac_cv___attribute___printf_4_5@!!g" \
+ -e "s!@ac_google_attribute@!${HAVE___ATTRIBUTE__:-0}!g" \
+ -e "s!@ac_google_end_namespace@!$_END_GOOGLE_NAMESPACE_!g" \
+ -e "s!@ac_google_namespace@!$GOOGLE_NAMESPACE!g" \
+ -e "s!@ac_google_start_namespace@!$_START_GOOGLE_NAMESPACE_!g" \
+ -e "s!@ac_htmlparser_namespace@!$HTMLPARSER_NAMESPACE!g" \
+ -e "s!\\bhash\\b!hash_compare!g" \
+ "$file" >> "$outfile"
+ done
+) < "$1/windows/config.h"
+
+# log_severity.h isn't a .in file.
+echo "\
+// This file is automatically generated from $1/glog/log_severity.h
+// using src/windows/preprocess.sh.
+// DO NOT EDIT!
+" > "$1/windows/glog/log_severity.h"
+cat "$1/glog/log_severity.h" >> "$1/windows/glog/log_severity.h"
+
+echo "DONE"
diff --git a/extern/libmv/third_party/ldl/CMakeLists.txt b/extern/libmv/third_party/ldl/CMakeLists.txt
new file mode 100644
index 00000000000..db2d40e2612
--- /dev/null
+++ b/extern/libmv/third_party/ldl/CMakeLists.txt
@@ -0,0 +1,5 @@
+include_directories(../ufconfig)
+include_directories(Include)
+add_library(ldl Source/ldl.c)
+
+LIBMV_INSTALL_THIRD_PARTY_LIB(ldl)
diff --git a/extern/libmv/third_party/ldl/Doc/ChangeLog b/extern/libmv/third_party/ldl/Doc/ChangeLog
new file mode 100644
index 00000000000..48c322d3e77
--- /dev/null
+++ b/extern/libmv/third_party/ldl/Doc/ChangeLog
@@ -0,0 +1,39 @@
+May 31, 2007: version 2.0.0
+
+ * C-callable 64-bit version added
+
+ * ported to 64-bit MATLAB
+
+ * subdirectories added (Source/, Include/, Lib/, Demo/, Doc/, MATLAB/)
+
+Dec 12, 2006: version 1.3.4
+
+ * minor MATLAB cleanup
+
+Sept 11, 2006: version 1.3.1
+
+ * The ldl m-file renamed to ldlsparse, to avoid name conflict with the
+ new MATLAB ldl function (in MATLAB 7.3).
+
+Apr 30, 2006: version 1.3
+
+ * requires AMD v2.0. ldlmain.c demo program modified, since AMD can now
+ handle jumbled matrices. Minor change to Makefile.
+
+Aug 30, 2005:
+
+ * Makefile changed to use ../UFconfig/UFconfig.mk. License changed to
+ GNU LGPL.
+
+July 4, 2005:
+
+ * user guide added. Since no changes to the code were made,
+ the version number (1.1) and code release date (Apr 22, 2005)
+ were left unchanged.
+
+Apr. 22, 2005: LDL v1.1 released.
+
+ * No real changes were made. The code was revised so
+ that each routine fits on a single page in the documentation.
+
+Dec 31, 2003: LDL v1.0 released.
diff --git a/extern/libmv/third_party/ldl/Doc/lesser.txt b/extern/libmv/third_party/ldl/Doc/lesser.txt
new file mode 100644
index 00000000000..8add30ad590
--- /dev/null
+++ b/extern/libmv/third_party/ldl/Doc/lesser.txt
@@ -0,0 +1,504 @@
+ GNU LESSER GENERAL PUBLIC LICENSE
+ Version 2.1, February 1999
+
+ Copyright (C) 1991, 1999 Free Software Foundation, Inc.
+ 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+[This is the first released version of the Lesser GPL. It also counts
+ as the successor of the GNU Library Public License, version 2, hence
+ the version number 2.1.]
+
+ Preamble
+
+ The licenses for most software are designed to take away your
+freedom to share and change it. By contrast, the GNU General Public
+Licenses are intended to guarantee your freedom to share and change
+free software--to make sure the software is free for all its users.
+
+ This license, the Lesser General Public License, applies to some
+specially designated software packages--typically libraries--of the
+Free Software Foundation and other authors who decide to use it. You
+can use it too, but we suggest you first think carefully about whether
+this license or the ordinary General Public License is the better
+strategy to use in any particular case, based on the explanations below.
+
+ When we speak of free software, we are referring to freedom of use,
+not price. Our General Public Licenses are designed to make sure that
+you have the freedom to distribute copies of free software (and charge
+for this service if you wish); that you receive source code or can get
+it if you want it; that you can change the software and use pieces of
+it in new free programs; and that you are informed that you can do
+these things.
+
+ To protect your rights, we need to make restrictions that forbid
+distributors to deny you these rights or to ask you to surrender these
+rights. These restrictions translate to certain responsibilities for
+you if you distribute copies of the library or if you modify it.
+
+ For example, if you distribute copies of the library, whether gratis
+or for a fee, you must give the recipients all the rights that we gave
+you. You must make sure that they, too, receive or can get the source
+code. If you link other code with the library, you must provide
+complete object files to the recipients, so that they can relink them
+with the library after making changes to the library and recompiling
+it. And you must show them these terms so they know their rights.
+
+ We protect your rights with a two-step method: (1) we copyright the
+library, and (2) we offer you this license, which gives you legal
+permission to copy, distribute and/or modify the library.
+
+ To protect each distributor, we want to make it very clear that
+there is no warranty for the free library. Also, if the library is
+modified by someone else and passed on, the recipients should know
+that what they have is not the original version, so that the original
+author's reputation will not be affected by problems that might be
+introduced by others.
+
+ Finally, software patents pose a constant threat to the existence of
+any free program. We wish to make sure that a company cannot
+effectively restrict the users of a free program by obtaining a
+restrictive license from a patent holder. Therefore, we insist that
+any patent license obtained for a version of the library must be
+consistent with the full freedom of use specified in this license.
+
+ Most GNU software, including some libraries, is covered by the
+ordinary GNU General Public License. This license, the GNU Lesser
+General Public License, applies to certain designated libraries, and
+is quite different from the ordinary General Public License. We use
+this license for certain libraries in order to permit linking those
+libraries into non-free programs.
+
+ When a program is linked with a library, whether statically or using
+a shared library, the combination of the two is legally speaking a
+combined work, a derivative of the original library. The ordinary
+General Public License therefore permits such linking only if the
+entire combination fits its criteria of freedom. The Lesser General
+Public License permits more lax criteria for linking other code with
+the library.
+
+ We call this license the "Lesser" General Public License because it
+does Less to protect the user's freedom than the ordinary General
+Public License. It also provides other free software developers Less
+of an advantage over competing non-free programs. These disadvantages
+are the reason we use the ordinary General Public License for many
+libraries. However, the Lesser license provides advantages in certain
+special circumstances.
+
+ For example, on rare occasions, there may be a special need to
+encourage the widest possible use of a certain library, so that it becomes
+a de-facto standard. To achieve this, non-free programs must be
+allowed to use the library. A more frequent case is that a free
+library does the same job as widely used non-free libraries. In this
+case, there is little to gain by limiting the free library to free
+software only, so we use the Lesser General Public License.
+
+ In other cases, permission to use a particular library in non-free
+programs enables a greater number of people to use a large body of
+free software. For example, permission to use the GNU C Library in
+non-free programs enables many more people to use the whole GNU
+operating system, as well as its variant, the GNU/Linux operating
+system.
+
+ Although the Lesser General Public License is Less protective of the
+users' freedom, it does ensure that the user of a program that is
+linked with the Library has the freedom and the wherewithal to run
+that program using a modified version of the Library.
+
+ The precise terms and conditions for copying, distribution and
+modification follow. Pay close attention to the difference between a
+"work based on the library" and a "work that uses the library". The
+former contains code derived from the library, whereas the latter must
+be combined with the library in order to run.
+
+ GNU LESSER GENERAL PUBLIC LICENSE
+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+ 0. This License Agreement applies to any software library or other
+program which contains a notice placed by the copyright holder or
+other authorized party saying it may be distributed under the terms of
+this Lesser General Public License (also called "this License").
+Each licensee is addressed as "you".
+
+ A "library" means a collection of software functions and/or data
+prepared so as to be conveniently linked with application programs
+(which use some of those functions and data) to form executables.
+
+ The "Library", below, refers to any such software library or work
+which has been distributed under these terms. A "work based on the
+Library" means either the Library or any derivative work under
+copyright law: that is to say, a work containing the Library or a
+portion of it, either verbatim or with modifications and/or translated
+straightforwardly into another language. (Hereinafter, translation is
+included without limitation in the term "modification".)
+
+ "Source code" for a work means the preferred form of the work for
+making modifications to it. For a library, complete source code means
+all the source code for all modules it contains, plus any associated
+interface definition files, plus the scripts used to control compilation
+and installation of the library.
+
+ Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope. The act of
+running a program using the Library is not restricted, and output from
+such a program is covered only if its contents constitute a work based
+on the Library (independent of the use of the Library in a tool for
+writing it). Whether that is true depends on what the Library does
+and what the program that uses the Library does.
+
+ 1. You may copy and distribute verbatim copies of the Library's
+complete source code as you receive it, in any medium, provided that
+you conspicuously and appropriately publish on each copy an
+appropriate copyright notice and disclaimer of warranty; keep intact
+all the notices that refer to this License and to the absence of any
+warranty; and distribute a copy of this License along with the
+Library.
+
+ You may charge a fee for the physical act of transferring a copy,
+and you may at your option offer warranty protection in exchange for a
+fee.
+
+ 2. You may modify your copy or copies of the Library or any portion
+of it, thus forming a work based on the Library, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+ a) The modified work must itself be a software library.
+
+ b) You must cause the files modified to carry prominent notices
+ stating that you changed the files and the date of any change.
+
+ c) You must cause the whole of the work to be licensed at no
+ charge to all third parties under the terms of this License.
+
+ d) If a facility in the modified Library refers to a function or a
+ table of data to be supplied by an application program that uses
+ the facility, other than as an argument passed when the facility
+ is invoked, then you must make a good faith effort to ensure that,
+ in the event an application does not supply such function or
+ table, the facility still operates, and performs whatever part of
+ its purpose remains meaningful.
+
+ (For example, a function in a library to compute square roots has
+ a purpose that is entirely well-defined independent of the
+ application. Therefore, Subsection 2d requires that any
+ application-supplied function or table used by this function must
+ be optional: if the application does not supply it, the square
+ root function must still compute square roots.)
+
+These requirements apply to the modified work as a whole. If
+identifiable sections of that work are not derived from the Library,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works. But when you
+distribute the same sections as part of a whole which is a work based
+on the Library, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote
+it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Library.
+
+In addition, mere aggregation of another work not based on the Library
+with the Library (or with a work based on the Library) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+ 3. You may opt to apply the terms of the ordinary GNU General Public
+License instead of this License to a given copy of the Library. To do
+this, you must alter all the notices that refer to this License, so
+that they refer to the ordinary GNU General Public License, version 2,
+instead of to this License. (If a newer version than version 2 of the
+ordinary GNU General Public License has appeared, then you can specify
+that version instead if you wish.) Do not make any other change in
+these notices.
+
+ Once this change is made in a given copy, it is irreversible for
+that copy, so the ordinary GNU General Public License applies to all
+subsequent copies and derivative works made from that copy.
+
+ This option is useful when you wish to copy part of the code of
+the Library into a program that is not a library.
+
+ 4. You may copy and distribute the Library (or a portion or
+derivative of it, under Section 2) in object code or executable form
+under the terms of Sections 1 and 2 above provided that you accompany
+it with the complete corresponding machine-readable source code, which
+must be distributed under the terms of Sections 1 and 2 above on a
+medium customarily used for software interchange.
+
+ If distribution of object code is made by offering access to copy
+from a designated place, then offering equivalent access to copy the
+source code from the same place satisfies the requirement to
+distribute the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+ 5. A program that contains no derivative of any portion of the
+Library, but is designed to work with the Library by being compiled or
+linked with it, is called a "work that uses the Library". Such a
+work, in isolation, is not a derivative work of the Library, and
+therefore falls outside the scope of this License.
+
+ However, linking a "work that uses the Library" with the Library
+creates an executable that is a derivative of the Library (because it
+contains portions of the Library), rather than a "work that uses the
+library". The executable is therefore covered by this License.
+Section 6 states terms for distribution of such executables.
+
+ When a "work that uses the Library" uses material from a header file
+that is part of the Library, the object code for the work may be a
+derivative work of the Library even though the source code is not.
+Whether this is true is especially significant if the work can be
+linked without the Library, or if the work is itself a library. The
+threshold for this to be true is not precisely defined by law.
+
+ If such an object file uses only numerical parameters, data
+structure layouts and accessors, and small macros and small inline
+functions (ten lines or less in length), then the use of the object
+file is unrestricted, regardless of whether it is legally a derivative
+work. (Executables containing this object code plus portions of the
+Library will still fall under Section 6.)
+
+ Otherwise, if the work is a derivative of the Library, you may
+distribute the object code for the work under the terms of Section 6.
+Any executables containing that work also fall under Section 6,
+whether or not they are linked directly with the Library itself.
+
+ 6. As an exception to the Sections above, you may also combine or
+link a "work that uses the Library" with the Library to produce a
+work containing portions of the Library, and distribute that work
+under terms of your choice, provided that the terms permit
+modification of the work for the customer's own use and reverse
+engineering for debugging such modifications.
+
+ You must give prominent notice with each copy of the work that the
+Library is used in it and that the Library and its use are covered by
+this License. You must supply a copy of this License. If the work
+during execution displays copyright notices, you must include the
+copyright notice for the Library among them, as well as a reference
+directing the user to the copy of this License. Also, you must do one
+of these things:
+
+ a) Accompany the work with the complete corresponding
+ machine-readable source code for the Library including whatever
+ changes were used in the work (which must be distributed under
+ Sections 1 and 2 above); and, if the work is an executable linked
+ with the Library, with the complete machine-readable "work that
+ uses the Library", as object code and/or source code, so that the
+ user can modify the Library and then relink to produce a modified
+ executable containing the modified Library. (It is understood
+ that the user who changes the contents of definitions files in the
+ Library will not necessarily be able to recompile the application
+ to use the modified definitions.)
+
+ b) Use a suitable shared library mechanism for linking with the
+ Library. A suitable mechanism is one that (1) uses at run time a
+ copy of the library already present on the user's computer system,
+ rather than copying library functions into the executable, and (2)
+ will operate properly with a modified version of the library, if
+ the user installs one, as long as the modified version is
+ interface-compatible with the version that the work was made with.
+
+ c) Accompany the work with a written offer, valid for at
+ least three years, to give the same user the materials
+ specified in Subsection 6a, above, for a charge no more
+ than the cost of performing this distribution.
+
+ d) If distribution of the work is made by offering access to copy
+ from a designated place, offer equivalent access to copy the above
+ specified materials from the same place.
+
+ e) Verify that the user has already received a copy of these
+ materials or that you have already sent this user a copy.
+
+ For an executable, the required form of the "work that uses the
+Library" must include any data and utility programs needed for
+reproducing the executable from it. However, as a special exception,
+the materials to be distributed need not include anything that is
+normally distributed (in either source or binary form) with the major
+components (compiler, kernel, and so on) of the operating system on
+which the executable runs, unless that component itself accompanies
+the executable.
+
+ It may happen that this requirement contradicts the license
+restrictions of other proprietary libraries that do not normally
+accompany the operating system. Such a contradiction means you cannot
+use both them and the Library together in an executable that you
+distribute.
+
+ 7. You may place library facilities that are a work based on the
+Library side-by-side in a single library together with other library
+facilities not covered by this License, and distribute such a combined
+library, provided that the separate distribution of the work based on
+the Library and of the other library facilities is otherwise
+permitted, and provided that you do these two things:
+
+ a) Accompany the combined library with a copy of the same work
+ based on the Library, uncombined with any other library
+ facilities. This must be distributed under the terms of the
+ Sections above.
+
+ b) Give prominent notice with the combined library of the fact
+ that part of it is a work based on the Library, and explaining
+ where to find the accompanying uncombined form of the same work.
+
+ 8. You may not copy, modify, sublicense, link with, or distribute
+the Library except as expressly provided under this License. Any
+attempt otherwise to copy, modify, sublicense, link with, or
+distribute the Library is void, and will automatically terminate your
+rights under this License. However, parties who have received copies,
+or rights, from you under this License will not have their licenses
+terminated so long as such parties remain in full compliance.
+
+ 9. You are not required to accept this License, since you have not
+signed it. However, nothing else grants you permission to modify or
+distribute the Library or its derivative works. These actions are
+prohibited by law if you do not accept this License. Therefore, by
+modifying or distributing the Library (or any work based on the
+Library), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Library or works based on it.
+
+ 10. Each time you redistribute the Library (or any work based on the
+Library), the recipient automatically receives a license from the
+original licensor to copy, distribute, link with or modify the Library
+subject to these terms and conditions. You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties with
+this License.
+
+ 11. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Library at all. For example, if a patent
+license would not permit royalty-free redistribution of the Library by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Library.
+
+If any portion of this section is held invalid or unenforceable under any
+particular circumstance, the balance of the section is intended to apply,
+and the section as a whole is intended to apply in other circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system which is
+implemented by public license practices. Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+ 12. If the distribution and/or use of the Library is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Library under this License may add
+an explicit geographical distribution limitation excluding those countries,
+so that distribution is permitted only in or among countries not thus
+excluded. In such case, this License incorporates the limitation as if
+written in the body of this License.
+
+ 13. The Free Software Foundation may publish revised and/or new
+versions of the Lesser General Public License from time to time.
+Such new versions will be similar in spirit to the present version,
+but may differ in detail to address new problems or concerns.
+
+Each version is given a distinguishing version number. If the Library
+specifies a version number of this License which applies to it and
+"any later version", you have the option of following the terms and
+conditions either of that version or of any later version published by
+the Free Software Foundation. If the Library does not specify a
+license version number, you may choose any version ever published by
+the Free Software Foundation.
+
+ 14. If you wish to incorporate parts of the Library into other free
+programs whose distribution conditions are incompatible with these,
+write to the author to ask for permission. For software which is
+copyrighted by the Free Software Foundation, write to the Free
+Software Foundation; we sometimes make exceptions for this. Our
+decision will be guided by the two goals of preserving the free status
+of all derivatives of our free software and of promoting the sharing
+and reuse of software generally.
+
+ NO WARRANTY
+
+ 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO
+WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW.
+EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR
+OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY
+KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE
+LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME
+THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
+
+ 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN
+WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY
+AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU
+FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR
+CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE
+LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING
+RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A
+FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
+SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+DAMAGES.
+
+ END OF TERMS AND CONDITIONS
+
+ How to Apply These Terms to Your New Libraries
+
+ If you develop a new library, and you want it to be of the greatest
+possible use to the public, we recommend making it free software that
+everyone can redistribute and change. You can do so by permitting
+redistribution under these terms (or, alternatively, under the terms of the
+ordinary General Public License).
+
+ To apply these terms, attach the following notices to the library. It is
+safest to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least the
+"copyright" line and a pointer to where the full notice is found.
+
+ <one line to give the library's name and a brief idea of what it does.>
+ Copyright (C) <year> <name of author>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+
+Also add information on how to contact you by electronic and paper mail.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the library, if
+necessary. Here is a sample; alter the names:
+
+ Yoyodyne, Inc., hereby disclaims all copyright interest in the
+ library `Frob' (a library for tweaking knobs) written by James Random Hacker.
+
+ <signature of Ty Coon>, 1 April 1990
+ Ty Coon, President of Vice
+
+That's all there is to it!
+
+
diff --git a/extern/libmv/third_party/ldl/Include/ldl.h b/extern/libmv/third_party/ldl/Include/ldl.h
new file mode 100644
index 00000000000..5840be322f7
--- /dev/null
+++ b/extern/libmv/third_party/ldl/Include/ldl.h
@@ -0,0 +1,104 @@
+/* ========================================================================== */
+/* === ldl.h: include file for the LDL package ============================= */
+/* ========================================================================== */
+
+/* LDL Copyright (c) Timothy A Davis,
+ * University of Florida. All Rights Reserved. See README for the License.
+ */
+
+#include "UFconfig.h"
+
+#ifdef LDL_LONG
+#define LDL_int UF_long
+#define LDL_ID UF_long_id
+
+#define LDL_symbolic ldl_l_symbolic
+#define LDL_numeric ldl_l_numeric
+#define LDL_lsolve ldl_l_lsolve
+#define LDL_dsolve ldl_l_dsolve
+#define LDL_ltsolve ldl_l_ltsolve
+#define LDL_perm ldl_l_perm
+#define LDL_permt ldl_l_permt
+#define LDL_valid_perm ldl_l_valid_perm
+#define LDL_valid_matrix ldl_l_valid_matrix
+
+#else
+#define LDL_int int
+#define LDL_ID "%d"
+
+#define LDL_symbolic ldl_symbolic
+#define LDL_numeric ldl_numeric
+#define LDL_lsolve ldl_lsolve
+#define LDL_dsolve ldl_dsolve
+#define LDL_ltsolve ldl_ltsolve
+#define LDL_perm ldl_perm
+#define LDL_permt ldl_permt
+#define LDL_valid_perm ldl_valid_perm
+#define LDL_valid_matrix ldl_valid_matrix
+
+#endif
+
+/* ========================================================================== */
+/* === int version ========================================================== */
+/* ========================================================================== */
+
+void ldl_symbolic (int n, int Ap [ ], int Ai [ ], int Lp [ ],
+ int Parent [ ], int Lnz [ ], int Flag [ ], int P [ ], int Pinv [ ]) ;
+
+int ldl_numeric (int n, int Ap [ ], int Ai [ ], double Ax [ ],
+ int Lp [ ], int Parent [ ], int Lnz [ ], int Li [ ], double Lx [ ],
+ double D [ ], double Y [ ], int Pattern [ ], int Flag [ ],
+ int P [ ], int Pinv [ ]) ;
+
+void ldl_lsolve (int n, double X [ ], int Lp [ ], int Li [ ],
+ double Lx [ ]) ;
+
+void ldl_dsolve (int n, double X [ ], double D [ ]) ;
+
+void ldl_ltsolve (int n, double X [ ], int Lp [ ], int Li [ ],
+ double Lx [ ]) ;
+
+void ldl_perm (int n, double X [ ], double B [ ], int P [ ]) ;
+void ldl_permt (int n, double X [ ], double B [ ], int P [ ]) ;
+
+int ldl_valid_perm (int n, int P [ ], int Flag [ ]) ;
+int ldl_valid_matrix ( int n, int Ap [ ], int Ai [ ]) ;
+
+/* ========================================================================== */
+/* === long version ========================================================= */
+/* ========================================================================== */
+
+void ldl_l_symbolic (UF_long n, UF_long Ap [ ], UF_long Ai [ ], UF_long Lp [ ],
+ UF_long Parent [ ], UF_long Lnz [ ], UF_long Flag [ ], UF_long P [ ],
+ UF_long Pinv [ ]) ;
+
+UF_long ldl_l_numeric (UF_long n, UF_long Ap [ ], UF_long Ai [ ], double Ax [ ],
+ UF_long Lp [ ], UF_long Parent [ ], UF_long Lnz [ ], UF_long Li [ ],
+ double Lx [ ], double D [ ], double Y [ ], UF_long Pattern [ ],
+ UF_long Flag [ ], UF_long P [ ], UF_long Pinv [ ]) ;
+
+void ldl_l_lsolve (UF_long n, double X [ ], UF_long Lp [ ], UF_long Li [ ],
+ double Lx [ ]) ;
+
+void ldl_l_dsolve (UF_long n, double X [ ], double D [ ]) ;
+
+void ldl_l_ltsolve (UF_long n, double X [ ], UF_long Lp [ ], UF_long Li [ ],
+ double Lx [ ]) ;
+
+void ldl_l_perm (UF_long n, double X [ ], double B [ ], UF_long P [ ]) ;
+void ldl_l_permt (UF_long n, double X [ ], double B [ ], UF_long P [ ]) ;
+
+UF_long ldl_l_valid_perm (UF_long n, UF_long P [ ], UF_long Flag [ ]) ;
+UF_long ldl_l_valid_matrix ( UF_long n, UF_long Ap [ ], UF_long Ai [ ]) ;
+
+/* ========================================================================== */
+/* === LDL version ========================================================== */
+/* ========================================================================== */
+
+#define LDL_DATE "Nov 1, 2007"
+#define LDL_VERSION_CODE(main,sub) ((main) * 1000 + (sub))
+#define LDL_MAIN_VERSION 2
+#define LDL_SUB_VERSION 0
+#define LDL_SUBSUB_VERSION 1
+#define LDL_VERSION LDL_VERSION_CODE(LDL_MAIN_VERSION,LDL_SUB_VERSION)
+
diff --git a/extern/libmv/third_party/ldl/README.libmv b/extern/libmv/third_party/ldl/README.libmv
new file mode 100644
index 00000000000..64ece48a390
--- /dev/null
+++ b/extern/libmv/third_party/ldl/README.libmv
@@ -0,0 +1,10 @@
+Project: LDL
+URL: http://www.cise.ufl.edu/research/sparse/ldl/
+License: LGPL2.1
+Upstream version: 2.0.1 (despite the ChangeLog saying 2.0.0)
+
+Local modifications:
+
+ * Deleted everything except ldl.c, ldl.h, the license, the ChangeLog, and the
+ README.
+
diff --git a/extern/libmv/third_party/ldl/README.txt b/extern/libmv/third_party/ldl/README.txt
new file mode 100644
index 00000000000..7be8dd1f001
--- /dev/null
+++ b/extern/libmv/third_party/ldl/README.txt
@@ -0,0 +1,136 @@
+LDL Version 2.0: a sparse LDL' factorization and solve package.
+ Written in C, with both a C and MATLAB mexFunction interface.
+
+These routines are not terrifically fast (they do not use dense matrix kernels),
+but the code is very short and concise. The purpose is to illustrate the
+algorithms in a very concise and readable manner, primarily for educational
+purposes. Although the code is very concise, this package is slightly faster
+than the built-in sparse Cholesky factorization in MATLAB 6.5 (chol), when
+using the same input permutation.
+
+Requires UFconfig, in the ../UFconfig directory relative to this directory.
+
+Quick start (Unix, or Windows with Cygwin):
+
+ To compile, test, and install LDL, you may wish to first obtain a copy of
+ AMD v2.0 from http://www.cise.ufl.edu/research/sparse, and place it in the
+ ../AMD directory, relative to this directory. Next, type "make", which
+ will compile the LDL library and three demo main programs (one of which
+ requires AMD). It will also compile the LDL MATLAB mexFunction (if you
+ have MATLAB). Typing "make clean" will remove non-essential files.
+ AMD v2.0 or later is required. Its use is optional.
+
+Quick start (for MATLAB users);
+
+ To compile, test, and install the LDL mexFunctions (ldlsparse and
+ ldlsymbol), start MATLAB in this directory and type ldl_install.
+ This works on any system supported by MATLAB.
+
+--------------------------------------------------------------------------------
+
+LDL Copyright (c) 2005 by Timothy A. Davis. All Rights Reserved.
+
+LDL License:
+
+ Your use or distribution of LDL or any modified version of
+ LDL implies that you agree to this License.
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+ USA
+
+ Permission is hereby granted to use or copy this program under the
+ terms of the GNU LGPL, provided that the Copyright, this License,
+ and the Availability of the original version is retained on all copies.
+ User documentation of any code that uses this code or any modified
+ version of this code must cite the Copyright, this License, the
+ Availability note, and "Used by permission." Permission to modify
+ the code and to distribute modified code is granted, provided the
+ Copyright, this License, and the Availability note are retained,
+ and a notice that the code was modified is included.
+
+Availability:
+
+ http://www.cise.ufl.edu/research/sparse/ldl
+
+Acknowledgements:
+
+ This work was supported by the National Science Foundation, under
+ grant CCR-0203270.
+
+ Portions of this work were done while on sabbatical at Stanford University
+ and Lawrence Berkeley National Laboratory (with funding from the SciDAC
+ program). I would like to thank Gene Golub, Esmond Ng, and Horst Simon
+ for making this sabbatical possible. I would like to thank Pete Stewart
+ for his comments on a draft of this software and paper.
+
+--------------------------------------------------------------------------------
+Files and directories in this distribution:
+--------------------------------------------------------------------------------
+
+ Documentation, and compiling:
+
+ README.txt this file
+ Makefile for compiling LDL
+ ChangeLog changes since V1.0 (Dec 31, 2003)
+ License license
+ lesser.txt the GNU LGPL license
+
+ ldl_userguide.pdf user guide in PDF
+ ldl_userguide.ps user guide in postscript
+ ldl_userguide.tex user guide in Latex
+ ldl.bib bibliography for user guide
+
+ The LDL library itself:
+
+ ldl.c the C-callable routines
+ ldl.h include file for any code that calls LDL
+
+ A simple C main program that demonstrates how to use LDL:
+
+ ldlsimple.c a stand-alone C program, uses the basic features of LDL
+ ldlsimple.out output of ldlsimple
+
+ ldllsimple.c long integer version of ldlsimple.c
+
+ Demo C program, for testing LDL and providing an example of its use
+
+ ldlmain.c a stand-alone C main program that uses and tests LDL
+ Matrix a directory containing matrices used by ldlmain.c
+ ldlmain.out output of ldlmain
+ ldlamd.out output of ldlamd (ldlmain.c compiled with AMD)
+ ldllamd.out output of ldllamd (ldlmain.c compiled with AMD, long)
+
+ MATLAB-related, not required for use in a regular C program
+
+ Contents.m a list of the MATLAB-callable routines
+ ldl.m MATLAB help file for the LDL mexFunction
+ ldldemo.m MATLAB demo of how to use the LDL mexFunction
+ ldldemo.out diary output of ldldemo
+ ldltest.m to test the LDL mexFunction
+ ldltest.out diary output of ldltest
+ ldlmex.c the LDL mexFunction for MATLAB
+ ldlrow.m the numerical algorithm that LDL is based on
+ ldlmain2.m compiles and runs ldlmain.c as a MATLAB mexFunction
+ ldlmain2.out output of ldlmain2.m
+ ldlsymbolmex.c symbolic factorization using LDL (see SYMBFACT, ETREE)
+ ldlsymbol.m help file for the LDLSYMBOL mexFunction
+
+ ldl_install.m compile, install, and test LDL functions
+ ldl_make.m compile LDL (ldlsparse and ldlsymbol)
+
+ ldlsparse.m help for ldlsparse
+
+See ldl.c for a description of how to use the code from a C program. Type
+"help ldl" in MATLAB for information on how to use LDL in a MATLAB program.
diff --git a/extern/libmv/third_party/ldl/Source/ldl.c b/extern/libmv/third_party/ldl/Source/ldl.c
new file mode 100644
index 00000000000..a9b35c846ef
--- /dev/null
+++ b/extern/libmv/third_party/ldl/Source/ldl.c
@@ -0,0 +1,507 @@
+/* ========================================================================== */
+/* === ldl.c: sparse LDL' factorization and solve package =================== */
+/* ========================================================================== */
+
+/* LDL: a simple set of routines for sparse LDL' factorization. These routines
+ * are not terrifically fast (they do not use dense matrix kernels), but the
+ * code is very short. The purpose is to illustrate the algorithms in a very
+ * concise manner, primarily for educational purposes. Although the code is
+ * very concise, this package is slightly faster than the built-in sparse
+ * Cholesky factorization in MATLAB 7.0 (chol), when using the same input
+ * permutation.
+ *
+ * The routines compute the LDL' factorization of a real sparse symmetric
+ * matrix A (or PAP' if a permutation P is supplied), and solve upper
+ * and lower triangular systems with the resulting L and D factors. If A is
+ * positive definite then the factorization will be accurate. A can be
+ * indefinite (with negative values on the diagonal D), but in this case no
+ * guarantee of accuracy is provided, since no numeric pivoting is performed.
+ *
+ * The n-by-n sparse matrix A is in compressed-column form. The nonzero values
+ * in column j are stored in Ax [Ap [j] ... Ap [j+1]-1], with corresponding row
+ * indices in Ai [Ap [j] ... Ap [j+1]-1]. Ap [0] = 0 is required, and thus
+ * nz = Ap [n] is the number of nonzeros in A. Ap is an int array of size n+1.
+ * The int array Ai and the double array Ax are of size nz. This data structure
+ * is identical to the one used by MATLAB, except for the following
+ * generalizations. The row indices in each column of A need not be in any
+ * particular order, although they must be in the range 0 to n-1. Duplicate
+ * entries can be present; any duplicates are summed. That is, if row index i
+ * appears twice in a column j, then the value of A (i,j) is the sum of the two
+ * entries. The data structure used here for the input matrix A is more
+ * flexible than MATLAB's, which requires sorted columns with no duplicate
+ * entries.
+ *
+ * Only the diagonal and upper triangular part of A (or PAP' if a permutation
+ * P is provided) is accessed. The lower triangular parts of the matrix A or
+ * PAP' can be present, but they are ignored.
+ *
+ * The optional input permutation is provided as an array P of length n. If
+ * P [k] = j, the row and column j of A is the kth row and column of PAP'.
+ * If P is present then the factorization is LDL' = PAP' or L*D*L' = A(P,P) in
+ * 0-based MATLAB notation. If P is not present (a null pointer) then no
+ * permutation is performed, and the factorization is LDL' = A.
+ *
+ * The lower triangular matrix L is stored in the same compressed-column
+ * form (an int Lp array of size n+1, an int Li array of size Lp [n], and a
+ * double array Lx of the same size as Li). It has a unit diagonal, which is
+ * not stored. The row indices in each column of L are always returned in
+ * ascending order, with no duplicate entries. This format is compatible with
+ * MATLAB, except that it would be more convenient for MATLAB to include the
+ * unit diagonal of L. Doing so here would add additional complexity to the
+ * code, and is thus omitted in the interest of keeping this code short and
+ * readable.
+ *
+ * The elimination tree is held in the Parent [0..n-1] array. It is normally
+ * not required by the user, but it is required by ldl_numeric. The diagonal
+ * matrix D is held as an array D [0..n-1] of size n.
+ *
+ * --------------------
+ * C-callable routines:
+ * --------------------
+ *
+ * ldl_symbolic: Given the pattern of A, computes the Lp and Parent arrays
+ * required by ldl_numeric. Takes time proportional to the number of
+ * nonzeros in L. Computes the inverse Pinv of P if P is provided.
+ * Also returns Lnz, the count of nonzeros in each column of L below
+ * the diagonal (this is not required by ldl_numeric).
+ * ldl_numeric: Given the pattern and numerical values of A, the Lp array,
+ * the Parent array, and P and Pinv if applicable, computes the
+ * pattern and numerical values of L and D.
+ * ldl_lsolve: Solves Lx=b for a dense vector b.
+ * ldl_dsolve: Solves Dx=b for a dense vector b.
+ * ldl_ltsolve: Solves L'x=b for a dense vector b.
+ * ldl_perm: Computes x=Pb for a dense vector b.
+ * ldl_permt: Computes x=P'b for a dense vector b.
+ * ldl_valid_perm: checks the validity of a permutation vector
+ * ldl_valid_matrix: checks the validity of the sparse matrix A
+ *
+ * ----------------------------
+ * Limitations of this package:
+ * ----------------------------
+ *
+ * In the interest of keeping this code simple and readable, ldl_symbolic and
+ * ldl_numeric assume their inputs are valid. You can check your own inputs
+ * prior to calling these routines with the ldl_valid_perm and ldl_valid_matrix
+ * routines. Except for the two ldl_valid_* routines, no routine checks to see
+ * if the array arguments are present (non-NULL). Like all C routines, no
+ * routine can determine if the arrays are long enough and don't overlap.
+ *
+ * The ldl_numeric does check the numerical factorization, however. It returns
+ * n if the factorization is successful. If D (k,k) is zero, then k is
+ * returned, and L is only partially computed.
+ *
+ * No pivoting to control fill-in is performed, which is often critical for
+ * obtaining good performance. I recommend that you compute the permutation P
+ * using AMD or SYMAMD (approximate minimum degree ordering routines), or an
+ * appropriate graph-partitioning based ordering. See the ldldemo.m routine for
+ * an example in MATLAB, and the ldlmain.c stand-alone C program for examples of
+ * how to find P. Routines for manipulating compressed-column matrices are
+ * available in UMFPACK. AMD, SYMAMD, UMFPACK, and this LDL package are all
+ * available at http://www.cise.ufl.edu/research/sparse.
+ *
+ * -------------------------
+ * Possible simplifications:
+ * -------------------------
+ *
+ * These routines could be made even simpler with a few additional assumptions.
+ * If no input permutation were performed, the caller would have to permute the
+ * matrix first, but the computation of Pinv, and the use of P and Pinv could be
+ * removed. If only the diagonal and upper triangular part of A or PAP' are
+ * present, then the tests in the "if (i < k)" statement in ldl_symbolic and
+ * "if (i <= k)" in ldl_numeric, are always true, and could be removed (i can
+ * equal k in ldl_symbolic, but then the body of the if statement would
+ * correctly do no work since Flag [k] == k). If we could assume that no
+ * duplicate entries are present, then the statement Y [i] += Ax [p] could be
+ * replaced with Y [i] = Ax [p] in ldl_numeric.
+ *
+ * --------------------------
+ * Description of the method:
+ * --------------------------
+ *
+ * LDL computes the symbolic factorization by finding the pattern of L one row
+ * at a time. It does this based on the following theory. Consider a sparse
+ * system Lx=b, where L, x, and b, are all sparse, and where L comes from a
+ * Cholesky (or LDL') factorization. The elimination tree (etree) of L is
+ * defined as follows. The parent of node j is the smallest k > j such that
+ * L (k,j) is nonzero. Node j has no parent if column j of L is completely zero
+ * below the diagonal (j is a root of the etree in this case). The nonzero
+ * pattern of x is the union of the paths from each node i to the root, for
+ * each nonzero b (i). To compute the numerical solution to Lx=b, we can
+ * traverse the columns of L corresponding to nonzero values of x. This
+ * traversal does not need to be done in the order 0 to n-1. It can be done in
+ * any "topological" order, such that x (i) is computed before x (j) if i is a
+ * descendant of j in the elimination tree.
+ *
+ * The row-form of the LDL' factorization is shown in the MATLAB function
+ * ldlrow.m in this LDL package. Note that row k of L is found via a sparse
+ * triangular solve of L (1:k-1, 1:k-1) \ A (1:k-1, k), to use 1-based MATLAB
+ * notation. Thus, we can start with the nonzero pattern of the kth column of
+ * A (above the diagonal), follow the paths up to the root of the etree of the
+ * (k-1)-by-(k-1) leading submatrix of L, and obtain the pattern of the kth row
+ * of L. Note that we only need the leading (k-1)-by-(k-1) submatrix of L to
+ * do this. The elimination tree can be constructed as we go.
+ *
+ * The symbolic factorization does the same thing, except that it discards the
+ * pattern of L as it is computed. It simply counts the number of nonzeros in
+ * each column of L and then constructs the Lp index array when it's done. The
+ * symbolic factorization does not need to do this in topological order.
+ * Compare ldl_symbolic with the first part of ldl_numeric, and note that the
+ * while (len > 0) loop is not present in ldl_symbolic.
+ *
+ * LDL Version 1.3, Copyright (c) 2006 by Timothy A Davis,
+ * University of Florida. All Rights Reserved. Developed while on sabbatical
+ * at Stanford University and Lawrence Berkeley National Laboratory. Refer to
+ * the README file for the License. Available at
+ * http://www.cise.ufl.edu/research/sparse.
+ */
+
+#include "ldl.h"
+
+/* ========================================================================== */
+/* === ldl_symbolic ========================================================= */
+/* ========================================================================== */
+
+/* The input to this routine is a sparse matrix A, stored in column form, and
+ * an optional permutation P. The output is the elimination tree
+ * and the number of nonzeros in each column of L. Parent [i] = k if k is the
+ * parent of i in the tree. The Parent array is required by ldl_numeric.
+ * Lnz [k] gives the number of nonzeros in the kth column of L, excluding the
+ * diagonal.
+ *
+ * One workspace vector (Flag) of size n is required.
+ *
+ * If P is NULL, then it is ignored. The factorization will be LDL' = A.
+ * Pinv is not computed. In this case, neither P nor Pinv are required by
+ * ldl_numeric.
+ *
+ * If P is not NULL, then it is assumed to be a valid permutation. If
+ * row and column j of A is the kth pivot, the P [k] = j. The factorization
+ * will be LDL' = PAP', or A (p,p) in MATLAB notation. The inverse permutation
+ * Pinv is computed, where Pinv [j] = k if P [k] = j. In this case, both P
+ * and Pinv are required as inputs to ldl_numeric.
+ *
+ * The floating-point operation count of the subsequent call to ldl_numeric
+ * is not returned, but could be computed after ldl_symbolic is done. It is
+ * the sum of (Lnz [k]) * (Lnz [k] + 2) for k = 0 to n-1.
+ */
+
+void LDL_symbolic
+(
+ LDL_int n, /* A and L are n-by-n, where n >= 0 */
+ LDL_int Ap [ ], /* input of size n+1, not modified */
+ LDL_int Ai [ ], /* input of size nz=Ap[n], not modified */
+ LDL_int Lp [ ], /* output of size n+1, not defined on input */
+ LDL_int Parent [ ], /* output of size n, not defined on input */
+ LDL_int Lnz [ ], /* output of size n, not defined on input */
+ LDL_int Flag [ ], /* workspace of size n, not defn. on input or output */
+ LDL_int P [ ], /* optional input of size n */
+ LDL_int Pinv [ ] /* optional output of size n (used if P is not NULL) */
+)
+{
+ LDL_int i, k, p, kk, p2 ;
+ if (P)
+ {
+ /* If P is present then compute Pinv, the inverse of P */
+ for (k = 0 ; k < n ; k++)
+ {
+ Pinv [P [k]] = k ;
+ }
+ }
+ for (k = 0 ; k < n ; k++)
+ {
+ /* L(k,:) pattern: all nodes reachable in etree from nz in A(0:k-1,k) */
+ Parent [k] = -1 ; /* parent of k is not yet known */
+ Flag [k] = k ; /* mark node k as visited */
+ Lnz [k] = 0 ; /* count of nonzeros in column k of L */
+ kk = (P) ? (P [k]) : (k) ; /* kth original, or permuted, column */
+ p2 = Ap [kk+1] ;
+ for (p = Ap [kk] ; p < p2 ; p++)
+ {
+ /* A (i,k) is nonzero (original or permuted A) */
+ i = (Pinv) ? (Pinv [Ai [p]]) : (Ai [p]) ;
+ if (i < k)
+ {
+ /* follow path from i to root of etree, stop at flagged node */
+ for ( ; Flag [i] != k ; i = Parent [i])
+ {
+ /* find parent of i if not yet determined */
+ if (Parent [i] == -1) Parent [i] = k ;
+ Lnz [i]++ ; /* L (k,i) is nonzero */
+ Flag [i] = k ; /* mark i as visited */
+ }
+ }
+ }
+ }
+ /* construct Lp index array from Lnz column counts */
+ Lp [0] = 0 ;
+ for (k = 0 ; k < n ; k++)
+ {
+ Lp [k+1] = Lp [k] + Lnz [k] ;
+ }
+}
+
+
+/* ========================================================================== */
+/* === ldl_numeric ========================================================== */
+/* ========================================================================== */
+
+/* Given a sparse matrix A (the arguments n, Ap, Ai, and Ax) and its symbolic
+ * analysis (Lp and Parent, and optionally P and Pinv), compute the numeric LDL'
+ * factorization of A or PAP'. The outputs of this routine are arguments Li,
+ * Lx, and D. It also requires three size-n workspaces (Y, Pattern, and Flag).
+ */
+
+LDL_int LDL_numeric /* returns n if successful, k if D (k,k) is zero */
+(
+ LDL_int n, /* A and L are n-by-n, where n >= 0 */
+ LDL_int Ap [ ], /* input of size n+1, not modified */
+ LDL_int Ai [ ], /* input of size nz=Ap[n], not modified */
+ double Ax [ ], /* input of size nz=Ap[n], not modified */
+ LDL_int Lp [ ], /* input of size n+1, not modified */
+ LDL_int Parent [ ], /* input of size n, not modified */
+ LDL_int Lnz [ ], /* output of size n, not defn. on input */
+ LDL_int Li [ ], /* output of size lnz=Lp[n], not defined on input */
+ double Lx [ ], /* output of size lnz=Lp[n], not defined on input */
+ double D [ ], /* output of size n, not defined on input */
+ double Y [ ], /* workspace of size n, not defn. on input or output */
+ LDL_int Pattern [ ],/* workspace of size n, not defn. on input or output */
+ LDL_int Flag [ ], /* workspace of size n, not defn. on input or output */
+ LDL_int P [ ], /* optional input of size n */
+ LDL_int Pinv [ ] /* optional input of size n */
+)
+{
+ double yi, l_ki ;
+ LDL_int i, k, p, kk, p2, len, top ;
+ for (k = 0 ; k < n ; k++)
+ {
+ /* compute nonzero Pattern of kth row of L, in topological order */
+ Y [k] = 0.0 ; /* Y(0:k) is now all zero */
+ top = n ; /* stack for pattern is empty */
+ Flag [k] = k ; /* mark node k as visited */
+ Lnz [k] = 0 ; /* count of nonzeros in column k of L */
+ kk = (P) ? (P [k]) : (k) ; /* kth original, or permuted, column */
+ p2 = Ap [kk+1] ;
+ for (p = Ap [kk] ; p < p2 ; p++)
+ {
+ i = (Pinv) ? (Pinv [Ai [p]]) : (Ai [p]) ; /* get A(i,k) */
+ if (i <= k)
+ {
+ Y [i] += Ax [p] ; /* scatter A(i,k) into Y (sum duplicates) */
+ for (len = 0 ; Flag [i] != k ; i = Parent [i])
+ {
+ Pattern [len++] = i ; /* L(k,i) is nonzero */
+ Flag [i] = k ; /* mark i as visited */
+ }
+ while (len > 0) Pattern [--top] = Pattern [--len] ;
+ }
+ }
+ /* compute numerical values kth row of L (a sparse triangular solve) */
+ D [k] = Y [k] ; /* get D(k,k) and clear Y(k) */
+ Y [k] = 0.0 ;
+ for ( ; top < n ; top++)
+ {
+ i = Pattern [top] ; /* Pattern [top:n-1] is pattern of L(:,k) */
+ yi = Y [i] ; /* get and clear Y(i) */
+ Y [i] = 0.0 ;
+ p2 = Lp [i] + Lnz [i] ;
+ for (p = Lp [i] ; p < p2 ; p++)
+ {
+ Y [Li [p]] -= Lx [p] * yi ;
+ }
+ l_ki = yi / D [i] ; /* the nonzero entry L(k,i) */
+ D [k] -= l_ki * yi ;
+ Li [p] = k ; /* store L(k,i) in column form of L */
+ Lx [p] = l_ki ;
+ Lnz [i]++ ; /* increment count of nonzeros in col i */
+ }
+ if (D [k] == 0.0) return (k) ; /* failure, D(k,k) is zero */
+ }
+ return (n) ; /* success, diagonal of D is all nonzero */
+}
+
+
+/* ========================================================================== */
+/* === ldl_lsolve: solve Lx=b ============================================== */
+/* ========================================================================== */
+
+void LDL_lsolve
+(
+ LDL_int n, /* L is n-by-n, where n >= 0 */
+ double X [ ], /* size n. right-hand-side on input, soln. on output */
+ LDL_int Lp [ ], /* input of size n+1, not modified */
+ LDL_int Li [ ], /* input of size lnz=Lp[n], not modified */
+ double Lx [ ] /* input of size lnz=Lp[n], not modified */
+)
+{
+ LDL_int j, p, p2 ;
+ for (j = 0 ; j < n ; j++)
+ {
+ p2 = Lp [j+1] ;
+ for (p = Lp [j] ; p < p2 ; p++)
+ {
+ X [Li [p]] -= Lx [p] * X [j] ;
+ }
+ }
+}
+
+
+/* ========================================================================== */
+/* === ldl_dsolve: solve Dx=b ============================================== */
+/* ========================================================================== */
+
+void LDL_dsolve
+(
+ LDL_int n, /* D is n-by-n, where n >= 0 */
+ double X [ ], /* size n. right-hand-side on input, soln. on output */
+ double D [ ] /* input of size n, not modified */
+)
+{
+ LDL_int j ;
+ for (j = 0 ; j < n ; j++)
+ {
+ X [j] /= D [j] ;
+ }
+}
+
+
+/* ========================================================================== */
+/* === ldl_ltsolve: solve L'x=b ============================================ */
+/* ========================================================================== */
+
+void LDL_ltsolve
+(
+ LDL_int n, /* L is n-by-n, where n >= 0 */
+ double X [ ], /* size n. right-hand-side on input, soln. on output */
+ LDL_int Lp [ ], /* input of size n+1, not modified */
+ LDL_int Li [ ], /* input of size lnz=Lp[n], not modified */
+ double Lx [ ] /* input of size lnz=Lp[n], not modified */
+)
+{
+ int j, p, p2 ;
+ for (j = n-1 ; j >= 0 ; j--)
+ {
+ p2 = Lp [j+1] ;
+ for (p = Lp [j] ; p < p2 ; p++)
+ {
+ X [j] -= Lx [p] * X [Li [p]] ;
+ }
+ }
+}
+
+
+/* ========================================================================== */
+/* === ldl_perm: permute a vector, x=Pb ===================================== */
+/* ========================================================================== */
+
+void LDL_perm
+(
+ LDL_int n, /* size of X, B, and P */
+ double X [ ], /* output of size n. */
+ double B [ ], /* input of size n. */
+ LDL_int P [ ] /* input permutation array of size n. */
+)
+{
+ LDL_int j ;
+ for (j = 0 ; j < n ; j++)
+ {
+ X [j] = B [P [j]] ;
+ }
+}
+
+
+/* ========================================================================== */
+/* === ldl_permt: permute a vector, x=P'b =================================== */
+/* ========================================================================== */
+
+void LDL_permt
+(
+ LDL_int n, /* size of X, B, and P */
+ double X [ ], /* output of size n. */
+ double B [ ], /* input of size n. */
+ LDL_int P [ ] /* input permutation array of size n. */
+)
+{
+ LDL_int j ;
+ for (j = 0 ; j < n ; j++)
+ {
+ X [P [j]] = B [j] ;
+ }
+}
+
+
+/* ========================================================================== */
+/* === ldl_valid_perm: check if a permutation vector is valid =============== */
+/* ========================================================================== */
+
+LDL_int LDL_valid_perm /* returns 1 if valid, 0 otherwise */
+(
+ LDL_int n,
+ LDL_int P [ ], /* input of size n, a permutation of 0:n-1 */
+ LDL_int Flag [ ] /* workspace of size n */
+)
+{
+ LDL_int j, k ;
+ if (n < 0 || !Flag)
+ {
+ return (0) ; /* n must be >= 0, and Flag must be present */
+ }
+ if (!P)
+ {
+ return (1) ; /* If NULL, P is assumed to be the identity perm. */
+ }
+ for (j = 0 ; j < n ; j++)
+ {
+ Flag [j] = 0 ; /* clear the Flag array */
+ }
+ for (k = 0 ; k < n ; k++)
+ {
+ j = P [k] ;
+ if (j < 0 || j >= n || Flag [j] != 0)
+ {
+ return (0) ; /* P is not valid */
+ }
+ Flag [j] = 1 ;
+ }
+ return (1) ; /* P is valid */
+}
+
+
+/* ========================================================================== */
+/* === ldl_valid_matrix: check if a sparse matrix is valid ================== */
+/* ========================================================================== */
+
+/* This routine checks to see if a sparse matrix A is valid for input to
+ * ldl_symbolic and ldl_numeric. It returns 1 if the matrix is valid, 0
+ * otherwise. A is in sparse column form. The numerical values in column j
+ * are stored in Ax [Ap [j] ... Ap [j+1]-1], with row indices in
+ * Ai [Ap [j] ... Ap [j+1]-1]. The Ax array is not checked.
+ */
+
+LDL_int LDL_valid_matrix
+(
+ LDL_int n,
+ LDL_int Ap [ ],
+ LDL_int Ai [ ]
+)
+{
+ LDL_int j, p ;
+ if (n < 0 || !Ap || !Ai || Ap [0] != 0)
+ {
+ return (0) ; /* n must be >= 0, and Ap and Ai must be present */
+ }
+ for (j = 0 ; j < n ; j++)
+ {
+ if (Ap [j] > Ap [j+1])
+ {
+ return (0) ; /* Ap must be monotonically nondecreasing */
+ }
+ }
+ for (p = 0 ; p < Ap [n] ; p++)
+ {
+ if (Ai [p] < 0 || Ai [p] >= n)
+ {
+ return (0) ; /* row indices must be in the range 0 to n-1 */
+ }
+ }
+ return (1) ; /* matrix is valid */
+}
diff --git a/extern/libmv/third_party/msinttypes/README.libmv b/extern/libmv/third_party/msinttypes/README.libmv
new file mode 100644
index 00000000000..423f599b4ad
--- /dev/null
+++ b/extern/libmv/third_party/msinttypes/README.libmv
@@ -0,0 +1,5 @@
+Project: msinttypes
+URL: http://code.google.com/p/msinttypes/
+License: New BSD License
+Upstream version: r24
+Local modifications: None.
diff --git a/extern/libmv/third_party/msinttypes/inttypes.h b/extern/libmv/third_party/msinttypes/inttypes.h
new file mode 100644
index 00000000000..0e8af69cb07
--- /dev/null
+++ b/extern/libmv/third_party/msinttypes/inttypes.h
@@ -0,0 +1,305 @@
+// ISO C9x compliant inttypes.h for Microsoft Visual Studio
+// Based on ISO/IEC 9899:TC2 Committee draft (May 6, 2005) WG14/N1124
+//
+// Copyright (c) 2006 Alexander Chemeris
+//
+// 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. The name of the author may be used to endorse or promote products
+// derived from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.
+//
+///////////////////////////////////////////////////////////////////////////////
+
+#ifndef _MSC_VER // [
+#error "Use this header only with Microsoft Visual C++ compilers!"
+#endif // _MSC_VER ]
+
+#ifndef _MSC_INTTYPES_H_ // [
+#define _MSC_INTTYPES_H_
+
+#if _MSC_VER > 1000
+#pragma once
+#endif
+
+#include <stdint.h>
+
+// 7.8 Format conversion of integer types
+
+typedef struct {
+ intmax_t quot;
+ intmax_t rem;
+} imaxdiv_t;
+
+// 7.8.1 Macros for format specifiers
+
+#if !defined(__cplusplus) || defined(__STDC_FORMAT_MACROS) // [ See footnote 185 at page 198
+
+// The fprintf macros for signed integers are:
+#define PRId8 "d"
+#define PRIi8 "i"
+#define PRIdLEAST8 "d"
+#define PRIiLEAST8 "i"
+#define PRIdFAST8 "d"
+#define PRIiFAST8 "i"
+
+#define PRId16 "hd"
+#define PRIi16 "hi"
+#define PRIdLEAST16 "hd"
+#define PRIiLEAST16 "hi"
+#define PRIdFAST16 "hd"
+#define PRIiFAST16 "hi"
+
+#define PRId32 "I32d"
+#define PRIi32 "I32i"
+#define PRIdLEAST32 "I32d"
+#define PRIiLEAST32 "I32i"
+#define PRIdFAST32 "I32d"
+#define PRIiFAST32 "I32i"
+
+#define PRId64 "I64d"
+#define PRIi64 "I64i"
+#define PRIdLEAST64 "I64d"
+#define PRIiLEAST64 "I64i"
+#define PRIdFAST64 "I64d"
+#define PRIiFAST64 "I64i"
+
+#define PRIdMAX "I64d"
+#define PRIiMAX "I64i"
+
+#define PRIdPTR "Id"
+#define PRIiPTR "Ii"
+
+// The fprintf macros for unsigned integers are:
+#define PRIo8 "o"
+#define PRIu8 "u"
+#define PRIx8 "x"
+#define PRIX8 "X"
+#define PRIoLEAST8 "o"
+#define PRIuLEAST8 "u"
+#define PRIxLEAST8 "x"
+#define PRIXLEAST8 "X"
+#define PRIoFAST8 "o"
+#define PRIuFAST8 "u"
+#define PRIxFAST8 "x"
+#define PRIXFAST8 "X"
+
+#define PRIo16 "ho"
+#define PRIu16 "hu"
+#define PRIx16 "hx"
+#define PRIX16 "hX"
+#define PRIoLEAST16 "ho"
+#define PRIuLEAST16 "hu"
+#define PRIxLEAST16 "hx"
+#define PRIXLEAST16 "hX"
+#define PRIoFAST16 "ho"
+#define PRIuFAST16 "hu"
+#define PRIxFAST16 "hx"
+#define PRIXFAST16 "hX"
+
+#define PRIo32 "I32o"
+#define PRIu32 "I32u"
+#define PRIx32 "I32x"
+#define PRIX32 "I32X"
+#define PRIoLEAST32 "I32o"
+#define PRIuLEAST32 "I32u"
+#define PRIxLEAST32 "I32x"
+#define PRIXLEAST32 "I32X"
+#define PRIoFAST32 "I32o"
+#define PRIuFAST32 "I32u"
+#define PRIxFAST32 "I32x"
+#define PRIXFAST32 "I32X"
+
+#define PRIo64 "I64o"
+#define PRIu64 "I64u"
+#define PRIx64 "I64x"
+#define PRIX64 "I64X"
+#define PRIoLEAST64 "I64o"
+#define PRIuLEAST64 "I64u"
+#define PRIxLEAST64 "I64x"
+#define PRIXLEAST64 "I64X"
+#define PRIoFAST64 "I64o"
+#define PRIuFAST64 "I64u"
+#define PRIxFAST64 "I64x"
+#define PRIXFAST64 "I64X"
+
+#define PRIoMAX "I64o"
+#define PRIuMAX "I64u"
+#define PRIxMAX "I64x"
+#define PRIXMAX "I64X"
+
+#define PRIoPTR "Io"
+#define PRIuPTR "Iu"
+#define PRIxPTR "Ix"
+#define PRIXPTR "IX"
+
+// The fscanf macros for signed integers are:
+#define SCNd8 "d"
+#define SCNi8 "i"
+#define SCNdLEAST8 "d"
+#define SCNiLEAST8 "i"
+#define SCNdFAST8 "d"
+#define SCNiFAST8 "i"
+
+#define SCNd16 "hd"
+#define SCNi16 "hi"
+#define SCNdLEAST16 "hd"
+#define SCNiLEAST16 "hi"
+#define SCNdFAST16 "hd"
+#define SCNiFAST16 "hi"
+
+#define SCNd32 "ld"
+#define SCNi32 "li"
+#define SCNdLEAST32 "ld"
+#define SCNiLEAST32 "li"
+#define SCNdFAST32 "ld"
+#define SCNiFAST32 "li"
+
+#define SCNd64 "I64d"
+#define SCNi64 "I64i"
+#define SCNdLEAST64 "I64d"
+#define SCNiLEAST64 "I64i"
+#define SCNdFAST64 "I64d"
+#define SCNiFAST64 "I64i"
+
+#define SCNdMAX "I64d"
+#define SCNiMAX "I64i"
+
+#ifdef _WIN64 // [
+# define SCNdPTR "I64d"
+# define SCNiPTR "I64i"
+#else // _WIN64 ][
+# define SCNdPTR "ld"
+# define SCNiPTR "li"
+#endif // _WIN64 ]
+
+// The fscanf macros for unsigned integers are:
+#define SCNo8 "o"
+#define SCNu8 "u"
+#define SCNx8 "x"
+#define SCNX8 "X"
+#define SCNoLEAST8 "o"
+#define SCNuLEAST8 "u"
+#define SCNxLEAST8 "x"
+#define SCNXLEAST8 "X"
+#define SCNoFAST8 "o"
+#define SCNuFAST8 "u"
+#define SCNxFAST8 "x"
+#define SCNXFAST8 "X"
+
+#define SCNo16 "ho"
+#define SCNu16 "hu"
+#define SCNx16 "hx"
+#define SCNX16 "hX"
+#define SCNoLEAST16 "ho"
+#define SCNuLEAST16 "hu"
+#define SCNxLEAST16 "hx"
+#define SCNXLEAST16 "hX"
+#define SCNoFAST16 "ho"
+#define SCNuFAST16 "hu"
+#define SCNxFAST16 "hx"
+#define SCNXFAST16 "hX"
+
+#define SCNo32 "lo"
+#define SCNu32 "lu"
+#define SCNx32 "lx"
+#define SCNX32 "lX"
+#define SCNoLEAST32 "lo"
+#define SCNuLEAST32 "lu"
+#define SCNxLEAST32 "lx"
+#define SCNXLEAST32 "lX"
+#define SCNoFAST32 "lo"
+#define SCNuFAST32 "lu"
+#define SCNxFAST32 "lx"
+#define SCNXFAST32 "lX"
+
+#define SCNo64 "I64o"
+#define SCNu64 "I64u"
+#define SCNx64 "I64x"
+#define SCNX64 "I64X"
+#define SCNoLEAST64 "I64o"
+#define SCNuLEAST64 "I64u"
+#define SCNxLEAST64 "I64x"
+#define SCNXLEAST64 "I64X"
+#define SCNoFAST64 "I64o"
+#define SCNuFAST64 "I64u"
+#define SCNxFAST64 "I64x"
+#define SCNXFAST64 "I64X"
+
+#define SCNoMAX "I64o"
+#define SCNuMAX "I64u"
+#define SCNxMAX "I64x"
+#define SCNXMAX "I64X"
+
+#ifdef _WIN64 // [
+# define SCNoPTR "I64o"
+# define SCNuPTR "I64u"
+# define SCNxPTR "I64x"
+# define SCNXPTR "I64X"
+#else // _WIN64 ][
+# define SCNoPTR "lo"
+# define SCNuPTR "lu"
+# define SCNxPTR "lx"
+# define SCNXPTR "lX"
+#endif // _WIN64 ]
+
+#endif // __STDC_FORMAT_MACROS ]
+
+// 7.8.2 Functions for greatest-width integer types
+
+// 7.8.2.1 The imaxabs function
+#define imaxabs _abs64
+
+// 7.8.2.2 The imaxdiv function
+
+// This is modified version of div() function from Microsoft's div.c found
+// in %MSVC.NET%\crt\src\div.c
+#ifdef STATIC_IMAXDIV // [
+static
+#else // STATIC_IMAXDIV ][
+_inline
+#endif // STATIC_IMAXDIV ]
+imaxdiv_t __cdecl imaxdiv(intmax_t numer, intmax_t denom)
+{
+ imaxdiv_t result;
+
+ result.quot = numer / denom;
+ result.rem = numer % denom;
+
+ if (numer < 0 && result.rem > 0) {
+ // did division wrong; must fix up
+ ++result.quot;
+ result.rem -= denom;
+ }
+
+ return result;
+}
+
+// 7.8.2.3 The strtoimax and strtoumax functions
+#define strtoimax _strtoi64
+#define strtoumax _strtoui64
+
+// 7.8.2.4 The wcstoimax and wcstoumax functions
+#define wcstoimax _wcstoi64
+#define wcstoumax _wcstoui64
+
+
+#endif // _MSC_INTTYPES_H_ ]
diff --git a/extern/libmv/third_party/msinttypes/stdint.h b/extern/libmv/third_party/msinttypes/stdint.h
new file mode 100644
index 00000000000..e236bb00015
--- /dev/null
+++ b/extern/libmv/third_party/msinttypes/stdint.h
@@ -0,0 +1,247 @@
+// ISO C9x compliant stdint.h for Microsoft Visual Studio
+// Based on ISO/IEC 9899:TC2 Committee draft (May 6, 2005) WG14/N1124
+//
+// Copyright (c) 2006-2008 Alexander Chemeris
+//
+// 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. The name of the author may be used to endorse or promote products
+// derived from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.
+//
+///////////////////////////////////////////////////////////////////////////////
+
+#ifndef _MSC_VER // [
+#error "Use this header only with Microsoft Visual C++ compilers!"
+#endif // _MSC_VER ]
+
+#ifndef _MSC_STDINT_H_ // [
+#define _MSC_STDINT_H_
+
+#if _MSC_VER > 1000
+#pragma once
+#endif
+
+#include <limits.h>
+
+// For Visual Studio 6 in C++ mode and for many Visual Studio versions when
+// compiling for ARM we should wrap <wchar.h> include with 'extern "C++" {}'
+// or compiler give many errors like this:
+// error C2733: second C linkage of overloaded function 'wmemchr' not allowed
+#ifdef __cplusplus
+extern "C" {
+#endif
+# include <wchar.h>
+#ifdef __cplusplus
+}
+#endif
+
+// Define _W64 macros to mark types changing their size, like intptr_t.
+#ifndef _W64
+# if !defined(__midl) && (defined(_X86_) || defined(_M_IX86)) && _MSC_VER >= 1300
+# define _W64 __w64
+# else
+# define _W64
+# endif
+#endif
+
+
+// 7.18.1 Integer types
+
+// 7.18.1.1 Exact-width integer types
+
+// Visual Studio 6 and Embedded Visual C++ 4 doesn't
+// realize that, e.g. char has the same size as __int8
+// so we give up on __intX for them.
+#if (_MSC_VER < 1300)
+ typedef char int8_t;
+ typedef short int16_t;
+ typedef int int32_t;
+ typedef unsigned char uint8_t;
+ typedef unsigned short uint16_t;
+ typedef unsigned int uint32_t;
+#else
+ typedef __int8 int8_t;
+ typedef __int16 int16_t;
+ typedef __int32 int32_t;
+ typedef unsigned __int8 uint8_t;
+ typedef unsigned __int16 uint16_t;
+ typedef unsigned __int32 uint32_t;
+#endif
+typedef __int64 int64_t;
+typedef unsigned __int64 uint64_t;
+
+
+// 7.18.1.2 Minimum-width integer types
+typedef int8_t int_least8_t;
+typedef int16_t int_least16_t;
+typedef int32_t int_least32_t;
+typedef int64_t int_least64_t;
+typedef uint8_t uint_least8_t;
+typedef uint16_t uint_least16_t;
+typedef uint32_t uint_least32_t;
+typedef uint64_t uint_least64_t;
+
+// 7.18.1.3 Fastest minimum-width integer types
+typedef int8_t int_fast8_t;
+typedef int16_t int_fast16_t;
+typedef int32_t int_fast32_t;
+typedef int64_t int_fast64_t;
+typedef uint8_t uint_fast8_t;
+typedef uint16_t uint_fast16_t;
+typedef uint32_t uint_fast32_t;
+typedef uint64_t uint_fast64_t;
+
+// 7.18.1.4 Integer types capable of holding object pointers
+#ifdef _WIN64 // [
+ typedef __int64 intptr_t;
+ typedef unsigned __int64 uintptr_t;
+#else // _WIN64 ][
+ typedef _W64 int intptr_t;
+ typedef _W64 unsigned int uintptr_t;
+#endif // _WIN64 ]
+
+// 7.18.1.5 Greatest-width integer types
+typedef int64_t intmax_t;
+typedef uint64_t uintmax_t;
+
+
+// 7.18.2 Limits of specified-width integer types
+
+#if !defined(__cplusplus) || defined(__STDC_LIMIT_MACROS) // [ See footnote 220 at page 257 and footnote 221 at page 259
+
+// 7.18.2.1 Limits of exact-width integer types
+#define INT8_MIN ((int8_t)_I8_MIN)
+#define INT8_MAX _I8_MAX
+#define INT16_MIN ((int16_t)_I16_MIN)
+#define INT16_MAX _I16_MAX
+#define INT32_MIN ((int32_t)_I32_MIN)
+#define INT32_MAX _I32_MAX
+#define INT64_MIN ((int64_t)_I64_MIN)
+#define INT64_MAX _I64_MAX
+#define UINT8_MAX _UI8_MAX
+#define UINT16_MAX _UI16_MAX
+#define UINT32_MAX _UI32_MAX
+#define UINT64_MAX _UI64_MAX
+
+// 7.18.2.2 Limits of minimum-width integer types
+#define INT_LEAST8_MIN INT8_MIN
+#define INT_LEAST8_MAX INT8_MAX
+#define INT_LEAST16_MIN INT16_MIN
+#define INT_LEAST16_MAX INT16_MAX
+#define INT_LEAST32_MIN INT32_MIN
+#define INT_LEAST32_MAX INT32_MAX
+#define INT_LEAST64_MIN INT64_MIN
+#define INT_LEAST64_MAX INT64_MAX
+#define UINT_LEAST8_MAX UINT8_MAX
+#define UINT_LEAST16_MAX UINT16_MAX
+#define UINT_LEAST32_MAX UINT32_MAX
+#define UINT_LEAST64_MAX UINT64_MAX
+
+// 7.18.2.3 Limits of fastest minimum-width integer types
+#define INT_FAST8_MIN INT8_MIN
+#define INT_FAST8_MAX INT8_MAX
+#define INT_FAST16_MIN INT16_MIN
+#define INT_FAST16_MAX INT16_MAX
+#define INT_FAST32_MIN INT32_MIN
+#define INT_FAST32_MAX INT32_MAX
+#define INT_FAST64_MIN INT64_MIN
+#define INT_FAST64_MAX INT64_MAX
+#define UINT_FAST8_MAX UINT8_MAX
+#define UINT_FAST16_MAX UINT16_MAX
+#define UINT_FAST32_MAX UINT32_MAX
+#define UINT_FAST64_MAX UINT64_MAX
+
+// 7.18.2.4 Limits of integer types capable of holding object pointers
+#ifdef _WIN64 // [
+# define INTPTR_MIN INT64_MIN
+# define INTPTR_MAX INT64_MAX
+# define UINTPTR_MAX UINT64_MAX
+#else // _WIN64 ][
+# define INTPTR_MIN INT32_MIN
+# define INTPTR_MAX INT32_MAX
+# define UINTPTR_MAX UINT32_MAX
+#endif // _WIN64 ]
+
+// 7.18.2.5 Limits of greatest-width integer types
+#define INTMAX_MIN INT64_MIN
+#define INTMAX_MAX INT64_MAX
+#define UINTMAX_MAX UINT64_MAX
+
+// 7.18.3 Limits of other integer types
+
+#ifdef _WIN64 // [
+# define PTRDIFF_MIN _I64_MIN
+# define PTRDIFF_MAX _I64_MAX
+#else // _WIN64 ][
+# define PTRDIFF_MIN _I32_MIN
+# define PTRDIFF_MAX _I32_MAX
+#endif // _WIN64 ]
+
+#define SIG_ATOMIC_MIN INT_MIN
+#define SIG_ATOMIC_MAX INT_MAX
+
+#ifndef SIZE_MAX // [
+# ifdef _WIN64 // [
+# define SIZE_MAX _UI64_MAX
+# else // _WIN64 ][
+# define SIZE_MAX _UI32_MAX
+# endif // _WIN64 ]
+#endif // SIZE_MAX ]
+
+// WCHAR_MIN and WCHAR_MAX are also defined in <wchar.h>
+#ifndef WCHAR_MIN // [
+# define WCHAR_MIN 0
+#endif // WCHAR_MIN ]
+#ifndef WCHAR_MAX // [
+# define WCHAR_MAX _UI16_MAX
+#endif // WCHAR_MAX ]
+
+#define WINT_MIN 0
+#define WINT_MAX _UI16_MAX
+
+#endif // __STDC_LIMIT_MACROS ]
+
+
+// 7.18.4 Limits of other integer types
+
+#if !defined(__cplusplus) || defined(__STDC_CONSTANT_MACROS) // [ See footnote 224 at page 260
+
+// 7.18.4.1 Macros for minimum-width integer constants
+
+#define INT8_C(val) val##i8
+#define INT16_C(val) val##i16
+#define INT32_C(val) val##i32
+#define INT64_C(val) val##i64
+
+#define UINT8_C(val) val##ui8
+#define UINT16_C(val) val##ui16
+#define UINT32_C(val) val##ui32
+#define UINT64_C(val) val##ui64
+
+// 7.18.4.2 Macros for greatest-width integer constants
+#define INTMAX_C INT64_C
+#define UINTMAX_C UINT64_C
+
+#endif // __STDC_CONSTANT_MACROS ]
+
+
+#endif // _MSC_STDINT_H_ ]
diff --git a/extern/libmv/third_party/ssba/COPYING.TXT b/extern/libmv/third_party/ssba/COPYING.TXT
new file mode 100644
index 00000000000..fc8a5de7edf
--- /dev/null
+++ b/extern/libmv/third_party/ssba/COPYING.TXT
@@ -0,0 +1,165 @@
+ GNU LESSER GENERAL PUBLIC LICENSE
+ Version 3, 29 June 2007
+
+ Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+
+ This version of the GNU Lesser General Public License incorporates
+the terms and conditions of version 3 of the GNU General Public
+License, supplemented by the additional permissions listed below.
+
+ 0. Additional Definitions.
+
+ As used herein, "this License" refers to version 3 of the GNU Lesser
+General Public License, and the "GNU GPL" refers to version 3 of the GNU
+General Public License.
+
+ "The Library" refers to a covered work governed by this License,
+other than an Application or a Combined Work as defined below.
+
+ An "Application" is any work that makes use of an interface provided
+by the Library, but which is not otherwise based on the Library.
+Defining a subclass of a class defined by the Library is deemed a mode
+of using an interface provided by the Library.
+
+ A "Combined Work" is a work produced by combining or linking an
+Application with the Library. The particular version of the Library
+with which the Combined Work was made is also called the "Linked
+Version".
+
+ The "Minimal Corresponding Source" for a Combined Work means the
+Corresponding Source for the Combined Work, excluding any source code
+for portions of the Combined Work that, considered in isolation, are
+based on the Application, and not on the Linked Version.
+
+ The "Corresponding Application Code" for a Combined Work means the
+object code and/or source code for the Application, including any data
+and utility programs needed for reproducing the Combined Work from the
+Application, but excluding the System Libraries of the Combined Work.
+
+ 1. Exception to Section 3 of the GNU GPL.
+
+ You may convey a covered work under sections 3 and 4 of this License
+without being bound by section 3 of the GNU GPL.
+
+ 2. Conveying Modified Versions.
+
+ If you modify a copy of the Library, and, in your modifications, a
+facility refers to a function or data to be supplied by an Application
+that uses the facility (other than as an argument passed when the
+facility is invoked), then you may convey a copy of the modified
+version:
+
+ a) under this License, provided that you make a good faith effort to
+ ensure that, in the event an Application does not supply the
+ function or data, the facility still operates, and performs
+ whatever part of its purpose remains meaningful, or
+
+ b) under the GNU GPL, with none of the additional permissions of
+ this License applicable to that copy.
+
+ 3. Object Code Incorporating Material from Library Header Files.
+
+ The object code form of an Application may incorporate material from
+a header file that is part of the Library. You may convey such object
+code under terms of your choice, provided that, if the incorporated
+material is not limited to numerical parameters, data structure
+layouts and accessors, or small macros, inline functions and templates
+(ten or fewer lines in length), you do both of the following:
+
+ a) Give prominent notice with each copy of the object code that the
+ Library is used in it and that the Library and its use are
+ covered by this License.
+
+ b) Accompany the object code with a copy of the GNU GPL and this license
+ document.
+
+ 4. Combined Works.
+
+ You may convey a Combined Work under terms of your choice that,
+taken together, effectively do not restrict modification of the
+portions of the Library contained in the Combined Work and reverse
+engineering for debugging such modifications, if you also do each of
+the following:
+
+ a) Give prominent notice with each copy of the Combined Work that
+ the Library is used in it and that the Library and its use are
+ covered by this License.
+
+ b) Accompany the Combined Work with a copy of the GNU GPL and this license
+ document.
+
+ c) For a Combined Work that displays copyright notices during
+ execution, include the copyright notice for the Library among
+ these notices, as well as a reference directing the user to the
+ copies of the GNU GPL and this license document.
+
+ d) Do one of the following:
+
+ 0) Convey the Minimal Corresponding Source under the terms of this
+ License, and the Corresponding Application Code in a form
+ suitable for, and under terms that permit, the user to
+ recombine or relink the Application with a modified version of
+ the Linked Version to produce a modified Combined Work, in the
+ manner specified by section 6 of the GNU GPL for conveying
+ Corresponding Source.
+
+ 1) Use a suitable shared library mechanism for linking with the
+ Library. A suitable mechanism is one that (a) uses at run time
+ a copy of the Library already present on the user's computer
+ system, and (b) will operate properly with a modified version
+ of the Library that is interface-compatible with the Linked
+ Version.
+
+ e) Provide Installation Information, but only if you would otherwise
+ be required to provide such information under section 6 of the
+ GNU GPL, and only to the extent that such information is
+ necessary to install and execute a modified version of the
+ Combined Work produced by recombining or relinking the
+ Application with a modified version of the Linked Version. (If
+ you use option 4d0, the Installation Information must accompany
+ the Minimal Corresponding Source and Corresponding Application
+ Code. If you use option 4d1, you must provide the Installation
+ Information in the manner specified by section 6 of the GNU GPL
+ for conveying Corresponding Source.)
+
+ 5. Combined Libraries.
+
+ You may place library facilities that are a work based on the
+Library side by side in a single library together with other library
+facilities that are not Applications and are not covered by this
+License, and convey such a combined library under terms of your
+choice, if you do both of the following:
+
+ a) Accompany the combined library with a copy of the same work based
+ on the Library, uncombined with any other library facilities,
+ conveyed under the terms of this License.
+
+ b) Give prominent notice with the combined library that part of it
+ is a work based on the Library, and explaining where to find the
+ accompanying uncombined form of the same work.
+
+ 6. Revised Versions of the GNU Lesser General Public License.
+
+ The Free Software Foundation may publish revised and/or new versions
+of the GNU Lesser General Public License from time to time. Such new
+versions will be similar in spirit to the present version, but may
+differ in detail to address new problems or concerns.
+
+ Each version is given a distinguishing version number. If the
+Library as you received it specifies that a certain numbered version
+of the GNU Lesser General Public License "or any later version"
+applies to it, you have the option of following the terms and
+conditions either of that published version or of any later version
+published by the Free Software Foundation. If the Library as you
+received it does not specify a version number of the GNU Lesser
+General Public License, you may choose any version of the GNU Lesser
+General Public License ever published by the Free Software Foundation.
+
+ If the Library as you received it specifies that a proxy can decide
+whether future versions of the GNU Lesser General Public License shall
+apply, that proxy's public statement of acceptance of any version is
+permanent authorization for you to choose that version for the
+Library.
diff --git a/extern/libmv/third_party/ssba/Geometry/v3d_cameramatrix.h b/extern/libmv/third_party/ssba/Geometry/v3d_cameramatrix.h
new file mode 100644
index 00000000000..448ae9714e5
--- /dev/null
+++ b/extern/libmv/third_party/ssba/Geometry/v3d_cameramatrix.h
@@ -0,0 +1,204 @@
+// -*- C++ -*-
+/*
+Copyright (c) 2008 University of North Carolina at Chapel Hill
+
+This file is part of SSBA (Simple Sparse Bundle Adjustment).
+
+SSBA is free software: you can redistribute it and/or modify it under the
+terms of the GNU Lesser General Public License as published by the Free
+Software Foundation, either version 3 of the License, or (at your option) any
+later version.
+
+SSBA is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
+A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
+details.
+
+You should have received a copy of the GNU Lesser General Public License along
+with SSBA. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef V3D_CAMERA_MATRIX_H
+#define V3D_CAMERA_MATRIX_H
+
+#include "Math/v3d_linear.h"
+#include "Geometry/v3d_distortion.h"
+
+namespace V3D
+{
+
+ struct CameraMatrix
+ {
+ CameraMatrix()
+ {
+ makeIdentityMatrix(_K);
+ makeIdentityMatrix(_R);
+ makeZeroVector(_T);
+ this->updateCachedValues(true, true);
+ }
+
+ CameraMatrix(double f, double cx, double cy)
+ {
+ makeIdentityMatrix(_K);
+ _K[0][0] = f;
+ _K[1][1] = f;
+ _K[0][2] = cx;
+ _K[1][2] = cy;
+ makeIdentityMatrix(_R);
+ makeZeroVector(_T);
+ this->updateCachedValues(true, true);
+ }
+
+ CameraMatrix(Matrix3x3d const& K,
+ Matrix3x3d const& R,
+ Vector3d const& T)
+ : _K(K), _R(R), _T(T)
+ {
+ this->updateCachedValues(true, true);
+ }
+
+ void setIntrinsic(Matrix3x3d const& K) { _K = K; this->updateCachedValues(true, false); }
+ void setRotation(Matrix3x3d const& R) { _R = R; this->updateCachedValues(false, true); }
+ void setTranslation(Vector3d const& T) { _T = T; this->updateCachedValues(false, true); }
+
+ template <typename Mat>
+ void setOrientation(Mat const& RT)
+ {
+ _R[0][0] = RT[0][0]; _R[0][1] = RT[0][1]; _R[0][2] = RT[0][2];
+ _R[1][0] = RT[1][0]; _R[1][1] = RT[1][1]; _R[1][2] = RT[1][2];
+ _R[2][0] = RT[2][0]; _R[2][1] = RT[2][1]; _R[2][2] = RT[2][2];
+ _T[0] = RT[0][3]; _T[1] = RT[1][3]; _T[2] = RT[2][3];
+ this->updateCachedValues(false, true);
+ }
+
+ Matrix3x3d const& getIntrinsic() const { return _K; }
+ Matrix3x3d const& getRotation() const { return _R; }
+ Vector3d const& getTranslation() const { return _T; }
+
+ Matrix3x4d getOrientation() const
+ {
+ Matrix3x4d RT;
+ RT[0][0] = _R[0][0]; RT[0][1] = _R[0][1]; RT[0][2] = _R[0][2];
+ RT[1][0] = _R[1][0]; RT[1][1] = _R[1][1]; RT[1][2] = _R[1][2];
+ RT[2][0] = _R[2][0]; RT[2][1] = _R[2][1]; RT[2][2] = _R[2][2];
+ RT[0][3] = _T[0]; RT[1][3] = _T[1]; RT[2][3] = _T[2];
+ return RT;
+ }
+
+ Matrix3x4d getProjection() const
+ {
+ Matrix3x4d const RT = this->getOrientation();
+ return _K * RT;
+ }
+
+ double getFocalLength() const { return _K[0][0]; }
+ double getAspectRatio() const { return _K[1][1] / _K[0][0]; }
+
+ Vector2d getPrincipalPoint() const
+ {
+ Vector2d pp;
+ pp[0] = _K[0][2];
+ pp[1] = _K[1][2];
+ return pp;
+ }
+
+ Vector2d projectPoint(Vector3d const& X) const
+ {
+ Vector3d q = _K*(_R*X + _T);
+ Vector2d res;
+ res[0] = q[0]/q[2]; res[1] = q[1]/q[2];
+ return res;
+ }
+
+ template <typename Distortion>
+ Vector2d projectPoint(Distortion const& distortion, Vector3d const& X) const
+ {
+ Vector3d XX = _R*X + _T;
+ Vector2d p;
+ p[0] = XX[0] / XX[2];
+ p[1] = XX[1] / XX[2];
+ p = distortion(p);
+
+ Vector2d res;
+ res[0] = _K[0][0] * p[0] + _K[0][1] * p[1] + _K[0][2];
+ res[1] = _K[1][1] * p[1] + _K[1][2];
+ return res;
+ }
+
+ Vector3d unprojectPixel(Vector2d const &p, double depth = 1) const
+ {
+ Vector3d pp;
+ pp[0] = p[0]; pp[1] = p[1]; pp[2] = 1.0;
+ Vector3d ray = _invK * pp;
+ ray[0] *= depth/ray[2];
+ ray[1] *= depth/ray[2];
+ ray[2] = depth;
+ ray = _Rt * ray;
+ return _center + ray;
+ }
+
+ Vector3d transformPointIntoCameraSpace(Vector3d const& p) const
+ {
+ return _R*p + _T;
+ }
+
+ Vector3d transformPointFromCameraSpace(Vector3d const& p) const
+ {
+ return _Rt*(p-_T);
+ }
+
+ Vector3d transformDirectionFromCameraSpace(Vector3d const& dir) const
+ {
+ return _Rt*dir;
+ }
+
+ Vector3d const& cameraCenter() const
+ {
+ return _center;
+ }
+
+ Vector3d opticalAxis() const
+ {
+ return this->transformDirectionFromCameraSpace(makeVector3(0.0, 0.0, 1.0));
+ }
+
+ Vector3d upVector() const
+ {
+ return this->transformDirectionFromCameraSpace(makeVector3(0.0, 1.0, 0.0));
+ }
+
+ Vector3d rightVector() const
+ {
+ return this->transformDirectionFromCameraSpace(makeVector3(1.0, 0.0, 0.0));
+ }
+
+ Vector3d getRay(Vector2d const& p) const
+ {
+ Vector3d pp = makeVector3(p[0], p[1], 1.0);
+ Vector3d ray = _invK * pp;
+ ray = _Rt * ray;
+ normalizeVector(ray);
+ return ray;
+ }
+
+ protected:
+ void updateCachedValues(bool intrinsic, bool orientation)
+ {
+ if (intrinsic) _invK = invertedMatrix(_K);
+
+ if (orientation)
+ {
+ makeTransposedMatrix(_R, _Rt);
+ _center = _Rt * (-1.0 * _T);
+ }
+ }
+
+ Matrix3x3d _K, _R;
+ Vector3d _T;
+ Matrix3x3d _invK, _Rt;
+ Vector3d _center;
+ }; // end struct CameraMatrix
+
+} // end namespace V3D
+
+#endif
diff --git a/extern/libmv/third_party/ssba/Geometry/v3d_distortion.h b/extern/libmv/third_party/ssba/Geometry/v3d_distortion.h
new file mode 100644
index 00000000000..d0816558314
--- /dev/null
+++ b/extern/libmv/third_party/ssba/Geometry/v3d_distortion.h
@@ -0,0 +1,97 @@
+// -*- C++ -*-
+/*
+Copyright (c) 2008 University of North Carolina at Chapel Hill
+
+This file is part of SSBA (Simple Sparse Bundle Adjustment).
+
+SSBA is free software: you can redistribute it and/or modify it under the
+terms of the GNU Lesser General Public License as published by the Free
+Software Foundation, either version 3 of the License, or (at your option) any
+later version.
+
+SSBA is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
+A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
+details.
+
+You should have received a copy of the GNU Lesser General Public License along
+with SSBA. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef V3D_DISTORTION_H
+#define V3D_DISTORTION_H
+
+#include "Math/v3d_linear.h"
+#include "Math/v3d_linear_utils.h"
+
+namespace V3D
+{
+
+ struct StdDistortionFunction
+ {
+ double k1, k2, p1, p2;
+
+ StdDistortionFunction()
+ : k1(0), k2(0), p1(0), p2(0)
+ { }
+
+ Vector2d operator()(Vector2d const& xu) const
+ {
+ double const r2 = xu[0]*xu[0] + xu[1]*xu[1];
+ double const r4 = r2*r2;
+ double const kr = 1 + k1*r2 + k2*r4;
+
+ Vector2d xd;
+ xd[0] = kr * xu[0] + 2*p1*xu[0]*xu[1] + p2*(r2 + 2*xu[0]*xu[0]);
+ xd[1] = kr * xu[1] + 2*p2*xu[0]*xu[1] + p1*(r2 + 2*xu[1]*xu[1]);
+ return xd;
+ }
+
+ Matrix2x2d derivativeWrtRadialParameters(Vector2d const& xu) const
+ {
+ double const r2 = xu[0]*xu[0] + xu[1]*xu[1];
+ double const r4 = r2*r2;
+ //double const kr = 1 + k1*r2 + k2*r4;
+
+ Matrix2x2d deriv;
+
+ deriv[0][0] = xu[0] * r2; // d xd/d k1
+ deriv[0][1] = xu[0] * r4; // d xd/d k2
+ deriv[1][0] = xu[1] * r2; // d yd/d k1
+ deriv[1][1] = xu[1] * r4; // d yd/d k2
+ return deriv;
+ }
+
+ Matrix2x2d derivativeWrtTangentialParameters(Vector2d const& xu) const
+ {
+ double const r2 = xu[0]*xu[0] + xu[1]*xu[1];
+ //double const r4 = r2*r2;
+ //double const kr = 1 + k1*r2 + k2*r4;
+
+ Matrix2x2d deriv;
+ deriv[0][0] = 2*xu[0]*xu[1]; // d xd/d p1
+ deriv[0][1] = r2 + 2*xu[0]*xu[0]; // d xd/d p2
+ deriv[1][0] = r2 + 2*xu[1]*xu[1]; // d yd/d p1
+ deriv[1][1] = deriv[0][0]; // d yd/d p2
+ return deriv;
+ }
+
+ Matrix2x2d derivativeWrtUndistortedPoint(Vector2d const& xu) const
+ {
+ double const r2 = xu[0]*xu[0] + xu[1]*xu[1];
+ double const r4 = r2*r2;
+ double const kr = 1 + k1*r2 + k2*r4;
+ double const dkr = 2*k1 + 4*k2*r2;
+
+ Matrix2x2d deriv;
+ deriv[0][0] = kr + xu[0] * xu[0] * dkr + 2*p1*xu[1] + 6*p2*xu[0]; // d xd/d xu
+ deriv[0][1] = xu[0] * xu[1] * dkr + 2*p1*xu[0] + 2*p2*xu[1]; // d xd/d yu
+ deriv[1][0] = deriv[0][1]; // d yd/d xu
+ deriv[1][1] = kr + xu[1] * xu[1] * dkr + 6*p1*xu[1] + 2*p2*xu[0]; // d yd/d yu
+ return deriv;
+ }
+ }; // end struct StdDistortionFunction
+
+} // end namespace V3D
+
+#endif
diff --git a/extern/libmv/third_party/ssba/Geometry/v3d_metricbundle.cpp b/extern/libmv/third_party/ssba/Geometry/v3d_metricbundle.cpp
new file mode 100644
index 00000000000..1c1f0cb2627
--- /dev/null
+++ b/extern/libmv/third_party/ssba/Geometry/v3d_metricbundle.cpp
@@ -0,0 +1,365 @@
+/*
+Copyright (c) 2008 University of North Carolina at Chapel Hill
+
+This file is part of SSBA (Simple Sparse Bundle Adjustment).
+
+SSBA is free software: you can redistribute it and/or modify it under the
+terms of the GNU Lesser General Public License as published by the Free
+Software Foundation, either version 3 of the License, or (at your option) any
+later version.
+
+SSBA is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
+A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
+details.
+
+You should have received a copy of the GNU Lesser General Public License along
+with SSBA. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "Geometry/v3d_metricbundle.h"
+
+#if defined(V3DLIB_ENABLE_SUITESPARSE)
+
+namespace
+{
+
+ typedef V3D::InlineMatrix<double, 2, 4> Matrix2x4d;
+ typedef V3D::InlineMatrix<double, 4, 2> Matrix4x2d;
+ typedef V3D::InlineMatrix<double, 2, 6> Matrix2x6d;
+
+} // end namespace <>
+
+namespace V3D
+{
+
+ void
+ MetricBundleOptimizerBase::updateParametersA(VectorArray<double> const& deltaAi)
+ {
+ Vector3d T, omega;
+ Matrix3x3d R0, dR;
+
+ for (int i = _nNonvaryingA; i < _nParametersA; ++i)
+ {
+ T = _cams[i].getTranslation();
+ T[0] += deltaAi[i][0];
+ T[1] += deltaAi[i][1];
+ T[2] += deltaAi[i][2];
+ _cams[i].setTranslation(T);
+
+ // Create incremental rotation using Rodriguez formula.
+ R0 = _cams[i].getRotation();
+ omega[0] = deltaAi[i][3];
+ omega[1] = deltaAi[i][4];
+ omega[2] = deltaAi[i][5];
+ createRotationMatrixRodriguez(omega, dR);
+ _cams[i].setRotation(dR * R0);
+ } // end for (i)
+ } // end MetricBundleOptimizerBase::updateParametersA()
+
+ void
+ MetricBundleOptimizerBase::updateParametersB(VectorArray<double> const& deltaBj)
+ {
+ for (int j = _nNonvaryingB; j < _nParametersB; ++j)
+ {
+ _Xs[j][0] += deltaBj[j][0];
+ _Xs[j][1] += deltaBj[j][1];
+ _Xs[j][2] += deltaBj[j][2];
+ }
+ } // end MetricBundleOptimizerBase::updateParametersB()
+
+ void
+ MetricBundleOptimizerBase::poseDerivatives(int i, int j, Vector3d& XX,
+ Matrix3x6d& d_dRT, Matrix3x3d& d_dX) const
+ {
+ XX = _cams[i].transformPointIntoCameraSpace(_Xs[j]);
+
+ // See Frank Dellaerts bundle adjustment tutorial.
+ // d(dR * R0 * X + t)/d omega = -[R0 * X]_x
+ Matrix3x3d J;
+ makeCrossProductMatrix(XX - _cams[i].getTranslation(), J);
+ scaleMatrixIP(-1.0, J);
+
+ // Now the transformation from world coords into camera space is xx = Rx + T
+ // Hence the derivative of x wrt. T is just the identity matrix.
+ makeIdentityMatrix(d_dRT);
+ copyMatrixSlice(J, 0, 0, 3, 3, d_dRT, 0, 3);
+
+ // The derivative of Rx+T wrt x is just R.
+ copyMatrix(_cams[i].getRotation(), d_dX);
+ } // end MetricBundleOptimizerBase::poseDerivatives()
+
+
+//----------------------------------------------------------------------
+
+ void
+ StdMetricBundleOptimizer::fillJacobians(Matrix<double>& Ak,
+ Matrix<double>& Bk,
+ Matrix<double>& Ck,
+ int i, int j, int k)
+ {
+ Vector3d XX;
+ Matrix3x6d d_dRT;
+ Matrix3x3d d_dX;
+ this->poseDerivatives(i, j, XX, d_dRT, d_dX);
+
+ double const f = _cams[i].getFocalLength();
+ double const ar = _cams[i].getAspectRatio();
+
+ Matrix2x3d dp_dX;
+ double const bx = f / (XX[2] * XX[2]);
+ double const by = ar * bx;
+ dp_dX[0][0] = bx * XX[2]; dp_dX[0][1] = 0; dp_dX[0][2] = -bx * XX[0];
+ dp_dX[1][0] = 0; dp_dX[1][1] = by * XX[2]; dp_dX[1][2] = -by * XX[1];
+
+ multiply_A_B(dp_dX, d_dRT, Ak);
+ multiply_A_B(dp_dX, d_dX, Bk);
+ } // end StdMetricBundleOptimizer::fillJacobians()
+
+ //----------------------------------------------------------------------
+
+ void
+ CommonInternalsMetricBundleOptimizer::fillJacobians(Matrix<double>& Ak,
+ Matrix<double>& Bk,
+ Matrix<double>& Ck,
+ int i, int j, int k)
+ {
+ double const focalLength = _K[0][0];
+
+ Vector3d XX;
+ Matrix3x6d dXX_dRT;
+ Matrix3x3d dXX_dX;
+ this->poseDerivatives(i, j, XX, dXX_dRT, dXX_dX);
+
+ Vector2d xu; // undistorted image point
+ xu[0] = XX[0] / XX[2];
+ xu[1] = XX[1] / XX[2];
+
+ Vector2d const xd = _distortion(xu); // distorted image point
+
+ Matrix2x2d dp_dxd;
+ dp_dxd[0][0] = focalLength; dp_dxd[0][1] = 0;
+ dp_dxd[1][0] = 0; dp_dxd[1][1] = _cachedAspectRatio * focalLength;
+
+ {
+ // First, lets do the derivative wrt the structure and motion parameters.
+ Matrix2x3d dxu_dXX;
+ dxu_dXX[0][0] = 1.0f / XX[2]; dxu_dXX[0][1] = 0; dxu_dXX[0][2] = -XX[0]/(XX[2]*XX[2]);
+ dxu_dXX[1][0] = 0; dxu_dXX[1][1] = 1.0f / XX[2]; dxu_dXX[1][2] = -XX[1]/(XX[2]*XX[2]);
+
+ Matrix2x2d dxd_dxu = _distortion.derivativeWrtUndistortedPoint(xu);
+
+ Matrix2x2d dp_dxu = dp_dxd * dxd_dxu;
+ Matrix2x3d dp_dXX = dp_dxu * dxu_dXX;
+
+ multiply_A_B(dp_dXX, dXX_dRT, Ak);
+ multiply_A_B(dp_dXX, dXX_dX, Bk);
+ } // end scope
+
+ switch (_mode)
+ {
+ case FULL_BUNDLE_RADIAL_TANGENTIAL:
+ {
+ Matrix2x2d dxd_dp1p2 = _distortion.derivativeWrtTangentialParameters(xu);
+ Matrix2x2d d_dp1p2 = dp_dxd * dxd_dp1p2;
+ copyMatrixSlice(d_dp1p2, 0, 0, 2, 2, Ck, 0, 5);
+ // No break here!
+ }
+ case FULL_BUNDLE_RADIAL:
+ {
+ Matrix2x2d dxd_dk1k2 = _distortion.derivativeWrtRadialParameters(xu);
+ Matrix2x2d d_dk1k2 = dp_dxd * dxd_dk1k2;
+ copyMatrixSlice(d_dk1k2, 0, 0, 2, 2, Ck, 0, 3);
+ // No break here!
+ }
+ case FULL_BUNDLE_FOCAL_LENGTH_PP:
+ {
+ Ck[0][1] = 1; Ck[0][2] = 0;
+ Ck[1][1] = 0; Ck[1][2] = 1;
+ // No break here!
+ }
+ case FULL_BUNDLE_FOCAL_LENGTH:
+ {
+ Ck[0][0] = xd[0];
+ Ck[1][0] = xd[1];
+ }
+ case FULL_BUNDLE_METRIC:
+ {
+ }
+ } // end switch
+ } // end CommonInternalsMetricBundleOptimizer::fillJacobians()
+
+ void
+ CommonInternalsMetricBundleOptimizer::updateParametersC(Vector<double> const& deltaC)
+ {
+ switch (_mode)
+ {
+ case FULL_BUNDLE_RADIAL_TANGENTIAL:
+ {
+ _distortion.p1 += deltaC[5];
+ _distortion.p2 += deltaC[6];
+ // No break here!
+ }
+ case FULL_BUNDLE_RADIAL:
+ {
+ _distortion.k1 += deltaC[3];
+ _distortion.k2 += deltaC[4];
+ // No break here!
+ }
+ case FULL_BUNDLE_FOCAL_LENGTH_PP:
+ {
+ _K[0][2] += deltaC[1];
+ _K[1][2] += deltaC[2];
+ // No break here!
+ }
+ case FULL_BUNDLE_FOCAL_LENGTH:
+ {
+ _K[0][0] += deltaC[0];
+ _K[1][1] = _cachedAspectRatio * _K[0][0];
+ }
+ case FULL_BUNDLE_METRIC:
+ {
+ }
+ } // end switch
+ } // end CommonInternalsMetricBundleOptimizer::updateParametersC()
+
+ //----------------------------------------------------------------------
+
+ void
+ VaryingInternalsMetricBundleOptimizer::fillJacobians(Matrix<double>& Ak,
+ Matrix<double>& Bk,
+ Matrix<double>& Ck,
+ int i, int j, int k)
+ {
+ Vector3d XX;
+ Matrix3x6d dXX_dRT;
+ Matrix3x3d dXX_dX;
+ this->poseDerivatives(i, j, XX, dXX_dRT, dXX_dX);
+
+ Vector2d xu; // undistorted image point
+ xu[0] = XX[0] / XX[2];
+ xu[1] = XX[1] / XX[2];
+
+ Vector2d const xd = _distortions[i](xu); // distorted image point
+
+ double const focalLength = _cams[i].getFocalLength();
+ double const aspectRatio = _cams[i].getAspectRatio();
+
+ Matrix2x2d dp_dxd;
+ dp_dxd[0][0] = focalLength; dp_dxd[0][1] = 0;
+ dp_dxd[1][0] = 0; dp_dxd[1][1] = aspectRatio * focalLength;
+
+ {
+ // First, lets do the derivative wrt the structure and motion parameters.
+ Matrix2x3d dxu_dXX;
+ dxu_dXX[0][0] = 1.0f / XX[2]; dxu_dXX[0][1] = 0; dxu_dXX[0][2] = -XX[0]/(XX[2]*XX[2]);
+ dxu_dXX[1][0] = 0; dxu_dXX[1][1] = 1.0f / XX[2]; dxu_dXX[1][2] = -XX[1]/(XX[2]*XX[2]);
+
+ Matrix2x2d dxd_dxu = _distortions[i].derivativeWrtUndistortedPoint(xu);
+
+ Matrix2x2d dp_dxu = dp_dxd * dxd_dxu;
+ Matrix2x3d dp_dXX = dp_dxu * dxu_dXX;
+
+ Matrix2x6d dp_dRT;
+
+ multiply_A_B(dp_dXX, dXX_dRT, dp_dRT);
+ copyMatrixSlice(dp_dRT, 0, 0, 2, 6, Ak, 0, 0);
+ multiply_A_B(dp_dXX, dXX_dX, Bk);
+ } // end scope
+
+ switch (_mode)
+ {
+ case FULL_BUNDLE_RADIAL_TANGENTIAL:
+ {
+ Matrix2x2d dxd_dp1p2 = _distortions[i].derivativeWrtTangentialParameters(xu);
+ Matrix2x2d d_dp1p2 = dp_dxd * dxd_dp1p2;
+ copyMatrixSlice(d_dp1p2, 0, 0, 2, 2, Ak, 0, 11);
+ // No break here!
+ }
+ case FULL_BUNDLE_RADIAL:
+ {
+ Matrix2x2d dxd_dk1k2 = _distortions[i].derivativeWrtRadialParameters(xu);
+ Matrix2x2d d_dk1k2 = dp_dxd * dxd_dk1k2;
+ copyMatrixSlice(d_dk1k2, 0, 0, 2, 2, Ak, 0, 9);
+ // No break here!
+ }
+ case FULL_BUNDLE_FOCAL_LENGTH_PP:
+ {
+ Ak[0][7] = 1; Ak[0][8] = 0;
+ Ak[1][7] = 0; Ak[1][8] = 1;
+ // No break here!
+ }
+ case FULL_BUNDLE_FOCAL_LENGTH:
+ {
+ Ak[0][6] = xd[0];
+ Ak[1][6] = xd[1];
+ }
+ case FULL_BUNDLE_METRIC:
+ {
+ }
+ } // end switch
+ } // end VaryingInternalsMetricBundleOptimizer::fillJacobians()
+
+ void
+ VaryingInternalsMetricBundleOptimizer::updateParametersA(VectorArray<double> const& deltaAi)
+ {
+ Vector3d T, omega;
+ Matrix3x3d R0, dR, K;
+
+ for (int i = _nNonvaryingA; i < _nParametersA; ++i)
+ {
+ Vector<double> const& deltaA = deltaAi[i];
+
+ T = _cams[i].getTranslation();
+ T[0] += deltaA[0];
+ T[1] += deltaA[1];
+ T[2] += deltaA[2];
+ _cams[i].setTranslation(T);
+
+ // Create incremental rotation using Rodriguez formula.
+ R0 = _cams[i].getRotation();
+ omega[0] = deltaA[3];
+ omega[1] = deltaA[4];
+ omega[2] = deltaA[5];
+ createRotationMatrixRodriguez(omega, dR);
+ _cams[i].setRotation(dR * R0);
+
+ K = _cams[i].getIntrinsic();
+
+ switch (_mode)
+ {
+ case FULL_BUNDLE_RADIAL_TANGENTIAL:
+ {
+ _distortions[i].p1 += deltaA[11];
+ _distortions[i].p2 += deltaA[12];
+ // No break here!
+ }
+ case FULL_BUNDLE_RADIAL:
+ {
+ _distortions[i].k1 += deltaA[9];
+ _distortions[i].k2 += deltaA[10];
+ // No break here!
+ }
+ case FULL_BUNDLE_FOCAL_LENGTH_PP:
+ {
+ K[0][2] += deltaA[7];
+ K[1][2] += deltaA[8];
+ // No break here!
+ }
+ case FULL_BUNDLE_FOCAL_LENGTH:
+ {
+ double const ar = K[1][1] / K[0][0];
+ K[0][0] += deltaA[6];
+ K[1][1] = ar * K[0][0];
+ }
+ case FULL_BUNDLE_METRIC:
+ {
+ }
+ } // end switch
+ _cams[i].setIntrinsic(K);
+ } // end for (i)
+ } // end VaryingInternalsMetricBundleOptimizer::updateParametersC()
+
+} // end namespace V3D
+
+#endif // defined(V3DLIB_ENABLE_SUITESPARSE)
diff --git a/extern/libmv/third_party/ssba/Geometry/v3d_metricbundle.h b/extern/libmv/third_party/ssba/Geometry/v3d_metricbundle.h
new file mode 100644
index 00000000000..076a9e64346
--- /dev/null
+++ b/extern/libmv/third_party/ssba/Geometry/v3d_metricbundle.h
@@ -0,0 +1,346 @@
+// -*- C++ -*-
+/*
+Copyright (c) 2008 University of North Carolina at Chapel Hill
+
+This file is part of SSBA (Simple Sparse Bundle Adjustment).
+
+SSBA is free software: you can redistribute it and/or modify it under the
+terms of the GNU Lesser General Public License as published by the Free
+Software Foundation, either version 3 of the License, or (at your option) any
+later version.
+
+SSBA is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
+A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
+details.
+
+You should have received a copy of the GNU Lesser General Public License along
+with SSBA. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef V3D_METRICBUNDLE_H
+#define V3D_METRICBUNDLE_H
+
+# if defined(V3DLIB_ENABLE_SUITESPARSE)
+
+#include "Math/v3d_optimization.h"
+#include "Math/v3d_linear.h"
+#include "Math/v3d_linear_utils.h"
+#include "Geometry/v3d_cameramatrix.h"
+#include "Geometry/v3d_distortion.h"
+
+namespace V3D
+{
+
+ // This structure provides some helper functions common to all metric BAs
+ struct MetricBundleOptimizerBase : public SparseLevenbergOptimizer
+ {
+ typedef SparseLevenbergOptimizer Base;
+
+ MetricBundleOptimizerBase(double inlierThreshold,
+ vector<CameraMatrix>& cams,
+ vector<Vector3d >& Xs,
+ vector<Vector2d > const& measurements,
+ vector<int> const& corrspondingView,
+ vector<int> const& corrspondingPoint,
+ int nAddParamsA, int nParamsC)
+ : SparseLevenbergOptimizer(2, cams.size(), 6+nAddParamsA, Xs.size(), 3, nParamsC,
+ corrspondingView, corrspondingPoint),
+ _cams(cams), _Xs(Xs), _measurements(measurements),
+ _savedTranslations(cams.size()), _savedRotations(cams.size()),
+ _savedXs(Xs.size()),
+ _inlierThreshold(inlierThreshold), _cachedParamLength(0.0)
+ {
+ // Since we assume that BA does not alter the inputs too much,
+ // we compute the overall length of the parameter vector in advance
+ // and return that value as the result of getParameterLength().
+ for (int i = _nNonvaryingA; i < _nParametersA; ++i)
+ {
+ _cachedParamLength += sqrNorm_L2(_cams[i].getTranslation());
+ _cachedParamLength += 3.0; // Assume eye(3) for R.
+ }
+ for (int j = _nNonvaryingB; j < _nParametersB; ++j)
+ _cachedParamLength += sqrNorm_L2(_Xs[j]);
+
+ _cachedParamLength = sqrt(_cachedParamLength);
+ }
+
+ // Huber robust cost function.
+ virtual void fillWeights(VectorArray<double> const& residual, Vector<double>& w)
+ {
+ for (unsigned int k = 0; k < w.size(); ++k)
+ {
+ Vector<double> const& r = residual[k];
+ double const e = norm_L2(r);
+ w[k] = (e < _inlierThreshold) ? 1.0 : sqrt(_inlierThreshold / e);
+ } // end for (k)
+ }
+
+ virtual double getParameterLength() const
+ {
+ return _cachedParamLength;
+ }
+
+ virtual void updateParametersA(VectorArray<double> const& deltaAi);
+ virtual void updateParametersB(VectorArray<double> const& deltaBj);
+ virtual void updateParametersC(Vector<double> const& deltaC)
+ {
+ (void)deltaC;
+ }
+
+ virtual void saveAllParameters()
+ {
+ for (int i = _nNonvaryingA; i < _nParametersA; ++i)
+ {
+ _savedTranslations[i] = _cams[i].getTranslation();
+ _savedRotations[i] = _cams[i].getRotation();
+ }
+ _savedXs = _Xs;
+ }
+
+ virtual void restoreAllParameters()
+ {
+ for (int i = _nNonvaryingA; i < _nParametersA; ++i)
+ {
+ _cams[i].setTranslation(_savedTranslations[i]);
+ _cams[i].setRotation(_savedRotations[i]);
+ }
+ _Xs = _savedXs;
+ }
+
+ protected:
+ typedef InlineMatrix<double, 3, 6> Matrix3x6d;
+
+ void poseDerivatives(int i, int j, Vector3d& XX,
+ Matrix3x6d& d_dRT, Matrix3x3d& d_dX) const;
+
+ vector<CameraMatrix>& _cams;
+ vector<Vector3d>& _Xs;
+
+ vector<Vector2d> const& _measurements;
+
+ vector<Vector3d> _savedTranslations;
+ vector<Matrix3x3d> _savedRotations;
+ vector<Vector3d> _savedXs;
+
+ double const _inlierThreshold;
+ double _cachedParamLength;
+ }; // end struct MetricBundleOptimizerBase
+
+ struct StdMetricBundleOptimizer : public MetricBundleOptimizerBase
+ {
+ typedef MetricBundleOptimizerBase Base;
+
+ StdMetricBundleOptimizer(double inlierThreshold,
+ vector<CameraMatrix>& cams,
+ vector<Vector3d >& Xs,
+ vector<Vector2d > const& measurements,
+ vector<int> const& corrspondingView,
+ vector<int> const& corrspondingPoint)
+ : MetricBundleOptimizerBase(inlierThreshold, cams, Xs, measurements,
+ corrspondingView, corrspondingPoint, 0, 0)
+ { }
+
+ virtual void evalResidual(VectorArray<double>& e)
+ {
+ for (unsigned int k = 0; k < e.count(); ++k)
+ {
+ int const i = _correspondingParamA[k];
+ int const j = _correspondingParamB[k];
+
+ Vector2d const q = _cams[i].projectPoint(_Xs[j]);
+ e[k][0] = q[0] - _measurements[k][0];
+ e[k][1] = q[1] - _measurements[k][1];
+ }
+ }
+
+ virtual void fillJacobians(Matrix<double>& Ak, Matrix<double>& Bk, Matrix<double>& Ck,
+ int i, int j, int k);
+ }; // end struct StdMetricBundleOptimizer
+
+//----------------------------------------------------------------------
+
+ enum
+ {
+ FULL_BUNDLE_METRIC = 0,
+ FULL_BUNDLE_FOCAL_LENGTH = 1, // f
+ FULL_BUNDLE_FOCAL_LENGTH_PP = 2, // f, cx, cy
+ FULL_BUNDLE_RADIAL = 3, // f, cx, cy, k1, k2
+ FULL_BUNDLE_RADIAL_TANGENTIAL = 4 // f, cx, cy, k1, k2, p1, p2
+ };
+
+ struct CommonInternalsMetricBundleOptimizer : public MetricBundleOptimizerBase
+ {
+ static int globalParamDimensionFromMode(int mode)
+ {
+ switch (mode)
+ {
+ case FULL_BUNDLE_METRIC: return 0;
+ case FULL_BUNDLE_FOCAL_LENGTH: return 1;
+ case FULL_BUNDLE_FOCAL_LENGTH_PP: return 3;
+ case FULL_BUNDLE_RADIAL: return 5;
+ case FULL_BUNDLE_RADIAL_TANGENTIAL: return 7;
+ }
+ return 0;
+ }
+
+ typedef MetricBundleOptimizerBase Base;
+
+ CommonInternalsMetricBundleOptimizer(int mode,
+ double inlierThreshold,
+ Matrix3x3d& K,
+ StdDistortionFunction& distortion,
+ vector<CameraMatrix>& cams,
+ vector<Vector3d >& Xs,
+ vector<Vector2d > const& measurements,
+ vector<int> const& corrspondingView,
+ vector<int> const& corrspondingPoint)
+ : MetricBundleOptimizerBase(inlierThreshold, cams, Xs, measurements,
+ corrspondingView, corrspondingPoint,
+ 0, globalParamDimensionFromMode(mode)),
+ _mode(mode), _K(K), _distortion(distortion)
+ {
+ _cachedAspectRatio = K[1][1] / K[0][0];
+ }
+
+ Vector2d projectPoint(Vector3d const& X, int i) const
+ {
+ Vector3d const XX = _cams[i].transformPointIntoCameraSpace(X);
+ Vector2d p;
+ p[0] = XX[0] / XX[2];
+ p[1] = XX[1] / XX[2];
+ p = _distortion(p);
+ Vector2d res;
+ res[0] = _K[0][0] * p[0] + _K[0][1] * p[1] + _K[0][2];
+ res[1] = _K[1][1] * p[1] + _K[1][2];
+ return res;
+ }
+
+ virtual void evalResidual(VectorArray<double>& e)
+ {
+ for (unsigned int k = 0; k < e.count(); ++k)
+ {
+ int const i = _correspondingParamA[k];
+ int const j = _correspondingParamB[k];
+
+ Vector2d const q = this->projectPoint(_Xs[j], i);
+ e[k][0] = q[0] - _measurements[k][0];
+ e[k][1] = q[1] - _measurements[k][1];
+ }
+ }
+
+ virtual void fillJacobians(Matrix<double>& Ak, Matrix<double>& Bk, Matrix<double>& Ck,
+ int i, int j, int k);
+
+ virtual void updateParametersC(Vector<double> const& deltaC);
+
+ virtual void saveAllParameters()
+ {
+ Base::saveAllParameters();
+ _savedK = _K;
+ _savedDistortion = _distortion;
+ }
+
+ virtual void restoreAllParameters()
+ {
+ Base::restoreAllParameters();
+ _K = _savedK;
+ _distortion = _savedDistortion;
+ }
+
+ protected:
+ int _mode;
+ Matrix3x3d& _K;
+ StdDistortionFunction& _distortion;
+
+ Matrix3x3d _savedK;
+ StdDistortionFunction _savedDistortion;
+ double _cachedAspectRatio;
+ }; // end struct CommonInternalsMetricBundleOptimizer
+
+//----------------------------------------------------------------------
+
+ struct VaryingInternalsMetricBundleOptimizer : public MetricBundleOptimizerBase
+ {
+ static int extParamDimensionFromMode(int mode)
+ {
+ switch (mode)
+ {
+ case FULL_BUNDLE_METRIC: return 0;
+ case FULL_BUNDLE_FOCAL_LENGTH: return 1;
+ case FULL_BUNDLE_FOCAL_LENGTH_PP: return 3;
+ case FULL_BUNDLE_RADIAL: return 5;
+ case FULL_BUNDLE_RADIAL_TANGENTIAL: return 7;
+ }
+ return 0;
+ }
+
+ typedef MetricBundleOptimizerBase Base;
+
+ VaryingInternalsMetricBundleOptimizer(int mode,
+ double inlierThreshold,
+ std::vector<StdDistortionFunction>& distortions,
+ vector<CameraMatrix>& cams,
+ vector<Vector3d >& Xs,
+ vector<Vector2d > const& measurements,
+ vector<int> const& corrspondingView,
+ vector<int> const& corrspondingPoint)
+ : MetricBundleOptimizerBase(inlierThreshold, cams, Xs, measurements,
+ corrspondingView, corrspondingPoint,
+ extParamDimensionFromMode(mode), 0),
+ _mode(mode), _distortions(distortions),
+ _savedKs(cams.size()), _savedDistortions(cams.size())
+ { }
+
+ Vector2d projectPoint(Vector3d const& X, int i) const
+ {
+ return _cams[i].projectPoint(_distortions[i], X);
+ }
+
+ virtual void evalResidual(VectorArray<double>& e)
+ {
+ for (unsigned int k = 0; k < e.count(); ++k)
+ {
+ int const i = _correspondingParamA[k];
+ int const j = _correspondingParamB[k];
+
+ Vector2d const q = this->projectPoint(_Xs[j], i);
+ e[k][0] = q[0] - _measurements[k][0];
+ e[k][1] = q[1] - _measurements[k][1];
+ }
+ }
+
+ virtual void fillJacobians(Matrix<double>& Ak, Matrix<double>& Bk, Matrix<double>& Ck,
+ int i, int j, int k);
+
+ virtual void updateParametersA(VectorArray<double> const& deltaAi);
+
+ virtual void saveAllParameters()
+ {
+ Base::saveAllParameters();
+ for (int i = _nNonvaryingA; i < _nParametersA; ++i)
+ _savedKs[i] = _cams[i].getIntrinsic();
+ std::copy(_distortions.begin(), _distortions.end(), _savedDistortions.begin());
+ }
+
+ virtual void restoreAllParameters()
+ {
+ Base::restoreAllParameters();
+ for (int i = _nNonvaryingA; i < _nParametersA; ++i)
+ _cams[i].setIntrinsic(_savedKs[i]);
+ std::copy(_savedDistortions.begin(), _savedDistortions.end(), _distortions.begin());
+ }
+
+ protected:
+ int _mode;
+ std::vector<StdDistortionFunction>& _distortions;
+
+ std::vector<Matrix3x3d> _savedKs;
+ std::vector<StdDistortionFunction> _savedDistortions;
+ }; // end struct VaryingInternalsMetricBundleOptimizer
+
+} // end namespace V3D
+
+# endif
+
+#endif
diff --git a/extern/libmv/third_party/ssba/Math/v3d_linear.h b/extern/libmv/third_party/ssba/Math/v3d_linear.h
new file mode 100644
index 00000000000..7d6e898169c
--- /dev/null
+++ b/extern/libmv/third_party/ssba/Math/v3d_linear.h
@@ -0,0 +1,923 @@
+// -*- C++ -*-
+/*
+Copyright (c) 2008 University of North Carolina at Chapel Hill
+
+This file is part of SSBA (Simple Sparse Bundle Adjustment).
+
+SSBA is free software: you can redistribute it and/or modify it under the
+terms of the GNU Lesser General Public License as published by the Free
+Software Foundation, either version 3 of the License, or (at your option) any
+later version.
+
+SSBA is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
+A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
+details.
+
+You should have received a copy of the GNU Lesser General Public License along
+with SSBA. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef V3D_LINEAR_H
+#define V3D_LINEAR_H
+
+#include <cassert>
+#include <algorithm>
+#include <vector>
+#include <cmath>
+
+namespace V3D
+{
+ using namespace std;
+
+ //! Unboxed vector type
+ template <typename Elem, int Size>
+ struct InlineVectorBase
+ {
+ typedef Elem value_type;
+ typedef Elem element_type;
+
+ typedef Elem const * const_iterator;
+ typedef Elem * iterator;
+
+ static unsigned int size() { return Size; }
+
+ Elem& operator[](unsigned int i) { return _vec[i]; }
+ Elem operator[](unsigned int i) const { return _vec[i]; }
+
+ Elem& operator()(unsigned int i) { return _vec[i-1]; }
+ Elem operator()(unsigned int i) const { return _vec[i-1]; }
+
+ const_iterator begin() const { return _vec; }
+ iterator begin() { return _vec; }
+ const_iterator end() const { return _vec + Size; }
+ iterator end() { return _vec + Size; }
+
+ void newsize(unsigned int sz) const
+ {
+ assert(sz == Size);
+ }
+
+ protected:
+ Elem _vec[Size];
+ };
+
+ //! Boxed (heap allocated) vector.
+ template <typename Elem>
+ struct VectorBase
+ {
+ typedef Elem value_type;
+ typedef Elem element_type;
+
+ typedef Elem const * const_iterator;
+ typedef Elem * iterator;
+
+ VectorBase()
+ : _size(0), _ownsVec(true), _vec(0)
+ { }
+
+ VectorBase(unsigned int size)
+ : _size(size), _ownsVec(true), _vec(0)
+ {
+ if (size > 0) _vec = new Elem[size];
+ }
+
+ VectorBase(unsigned int size, Elem * values)
+ : _size(size), _ownsVec(false), _vec(values)
+ { }
+
+ VectorBase(VectorBase<Elem> const& a)
+ : _size(0), _ownsVec(true), _vec(0)
+ {
+ _size = a._size;
+ if (_size == 0) return;
+ _vec = new Elem[_size];
+ std::copy(a._vec, a._vec + _size, _vec);
+ }
+
+ ~VectorBase() { if (_ownsVec && _vec != 0) delete [] _vec; }
+
+ VectorBase& operator=(VectorBase<Elem> const& a)
+ {
+ if (this == &a) return *this;
+
+ this->newsize(a._size);
+ std::copy(a._vec, a._vec + _size, _vec);
+ return *this;
+ }
+
+ unsigned int size() const { return _size; }
+
+ VectorBase<Elem>& newsize(unsigned int sz)
+ {
+ if (sz == _size) return *this;
+ assert(_ownsVec);
+
+ __destroy();
+ _size = sz;
+ if (_size > 0) _vec = new Elem[_size];
+
+ return *this;
+ }
+
+
+ Elem& operator[](unsigned int i) { return _vec[i]; }
+ Elem operator[](unsigned int i) const { return _vec[i]; }
+
+ Elem& operator()(unsigned int i) { return _vec[i-1]; }
+ Elem operator()(unsigned int i) const { return _vec[i-1]; }
+
+ const_iterator begin() const { return _vec; }
+ iterator begin() { return _vec; }
+ const_iterator end() const { return _vec + _size; }
+ iterator end() { return _vec + _size; }
+
+ protected:
+ void __destroy()
+ {
+ assert(_ownsVec);
+
+ if (_vec != 0) delete [] _vec;
+ _size = 0;
+ _vec = 0;
+ }
+
+ unsigned int _size;
+ bool _ownsVec;
+ Elem * _vec;
+ };
+
+ template <typename Elem, int Rows, int Cols>
+ struct InlineMatrixBase
+ {
+ typedef Elem value_type;
+ typedef Elem element_type;
+
+ typedef Elem * iterator;
+ typedef Elem const * const_iterator;
+
+ static unsigned int num_rows() { return Rows; }
+ static unsigned int num_cols() { return Cols; }
+
+ Elem * operator[](unsigned int row) { return _m[row]; }
+ Elem const * operator[](unsigned int row) const { return _m[row]; }
+
+ Elem& operator()(unsigned int row, unsigned int col) { return _m[row-1][col-1]; }
+ Elem operator()(unsigned int row, unsigned int col) const { return _m[row-1][col-1]; }
+
+ template <typename Vec>
+ void getRowSlice(unsigned int row, unsigned int first, unsigned int last, Vec& dst) const
+ {
+ for (unsigned int c = first; c < last; ++c) dst[c-first] = _m[row][c];
+ }
+
+ template <typename Vec>
+ void getColumnSlice(unsigned int first, unsigned int len, unsigned int col, Vec& dst) const
+ {
+ for (unsigned int r = 0; r < len; ++r) dst[r] = _m[r+first][col];
+ }
+
+ void newsize(unsigned int rows, unsigned int cols) const
+ {
+ assert(rows == Rows && cols == Cols);
+ }
+
+ const_iterator begin() const { return &_m[0][0]; }
+ iterator begin() { return &_m[0][0]; }
+ const_iterator end() const { return &_m[0][0] + Rows*Cols; }
+ iterator end() { return &_m[0][0] + Rows*Cols; }
+
+ protected:
+ Elem _m[Rows][Cols];
+ };
+
+ template <typename Elem>
+ struct MatrixBase
+ {
+ typedef Elem value_type;
+ typedef Elem element_type;
+
+ typedef Elem const * const_iterator;
+ typedef Elem * iterator;
+
+ MatrixBase()
+ : _rows(0), _cols(0), _ownsData(true), _m(0)
+ { }
+
+ MatrixBase(unsigned int rows, unsigned int cols)
+ : _rows(rows), _cols(cols), _ownsData(true), _m(0)
+ {
+ if (_rows * _cols == 0) return;
+ _m = new Elem[rows*cols];
+ }
+
+ MatrixBase(unsigned int rows, unsigned int cols, Elem * values)
+ : _rows(rows), _cols(cols), _ownsData(false), _m(values)
+ { }
+
+ MatrixBase(MatrixBase<Elem> const& a)
+ : _ownsData(true), _m(0)
+ {
+ _rows = a._rows; _cols = a._cols;
+ if (_rows * _cols == 0) return;
+ _m = new Elem[_rows*_cols];
+ std::copy(a._m, a._m+_rows*_cols, _m);
+ }
+
+ ~MatrixBase()
+ {
+ if (_ownsData && _m != 0) delete [] _m;
+ }
+
+ MatrixBase& operator=(MatrixBase<Elem> const& a)
+ {
+ if (this == &a) return *this;
+
+ this->newsize(a.num_rows(), a.num_cols());
+
+ std::copy(a._m, a._m+_rows*_cols, _m);
+ return *this;
+ }
+
+ void newsize(unsigned int rows, unsigned int cols)
+ {
+ if (rows == _rows && cols == _cols) return;
+
+ assert(_ownsData);
+
+ __destroy();
+
+ _rows = rows;
+ _cols = cols;
+ if (_rows * _cols == 0) return;
+ _m = new Elem[rows*cols];
+ }
+
+ unsigned int num_rows() const { return _rows; }
+ unsigned int num_cols() const { return _cols; }
+
+ Elem * operator[](unsigned int row) { return _m + row*_cols; }
+ Elem const * operator[](unsigned int row) const { return _m + row*_cols; }
+
+ Elem& operator()(unsigned int row, unsigned int col) { return _m[(row-1)*_cols + col-1]; }
+ Elem operator()(unsigned int row, unsigned int col) const { return _m[(row-1)*_cols + col-1]; }
+
+ const_iterator begin() const { return _m; }
+ iterator begin() { return _m; }
+ const_iterator end() const { return _m + _rows*_cols; }
+ iterator end() { return _m + _rows*_cols; }
+
+ template <typename Vec>
+ void getRowSlice(unsigned int row, unsigned int first, unsigned int last, Vec& dst) const
+ {
+ Elem const * v = (*this)[row];
+ for (unsigned int c = first; c < last; ++c) dst[c-first] = v[c];
+ }
+
+ template <typename Vec>
+ void getColumnSlice(unsigned int first, unsigned int len, unsigned int col, Vec& dst) const
+ {
+ for (unsigned int r = 0; r < len; ++r) dst[r] = _m[r+first][col];
+ }
+
+ protected:
+ void __destroy()
+ {
+ assert(_ownsData);
+ if (_m != 0) delete [] _m;
+ _m = 0;
+ _rows = _cols = 0;
+ }
+
+ unsigned int _rows, _cols;
+ bool _ownsData;
+ Elem * _m;
+ };
+
+ template <typename T>
+ struct CCS_Matrix
+ {
+ CCS_Matrix()
+ : _rows(0), _cols(0)
+ { }
+
+ CCS_Matrix(int const rows, int const cols, vector<pair<int, int> > const& nonZeros)
+ : _rows(rows), _cols(cols)
+ {
+ this->initialize(nonZeros);
+ }
+
+ CCS_Matrix(CCS_Matrix const& b)
+ : _rows(b._rows), _cols(b._cols),
+ _colStarts(b._colStarts), _rowIdxs(b._rowIdxs), _destIdxs(b._destIdxs), _values(b._values)
+ { }
+
+ CCS_Matrix& operator=(CCS_Matrix const& b)
+ {
+ if (this == &b) return *this;
+ _rows = b._rows;
+ _cols = b._cols;
+ _colStarts = b._colStarts;
+ _rowIdxs = b._rowIdxs;
+ _destIdxs = b._destIdxs;
+ _values = b._values;
+ return *this;
+ }
+
+ void create(int const rows, int const cols, vector<pair<int, int> > const& nonZeros)
+ {
+ _rows = rows;
+ _cols = cols;
+ this->initialize(nonZeros);
+ }
+
+ unsigned int num_rows() const { return _rows; }
+ unsigned int num_cols() const { return _cols; }
+
+ int getNonzeroCount() const { return _values.size(); }
+
+ T const * getValues() const { return &_values[0]; }
+ T * getValues() { return &_values[0]; }
+
+ int const * getDestIndices() const { return &_destIdxs[0]; }
+ int const * getColumnStarts() const { return &_colStarts[0]; }
+ int const * getRowIndices() const { return &_rowIdxs[0]; }
+
+ void getRowRange(unsigned int col, unsigned int& firstRow, unsigned int& lastRow) const
+ {
+ firstRow = _rowIdxs[_colStarts[col]];
+ lastRow = _rowIdxs[_colStarts[col+1]-1]+1;
+ }
+
+ template <typename Vec>
+ void getColumnSlice(unsigned int first, unsigned int len, unsigned int col, Vec& dst) const
+ {
+ unsigned int const last = first + len;
+
+ for (int r = 0; r < len; ++r) dst[r] = 0; // Fill vector with zeros
+
+ int const colStart = _colStarts[col];
+ int const colEnd = _colStarts[col+1];
+
+ int i = colStart;
+ int r;
+ // Skip rows less than the given start row
+ while (i < colEnd && (r = _rowIdxs[i]) < first) ++i;
+
+ // Copy elements until the final row
+ while (i < colEnd && (r = _rowIdxs[i]) < last)
+ {
+ dst[r-first] = _values[i];
+ ++i;
+ }
+ } // end getColumnSlice()
+
+ int getColumnNonzeroCount(unsigned int col) const
+ {
+ int const colStart = _colStarts[col];
+ int const colEnd = _colStarts[col+1];
+ return colEnd - colStart;
+ }
+
+ template <typename VecA, typename VecB>
+ void getSparseColumn(unsigned int col, VecA& rows, VecB& values) const
+ {
+ int const colStart = _colStarts[col];
+ int const colEnd = _colStarts[col+1];
+ int const nnz = colEnd - colStart;
+
+ for (int i = 0; i < nnz; ++i)
+ {
+ rows[i] = _rowIdxs[colStart + i];
+ values[i] = _values[colStart + i];
+ }
+ }
+
+ protected:
+ struct NonzeroInfo
+ {
+ int row, col, serial;
+
+ // Sort wrt the column first
+ bool operator<(NonzeroInfo const& rhs) const
+ {
+ if (col < rhs.col) return true;
+ if (col > rhs.col) return false;
+ return row < rhs.row;
+ }
+ };
+
+ void initialize(std::vector<std::pair<int, int> > const& nonZeros)
+ {
+ using namespace std;
+
+ int const nnz = nonZeros.size();
+
+ _colStarts.resize(_cols + 1);
+ _rowIdxs.resize(nnz);
+
+ vector<NonzeroInfo> nz(nnz);
+ for (int k = 0; k < nnz; ++k)
+ {
+ nz[k].row = nonZeros[k].first;
+ nz[k].col = nonZeros[k].second;
+ nz[k].serial = k;
+ }
+
+ // Sort in column major order
+ std::sort(nz.begin(), nz.end());
+
+ for (size_t k = 0; k < nnz; ++k) _rowIdxs[k] = nz[k].row;
+
+ int curCol = -1;
+ for (int k = 0; k < nnz; ++k)
+ {
+ NonzeroInfo const& el = nz[k];
+ if (el.col != curCol)
+ {
+ // Update empty cols between
+ for (int c = curCol+1; c < el.col; ++c) _colStarts[c] = k;
+
+ curCol = el.col;
+ _colStarts[curCol] = k;
+ } // end if
+ } // end for (k)
+
+ // Update remaining columns
+ for (int c = curCol+1; c <= _cols; ++c) _colStarts[c] = nnz;
+
+ _destIdxs.resize(nnz);
+ for (int k = 0; k < nnz; ++k) _destIdxs[nz[k].serial] = k;
+
+ _values.resize(nnz);
+ } // end initialize()
+
+ int _rows, _cols;
+ std::vector<int> _colStarts;
+ std::vector<int> _rowIdxs;
+ std::vector<int> _destIdxs;
+ std::vector<T> _values;
+ }; // end struct CCS_Matrix
+
+//----------------------------------------------------------------------
+
+ template <typename Vec, typename Elem>
+ inline void
+ fillVector(Vec& v, Elem val)
+ {
+ // We do not use std::fill since we rely only on size() and operator[] member functions.
+ for (unsigned int i = 0; i < v.size(); ++i) v[i] = val;
+ }
+
+ template <typename Vec>
+ inline void
+ makeZeroVector(Vec& v)
+ {
+ fillVector(v, 0);
+ }
+
+ template <typename VecA, typename VecB>
+ inline void
+ copyVector(VecA const& src, VecB& dst)
+ {
+ assert(src.size() == dst.size());
+ // We do not use std::fill since we rely only on size() and operator[] member functions.
+ for (unsigned int i = 0; i < src.size(); ++i) dst[i] = src[i];
+ }
+
+ template <typename VecA, typename VecB>
+ inline void
+ copyVectorSlice(VecA const& src, unsigned int srcStart, unsigned int srcLen,
+ VecB& dst, unsigned int dstStart)
+ {
+ unsigned int const end = std::min(srcStart + srcLen, src.size());
+ unsigned int const sz = dst.size();
+ unsigned int i0, i1;
+ for (i0 = srcStart, i1 = dstStart; i0 < end && i1 < sz; ++i0, ++i1) dst[i1] = src[i0];
+ }
+
+ template <typename Vec>
+ inline typename Vec::value_type
+ norm_L1(Vec const& v)
+ {
+ typename Vec::value_type res(0);
+ for (unsigned int i = 0; i < v.size(); ++i) res += fabs(v[i]);
+ return res;
+ }
+
+ template <typename Vec>
+ inline typename Vec::value_type
+ norm_Linf(Vec const& v)
+ {
+ typename Vec::value_type res(0);
+ for (unsigned int i = 0; i < v.size(); ++i) res = std::max(res, fabs(v[i]));
+ return res;
+ }
+
+ template <typename Vec>
+ inline typename Vec::value_type
+ norm_L2(Vec const& v)
+ {
+ typename Vec::value_type res(0);
+ for (unsigned int i = 0; i < v.size(); ++i) res += v[i]*v[i];
+ return sqrt((double)res);
+ }
+
+ template <typename Vec>
+ inline typename Vec::value_type
+ sqrNorm_L2(Vec const& v)
+ {
+ typename Vec::value_type res(0);
+ for (unsigned int i = 0; i < v.size(); ++i) res += v[i]*v[i];
+ return res;
+ }
+
+ template <typename Vec>
+ inline void
+ normalizeVector(Vec& v)
+ {
+ typename Vec::value_type norm(norm_L2(v));
+ for (unsigned int i = 0; i < v.size(); ++i) v[i] /= norm;
+ }
+
+ template<typename VecA, typename VecB>
+ inline typename VecA::value_type
+ innerProduct(VecA const& a, VecB const& b)
+ {
+ assert(a.size() == b.size());
+ typename VecA::value_type res(0);
+ for (unsigned int i = 0; i < a.size(); ++i) res += a[i] * b[i];
+ return res;
+ }
+
+ template <typename Elem, typename VecA, typename VecB>
+ inline void
+ scaleVector(Elem s, VecA const& v, VecB& dst)
+ {
+ for (unsigned int i = 0; i < v.size(); ++i) dst[i] = s * v[i];
+ }
+
+ template <typename Elem, typename Vec>
+ inline void
+ scaleVectorIP(Elem s, Vec& v)
+ {
+ typedef typename Vec::value_type Elem2;
+ for (unsigned int i = 0; i < v.size(); ++i)
+ v[i] = (Elem2)(v[i] * s);
+ }
+
+ template <typename VecA, typename VecB, typename VecC>
+ inline void
+ makeCrossProductVector(VecA const& v, VecB const& w, VecC& dst)
+ {
+ assert(v.size() == 3);
+ assert(w.size() == 3);
+ assert(dst.size() == 3);
+ dst[0] = v[1]*w[2] - v[2]*w[1];
+ dst[1] = v[2]*w[0] - v[0]*w[2];
+ dst[2] = v[0]*w[1] - v[1]*w[0];
+ }
+
+ template <typename VecA, typename VecB, typename VecC>
+ inline void
+ addVectors(VecA const& v, VecB const& w, VecC& dst)
+ {
+ assert(v.size() == w.size());
+ assert(v.size() == dst.size());
+ for (unsigned int i = 0; i < v.size(); ++i) dst[i] = v[i] + w[i];
+ }
+
+ template <typename VecA, typename VecB, typename VecC>
+ inline void
+ subtractVectors(VecA const& v, VecB const& w, VecC& dst)
+ {
+ assert(v.size() == w.size());
+ assert(v.size() == dst.size());
+ for (unsigned int i = 0; i < v.size(); ++i) dst[i] = v[i] - w[i];
+ }
+
+ template <typename MatA, typename MatB>
+ inline void
+ copyMatrix(MatA const& src, MatB& dst)
+ {
+ unsigned int const rows = src.num_rows();
+ unsigned int const cols = src.num_cols();
+ assert(dst.num_rows() == rows);
+ assert(dst.num_cols() == cols);
+ for (unsigned int c = 0; c < cols; ++c)
+ for (unsigned int r = 0; r < rows; ++r) dst[r][c] = src[r][c];
+ }
+
+ template <typename MatA, typename MatB>
+ inline void
+ copyMatrixSlice(MatA const& src, unsigned int rowStart, unsigned int colStart, unsigned int rowLen, unsigned int colLen,
+ MatB& dst, unsigned int dstRow, unsigned int dstCol)
+ {
+ unsigned int const rows = dst.num_rows();
+ unsigned int const cols = dst.num_cols();
+
+ unsigned int const rowEnd = std::min(rowStart + rowLen, src.num_rows());
+ unsigned int const colEnd = std::min(colStart + colLen, src.num_cols());
+
+ unsigned int c0, c1, r0, r1;
+
+ for (c0 = colStart, c1 = dstCol; c0 < colEnd && c1 < cols; ++c0, ++c1)
+ for (r0 = rowStart, r1 = dstRow; r0 < rowEnd && r1 < rows; ++r0, ++r1)
+ dst[r1][c1] = src[r0][c0];
+ }
+
+ template <typename MatA, typename MatB>
+ inline void
+ makeTransposedMatrix(MatA const& src, MatB& dst)
+ {
+ unsigned int const rows = src.num_rows();
+ unsigned int const cols = src.num_cols();
+ assert(dst.num_cols() == rows);
+ assert(dst.num_rows() == cols);
+ for (unsigned int c = 0; c < cols; ++c)
+ for (unsigned int r = 0; r < rows; ++r) dst[c][r] = src[r][c];
+ }
+
+ template <typename Mat>
+ inline void
+ fillMatrix(Mat& m, typename Mat::value_type val)
+ {
+ unsigned int const rows = m.num_rows();
+ unsigned int const cols = m.num_cols();
+ for (unsigned int c = 0; c < cols; ++c)
+ for (unsigned int r = 0; r < rows; ++r) m[r][c] = val;
+ }
+
+ template <typename Mat>
+ inline void
+ makeZeroMatrix(Mat& m)
+ {
+ fillMatrix(m, 0);
+ }
+
+ template <typename Mat>
+ inline void
+ makeIdentityMatrix(Mat& m)
+ {
+ makeZeroMatrix(m);
+ unsigned int const rows = m.num_rows();
+ unsigned int const cols = m.num_cols();
+ unsigned int n = std::min(rows, cols);
+ for (unsigned int i = 0; i < n; ++i)
+ m[i][i] = 1;
+ }
+
+ template <typename Mat, typename Vec>
+ inline void
+ makeCrossProductMatrix(Vec const& v, Mat& m)
+ {
+ assert(v.size() == 3);
+ assert(m.num_rows() == 3);
+ assert(m.num_cols() == 3);
+ m[0][0] = 0; m[0][1] = -v[2]; m[0][2] = v[1];
+ m[1][0] = v[2]; m[1][1] = 0; m[1][2] = -v[0];
+ m[2][0] = -v[1]; m[2][1] = v[0]; m[2][2] = 0;
+ }
+
+ template <typename Mat, typename Vec>
+ inline void
+ makeOuterProductMatrix(Vec const& v, Mat& m)
+ {
+ assert(m.num_cols() == m.num_rows());
+ assert(v.size() == m.num_cols());
+ unsigned const sz = v.size();
+ for (unsigned r = 0; r < sz; ++r)
+ for (unsigned c = 0; c < sz; ++c) m[r][c] = v[r]*v[c];
+ }
+
+ template <typename Mat, typename VecA, typename VecB>
+ inline void
+ makeOuterProductMatrix(VecA const& u, VecB const& v, Mat& m)
+ {
+ assert(m.num_cols() == m.num_rows());
+ assert(u.size() == m.num_cols());
+ assert(v.size() == m.num_cols());
+ unsigned const sz = u.size();
+ for (unsigned r = 0; r < sz; ++r)
+ for (unsigned c = 0; c < sz; ++c) m[r][c] = u[r]*v[c];
+ }
+
+ template <typename MatA, typename MatB, typename MatC>
+ void addMatrices(MatA const& a, MatB const& b, MatC& dst)
+ {
+ assert(a.num_cols() == b.num_cols());
+ assert(a.num_rows() == b.num_rows());
+ assert(dst.num_cols() == a.num_cols());
+ assert(dst.num_rows() == a.num_rows());
+
+ unsigned int const rows = a.num_rows();
+ unsigned int const cols = a.num_cols();
+
+ for (unsigned r = 0; r < rows; ++r)
+ for (unsigned c = 0; c < cols; ++c) dst[r][c] = a[r][c] + b[r][c];
+ }
+
+ template <typename MatA, typename MatB>
+ void addMatricesIP(MatA const& a, MatB& dst)
+ {
+ assert(dst.num_cols() == a.num_cols());
+ assert(dst.num_rows() == a.num_rows());
+
+ unsigned int const rows = a.num_rows();
+ unsigned int const cols = a.num_cols();
+
+ for (unsigned r = 0; r < rows; ++r)
+ for (unsigned c = 0; c < cols; ++c) dst[r][c] += a[r][c];
+ }
+
+ template <typename MatA, typename MatB, typename MatC>
+ void subtractMatrices(MatA const& a, MatB const& b, MatC& dst)
+ {
+ assert(a.num_cols() == b.num_cols());
+ assert(a.num_rows() == b.num_rows());
+ assert(dst.num_cols() == a.num_cols());
+ assert(dst.num_rows() == a.num_rows());
+
+ unsigned int const rows = a.num_rows();
+ unsigned int const cols = a.num_cols();
+
+ for (unsigned r = 0; r < rows; ++r)
+ for (unsigned c = 0; c < cols; ++c) dst[r][c] = a[r][c] - b[r][c];
+ }
+
+ template <typename MatA, typename Elem, typename MatB>
+ inline void
+ makeScaledMatrix(MatA const& m, Elem scale, MatB& dst)
+ {
+ unsigned int const rows = m.num_rows();
+ unsigned int const cols = m.num_cols();
+ for (unsigned int c = 0; c < cols; ++c)
+ for (unsigned int r = 0; r < rows; ++r) dst[r][c] = m[r][c] * scale;
+ }
+
+ template <typename Mat, typename Elem>
+ inline void
+ scaleMatrixIP(Elem scale, Mat& m)
+ {
+ unsigned int const rows = m.num_rows();
+ unsigned int const cols = m.num_cols();
+ for (unsigned int c = 0; c < cols; ++c)
+ for (unsigned int r = 0; r < rows; ++r) m[r][c] *= scale;
+ }
+
+ template <typename Mat, typename VecA, typename VecB>
+ inline void
+ multiply_A_v(Mat const& m, VecA const& in, VecB& dst)
+ {
+ unsigned int const rows = m.num_rows();
+ unsigned int const cols = m.num_cols();
+ assert(in.size() == cols);
+ assert(dst.size() == rows);
+
+ makeZeroVector(dst);
+
+ for (unsigned int r = 0; r < rows; ++r)
+ for (unsigned int c = 0; c < cols; ++c) dst[r] += m[r][c] * in[c];
+ }
+
+ template <typename Mat, typename VecA, typename VecB>
+ inline void
+ multiply_A_v_projective(Mat const& m, VecA const& in, VecB& dst)
+ {
+ unsigned int const rows = m.num_rows();
+ unsigned int const cols = m.num_cols();
+ assert(in.size() == cols-1);
+ assert(dst.size() == rows-1);
+
+ typename VecB::value_type w = m(rows-1, cols-1);
+ unsigned int r, i;
+ for (i = 0; i < cols-1; ++i) w += m(rows-1, i) * in[i];
+ for (r = 0; r < rows-1; ++r) dst[r] = m(r, cols-1);
+ for (r = 0; r < rows-1; ++r)
+ for (unsigned int c = 0; c < cols-1; ++c) dst[r] += m[r][c] * in[c];
+ for (i = 0; i < rows-1; ++i) dst[i] /= w;
+ }
+
+ template <typename Mat, typename VecA, typename VecB>
+ inline void
+ multiply_A_v_affine(Mat const& m, VecA const& in, VecB& dst)
+ {
+ unsigned int const rows = m.num_rows();
+ unsigned int const cols = m.num_cols();
+ assert(in.size() == cols-1);
+ assert(dst.size() == rows);
+
+ unsigned int r;
+
+ for (r = 0; r < rows; ++r) dst[r] = m(r, cols-1);
+ for (r = 0; r < rows; ++r)
+ for (unsigned int c = 0; c < cols-1; ++c) dst[r] += m[r][c] * in[c];
+ }
+
+ template <typename Mat, typename VecA, typename VecB>
+ inline void
+ multiply_At_v(Mat const& m, VecA const& in, VecB& dst)
+ {
+ unsigned int const rows = m.num_rows();
+ unsigned int const cols = m.num_cols();
+ assert(in.size() == rows);
+ assert(dst.size() == cols);
+
+ makeZeroVector(dst);
+ for (unsigned int c = 0; c < cols; ++c)
+ for (unsigned int r = 0; r < rows; ++r) dst[c] += m[r][c] * in[r];
+ }
+
+ template <typename MatA, typename MatB>
+ inline void
+ multiply_At_A(MatA const& a, MatB& dst)
+ {
+ assert(dst.num_rows() == a.num_cols());
+ assert(dst.num_cols() == a.num_cols());
+
+ typedef typename MatB::value_type Elem;
+
+ Elem accum;
+ for (unsigned int r = 0; r < a.num_cols(); ++r)
+ for (unsigned int c = 0; c < a.num_cols(); ++c)
+ {
+ accum = 0;
+ for (unsigned int k = 0; k < a.num_rows(); ++k) accum += a[k][r] * a[k][c];
+ dst[r][c] = accum;
+ }
+ }
+
+ template <typename MatA, typename MatB, typename MatC>
+ inline void
+ multiply_A_B(MatA const& a, MatB const& b, MatC& dst)
+ {
+ assert(a.num_cols() == b.num_rows());
+ assert(dst.num_rows() == a.num_rows());
+ assert(dst.num_cols() == b.num_cols());
+
+ typedef typename MatC::value_type Elem;
+
+ Elem accum;
+ for (unsigned int r = 0; r < a.num_rows(); ++r)
+ for (unsigned int c = 0; c < b.num_cols(); ++c)
+ {
+ accum = 0;
+ for (unsigned int k = 0; k < a.num_cols(); ++k) accum += a[r][k] * b[k][c];
+ dst[r][c] = accum;
+ }
+ }
+
+ template <typename MatA, typename MatB, typename MatC>
+ inline void
+ multiply_At_B(MatA const& a, MatB const& b, MatC& dst)
+ {
+ assert(a.num_rows() == b.num_rows());
+ assert(dst.num_rows() == a.num_cols());
+ assert(dst.num_cols() == b.num_cols());
+
+ typedef typename MatC::value_type Elem;
+
+ Elem accum;
+ for (unsigned int r = 0; r < a.num_cols(); ++r)
+ for (unsigned int c = 0; c < b.num_cols(); ++c)
+ {
+ accum = 0;
+ for (unsigned int k = 0; k < a.num_rows(); ++k) accum += a[k][r] * b[k][c];
+ dst[r][c] = accum;
+ }
+ }
+
+ template <typename MatA, typename MatB, typename MatC>
+ inline void
+ multiply_A_Bt(MatA const& a, MatB const& b, MatC& dst)
+ {
+ assert(a.num_cols() == b.num_cols());
+ assert(dst.num_rows() == a.num_rows());
+ assert(dst.num_cols() == b.num_rows());
+
+ typedef typename MatC::value_type Elem;
+
+ Elem accum;
+ for (unsigned int r = 0; r < a.num_rows(); ++r)
+ for (unsigned int c = 0; c < b.num_rows(); ++c)
+ {
+ accum = 0;
+ for (unsigned int k = 0; k < a.num_cols(); ++k) accum += a[r][k] * b[c][k];
+ dst[r][c] = accum;
+ }
+ }
+
+ template <typename Mat>
+ inline void
+ transposeMatrixIP(Mat& a)
+ {
+ assert(a.num_rows() == a.num_cols());
+
+ for (unsigned int r = 0; r < a.num_rows(); ++r)
+ for (unsigned int c = 0; c < r; ++c)
+ std::swap(a[r][c], a[c][r]);
+ }
+
+} // end namespace V3D
+
+#endif
diff --git a/extern/libmv/third_party/ssba/Math/v3d_linear_utils.h b/extern/libmv/third_party/ssba/Math/v3d_linear_utils.h
new file mode 100644
index 00000000000..969ec99694f
--- /dev/null
+++ b/extern/libmv/third_party/ssba/Math/v3d_linear_utils.h
@@ -0,0 +1,391 @@
+// -*- C++ -*-
+/*
+Copyright (c) 2008 University of North Carolina at Chapel Hill
+
+This file is part of SSBA (Simple Sparse Bundle Adjustment).
+
+SSBA is free software: you can redistribute it and/or modify it under the
+terms of the GNU Lesser General Public License as published by the Free
+Software Foundation, either version 3 of the License, or (at your option) any
+later version.
+
+SSBA is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
+A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
+details.
+
+You should have received a copy of the GNU Lesser General Public License along
+with SSBA. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef V3D_LINEAR_UTILS_H
+#define V3D_LINEAR_UTILS_H
+
+#include "Math/v3d_linear.h"
+
+#include <iostream>
+
+namespace V3D
+{
+
+ template <typename Elem, int Size>
+ struct InlineVector : public InlineVectorBase<Elem, Size>
+ {
+ }; // end struct InlineVector
+
+ template <typename Elem>
+ struct Vector : public VectorBase<Elem>
+ {
+ Vector()
+ : VectorBase<Elem>()
+ { }
+
+ Vector(unsigned int size)
+ : VectorBase<Elem>(size)
+ { }
+
+ Vector(unsigned int size, Elem * values)
+ : VectorBase<Elem>(size, values)
+ { }
+
+ Vector(Vector<Elem> const& a)
+ : VectorBase<Elem>(a)
+ { }
+
+ Vector<Elem>& operator=(Vector<Elem> const& a)
+ {
+ (VectorBase<Elem>::operator=)(a);
+ return *this;
+ }
+
+ Vector<Elem>& operator+=(Vector<Elem> const& rhs)
+ {
+ addVectorsIP(rhs, *this);
+ return *this;
+ }
+
+ Vector<Elem>& operator*=(Elem scale)
+ {
+ scaleVectorsIP(scale, *this);
+ return *this;
+ }
+
+ Vector<Elem> operator+(Vector<Elem> const& rhs) const
+ {
+ Vector<Elem> res(this->size());
+ addVectors(*this, rhs, res);
+ return res;
+ }
+
+ Vector<Elem> operator-(Vector<Elem> const& rhs) const
+ {
+ Vector<Elem> res(this->size());
+ subtractVectors(*this, rhs, res);
+ return res;
+ }
+
+ Elem operator*(Vector<Elem> const& rhs) const
+ {
+ return innerProduct(*this, rhs);
+ }
+
+ }; // end struct Vector
+
+ template <typename Elem, int Rows, int Cols>
+ struct InlineMatrix : public InlineMatrixBase<Elem, Rows, Cols>
+ {
+ }; // end struct InlineMatrix
+
+ template <typename Elem>
+ struct Matrix : public MatrixBase<Elem>
+ {
+ Matrix()
+ : MatrixBase<Elem>()
+ { }
+
+ Matrix(unsigned int rows, unsigned int cols)
+ : MatrixBase<Elem>(rows, cols)
+ { }
+
+ Matrix(unsigned int rows, unsigned int cols, Elem * values)
+ : MatrixBase<Elem>(rows, cols, values)
+ { }
+
+ Matrix(Matrix<Elem> const& a)
+ : MatrixBase<Elem>(a)
+ { }
+
+ Matrix<Elem>& operator=(Matrix<Elem> const& a)
+ {
+ (MatrixBase<Elem>::operator=)(a);
+ return *this;
+ }
+
+ Matrix<Elem>& operator+=(Matrix<Elem> const& rhs)
+ {
+ addMatricesIP(rhs, *this);
+ return *this;
+ }
+
+ Matrix<Elem>& operator*=(Elem scale)
+ {
+ scaleMatrixIP(scale, *this);
+ return *this;
+ }
+
+ Matrix<Elem> operator+(Matrix<Elem> const& rhs) const
+ {
+ Matrix<Elem> res(this->num_rows(), this->num_cols());
+ addMatrices(*this, rhs, res);
+ return res;
+ }
+
+ Matrix<Elem> operator-(Matrix<Elem> const& rhs) const
+ {
+ Matrix<Elem> res(this->num_rows(), this->num_cols());
+ subtractMatrices(*this, rhs, res);
+ return res;
+ }
+
+ }; // end struct Matrix
+
+//----------------------------------------------------------------------
+
+ typedef InlineVector<float, 2> Vector2f;
+ typedef InlineVector<double, 2> Vector2d;
+ typedef InlineVector<float, 3> Vector3f;
+ typedef InlineVector<double, 3> Vector3d;
+ typedef InlineVector<float, 4> Vector4f;
+ typedef InlineVector<double, 4> Vector4d;
+
+ typedef InlineMatrix<float, 2, 2> Matrix2x2f;
+ typedef InlineMatrix<double, 2, 2> Matrix2x2d;
+ typedef InlineMatrix<float, 3, 3> Matrix3x3f;
+ typedef InlineMatrix<double, 3, 3> Matrix3x3d;
+ typedef InlineMatrix<float, 4, 4> Matrix4x4f;
+ typedef InlineMatrix<double, 4, 4> Matrix4x4d;
+
+ typedef InlineMatrix<float, 2, 3> Matrix2x3f;
+ typedef InlineMatrix<double, 2, 3> Matrix2x3d;
+ typedef InlineMatrix<float, 3, 4> Matrix3x4f;
+ typedef InlineMatrix<double, 3, 4> Matrix3x4d;
+
+ template <typename Elem>
+ struct VectorArray
+ {
+ VectorArray(unsigned count, unsigned size)
+ : _count(count), _size(size), _values(0), _vectors(0)
+ {
+ unsigned const nTotal = _count * _size;
+ if (count > 0) _vectors = new Vector<Elem>[count];
+ if (nTotal > 0) _values = new Elem[nTotal];
+ for (unsigned i = 0; i < _count; ++i) new (&_vectors[i]) Vector<Elem>(_size, _values + i*_size);
+ }
+
+ VectorArray(unsigned count, unsigned size, Elem initVal)
+ : _count(count), _size(size), _values(0), _vectors(0)
+ {
+ unsigned const nTotal = _count * _size;
+ if (count > 0) _vectors = new Vector<Elem>[count];
+ if (nTotal > 0) _values = new Elem[nTotal];
+ for (unsigned i = 0; i < _count; ++i) new (&_vectors[i]) Vector<Elem>(_size, _values + i*_size);
+ std::fill(_values, _values + nTotal, initVal);
+ }
+
+ ~VectorArray()
+ {
+ delete [] _values;
+ delete [] _vectors;
+ }
+
+ unsigned count() const { return _count; }
+ unsigned size() const { return _size; }
+
+ //! Get the submatrix at position ix
+ Vector<Elem> const& operator[](unsigned ix) const
+ {
+ return _vectors[ix];
+ }
+
+ //! Get the submatrix at position ix
+ Vector<Elem>& operator[](unsigned ix)
+ {
+ return _vectors[ix];
+ }
+
+ protected:
+ unsigned _count, _size;
+ Elem * _values;
+ Vector<Elem> * _vectors;
+
+ private:
+ VectorArray(VectorArray const&);
+ void operator=(VectorArray const&);
+ };
+
+ template <typename Elem>
+ struct MatrixArray
+ {
+ MatrixArray(unsigned count, unsigned nRows, unsigned nCols)
+ : _count(count), _rows(nRows), _columns(nCols), _values(0), _matrices(0)
+ {
+ unsigned const nTotal = _count * _rows * _columns;
+ if (count > 0) _matrices = new Matrix<Elem>[count];
+ if (nTotal > 0) _values = new double[nTotal];
+ for (unsigned i = 0; i < _count; ++i)
+ new (&_matrices[i]) Matrix<Elem>(_rows, _columns, _values + i*(_rows*_columns));
+ }
+
+ ~MatrixArray()
+ {
+ delete [] _matrices;
+ delete [] _values;
+ }
+
+ //! Get the submatrix at position ix
+ Matrix<Elem> const& operator[](unsigned ix) const
+ {
+ return _matrices[ix];
+ }
+
+ //! Get the submatrix at position ix
+ Matrix<Elem>& operator[](unsigned ix)
+ {
+ return _matrices[ix];
+ }
+
+ unsigned count() const { return _count; }
+ unsigned num_rows() const { return _rows; }
+ unsigned num_cols() const { return _columns; }
+
+ protected:
+ unsigned _count, _rows, _columns;
+ double * _values;
+ Matrix<Elem> * _matrices;
+
+ private:
+ MatrixArray(MatrixArray const&);
+ void operator=(MatrixArray const&);
+ };
+
+//----------------------------------------------------------------------
+
+ template <typename Elem, int Size>
+ inline InlineVector<Elem, Size>
+ operator+(InlineVector<Elem, Size> const& v, InlineVector<Elem, Size> const& w)
+ {
+ InlineVector<Elem, Size> res;
+ addVectors(v, w, res);
+ return res;
+ }
+
+ template <typename Elem, int Size>
+ inline InlineVector<Elem, Size>
+ operator-(InlineVector<Elem, Size> const& v, InlineVector<Elem, Size> const& w)
+ {
+ InlineVector<Elem, Size> res;
+ subtractVectors(v, w, res);
+ return res;
+ }
+
+ template <typename Elem, int Size>
+ inline InlineVector<Elem, Size>
+ operator*(Elem scale, InlineVector<Elem, Size> const& v)
+ {
+ InlineVector<Elem, Size> res;
+ scaleVector(scale, v, res);
+ return res;
+ }
+
+ template <typename Elem, int Rows, int Cols>
+ inline InlineVector<Elem, Rows>
+ operator*(InlineMatrix<Elem, Rows, Cols> const& A, InlineVector<Elem, Cols> const& v)
+ {
+ InlineVector<Elem, Rows> res;
+ multiply_A_v(A, v, res);
+ return res;
+ }
+
+ template <typename Elem, int RowsA, int ColsA, int ColsB>
+ inline InlineMatrix<Elem, RowsA, ColsB>
+ operator*(InlineMatrix<Elem, RowsA, ColsA> const& A, InlineMatrix<Elem, ColsA, ColsB> const& B)
+ {
+ InlineMatrix<Elem, RowsA, ColsB> res;
+ multiply_A_B(A, B, res);
+ return res;
+ }
+
+ template <typename Elem, int Rows, int Cols>
+ inline InlineMatrix<Elem, Cols, Rows>
+ transposedMatrix(InlineMatrix<Elem, Rows, Cols> const& A)
+ {
+ InlineMatrix<Elem, Cols, Rows> At;
+ makeTransposedMatrix(A, At);
+ return At;
+ }
+
+ template <typename Elem>
+ inline InlineMatrix<Elem, 3, 3>
+ invertedMatrix(InlineMatrix<Elem, 3, 3> const& A)
+ {
+ Elem a = A[0][0], b = A[0][1], c = A[0][2];
+ Elem d = A[1][0], e = A[1][1], f = A[1][2];
+ Elem g = A[2][0], h = A[2][1], i = A[2][2];
+
+ Elem const det = a*e*i + b*f*g + c*d*h - c*e*g - b*d*i - a*f*h;
+
+ InlineMatrix<Elem, 3, 3> res;
+ res[0][0] = e*i-f*h; res[0][1] = c*h-b*i; res[0][2] = b*f-c*e;
+ res[1][0] = f*g-d*i; res[1][1] = a*i-c*g; res[1][2] = c*d-a*f;
+ res[2][0] = d*h-e*g; res[2][1] = b*g-a*h; res[2][2] = a*e-b*d;
+
+ scaleMatrixIP(1.0/det, res);
+ return res;
+ }
+
+ template <typename Elem>
+ inline InlineVector<Elem, 2>
+ makeVector2(Elem a, Elem b)
+ {
+ InlineVector<Elem, 2> res;
+ res[0] = a; res[1] = b;
+ return res;
+ }
+
+ template <typename Elem>
+ inline InlineVector<Elem, 3>
+ makeVector3(Elem a, Elem b, Elem c)
+ {
+ InlineVector<Elem, 3> res;
+ res[0] = a; res[1] = b; res[2] = c;
+ return res;
+ }
+
+ template <typename Vec>
+ inline void
+ displayVector(Vec const& v)
+ {
+ using namespace std;
+
+ for (int r = 0; r < v.size(); ++r)
+ cout << v[r] << " ";
+ cout << endl;
+ }
+
+ template <typename Mat>
+ inline void
+ displayMatrix(Mat const& A)
+ {
+ using namespace std;
+
+ for (int r = 0; r < A.num_rows(); ++r)
+ {
+ for (int c = 0; c < A.num_cols(); ++c)
+ cout << A[r][c] << " ";
+ cout << endl;
+ }
+ }
+
+} // end namespace V3D
+
+#endif
diff --git a/extern/libmv/third_party/ssba/Math/v3d_mathutilities.h b/extern/libmv/third_party/ssba/Math/v3d_mathutilities.h
new file mode 100644
index 00000000000..9e38b92a94b
--- /dev/null
+++ b/extern/libmv/third_party/ssba/Math/v3d_mathutilities.h
@@ -0,0 +1,59 @@
+// -*- C++ -*-
+/*
+Copyright (c) 2008 University of North Carolina at Chapel Hill
+
+This file is part of SSBA (Simple Sparse Bundle Adjustment).
+
+SSBA is free software: you can redistribute it and/or modify it under the
+terms of the GNU Lesser General Public License as published by the Free
+Software Foundation, either version 3 of the License, or (at your option) any
+later version.
+
+SSBA is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
+A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
+details.
+
+You should have received a copy of the GNU Lesser General Public License along
+with SSBA. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef V3D_MATH_UTILITIES_H
+#define V3D_MATH_UTILITIES_H
+
+#include "Math/v3d_linear.h"
+#include "Math/v3d_linear_utils.h"
+
+#include <vector>
+
+namespace V3D
+{
+
+ template <typename Vec, typename Mat>
+ inline void
+ createRotationMatrixRodriguez(Vec const& omega, Mat& R)
+ {
+ assert(omega.size() == 3);
+ assert(R.num_rows() == 3);
+ assert(R.num_cols() == 3);
+
+ double const theta = norm_L2(omega);
+ makeIdentityMatrix(R);
+ if (fabs(theta) > 1e-6)
+ {
+ Matrix3x3d J, J2;
+ makeCrossProductMatrix(omega, J);
+ multiply_A_B(J, J, J2);
+ double const c1 = sin(theta)/theta;
+ double const c2 = (1-cos(theta))/(theta*theta);
+ for (int i = 0; i < 3; ++i)
+ for (int j = 0; j < 3; ++j)
+ R[i][j] += c1*J[i][j] + c2*J2[i][j];
+ }
+ } // end createRotationMatrixRodriguez()
+
+ template <typename T> inline double sqr(T x) { return x*x; }
+
+} // namespace V3D
+
+#endif
diff --git a/extern/libmv/third_party/ssba/Math/v3d_optimization.cpp b/extern/libmv/third_party/ssba/Math/v3d_optimization.cpp
new file mode 100644
index 00000000000..234815fcd1f
--- /dev/null
+++ b/extern/libmv/third_party/ssba/Math/v3d_optimization.cpp
@@ -0,0 +1,955 @@
+/*
+Copyright (c) 2008 University of North Carolina at Chapel Hill
+
+This file is part of SSBA (Simple Sparse Bundle Adjustment).
+
+SSBA is free software: you can redistribute it and/or modify it under the
+terms of the GNU Lesser General Public License as published by the Free
+Software Foundation, either version 3 of the License, or (at your option) any
+later version.
+
+SSBA is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
+A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
+details.
+
+You should have received a copy of the GNU Lesser General Public License along
+with SSBA. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "Math/v3d_optimization.h"
+
+#if defined(V3DLIB_ENABLE_SUITESPARSE)
+//# include "COLAMD/Include/colamd.h"
+# include "colamd.h"
+extern "C"
+{
+//# include "LDL/Include/ldl.h"
+# include "ldl.h"
+}
+#endif
+
+#include <iostream>
+#include <map>
+
+#define USE_BLOCK_REORDERING 1
+#define USE_MULTIPLICATIVE_UPDATE 1
+
+using namespace std;
+
+namespace
+{
+
+ using namespace V3D;
+
+ inline double
+ squaredResidual(VectorArray<double> const& e)
+ {
+ int const N = e.count();
+ int const M = e.size();
+
+ double res = 0.0;
+
+ for (int n = 0; n < N; ++n)
+ for (int m = 0; m < M; ++m)
+ res += e[n][m] * e[n][m];
+
+ return res;
+ } // end squaredResidual()
+
+} // end namespace <>
+
+namespace V3D
+{
+
+ int optimizerVerbosenessLevel = 0;
+
+#if defined(V3DLIB_ENABLE_SUITESPARSE)
+
+ void
+ SparseLevenbergOptimizer::setupSparseJtJ()
+ {
+ int const nVaryingA = _nParametersA - _nNonvaryingA;
+ int const nVaryingB = _nParametersB - _nNonvaryingB;
+ int const nVaryingC = _paramDimensionC - _nNonvaryingC;
+
+ int const bColumnStart = nVaryingA*_paramDimensionA;
+ int const cColumnStart = bColumnStart + nVaryingB*_paramDimensionB;
+ int const nColumns = cColumnStart + nVaryingC;
+
+ _jointNonzerosW.clear();
+ _jointIndexW.resize(_nMeasurements);
+#if 1
+ {
+ map<pair<int, int>, int> jointNonzeroMap;
+ for (size_t k = 0; k < _nMeasurements; ++k)
+ {
+ int const i = _correspondingParamA[k] - _nNonvaryingA;
+ int const j = _correspondingParamB[k] - _nNonvaryingB;
+ if (i >= 0 && j >= 0)
+ {
+ map<pair<int, int>, int>::const_iterator p = jointNonzeroMap.find(make_pair(i, j));
+ if (p == jointNonzeroMap.end())
+ {
+ jointNonzeroMap.insert(make_pair(make_pair(i, j), _jointNonzerosW.size()));
+ _jointIndexW[k] = _jointNonzerosW.size();
+ _jointNonzerosW.push_back(make_pair(i, j));
+ }
+ else
+ {
+ _jointIndexW[k] = (*p).second;
+ } // end if
+ } // end if
+ } // end for (k)
+ } // end scope
+#else
+ for (size_t k = 0; k < _nMeasurements; ++k)
+ {
+ int const i = _correspondingParamA[k] - _nNonvaryingA;
+ int const j = _correspondingParamB[k] - _nNonvaryingB;
+ if (i >= 0 && j >= 0)
+ {
+ _jointIndexW[k] = _jointNonzerosW.size();
+ _jointNonzerosW.push_back(make_pair(i, j));
+ }
+ } // end for (k)
+#endif
+
+#if defined(USE_BLOCK_REORDERING)
+ int const bBlockColumnStart = nVaryingA;
+ int const cBlockColumnStart = bBlockColumnStart + nVaryingB;
+
+ int const nBlockColumns = cBlockColumnStart + ((nVaryingC > 0) ? 1 : 0);
+
+ //cout << "nBlockColumns = " << nBlockColumns << endl;
+
+ // For the column reordering we treat the columns belonging to one set
+ // of parameters as one (logical) column.
+
+ // Determine non-zeros of JtJ (we forget about the non-zero diagonal for now)
+ // Only consider nonzeros of Ai^t * Bj induced by the measurements.
+ vector<pair<int, int> > nz_blockJtJ(_jointNonzerosW.size());
+ for (int k = 0; k < _jointNonzerosW.size(); ++k)
+ {
+ nz_blockJtJ[k].first = _jointNonzerosW[k].second + bBlockColumnStart;
+ nz_blockJtJ[k].second = _jointNonzerosW[k].first;
+ }
+
+ if (nVaryingC > 0)
+ {
+ // We assume, that the global unknowns are linked to every other variable.
+ for (int i = 0; i < nVaryingA; ++i)
+ nz_blockJtJ.push_back(make_pair(cBlockColumnStart, i));
+ for (int j = 0; j < nVaryingB; ++j)
+ nz_blockJtJ.push_back(make_pair(cBlockColumnStart, j + bBlockColumnStart));
+ } // end if
+
+ int const nnzBlock = nz_blockJtJ.size();
+
+ vector<int> permBlockJtJ(nBlockColumns + 1);
+
+ if (nnzBlock > 0)
+ {
+// cout << "nnzBlock = " << nnzBlock << endl;
+
+ CCS_Matrix<int> blockJtJ(nBlockColumns, nBlockColumns, nz_blockJtJ);
+
+// cout << " nz_blockJtJ: " << endl;
+// for (size_t k = 0; k < nz_blockJtJ.size(); ++k)
+// cout << " " << nz_blockJtJ[k].first << ":" << nz_blockJtJ[k].second << endl;
+// cout << endl;
+
+ int * colStarts = (int *)blockJtJ.getColumnStarts();
+ int * rowIdxs = (int *)blockJtJ.getRowIndices();
+
+// cout << "blockJtJ_colStarts = ";
+// for (int k = 0; k <= nBlockColumns; ++k) cout << colStarts[k] << " ";
+// cout << endl;
+
+// cout << "blockJtJ_rowIdxs = ";
+// for (int k = 0; k < nnzBlock; ++k) cout << rowIdxs[k] << " ";
+// cout << endl;
+
+ int stats[COLAMD_STATS];
+ symamd(nBlockColumns, rowIdxs, colStarts, &permBlockJtJ[0], (double *) NULL, stats, &calloc, &free);
+ if (optimizerVerbosenessLevel >= 2) symamd_report(stats);
+ }
+ else
+ {
+ for (int k = 0; k < permBlockJtJ.size(); ++k) permBlockJtJ[k] = k;
+ } // end if
+
+// cout << "permBlockJtJ = ";
+// for (int k = 0; k < permBlockJtJ.size(); ++k)
+// cout << permBlockJtJ[k] << " ";
+// cout << endl;
+
+ // From the determined symbolic permutation with logical variables, determine the actual ordering
+ _perm_JtJ.resize(nVaryingA*_paramDimensionA + nVaryingB*_paramDimensionB + nVaryingC + 1);
+
+ int curDstCol = 0;
+ for (int k = 0; k < permBlockJtJ.size()-1; ++k)
+ {
+ int const srcCol = permBlockJtJ[k];
+ if (srcCol < nVaryingA)
+ {
+ for (int n = 0; n < _paramDimensionA; ++n)
+ _perm_JtJ[curDstCol + n] = srcCol*_paramDimensionA + n;
+ curDstCol += _paramDimensionA;
+ }
+ else if (srcCol >= bBlockColumnStart && srcCol < cBlockColumnStart)
+ {
+ int const bStart = nVaryingA*_paramDimensionA;
+ int const j = srcCol - bBlockColumnStart;
+
+ for (int n = 0; n < _paramDimensionB; ++n)
+ _perm_JtJ[curDstCol + n] = bStart + j*_paramDimensionB + n;
+ curDstCol += _paramDimensionB;
+ }
+ else if (srcCol == cBlockColumnStart)
+ {
+ int const cStart = nVaryingA*_paramDimensionA + nVaryingB*_paramDimensionB;
+
+ for (int n = 0; n < nVaryingC; ++n)
+ _perm_JtJ[curDstCol + n] = cStart + n;
+ curDstCol += nVaryingC;
+ }
+ else
+ {
+ cerr << "Should not reach " << __LINE__ << ":" << __LINE__ << "!" << endl;
+ assert(false);
+ }
+ }
+#else
+ vector<pair<int, int> > nz, nzL;
+ this->serializeNonZerosJtJ(nz);
+
+ for (int k = 0; k < nz.size(); ++k)
+ {
+ // Swap rows and columns, since serializeNonZerosJtJ() generates the
+ // upper triangular part but symamd wants the lower triangle.
+ nzL.push_back(make_pair(nz[k].second, nz[k].first));
+ }
+
+ _perm_JtJ.resize(nColumns+1);
+
+ if (nzL.size() > 0)
+ {
+ CCS_Matrix<int> symbJtJ(nColumns, nColumns, nzL);
+
+ int * colStarts = (int *)symbJtJ.getColumnStarts();
+ int * rowIdxs = (int *)symbJtJ.getRowIndices();
+
+// cout << "symbJtJ_colStarts = ";
+// for (int k = 0; k <= nColumns; ++k) cout << colStarts[k] << " ";
+// cout << endl;
+
+// cout << "symbJtJ_rowIdxs = ";
+// for (int k = 0; k < nzL.size(); ++k) cout << rowIdxs[k] << " ";
+// cout << endl;
+
+ int stats[COLAMD_STATS];
+ symamd(nColumns, rowIdxs, colStarts, &_perm_JtJ[0], (double *) NULL, stats, &calloc, &free);
+ if (optimizerVerbosenessLevel >= 2) symamd_report(stats);
+ }
+ else
+ {
+ for (int k = 0; k < _perm_JtJ.size(); ++k) _perm_JtJ[k] = k;
+ } //// end if
+#endif
+ _perm_JtJ.back() = _perm_JtJ.size() - 1;
+
+// cout << "_perm_JtJ = ";
+// for (int k = 0; k < _perm_JtJ.size(); ++k) cout << _perm_JtJ[k] << " ";
+// cout << endl;
+
+ // Finally, compute the inverse of the full permutation.
+ _invPerm_JtJ.resize(_perm_JtJ.size());
+ for (size_t k = 0; k < _perm_JtJ.size(); ++k)
+ _invPerm_JtJ[_perm_JtJ[k]] = k;
+
+ vector<pair<int, int> > nz_JtJ;
+ this->serializeNonZerosJtJ(nz_JtJ);
+
+ for (int k = 0; k < nz_JtJ.size(); ++k)
+ {
+ int const i = nz_JtJ[k].first;
+ int const j = nz_JtJ[k].second;
+
+ int pi = _invPerm_JtJ[i];
+ int pj = _invPerm_JtJ[j];
+ // Swap values if in lower triangular part
+ if (pi > pj) std::swap(pi, pj);
+ nz_JtJ[k].first = pi;
+ nz_JtJ[k].second = pj;
+ }
+
+ int const nnz = nz_JtJ.size();
+
+// cout << "nz_JtJ = ";
+// for (int k = 0; k < nnz; ++k) cout << nz_JtJ[k].first << ":" << nz_JtJ[k].second << " ";
+// cout << endl;
+
+ _JtJ.create(nColumns, nColumns, nz_JtJ);
+
+// cout << "_colStart_JtJ = ";
+// for (int k = 0; k < _JtJ.num_cols(); ++k) cout << _JtJ.getColumnStarts()[k] << " ";
+// cout << endl;
+
+// cout << "_rowIdxs_JtJ = ";
+// for (int k = 0; k < nnz; ++k) cout << _JtJ.getRowIndices()[k] << " ";
+// cout << endl;
+
+ vector<int> workFlags(nColumns);
+
+ _JtJ_Lp.resize(nColumns+1);
+ _JtJ_Parent.resize(nColumns);
+ _JtJ_Lnz.resize(nColumns);
+
+ ldl_symbolic(nColumns, (int *)_JtJ.getColumnStarts(), (int *)_JtJ.getRowIndices(),
+ &_JtJ_Lp[0], &_JtJ_Parent[0], &_JtJ_Lnz[0],
+ &workFlags[0], NULL, NULL);
+
+ if (optimizerVerbosenessLevel >= 1)
+ cout << "SparseLevenbergOptimizer: Nonzeros in LDL decomposition: " << _JtJ_Lp[nColumns] << endl;
+
+ } // end SparseLevenbergOptimizer::setupSparseJtJ()
+
+ void
+ SparseLevenbergOptimizer::serializeNonZerosJtJ(vector<pair<int, int> >& dst) const
+ {
+ int const nVaryingA = _nParametersA - _nNonvaryingA;
+ int const nVaryingB = _nParametersB - _nNonvaryingB;
+ int const nVaryingC = _paramDimensionC - _nNonvaryingC;
+
+ int const bColumnStart = nVaryingA*_paramDimensionA;
+ int const cColumnStart = bColumnStart + nVaryingB*_paramDimensionB;
+
+ dst.clear();
+
+ // Add the diagonal block matrices (only the upper triangular part).
+
+ // Ui submatrices of JtJ
+ for (int i = 0; i < nVaryingA; ++i)
+ {
+ int const i0 = i * _paramDimensionA;
+
+ for (int c = 0; c < _paramDimensionA; ++c)
+ for (int r = 0; r <= c; ++r)
+ dst.push_back(make_pair(i0 + r, i0 + c));
+ }
+
+ // Vj submatrices of JtJ
+ for (int j = 0; j < nVaryingB; ++j)
+ {
+ int const j0 = j*_paramDimensionB + bColumnStart;
+
+ for (int c = 0; c < _paramDimensionB; ++c)
+ for (int r = 0; r <= c; ++r)
+ dst.push_back(make_pair(j0 + r, j0 + c));
+ }
+
+ // Z submatrix of JtJ
+ for (int c = 0; c < nVaryingC; ++c)
+ for (int r = 0; r <= c; ++r)
+ dst.push_back(make_pair(cColumnStart + r, cColumnStart + c));
+
+ // Add the elements i and j linked by an observation k
+ // W submatrix of JtJ
+ for (size_t n = 0; n < _jointNonzerosW.size(); ++n)
+ {
+ int const i0 = _jointNonzerosW[n].first;
+ int const j0 = _jointNonzerosW[n].second;
+ int const r0 = i0*_paramDimensionA;
+ int const c0 = j0*_paramDimensionB + bColumnStart;
+
+ for (int r = 0; r < _paramDimensionA; ++r)
+ for (int c = 0; c < _paramDimensionB; ++c)
+ dst.push_back(make_pair(r0 + r, c0 + c));
+ } // end for (n)
+
+ if (nVaryingC > 0)
+ {
+ // Finally, add the dense columns linking i (resp. j) with the global parameters.
+ // X submatrix of JtJ
+ for (int i = 0; i < nVaryingA; ++i)
+ {
+ int const i0 = i*_paramDimensionA;
+
+ for (int r = 0; r < _paramDimensionA; ++r)
+ for (int c = 0; c < nVaryingC; ++c)
+ dst.push_back(make_pair(i0 + r, cColumnStart + c));
+ }
+
+ // Y submatrix of JtJ
+ for (int j = 0; j < nVaryingB; ++j)
+ {
+ int const j0 = j*_paramDimensionB + bColumnStart;
+
+ for (int r = 0; r < _paramDimensionB; ++r)
+ for (int c = 0; c < nVaryingC; ++c)
+ dst.push_back(make_pair(j0 + r, cColumnStart + c));
+ }
+ } // end if
+ } // end SparseLevenbergOptimizer::serializeNonZerosJtJ()
+
+ void
+ SparseLevenbergOptimizer::fillSparseJtJ(MatrixArray<double> const& Ui,
+ MatrixArray<double> const& Vj,
+ MatrixArray<double> const& Wn,
+ Matrix<double> const& Z,
+ Matrix<double> const& X,
+ Matrix<double> const& Y)
+ {
+ int const nVaryingA = _nParametersA - _nNonvaryingA;
+ int const nVaryingB = _nParametersB - _nNonvaryingB;
+ int const nVaryingC = _paramDimensionC - _nNonvaryingC;
+
+ int const bColumnStart = nVaryingA*_paramDimensionA;
+ int const cColumnStart = bColumnStart + nVaryingB*_paramDimensionB;
+
+ int const nCols = _JtJ.num_cols();
+ int const nnz = _JtJ.getNonzeroCount();
+
+ // The following has to replicate the procedure as in serializeNonZerosJtJ()
+
+ int serial = 0;
+
+ double * values = _JtJ.getValues();
+ int const * destIdxs = _JtJ.getDestIndices();
+
+ // Add the diagonal block matrices (only the upper triangular part).
+
+ // Ui submatrices of JtJ
+ for (int i = 0; i < nVaryingA; ++i)
+ {
+ int const i0 = i * _paramDimensionA;
+
+ for (int c = 0; c < _paramDimensionA; ++c)
+ for (int r = 0; r <= c; ++r, ++serial)
+ values[destIdxs[serial]] = Ui[i][r][c];
+ }
+
+ // Vj submatrices of JtJ
+ for (int j = 0; j < nVaryingB; ++j)
+ {
+ int const j0 = j*_paramDimensionB + bColumnStart;
+
+ for (int c = 0; c < _paramDimensionB; ++c)
+ for (int r = 0; r <= c; ++r, ++serial)
+ values[destIdxs[serial]] = Vj[j][r][c];
+ }
+
+ // Z submatrix of JtJ
+ for (int c = 0; c < nVaryingC; ++c)
+ for (int r = 0; r <= c; ++r, ++serial)
+ values[destIdxs[serial]] = Z[r][c];
+
+ // Add the elements i and j linked by an observation k
+ // W submatrix of JtJ
+ for (size_t n = 0; n < _jointNonzerosW.size(); ++n)
+ {
+ for (int r = 0; r < _paramDimensionA; ++r)
+ for (int c = 0; c < _paramDimensionB; ++c, ++serial)
+ values[destIdxs[serial]] = Wn[n][r][c];
+ } // end for (k)
+
+ if (nVaryingC > 0)
+ {
+ // Finally, add the dense columns linking i (resp. j) with the global parameters.
+ // X submatrix of JtJ
+ for (int i = 0; i < nVaryingA; ++i)
+ {
+ int const r0 = i * _paramDimensionA;
+ for (int r = 0; r < _paramDimensionA; ++r)
+ for (int c = 0; c < nVaryingC; ++c, ++serial)
+ values[destIdxs[serial]] = X[r0+r][c];
+ }
+
+ // Y submatrix of JtJ
+ for (int j = 0; j < nVaryingB; ++j)
+ {
+ int const r0 = j * _paramDimensionB;
+ for (int r = 0; r < _paramDimensionB; ++r)
+ for (int c = 0; c < nVaryingC; ++c, ++serial)
+ values[destIdxs[serial]] = Y[r0+r][c];
+ }
+ } // end if
+ } // end SparseLevenbergOptimizer::fillSparseJtJ()
+
+ void
+ SparseLevenbergOptimizer::minimize()
+ {
+ status = LEVENBERG_OPTIMIZER_TIMEOUT;
+ bool computeDerivatives = true;
+
+ int const nVaryingA = _nParametersA - _nNonvaryingA;
+ int const nVaryingB = _nParametersB - _nNonvaryingB;
+ int const nVaryingC = _paramDimensionC - _nNonvaryingC;
+
+ if (nVaryingA == 0 && nVaryingB == 0 && nVaryingC == 0)
+ {
+ // No degrees of freedom, nothing to optimize.
+ status = LEVENBERG_OPTIMIZER_CONVERGED;
+ return;
+ }
+
+ this->setupSparseJtJ();
+
+ Vector<double> weights(_nMeasurements);
+
+ MatrixArray<double> Ak(_nMeasurements, _measurementDimension, _paramDimensionA);
+ MatrixArray<double> Bk(_nMeasurements, _measurementDimension, _paramDimensionB);
+ MatrixArray<double> Ck(_nMeasurements, _measurementDimension, _paramDimensionC);
+
+ MatrixArray<double> Ui(nVaryingA, _paramDimensionA, _paramDimensionA);
+ MatrixArray<double> Vj(nVaryingB, _paramDimensionB, _paramDimensionB);
+
+ // Wn = Ak^t*Bk
+ MatrixArray<double> Wn(_jointNonzerosW.size(), _paramDimensionA, _paramDimensionB);
+
+ Matrix<double> Z(nVaryingC, nVaryingC);
+
+ // X = A^t*C
+ Matrix<double> X(nVaryingA*_paramDimensionA, nVaryingC);
+ // Y = B^t*C
+ Matrix<double> Y(nVaryingB*_paramDimensionB, nVaryingC);
+
+ VectorArray<double> residuals(_nMeasurements, _measurementDimension);
+ VectorArray<double> residuals2(_nMeasurements, _measurementDimension);
+
+ VectorArray<double> diagUi(nVaryingA, _paramDimensionA);
+ VectorArray<double> diagVj(nVaryingB, _paramDimensionB);
+ Vector<double> diagZ(nVaryingC);
+
+ VectorArray<double> At_e(nVaryingA, _paramDimensionA);
+ VectorArray<double> Bt_e(nVaryingB, _paramDimensionB);
+ Vector<double> Ct_e(nVaryingC);
+
+ Vector<double> Jt_e(nVaryingA*_paramDimensionA + nVaryingB*_paramDimensionB + nVaryingC);
+
+ Vector<double> delta(nVaryingA*_paramDimensionA + nVaryingB*_paramDimensionB + nVaryingC);
+ Vector<double> deltaPerm(nVaryingA*_paramDimensionA + nVaryingB*_paramDimensionB + nVaryingC);
+
+ VectorArray<double> deltaAi(_nParametersA, _paramDimensionA);
+ VectorArray<double> deltaBj(_nParametersB, _paramDimensionB);
+ Vector<double> deltaC(_paramDimensionC);
+
+ double err = 0.0;
+
+ for (currentIteration = 0; currentIteration < maxIterations; ++currentIteration)
+ {
+ if (optimizerVerbosenessLevel >= 2)
+ cout << "SparseLevenbergOptimizer: currentIteration: " << currentIteration << endl;
+ if (computeDerivatives)
+ {
+ this->evalResidual(residuals);
+ this->fillWeights(residuals, weights);
+ for (int k = 0; k < _nMeasurements; ++k)
+ scaleVectorIP(weights[k], residuals[k]);
+
+ err = squaredResidual(residuals);
+
+ if (optimizerVerbosenessLevel >= 1) cout << "SparseLevenbergOptimizer: |residual|^2 = " << err << endl;
+ if (optimizerVerbosenessLevel >= 2) cout << "SparseLevenbergOptimizer: lambda = " << lambda << endl;
+
+ for (int k = 0; k < residuals.count(); ++k) scaleVectorIP(-1.0, residuals[k]);
+
+ this->setupJacobianGathering();
+ this->fillAllJacobians(weights, Ak, Bk, Ck);
+
+ // Compute the different parts of J^t*e
+ if (nVaryingA > 0)
+ {
+ for (int i = 0; i < nVaryingA; ++i) makeZeroVector(At_e[i]);
+
+ Vector<double> tmp(_paramDimensionA);
+
+ for (int k = 0; k < _nMeasurements; ++k)
+ {
+ int const i = _correspondingParamA[k] - _nNonvaryingA;
+ if (i < 0) continue;
+ multiply_At_v(Ak[k], residuals[k], tmp);
+ addVectors(tmp, At_e[i], At_e[i]);
+ } // end for (k)
+ } // end if
+
+ if (nVaryingB > 0)
+ {
+ for (int j = 0; j < nVaryingB; ++j) makeZeroVector(Bt_e[j]);
+
+ Vector<double> tmp(_paramDimensionB);
+
+ for (int k = 0; k < _nMeasurements; ++k)
+ {
+ int const j = _correspondingParamB[k] - _nNonvaryingB;
+ if (j < 0) continue;
+ multiply_At_v(Bk[k], residuals[k], tmp);
+ addVectors(tmp, Bt_e[j], Bt_e[j]);
+ } // end for (k)
+ } // end if
+
+ if (nVaryingC > 0)
+ {
+ makeZeroVector(Ct_e);
+
+ Vector<double> tmp(_paramDimensionC);
+
+ for (int k = 0; k < _nMeasurements; ++k)
+ {
+ multiply_At_v(Ck[k], residuals[k], tmp);
+ for (int l = 0; l < nVaryingC; ++l) Ct_e[l] += tmp[_nNonvaryingC + l];
+ }
+ } // end if
+
+ int pos = 0;
+ for (int i = 0; i < nVaryingA; ++i)
+ for (int l = 0; l < _paramDimensionA; ++l, ++pos)
+ Jt_e[pos] = At_e[i][l];
+ for (int j = 0; j < nVaryingB; ++j)
+ for (int l = 0; l < _paramDimensionB; ++l, ++pos)
+ Jt_e[pos] = Bt_e[j][l];
+ for (int l = 0; l < nVaryingC; ++l, ++pos)
+ Jt_e[pos] = Ct_e[l];
+
+// cout << "Jt_e = ";
+// for (int k = 0; k < Jt_e.size(); ++k) cout << Jt_e[k] << " ";
+// cout << endl;
+
+ if (this->applyGradientStoppingCriteria(norm_Linf(Jt_e)))
+ {
+ status = LEVENBERG_OPTIMIZER_CONVERGED;
+ goto end;
+ }
+
+ // The lhs J^t*J consists of several parts:
+ // [ U W X ]
+ // J^t*J = [ W^t V Y ]
+ // [ X^t Y^t Z ],
+ // where U, V and W are block-sparse matrices (due to the sparsity of A and B).
+ // X, Y and Z contain only a few columns (the number of global parameters).
+
+ if (nVaryingA > 0)
+ {
+ // Compute Ui
+ Matrix<double> U(_paramDimensionA, _paramDimensionA);
+
+ for (int i = 0; i < nVaryingA; ++i) makeZeroMatrix(Ui[i]);
+
+ for (int k = 0; k < _nMeasurements; ++k)
+ {
+ int const i = _correspondingParamA[k] - _nNonvaryingA;
+ if (i < 0) continue;
+ multiply_At_A(Ak[k], U);
+ addMatricesIP(U, Ui[i]);
+ } // end for (k)
+ } // end if
+
+ if (nVaryingB > 0)
+ {
+ // Compute Vj
+ Matrix<double> V(_paramDimensionB, _paramDimensionB);
+
+ for (int j = 0; j < nVaryingB; ++j) makeZeroMatrix(Vj[j]);
+
+ for (int k = 0; k < _nMeasurements; ++k)
+ {
+ int const j = _correspondingParamB[k] - _nNonvaryingB;
+ if (j < 0) continue;
+ multiply_At_A(Bk[k], V);
+ addMatricesIP(V, Vj[j]);
+ } // end for (k)
+ } // end if
+
+ if (nVaryingC > 0)
+ {
+ Matrix<double> ZZ(_paramDimensionC, _paramDimensionC);
+ Matrix<double> Zsum(_paramDimensionC, _paramDimensionC);
+
+ makeZeroMatrix(Zsum);
+
+ for (int k = 0; k < _nMeasurements; ++k)
+ {
+ multiply_At_A(Ck[k], ZZ);
+ addMatricesIP(ZZ, Zsum);
+ } // end for (k)
+
+ // Ignore the non-varying parameters
+ for (int i = 0; i < nVaryingC; ++i)
+ for (int j = 0; j < nVaryingC; ++j)
+ Z[i][j] = Zsum[i+_nNonvaryingC][j+_nNonvaryingC];
+ } // end if
+
+ if (nVaryingA > 0 && nVaryingB > 0)
+ {
+ for (int n = 0; n < Wn.count(); ++n) makeZeroMatrix(Wn[n]);
+
+ Matrix<double> W(_paramDimensionA, _paramDimensionB);
+
+ for (int k = 0; k < _nMeasurements; ++k)
+ {
+ int const n = _jointIndexW[k];
+ if (n >= 0)
+ {
+ int const i0 = _jointNonzerosW[n].first;
+ int const j0 = _jointNonzerosW[n].second;
+
+ multiply_At_B(Ak[k], Bk[k], W);
+ addMatricesIP(W, Wn[n]);
+ } // end if
+ } // end for (k)
+ } // end if
+
+ if (nVaryingA > 0 && nVaryingC > 0)
+ {
+ Matrix<double> XX(_paramDimensionA, _paramDimensionC);
+
+ makeZeroMatrix(X);
+
+ for (int k = 0; k < _nMeasurements; ++k)
+ {
+ int const i = _correspondingParamA[k] - _nNonvaryingA;
+ // Ignore the non-varying parameters
+ if (i < 0) continue;
+
+ multiply_At_B(Ak[k], Ck[k], XX);
+
+ for (int r = 0; r < _paramDimensionA; ++r)
+ for (int c = 0; c < nVaryingC; ++c)
+ X[r+i*_paramDimensionA][c] += XX[r][c+_nNonvaryingC];
+ } // end for (k)
+ } // end if
+
+ if (nVaryingB > 0 && nVaryingC > 0)
+ {
+ Matrix<double> YY(_paramDimensionB, _paramDimensionC);
+
+ makeZeroMatrix(Y);
+
+ for (int k = 0; k < _nMeasurements; ++k)
+ {
+ int const j = _correspondingParamB[k] - _nNonvaryingB;
+ // Ignore the non-varying parameters
+ if (j < 0) continue;
+
+ multiply_At_B(Bk[k], Ck[k], YY);
+
+ for (int r = 0; r < _paramDimensionB; ++r)
+ for (int c = 0; c < nVaryingC; ++c)
+ Y[r+j*_paramDimensionB][c] += YY[r][c+_nNonvaryingC];
+ } // end for (k)
+ } // end if
+
+ if (currentIteration == 0)
+ {
+ // Initialize lambda as tau*max(JtJ[i][i])
+ double maxEl = -1e30;
+ if (nVaryingA > 0)
+ {
+ for (int i = 0; i < nVaryingA; ++i)
+ for (int l = 0; l < _paramDimensionA; ++l)
+ maxEl = std::max(maxEl, Ui[i][l][l]);
+ }
+ if (nVaryingB > 0)
+ {
+ for (int j = 0; j < nVaryingB; ++j)
+ for (int l = 0; l < _paramDimensionB; ++l)
+ maxEl = std::max(maxEl, Vj[j][l][l]);
+ }
+ if (nVaryingC > 0)
+ {
+ for (int l = 0; l < nVaryingC; ++l)
+ maxEl = std::max(maxEl, Z[l][l]);
+ }
+
+ lambda = tau * maxEl;
+ if (optimizerVerbosenessLevel >= 2)
+ cout << "SparseLevenbergOptimizer: initial lambda = " << lambda << endl;
+ } // end if (currentIteration == 0)
+ } // end if (computeDerivatives)
+
+ for (int i = 0; i < nVaryingA; ++i)
+ {
+ for (int l = 0; l < _paramDimensionA; ++l) diagUi[i][l] = Ui[i][l][l];
+ } // end for (i)
+
+ for (int j = 0; j < nVaryingB; ++j)
+ {
+ for (int l = 0; l < _paramDimensionB; ++l) diagVj[j][l] = Vj[j][l][l];
+ } // end for (j)
+
+ for (int l = 0; l < nVaryingC; ++l) diagZ[l] = Z[l][l];
+
+ // Augment the diagonals with lambda (either by the standard additive update or by multiplication).
+#if !defined(USE_MULTIPLICATIVE_UPDATE)
+ for (int i = 0; i < nVaryingA; ++i)
+ for (unsigned l = 0; l < _paramDimensionA; ++l)
+ Ui[i][l][l] += lambda;
+
+ for (int j = 0; j < nVaryingB; ++j)
+ for (unsigned l = 0; l < _paramDimensionB; ++l)
+ Vj[j][l][l] += lambda;
+
+ for (unsigned l = 0; l < nVaryingC; ++l)
+ Z[l][l] += lambda;
+#else
+ for (int i = 0; i < nVaryingA; ++i)
+ for (unsigned l = 0; l < _paramDimensionA; ++l)
+ Ui[i][l][l] = std::max(Ui[i][l][l] * (1.0 + lambda), 1e-15);
+
+ for (int j = 0; j < nVaryingB; ++j)
+ for (unsigned l = 0; l < _paramDimensionB; ++l)
+ Vj[j][l][l] = std::max(Vj[j][l][l] * (1.0 + lambda), 1e-15);
+
+ for (unsigned l = 0; l < nVaryingC; ++l)
+ Z[l][l] = std::max(Z[l][l] * (1.0 + lambda), 1e-15);
+#endif
+
+ this->fillSparseJtJ(Ui, Vj, Wn, Z, X, Y);
+
+ bool success = true;
+ double rho = 0.0;
+ {
+ int const nCols = _JtJ_Parent.size();
+ int const nnz = _JtJ.getNonzeroCount();
+ int const lnz = _JtJ_Lp.back();
+
+ vector<int> Li(lnz);
+ vector<double> Lx(lnz);
+ vector<double> D(nCols), Y(nCols);
+ vector<int> workPattern(nCols), workFlag(nCols);
+
+ int * colStarts = (int *)_JtJ.getColumnStarts();
+ int * rowIdxs = (int *)_JtJ.getRowIndices();
+ double * values = _JtJ.getValues();
+
+ int const d = ldl_numeric(nCols, colStarts, rowIdxs, values,
+ &_JtJ_Lp[0], &_JtJ_Parent[0], &_JtJ_Lnz[0],
+ &Li[0], &Lx[0], &D[0],
+ &Y[0], &workPattern[0], &workFlag[0],
+ NULL, NULL);
+
+ if (d == nCols)
+ {
+ ldl_perm(nCols, &deltaPerm[0], &Jt_e[0], &_perm_JtJ[0]);
+ ldl_lsolve(nCols, &deltaPerm[0], &_JtJ_Lp[0], &Li[0], &Lx[0]);
+ ldl_dsolve(nCols, &deltaPerm[0], &D[0]);
+ ldl_ltsolve(nCols, &deltaPerm[0], &_JtJ_Lp[0], &Li[0], &Lx[0]);
+ ldl_permt(nCols, &delta[0], &deltaPerm[0], &_perm_JtJ[0]);
+ }
+ else
+ {
+ if (optimizerVerbosenessLevel >= 2)
+ cout << "SparseLevenbergOptimizer: LDL decomposition failed. Increasing lambda." << endl;
+ success = false;
+ }
+ }
+
+ if (success)
+ {
+ double const deltaSqrLength = sqrNorm_L2(delta);
+
+ if (optimizerVerbosenessLevel >= 2)
+ cout << "SparseLevenbergOptimizer: ||delta||^2 = " << deltaSqrLength << endl;
+
+ double const paramLength = this->getParameterLength();
+ if (this->applyUpdateStoppingCriteria(paramLength, sqrt(deltaSqrLength)))
+ {
+ status = LEVENBERG_OPTIMIZER_SMALL_UPDATE;
+ goto end;
+ }
+
+ // Copy the updates from delta to the respective arrays
+ int pos = 0;
+
+ for (int i = 0; i < _nNonvaryingA; ++i) makeZeroVector(deltaAi[i]);
+ for (int i = _nNonvaryingA; i < _nParametersA; ++i)
+ for (int l = 0; l < _paramDimensionA; ++l, ++pos)
+ deltaAi[i][l] = delta[pos];
+
+ for (int j = 0; j < _nNonvaryingB; ++j) makeZeroVector(deltaBj[j]);
+ for (int j = _nNonvaryingB; j < _nParametersB; ++j)
+ for (int l = 0; l < _paramDimensionB; ++l, ++pos)
+ deltaBj[j][l] = delta[pos];
+
+ makeZeroVector(deltaC);
+ for (int l = _nNonvaryingC; l < _paramDimensionC; ++l, ++pos)
+ deltaC[l] = delta[pos];
+
+ saveAllParameters();
+ if (nVaryingA > 0) updateParametersA(deltaAi);
+ if (nVaryingB > 0) updateParametersB(deltaBj);
+ if (nVaryingC > 0) updateParametersC(deltaC);
+
+ this->evalResidual(residuals2);
+ for (int k = 0; k < _nMeasurements; ++k)
+ scaleVectorIP(weights[k], residuals2[k]);
+
+ double const newErr = squaredResidual(residuals2);
+ rho = err - newErr;
+ if (optimizerVerbosenessLevel >= 2)
+ cout << "SparseLevenbergOptimizer: |new residual|^2 = " << newErr << endl;
+
+#if !defined(USE_MULTIPLICATIVE_UPDATE)
+ double const denom1 = lambda * deltaSqrLength;
+#else
+ double denom1 = 0.0f;
+ for (int i = _nNonvaryingA; i < _nParametersA; ++i)
+ for (int l = 0; l < _paramDimensionA; ++l)
+ denom1 += deltaAi[i][l] * deltaAi[i][l] * diagUi[i-_nNonvaryingA][l];
+
+ for (int j = _nNonvaryingB; j < _nParametersB; ++j)
+ for (int l = 0; l < _paramDimensionB; ++l)
+ denom1 += deltaBj[j][l] * deltaBj[j][l] * diagVj[j-_nNonvaryingB][l];
+
+ for (int l = _nNonvaryingC; l < _paramDimensionC; ++l)
+ denom1 += deltaC[l] * deltaC[l] * diagZ[l-_nNonvaryingC];
+
+ denom1 *= lambda;
+#endif
+ double const denom2 = innerProduct(delta, Jt_e);
+ rho = rho / (denom1 + denom2);
+ if (optimizerVerbosenessLevel >= 2)
+ cout << "SparseLevenbergOptimizer: rho = " << rho
+ << " denom1 = " << denom1 << " denom2 = " << denom2 << endl;
+ } // end if (success)
+
+ if (success && rho > 0)
+ {
+ if (optimizerVerbosenessLevel >= 2)
+ cout << "SparseLevenbergOptimizer: Improved solution - decreasing lambda." << endl;
+ // Improvement in the new solution
+ decreaseLambda(rho);
+ computeDerivatives = true;
+ }
+ else
+ {
+ if (optimizerVerbosenessLevel >= 2)
+ cout << "SparseLevenbergOptimizer: Inferior solution - increasing lambda." << endl;
+ restoreAllParameters();
+ increaseLambda();
+ computeDerivatives = false;
+
+ // Restore diagonal elements in Ui, Vj and Z.
+ for (int i = 0; i < nVaryingA; ++i)
+ {
+ for (int l = 0; l < _paramDimensionA; ++l) Ui[i][l][l] = diagUi[i][l];
+ } // end for (i)
+
+ for (int j = 0; j < nVaryingB; ++j)
+ {
+ for (int l = 0; l < _paramDimensionB; ++l) Vj[j][l][l] = diagVj[j][l];
+ } // end for (j)
+
+ for (int l = 0; l < nVaryingC; ++l) Z[l][l] = diagZ[l];
+ } // end if
+ } // end for
+
+ end:;
+ if (optimizerVerbosenessLevel >= 2)
+ cout << "Leaving SparseLevenbergOptimizer::minimize()." << endl;
+ } // end SparseLevenbergOptimizer::minimize()
+
+#endif // defined(V3DLIB_ENABLE_SUITESPARSE)
+
+} // end namespace V3D
diff --git a/extern/libmv/third_party/ssba/Math/v3d_optimization.h b/extern/libmv/third_party/ssba/Math/v3d_optimization.h
new file mode 100644
index 00000000000..27d2e12287f
--- /dev/null
+++ b/extern/libmv/third_party/ssba/Math/v3d_optimization.h
@@ -0,0 +1,273 @@
+// -*- C++ -*-
+/*
+Copyright (c) 2008 University of North Carolina at Chapel Hill
+
+This file is part of SSBA (Simple Sparse Bundle Adjustment).
+
+SSBA is free software: you can redistribute it and/or modify it under the
+terms of the GNU Lesser General Public License as published by the Free
+Software Foundation, either version 3 of the License, or (at your option) any
+later version.
+
+SSBA is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
+A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
+details.
+
+You should have received a copy of the GNU Lesser General Public License along
+with SSBA. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef V3D_OPTIMIZATION_H
+#define V3D_OPTIMIZATION_H
+
+#include "Math/v3d_linear.h"
+#include "Math/v3d_mathutilities.h"
+
+#include <vector>
+#include <iostream>
+
+namespace V3D
+{
+
+ enum
+ {
+ LEVENBERG_OPTIMIZER_TIMEOUT = 0,
+ LEVENBERG_OPTIMIZER_SMALL_UPDATE = 1,
+ LEVENBERG_OPTIMIZER_CONVERGED = 2
+ };
+
+ extern int optimizerVerbosenessLevel;
+
+ struct LevenbergOptimizerCommon
+ {
+ LevenbergOptimizerCommon()
+ : status(LEVENBERG_OPTIMIZER_TIMEOUT), currentIteration(0), maxIterations(50),
+ tau(1e-3), lambda(1e-3),
+ gradientThreshold(1e-10), updateThreshold(1e-10),
+ _nu(2.0)
+ { }
+ virtual ~LevenbergOptimizerCommon() {}
+
+ // See Madsen et al., "Methods for non-linear least squares problems."
+ virtual void increaseLambda()
+ {
+ lambda *= _nu; _nu *= 2.0;
+ }
+
+ virtual void decreaseLambda(double const rho)
+ {
+ double const r = 2*rho - 1.0;
+ lambda *= std::max(1.0/3.0, 1 - r*r*r);
+ if (lambda < 1e-10) lambda = 1e-10;
+ _nu = 2;
+ }
+
+ bool applyGradientStoppingCriteria(double maxGradient) const
+ {
+ return maxGradient < gradientThreshold;
+ }
+
+ bool applyUpdateStoppingCriteria(double paramLength, double updateLength) const
+ {
+ return updateLength < updateThreshold * (paramLength + updateThreshold);
+ }
+
+ int status;
+ int currentIteration, maxIterations;
+ double tau, lambda;
+ double gradientThreshold, updateThreshold;
+
+ protected:
+ double _nu;
+ }; // end struct LevenbergOptimizerCommon
+
+# if defined(V3DLIB_ENABLE_SUITESPARSE)
+
+ struct SparseLevenbergOptimizer : public LevenbergOptimizerCommon
+ {
+ SparseLevenbergOptimizer(int measurementDimension,
+ int nParametersA, int paramDimensionA,
+ int nParametersB, int paramDimensionB,
+ int paramDimensionC,
+ std::vector<int> const& correspondingParamA,
+ std::vector<int> const& correspondingParamB)
+ : LevenbergOptimizerCommon(),
+ _nMeasurements(correspondingParamA.size()),
+ _measurementDimension(measurementDimension),
+ _nParametersA(nParametersA), _paramDimensionA(paramDimensionA),
+ _nParametersB(nParametersB), _paramDimensionB(paramDimensionB),
+ _paramDimensionC(paramDimensionC),
+ _nNonvaryingA(0), _nNonvaryingB(0), _nNonvaryingC(0),
+ _correspondingParamA(correspondingParamA),
+ _correspondingParamB(correspondingParamB)
+ {
+ assert(correspondingParamA.size() == correspondingParamB.size());
+ }
+
+ ~SparseLevenbergOptimizer() { }
+
+ void setNonvaryingCounts(int nNonvaryingA, int nNonvaryingB, int nNonvaryingC)
+ {
+ _nNonvaryingA = nNonvaryingA;
+ _nNonvaryingB = nNonvaryingB;
+ _nNonvaryingC = nNonvaryingC;
+ }
+
+ void getNonvaryingCounts(int& nNonvaryingA, int& nNonvaryingB, int& nNonvaryingC) const
+ {
+ nNonvaryingA = _nNonvaryingA;
+ nNonvaryingB = _nNonvaryingB;
+ nNonvaryingC = _nNonvaryingC;
+ }
+
+ void minimize();
+
+ virtual void evalResidual(VectorArray<double>& residuals) = 0;
+
+ virtual void fillWeights(VectorArray<double> const& residuals, Vector<double>& w)
+ {
+ (void)residuals;
+ std::fill(w.begin(), w.end(), 1.0);
+ }
+
+ void fillAllJacobians(Vector<double> const& w,
+ MatrixArray<double>& Ak,
+ MatrixArray<double>& Bk,
+ MatrixArray<double>& Ck)
+ {
+ int const nVaryingA = _nParametersA - _nNonvaryingA;
+ int const nVaryingB = _nParametersB - _nNonvaryingB;
+ int const nVaryingC = _paramDimensionC - _nNonvaryingC;
+
+ for (unsigned k = 0; k < _nMeasurements; ++k)
+ {
+ int const i = _correspondingParamA[k];
+ int const j = _correspondingParamB[k];
+
+ if (i < _nNonvaryingA && j < _nNonvaryingB) continue;
+
+ fillJacobians(Ak[k], Bk[k], Ck[k], i, j, k);
+ } // end for (k)
+
+ if (nVaryingA > 0)
+ {
+ for (unsigned k = 0; k < _nMeasurements; ++k)
+ scaleMatrixIP(w[k], Ak[k]);
+ }
+ if (nVaryingB > 0)
+ {
+ for (unsigned k = 0; k < _nMeasurements; ++k)
+ scaleMatrixIP(w[k], Bk[k]);
+ }
+ if (nVaryingC > 0)
+ {
+ for (unsigned k = 0; k < _nMeasurements; ++k)
+ scaleMatrixIP(w[k], Ck[k]);
+ }
+ } // end fillAllJacobians()
+
+ virtual void setupJacobianGathering() { }
+
+ virtual void fillJacobians(Matrix<double>& Ak, Matrix<double>& Bk, Matrix<double>& Ck,
+ int i, int j, int k) = 0;
+
+ virtual double getParameterLength() const = 0;
+
+ virtual void updateParametersA(VectorArray<double> const& deltaAi) = 0;
+ virtual void updateParametersB(VectorArray<double> const& deltaBj) = 0;
+ virtual void updateParametersC(Vector<double> const& deltaC) = 0;
+ virtual void saveAllParameters() = 0;
+ virtual void restoreAllParameters() = 0;
+
+ int currentIteration, maxIterations;
+
+ protected:
+ void serializeNonZerosJtJ(std::vector<std::pair<int, int> >& dst) const;
+ void setupSparseJtJ();
+ void fillSparseJtJ(MatrixArray<double> const& Ui, MatrixArray<double> const& Vj, MatrixArray<double> const& Wk,
+ Matrix<double> const& Z, Matrix<double> const& X, Matrix<double> const& Y);
+
+ int const _nMeasurements, _measurementDimension;
+ int const _nParametersA, _paramDimensionA;
+ int const _nParametersB, _paramDimensionB;
+ int const _paramDimensionC;
+
+ int _nNonvaryingA, _nNonvaryingB, _nNonvaryingC;
+
+ std::vector<int> const& _correspondingParamA;
+ std::vector<int> const& _correspondingParamB;
+
+ std::vector<pair<int, int> > _jointNonzerosW;
+ std::vector<int> _jointIndexW;
+
+ std::vector<int> _JtJ_Lp, _JtJ_Parent, _JtJ_Lnz;
+ std::vector<int> _perm_JtJ, _invPerm_JtJ;
+
+ CCS_Matrix<double> _JtJ;
+ }; // end struct SparseLevenbergOptimizer
+
+ struct StdSparseLevenbergOptimizer : public SparseLevenbergOptimizer
+ {
+ StdSparseLevenbergOptimizer(int measurementDimension,
+ int nParametersA, int paramDimensionA,
+ int nParametersB, int paramDimensionB,
+ int paramDimensionC,
+ std::vector<int> const& correspondingParamA,
+ std::vector<int> const& correspondingParamB)
+ : SparseLevenbergOptimizer(measurementDimension, nParametersA, paramDimensionA,
+ nParametersB, paramDimensionB, paramDimensionC,
+ correspondingParamA, correspondingParamB),
+ curParametersA(nParametersA, paramDimensionA), savedParametersA(nParametersA, paramDimensionA),
+ curParametersB(nParametersB, paramDimensionB), savedParametersB(nParametersB, paramDimensionB),
+ curParametersC(paramDimensionC), savedParametersC(paramDimensionC)
+ { }
+
+ virtual double getParameterLength() const
+ {
+ double res = 0.0;
+ for (int i = 0; i < _nParametersA; ++i) res += sqrNorm_L2(curParametersA[i]);
+ for (int j = 0; j < _nParametersB; ++j) res += sqrNorm_L2(curParametersB[j]);
+ res += sqrNorm_L2(curParametersC);
+ return sqrt(res);
+ }
+
+ virtual void updateParametersA(VectorArray<double> const& deltaAi)
+ {
+ for (int i = 0; i < _nParametersA; ++i) addVectors(deltaAi[i], curParametersA[i], curParametersA[i]);
+ }
+
+ virtual void updateParametersB(VectorArray<double> const& deltaBj)
+ {
+ for (int j = 0; j < _nParametersB; ++j) addVectors(deltaBj[j], curParametersB[j], curParametersB[j]);
+ }
+
+ virtual void updateParametersC(Vector<double> const& deltaC)
+ {
+ addVectors(deltaC, curParametersC, curParametersC);
+ }
+
+ virtual void saveAllParameters()
+ {
+ for (int i = 0; i < _nParametersA; ++i) savedParametersA[i] = curParametersA[i];
+ for (int j = 0; j < _nParametersB; ++j) savedParametersB[j] = curParametersB[j];
+ savedParametersC = curParametersC;
+ }
+
+ virtual void restoreAllParameters()
+ {
+ for (int i = 0; i < _nParametersA; ++i) curParametersA[i] = savedParametersA[i];
+ for (int j = 0; j < _nParametersB; ++j) curParametersB[j] = savedParametersB[j];
+ curParametersC = savedParametersC;
+ }
+
+ VectorArray<double> curParametersA, savedParametersA;
+ VectorArray<double> curParametersB, savedParametersB;
+ Vector<double> curParametersC, savedParametersC;
+ }; // end struct StdSparseLevenbergOptimizer
+
+# endif
+
+} // end namespace V3D
+
+#endif
diff --git a/extern/libmv/third_party/ssba/README.TXT b/extern/libmv/third_party/ssba/README.TXT
new file mode 100644
index 00000000000..734962b1df8
--- /dev/null
+++ b/extern/libmv/third_party/ssba/README.TXT
@@ -0,0 +1,92 @@
+Description
+
+This is an implementation of a sparse Levenberg-Marquardt optimization
+procedure and several bundle adjustment modules based on it. There are three
+versions of bundle adjustment:
+1) Pure metric adjustment. Camera poses have 6 dof and 3D points have 3 dof.
+2) Common, but adjustable intrinsic and distortion parameters. This is useful,
+ if the set of images are taken with the same camera under constant zoom
+ settings.
+3) Variable intrinsics and distortion parameters for each view. This addresses
+ the "community photo collection" setting, where each image is captured with
+ a different camera and/or with varying zoom setting.
+
+There are two demo applications in the Apps directory, bundle_common and
+bundle_varying, which correspond to item 2) and 3) above.
+
+The input data file for both applications is a text file with the following
+numerical values:
+
+First, the number of 3D points, views and 2D measurements:
+<M> <N> <K>
+Then, the values of the intrinsic matrix
+ [ fx skew cx ]
+K = [ 0 fy cy ]
+ [ 0 0 1 ],
+and the distortion parameters according to the convention of the Bouget
+toolbox:
+
+ <fx> <skew> <cx> <fy> <cy> <k1> <k2> <p1> <p2>
+
+For the bundle_varying application this is given <N> times, one for each
+camera/view.
+Then the <M> 3D point positions are given:
+
+ <point-id> <X> <Y> <Z>
+
+Note: the point-ids need not to be exactly from 0 to M-1, any (unique) ids
+will do.
+The camera poses are given subsequently:
+
+ <view-id> <12 entries of the RT matrix>
+
+There is a lot of confusion how to specify the orientation of cameras. We use
+projection matrix notation, i.e. P = K [R|T], and a 3D point X in world
+coordinates is transformed into the camera coordinate system by XX=R*X+T.
+
+Finally, the <K> 2d image measurements (given in pixels) are provided:
+
+ <view-id> <point-id> <x> <y> 1
+
+See the example in the Dataset folder.
+
+
+Performance
+
+This software is able to perform successful loop closing for a video sequence
+containing 1745 views, 37920 3D points and 627228 image measurements in about
+16min on a 2.2 GHz Core 2. The footprint in memory was <700MB.
+
+
+Requirements
+
+Solving the augmented normal equation in the LM optimizer is done with LDL, a
+Cholsky like decomposition method for sparse matrices (see
+http://www.cise.ufl.edu/research/sparse/ldl). The appropriate column
+reordering is done with COLAMD (see
+http://www.cise.ufl.edu/research/sparse/colamd). Both packages are licensed
+under the GNU LGPL.
+
+This software was developed under Linux, but should compile equally well on
+other operating systems.
+
+-Christopher Zach (cmzach@cs.unc.edu)
+
+/*
+Copyright (c) 2008 University of North Carolina at Chapel Hill
+
+This file is part of SSBA (Simple Sparse Bundle Adjustment).
+
+SSBA is free software: you can redistribute it and/or modify it under the
+terms of the GNU Lesser General Public License as published by the Free
+Software Foundation, either version 3 of the License, or (at your option) any
+later version.
+
+SSBA is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
+A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
+details.
+
+You should have received a copy of the GNU Lesser General Public License along
+with SSBA. If not, see <http://www.gnu.org/licenses/>.
+*/
diff --git a/extern/libmv/third_party/ssba/README.libmv b/extern/libmv/third_party/ssba/README.libmv
new file mode 100755
index 00000000000..45e0a31f6fc
--- /dev/null
+++ b/extern/libmv/third_party/ssba/README.libmv
@@ -0,0 +1,23 @@
+Project: SSBA
+URL: http://www.cs.unc.edu/~cmzach/opensource.html
+License: LGPL3
+Upstream version: 1.0
+
+Local modifications:
+
+ * Added
+ SET(CMAKE_CXX_FLAGS "")
+ to CMakeLists.txt to prevent warnings from being treated as errors.
+ * Fixed "unused variable" in the header files. Warnings in the cpps files
+ are still there.
+ * Fixed a bug in CameraMatrix::opticalAxis() in file
+ Geometry/v3d_cameramatrix.h
+ * Deleted the Dataset directory.
+ * Added '#include <string>' to ssba/Apps/bundle_common.cpp and
+ ssba/Apps/bundle_varying.cpp to stop undefined references to strcmp
+ * Removed unnecessary elements from the CMakeLists.txt file, including the
+ obsoleted local_config.cmake and friends.
+ * Added a virtual destructor to V3D::LevenbergOptimizerCommon in
+ Math/v3d_optimization.h
+ * Added /EHsc WIN32-specific flag to CMakeLists.txt
+ * Remove unused variable Vector3d np in bundle_common.cpp and bundle_varying (in main() function).