diff options
author | Brecht Van Lommel <brechtvanlommel@pandora.be> | 2011-11-07 19:23:08 +0400 |
---|---|---|
committer | Brecht Van Lommel <brechtvanlommel@pandora.be> | 2011-11-07 19:23:08 +0400 |
commit | 5ef9039b7e2ea16bd4b651aab21d5aa690485569 (patch) | |
tree | e67247fa43d89748900b697eb9bdf0341fe53afc /extern/libmv | |
parent | fb56dbc2afc7c8b6ffc24406ed82cbcbff090da3 (diff) | |
parent | 5ebee683bd736ef80df939552bbe0d8e104b56df (diff) |
Cycles: svn merge -r41531:41613 ^/trunk/blender
Diffstat (limited to 'extern/libmv')
162 files changed, 51119 insertions, 0 deletions
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 ¶ms, + 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 ¶ms, 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 ¶ms, + 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 ¶ms, 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 ¬able_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, + ¬able_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, + ¬able_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 = + { "", + "==========", + ¬able_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 *-", + "===========================", + ¬able_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 *-", + "============================", + ¬able_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 *-", + "=========================", + ¬able_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 *-", + "================================", + ¬able_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 ¬able_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, "&"); + for (string::size_type pos = 0; (pos = ans.find("<", pos)) != string::npos; ) + ans.replace(pos++, 1, "<"); + 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(×tamp, &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). |